@timurproko/a1 0.1.8-dev.226 → 0.1.8-dev.259
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/bin/guardian.js +4 -2
- package/bin/supervisor.js +1 -1
- package/bin/ui.js +44 -36
- package/bin/warmup.js +18 -9
- package/dist/cli/dispatch.d.ts +9 -1
- package/dist/cli/dispatch.js +73 -14
- package/dist/cli/package-messages.d.ts +26 -0
- package/dist/cli/package-messages.js +71 -0
- package/dist/cli/packages.d.ts +2 -1
- package/dist/cli/packages.js +12 -19
- package/dist/composition/owned-ui.d.ts +5 -2
- package/dist/composition/owned-ui.js +3 -1
- package/dist/contracts/agent-engine/package-ports.d.ts +6 -0
- package/dist/features/launch/intent.d.ts +5 -3
- package/dist/features/launch/intent.js +7 -2
- package/dist/features/owned-ui/index.d.ts +1 -0
- package/dist/features/owned-ui/index.js +1 -0
- package/dist/features/owned-ui/session-fork-prompt.d.ts +8 -0
- package/dist/features/owned-ui/session-fork-prompt.js +34 -0
- package/dist/foundation/launch-guardian/main.d.ts +2 -0
- package/dist/foundation/launch-guardian/main.js +8 -3
- package/dist/foundation/lifecycle/index.d.ts +2 -0
- package/dist/foundation/lifecycle/index.js +2 -0
- package/dist/foundation/lifecycle/paths.d.ts +2 -0
- package/dist/foundation/lifecycle/paths.js +9 -2
- package/dist/foundation/lifecycle/session-selection.d.ts +9 -0
- package/dist/foundation/lifecycle/session-selection.js +39 -0
- package/dist/foundation/lifecycle/supervisor-startup.d.ts +30 -0
- package/dist/foundation/lifecycle/supervisor-startup.js +106 -0
- package/dist/foundation/process-containment/darwin-process-inspector.d.ts +5 -0
- package/dist/foundation/process-containment/darwin-process-inspector.js +7 -0
- package/dist/foundation/process-containment/index.d.ts +1 -0
- package/dist/foundation/process-containment/index.js +1 -0
- package/dist/foundation/process-containment/windows-process-inspector.d.ts +2 -1
- package/dist/foundation/process-containment/windows-process-inspector.js +4 -2
- package/dist/foundation/release/bootstrap.d.ts +10 -3
- package/dist/foundation/release/bootstrap.js +58 -25
- package/dist/foundation/release/dependency-layer.js +11 -10
- package/dist/foundation/release/immutable-platform.d.ts +6 -0
- package/dist/foundation/release/immutable-platform.js +13 -0
- package/dist/foundation/release/index.d.ts +1 -0
- package/dist/foundation/release/index.js +1 -0
- package/dist/foundation/release/release-store.d.ts +1 -1
- package/dist/foundation/release/release-store.js +4 -2
- package/dist/foundation/release/restart-certification.d.ts +67 -0
- package/dist/foundation/release/restart-certification.js +211 -0
- package/dist/foundation/release/update.js +4 -4
- package/dist/foundation/release/warmup.js +1 -1
- package/dist/foundation/startup/startup-runtime.d.ts +2 -2
- package/dist/foundation/startup/startup-runtime.js +1 -1
- package/dist/foundation/supervision/main.d.ts +1 -1
- package/dist/foundation/supervision/main.js +60 -30
- package/dist/foundation/supervision/server.js +14 -1
- package/dist/integrations/pi/components/shell-footer-status.js +28 -12
- package/dist/integrations/pi/components/shell-selectors-dialogs.d.ts +4 -1
- package/dist/integrations/pi/components/shell-selectors-dialogs.js +2 -1
- package/dist/integrations/pi/components/shell-shared-facade.d.ts +5 -0
- package/dist/integrations/pi/engine/adapter.d.ts +6 -0
- package/dist/integrations/pi/engine/adapter.js +354 -53
- package/dist/integrations/pi/engine/index.d.ts +1 -0
- package/dist/integrations/pi/engine/index.js +1 -0
- package/dist/integrations/pi/engine/package-integration.js +31 -25
- package/dist/integrations/pi/engine/runtime-integration.d.ts +3 -0
- package/dist/integrations/pi/engine/runtime-integration.js +11 -4
- package/dist/integrations/pi/engine/session-selection.d.ts +28 -0
- package/dist/integrations/pi/engine/session-selection.js +90 -0
- package/dist/integrations/pi/engine/workflows.d.ts +18 -1
- package/dist/integrations/pi/session-ui/session-shell-root.d.ts +5 -1
- package/dist/integrations/pi/session-ui/session-shell-root.js +76 -24
- package/dist/integrations/pi/session-ui/session-shell.d.ts +1 -1
- package/dist/integrations/pi/session-ui/session-shell.js +46 -14
- package/dist/integrations/pi/session-ui/session-viewport-controller.d.ts +2 -1
- package/dist/integrations/pi/session-ui/session-viewport-controller.js +47 -18
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +12 -1
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +166 -26
- package/dist/native/darwin-arm64/manifest.json +4 -4
- package/dist/native/darwin-arm64/process-guardian +0 -0
- package/dist/native/linux-x64/manifest.json +1 -1
- package/dist/native/linux-x64/process-guardian +0 -0
- package/dist/native/win32-x64/manifest.json +2 -2
- package/dist/native/win32-x64/process-guardian.exe +0 -0
- package/dist/ui/components/index.d.ts +1 -0
- package/dist/ui/components/index.js +1 -0
- package/dist/ui/components/text-selection.js +8 -35
- package/dist/ui/components/transcript-viewport.d.ts +8 -2
- package/dist/ui/components/transcript-viewport.js +8 -6
- package/dist/ui/components/visible-hyperlinks.d.ts +19 -0
- package/dist/ui/components/visible-hyperlinks.js +64 -0
- package/docs/architecture/process-guardian-provenance.md +3 -1
- package/docs/architecture/ui-reference-provenance.md +2 -0
- package/docs/ci-release-runbook.md +1 -1
- package/docs/features/launch-profiles.md +17 -1
- package/docs/manual-ghost-link-baseline.md +89 -0
- package/package.json +1 -1
package/bin/guardian.js
CHANGED
|
@@ -5,18 +5,20 @@ startup.enableEnvironmentCompileCache(process.env);
|
|
|
5
5
|
await startup.markStartupPhase(process.env, "guardian-start");
|
|
6
6
|
const { fileURLToPath } = await import("node:url");
|
|
7
7
|
const { resolve } = await import("node:path");
|
|
8
|
+
const { parseSessionSelection } = await import("../dist/foundation/lifecycle/index.js");
|
|
8
9
|
const { runLaunchGuardian } = await import("../dist/foundation/launch-guardian/index.js");
|
|
9
10
|
|
|
10
11
|
const releaseRoot = process.env.A1_RELEASE_ROOT ?? fileURLToPath(new URL("..", import.meta.url));
|
|
11
12
|
const profileId = process.env.A1_LAUNCH_PROFILE ?? "a1";
|
|
12
13
|
|
|
13
|
-
runLaunchGuardian({
|
|
14
|
+
Promise.resolve().then(() => runLaunchGuardian({
|
|
15
|
+
sessionSelection: parseSessionSelection(process.argv.slice(2)),
|
|
14
16
|
profileId,
|
|
15
17
|
releaseRoot,
|
|
16
18
|
uiEntry: resolve(releaseRoot, "bin", "ui.js"),
|
|
17
19
|
environment: process.env,
|
|
18
20
|
cwd: process.cwd(),
|
|
19
|
-
}).then(
|
|
21
|
+
})).then(
|
|
20
22
|
code => { process.exitCode = code; },
|
|
21
23
|
error => {
|
|
22
24
|
console.error(error instanceof Error ? error.message : String(error));
|
package/bin/supervisor.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { runSupervisor } from "../dist/foundation/supervision/index.js";
|
|
3
3
|
|
|
4
|
-
runSupervisor().catch(error => {
|
|
4
|
+
runSupervisor(process.argv.slice(2)).catch(error => {
|
|
5
5
|
console.error(error instanceof Error ? error.stack ?? error.message : String(error));
|
|
6
6
|
process.exitCode = 1;
|
|
7
7
|
});
|
package/bin/ui.js
CHANGED
|
@@ -2,48 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
const startup = await import("../dist/foundation/startup/index.js");
|
|
4
4
|
startup.enableEnvironmentCompileCache(process.env);
|
|
5
|
+
// Performance: begin the exact launch graph together while the trace write is pending.
|
|
6
|
+
// Direct owned-module entries avoid evaluating unrelated barrel exports before first paint.
|
|
7
|
+
const modules = Promise.all([
|
|
8
|
+
import("./module-identity.js"),
|
|
9
|
+
import("node:url"),
|
|
10
|
+
import("../dist/features/launch/runtime-selection.js"),
|
|
11
|
+
import("../dist/foundation/lifecycle/session-selection.js"),
|
|
12
|
+
import("../dist/features/owned-ui/project-trust-prompt.js"),
|
|
13
|
+
import("../dist/features/owned-ui/session-fork-prompt.js"),
|
|
14
|
+
import("../dist/features/owned-ui/run.js"),
|
|
15
|
+
import("../dist/composition/owned-ui.js"),
|
|
16
|
+
]);
|
|
5
17
|
await startup.markStartupPhase(process.env, "ui-entry");
|
|
6
|
-
const
|
|
7
|
-
|
|
18
|
+
const [
|
|
19
|
+
{ assertSinglePiTuiModuleAtLaunch },
|
|
20
|
+
{ fileURLToPath },
|
|
21
|
+
{ runSelectedInteractiveRuntime },
|
|
22
|
+
{ parseSessionSelection },
|
|
23
|
+
{ createConsoleProjectTrustPrompt },
|
|
24
|
+
{ createConsoleSessionForkPrompt },
|
|
25
|
+
{ runOwnedUi },
|
|
26
|
+
{ composeOwnedUi },
|
|
27
|
+
] = await modules;
|
|
8
28
|
|
|
9
|
-
// Compatibility: before the composition
|
|
10
|
-
// resolve it to the same copy, so extensions and the owned UI share one module
|
|
11
|
-
// identity (see bin/module-identity.js for the full story). Nothing is repaired
|
|
12
|
-
// here — A1's package manifest decides which copy wins, and this only reports
|
|
13
|
-
// when that stopped being true.
|
|
29
|
+
// Compatibility: before the composition uses pinned Pi's terminal stack: confirm A1 and Pi
|
|
30
|
+
// resolve it to the same copy, so extensions and the owned UI share one module identity.
|
|
14
31
|
assertSinglePiTuiModuleAtLaunch(fileURLToPath(new URL("..", import.meta.url)), message => process.stderr.write(message));
|
|
32
|
+
await startup.markStartupPhase(process.env, "ui-modules-loaded");
|
|
15
33
|
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
await startup.markStartupPhase(process.env, "ui-modules-loaded");
|
|
34
|
-
const { application, settings } = await composeOwnedUi({
|
|
35
|
-
cwd: process.cwd(),
|
|
36
|
-
profileId,
|
|
37
|
-
ownedSurfaces,
|
|
38
|
-
projectTrustPrompt: createConsoleProjectTrustPrompt(),
|
|
39
|
-
...(sessionPath === undefined ? {} : { sessionPath }),
|
|
40
|
-
});
|
|
41
|
-
return await runOwnedUi({ application, ...(settings === null ? {} : { settings }) });
|
|
42
|
-
},
|
|
34
|
+
const sessionSelection = parseSessionSelection(process.argv.slice(2));
|
|
35
|
+
const profile = process.env.A1_LAUNCH_PROFILE ?? "a1";
|
|
36
|
+
Promise.resolve().then(() => {
|
|
37
|
+
if (sessionSelection && profile !== "a1") throw new Error("session selection requires the normal A1 profile");
|
|
38
|
+
return runSelectedInteractiveRuntime(profile, {
|
|
39
|
+
ownedUi: async (profileId, ownedSurfaces) => {
|
|
40
|
+
const { application, settings } = await composeOwnedUi({
|
|
41
|
+
cwd: process.cwd(),
|
|
42
|
+
profileId,
|
|
43
|
+
ownedSurfaces,
|
|
44
|
+
projectTrustPrompt: createConsoleProjectTrustPrompt(),
|
|
45
|
+
sessionForkPrompt: createConsoleSessionForkPrompt(),
|
|
46
|
+
...(sessionSelection === undefined ? {} : { sessionSelection }),
|
|
47
|
+
});
|
|
48
|
+
return await runOwnedUi({ application, ...(settings === null ? {} : { settings }) });
|
|
49
|
+
},
|
|
50
|
+
});
|
|
43
51
|
}).then(
|
|
44
52
|
code => { process.exitCode = code; },
|
|
45
53
|
error => {
|
|
46
|
-
console.error(error instanceof Error ? error.
|
|
47
|
-
process.exitCode = 1;
|
|
54
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
55
|
+
process.exitCode = error?.name === "PiSessionSelectionError" ? error.exitCode : 1;
|
|
48
56
|
},
|
|
49
57
|
);
|
package/bin/warmup.js
CHANGED
|
@@ -4,15 +4,24 @@ const startup = await import("../dist/foundation/startup/index.js");
|
|
|
4
4
|
startup.assertImmutableWarmupEnvironment(process.env);
|
|
5
5
|
startup.enableEnvironmentCompileCache(process.env);
|
|
6
6
|
|
|
7
|
-
// Security: this entry imports but never composes, so it
|
|
8
|
-
// path, trust callback, executable resource loader,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
import("
|
|
12
|
-
import("../dist/
|
|
13
|
-
import("../dist/
|
|
7
|
+
// Security: this entry imports the exact interactive graph but never composes it, so it
|
|
8
|
+
// creates no terminal, profile/session path, trust callback, executable resource loader,
|
|
9
|
+
// extension runner, or network client.
|
|
10
|
+
const [identity, launch, selection, trustPrompt, forkPrompt, run, composition] = await Promise.all([
|
|
11
|
+
import("./module-identity.js"),
|
|
12
|
+
import("../dist/features/launch/runtime-selection.js"),
|
|
13
|
+
import("../dist/foundation/lifecycle/session-selection.js"),
|
|
14
|
+
import("../dist/features/owned-ui/project-trust-prompt.js"),
|
|
15
|
+
import("../dist/features/owned-ui/session-fork-prompt.js"),
|
|
16
|
+
import("../dist/features/owned-ui/run.js"),
|
|
17
|
+
import("../dist/composition/owned-ui.js"),
|
|
14
18
|
]);
|
|
15
|
-
if (typeof
|
|
16
|
-
|| typeof
|
|
19
|
+
if (typeof identity.assertSinglePiTuiModuleAtLaunch !== "function"
|
|
20
|
+
|| typeof launch.runSelectedInteractiveRuntime !== "function"
|
|
21
|
+
|| typeof selection.parseSessionSelection !== "function"
|
|
22
|
+
|| typeof trustPrompt.createConsoleProjectTrustPrompt !== "function"
|
|
23
|
+
|| typeof forkPrompt.createConsoleSessionForkPrompt !== "function"
|
|
24
|
+
|| typeof run.runOwnedUi !== "function"
|
|
25
|
+
|| typeof composition.composeOwnedUi !== "function") {
|
|
17
26
|
throw new Error("immutable startup graph is incomplete");
|
|
18
27
|
}
|
package/dist/cli/dispatch.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { type InteractiveLaunchIntent, type LaunchProfileId } from "../features/launch/index.js";
|
|
1
|
+
import { type InteractiveLaunchIntent, type LaunchProfileId, type SessionSelection } from "../features/launch/index.js";
|
|
2
2
|
import type { CliCapabilities } from "./capabilities.js";
|
|
3
3
|
import type { PackageCommandRequest } from "./packages.js";
|
|
4
|
+
import { type PackageCliVerb, type PackageSyntaxDiagnostic } from "./package-messages.js";
|
|
4
5
|
export type UpdateChannel = "stable" | "next";
|
|
5
6
|
export interface CliHandlers {
|
|
6
7
|
readonly launch: (intent: InteractiveLaunchIntent) => Promise<number>;
|
|
@@ -19,9 +20,16 @@ export type CliCommand = {
|
|
|
19
20
|
readonly kind: "noop";
|
|
20
21
|
} | {
|
|
21
22
|
readonly kind: "help";
|
|
23
|
+
} | {
|
|
24
|
+
readonly kind: "package-help";
|
|
25
|
+
readonly verb: PackageCliVerb;
|
|
26
|
+
} | {
|
|
27
|
+
readonly kind: "package-error";
|
|
28
|
+
readonly diagnostic: PackageSyntaxDiagnostic;
|
|
22
29
|
} | {
|
|
23
30
|
readonly kind: "launch";
|
|
24
31
|
readonly profileId: LaunchProfileId;
|
|
32
|
+
readonly sessionSelection?: SessionSelection;
|
|
25
33
|
} | {
|
|
26
34
|
readonly kind: "version";
|
|
27
35
|
} | {
|
package/dist/cli/dispatch.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import { interactiveLaunchIntent } from "../features/launch/index.js";
|
|
1
|
+
import { interactiveLaunchIntent, parseSessionSelection } from "../features/launch/index.js";
|
|
2
|
+
import { packageCommandHelp, renderPackageSyntax } from "./package-messages.js";
|
|
2
3
|
import { PRODUCT_TEXT } from "../product-identity.js";
|
|
3
4
|
export function cliUsage(capabilities) {
|
|
4
5
|
return PRODUCT_TEXT.usage([
|
|
5
6
|
"",
|
|
7
|
+
"--session <path|id>",
|
|
8
|
+
"--session-dir <dir> --session <path|id>",
|
|
6
9
|
...(capabilities.developmentComparison ? ["pi"] : []),
|
|
7
10
|
"--help",
|
|
8
11
|
"-h",
|
|
@@ -25,6 +28,8 @@ export function cliHelp(capabilities) {
|
|
|
25
28
|
return [
|
|
26
29
|
"Common:",
|
|
27
30
|
` ${command}`,
|
|
31
|
+
` ${command} --session <path|id>`,
|
|
32
|
+
` ${command} --session-dir <dir> --session <path|id>`,
|
|
28
33
|
...(capabilities.developmentComparison ? [` ${command} pi`] : []),
|
|
29
34
|
` ${command} --help`,
|
|
30
35
|
` ${command} -h`,
|
|
@@ -56,12 +61,20 @@ export async function dispatchCli(arguments_, handlers, output, capabilities) {
|
|
|
56
61
|
output.stdout(cliHelp(capabilities));
|
|
57
62
|
return 0;
|
|
58
63
|
}
|
|
64
|
+
if (command.kind === "package-help") {
|
|
65
|
+
output.stdout(packageCommandHelp(command.verb));
|
|
66
|
+
return 0;
|
|
67
|
+
}
|
|
68
|
+
if (command.kind === "package-error") {
|
|
69
|
+
output.stderr(renderPackageSyntax(command.diagnostic));
|
|
70
|
+
return 2;
|
|
71
|
+
}
|
|
59
72
|
if (command.kind === "error") {
|
|
60
73
|
output.stderr(`${command.message}\n`);
|
|
61
74
|
return 2;
|
|
62
75
|
}
|
|
63
76
|
if (command.kind === "launch")
|
|
64
|
-
return await handlers.launch(interactiveLaunchIntent(command.profileId));
|
|
77
|
+
return await handlers.launch(interactiveLaunchIntent(command.profileId, command.sessionSelection));
|
|
65
78
|
if (command.kind === "version")
|
|
66
79
|
return await handlers.version();
|
|
67
80
|
if (command.kind === "packages")
|
|
@@ -72,6 +85,15 @@ export function parseCliCommand(arguments_, capabilities) {
|
|
|
72
85
|
if (arguments_.length === 0)
|
|
73
86
|
return { kind: "launch", profileId: "a1" };
|
|
74
87
|
const [command, ...rest] = arguments_;
|
|
88
|
+
if (command === "--session" || command === "--session-dir") {
|
|
89
|
+
try {
|
|
90
|
+
const sessionSelection = parseSessionSelection(arguments_);
|
|
91
|
+
return { kind: "launch", profileId: "a1", ...(sessionSelection === undefined ? {} : { sessionSelection }) };
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
return { kind: "error", message: PRODUCT_TEXT.diagnostic(`could not parse session launch: ${error instanceof Error ? error.message : String(error)}`) };
|
|
95
|
+
}
|
|
96
|
+
}
|
|
75
97
|
if (command === "--help" || command === "-h")
|
|
76
98
|
return withoutArguments(rest, { kind: "help" });
|
|
77
99
|
if (command === "--version" || command === "-v")
|
|
@@ -132,11 +154,21 @@ function updateGrammarError(detail) {
|
|
|
132
154
|
}
|
|
133
155
|
function parsePiPackageCommand(arguments_) {
|
|
134
156
|
const [verb, ...rest] = arguments_;
|
|
157
|
+
if ((verb === "install" || verb === "remove" || verb === "uninstall" || verb === "list" || verb === "update")
|
|
158
|
+
&& rest.some(value => value === "--help" || value === "-h")) {
|
|
159
|
+
return { kind: "package-help", verb: verb === "uninstall" ? "remove" : verb };
|
|
160
|
+
}
|
|
135
161
|
if (verb === "install" || verb === "remove" || verb === "uninstall") {
|
|
136
162
|
return parseSourceCommand(verb === "install" ? "install" : "remove", rest);
|
|
137
163
|
}
|
|
138
|
-
if (verb === "list")
|
|
139
|
-
|
|
164
|
+
if (verb === "list") {
|
|
165
|
+
const flag = rest.find(argument => argument.startsWith("-"));
|
|
166
|
+
if (flag !== undefined)
|
|
167
|
+
return packageOptionError(flag, "list");
|
|
168
|
+
if (rest[0] !== undefined)
|
|
169
|
+
return packageSyntax({ verb: "list", kind: "unexpected-argument", value: rest[0] });
|
|
170
|
+
return { kind: "packages", request: { verb: "list", source: null } };
|
|
171
|
+
}
|
|
140
172
|
if (verb === "update")
|
|
141
173
|
return parsePiPackageUpdate(rest);
|
|
142
174
|
return { kind: "noop" };
|
|
@@ -144,8 +176,25 @@ function parsePiPackageCommand(arguments_) {
|
|
|
144
176
|
function parsePiPackageUpdate(rest) {
|
|
145
177
|
if (rest.length === 0)
|
|
146
178
|
return pinnedPiUpdateError();
|
|
147
|
-
if (rest.length > 1)
|
|
148
|
-
|
|
179
|
+
if (rest.length > 1) {
|
|
180
|
+
const unknown = rest.find(value => value.startsWith("-") && !["--extensions", "--models", "--self", "--all"].includes(value));
|
|
181
|
+
if (unknown !== undefined)
|
|
182
|
+
return packageOptionError(unknown, "update");
|
|
183
|
+
if (rest.includes("--self") || rest.includes("--all") || rest.includes("self") || rest.includes("pi"))
|
|
184
|
+
return pinnedPiUpdateError();
|
|
185
|
+
if (rest.every(value => value === rest[0]) && rest[0]?.startsWith("-")) {
|
|
186
|
+
return { kind: "error", message: PRODUCT_TEXT.diagnostic("pi update accepts one target.") };
|
|
187
|
+
}
|
|
188
|
+
const sources = rest.filter(value => !value.startsWith("-"));
|
|
189
|
+
if (sources[1] !== undefined)
|
|
190
|
+
return packageSyntax({ verb: "update", kind: "unexpected-argument", value: sources[1] });
|
|
191
|
+
const message = rest.includes("--models")
|
|
192
|
+
? rest.includes("--extensions")
|
|
193
|
+
? "--models cannot be combined with --self, --extensions, --all, or --extension"
|
|
194
|
+
: "--models cannot be combined with a positional source"
|
|
195
|
+
: "positional update targets cannot be combined with --self, --extensions, or --all";
|
|
196
|
+
return packageSyntax({ verb: "update", kind: "conflict", message });
|
|
197
|
+
}
|
|
149
198
|
const [target] = rest;
|
|
150
199
|
if (target === "--extensions")
|
|
151
200
|
return { kind: "packages", request: { verb: "update", source: null } };
|
|
@@ -154,7 +203,7 @@ function parsePiPackageUpdate(rest) {
|
|
|
154
203
|
if (target === "--self" || target === "--all" || target === "self" || target === "pi")
|
|
155
204
|
return pinnedPiUpdateError();
|
|
156
205
|
if (target === undefined || target.startsWith("-"))
|
|
157
|
-
return
|
|
206
|
+
return packageOptionError(target ?? "", "update");
|
|
158
207
|
return { kind: "packages", request: { verb: "update", source: target } };
|
|
159
208
|
}
|
|
160
209
|
function pinnedPiUpdateError() {
|
|
@@ -172,18 +221,28 @@ function pinnedPiUpdateError() {
|
|
|
172
221
|
function parseSourceCommand(verb, rest) {
|
|
173
222
|
const flag = rest.find(argument => argument.startsWith("-"));
|
|
174
223
|
if (flag !== undefined)
|
|
175
|
-
return
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
return { kind: "error", message: PRODUCT_TEXT.diagnostic(`${verb} accepts one package source.`) };
|
|
180
|
-
const [source] = rest;
|
|
224
|
+
return packageOptionError(flag, verb);
|
|
225
|
+
const [source, extra] = rest;
|
|
226
|
+
if (extra !== undefined)
|
|
227
|
+
return packageSyntax({ verb, kind: "unexpected-argument", value: extra });
|
|
181
228
|
if (source === undefined)
|
|
182
|
-
return { kind: "
|
|
229
|
+
return packageSyntax({ verb, kind: "missing-source" });
|
|
183
230
|
if (PROFILE_WORDS.has(source))
|
|
184
231
|
return profileRejection(verb);
|
|
185
232
|
return { kind: "packages", request: { verb, source } };
|
|
186
233
|
}
|
|
234
|
+
function packageSyntax(diagnostic) {
|
|
235
|
+
return { kind: "package-error", diagnostic };
|
|
236
|
+
}
|
|
237
|
+
function packageOptionError(option, verb) {
|
|
238
|
+
if (option.startsWith("--profile") || option === "-l" || option === "--local")
|
|
239
|
+
return profileRejection(verb);
|
|
240
|
+
// Compatibility: these recognized Pi flags remain outside A1's supported subset.
|
|
241
|
+
if (["--extension", "--approve", "--no-approve", "-a", "-na", "--force"].includes(option)) {
|
|
242
|
+
return unknownOption(option, `pi ${verb}`);
|
|
243
|
+
}
|
|
244
|
+
return packageSyntax({ verb, kind: "unknown-option", value: option });
|
|
245
|
+
}
|
|
187
246
|
function withoutArguments(rest, command) {
|
|
188
247
|
if (rest.length === 0)
|
|
189
248
|
return command;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
/** Supported subset of pinned Pi's package-manager CLI presentation. */
|
|
3
|
+
export type PackageCliVerb = "install" | "remove" | "list" | "update";
|
|
4
|
+
export type PackageSyntaxDiagnostic = {
|
|
5
|
+
readonly verb: PackageCliVerb;
|
|
6
|
+
readonly kind: "missing-source";
|
|
7
|
+
} | {
|
|
8
|
+
readonly verb: PackageCliVerb;
|
|
9
|
+
readonly kind: "unknown-option";
|
|
10
|
+
readonly value: string;
|
|
11
|
+
} | {
|
|
12
|
+
readonly verb: PackageCliVerb;
|
|
13
|
+
readonly kind: "unexpected-argument";
|
|
14
|
+
readonly value: string;
|
|
15
|
+
} | {
|
|
16
|
+
readonly verb: "update";
|
|
17
|
+
readonly kind: "conflict";
|
|
18
|
+
readonly message: string;
|
|
19
|
+
};
|
|
20
|
+
type MessageStyle = Pick<typeof chalk, "red" | "dim" | "bold">;
|
|
21
|
+
export declare function packageCommandUsage(verb: PackageCliVerb): string;
|
|
22
|
+
/** Diagnostic facts stay unstyled until the terminal boundary decides color support. */
|
|
23
|
+
export declare function renderPackageSyntax(diagnostic: PackageSyntaxDiagnostic, style?: MessageStyle): string;
|
|
24
|
+
/** Pi's help layout, with unsupported options and examples deliberately absent. */
|
|
25
|
+
export declare function packageCommandHelp(verb: PackageCliVerb, style?: MessageStyle): string;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// Provenance: wording/layout adapted from Pi 0.84.2 packages/coding-agent/src/package-manager-cli.ts
|
|
2
|
+
// at 914cf1472e715297caa30db4b9535d534a9eb718 (MIT); grammar is restricted to A1's supported subset.
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import { PRODUCT_TEXT } from "../product-identity.js";
|
|
5
|
+
export function packageCommandUsage(verb) {
|
|
6
|
+
const command = `${PRODUCT_TEXT.commandName} pi ${verb}`;
|
|
7
|
+
if (verb === "install" || verb === "remove")
|
|
8
|
+
return `${command} <source>`;
|
|
9
|
+
if (verb === "update")
|
|
10
|
+
return `${command} [source|--extensions|--models]`;
|
|
11
|
+
return command;
|
|
12
|
+
}
|
|
13
|
+
/** Diagnostic facts stay unstyled until the terminal boundary decides color support. */
|
|
14
|
+
export function renderPackageSyntax(diagnostic, style = chalk) {
|
|
15
|
+
const usage = packageCommandUsage(diagnostic.verb);
|
|
16
|
+
let message;
|
|
17
|
+
if (diagnostic.kind === "unknown-option") {
|
|
18
|
+
return `${style.red(`Unknown option ${diagnostic.value} for "${diagnostic.verb}".`)}\n`
|
|
19
|
+
+ `${style.dim(`Use "${PRODUCT_TEXT.commandName} --help" or "${usage}".`)}\n`;
|
|
20
|
+
}
|
|
21
|
+
if (diagnostic.kind === "missing-source")
|
|
22
|
+
message = `Missing ${diagnostic.verb} source.`;
|
|
23
|
+
else if (diagnostic.kind === "unexpected-argument")
|
|
24
|
+
message = `Unexpected argument ${diagnostic.value}.`;
|
|
25
|
+
else
|
|
26
|
+
message = diagnostic.message;
|
|
27
|
+
return `${style.red(message)}\n${style.dim(`Usage: ${usage}`)}\n`;
|
|
28
|
+
}
|
|
29
|
+
/** Pi's help layout, with unsupported options and examples deliberately absent. */
|
|
30
|
+
export function packageCommandHelp(verb, style = chalk) {
|
|
31
|
+
const command = `${PRODUCT_TEXT.commandName} pi`;
|
|
32
|
+
const header = `${style.bold("Usage:")}\n ${packageCommandUsage(verb)}\n\n`;
|
|
33
|
+
switch (verb) {
|
|
34
|
+
case "install":
|
|
35
|
+
return header + `Install a package and add it to settings.
|
|
36
|
+
|
|
37
|
+
Examples:
|
|
38
|
+
${command} install npm:@foo/bar
|
|
39
|
+
${command} install git:github.com/user/repo
|
|
40
|
+
${command} install git:git@github.com:user/repo
|
|
41
|
+
${command} install https://github.com/user/repo
|
|
42
|
+
${command} install ssh://git@github.com/user/repo
|
|
43
|
+
${command} install ./local/path
|
|
44
|
+
|
|
45
|
+
`;
|
|
46
|
+
case "remove":
|
|
47
|
+
return header + `Remove a package and its source from settings.
|
|
48
|
+
Alias: ${command} uninstall <source>
|
|
49
|
+
|
|
50
|
+
Examples:
|
|
51
|
+
${command} remove npm:@foo/bar
|
|
52
|
+
${command} uninstall npm:@foo/bar
|
|
53
|
+
|
|
54
|
+
`;
|
|
55
|
+
case "list":
|
|
56
|
+
return header + "List installed packages from user settings.\n\n";
|
|
57
|
+
case "update":
|
|
58
|
+
return header + `Update installed packages or model catalogs.
|
|
59
|
+
|
|
60
|
+
Options:
|
|
61
|
+
--extensions Update installed packages only
|
|
62
|
+
--models Refresh model catalogs only
|
|
63
|
+
|
|
64
|
+
Short forms:
|
|
65
|
+
${command} update --extensions Update installed packages only
|
|
66
|
+
${command} update --models Refresh model catalogs only
|
|
67
|
+
${command} update <source> Update one package
|
|
68
|
+
|
|
69
|
+
`;
|
|
70
|
+
}
|
|
71
|
+
}
|
package/dist/cli/packages.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ export interface PackageCommandStyle {
|
|
|
16
16
|
readonly bold: (message: string) => string;
|
|
17
17
|
readonly green: (message: string) => string;
|
|
18
18
|
readonly red: (message: string) => string;
|
|
19
|
+
readonly yellow: (message: string) => string;
|
|
19
20
|
}
|
|
20
21
|
export interface PackageCommandEnvironment {
|
|
21
22
|
readonly createPort: (input: AgentPackagesPortInput) => AgentPackagesPort;
|
|
@@ -28,4 +29,4 @@ export interface PackageCommandEnvironment {
|
|
|
28
29
|
readonly style?: PackageCommandStyle;
|
|
29
30
|
}
|
|
30
31
|
export declare function runPackageCommand(request: PackageCommandRequest, environment: PackageCommandEnvironment): Promise<number>;
|
|
31
|
-
export declare function renderPackageOutcome(outcome: AgentPackageOutcome,
|
|
32
|
+
export declare function renderPackageOutcome(outcome: AgentPackageOutcome, style?: PackageCommandStyle): string;
|
package/dist/cli/packages.js
CHANGED
|
@@ -21,10 +21,15 @@ export async function runPackageCommand(request, environment) {
|
|
|
21
21
|
const port = environment.createPort({
|
|
22
22
|
profileRoot,
|
|
23
23
|
cwd,
|
|
24
|
-
onProgress: progress => stdout(
|
|
24
|
+
onProgress: progress => stdout(style.dim(`${progress.message}\n`)),
|
|
25
|
+
onDiagnostic: diagnostic => {
|
|
26
|
+
stderr(`${style.yellow(diagnostic.message)}\n`);
|
|
27
|
+
if (diagnostic.detail)
|
|
28
|
+
stderr(`${style.dim(diagnostic.detail)}\n`);
|
|
29
|
+
},
|
|
25
30
|
});
|
|
26
31
|
const outcome = await runVerb(port, request);
|
|
27
|
-
const rendered = renderPackageOutcome(outcome,
|
|
32
|
+
const rendered = renderPackageOutcome(outcome, style);
|
|
28
33
|
(outcome.status === "completed" ? stdout : stderr)(rendered);
|
|
29
34
|
return outcome.status === "completed" ? 0 : 1;
|
|
30
35
|
}
|
|
@@ -39,22 +44,17 @@ async function runVerb(port, request) {
|
|
|
39
44
|
throw new Error(PRODUCT_TEXT.diagnostic(`requires a source for ${request.verb}`));
|
|
40
45
|
return request.verb === "install" ? await port.install(request.source) : await port.remove(request.source);
|
|
41
46
|
}
|
|
42
|
-
export function renderPackageOutcome(outcome,
|
|
43
|
-
// Compatibility: model refresh remains an A1 top-level command. The `a1 pi` compatibility
|
|
44
|
-
// transcript applies to package operations only.
|
|
45
|
-
if (outcome.operation === "refresh-models") {
|
|
46
|
-
if (outcome.status === "failed") {
|
|
47
|
-
return `${PRODUCT_TEXT.diagnostic(`could not ${describeOperation(outcome.operation)}: ${outcome.detail ?? "unknown failure"}`)}\n`;
|
|
48
|
-
}
|
|
49
|
-
return `${PRODUCT_TEXT.displayName} refreshed the model catalogs in ${profileRoot}.\n`;
|
|
50
|
-
}
|
|
47
|
+
export function renderPackageOutcome(outcome, style = chalk) {
|
|
51
48
|
if (outcome.status === "failed") {
|
|
52
|
-
|
|
49
|
+
const fallback = outcome.operation === "refresh-models" ? "Unknown model catalog refresh error" : "Unknown package command error";
|
|
50
|
+
return `${style.red(`Error: ${outcome.detail ?? fallback}`)}\n`;
|
|
53
51
|
}
|
|
54
52
|
if (outcome.status === "not-found") {
|
|
55
53
|
return `${style.red(`No matching package found for ${outcome.source ?? "that source"}`)}\n`;
|
|
56
54
|
}
|
|
57
55
|
switch (outcome.operation) {
|
|
56
|
+
case "refresh-models":
|
|
57
|
+
return `${style.green("Model catalogs refreshed")}\n`;
|
|
58
58
|
case "install":
|
|
59
59
|
return `${style.green(`Installed ${outcome.source}`)}\n`;
|
|
60
60
|
case "remove":
|
|
@@ -76,13 +76,6 @@ function renderPackageList(outcome, style) {
|
|
|
76
76
|
}
|
|
77
77
|
return `${lines.join("\n")}\n`;
|
|
78
78
|
}
|
|
79
|
-
function describeOperation(operation) {
|
|
80
|
-
if (operation === "refresh-models")
|
|
81
|
-
return "refresh the model catalogs";
|
|
82
|
-
if (operation === "list")
|
|
83
|
-
return "list installed packages";
|
|
84
|
-
return `${operation} the package`;
|
|
85
|
-
}
|
|
86
79
|
function message(error) {
|
|
87
80
|
return (error instanceof Error ? error.message : String(error)).replace(/\s+/g, " ").trim();
|
|
88
81
|
}
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type SessionSelection } from "../foundation/lifecycle/index.js";
|
|
2
|
+
import { type PiEngineAdapter, type PiProjectTrustPreflightPrompt, type PiSessionForkPrompt } from "../integrations/pi/engine/index.js";
|
|
2
3
|
import { OwnedUiSettingsSession } from "../ui/settings/index.js";
|
|
3
4
|
import type { OwnedUiApplicationPort, PresentationTerminalPort } from "../contracts/presentation/index.js";
|
|
4
5
|
export interface OwnedUiCompositionOptions {
|
|
5
6
|
readonly cwd?: string;
|
|
6
7
|
readonly terminal?: PresentationTerminalPort;
|
|
7
8
|
readonly createPiAdapter?: () => Promise<PiEngineAdapter>;
|
|
8
|
-
/**
|
|
9
|
+
/** Explicit file selection retained for SDK callers. Public CLI uses sessionSelection. */
|
|
9
10
|
readonly sessionPath?: string;
|
|
11
|
+
readonly sessionSelection?: SessionSelection;
|
|
12
|
+
readonly sessionForkPrompt?: PiSessionForkPrompt;
|
|
10
13
|
/**
|
|
11
14
|
* A1 profile whose settings this session reads and writes. Omitted keeps the
|
|
12
15
|
* session settings-free, which is what the pinned comparison paths use.
|
|
@@ -17,6 +17,8 @@ export async function composeOwnedUi(options = {}) {
|
|
|
17
17
|
availableThemes: () => getAvailablePiThemes().map(theme => theme.name),
|
|
18
18
|
settingsProductMode: options.ownedSurfaces === "off" ? "comparison" : "bare",
|
|
19
19
|
...(options.sessionPath === undefined ? {} : { sessionPath: options.sessionPath }),
|
|
20
|
+
...(options.sessionSelection === undefined ? {} : { sessionSelection: options.sessionSelection }),
|
|
21
|
+
...(options.sessionForkPrompt === undefined ? {} : { sessionForkPrompt: options.sessionForkPrompt }),
|
|
20
22
|
...(options.projectTrustPrompt === undefined ? {} : { projectTrustPrompt: options.projectTrustPrompt }),
|
|
21
23
|
});
|
|
22
24
|
const ownedSurfaces = options.ownedSurfaces !== "off";
|
|
@@ -37,7 +39,7 @@ export async function composeOwnedUi(options = {}) {
|
|
|
37
39
|
};
|
|
38
40
|
const shell = new OwnedUiSessionShell({
|
|
39
41
|
backend: adapter,
|
|
40
|
-
cwd,
|
|
42
|
+
cwd: adapter.cwd,
|
|
41
43
|
...(options.terminal === undefined ? {} : { terminal: createPiTerminalBridge(options.terminal) }),
|
|
42
44
|
...(routeHost === null ? {} : { routeHost }),
|
|
43
45
|
...(ownedSurfaces ? { sessionLayout: "custom-viewport" } : {}),
|
|
@@ -45,10 +45,16 @@ export interface AgentPackagesPort {
|
|
|
45
45
|
update(source?: string): Promise<AgentPackageOutcome>;
|
|
46
46
|
refreshModels(): Promise<AgentPackageOutcome>;
|
|
47
47
|
}
|
|
48
|
+
/** Recoverable operation diagnostics retain the engine's visible detail and order. */
|
|
49
|
+
export interface AgentPackageDiagnostic {
|
|
50
|
+
readonly message: string;
|
|
51
|
+
readonly detail?: string;
|
|
52
|
+
}
|
|
48
53
|
export interface AgentPackagesPortInput {
|
|
49
54
|
readonly profileRoot: string;
|
|
50
55
|
readonly cwd: string;
|
|
51
56
|
readonly onProgress?: (progress: AgentPackageProgress) => void;
|
|
57
|
+
readonly onDiagnostic?: (diagnostic: AgentPackageDiagnostic) => void;
|
|
52
58
|
}
|
|
53
59
|
export declare function assertAgentPackagesPort(port: AgentPackagesPort): void;
|
|
54
60
|
export declare function agentPackageOutcome(operation: AgentPackageOperation, status: AgentPackageStatus, detail?: string | null, source?: string | null, packages?: readonly AgentPackageDescriptor[]): AgentPackageOutcome;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import type
|
|
2
|
-
export
|
|
1
|
+
import { type SessionSelection, type LaunchProfileId } from "../../foundation/lifecycle/index.js";
|
|
2
|
+
export { parseSessionSelection } from "../../foundation/lifecycle/index.js";
|
|
3
|
+
export type { LaunchProfileId, SessionSelection } from "../../foundation/lifecycle/index.js";
|
|
3
4
|
export interface InteractiveLaunchIntent {
|
|
4
5
|
readonly kind: "interactive";
|
|
5
6
|
readonly profileId: LaunchProfileId;
|
|
7
|
+
readonly sessionSelection?: SessionSelection;
|
|
6
8
|
}
|
|
7
9
|
export type LaunchIntent = InteractiveLaunchIntent;
|
|
8
|
-
export declare function interactiveLaunchIntent(profileId: LaunchProfileId): InteractiveLaunchIntent;
|
|
10
|
+
export declare function interactiveLaunchIntent(profileId: LaunchProfileId, sessionSelection?: SessionSelection): InteractiveLaunchIntent;
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { sessionSelectionArguments } from "../../foundation/lifecycle/index.js";
|
|
2
|
+
export { parseSessionSelection } from "../../foundation/lifecycle/index.js";
|
|
3
|
+
export function interactiveLaunchIntent(profileId, sessionSelection) {
|
|
4
|
+
if (sessionSelection !== undefined && profileId !== "a1")
|
|
5
|
+
throw new Error("session selection requires the normal A1 profile");
|
|
6
|
+
sessionSelectionArguments(sessionSelection);
|
|
7
|
+
return Object.freeze({ kind: "interactive", profileId, ...(sessionSelection === undefined ? {} : { sessionSelection }) });
|
|
3
8
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Readable, Writable } from "node:stream";
|
|
2
|
+
/** Pre-resource, line-mode confirmation matching Pi's cross-project CLI fork decision. */
|
|
3
|
+
export declare function createConsoleSessionForkPrompt(options?: {
|
|
4
|
+
readonly input?: Readable;
|
|
5
|
+
readonly output?: Writable;
|
|
6
|
+
}): (request: {
|
|
7
|
+
readonly sourceCwd: string;
|
|
8
|
+
}) => Promise<boolean>;
|