@herbertgao/pi-extensions 2026.8.9 → 2026.8.11
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 +4 -2
- package/node_modules/@herbertgao/resume-from/LICENSE +21 -0
- package/node_modules/@herbertgao/resume-from/README.md +163 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/claude-code/adapter.d.ts +25 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/claude-code/adapter.js +60 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/claude-code/contract.d.ts +8 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/claude-code/contract.js +4 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/claude-code/entries.d.ts +30 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/claude-code/entries.js +107 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/claude-code/index.d.ts +3 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/claude-code/index.js +2 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/claude-code/layout.d.ts +29 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/claude-code/layout.js +80 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/claude-code/readback.d.ts +9 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/claude-code/readback.js +39 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/claude-code/reader.d.ts +37 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/claude-code/reader.js +424 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/claude-code/redaction.d.ts +26 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/claude-code/redaction.js +132 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/claude-code/validation.d.ts +4 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/claude-code/validation.js +39 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/claude-code/writer.d.ts +23 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/claude-code/writer.js +306 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/codex/contract.d.ts +15 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/codex/contract.js +4 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/codex/index.d.ts +6 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/codex/index.js +44 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/codex/read.d.ts +28 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/codex/read.js +270 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/codex/readback.d.ts +9 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/codex/readback.js +47 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/codex/redaction.d.ts +26 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/codex/redaction.js +132 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/codex/rollout.d.ts +75 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/codex/rollout.js +185 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/codex/validation.d.ts +7 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/codex/validation.js +78 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/codex/write.d.ts +17 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/codex/write.js +141 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/contract.d.ts +74 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/contract.js +4 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/pi/adapter.d.ts +15 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/pi/adapter.js +209 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/pi/contract.d.ts +24 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/pi/contract.js +4 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/pi/format.d.ts +162 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/pi/format.js +223 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/pi/index.d.ts +7 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/pi/index.js +10 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/pi/parse.d.ts +41 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/pi/parse.js +371 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/pi/redaction.d.ts +26 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/pi/redaction.js +132 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/pi/serialize.d.ts +22 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/pi/serialize.js +87 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/pi/validate.d.ts +14 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/pi/validate.js +134 -0
- package/node_modules/@herbertgao/resume-from/dist/bin.d.ts +35 -0
- package/node_modules/@herbertgao/resume-from/dist/bin.js +135 -0
- package/node_modules/@herbertgao/resume-from/dist/contract.d.ts +10 -0
- package/node_modules/@herbertgao/resume-from/dist/contract.js +4 -0
- package/node_modules/@herbertgao/resume-from/dist/host/agents.d.ts +29 -0
- package/node_modules/@herbertgao/resume-from/dist/host/agents.js +20 -0
- package/node_modules/@herbertgao/resume-from/dist/host/cli/args.d.ts +21 -0
- package/node_modules/@herbertgao/resume-from/dist/host/cli/args.js +187 -0
- package/node_modules/@herbertgao/resume-from/dist/host/cli/contract.d.ts +27 -0
- package/node_modules/@herbertgao/resume-from/dist/host/cli/contract.js +4 -0
- package/node_modules/@herbertgao/resume-from/dist/host/cli/index.d.ts +2 -0
- package/node_modules/@herbertgao/resume-from/dist/host/cli/index.js +1 -0
- package/node_modules/@herbertgao/resume-from/dist/host/cli/presentation.d.ts +2 -0
- package/node_modules/@herbertgao/resume-from/dist/host/cli/presentation.js +11 -0
- package/node_modules/@herbertgao/resume-from/dist/host/cli/render.d.ts +3 -0
- package/node_modules/@herbertgao/resume-from/dist/host/cli/render.js +70 -0
- package/node_modules/@herbertgao/resume-from/dist/host/cli/runner.d.ts +8 -0
- package/node_modules/@herbertgao/resume-from/dist/host/cli/runner.js +125 -0
- package/node_modules/@herbertgao/resume-from/dist/host/contract.d.ts +42 -0
- package/node_modules/@herbertgao/resume-from/dist/host/contract.js +4 -0
- package/node_modules/@herbertgao/resume-from/dist/host/entry.d.ts +52 -0
- package/node_modules/@herbertgao/resume-from/dist/host/entry.js +91 -0
- package/node_modules/@herbertgao/resume-from/dist/host/index.d.ts +11 -0
- package/node_modules/@herbertgao/resume-from/dist/host/index.js +10 -0
- package/node_modules/@herbertgao/resume-from/dist/host/pi-extension/command.d.ts +18 -0
- package/node_modules/@herbertgao/resume-from/dist/host/pi-extension/command.js +103 -0
- package/node_modules/@herbertgao/resume-from/dist/host/pi-extension/contract.d.ts +34 -0
- package/node_modules/@herbertgao/resume-from/dist/host/pi-extension/contract.js +4 -0
- package/node_modules/@herbertgao/resume-from/dist/host/pi-extension/index.d.ts +6 -0
- package/node_modules/@herbertgao/resume-from/dist/host/pi-extension/index.js +4 -0
- package/node_modules/@herbertgao/resume-from/dist/host/pi-extension/picker.d.ts +16 -0
- package/node_modules/@herbertgao/resume-from/dist/host/pi-extension/picker.js +35 -0
- package/node_modules/@herbertgao/resume-from/dist/host/pi-extension/presentation.d.ts +2 -0
- package/node_modules/@herbertgao/resume-from/dist/host/pi-extension/presentation.js +11 -0
- package/node_modules/@herbertgao/resume-from/dist/host/pi-extension/register.d.ts +25 -0
- package/node_modules/@herbertgao/resume-from/dist/host/pi-extension/register.js +11 -0
- package/node_modules/@herbertgao/resume-from/dist/host/pi-extension/ui.d.ts +20 -0
- package/node_modules/@herbertgao/resume-from/dist/host/pi-extension/ui.js +1 -0
- package/node_modules/@herbertgao/resume-from/dist/host/profile.d.ts +8 -0
- package/node_modules/@herbertgao/resume-from/dist/host/profile.js +31 -0
- package/node_modules/@herbertgao/resume-from/dist/host/registry.d.ts +8 -0
- package/node_modules/@herbertgao/resume-from/dist/host/registry.js +33 -0
- package/node_modules/@herbertgao/resume-from/dist/host/wiring.d.ts +41 -0
- package/node_modules/@herbertgao/resume-from/dist/host/wiring.js +67 -0
- package/node_modules/@herbertgao/resume-from/dist/import/confirmation.d.ts +6 -0
- package/node_modules/@herbertgao/resume-from/dist/import/confirmation.js +27 -0
- package/node_modules/@herbertgao/resume-from/dist/import/contract.d.ts +41 -0
- package/node_modules/@herbertgao/resume-from/dist/import/contract.js +4 -0
- package/node_modules/@herbertgao/resume-from/dist/import/discovery/contract.d.ts +58 -0
- package/node_modules/@herbertgao/resume-from/dist/import/discovery/contract.js +4 -0
- package/node_modules/@herbertgao/resume-from/dist/import/discovery/errors.d.ts +9 -0
- package/node_modules/@herbertgao/resume-from/dist/import/discovery/errors.js +12 -0
- package/node_modules/@herbertgao/resume-from/dist/import/discovery/finder.d.ts +10 -0
- package/node_modules/@herbertgao/resume-from/dist/import/discovery/finder.js +129 -0
- package/node_modules/@herbertgao/resume-from/dist/import/discovery/homes.d.ts +23 -0
- package/node_modules/@herbertgao/resume-from/dist/import/discovery/homes.js +83 -0
- package/node_modules/@herbertgao/resume-from/dist/import/discovery/index.d.ts +2 -0
- package/node_modules/@herbertgao/resume-from/dist/import/discovery/index.js +2 -0
- package/node_modules/@herbertgao/resume-from/dist/import/discovery/ordering.d.ts +3 -0
- package/node_modules/@herbertgao/resume-from/dist/import/discovery/ordering.js +21 -0
- package/node_modules/@herbertgao/resume-from/dist/import/errors.d.ts +22 -0
- package/node_modules/@herbertgao/resume-from/dist/import/errors.js +20 -0
- package/node_modules/@herbertgao/resume-from/dist/import/index.d.ts +3 -0
- package/node_modules/@herbertgao/resume-from/dist/import/index.js +5 -0
- package/node_modules/@herbertgao/resume-from/dist/import/landing/contract.d.ts +44 -0
- package/node_modules/@herbertgao/resume-from/dist/import/landing/contract.js +4 -0
- package/node_modules/@herbertgao/resume-from/dist/import/landing/errors.d.ts +15 -0
- package/node_modules/@herbertgao/resume-from/dist/import/landing/errors.js +15 -0
- package/node_modules/@herbertgao/resume-from/dist/import/landing/handover.d.ts +5 -0
- package/node_modules/@herbertgao/resume-from/dist/import/landing/handover.js +12 -0
- package/node_modules/@herbertgao/resume-from/dist/import/landing/index.d.ts +4 -0
- package/node_modules/@herbertgao/resume-from/dist/import/landing/index.js +4 -0
- package/node_modules/@herbertgao/resume-from/dist/import/landing/lander.d.ts +7 -0
- package/node_modules/@herbertgao/resume-from/dist/import/landing/lander.js +133 -0
- package/node_modules/@herbertgao/resume-from/dist/import/landing/marker.d.ts +9 -0
- package/node_modules/@herbertgao/resume-from/dist/import/landing/marker.js +46 -0
- package/node_modules/@herbertgao/resume-from/dist/import/pipeline.d.ts +17 -0
- package/node_modules/@herbertgao/resume-from/dist/import/pipeline.js +134 -0
- package/node_modules/@herbertgao/resume-from/dist/import/preview/builder.d.ts +6 -0
- package/node_modules/@herbertgao/resume-from/dist/import/preview/builder.js +76 -0
- package/node_modules/@herbertgao/resume-from/dist/import/preview/contract.d.ts +39 -0
- package/node_modules/@herbertgao/resume-from/dist/import/preview/contract.js +4 -0
- package/node_modules/@herbertgao/resume-from/dist/import/preview/format.d.ts +19 -0
- package/node_modules/@herbertgao/resume-from/dist/import/preview/format.js +45 -0
- package/node_modules/@herbertgao/resume-from/dist/import/preview/index.d.ts +2 -0
- package/node_modules/@herbertgao/resume-from/dist/import/preview/index.js +1 -0
- package/node_modules/@herbertgao/resume-from/dist/import/preview/warnings.d.ts +11 -0
- package/node_modules/@herbertgao/resume-from/dist/import/preview/warnings.js +80 -0
- package/node_modules/@herbertgao/resume-from/dist/import/transfer/contract.d.ts +48 -0
- package/node_modules/@herbertgao/resume-from/dist/import/transfer/contract.js +4 -0
- package/node_modules/@herbertgao/resume-from/dist/import/transfer/index.d.ts +2 -0
- package/node_modules/@herbertgao/resume-from/dist/import/transfer/index.js +1 -0
- package/node_modules/@herbertgao/resume-from/dist/import/transfer/rules.d.ts +3 -0
- package/node_modules/@herbertgao/resume-from/dist/import/transfer/rules.js +228 -0
- package/node_modules/@herbertgao/resume-from/dist/import/wiring.d.ts +24 -0
- package/node_modules/@herbertgao/resume-from/dist/import/wiring.js +27 -0
- package/node_modules/@herbertgao/resume-from/dist/index.d.ts +36 -0
- package/node_modules/@herbertgao/resume-from/dist/index.js +36 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/config/contract.d.ts +35 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/config/contract.js +4 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/config/defaults.d.ts +16 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/config/defaults.js +22 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/config/errors.d.ts +9 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/config/errors.js +12 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/config/index.d.ts +5 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/config/index.js +6 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/config/loader.d.ts +10 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/config/loader.js +47 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/config/paths.d.ts +13 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/config/paths.js +37 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/config/validate.d.ts +9 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/config/validate.js +117 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/repo/contract.d.ts +30 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/repo/contract.js +4 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/repo/git.d.ts +21 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/repo/git.js +74 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/repo/index.d.ts +2 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/repo/index.js +1 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/repo/reader.d.ts +8 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/repo/reader.js +130 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/store/contract.d.ts +31 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/store/contract.js +4 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/store/file-committer.d.ts +3 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/store/file-committer.js +391 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/store/index.d.ts +2 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/store/index.js +2 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/tokens/contract.d.ts +12 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/tokens/contract.js +4 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/tokens/estimator.d.ts +12 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/tokens/estimator.js +111 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/tokens/index.d.ts +2 -0
- package/node_modules/@herbertgao/resume-from/dist/platform/tokens/index.js +1 -0
- package/node_modules/@herbertgao/resume-from/dist/session/contract.d.ts +109 -0
- package/node_modules/@herbertgao/resume-from/dist/session/contract.js +4 -0
- package/node_modules/@herbertgao/resume-from/package.json +94 -0
- package/node_modules/@herbertgao/resume-from/shims/pi/extensions/resume-from.js +118 -0
- package/package.json +6 -2
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
// The flag and argument grammar of the command binary (FR-10, FR-12, FR-15).
|
|
2
|
+
// It parses; it decides nothing about sessions.
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { join, resolve, win32 } from "node:path";
|
|
5
|
+
export const USAGE = "Usage: /resume-from [<agent>] [<row> | <session-id> | <file-path>] [--home <path>] [--agent <name>] [--confirm <token>]";
|
|
6
|
+
/** The agent names the user may type, and the agent they mean (FR-15). */
|
|
7
|
+
const AGENT_NAMES = {
|
|
8
|
+
pi: "pi",
|
|
9
|
+
codex: "codex",
|
|
10
|
+
claude: "claude-code",
|
|
11
|
+
"claude-code": "claude-code",
|
|
12
|
+
};
|
|
13
|
+
const KNOWN_AGENTS = Object.keys(AGENT_NAMES).join(", ");
|
|
14
|
+
/** The one confirmation flag. `runner.ts` strips it from re-run hints with the same predicate. */
|
|
15
|
+
export const CONFIRM_FLAG = "--confirm";
|
|
16
|
+
/** True for both accepted forms: `--confirm <token>` and `--confirm=<token>`. */
|
|
17
|
+
export function isConfirmFlag(arg) {
|
|
18
|
+
return arg === CONFIRM_FLAG || arg.startsWith(`${CONFIRM_FLAG}=`);
|
|
19
|
+
}
|
|
20
|
+
export function parseArgs(argv, cwd) {
|
|
21
|
+
const positionals = [];
|
|
22
|
+
let onlyAgent = null;
|
|
23
|
+
let onlyHome = null;
|
|
24
|
+
let confirmationToken = null;
|
|
25
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
26
|
+
const arg = argv[index];
|
|
27
|
+
if (arg === undefined)
|
|
28
|
+
continue;
|
|
29
|
+
if (isConfirmFlag(arg)) {
|
|
30
|
+
if (confirmationToken !== null) {
|
|
31
|
+
return {
|
|
32
|
+
ok: false,
|
|
33
|
+
problem: "--confirm was given twice. Use the token from one preview.",
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const value = arg.startsWith(`${CONFIRM_FLAG}=`)
|
|
37
|
+
? arg.slice(CONFIRM_FLAG.length + 1)
|
|
38
|
+
: argv[index + 1];
|
|
39
|
+
if (value === undefined || !/^v1-sha256-[0-9a-f]{64}$/.test(value)) {
|
|
40
|
+
return {
|
|
41
|
+
ok: false,
|
|
42
|
+
problem: "--confirm needs the exact token printed by the preview. Preview the session again.",
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
confirmationToken = value;
|
|
46
|
+
if (!arg.startsWith(`${CONFIRM_FLAG}=`))
|
|
47
|
+
index += 1;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (arg === "--home" || arg.startsWith("--home=")) {
|
|
51
|
+
if (onlyHome !== null) {
|
|
52
|
+
return {
|
|
53
|
+
ok: false,
|
|
54
|
+
problem: "--home was given twice. Name one source home.",
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
const value = arg.startsWith("--home=") ? arg.slice("--home=".length) : argv[index + 1];
|
|
58
|
+
if (value === undefined || value === "" || value.startsWith("-")) {
|
|
59
|
+
return {
|
|
60
|
+
ok: false,
|
|
61
|
+
problem: "--home needs a path. Correct form: --home <path>.",
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
if (!arg.startsWith("--home="))
|
|
65
|
+
index += 1;
|
|
66
|
+
onlyHome = resolvePath(value, cwd);
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (arg === "--agent" || arg.startsWith("--agent=")) {
|
|
70
|
+
if (onlyAgent !== null) {
|
|
71
|
+
return {
|
|
72
|
+
ok: false,
|
|
73
|
+
problem: "The agent was given twice. Name it once.",
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
const value = arg.startsWith("--agent=") ? arg.slice("--agent=".length) : argv[index + 1];
|
|
77
|
+
if (value === undefined || value === "" || value.startsWith("-")) {
|
|
78
|
+
return {
|
|
79
|
+
ok: false,
|
|
80
|
+
problem: `--agent needs a name. Correct form: --agent <name>, one of: ${KNOWN_AGENTS}.`,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
if (!arg.startsWith("--agent="))
|
|
84
|
+
index += 1;
|
|
85
|
+
const agent = AGENT_NAMES[value];
|
|
86
|
+
if (agent === undefined) {
|
|
87
|
+
return {
|
|
88
|
+
ok: false,
|
|
89
|
+
problem: `"${value}" is not an agent this command knows. Use one of: ${KNOWN_AGENTS}.`,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
onlyAgent = agent;
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (arg.startsWith("-")) {
|
|
96
|
+
if (/^-\d/.test(arg)) {
|
|
97
|
+
return {
|
|
98
|
+
ok: false,
|
|
99
|
+
problem: `"${arg}" is not a row. Rows start at 1 and are whole numbers.`,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
ok: false,
|
|
104
|
+
problem: `"${arg}" is not a flag this command knows. Known flags: --home, --agent, --confirm.`,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
positionals.push(arg);
|
|
108
|
+
}
|
|
109
|
+
let rest = positionals;
|
|
110
|
+
const first = positionals[0];
|
|
111
|
+
if (first !== undefined) {
|
|
112
|
+
const named = AGENT_NAMES[first];
|
|
113
|
+
if (named !== undefined) {
|
|
114
|
+
if (onlyAgent !== null) {
|
|
115
|
+
return {
|
|
116
|
+
ok: false,
|
|
117
|
+
problem: "The agent was given twice. Name it once.",
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
onlyAgent = named;
|
|
121
|
+
rest = positionals.slice(1);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (rest.length > 1) {
|
|
125
|
+
return {
|
|
126
|
+
ok: false,
|
|
127
|
+
problem: `Too many arguments: ${rest.join(" ")}. Give one row, session ID or file path.`,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
let selection = null;
|
|
131
|
+
const token = rest[0];
|
|
132
|
+
if (token !== undefined) {
|
|
133
|
+
const classified = classify(token, cwd);
|
|
134
|
+
if (!classified.ok)
|
|
135
|
+
return classified;
|
|
136
|
+
selection = classified.value;
|
|
137
|
+
}
|
|
138
|
+
if (selection === null && confirmationToken !== null) {
|
|
139
|
+
return {
|
|
140
|
+
ok: false,
|
|
141
|
+
problem: "--confirm needs the row, session ID or file path you previewed.",
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
ok: true,
|
|
146
|
+
args: { selection, onlyAgent, onlyHome, confirmationToken },
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
/** A row, a session ID or a file path — told apart by shape alone (FR-12). */
|
|
150
|
+
function classify(token, cwd) {
|
|
151
|
+
if (/^\d+$/.test(token)) {
|
|
152
|
+
const row = Number(token);
|
|
153
|
+
if (row < 1) {
|
|
154
|
+
return {
|
|
155
|
+
ok: false,
|
|
156
|
+
problem: `"${token}" is not a row. Rows start at 1.`,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
return { ok: true, value: { by: "row", row } };
|
|
160
|
+
}
|
|
161
|
+
// Numeric but not a row: caught here so a session ID that starts with a digit
|
|
162
|
+
// (a UUID, for example) is still read as a session ID.
|
|
163
|
+
if (/^[+-]?\d+(\.\d+)?$/.test(token)) {
|
|
164
|
+
return {
|
|
165
|
+
ok: false,
|
|
166
|
+
problem: `"${token}" is not a row. A row is a whole number, 1 or greater.`,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
if (token.startsWith("~") || token.includes("/") || token.includes("\\")) {
|
|
170
|
+
return {
|
|
171
|
+
ok: true,
|
|
172
|
+
value: { by: "file-path", path: resolvePath(token, cwd) },
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
return { ok: true, value: { by: "session-id", id: token } };
|
|
176
|
+
}
|
|
177
|
+
function resolvePath(value, cwd) {
|
|
178
|
+
if (value === "~")
|
|
179
|
+
return homedir();
|
|
180
|
+
if (/^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\")) {
|
|
181
|
+
return win32.normalize(value);
|
|
182
|
+
}
|
|
183
|
+
const expanded = value.startsWith("~/") || value.startsWith("~\\")
|
|
184
|
+
? join(homedir(), value.slice(2).replaceAll("\\", "/"))
|
|
185
|
+
: value.replaceAll("\\", "/");
|
|
186
|
+
return resolve(cwd, expanded);
|
|
187
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { AgentRuntime, HandoverInstruction, HomeFailure, ImportPipeline, ImportRequest, LandingResult, Listing, ListRequest, PreviewReport, PreviewWarning, SelectionError, SelectionInput, WarningKind } from "../../import/contract.js";
|
|
2
|
+
export type { AgentRuntime, HandoverInstruction, HomeFailure, ImportPipeline, ImportRequest, LandingResult, Listing, ListRequest, PreviewReport, PreviewWarning, SelectionError, SelectionInput, WarningKind, };
|
|
3
|
+
import type { AgentId, HomePath, ProvenanceMarker, SessionDescriptor, SessionId, SessionRef, TargetProfile } from "../../session/contract.js";
|
|
4
|
+
export type { AgentId, HomePath, ProvenanceMarker, SessionDescriptor, SessionId, SessionRef, TargetProfile, };
|
|
5
|
+
/** One invocation of the command binary (FR-10). */
|
|
6
|
+
export interface CliInvocation {
|
|
7
|
+
/** Arguments after the command name. */
|
|
8
|
+
argv: string[];
|
|
9
|
+
/** The directory the agent is running in. Used to find the repository (FR-13). */
|
|
10
|
+
cwd: string;
|
|
11
|
+
/** The agent the binary is running inside. The shim states it; the binary never guesses. */
|
|
12
|
+
targetAgent: AgentId;
|
|
13
|
+
/** The target home, when the shim knows it. Otherwise the adapter default is used (FR-3). */
|
|
14
|
+
targetHome: HomePath | null;
|
|
15
|
+
}
|
|
16
|
+
/** 0 success, 1 refused, 2 error (FR-56). */
|
|
17
|
+
export type CliExit = 0 | 1 | 2;
|
|
18
|
+
/** What one invocation produced. */
|
|
19
|
+
export interface CliOutcome {
|
|
20
|
+
stdout: string[];
|
|
21
|
+
stderr: string[];
|
|
22
|
+
exitCode: CliExit;
|
|
23
|
+
}
|
|
24
|
+
/** Runs one invocation of the command binary. */
|
|
25
|
+
export interface CliRunner {
|
|
26
|
+
run(invocation: CliInvocation, pipeline: ImportPipeline): Promise<CliOutcome>;
|
|
27
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createCliRunner } from "./runner.js";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
function globalPattern(source) {
|
|
2
|
+
return new RegExp(source, "gu");
|
|
3
|
+
}
|
|
4
|
+
const ANSI_SEQUENCE = globalPattern(String.raw `\x1b(?:\][^\x07]*(?:\x07|\x1b\\)|\[[0-?]*[ -/]*[@-~])`);
|
|
5
|
+
const UNSAFE_CONTROL = globalPattern(String.raw `[\x00-\x1f\x7f-\x9f\u2028\u2029\u202a-\u202e\u2066-\u2069]`);
|
|
6
|
+
export function safeText(value) {
|
|
7
|
+
return value.replace(ANSI_SEQUENCE, " ").replace(UNSAFE_CONTROL, " ");
|
|
8
|
+
}
|
|
9
|
+
export function safeLines(lines) {
|
|
10
|
+
return lines.map(safeText);
|
|
11
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// The text layout of the numbered list and of the landing outcome.
|
|
2
|
+
// Nothing here decides anything: it prints what the pipeline returned.
|
|
3
|
+
import { safeText } from "./presentation.js";
|
|
4
|
+
const COLUMN_GAP = " ";
|
|
5
|
+
export function renderListing(listing, repoRoot) {
|
|
6
|
+
const lines = listing.rows.length === 0
|
|
7
|
+
? [`No session of ${safeText(repoRoot)} was found.`]
|
|
8
|
+
: renderRows(listing.rows);
|
|
9
|
+
// Homes that could not be read are printed, never hidden.
|
|
10
|
+
if (listing.failures.length > 0) {
|
|
11
|
+
const count = listing.failures.length;
|
|
12
|
+
lines.push("", `${count} home${count === 1 ? "" : "s"} could not be read:`);
|
|
13
|
+
for (const failure of listing.failures) {
|
|
14
|
+
lines.push(` ${safeText(failure.agent)}${COLUMN_GAP}${safeText(failure.home)}${COLUMN_GAP}${safeText(failure.message)}`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
if (listing.rows.length > 0) {
|
|
18
|
+
lines.push("", 'Run "/resume-from <n>" to preview a session.');
|
|
19
|
+
}
|
|
20
|
+
return lines;
|
|
21
|
+
}
|
|
22
|
+
export function renderLanding(result) {
|
|
23
|
+
const lines = [
|
|
24
|
+
`Imported into ${safeText(result.ref.agent)} (${safeText(result.ref.home)}) as session ${safeText(result.ref.id)}.`,
|
|
25
|
+
`${result.itemsSent} items sent, ${result.itemsStored} stored.`,
|
|
26
|
+
];
|
|
27
|
+
if (result.switched) {
|
|
28
|
+
lines.push("You are now in the imported session.");
|
|
29
|
+
}
|
|
30
|
+
else if (result.handover !== null) {
|
|
31
|
+
lines.push(`Open it with: ${safeText(result.handover.command)}`);
|
|
32
|
+
}
|
|
33
|
+
// The marker is always printed: this host has no way to know whether the
|
|
34
|
+
// target can show one itself (FR-47, FR-48), and hiding it would be a rule.
|
|
35
|
+
lines.push("", ...result.marker.lines.map(safeText));
|
|
36
|
+
return lines;
|
|
37
|
+
}
|
|
38
|
+
/** Rows are 1-based and keep the order the pipeline produced (FR-10, FR-14). */
|
|
39
|
+
function renderRows(rows) {
|
|
40
|
+
const cells = rows.map((row, index) => [
|
|
41
|
+
`${index + 1}`,
|
|
42
|
+
safeText(row.ref.agent),
|
|
43
|
+
safeText(row.ref.home),
|
|
44
|
+
formatTime(row.updatedAt),
|
|
45
|
+
`${row.turnCount} turns`,
|
|
46
|
+
safeText(row.title),
|
|
47
|
+
]);
|
|
48
|
+
const widths = cells.reduce((widest, cell) => {
|
|
49
|
+
cell.forEach((value, column) => {
|
|
50
|
+
widest[column] = Math.max(widest[column] ?? 0, value.length);
|
|
51
|
+
});
|
|
52
|
+
return widest;
|
|
53
|
+
}, []);
|
|
54
|
+
return cells.map((cell) => cell
|
|
55
|
+
.map((value, column) => {
|
|
56
|
+
if (column === cell.length - 1)
|
|
57
|
+
return value;
|
|
58
|
+
const width = widths[column] ?? value.length;
|
|
59
|
+
return column === 0 ? value.padStart(width) : value.padEnd(width);
|
|
60
|
+
})
|
|
61
|
+
.join(COLUMN_GAP));
|
|
62
|
+
}
|
|
63
|
+
/** ISO-8601 UTC, shortened to the minute. Unknown shapes are printed as they came. */
|
|
64
|
+
function formatTime(updatedAt) {
|
|
65
|
+
const safe = safeText(updatedAt);
|
|
66
|
+
const match = /^(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2})/.exec(safe);
|
|
67
|
+
if (match === null)
|
|
68
|
+
return safe;
|
|
69
|
+
return `${match[1]} ${match[2]}Z`;
|
|
70
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { CliRunner, TargetProfile } from "./contract.js";
|
|
2
|
+
/**
|
|
3
|
+
* @param target the profile the pipeline was built for, when the caller knows it.
|
|
4
|
+
* The shim-stated home wins, but only through the profile builder, which resolves "~/x" and
|
|
5
|
+
* relative paths to absolute form (FR-3, T-CLI-18). The resolved profile is the fallback;
|
|
6
|
+
* preferring it over the raw string ensures the pipeline never sees an unresolved path.
|
|
7
|
+
*/
|
|
8
|
+
export declare function createCliRunner(target?: TargetProfile): CliRunner;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// One invocation of the command binary: parse, call the pipeline, print.
|
|
2
|
+
// Every decision this file appears to make is a decision the pipeline made (FR-60).
|
|
3
|
+
import { CONFIRM_FLAG, isConfirmFlag, parseArgs, USAGE } from "./args.js";
|
|
4
|
+
import { safeLines, safeText } from "./presentation.js";
|
|
5
|
+
import { renderLanding, renderListing } from "./render.js";
|
|
6
|
+
/**
|
|
7
|
+
* The shim may state the target home; it never states the window size.
|
|
8
|
+
* These stand for "not stated": the pipeline was built for this target and
|
|
9
|
+
* applies the adapter default (FR-3).
|
|
10
|
+
*/
|
|
11
|
+
const HOME_NOT_STATED = "";
|
|
12
|
+
const WINDOW_NOT_STATED = 0;
|
|
13
|
+
/**
|
|
14
|
+
* @param target the profile the pipeline was built for, when the caller knows it.
|
|
15
|
+
* The shim-stated home wins, but only through the profile builder, which resolves "~/x" and
|
|
16
|
+
* relative paths to absolute form (FR-3, T-CLI-18). The resolved profile is the fallback;
|
|
17
|
+
* preferring it over the raw string ensures the pipeline never sees an unresolved path.
|
|
18
|
+
*/
|
|
19
|
+
export function createCliRunner(target) {
|
|
20
|
+
return {
|
|
21
|
+
run: (invocation, pipeline) => run(invocation, pipeline, target),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
async function run(invocation, pipeline, fallback) {
|
|
25
|
+
const parsed = parseArgs(invocation.argv, invocation.cwd);
|
|
26
|
+
if (!parsed.ok) {
|
|
27
|
+
return { stdout: [], stderr: [parsed.problem, USAGE], exitCode: 2 };
|
|
28
|
+
}
|
|
29
|
+
const { selection, onlyAgent, onlyHome, confirmationToken } = parsed.args;
|
|
30
|
+
const target = {
|
|
31
|
+
// The shim states the agent. The binary never guesses it.
|
|
32
|
+
agent: invocation.targetAgent,
|
|
33
|
+
home: fallback?.home ?? invocation.targetHome ?? HOME_NOT_STATED,
|
|
34
|
+
windowTokens: fallback?.windowTokens ?? WINDOW_NOT_STATED,
|
|
35
|
+
};
|
|
36
|
+
if (selection === null) {
|
|
37
|
+
const request = {
|
|
38
|
+
repoRoot: invocation.cwd,
|
|
39
|
+
target,
|
|
40
|
+
onlyAgent,
|
|
41
|
+
onlyHome,
|
|
42
|
+
};
|
|
43
|
+
try {
|
|
44
|
+
const listing = await pipeline.list(request);
|
|
45
|
+
return {
|
|
46
|
+
stdout: renderListing(listing, invocation.cwd),
|
|
47
|
+
stderr: [],
|
|
48
|
+
exitCode: 0,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
return failure(`The listing failed: ${messageOf(error)}`, "Fix that, then run /resume-from again.");
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const request = {
|
|
56
|
+
repoRoot: invocation.cwd,
|
|
57
|
+
target,
|
|
58
|
+
selection,
|
|
59
|
+
onlyAgent,
|
|
60
|
+
onlyHome,
|
|
61
|
+
};
|
|
62
|
+
// Confirming still previews first: a blocked import must not be committed (FR-33).
|
|
63
|
+
const preview = await pipeline.preview(request).then((report) => ({ ok: true, report }), (error) => ({ ok: false, error }));
|
|
64
|
+
if (!preview.ok) {
|
|
65
|
+
return failure(`Could not open the preview: ${messageOf(preview.error)}`, 'Run "/resume-from" to see the numbered list again.');
|
|
66
|
+
}
|
|
67
|
+
const report = preview.report;
|
|
68
|
+
if (report.blocked) {
|
|
69
|
+
return {
|
|
70
|
+
stdout: safeLines(report.lines),
|
|
71
|
+
stderr: [
|
|
72
|
+
`The import cannot run: ${safeText(report.blockedReason ?? "the preview did not say why.")}`,
|
|
73
|
+
],
|
|
74
|
+
exitCode: 1,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
if (confirmationToken === null) {
|
|
78
|
+
return {
|
|
79
|
+
stdout: [
|
|
80
|
+
...safeLines(report.lines),
|
|
81
|
+
"",
|
|
82
|
+
`Run ${renderCommand([...invocation.argv, "--confirm", report.confirmationToken])} to import it.`,
|
|
83
|
+
],
|
|
84
|
+
stderr: [],
|
|
85
|
+
exitCode: 0,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
// Neither Codex nor Claude Code can move the user, so there is no runtime (C-2).
|
|
90
|
+
const result = await pipeline.commit(request, null, confirmationToken);
|
|
91
|
+
return { stdout: renderLanding(result), stderr: [], exitCode: 0 };
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
return failure(`The import failed: ${messageOf(error)}`, `Run ${renderCommand(withoutConfirmation(invocation.argv))} to see the preview again.`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function failure(what, nextStep) {
|
|
98
|
+
return { stdout: [], stderr: [what, nextStep], exitCode: 2 };
|
|
99
|
+
}
|
|
100
|
+
function withoutConfirmation(argv) {
|
|
101
|
+
const index = argv.findIndex(isConfirmFlag);
|
|
102
|
+
if (index < 0)
|
|
103
|
+
return argv;
|
|
104
|
+
// "--confirm <token>" consumes two slots; "--confirm=<token>" consumes one.
|
|
105
|
+
const consumed = argv[index] === CONFIRM_FLAG ? 2 : 1;
|
|
106
|
+
return [...argv.slice(0, index), ...argv.slice(index + consumed)];
|
|
107
|
+
}
|
|
108
|
+
function renderCommand(argv) {
|
|
109
|
+
return ["/resume-from", ...argv].map(quoteArgument).join(" ");
|
|
110
|
+
}
|
|
111
|
+
function quoteArgument(argument) {
|
|
112
|
+
if (/^[A-Za-z0-9_./:=+-]+$/.test(argument))
|
|
113
|
+
return argument;
|
|
114
|
+
return `'${argument.replaceAll("'", `'"'"'`)}'`;
|
|
115
|
+
}
|
|
116
|
+
function messageOf(error) {
|
|
117
|
+
if (typeof error === "string")
|
|
118
|
+
return safeText(error);
|
|
119
|
+
if (typeof error === "object" && error !== null && "message" in error) {
|
|
120
|
+
const message = error.message;
|
|
121
|
+
if (typeof message === "string")
|
|
122
|
+
return safeText(message);
|
|
123
|
+
}
|
|
124
|
+
return safeText(String(error));
|
|
125
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { AdapterRole, AgentAdapter, AgentCapabilities, LandingLevel, ProvenanceSupport, SelectionLevel, SerializedSession, StoredSessionFacts, SwitchOutcome, ValidationDefect } from "../adapters/contract.js";
|
|
2
|
+
export type { AdapterRole, AgentAdapter, AgentCapabilities, LandingLevel, ProvenanceSupport, SelectionLevel, SerializedSession, StoredSessionFacts, SwitchOutcome, ValidationDefect, };
|
|
3
|
+
import type { CliExit, CliInvocation, CliOutcome, CliRunner } from "./cli/contract.js";
|
|
4
|
+
export type { CliExit, CliInvocation, CliOutcome, CliRunner };
|
|
5
|
+
import type { PiCommandContext, PiResumeFromCommand, PiSwitchContext, PiSwitchOptions, PiSwitchResult } from "./pi-extension/contract.js";
|
|
6
|
+
export type { PiCommandContext, PiResumeFromCommand, PiSwitchContext, PiSwitchOptions, PiSwitchResult, };
|
|
7
|
+
import type { AgentRuntime, HandoverInstruction, HomeFailure, ImportPipeline, ImportRequest, LandingResult, Listing, ListRequest, PreviewReport, PreviewWarning, SelectionError, SelectionInput, WarningKind } from "../import/contract.js";
|
|
8
|
+
export type { AgentRuntime, HandoverInstruction, HomeFailure, ImportPipeline, ImportRequest, LandingResult, Listing, ListRequest, PreviewReport, PreviewWarning, SelectionError, SelectionInput, WarningKind, };
|
|
9
|
+
import type { ConfigError, ConfigLoader, HomeEntry, ImportConfig, WindowOverride } from "../platform/config/contract.js";
|
|
10
|
+
export type { ConfigError, ConfigLoader, HomeEntry, ImportConfig, WindowOverride };
|
|
11
|
+
import type { CommitDistance, RepoIdentity, RepoReader } from "../platform/repo/contract.js";
|
|
12
|
+
export type { CommitDistance, RepoIdentity, RepoReader };
|
|
13
|
+
import type { Bytes, CommitError, CommitHandle, CommitRefusal, FileCommitter, PendingFile } from "../platform/store/contract.js";
|
|
14
|
+
export type { Bytes, CommitError, CommitHandle, CommitRefusal, FileCommitter, PendingFile };
|
|
15
|
+
import type { EstimatorFactory, EstimatorFamily, TokenEstimator } from "../platform/tokens/contract.js";
|
|
16
|
+
export type { EstimatorFactory, EstimatorFamily, TokenEstimator };
|
|
17
|
+
import type { AgentId, CanonicalSession, CanonicalTurn, HomePath, ProvenanceMarker, RepoSnapshot, SessionDescriptor, SessionId, SessionRef, SourceProvenance, TargetProfile, ToolCallRecord, ToolEffect, TurnKind, TurnRole } from "../session/contract.js";
|
|
18
|
+
export type { AgentId, CanonicalSession, CanonicalTurn, HomePath, ProvenanceMarker, RepoSnapshot, SessionDescriptor, SessionId, SessionRef, SourceProvenance, TargetProfile, ToolCallRecord, ToolEffect, TurnKind, TurnRole, };
|
|
19
|
+
/** The agent list. Adding an agent adds one line here (FR-57). */
|
|
20
|
+
export interface AgentRegistry {
|
|
21
|
+
/** Every adapter, in the order they were listed. */
|
|
22
|
+
all(): AgentAdapter[];
|
|
23
|
+
/** Rejects when the agent has no adapter (FR-56). */
|
|
24
|
+
get(agent: AgentId): AgentAdapter;
|
|
25
|
+
/** Adapters whose roles include "source" (FR-59). */
|
|
26
|
+
sources(): AgentAdapter[];
|
|
27
|
+
/** Adapters whose roles include "target" (FR-59). */
|
|
28
|
+
targets(): AgentAdapter[];
|
|
29
|
+
}
|
|
30
|
+
/** Builds one pipeline for one target agent. */
|
|
31
|
+
export interface HostWiring {
|
|
32
|
+
registry(): AgentRegistry;
|
|
33
|
+
pipelineFor(target: TargetProfile): Promise<ImportPipeline>;
|
|
34
|
+
}
|
|
35
|
+
/** Builds the target profile for the agent the user is in (FR-3, FR-18). */
|
|
36
|
+
export interface TargetProfileBuilder {
|
|
37
|
+
/**
|
|
38
|
+
* Uses the adapter's declared default home when home is null (FR-3),
|
|
39
|
+
* and the user's window override when there is one (FR-18).
|
|
40
|
+
*/
|
|
41
|
+
build(agent: AgentId, home: HomePath | null, config: ImportConfig): TargetProfile;
|
|
42
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which entry point runs, and starting it.
|
|
3
|
+
*
|
|
4
|
+
* C-1 forces two mechanisms: Codex and Claude Code cannot host the command, so they call a
|
|
5
|
+
* binary; Pi can, and its switch needs a live command context (C-10), so it loads an extension
|
|
6
|
+
* in-process. Exactly one of them runs per process, and which one is read from the target
|
|
7
|
+
* adapter's declared `selection` level — never from its name (FR-43, FR-58).
|
|
8
|
+
*
|
|
9
|
+
* The two starts are not symmetrical, and that is the design rather than an omission: the binary
|
|
10
|
+
* is handed an invocation and answers with an outcome, while the extension is handed the live
|
|
11
|
+
* context C-10 proved the switch needs and answers by registering a command.
|
|
12
|
+
*/
|
|
13
|
+
import type { AgentCapabilities, AgentId, CliInvocation, CliOutcome, HomePath } from "./contract.js";
|
|
14
|
+
import { type KeySource, type PiCommandRegistrar, type PiUi, type SessionPicker } from "./pi-extension/index.js";
|
|
15
|
+
import { type HostDeps } from "./wiring.js";
|
|
16
|
+
export type { KeySource, PiCommandRegistrar, PiUi };
|
|
17
|
+
/** The two mechanisms C-1 forces. */
|
|
18
|
+
export type EntryPointKind = "command-binary" | "interactive-picker";
|
|
19
|
+
/** Which entry point hosts an agent (FR-43, FR-58). */
|
|
20
|
+
export declare function entryPointFor(capabilities: AgentCapabilities): EntryPointKind;
|
|
21
|
+
/**
|
|
22
|
+
* One invocation of the command binary, from configuration to printed lines.
|
|
23
|
+
*
|
|
24
|
+
* Every failure is an outcome rather than a rejection: the binary's contract is an exit code and
|
|
25
|
+
* two streams, so a configuration error reaches the user as exit 2 and a sentence (FR-56).
|
|
26
|
+
*/
|
|
27
|
+
export declare function runCommandBinary(invocation: CliInvocation, deps?: HostDeps): Promise<CliOutcome>;
|
|
28
|
+
/** What the agent's own process supplies when it loads the extension. */
|
|
29
|
+
export interface PiActivation {
|
|
30
|
+
/** The agent the extension is loaded inside. The host states it; this module never guesses. */
|
|
31
|
+
agent: AgentId;
|
|
32
|
+
/** The command surface of the agent that loaded the extension. */
|
|
33
|
+
registrar: PiCommandRegistrar;
|
|
34
|
+
/** How lines reach the user, and how a confirmation is taken. */
|
|
35
|
+
ui: PiUi;
|
|
36
|
+
/** A host-native picker. When present it replaces the lower-level key source. */
|
|
37
|
+
picker?: SessionPicker;
|
|
38
|
+
/** Where the picker's keys come from (FR-9) when the host has no native picker. */
|
|
39
|
+
keys?: KeySource;
|
|
40
|
+
/** The home the agent is running, or null to use the adapter's declared default (FR-3). */
|
|
41
|
+
home: HomePath | null;
|
|
42
|
+
/** The directory the agent is running in. Used to find the repository (FR-13). */
|
|
43
|
+
cwd?: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Registers /resume-from inside an agent that hosts it itself.
|
|
47
|
+
*
|
|
48
|
+
* Unlike the binary this rejects rather than returning an outcome: there is no exit code to
|
|
49
|
+
* carry the failure, and an extension that registered a command it cannot drive would be worse
|
|
50
|
+
* than one that failed to load.
|
|
51
|
+
*/
|
|
52
|
+
export declare function activatePiExtension(activation: PiActivation, deps?: HostDeps): Promise<void>;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which entry point runs, and starting it.
|
|
3
|
+
*
|
|
4
|
+
* C-1 forces two mechanisms: Codex and Claude Code cannot host the command, so they call a
|
|
5
|
+
* binary; Pi can, and its switch needs a live command context (C-10), so it loads an extension
|
|
6
|
+
* in-process. Exactly one of them runs per process, and which one is read from the target
|
|
7
|
+
* adapter's declared `selection` level — never from its name (FR-43, FR-58).
|
|
8
|
+
*
|
|
9
|
+
* The two starts are not symmetrical, and that is the design rather than an omission: the binary
|
|
10
|
+
* is handed an invocation and answers with an outcome, while the extension is handed the live
|
|
11
|
+
* context C-10 proved the switch needs and answers by registering a command.
|
|
12
|
+
*/
|
|
13
|
+
import { createCliRunner } from "./cli/index.js";
|
|
14
|
+
import { createKeyPicker, registerResumeFrom, } from "./pi-extension/index.js";
|
|
15
|
+
import { createHost } from "./wiring.js";
|
|
16
|
+
/**
|
|
17
|
+
* Exhaustive by construction: a new selection level fails to compile here until it is placed,
|
|
18
|
+
* which is the whole reason this is a table and not a branch on the agent.
|
|
19
|
+
*/
|
|
20
|
+
const ENTRY_POINTS = {
|
|
21
|
+
"interactive-picker": "interactive-picker",
|
|
22
|
+
"numbered-list": "command-binary",
|
|
23
|
+
};
|
|
24
|
+
/** Which entry point hosts an agent (FR-43, FR-58). */
|
|
25
|
+
export function entryPointFor(capabilities) {
|
|
26
|
+
return ENTRY_POINTS[capabilities.selection];
|
|
27
|
+
}
|
|
28
|
+
const messageOf = (cause) => cause instanceof Error ? cause.message : String(cause);
|
|
29
|
+
/**
|
|
30
|
+
* One invocation of the command binary, from configuration to printed lines.
|
|
31
|
+
*
|
|
32
|
+
* Every failure is an outcome rather than a rejection: the binary's contract is an exit code and
|
|
33
|
+
* two streams, so a configuration error reaches the user as exit 2 and a sentence (FR-56).
|
|
34
|
+
*/
|
|
35
|
+
export async function runCommandBinary(invocation, deps = {}) {
|
|
36
|
+
try {
|
|
37
|
+
const host = await createHost(deps);
|
|
38
|
+
const declared = host.registry().get(invocation.targetAgent).capabilities();
|
|
39
|
+
if (entryPointFor(declared) !== "command-binary") {
|
|
40
|
+
return {
|
|
41
|
+
stdout: [],
|
|
42
|
+
stderr: [
|
|
43
|
+
`The "${invocation.targetAgent}" adapter declares selection ` +
|
|
44
|
+
`"${declared.selection}", so it hosts /resume-from in-process and not through this ` +
|
|
45
|
+
"binary. Type /resume-from inside the agent itself.",
|
|
46
|
+
],
|
|
47
|
+
exitCode: 2,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
const target = host
|
|
51
|
+
.profiles()
|
|
52
|
+
.build(invocation.targetAgent, invocation.targetHome, host.config());
|
|
53
|
+
const pipeline = await host.pipelineFor(target);
|
|
54
|
+
return await createCliRunner(target).run(invocation, pipeline);
|
|
55
|
+
}
|
|
56
|
+
catch (cause) {
|
|
57
|
+
return { stdout: [], stderr: [messageOf(cause)], exitCode: 2 };
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Registers /resume-from inside an agent that hosts it itself.
|
|
62
|
+
*
|
|
63
|
+
* Unlike the binary this rejects rather than returning an outcome: there is no exit code to
|
|
64
|
+
* carry the failure, and an extension that registered a command it cannot drive would be worse
|
|
65
|
+
* than one that failed to load.
|
|
66
|
+
*/
|
|
67
|
+
export async function activatePiExtension(activation, deps = {}) {
|
|
68
|
+
const host = await createHost(activation.cwd === undefined ? deps : { cwd: activation.cwd, ...deps });
|
|
69
|
+
const declared = host.registry().get(activation.agent).capabilities();
|
|
70
|
+
if (entryPointFor(declared) !== "interactive-picker") {
|
|
71
|
+
throw new Error(`The "${activation.agent}" adapter declares selection "${declared.selection}", so it ` +
|
|
72
|
+
"cannot host the picker in-process. It is driven by the command binary instead.");
|
|
73
|
+
}
|
|
74
|
+
const target = host.profiles().build(activation.agent, activation.home, host.config());
|
|
75
|
+
const pipeline = await host.pipelineFor(target);
|
|
76
|
+
registerResumeFrom(activation.registrar, {
|
|
77
|
+
pipeline,
|
|
78
|
+
picker: pickerFor(activation),
|
|
79
|
+
ui: activation.ui,
|
|
80
|
+
// The extension holds no capability knowledge, so the window comes from here (FR-18).
|
|
81
|
+
windowTokens: target.windowTokens,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
function pickerFor(activation) {
|
|
85
|
+
if (activation.picker !== undefined)
|
|
86
|
+
return activation.picker;
|
|
87
|
+
if (activation.keys !== undefined) {
|
|
88
|
+
return createKeyPicker({ keys: activation.keys, ui: activation.ui });
|
|
89
|
+
}
|
|
90
|
+
throw new Error("Pi activation requires either a native picker or a key source.");
|
|
91
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The composition root. It builds everything and drives nothing: `createHost` loads the
|
|
3
|
+
* configuration, the platform services and the agent list, and the two starts below run the one
|
|
4
|
+
* entry point the target agent's declared capability names.
|
|
5
|
+
*/
|
|
6
|
+
export { AGENTS, type AgentEntry } from "./agents.js";
|
|
7
|
+
export type { AgentAdapter, AgentCapabilities, AgentId, AgentRegistry, AgentRuntime, CliInvocation, CliOutcome, HomePath, HostWiring, ImportConfig, ImportPipeline, ImportRequest, Listing, ListRequest, PreviewReport, TargetProfile, TargetProfileBuilder, } from "./contract.js";
|
|
8
|
+
export { activatePiExtension, type EntryPointKind, entryPointFor, type KeySource, type PiActivation, type PiCommandRegistrar, type PiUi, runCommandBinary, } from "./entry.js";
|
|
9
|
+
export { createTargetProfileBuilder } from "./profile.js";
|
|
10
|
+
export { createAgentRegistry } from "./registry.js";
|
|
11
|
+
export { createHost, type Host, type HostDeps } from "./wiring.js";
|