acpx 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/{cli-Bf3yjqzE.js → cli-8dP_TqBp.js} +4 -4
- package/dist/{cli-Bf3yjqzE.js.map → cli-8dP_TqBp.js.map} +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +392 -12
- package/dist/cli.js.map +1 -1
- package/dist/{client-BssohYqM.d.ts → client-C4iJBO0j.d.ts} +2 -2
- package/dist/{client-BssohYqM.d.ts.map → client-C4iJBO0j.d.ts.map} +1 -1
- package/dist/{flags-C-rwARqg.js → flags--2oX_ubW.js} +3 -3
- package/dist/flags--2oX_ubW.js.map +1 -0
- package/dist/{flows-WLs26_5Y.js → flows-e4umXVbY.js} +4 -4
- package/dist/{flows-WLs26_5Y.js.map → flows-e4umXVbY.js.map} +1 -1
- package/dist/flows.d.ts +1 -1
- package/dist/flows.js +1 -1
- package/dist/{live-checkpoint-D5d-K9s1.js → live-checkpoint-CuFft_Nd.js} +300 -272
- package/dist/live-checkpoint-CuFft_Nd.js.map +1 -0
- package/dist/{output-DPg20dvn.js → output-Di77Yugq.js} +12 -12
- package/dist/{output-DPg20dvn.js.map → output-Di77Yugq.js.map} +1 -1
- package/dist/runtime.d.ts +2 -2
- package/dist/runtime.js +1 -1
- package/dist/{session-options-CFudjdkU.d.ts → session-options-Bh1bIqQ2.d.ts} +8 -1
- package/dist/{session-options-CFudjdkU.d.ts.map → session-options-Bh1bIqQ2.d.ts.map} +1 -1
- package/package.json +7 -1
- package/skills/acpx/SKILL.md +11 -2
- package/dist/flags-C-rwARqg.js.map +0 -1
- package/dist/live-checkpoint-D5d-K9s1.js.map +0 -1
package/README.md
CHANGED
|
@@ -33,6 +33,7 @@ One command surface for Pi, OpenClaw ACP, Codex, Claude, and other ACP-compatibl
|
|
|
33
33
|
- **Prompt from file/stdin**: `--file <path>` or piped stdin for prompt content
|
|
34
34
|
- **Config files**: global + project JSON config with `acpx config show|init`
|
|
35
35
|
- **Session inspect/history**: `sessions show` and `sessions history --limit <n>`
|
|
36
|
+
- **Session export/import**: move portable session archives between machines
|
|
36
37
|
- **Local status checks**: `status` reports running/idle/dead/no-session, pid, uptime, last prompt
|
|
37
38
|
- **Client methods**: stable `fs/*` and `terminal/*` handlers with permission controls and cwd sandboxing
|
|
38
39
|
- **Auth handshake**: stable `authenticate` support via env/config credentials
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { _ as resolveOutputPolicy, a as hasExplicitPermissionModeFlag, b as loadPermissionPolicySpec, g as resolveGlobalFlags, h as resolveAgentInvocation, v as resolvePermissionMode } from "./flags
|
|
3
|
-
import { c as validateFlowDefinition, h as isDefinedFlow, o as FlowRunner } from "./flows-
|
|
1
|
+
import { D as permissionModeSatisfies } from "./live-checkpoint-CuFft_Nd.js";
|
|
2
|
+
import { _ as resolveOutputPolicy, a as hasExplicitPermissionModeFlag, b as loadPermissionPolicySpec, g as resolveGlobalFlags, h as resolveAgentInvocation, v as resolvePermissionMode } from "./flags--2oX_ubW.js";
|
|
3
|
+
import { c as validateFlowDefinition, h as isDefinedFlow, o as FlowRunner } from "./flows-e4umXVbY.js";
|
|
4
4
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { InvalidArgumentError } from "commander";
|
|
@@ -194,4 +194,4 @@ function printFlowRunResult(result, globalFlags) {
|
|
|
194
194
|
//#endregion
|
|
195
195
|
export { handleFlowRun };
|
|
196
196
|
|
|
197
|
-
//# sourceMappingURL=cli-
|
|
197
|
+
//# sourceMappingURL=cli-8dP_TqBp.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-Bf3yjqzE.js","names":[],"sources":["../src/flows/cli.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { fileURLToPath, pathToFileURL } from \"node:url\";\nimport { InvalidArgumentError, type Command } from \"commander\";\nimport type { ResolvedAcpxConfig } from \"../cli/config.js\";\nimport {\n hasExplicitPermissionModeFlag,\n resolveAgentInvocation,\n resolveGlobalFlags,\n resolveOutputPolicy,\n resolvePermissionMode,\n type GlobalFlags,\n} from \"../cli/flags.js\";\nimport { type FlowDefinition, FlowRunner } from \"../flows.js\";\nimport { loadPermissionPolicySpec } from \"../permission-policy.js\";\nimport { permissionModeSatisfies } from \"../permissions.js\";\nimport type { PermissionMode } from \"../types.js\";\nimport { isDefinedFlow } from \"./authoring.js\";\nimport { validateFlowDefinition } from \"./graph.js\";\n\ntype FlowRunFlags = {\n inputJson?: string;\n inputFile?: string;\n defaultAgent?: string;\n};\n\nconst FLOW_RUNTIME_SPECIFIER = \"acpx/flows\";\nconst TEXT_MODULE_EXTENSIONS = new Set([\".js\", \".mjs\", \".cjs\", \".ts\", \".tsx\", \".mts\", \".cts\"]);\n\nexport async function handleFlowRun(\n flowFile: string,\n flags: FlowRunFlags,\n command: Command,\n config: ResolvedAcpxConfig,\n): Promise<void> {\n const globalFlags = resolveGlobalFlags(command, config);\n const permissionMode = resolvePermissionMode(globalFlags, config.defaultPermissions);\n const permissionPolicy = await resolveFlowPermissionPolicy(globalFlags);\n const outputPolicy = resolveOutputPolicy(globalFlags.format, globalFlags.jsonStrict === true);\n const input = await readFlowInput(flags);\n const flowPath = path.resolve(flowFile);\n const flow = await loadFlowModule(flowPath);\n assertFlowPermissionRequirements(flow, permissionMode, globalFlags);\n\n const runner = new FlowRunner({\n resolveAgent: (profile?: string) => {\n return resolveAgentInvocation(profile ?? flags.defaultAgent, globalFlags, config);\n },\n permissionMode,\n mcpServers: config.mcpServers,\n nonInteractivePermissions: globalFlags.nonInteractivePermissions,\n permissionPolicy,\n authCredentials: config.auth,\n authPolicy: globalFlags.authPolicy,\n timeoutMs: globalFlags.timeout,\n ttlMs: globalFlags.ttl,\n verbose: globalFlags.verbose,\n suppressSdkConsoleErrors: outputPolicy.suppressSdkConsoleErrors,\n sessionOptions: {\n model: globalFlags.model,\n allowedTools: globalFlags.allowedTools,\n maxTurns: globalFlags.maxTurns,\n },\n });\n\n const result = await runner.run(flow, input, {\n flowPath,\n });\n\n printFlowRunResult(result, globalFlags);\n}\n\nasync function resolveFlowPermissionPolicy(globalFlags: GlobalFlags) {\n try {\n return await loadPermissionPolicySpec(globalFlags.permissionPolicy, globalFlags.cwd);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new InvalidArgumentError(`Invalid permission policy: ${message}`);\n }\n}\n\nfunction assertFlowPermissionRequirements(\n flow: FlowDefinition,\n permissionMode: PermissionMode,\n globalFlags: GlobalFlags,\n): void {\n const permissions = flow.permissions;\n if (!permissions) {\n return;\n }\n\n if (permissions.requireExplicitGrant && !hasExplicitPermissionModeFlag(globalFlags)) {\n throw new InvalidArgumentError(\n buildFlowPermissionFailureMessage(flow, permissions.requiredMode, permissions.reason, true),\n );\n }\n\n if (!permissionModeSatisfies(permissionMode, permissions.requiredMode)) {\n throw new InvalidArgumentError(\n buildFlowPermissionFailureMessage(flow, permissions.requiredMode, permissions.reason, false),\n );\n }\n}\n\nfunction buildFlowPermissionFailureMessage(\n flow: FlowDefinition,\n requiredMode: PermissionMode,\n reason?: string,\n explicit = false,\n): string {\n return [\n explicit\n ? `Flow \"${flow.name}\" requires an explicit ${requiredMode} grant.`\n : `Flow \"${flow.name}\" requires permission mode ${requiredMode}.`,\n `Rerun with --${requiredMode}.`,\n ...(reason ? [`Reason: ${reason}`] : []),\n ].join(\" \");\n}\n\nasync function readFlowInput(flags: FlowRunFlags): Promise<unknown> {\n if (flags.inputJson && flags.inputFile) {\n throw new InvalidArgumentError(\"Use only one of --input-json or --input-file\");\n }\n\n if (flags.inputJson) {\n return parseJsonInput(flags.inputJson, \"--input-json\");\n }\n\n if (flags.inputFile) {\n const inputPath = path.resolve(flags.inputFile);\n const payload = await fs.readFile(inputPath, \"utf8\");\n return parseJsonInput(payload, \"--input-file\");\n }\n\n return {};\n}\n\nasync function loadFlowModule(flowPath: string): Promise<FlowDefinition> {\n const extension = path.extname(flowPath).toLowerCase();\n const prepared = await prepareFlowModuleImport(flowPath, extension);\n try {\n const module = await loadFlowRuntimeModule(prepared.flowUrl, extension);\n\n const candidate = findFlowDefinition(module);\n if (!candidate) {\n throw new Error(\n `Flow module must export default defineFlow({...}) from \"acpx/flows\": ${flowPath}`,\n );\n }\n validateFlowDefinition(candidate);\n return candidate;\n } finally {\n await prepared.cleanup?.();\n }\n}\n\nasync function prepareFlowModuleImport(\n flowPath: string,\n extension: string,\n): Promise<{\n flowUrl: string;\n cleanup?: () => Promise<void>;\n}> {\n const flowUrl = pathToFileURL(flowPath).href;\n if (!TEXT_MODULE_EXTENSIONS.has(extension)) {\n return { flowUrl };\n }\n\n const source = await fs.readFile(flowPath, \"utf8\");\n if (!source.includes(FLOW_RUNTIME_SPECIFIER)) {\n return { flowUrl };\n }\n\n const runtimeSpecifier = resolveFlowRuntimeImportSpecifier();\n const rewritten = source.replaceAll(\n /([\"'])acpx\\/flows\\1/g,\n (_match, quote: string) => `${quote}${runtimeSpecifier}${quote}`,\n );\n if (rewritten === source) {\n return { flowUrl };\n }\n\n const tempPath = path.join(path.dirname(flowPath), `.acpx-flow-load-${randomUUID()}${extension}`);\n await fs.writeFile(tempPath, rewritten, \"utf8\");\n return {\n flowUrl: pathToFileURL(tempPath).href,\n cleanup: async () => {\n await fs.rm(tempPath, { force: true });\n },\n };\n}\n\nfunction resolveFlowRuntimeImportSpecifier(): string {\n const selfPath = fileURLToPath(import.meta.url);\n let runtimePath: string;\n\n if (selfPath.endsWith(`${path.sep}src${path.sep}flows${path.sep}cli.ts`)) {\n runtimePath = fileURLToPath(new URL(\"../flows.ts\", import.meta.url));\n } else if (selfPath.endsWith(`${path.sep}src${path.sep}flows${path.sep}cli.js`)) {\n runtimePath = fileURLToPath(new URL(\"../flows.js\", import.meta.url));\n } else {\n runtimePath = fileURLToPath(new URL(\"./flows.js\", import.meta.url));\n }\n return runtimePath.replaceAll(path.sep, \"/\");\n}\n\nasync function loadFlowRuntimeModule(\n flowUrl: string,\n extension: string,\n): Promise<{\n default?: unknown;\n \"module.exports\"?: unknown;\n}> {\n if (extension === \".ts\" || extension === \".tsx\" || extension === \".cts\") {\n const { register } = (await import(\"tsx/cjs/api\")) as {\n register: (options: { namespace: string }) => {\n require: (\n specifier: string,\n parentURL: string,\n ) => {\n default?: unknown;\n \"module.exports\"?: unknown;\n };\n unregister: () => void;\n };\n };\n const loader = register({ namespace: randomUUID() });\n try {\n return loader.require(flowUrl, import.meta.url);\n } finally {\n loader.unregister();\n }\n }\n\n if (extension === \".mts\") {\n const { register } = (await import(\"tsx/esm/api\")) as {\n register: (options: { namespace: string }) => {\n import: (\n specifier: string,\n parentURL: string,\n ) => Promise<{\n default?: unknown;\n \"module.exports\"?: unknown;\n }>;\n unregister: () => Promise<void>;\n };\n };\n const loader = register({ namespace: randomUUID() });\n try {\n return (await loader.import(flowUrl, import.meta.url)) as {\n default?: unknown;\n \"module.exports\"?: unknown;\n };\n } finally {\n await loader.unregister();\n }\n }\n\n return (await import(flowUrl)) as {\n default?: unknown;\n \"module.exports\"?: unknown;\n };\n}\n\nfunction findFlowDefinition(module: {\n default?: unknown;\n \"module.exports\"?: unknown;\n}): FlowDefinition | null {\n const candidates = [\n module.default,\n module[\"module.exports\"],\n getNestedDefault(module.default),\n getNestedDefault(module[\"module.exports\"]),\n ];\n\n for (const candidate of candidates) {\n if (isDefinedFlow(candidate)) {\n return candidate;\n }\n }\n\n return null;\n}\n\nfunction getNestedDefault(value: unknown): unknown {\n if (!value || typeof value !== \"object\" || !(\"default\" in value)) {\n return null;\n }\n return (value as { default?: unknown }).default ?? null;\n}\n\nfunction parseJsonInput(raw: string, label: string): unknown {\n try {\n return JSON.parse(raw);\n } catch (error) {\n throw new InvalidArgumentError(\n `${label} must contain valid JSON: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n}\n\nfunction printFlowRunResult(\n result: Awaited<ReturnType<FlowRunner[\"run\"]>>,\n globalFlags: GlobalFlags,\n): void {\n const payload = {\n action: \"flow_run_result\",\n runId: result.state.runId,\n flowName: result.state.flowName,\n runTitle: result.state.runTitle,\n flowPath: result.state.flowPath,\n status: result.state.status,\n currentNode: result.state.currentNode,\n currentNodeType: result.state.currentNodeType,\n currentNodeStartedAt: result.state.currentNodeStartedAt,\n lastHeartbeatAt: result.state.lastHeartbeatAt,\n statusDetail: result.state.statusDetail,\n waitingOn: result.state.waitingOn,\n runDir: result.runDir,\n outputs: result.state.outputs,\n sessionBindings: result.state.sessionBindings,\n };\n\n if (globalFlags.format === \"json\") {\n process.stdout.write(`${JSON.stringify(payload)}\\n`);\n return;\n }\n\n if (globalFlags.format === \"quiet\") {\n process.stdout.write(`${result.state.runId}\\n`);\n return;\n }\n\n process.stdout.write(`runId: ${payload.runId}\\n`);\n process.stdout.write(`flow: ${payload.flowName}\\n`);\n if (payload.runTitle) {\n process.stdout.write(`title: ${payload.runTitle}\\n`);\n }\n process.stdout.write(`status: ${payload.status}\\n`);\n process.stdout.write(`runDir: ${payload.runDir}\\n`);\n if (payload.currentNode) {\n process.stdout.write(`currentNode: ${payload.currentNode}\\n`);\n }\n if (payload.statusDetail) {\n process.stdout.write(`statusDetail: ${payload.statusDetail}\\n`);\n }\n if (payload.waitingOn) {\n process.stdout.write(`waitingOn: ${payload.waitingOn}\\n`);\n }\n process.stdout.write(`${JSON.stringify(payload.outputs, null, 2)}\\n`);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cli-8dP_TqBp.js","names":[],"sources":["../src/flows/cli.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { fileURLToPath, pathToFileURL } from \"node:url\";\nimport { InvalidArgumentError, type Command } from \"commander\";\nimport type { ResolvedAcpxConfig } from \"../cli/config.js\";\nimport {\n hasExplicitPermissionModeFlag,\n resolveAgentInvocation,\n resolveGlobalFlags,\n resolveOutputPolicy,\n resolvePermissionMode,\n type GlobalFlags,\n} from \"../cli/flags.js\";\nimport { type FlowDefinition, FlowRunner } from \"../flows.js\";\nimport { loadPermissionPolicySpec } from \"../permission-policy.js\";\nimport { permissionModeSatisfies } from \"../permissions.js\";\nimport type { PermissionMode } from \"../types.js\";\nimport { isDefinedFlow } from \"./authoring.js\";\nimport { validateFlowDefinition } from \"./graph.js\";\n\ntype FlowRunFlags = {\n inputJson?: string;\n inputFile?: string;\n defaultAgent?: string;\n};\n\nconst FLOW_RUNTIME_SPECIFIER = \"acpx/flows\";\nconst TEXT_MODULE_EXTENSIONS = new Set([\".js\", \".mjs\", \".cjs\", \".ts\", \".tsx\", \".mts\", \".cts\"]);\n\nexport async function handleFlowRun(\n flowFile: string,\n flags: FlowRunFlags,\n command: Command,\n config: ResolvedAcpxConfig,\n): Promise<void> {\n const globalFlags = resolveGlobalFlags(command, config);\n const permissionMode = resolvePermissionMode(globalFlags, config.defaultPermissions);\n const permissionPolicy = await resolveFlowPermissionPolicy(globalFlags);\n const outputPolicy = resolveOutputPolicy(globalFlags.format, globalFlags.jsonStrict === true);\n const input = await readFlowInput(flags);\n const flowPath = path.resolve(flowFile);\n const flow = await loadFlowModule(flowPath);\n assertFlowPermissionRequirements(flow, permissionMode, globalFlags);\n\n const runner = new FlowRunner({\n resolveAgent: (profile?: string) => {\n return resolveAgentInvocation(profile ?? flags.defaultAgent, globalFlags, config);\n },\n permissionMode,\n mcpServers: config.mcpServers,\n nonInteractivePermissions: globalFlags.nonInteractivePermissions,\n permissionPolicy,\n authCredentials: config.auth,\n authPolicy: globalFlags.authPolicy,\n timeoutMs: globalFlags.timeout,\n ttlMs: globalFlags.ttl,\n verbose: globalFlags.verbose,\n suppressSdkConsoleErrors: outputPolicy.suppressSdkConsoleErrors,\n sessionOptions: {\n model: globalFlags.model,\n allowedTools: globalFlags.allowedTools,\n maxTurns: globalFlags.maxTurns,\n },\n });\n\n const result = await runner.run(flow, input, {\n flowPath,\n });\n\n printFlowRunResult(result, globalFlags);\n}\n\nasync function resolveFlowPermissionPolicy(globalFlags: GlobalFlags) {\n try {\n return await loadPermissionPolicySpec(globalFlags.permissionPolicy, globalFlags.cwd);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new InvalidArgumentError(`Invalid permission policy: ${message}`);\n }\n}\n\nfunction assertFlowPermissionRequirements(\n flow: FlowDefinition,\n permissionMode: PermissionMode,\n globalFlags: GlobalFlags,\n): void {\n const permissions = flow.permissions;\n if (!permissions) {\n return;\n }\n\n if (permissions.requireExplicitGrant && !hasExplicitPermissionModeFlag(globalFlags)) {\n throw new InvalidArgumentError(\n buildFlowPermissionFailureMessage(flow, permissions.requiredMode, permissions.reason, true),\n );\n }\n\n if (!permissionModeSatisfies(permissionMode, permissions.requiredMode)) {\n throw new InvalidArgumentError(\n buildFlowPermissionFailureMessage(flow, permissions.requiredMode, permissions.reason, false),\n );\n }\n}\n\nfunction buildFlowPermissionFailureMessage(\n flow: FlowDefinition,\n requiredMode: PermissionMode,\n reason?: string,\n explicit = false,\n): string {\n return [\n explicit\n ? `Flow \"${flow.name}\" requires an explicit ${requiredMode} grant.`\n : `Flow \"${flow.name}\" requires permission mode ${requiredMode}.`,\n `Rerun with --${requiredMode}.`,\n ...(reason ? [`Reason: ${reason}`] : []),\n ].join(\" \");\n}\n\nasync function readFlowInput(flags: FlowRunFlags): Promise<unknown> {\n if (flags.inputJson && flags.inputFile) {\n throw new InvalidArgumentError(\"Use only one of --input-json or --input-file\");\n }\n\n if (flags.inputJson) {\n return parseJsonInput(flags.inputJson, \"--input-json\");\n }\n\n if (flags.inputFile) {\n const inputPath = path.resolve(flags.inputFile);\n const payload = await fs.readFile(inputPath, \"utf8\");\n return parseJsonInput(payload, \"--input-file\");\n }\n\n return {};\n}\n\nasync function loadFlowModule(flowPath: string): Promise<FlowDefinition> {\n const extension = path.extname(flowPath).toLowerCase();\n const prepared = await prepareFlowModuleImport(flowPath, extension);\n try {\n const module = await loadFlowRuntimeModule(prepared.flowUrl, extension);\n\n const candidate = findFlowDefinition(module);\n if (!candidate) {\n throw new Error(\n `Flow module must export default defineFlow({...}) from \"acpx/flows\": ${flowPath}`,\n );\n }\n validateFlowDefinition(candidate);\n return candidate;\n } finally {\n await prepared.cleanup?.();\n }\n}\n\nasync function prepareFlowModuleImport(\n flowPath: string,\n extension: string,\n): Promise<{\n flowUrl: string;\n cleanup?: () => Promise<void>;\n}> {\n const flowUrl = pathToFileURL(flowPath).href;\n if (!TEXT_MODULE_EXTENSIONS.has(extension)) {\n return { flowUrl };\n }\n\n const source = await fs.readFile(flowPath, \"utf8\");\n if (!source.includes(FLOW_RUNTIME_SPECIFIER)) {\n return { flowUrl };\n }\n\n const runtimeSpecifier = resolveFlowRuntimeImportSpecifier();\n const rewritten = source.replaceAll(\n /([\"'])acpx\\/flows\\1/g,\n (_match, quote: string) => `${quote}${runtimeSpecifier}${quote}`,\n );\n if (rewritten === source) {\n return { flowUrl };\n }\n\n const tempPath = path.join(path.dirname(flowPath), `.acpx-flow-load-${randomUUID()}${extension}`);\n await fs.writeFile(tempPath, rewritten, \"utf8\");\n return {\n flowUrl: pathToFileURL(tempPath).href,\n cleanup: async () => {\n await fs.rm(tempPath, { force: true });\n },\n };\n}\n\nfunction resolveFlowRuntimeImportSpecifier(): string {\n const selfPath = fileURLToPath(import.meta.url);\n let runtimePath: string;\n\n if (selfPath.endsWith(`${path.sep}src${path.sep}flows${path.sep}cli.ts`)) {\n runtimePath = fileURLToPath(new URL(\"../flows.ts\", import.meta.url));\n } else if (selfPath.endsWith(`${path.sep}src${path.sep}flows${path.sep}cli.js`)) {\n runtimePath = fileURLToPath(new URL(\"../flows.js\", import.meta.url));\n } else {\n runtimePath = fileURLToPath(new URL(\"./flows.js\", import.meta.url));\n }\n return runtimePath.replaceAll(path.sep, \"/\");\n}\n\nasync function loadFlowRuntimeModule(\n flowUrl: string,\n extension: string,\n): Promise<{\n default?: unknown;\n \"module.exports\"?: unknown;\n}> {\n if (extension === \".ts\" || extension === \".tsx\" || extension === \".cts\") {\n const { register } = (await import(\"tsx/cjs/api\")) as {\n register: (options: { namespace: string }) => {\n require: (\n specifier: string,\n parentURL: string,\n ) => {\n default?: unknown;\n \"module.exports\"?: unknown;\n };\n unregister: () => void;\n };\n };\n const loader = register({ namespace: randomUUID() });\n try {\n return loader.require(flowUrl, import.meta.url);\n } finally {\n loader.unregister();\n }\n }\n\n if (extension === \".mts\") {\n const { register } = (await import(\"tsx/esm/api\")) as {\n register: (options: { namespace: string }) => {\n import: (\n specifier: string,\n parentURL: string,\n ) => Promise<{\n default?: unknown;\n \"module.exports\"?: unknown;\n }>;\n unregister: () => Promise<void>;\n };\n };\n const loader = register({ namespace: randomUUID() });\n try {\n return (await loader.import(flowUrl, import.meta.url)) as {\n default?: unknown;\n \"module.exports\"?: unknown;\n };\n } finally {\n await loader.unregister();\n }\n }\n\n return (await import(flowUrl)) as {\n default?: unknown;\n \"module.exports\"?: unknown;\n };\n}\n\nfunction findFlowDefinition(module: {\n default?: unknown;\n \"module.exports\"?: unknown;\n}): FlowDefinition | null {\n const candidates = [\n module.default,\n module[\"module.exports\"],\n getNestedDefault(module.default),\n getNestedDefault(module[\"module.exports\"]),\n ];\n\n for (const candidate of candidates) {\n if (isDefinedFlow(candidate)) {\n return candidate;\n }\n }\n\n return null;\n}\n\nfunction getNestedDefault(value: unknown): unknown {\n if (!value || typeof value !== \"object\" || !(\"default\" in value)) {\n return null;\n }\n return (value as { default?: unknown }).default ?? null;\n}\n\nfunction parseJsonInput(raw: string, label: string): unknown {\n try {\n return JSON.parse(raw);\n } catch (error) {\n throw new InvalidArgumentError(\n `${label} must contain valid JSON: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n}\n\nfunction printFlowRunResult(\n result: Awaited<ReturnType<FlowRunner[\"run\"]>>,\n globalFlags: GlobalFlags,\n): void {\n const payload = {\n action: \"flow_run_result\",\n runId: result.state.runId,\n flowName: result.state.flowName,\n runTitle: result.state.runTitle,\n flowPath: result.state.flowPath,\n status: result.state.status,\n currentNode: result.state.currentNode,\n currentNodeType: result.state.currentNodeType,\n currentNodeStartedAt: result.state.currentNodeStartedAt,\n lastHeartbeatAt: result.state.lastHeartbeatAt,\n statusDetail: result.state.statusDetail,\n waitingOn: result.state.waitingOn,\n runDir: result.runDir,\n outputs: result.state.outputs,\n sessionBindings: result.state.sessionBindings,\n };\n\n if (globalFlags.format === \"json\") {\n process.stdout.write(`${JSON.stringify(payload)}\\n`);\n return;\n }\n\n if (globalFlags.format === \"quiet\") {\n process.stdout.write(`${result.state.runId}\\n`);\n return;\n }\n\n process.stdout.write(`runId: ${payload.runId}\\n`);\n process.stdout.write(`flow: ${payload.flowName}\\n`);\n if (payload.runTitle) {\n process.stdout.write(`title: ${payload.runTitle}\\n`);\n }\n process.stdout.write(`status: ${payload.status}\\n`);\n process.stdout.write(`runDir: ${payload.runDir}\\n`);\n if (payload.currentNode) {\n process.stdout.write(`currentNode: ${payload.currentNode}\\n`);\n }\n if (payload.statusDetail) {\n process.stdout.write(`statusDetail: ${payload.statusDetail}\\n`);\n }\n if (payload.waitingOn) {\n process.stdout.write(`waitingOn: ${payload.waitingOn}\\n`);\n }\n process.stdout.write(`${JSON.stringify(payload.outputs, null, 2)}\\n`);\n}\n"],"mappings":"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"}
|
package/dist/cli.d.ts
CHANGED
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","names":[],"sources":["../src/cli/flags.ts","../src/cli/output/render.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"cli.d.ts","names":[],"sources":["../src/cli/flags.ts","../src/cli/output/render.ts"],"mappings":";;;;iBA4JgB,eAAA,CAAgB,KAAa;AAAA,iBAkD7B,iBAAA,CAAkB,KAAa;AAAA,iBAgB/B,aAAA,CAAc,KAAa;;;KC5MtC,uBAAA;AAAA,iBAwLW,6BAAA,CACd,MAAA,EAAQ,aAAA,EACR,UAAA,UACA,gBAAA,GAAkB,uBAA2C"}
|
package/dist/cli.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as runSessionQueueOwner, c as buildQueueOwnerArgOverride,
|
|
3
|
-
import { At as EXIT_CODES,
|
|
4
|
-
import { _ as resolveOutputPolicy, b as loadPermissionPolicySpec, c as parseHistoryLimit, d as parseOutputFormat$1, f as parsePruneBeforeDate, g as resolveGlobalFlags, h as resolveAgentInvocation, i as addSessionOption, l as parseMaxTurns, m as parseTtlSeconds, n as addPromptInputOption, o as parseAllowedTools, p as parseSessionName, r as addSessionNameOption, s as parseDaysOlderThan, t as addGlobalFlags, u as parseNonEmptyValue, v as resolvePermissionMode, y as resolveSessionNameFromFlags } from "./flags
|
|
2
|
+
import { a as runSessionQueueOwner, c as buildQueueOwnerArgOverride, g as __exportAll, h as isProcessAlive, l as flushPerfMetricsCapture, n as getTextErrorRemediationHints, p as probeQueueOwnerHealth, t as createOutputFormatter, u as installPerfMetricsCapture } from "./output-Di77Yugq.js";
|
|
3
|
+
import { $ as defaultSessionEventLog, A as findGitRepositoryRoot, At as EXIT_CODES, I as normalizeName, M as findSessionByDirectoryWalk, P as listSessions, Pt as OUTPUT_FORMATS, Rt as AcpxOperationalError, St as exitCodeForOutputErrorCode, Tt as normalizeOutputError, X as serializeSessionRecordForDisk, Y as parseSessionRecord, Z as normalizeRuntimeSessionId, at as isAcpJsonRpcMessage, bt as normalizeAgentName$1, ct as PromptInputValidationError, dt as parsePromptSource, j as findSession, mt as InterruptedError, nt as sessionEventLockPath, pt as textPrompt, rt as sessionEventSegmentPath, tt as sessionEventActivePath, ut as mergePromptSourceWithText, vt as DEFAULT_AGENT_NAME, yt as listBuiltInAgents, z as writeSessionRecord, zt as AgentSpawnError } from "./live-checkpoint-CuFft_Nd.js";
|
|
4
|
+
import { _ as resolveOutputPolicy, b as loadPermissionPolicySpec, c as parseHistoryLimit, d as parseOutputFormat$1, f as parsePruneBeforeDate, g as resolveGlobalFlags, h as resolveAgentInvocation, i as addSessionOption, l as parseMaxTurns, m as parseTtlSeconds, n as addPromptInputOption, o as parseAllowedTools, p as parseSessionName, r as addSessionNameOption, s as parseDaysOlderThan, t as addGlobalFlags, u as parseNonEmptyValue, v as resolvePermissionMode, y as resolveSessionNameFromFlags } from "./flags--2oX_ubW.js";
|
|
5
5
|
import { readFileSync, realpathSync } from "node:fs";
|
|
6
6
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
7
7
|
import path from "node:path";
|
|
8
|
-
import { Command, CommanderError, InvalidArgumentError } from "commander";
|
|
8
|
+
import { Command, CommanderError, InvalidArgumentError, Option } from "commander";
|
|
9
9
|
import fs$1 from "node:fs/promises";
|
|
10
10
|
import os from "node:os";
|
|
11
|
+
import { randomUUID } from "node:crypto";
|
|
12
|
+
import { ZodError, z } from "zod";
|
|
11
13
|
//#region src/cli-public.ts
|
|
12
14
|
function configurePublicCli(options) {
|
|
13
15
|
const builtInAgents = options.listBuiltInAgents(options.config.agents);
|
|
@@ -53,6 +55,319 @@ function isLegacyZedCodexAcpInvocation(agentCommand) {
|
|
|
53
55
|
return /@zed-industries\/codex-acp\b/u.test(agentCommand);
|
|
54
56
|
}
|
|
55
57
|
//#endregion
|
|
58
|
+
//#region src/session/export.ts
|
|
59
|
+
var SessionExportError = class extends AcpxOperationalError {
|
|
60
|
+
code;
|
|
61
|
+
exitCode = 2;
|
|
62
|
+
constructor(message, code) {
|
|
63
|
+
super(message, {
|
|
64
|
+
outputCode: "USAGE",
|
|
65
|
+
detailCode: code,
|
|
66
|
+
origin: "cli"
|
|
67
|
+
});
|
|
68
|
+
this.code = code;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
function sessionLookupError(message, code) {
|
|
72
|
+
return new SessionExportError(message, code);
|
|
73
|
+
}
|
|
74
|
+
async function loadSessionRecord(sessionLookup) {
|
|
75
|
+
const cwd = path.resolve(sessionLookup.cwd ?? process.cwd());
|
|
76
|
+
const name = normalizeName(sessionLookup.name);
|
|
77
|
+
if (sessionLookup.agentCommand) {
|
|
78
|
+
const active = await findSession({
|
|
79
|
+
agentCommand: sessionLookup.agentCommand,
|
|
80
|
+
cwd,
|
|
81
|
+
name
|
|
82
|
+
});
|
|
83
|
+
if (active) return active;
|
|
84
|
+
return (await listSessions()).find((session) => {
|
|
85
|
+
if (session.agentCommand !== sessionLookup.agentCommand || session.cwd !== cwd) return false;
|
|
86
|
+
if (name == null) return session.name == null;
|
|
87
|
+
return session.name === name;
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
const matches = (await listSessions()).filter((session) => {
|
|
91
|
+
if (session.cwd !== cwd) return false;
|
|
92
|
+
if (name == null) return session.name == null;
|
|
93
|
+
return session.name === name;
|
|
94
|
+
});
|
|
95
|
+
if (matches.length > 1) throw sessionLookupError("multiple sessions match export lookup", "ambiguous-session");
|
|
96
|
+
return matches[0];
|
|
97
|
+
}
|
|
98
|
+
function parseEventLockPayload(raw) {
|
|
99
|
+
try {
|
|
100
|
+
const parsed = JSON.parse(raw);
|
|
101
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
|
102
|
+
const record = parsed;
|
|
103
|
+
return { pid: typeof record.pid === "number" ? record.pid : void 0 };
|
|
104
|
+
} catch {
|
|
105
|
+
return {};
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
async function hasLiveEventLock(recordId) {
|
|
109
|
+
try {
|
|
110
|
+
return isProcessAlive(parseEventLockPayload(await fs$1.readFile(sessionEventLockPath(recordId), "utf8")).pid);
|
|
111
|
+
} catch (error) {
|
|
112
|
+
if (error.code === "ENOENT") return false;
|
|
113
|
+
throw error;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
async function isSessionActive(record) {
|
|
117
|
+
if (record.closed) return false;
|
|
118
|
+
return isProcessAlive(record.pid) || await hasLiveEventLock(record.acpxRecordId);
|
|
119
|
+
}
|
|
120
|
+
async function readHistoryFile(filePath) {
|
|
121
|
+
const payload = await fs$1.readFile(filePath, "utf8").catch((error) => {
|
|
122
|
+
if (error.code === "ENOENT") return "";
|
|
123
|
+
throw error;
|
|
124
|
+
});
|
|
125
|
+
const history = [];
|
|
126
|
+
for (const line of payload.split("\n").filter((entry) => entry.trim().length > 0)) try {
|
|
127
|
+
const parsed = JSON.parse(line);
|
|
128
|
+
if (isAcpJsonRpcMessage(parsed)) history.push(parsed);
|
|
129
|
+
} catch {}
|
|
130
|
+
return history;
|
|
131
|
+
}
|
|
132
|
+
async function readSessionHistory(record) {
|
|
133
|
+
const history = [];
|
|
134
|
+
const maxSegments = Number.isInteger(record.eventLog.max_segments) ? record.eventLog.max_segments : 0;
|
|
135
|
+
for (let segment = maxSegments; segment >= 1; segment -= 1) history.push(...await readHistoryFile(sessionEventSegmentPath(record.acpxRecordId, segment)));
|
|
136
|
+
history.push(...await readHistoryFile(sessionEventActivePath(record.acpxRecordId)));
|
|
137
|
+
return history;
|
|
138
|
+
}
|
|
139
|
+
function cwdRelativeToHome(cwd, home) {
|
|
140
|
+
const relative = path.relative(home, cwd);
|
|
141
|
+
if (relative.length === 0) return ".";
|
|
142
|
+
if (relative.length > 0 && !relative.startsWith("..") && !path.isAbsolute(relative)) return relative;
|
|
143
|
+
return cwd;
|
|
144
|
+
}
|
|
145
|
+
function serializeSessionRecordForArchive(record, cwdRelative) {
|
|
146
|
+
const state = serializeSessionRecordForDisk(record);
|
|
147
|
+
state.cwd = cwdRelative;
|
|
148
|
+
if (state.event_log && typeof state.event_log === "object" && !Array.isArray(state.event_log)) state.event_log = {
|
|
149
|
+
...state.event_log,
|
|
150
|
+
active_path: ".stream.ndjson"
|
|
151
|
+
};
|
|
152
|
+
return state;
|
|
153
|
+
}
|
|
154
|
+
async function exportSession(sessionLookup, outputPath) {
|
|
155
|
+
const record = await loadSessionRecord(sessionLookup);
|
|
156
|
+
if (!record) throw sessionLookupError("session not found", "not-found");
|
|
157
|
+
if (await isSessionActive(record)) throw sessionLookupError("session is currently locked by a running queue owner; close it first with `acpx sessions close`", "session-locked");
|
|
158
|
+
const home = os.homedir();
|
|
159
|
+
const cwdRelative = cwdRelativeToHome(record.cwd, home);
|
|
160
|
+
const exported = {
|
|
161
|
+
format_version: 1,
|
|
162
|
+
exported_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
163
|
+
exported_by: "acpx",
|
|
164
|
+
session: {
|
|
165
|
+
record_id: record.acpxRecordId,
|
|
166
|
+
name: record.name ?? null,
|
|
167
|
+
agent: record.agentCommand,
|
|
168
|
+
agent_name: normalizeAgentName(sessionLookup.agentName),
|
|
169
|
+
cwd_relative: cwdRelative,
|
|
170
|
+
cwd_original: cwdRelative,
|
|
171
|
+
created_at: record.createdAt,
|
|
172
|
+
updated_at: record.lastUsedAt,
|
|
173
|
+
state: serializeSessionRecordForArchive(record, cwdRelative)
|
|
174
|
+
},
|
|
175
|
+
history: await readSessionHistory(record)
|
|
176
|
+
};
|
|
177
|
+
await fs$1.mkdir(path.dirname(path.resolve(outputPath)), { recursive: true });
|
|
178
|
+
await fs$1.writeFile(outputPath, `${JSON.stringify(exported, null, 2)}\n`, "utf8");
|
|
179
|
+
}
|
|
180
|
+
function normalizeAgentName(agentName) {
|
|
181
|
+
const normalized = agentName?.trim().toLowerCase();
|
|
182
|
+
if (!normalized || normalized.length === 0) return;
|
|
183
|
+
return normalized === "factory-droid" || normalized === "factorydroid" ? "droid" : normalized;
|
|
184
|
+
}
|
|
185
|
+
//#endregion
|
|
186
|
+
//#region src/session/import.ts
|
|
187
|
+
const SUPPORTED_FORMAT_VERSION = 1;
|
|
188
|
+
const exportedSessionSchema = z.object({
|
|
189
|
+
format_version: z.literal(SUPPORTED_FORMAT_VERSION),
|
|
190
|
+
exported_at: z.string(),
|
|
191
|
+
exported_by: z.string(),
|
|
192
|
+
session: z.object({
|
|
193
|
+
record_id: z.string(),
|
|
194
|
+
name: z.string().nullable(),
|
|
195
|
+
agent: z.string(),
|
|
196
|
+
agent_name: z.string().optional(),
|
|
197
|
+
cwd_relative: z.string(),
|
|
198
|
+
cwd_original: z.string().optional(),
|
|
199
|
+
cwd_absolute_original: z.string().optional(),
|
|
200
|
+
created_at: z.string(),
|
|
201
|
+
updated_at: z.string(),
|
|
202
|
+
state: z.unknown()
|
|
203
|
+
}),
|
|
204
|
+
history: z.array(z.unknown())
|
|
205
|
+
});
|
|
206
|
+
var SessionImportError = class extends AcpxOperationalError {
|
|
207
|
+
code;
|
|
208
|
+
exitCode = 2;
|
|
209
|
+
constructor(message, code) {
|
|
210
|
+
super(message, {
|
|
211
|
+
outputCode: "USAGE",
|
|
212
|
+
detailCode: code,
|
|
213
|
+
origin: "cli"
|
|
214
|
+
});
|
|
215
|
+
this.code = code;
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
function importError(message, code) {
|
|
219
|
+
return new SessionImportError(message, code);
|
|
220
|
+
}
|
|
221
|
+
function parseArchiveJson(raw) {
|
|
222
|
+
try {
|
|
223
|
+
return JSON.parse(raw);
|
|
224
|
+
} catch (error) {
|
|
225
|
+
throw importError(`Invalid session export archive JSON: ${error instanceof Error ? error.message : String(error)}`, "invalid-archive");
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
function assertSupportedFormatVersion(parsed) {
|
|
229
|
+
const record = parsed && typeof parsed === "object" ? parsed : {};
|
|
230
|
+
if (record.format_version !== SUPPORTED_FORMAT_VERSION) throw importError(`Unsupported session export format_version ${String(record.format_version)}; supported version is ${SUPPORTED_FORMAT_VERSION}`, "unsupported-format-version");
|
|
231
|
+
}
|
|
232
|
+
function parseArchive(raw) {
|
|
233
|
+
const parsed = parseArchiveJson(raw);
|
|
234
|
+
assertSupportedFormatVersion(parsed);
|
|
235
|
+
try {
|
|
236
|
+
return exportedSessionSchema.parse(parsed);
|
|
237
|
+
} catch (error) {
|
|
238
|
+
if (error instanceof ZodError) throw importError(`Invalid session export archive: ${error.issues[0]?.message}`, "invalid-archive");
|
|
239
|
+
throw error;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
async function generateRecordId(sessionsDir) {
|
|
243
|
+
for (;;) {
|
|
244
|
+
const recordId = randomUUID();
|
|
245
|
+
const filePath = path.join(sessionsDir, `${encodeURIComponent(recordId)}.json`);
|
|
246
|
+
try {
|
|
247
|
+
await fs$1.access(filePath);
|
|
248
|
+
} catch (error) {
|
|
249
|
+
if (error.code === "ENOENT") return recordId;
|
|
250
|
+
throw error;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
function resolveImportedCwd(cwdRelative, newCwd) {
|
|
255
|
+
if (newCwd) return path.resolve(newCwd);
|
|
256
|
+
if (path.isAbsolute(cwdRelative)) return cwdRelative;
|
|
257
|
+
return path.join(os.homedir(), cwdRelative);
|
|
258
|
+
}
|
|
259
|
+
function resolveImportedName(parsed, requestedName) {
|
|
260
|
+
return requestedName ?? parsed.session.name ?? void 0;
|
|
261
|
+
}
|
|
262
|
+
function assertExpectedAgentCommand(parsed, sourceRecord, options) {
|
|
263
|
+
const expectedAgentCommand = options.expectedAgentCommand;
|
|
264
|
+
if (!expectedAgentCommand) return;
|
|
265
|
+
const expectedAgentName = normalizeAgentIdentity(options.expectedAgentName);
|
|
266
|
+
const archiveAgentName = normalizeAgentIdentity(parsed.session.agent_name);
|
|
267
|
+
const archiveCommandMatches = agentCommandMatchesExpected(parsed.session.agent, expectedAgentCommand, expectedAgentName);
|
|
268
|
+
const stateCommandMatches = agentCommandMatchesExpected(sourceRecord.agentCommand, expectedAgentCommand, expectedAgentName);
|
|
269
|
+
if (archiveCommandMatches && stateCommandMatches && archiveAgentNameMatches({
|
|
270
|
+
archiveAgentName,
|
|
271
|
+
expectedAgentName,
|
|
272
|
+
archiveCommand: parsed.session.agent,
|
|
273
|
+
stateCommand: sourceRecord.agentCommand,
|
|
274
|
+
expectedAgentCommand
|
|
275
|
+
})) {
|
|
276
|
+
sourceRecord.agentCommand = expectedAgentCommand;
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
throw importError("Session export archive agent does not match the requested agent", "agent-mismatch");
|
|
280
|
+
}
|
|
281
|
+
function archiveAgentNameMatches(params) {
|
|
282
|
+
if (params.archiveCommand === params.expectedAgentCommand && params.stateCommand === params.expectedAgentCommand) return true;
|
|
283
|
+
return params.archiveAgentName == null || params.expectedAgentName == null || params.archiveAgentName === params.expectedAgentName;
|
|
284
|
+
}
|
|
285
|
+
function normalizeAgentIdentity(agentName) {
|
|
286
|
+
const normalized = agentName?.trim().toLowerCase();
|
|
287
|
+
if (!normalized || normalized.length === 0) return;
|
|
288
|
+
return normalized === "factory-droid" || normalized === "factorydroid" ? "droid" : normalized;
|
|
289
|
+
}
|
|
290
|
+
function agentCommandMatchesExpected(archivedCommand, expectedAgentCommand, expectedAgentName) {
|
|
291
|
+
if (archivedCommand === expectedAgentCommand) return true;
|
|
292
|
+
return expectedAgentName ? commandLooksLikeBuiltInAgent(archivedCommand, expectedAgentName) : false;
|
|
293
|
+
}
|
|
294
|
+
function commandLooksLikeBuiltInAgent(command, agentName) {
|
|
295
|
+
const normalized = command.trim();
|
|
296
|
+
switch (agentName) {
|
|
297
|
+
case "pi": return /(?:^|\s)pi-acp(?:@|\s|$)/.test(normalized);
|
|
298
|
+
case "codex": return /(?:^|\s)@agentclientprotocol\/codex-acp(?:@|\s|$)/.test(normalized);
|
|
299
|
+
case "claude": return /(?:^|\s)@agentclientprotocol\/claude-agent-acp(?:@|\s|$)/.test(normalized);
|
|
300
|
+
default: return false;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
async function assertDestinationScopeAvailable(record) {
|
|
304
|
+
if (!await findSession({
|
|
305
|
+
agentCommand: record.agentCommand,
|
|
306
|
+
cwd: record.cwd,
|
|
307
|
+
name: record.name
|
|
308
|
+
})) return;
|
|
309
|
+
throw importError("A session already exists for the import destination scope; pass --name or --cwd to import a separate copy", "session-scope-exists");
|
|
310
|
+
}
|
|
311
|
+
async function assertProviderSessionAvailable(record) {
|
|
312
|
+
if (!(await listSessions()).find((session) => session.acpSessionId === record.acpSessionId)) return;
|
|
313
|
+
throw importError("A local session already uses this provider session id; prune or remove the existing record before importing this archive", "session-provider-exists");
|
|
314
|
+
}
|
|
315
|
+
function buildImportedRecord(parsed, sourceRecord, options) {
|
|
316
|
+
const eventLog = {
|
|
317
|
+
...defaultSessionEventLog(options.newRecordId),
|
|
318
|
+
max_segment_bytes: sourceRecord.eventLog.max_segment_bytes,
|
|
319
|
+
max_segments: sourceRecord.eventLog.max_segments,
|
|
320
|
+
segment_count: parsed.history.length > 0 ? 1 : sourceRecord.eventLog.segment_count
|
|
321
|
+
};
|
|
322
|
+
return {
|
|
323
|
+
...sourceRecord,
|
|
324
|
+
acpxRecordId: options.newRecordId,
|
|
325
|
+
cwd: options.cwd,
|
|
326
|
+
name: resolveImportedName(parsed, options.name),
|
|
327
|
+
closed: false,
|
|
328
|
+
closedAt: void 0,
|
|
329
|
+
pid: void 0,
|
|
330
|
+
agentStartedAt: void 0,
|
|
331
|
+
lastAgentExitCode: void 0,
|
|
332
|
+
lastAgentExitSignal: void 0,
|
|
333
|
+
lastAgentExitAt: void 0,
|
|
334
|
+
lastAgentDisconnectReason: void 0,
|
|
335
|
+
eventLog,
|
|
336
|
+
importedFrom: {
|
|
337
|
+
recordId: parsed.session.record_id,
|
|
338
|
+
cwdOriginal: parsed.session.cwd_original ?? parsed.session.cwd_relative,
|
|
339
|
+
exportedBy: parsed.exported_by,
|
|
340
|
+
exportedAt: parsed.exported_at
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
async function importSession(archivePath, options = {}) {
|
|
345
|
+
const parsed = parseArchive(await fs$1.readFile(archivePath, "utf8"));
|
|
346
|
+
const sourceRecord = parseSessionRecord(parsed.session.state);
|
|
347
|
+
if (!sourceRecord) throw importError("Invalid session export archive: session.state is not a session record", "invalid-archive");
|
|
348
|
+
assertExpectedAgentCommand(parsed, sourceRecord, options);
|
|
349
|
+
const sessionsDir = path.join(os.homedir(), ".acpx", "sessions");
|
|
350
|
+
await fs$1.mkdir(sessionsDir, { recursive: true });
|
|
351
|
+
const cwd = resolveImportedCwd(parsed.session.cwd_relative, options.newCwd);
|
|
352
|
+
const newRecordId = await generateRecordId(sessionsDir);
|
|
353
|
+
const newRecord = buildImportedRecord(parsed, sourceRecord, {
|
|
354
|
+
newRecordId,
|
|
355
|
+
cwd,
|
|
356
|
+
name: options.name
|
|
357
|
+
});
|
|
358
|
+
await assertDestinationScopeAvailable(newRecord);
|
|
359
|
+
await assertProviderSessionAvailable(newRecord);
|
|
360
|
+
await writeSessionRecord(newRecord);
|
|
361
|
+
if (parsed.history.length > 0) {
|
|
362
|
+
const history = parsed.history;
|
|
363
|
+
await fs$1.writeFile(sessionEventActivePath(newRecordId), `${history.map((entry) => JSON.stringify(entry)).join("\n")}\n`, "utf8");
|
|
364
|
+
}
|
|
365
|
+
return {
|
|
366
|
+
record_id: newRecordId,
|
|
367
|
+
cwd
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
//#endregion
|
|
56
371
|
//#region src/cli/output/json-output.ts
|
|
57
372
|
function emitJsonResult(format, payload) {
|
|
58
373
|
if (format !== "json") return false;
|
|
@@ -71,11 +386,11 @@ let sessionModulePromise;
|
|
|
71
386
|
let outputModulePromise;
|
|
72
387
|
let outputRenderModulePromise;
|
|
73
388
|
function loadSessionModule() {
|
|
74
|
-
sessionModulePromise ??= import("./output-
|
|
389
|
+
sessionModulePromise ??= import("./output-Di77Yugq.js").then((n) => n.i);
|
|
75
390
|
return sessionModulePromise;
|
|
76
391
|
}
|
|
77
392
|
function loadOutputModule() {
|
|
78
|
-
outputModulePromise ??= import("./output-
|
|
393
|
+
outputModulePromise ??= import("./output-Di77Yugq.js").then((n) => n.r);
|
|
79
394
|
return outputModulePromise;
|
|
80
395
|
}
|
|
81
396
|
function loadOutputRenderModule() {
|
|
@@ -618,6 +933,46 @@ async function handleSessionsHistory(explicitAgentName, sessionName, flags, comm
|
|
|
618
933
|
const globalFlags = resolveGlobalFlags(command, config);
|
|
619
934
|
printSessionHistoryByFormat(await findScopedSessionOrThrow(resolveAgentInvocation(explicitAgentName, globalFlags, config), sessionName), flags.limit, globalFlags.format);
|
|
620
935
|
}
|
|
936
|
+
async function handleSessionsExport(explicitAgentName, sessionName, flags, command, config) {
|
|
937
|
+
const globalFlags = resolveGlobalFlags(command, config);
|
|
938
|
+
const agent = resolveAgentInvocation(explicitAgentName, globalFlags, config);
|
|
939
|
+
const cwd = flags.sourceCwd ? path.resolve(agent.cwd, flags.sourceCwd) : agent.cwd;
|
|
940
|
+
await exportSession({
|
|
941
|
+
agentName: globalFlags.agent ? void 0 : agent.agentName,
|
|
942
|
+
agentCommand: agent.agentCommand,
|
|
943
|
+
cwd,
|
|
944
|
+
name: sessionName
|
|
945
|
+
}, flags.output);
|
|
946
|
+
if (emitJsonResult(globalFlags.format, {
|
|
947
|
+
action: "session_exported",
|
|
948
|
+
output: flags.output
|
|
949
|
+
})) return;
|
|
950
|
+
if (globalFlags.format === "quiet") {
|
|
951
|
+
process.stdout.write(`${flags.output}\n`);
|
|
952
|
+
return;
|
|
953
|
+
}
|
|
954
|
+
process.stdout.write(`exported session to ${flags.output}\n`);
|
|
955
|
+
}
|
|
956
|
+
async function handleSessionsImport(explicitAgentName, archivePath, flags, command, config) {
|
|
957
|
+
const globalFlags = resolveGlobalFlags(command, config);
|
|
958
|
+
const agent = resolveAgentInvocation(explicitAgentName, globalFlags, config);
|
|
959
|
+
const result = await importSession(archivePath, {
|
|
960
|
+
name: flags.name,
|
|
961
|
+
newCwd: flags.destinationCwd ? path.resolve(globalFlags.cwd, flags.destinationCwd) : void 0,
|
|
962
|
+
expectedAgentName: globalFlags.agent ? void 0 : agent.agentName,
|
|
963
|
+
expectedAgentCommand: agent.agentCommand
|
|
964
|
+
});
|
|
965
|
+
if (emitJsonResult(globalFlags.format, {
|
|
966
|
+
action: "session_imported",
|
|
967
|
+
record_id: result.record_id,
|
|
968
|
+
cwd: result.cwd
|
|
969
|
+
})) return;
|
|
970
|
+
if (globalFlags.format === "quiet") {
|
|
971
|
+
process.stdout.write(`${result.record_id}\n`);
|
|
972
|
+
return;
|
|
973
|
+
}
|
|
974
|
+
process.stdout.write(`imported session ${result.record_id} at ${result.cwd}\n`);
|
|
975
|
+
}
|
|
621
976
|
async function handleSessionsPrune(explicitAgentName, flags, command, config) {
|
|
622
977
|
const globalFlags = resolveGlobalFlags(command, config);
|
|
623
978
|
const agent = resolveAgentInvocation(explicitAgentName, globalFlags, config);
|
|
@@ -802,7 +1157,7 @@ function parseOutputFormat(value, sourcePath) {
|
|
|
802
1157
|
function parseDefaultAgent(value, sourcePath) {
|
|
803
1158
|
if (value == null) return;
|
|
804
1159
|
if (typeof value !== "string" || value.trim().length === 0) throw new Error(`Invalid config defaultAgent in ${sourcePath}: expected non-empty string`);
|
|
805
|
-
return normalizeAgentName(value);
|
|
1160
|
+
return normalizeAgentName$1(value);
|
|
806
1161
|
}
|
|
807
1162
|
function parseAgents(value, sourcePath) {
|
|
808
1163
|
if (value == null) return;
|
|
@@ -813,7 +1168,7 @@ function parseAgents(value, sourcePath) {
|
|
|
813
1168
|
const command = raw.command;
|
|
814
1169
|
if (typeof command !== "string" || command.trim().length === 0) throw new Error(`Invalid config agents.${name}.command in ${sourcePath}: expected non-empty string`);
|
|
815
1170
|
const args = parseAgentArgs(raw.args, name, sourcePath);
|
|
816
|
-
parsed[normalizeAgentName(name)] = args.length > 0 ? `${command.trim()} ${args.map(quoteCommandArg).join(" ")}` : command.trim();
|
|
1171
|
+
parsed[normalizeAgentName$1(name)] = args.length > 0 ? `${command.trim()} ${args.map(quoteCommandArg).join(" ")}` : command.trim();
|
|
817
1172
|
}
|
|
818
1173
|
return parsed;
|
|
819
1174
|
}
|
|
@@ -1409,6 +1764,16 @@ function registerStatusCommand(parent, explicitAgentName, config, description) {
|
|
|
1409
1764
|
}
|
|
1410
1765
|
//#endregion
|
|
1411
1766
|
//#region src/cli/command-registration.ts
|
|
1767
|
+
var LocalAttributeOption = class extends Option {
|
|
1768
|
+
localAttributeName;
|
|
1769
|
+
constructor(flags, description, localAttributeName) {
|
|
1770
|
+
super(flags, description);
|
|
1771
|
+
this.localAttributeName = localAttributeName;
|
|
1772
|
+
}
|
|
1773
|
+
attributeName() {
|
|
1774
|
+
return this.localAttributeName;
|
|
1775
|
+
}
|
|
1776
|
+
};
|
|
1412
1777
|
function addSessionsListOptions(command) {
|
|
1413
1778
|
return command.option("--local", "List local acpx session records instead of agent protocol sessions").option("--cursor <cursor>", "Opaque ACP session/list cursor", (value) => parseNonEmptyValue("Cursor", value)).option("--filter-cwd <dir>", "Filter agent sessions by working directory", (value) => parseNonEmptyValue("Filter cwd", value));
|
|
1414
1779
|
}
|
|
@@ -1439,6 +1804,12 @@ function registerSessionsCommand(parent, explicitAgentName, config) {
|
|
|
1439
1804
|
sessionsCommand.command("read").description("Read full session history").argument("[name]", "Session name", parseSessionName).option("--tail <count>", "Show only the last N entries instead of all history", parseHistoryLimit).action(async function(name, flags) {
|
|
1440
1805
|
await handleSessionsHistory(explicitAgentName, name, { limit: flags.tail ?? 0 }, this, config);
|
|
1441
1806
|
});
|
|
1807
|
+
sessionsCommand.command("export").description("Export a portable session archive").argument("[name]", "Session name", parseSessionName).requiredOption("--output <path>", "Output archive path", (value) => parseNonEmptyValue("Output path", value)).addOption(new LocalAttributeOption("--cwd <cwd>", "Session cwd to export", "sourceCwd").argParser((value) => parseNonEmptyValue("Session cwd", value))).action(async function(name, flags) {
|
|
1808
|
+
await handleSessionsExport(explicitAgentName, name, flags, this, config);
|
|
1809
|
+
});
|
|
1810
|
+
sessionsCommand.command("import").description("Import a portable session archive").argument("<archive-path>", "Archive path", (value) => parseNonEmptyValue("Archive path", value)).option("--name <name>", "Imported session name", parseSessionName).addOption(new LocalAttributeOption("--cwd <cwd>", "Imported session cwd", "destinationCwd").argParser((value) => parseNonEmptyValue("Imported session cwd", value))).action(async function(archivePath, flags) {
|
|
1811
|
+
await handleSessionsImport(explicitAgentName, archivePath, flags, this, config);
|
|
1812
|
+
});
|
|
1442
1813
|
sessionsCommand.command("prune").description("Delete closed sessions and free disk space").option("--dry-run", "Preview what would be pruned without deleting anything").option("--before <date>", "Prune sessions closed before this date", parsePruneBeforeDate).option("--older-than <days>", "Prune sessions closed more than N days ago", parseDaysOlderThan).option("--include-history", "Also delete event stream files (.stream.ndjson)").action(async function(flags) {
|
|
1443
1814
|
await handleSessionsPrune(explicitAgentName, flags, this, config);
|
|
1444
1815
|
});
|
|
@@ -1491,7 +1862,7 @@ function registerAgentCommand(program, agentName, config) {
|
|
|
1491
1862
|
}
|
|
1492
1863
|
function registerFlowCommand(program, config) {
|
|
1493
1864
|
program.command("flow").description("Run multi-step ACP workflows from flow files").command("run").description("Run a flow file").argument("<file>", "Flow module path").option("--input-json <json>", "Flow input as JSON").option("--input-file <path>", "Read flow input JSON from file").option("--default-agent <name>", "Default agent profile for ACP nodes without profile", (value) => parseNonEmptyValue("Default agent", value)).action(async function(file, flags) {
|
|
1494
|
-
const { handleFlowRun } = await import("./cli-
|
|
1865
|
+
const { handleFlowRun } = await import("./cli-8dP_TqBp.js");
|
|
1495
1866
|
await handleFlowRun(file, flags, this, config);
|
|
1496
1867
|
});
|
|
1497
1868
|
}
|
|
@@ -1872,13 +2243,18 @@ async function handleProgramParseError(error, requestedOutputPolicy) {
|
|
|
1872
2243
|
process.exit(exitCodeForOutputErrorCode(normalized.code));
|
|
1873
2244
|
}
|
|
1874
2245
|
async function main(argv = process.argv) {
|
|
1875
|
-
const rawArgs = argv.slice(2);
|
|
2246
|
+
const rawArgs = normalizeLifecycleScriptArgs(argv.slice(2));
|
|
2247
|
+
const normalizedArgv = [
|
|
2248
|
+
argv[0] ?? "node",
|
|
2249
|
+
argv[1] ?? "acpx",
|
|
2250
|
+
...rawArgs
|
|
2251
|
+
];
|
|
1876
2252
|
if (await handleQueueOwnerCommand(argv)) return;
|
|
1877
2253
|
if (isTopLevelVersionRequest(rawArgs)) {
|
|
1878
2254
|
process.stdout.write(`${getAcpxVersion()}\n`);
|
|
1879
2255
|
return;
|
|
1880
2256
|
}
|
|
1881
|
-
await maybeHandleSkillflag(
|
|
2257
|
+
await maybeHandleSkillflag(normalizedArgv);
|
|
1882
2258
|
const config = await loadResolvedConfig(detectInitialCwd(rawArgs));
|
|
1883
2259
|
const requestedJsonStrict = detectJsonStrict(rawArgs);
|
|
1884
2260
|
const requestedOutputPolicy = {
|
|
@@ -1907,7 +2283,7 @@ async function main(argv = process.argv) {
|
|
|
1907
2283
|
try {
|
|
1908
2284
|
await runWithOutputPolicy(requestedOutputPolicy, async () => {
|
|
1909
2285
|
try {
|
|
1910
|
-
await program.parseAsync(
|
|
2286
|
+
await program.parseAsync(normalizedArgv);
|
|
1911
2287
|
} catch (error) {
|
|
1912
2288
|
await handleProgramParseError(error, requestedOutputPolicy);
|
|
1913
2289
|
}
|
|
@@ -1916,6 +2292,10 @@ async function main(argv = process.argv) {
|
|
|
1916
2292
|
flushPerfMetricsCapture();
|
|
1917
2293
|
}
|
|
1918
2294
|
}
|
|
2295
|
+
function normalizeLifecycleScriptArgs(rawArgs) {
|
|
2296
|
+
if (rawArgs[0] === "--" && (process.env.npm_lifecycle_event || process.env.npm_lifecycle_script)) return rawArgs.slice(1);
|
|
2297
|
+
return rawArgs;
|
|
2298
|
+
}
|
|
1919
2299
|
//#endregion
|
|
1920
2300
|
//#region src/cli.ts
|
|
1921
2301
|
function installBrokenPipeHandler(stream) {
|