diff --git a/README.md b/README.md index ce66215..d190838 100644 --- a/README.md +++ b/README.md @@ -168,6 +168,38 @@ npm run check npm test ``` +## Project structure + +The plugin is organized into purpose-named feature folders under `src/`, each +concern in its own module with a barrel `index.ts` where a folder groups several +files: + +``` +index.ts # extension entry point (registers tool, command, hook) +src/ + tool.ts # the universal `apify` tool definition + actions/ # tool action layer + index.ts # barrel re-exporting the router + handlers + execute.ts # apifyExecute router (config gate → handler dispatch) + discover.ts # discover action (search / schema) + start.ts # start action (launch a run) + collect.ts # collect action (poll runs & fetch datasets) + commands/ # /apify slash-command handlers + index.ts # barrel re-exporting the three commands + login.ts # /apify login + status.ts # /apify status + test.ts # /apify test + security/ # input/output safety helpers + index.ts # barrel re-exporting normalize + wrap + normalize.ts # secret normalization, slug validation, fingerprint + wrap.ts # untrusted-content wrapping (prompt-injection defense) + utils/ # single-concern helpers, one flat file each + config.ts # config load / merge / resolve + client.ts # ApifyClient creation + connectivity check + constants.ts # shared constants (limits, markers, known actors) + types.ts # shared TypeScript interfaces +``` + ## License ISC \ No newline at end of file diff --git a/index.ts b/index.ts index e90251f..5dc9a8f 100644 --- a/index.ts +++ b/index.ts @@ -3,7 +3,7 @@ import { apifyTool } from "./src/tool.ts"; import { apifyLoginCommand, apifyStatusCommand, apifyTestCommand } from "./src/commands/index.ts"; import { loadConfig, resolveApiKey } from "./src/utils/config.ts"; import { createClient, testConnectivity } from "./src/utils/client.ts"; -import { fingerprintKey } from "./src/utils/normalize.ts"; +import { fingerprintKey } from "./src/security/index.ts"; /** * Apify Pi Plugin - Universal Apify Actor integration for the Pi agent. diff --git a/package-lock.json b/package-lock.json index 43fc629..235cacc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1229,6 +1229,9 @@ "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1246,6 +1249,9 @@ "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -1263,6 +1269,9 @@ "cpu": [ "riscv64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1280,6 +1289,9 @@ "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1297,6 +1309,9 @@ "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ diff --git a/package.json b/package.json index dd39959..ca201f1 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ }, "scripts": { "check": "tsc --noEmit", + "test": "node test-structure.js", "setup:pi": "bash scripts/setup.sh", "cleanup:pi": "rm -rf .pi-install ~/.pi/agent/auth.json ~/.pi/agent/apify.json 2>/dev/null; true" }, diff --git a/src/actions/collect.ts b/src/actions/collect.ts index 9fcc842..0eca19a 100644 --- a/src/actions/collect.ts +++ b/src/actions/collect.ts @@ -1,6 +1,6 @@ import type { AgentToolResult } from "@earendil-works/pi-coding-agent"; -import type { ApifyToolParams, CollectDetails } from "../types/index.ts"; -import { wrapUntrustedContent } from "../utils/wrap.ts"; +import type { ApifyToolParams, CollectDetails } from "../utils/types.ts"; +import { wrapUntrustedContent } from "../security/index.ts"; import { MAX_RESULT_CHARS } from "../utils/constants.ts"; // Maximum number of items per dataset to prevent context overflow diff --git a/src/actions/discover.ts b/src/actions/discover.ts index af3416c..8a414f4 100644 --- a/src/actions/discover.ts +++ b/src/actions/discover.ts @@ -1,6 +1,6 @@ import type { AgentToolResult } from "@earendil-works/pi-coding-agent"; -import type { ApifyToolParams, DiscoverDetails } from "../types/index.ts"; -import { validateSlug } from "../utils/normalize.ts"; +import type { ApifyToolParams, DiscoverDetails } from "../utils/types.ts"; +import { validateSlug } from "../security/index.ts"; /** * Handle discover action (search or schema mode). diff --git a/src/actions/execute.ts b/src/actions/execute.ts new file mode 100644 index 0000000..a35e90b --- /dev/null +++ b/src/actions/execute.ts @@ -0,0 +1,77 @@ +import type { AgentToolResult, AgentToolUpdateCallback, ExtensionContext } from "@earendil-works/pi-coding-agent"; +import type { ApifyToolParams, ApifyToolDetails, DiscoverDetails } from "../utils/types.ts"; +import { createClient } from "../utils/client.ts"; +import { loadConfig, resolveApiKey } from "../utils/config.ts"; +import { handleDiscover } from "./discover.ts"; +import { handleStart } from "./start.ts"; +import { handleCollect } from "./collect.ts"; + +/** + * Main execute function for the apify tool. + */ +export async function apifyExecute( + _toolCallId: string, + params: ApifyToolParams, + _signal: AbortSignal | undefined, + _onUpdate: AgentToolUpdateCallback | undefined, + ctx: ExtensionContext +): Promise> { + // Load config + const config = loadConfig(); + + // Check if enabled + if (config.enabled === false) { + return { + content: [{ type: "text", text: "Apify integration is disabled. Enable it in config or run /apify login." }], + details: { mode: "search" } as DiscoverDetails, + }; + } + + // Check enabledTools + if (config.enabledTools && !config.enabledTools.includes(params.action)) { + return { + content: [{ type: "text", text: `Action "${params.action}" is not enabled. Enabled actions: ${config.enabledTools.join(", ")}` }], + details: { mode: "search" } as DiscoverDetails, + }; + } + + // Resolve API key + const apiKey = resolveApiKey(config); + if (!apiKey) { + return { + content: [{ + type: "text", + text: JSON.stringify({ + error: "missing_credential", + message: "No Apify API key configured. Run /apify login or set APIFY_API_KEY env var.", + docs: "https://docs.apify.com/api-reference/v2" + }, null, 2) + }], + details: { mode: "search" } as DiscoverDetails, + }; + } + + // Create client + const client = createClient(config, apiKey); + if (!client) { + return { + content: [{ type: "text", text: "Failed to create Apify client" }], + details: { mode: "search" } as DiscoverDetails, + }; + } + + // Route to appropriate handler + switch (params.action) { + case "discover": + return handleDiscover(client, params, config); + case "start": + return handleStart(client, params, config); + case "collect": + return handleCollect(client, params, config); + default: + return { + content: [{ type: "text", text: `Unknown action: ${params.action}` }], + details: { mode: "search" } as DiscoverDetails, + }; + } +} \ No newline at end of file diff --git a/src/actions/index.ts b/src/actions/index.ts index 2a40c41..4149a8e 100644 --- a/src/actions/index.ts +++ b/src/actions/index.ts @@ -1,77 +1,4 @@ -import type { AgentToolResult, AgentToolUpdateCallback, ExtensionContext } from "@earendil-works/pi-coding-agent"; -import type { ApifyToolParams, ApifyToolDetails, DiscoverDetails } from "../types/index.ts"; -import { createClient } from "../utils/client.ts"; -import { loadConfig, resolveApiKey } from "../utils/config.ts"; -import { handleDiscover } from "./discover.ts"; -import { handleStart } from "./start.ts"; -import { handleCollect } from "./collect.ts"; - -/** - * Main execute function for the apify tool. - */ -export async function apifyExecute( - _toolCallId: string, - params: ApifyToolParams, - _signal: AbortSignal | undefined, - _onUpdate: AgentToolUpdateCallback | undefined, - ctx: ExtensionContext -): Promise> { - // Load config - const config = loadConfig(); - - // Check if enabled - if (config.enabled === false) { - return { - content: [{ type: "text", text: "Apify integration is disabled. Enable it in config or run /apify login." }], - details: { mode: "search" } as DiscoverDetails, - }; - } - - // Check enabledTools - if (config.enabledTools && !config.enabledTools.includes(params.action)) { - return { - content: [{ type: "text", text: `Action "${params.action}" is not enabled. Enabled actions: ${config.enabledTools.join(", ")}` }], - details: { mode: "search" } as DiscoverDetails, - }; - } - - // Resolve API key - const apiKey = resolveApiKey(config); - if (!apiKey) { - return { - content: [{ - type: "text", - text: JSON.stringify({ - error: "missing_credential", - message: "No Apify API key configured. Run /apify login or set APIFY_API_KEY env var.", - docs: "https://docs.apify.com/api-reference/v2" - }, null, 2) - }], - details: { mode: "search" } as DiscoverDetails, - }; - } - - // Create client - const client = createClient(config, apiKey); - if (!client) { - return { - content: [{ type: "text", text: "Failed to create Apify client" }], - details: { mode: "search" } as DiscoverDetails, - }; - } - - // Route to appropriate handler - switch (params.action) { - case "discover": - return handleDiscover(client, params, config); - case "start": - return handleStart(client, params, config); - case "collect": - return handleCollect(client, params, config); - default: - return { - content: [{ type: "text", text: `Unknown action: ${params.action}` }], - details: { mode: "search" } as DiscoverDetails, - }; - } -} \ No newline at end of file +export * from "./execute.ts"; +export * from "./discover.ts"; +export * from "./start.ts"; +export * from "./collect.ts"; diff --git a/src/actions/start.ts b/src/actions/start.ts index 858824a..fe78cac 100644 --- a/src/actions/start.ts +++ b/src/actions/start.ts @@ -1,6 +1,6 @@ import type { AgentToolResult } from "@earendil-works/pi-coding-agent"; -import type { ApifyToolParams, StartDetails } from "../types/index.ts"; -import { validateSlug } from "../utils/normalize.ts"; +import type { ApifyToolParams, StartDetails } from "../utils/types.ts"; +import { validateSlug } from "../security/index.ts"; /** * Handle start action (launch actor run). diff --git a/src/commands/index.ts b/src/commands/index.ts index ec5412d..479b9e8 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -1,181 +1,3 @@ -import type { ExtensionContext } from "@earendil-works/pi-coding-agent"; -import { createClient, testConnectivity } from "../utils/client.ts"; -import { loadConfig, writeGlobalConfig, resolveApiKey } from "../utils/config.ts"; -import { normalizeSecretInput, fingerprintKey } from "../utils/normalize.ts"; - -/** - * Handle /apify login command. - * Interactive key configuration with masked input. - */ -export async function apifyLoginCommand(ctx: ExtensionContext): Promise { - try { - // Prompt for API key - ctx.ui.notify("Please enter your Apify API key:"); - ctx.ui.notify("You can find your API key at: https://console.apify.com/account/integrations"); - - // Note: The ui.input method doesn't support password masking in Pi's current API - // The user will need to paste their key in plain text - const keyInput = await ctx.ui.input("Apify API key:", "paste your API key here"); - - if (!keyInput || !keyInput.trim()) { - ctx.ui.notify("No API key provided. Login cancelled."); - return; - } - - // Normalize the key - const apiKey = normalizeSecretInput(keyInput); - - // Test the key - ctx.ui.notify("Validating API key..."); - const client = createClient({ apiKey }); - - if (!client) { - ctx.ui.notify("Failed to create Apify client. Please check your API key."); - return; - } - - const result = await testConnectivity(client); - - if (result.success) { - // Save the key to global config - const config = loadConfig(); - config.apiKey = apiKey; - config.enabled = true; // Auto-enable - writeGlobalConfig(config); - - ctx.ui.notify(`✅ Authenticated as ${result.userId} (${result.plan} plan).`); - ctx.ui.notify(`Key saved to ~/.pi/agent/apify.json (fingerprint: ${fingerprintKey(apiKey)})`); - } else { - ctx.ui.notify(`❌ Authentication failed: ${result.error}`); - ctx.ui.notify("Please check your API key and try again."); - } - } catch (error) { - ctx.ui.notify(`Error during login: ${error instanceof Error ? error.message : String(error)}`); - } -} - -/** - * Handle /apify status command. - * Show current configuration and authentication status. - */ -export async function apifyStatusCommand(_args: string, ctx: ExtensionContext): Promise { - try { - const config = loadConfig(); - - // Check if configured - const apiKey = resolveApiKey(config); - if (!apiKey) { - ctx.ui.notify("❌ Apify not configured. Run /apify login to set up your API key."); - ctx.ui.notify("You can also set the APIFY_API_KEY environment variable."); - return; - } - - // Test connectivity - ctx.ui.notify("Checking Apify connection..."); - const client = createClient(config); - - if (!client) { - ctx.ui.notify("Failed to create Apify client."); - return; - } - - const result = await testConnectivity(client); - - if (result.success) { - ctx.ui.notify(`✅ Authenticated as ${result.userId} (${result.plan} plan)`); - ctx.ui.notify(`Key fingerprint: ${fingerprintKey(apiKey)}`); - } else { - ctx.ui.notify(`⚠️ Authentication failed: ${result.error}`); - ctx.ui.notify(`Key fingerprint: ${fingerprintKey(apiKey)}`); - } - - // Show enabled status - if (config.enabled === false) { - ctx.ui.notify("⚠️ Apify integration is disabled in config"); - } else { - ctx.ui.notify("✅ Apify integration is enabled"); - } - - // Show enabled tools - if (config.enabledTools) { - ctx.ui.notify(`Enabled actions: ${config.enabledTools.join(", ")}`); - } else { - ctx.ui.notify("All actions enabled: discover, start, collect"); - } - - // Show other config - ctx.ui.notify(`Base URL: ${config.baseUrl || "https://api.apify.com"}`); - ctx.ui.notify(`Max results: ${config.maxResults || 50000} chars`); - } catch (error) { - ctx.ui.notify(`Error checking status: ${error instanceof Error ? error.message : String(error)}`); - } -} - -/** - * Handle /apify test command. - * Test connectivity and optionally run a simple actor. - */ -export async function apifyTestCommand(_args: string, ctx: ExtensionContext): Promise { - try { - const config = loadConfig(); - - // Check if configured - const apiKey = resolveApiKey(config); - if (!apiKey) { - ctx.ui.notify("❌ Apify not configured. Run /apify login first."); - return; - } - - // Test basic connectivity - ctx.ui.notify("Testing Apify connection..."); - const client = createClient(config); - - if (!client) { - ctx.ui.notify("Failed to create Apify client."); - return; - } - - const result = await testConnectivity(client); - - if (!result.success) { - ctx.ui.notify(`❌ Connection failed: ${result.error}`); - return; - } - - ctx.ui.notify(`✅ Connected as ${result.userId} (${result.plan} plan)`); - - // Optionally test a simple actor run - ctx.ui.notify("\nTesting actor run with a minimal example..."); - try { - // Use a simple, fast actor for testing - const testActor = "apify~web-scraper"; - const testInput = { - startUrls: [{ url: "https://example.com" }], - maxRequestsPerCrawl: 1, - maxRequestRetries: 0, - maxCrawlDepth: 0, - keepUrlFragments: false, - }; - - ctx.ui.notify(`Starting test run of ${testActor}...`); - const run = await client.actor(testActor).start(testInput, { waitForFinish: 60 }); // Wait max 60 seconds - - if (run.status === "SUCCEEDED") { - const dataset = await client.dataset(run.defaultDatasetId).listItems({ limit: 1 }); - ctx.ui.notify(`✅ Test run succeeded! Got ${dataset.items?.length || 0} results.`); - ctx.ui.notify(`Run ID: ${run.id}`); - ctx.ui.notify(`Duration: ${run.stats?.durationMillis || 0}ms`); - } else { - ctx.ui.notify(`⚠️ Test run ended with status: ${run.status}`); - if (run.statusMessage) { - ctx.ui.notify(`Message: ${run.statusMessage}`); - } - } - } catch (runError) { - ctx.ui.notify(`⚠️ Test run failed: ${runError instanceof Error ? runError.message : String(runError)}`); - ctx.ui.notify("Basic connectivity works, but actor execution may have issues."); - } - } catch (error) { - ctx.ui.notify(`Error during test: ${error instanceof Error ? error.message : String(error)}`); - } -} \ No newline at end of file +export { apifyLoginCommand } from "./login.ts"; +export { apifyStatusCommand } from "./status.ts"; +export { apifyTestCommand } from "./test.ts"; diff --git a/src/commands/login.ts b/src/commands/login.ts new file mode 100644 index 0000000..78b0f30 --- /dev/null +++ b/src/commands/login.ts @@ -0,0 +1,55 @@ +import type { ExtensionContext } from "@earendil-works/pi-coding-agent"; +import { createClient, testConnectivity } from "../utils/client.ts"; +import { loadConfig, writeGlobalConfig } from "../utils/config.ts"; +import { normalizeSecretInput, fingerprintKey } from "../security/index.ts"; + +/** + * Handle /apify login command. + * Interactive key configuration with masked input. + */ +export async function apifyLoginCommand(ctx: ExtensionContext): Promise { + try { + // Prompt for API key + ctx.ui.notify("Please enter your Apify API key:"); + ctx.ui.notify("You can find your API key at: https://console.apify.com/account/integrations"); + + // Note: The ui.input method doesn't support password masking in Pi's current API + // The user will need to paste their key in plain text + const keyInput = await ctx.ui.input("Apify API key:", "paste your API key here"); + + if (!keyInput || !keyInput.trim()) { + ctx.ui.notify("No API key provided. Login cancelled."); + return; + } + + // Normalize the key + const apiKey = normalizeSecretInput(keyInput); + + // Test the key + ctx.ui.notify("Validating API key..."); + const client = createClient({ apiKey }); + + if (!client) { + ctx.ui.notify("Failed to create Apify client. Please check your API key."); + return; + } + + const result = await testConnectivity(client); + + if (result.success) { + // Save the key to global config + const config = loadConfig(); + config.apiKey = apiKey; + config.enabled = true; // Auto-enable + writeGlobalConfig(config); + + ctx.ui.notify(`✅ Authenticated as ${result.userId} (${result.plan} plan).`); + ctx.ui.notify(`Key saved to ~/.pi/agent/apify.json (fingerprint: ${fingerprintKey(apiKey)})`); + } else { + ctx.ui.notify(`❌ Authentication failed: ${result.error}`); + ctx.ui.notify("Please check your API key and try again."); + } + } catch (error) { + ctx.ui.notify(`Error during login: ${error instanceof Error ? error.message : String(error)}`); + } +} diff --git a/src/commands/status.ts b/src/commands/status.ts new file mode 100644 index 0000000..00e3df9 --- /dev/null +++ b/src/commands/status.ts @@ -0,0 +1,61 @@ +import type { ExtensionContext } from "@earendil-works/pi-coding-agent"; +import { createClient, testConnectivity } from "../utils/client.ts"; +import { loadConfig, resolveApiKey } from "../utils/config.ts"; +import { fingerprintKey } from "../security/index.ts"; + +/** + * Handle /apify status command. + * Show current configuration and authentication status. + */ +export async function apifyStatusCommand(_args: string, ctx: ExtensionContext): Promise { + try { + const config = loadConfig(); + + // Check if configured + const apiKey = resolveApiKey(config); + if (!apiKey) { + ctx.ui.notify("❌ Apify not configured. Run /apify login to set up your API key."); + ctx.ui.notify("You can also set the APIFY_API_KEY environment variable."); + return; + } + + // Test connectivity + ctx.ui.notify("Checking Apify connection..."); + const client = createClient(config); + + if (!client) { + ctx.ui.notify("Failed to create Apify client."); + return; + } + + const result = await testConnectivity(client); + + if (result.success) { + ctx.ui.notify(`✅ Authenticated as ${result.userId} (${result.plan} plan)`); + ctx.ui.notify(`Key fingerprint: ${fingerprintKey(apiKey)}`); + } else { + ctx.ui.notify(`⚠️ Authentication failed: ${result.error}`); + ctx.ui.notify(`Key fingerprint: ${fingerprintKey(apiKey)}`); + } + + // Show enabled status + if (config.enabled === false) { + ctx.ui.notify("⚠️ Apify integration is disabled in config"); + } else { + ctx.ui.notify("✅ Apify integration is enabled"); + } + + // Show enabled tools + if (config.enabledTools) { + ctx.ui.notify(`Enabled actions: ${config.enabledTools.join(", ")}`); + } else { + ctx.ui.notify("All actions enabled: discover, start, collect"); + } + + // Show other config + ctx.ui.notify(`Base URL: ${config.baseUrl || "https://api.apify.com"}`); + ctx.ui.notify(`Max results: ${config.maxResults || 50000} chars`); + } catch (error) { + ctx.ui.notify(`Error checking status: ${error instanceof Error ? error.message : String(error)}`); + } +} diff --git a/src/commands/test.ts b/src/commands/test.ts new file mode 100644 index 0000000..a13b286 --- /dev/null +++ b/src/commands/test.ts @@ -0,0 +1,72 @@ +import type { ExtensionContext } from "@earendil-works/pi-coding-agent"; +import { createClient, testConnectivity } from "../utils/client.ts"; +import { loadConfig, resolveApiKey } from "../utils/config.ts"; + +/** + * Handle /apify test command. + * Test connectivity and optionally run a simple actor. + */ +export async function apifyTestCommand(_args: string, ctx: ExtensionContext): Promise { + try { + const config = loadConfig(); + + // Check if configured + const apiKey = resolveApiKey(config); + if (!apiKey) { + ctx.ui.notify("❌ Apify not configured. Run /apify login first."); + return; + } + + // Test basic connectivity + ctx.ui.notify("Testing Apify connection..."); + const client = createClient(config); + + if (!client) { + ctx.ui.notify("Failed to create Apify client."); + return; + } + + const result = await testConnectivity(client); + + if (!result.success) { + ctx.ui.notify(`❌ Connection failed: ${result.error}`); + return; + } + + ctx.ui.notify(`✅ Connected as ${result.userId} (${result.plan} plan)`); + + // Optionally test a simple actor run + ctx.ui.notify("\nTesting actor run with a minimal example..."); + try { + // Use a simple, fast actor for testing + const testActor = "apify~web-scraper"; + const testInput = { + startUrls: [{ url: "https://example.com" }], + maxRequestsPerCrawl: 1, + maxRequestRetries: 0, + maxCrawlDepth: 0, + keepUrlFragments: false, + }; + + ctx.ui.notify(`Starting test run of ${testActor}...`); + const run = await client.actor(testActor).start(testInput, { waitForFinish: 60 }); // Wait max 60 seconds + + if (run.status === "SUCCEEDED") { + const dataset = await client.dataset(run.defaultDatasetId).listItems({ limit: 1 }); + ctx.ui.notify(`✅ Test run succeeded! Got ${dataset.items?.length || 0} results.`); + ctx.ui.notify(`Run ID: ${run.id}`); + ctx.ui.notify(`Duration: ${run.stats?.durationMillis || 0}ms`); + } else { + ctx.ui.notify(`⚠️ Test run ended with status: ${run.status}`); + if (run.statusMessage) { + ctx.ui.notify(`Message: ${run.statusMessage}`); + } + } + } catch (runError) { + ctx.ui.notify(`⚠️ Test run failed: ${runError instanceof Error ? runError.message : String(runError)}`); + ctx.ui.notify("Basic connectivity works, but actor execution may have issues."); + } + } catch (error) { + ctx.ui.notify(`Error during test: ${error instanceof Error ? error.message : String(error)}`); + } +} diff --git a/src/security/index.ts b/src/security/index.ts new file mode 100644 index 0000000..e03f55c --- /dev/null +++ b/src/security/index.ts @@ -0,0 +1,2 @@ +export * from "./normalize.ts"; +export * from "./wrap.ts"; diff --git a/src/utils/normalize.ts b/src/security/normalize.ts similarity index 100% rename from src/utils/normalize.ts rename to src/security/normalize.ts diff --git a/src/utils/wrap.ts b/src/security/wrap.ts similarity index 98% rename from src/utils/wrap.ts rename to src/security/wrap.ts index d0e6eca..d53dfcd 100644 --- a/src/utils/wrap.ts +++ b/src/security/wrap.ts @@ -1,4 +1,4 @@ -import { EXTERNAL_CONTENT_START, EXTERNAL_CONTENT_END, MAX_RESULT_CHARS } from "./constants.ts"; +import { EXTERNAL_CONTENT_START, EXTERNAL_CONTENT_END, MAX_RESULT_CHARS } from "../utils/constants.ts"; /** * Sanitize content to prevent marker collision. diff --git a/src/utils/client.ts b/src/utils/client.ts index 43618a2..413a544 100644 --- a/src/utils/client.ts +++ b/src/utils/client.ts @@ -1,6 +1,6 @@ import { ApifyClient } from "apify-client"; import type { ApifyConfig } from "./config.ts"; -import { normalizeSecretInput } from "./normalize.ts"; +import { normalizeSecretInput } from "../security/index.ts"; import { resolveApiKey } from "./config.ts"; /** diff --git a/src/types/index.ts b/src/utils/types.ts similarity index 100% rename from src/types/index.ts rename to src/utils/types.ts diff --git a/test-structure.js b/test-structure.js index 62556dd..a16ad0d 100644 --- a/test-structure.js +++ b/test-structure.js @@ -42,14 +42,23 @@ try { console.log('3. Checking required files...'); const requiredFiles = [ 'index.ts', - 'tool.ts', - 'execute.ts', - 'commands.ts', - 'config.ts', - 'client.ts', - 'constants.ts', - 'wrap.ts', - 'normalize.ts', + 'src/tool.ts', + 'src/actions/index.ts', + 'src/actions/execute.ts', + 'src/actions/discover.ts', + 'src/actions/start.ts', + 'src/actions/collect.ts', + 'src/commands/index.ts', + 'src/commands/login.ts', + 'src/commands/status.ts', + 'src/commands/test.ts', + 'src/security/index.ts', + 'src/security/normalize.ts', + 'src/security/wrap.ts', + 'src/utils/config.ts', + 'src/utils/client.ts', + 'src/utils/constants.ts', + 'src/utils/types.ts', 'tsconfig.json', 'README.md' ];