@timurproko/a1 0.1.8-dev.182 → 0.1.8-dev.214
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/cli.js +2 -2
- package/bin/sync-pi-tui-proxy.js +1 -1
- package/bin/ui.js +1 -1
- package/dist/cli/dispatch.js +3 -3
- package/dist/cli/packages.js +1 -1
- package/dist/cli/version-stats.js +3 -3
- package/dist/composition/owned-ui.js +1 -1
- package/dist/composition/settings-route-host.js +6 -4
- package/dist/features/launch/development-launch.js +1 -1
- package/dist/features/owned-ui/customization.d.ts +2 -0
- package/dist/features/owned-ui/customization.js +2 -0
- package/dist/features/owned-ui/diagnostics.d.ts +1 -0
- package/dist/features/owned-ui/diagnostics.js +1 -0
- package/dist/features/owned-ui/project-trust-prompt.d.ts +11 -6
- package/dist/features/owned-ui/project-trust-prompt.js +134 -17
- package/dist/features/owned-ui/settings-app.js +47 -50
- package/dist/features/workspace/reducer.d.ts +1 -0
- package/dist/features/workspace/reducer.js +1 -0
- package/dist/features/workspace/router.d.ts +1 -0
- package/dist/features/workspace/router.js +1 -0
- package/dist/features/workspace/store.d.ts +1 -0
- package/dist/features/workspace/store.js +1 -0
- package/dist/foundation/launch-guardian/main.js +1 -1
- package/dist/foundation/native-host-protocol/codec.d.ts +2 -0
- package/dist/foundation/native-host-protocol/codec.js +2 -0
- package/dist/foundation/process-containment/linux-process-inspector.d.ts +1 -0
- package/dist/foundation/process-containment/linux-process-inspector.js +1 -0
- package/dist/foundation/process-containment/native-guardian-containment.d.ts +1 -0
- package/dist/foundation/process-containment/native-guardian-containment.js +1 -0
- package/dist/foundation/process-containment/windows-process-inspector.d.ts +1 -0
- package/dist/foundation/process-containment/windows-process-inspector.js +1 -0
- package/dist/foundation/protocol/client.d.ts +1 -0
- package/dist/foundation/protocol/client.js +1 -0
- package/dist/foundation/protocol/messages.d.ts +1 -0
- package/dist/foundation/protocol/messages.js +1 -0
- package/dist/foundation/release/bootstrap.js +6 -6
- package/dist/foundation/release/cohort-state.d.ts +1 -0
- package/dist/foundation/release/cohort-state.js +1 -0
- package/dist/foundation/release/release-gc.js +1 -1
- package/dist/foundation/release/release.js +1 -1
- package/dist/foundation/release/update-transaction.d.ts +1 -0
- package/dist/foundation/release/update-transaction.js +1 -0
- package/dist/foundation/release/update.js +12 -12
- package/dist/foundation/storage/control-store.d.ts +1 -0
- package/dist/foundation/storage/control-store.js +1 -0
- package/dist/foundation/structured-agent-runtime/backpressure.d.ts +1 -0
- package/dist/foundation/structured-agent-runtime/backpressure.js +1 -0
- package/dist/foundation/structured-agent-runtime/commands.d.ts +1 -0
- package/dist/foundation/structured-agent-runtime/commands.js +1 -0
- package/dist/foundation/structured-agent-runtime/reconnection.d.ts +1 -0
- package/dist/foundation/structured-agent-runtime/reconnection.js +1 -0
- package/dist/foundation/structured-agent-runtime/state.d.ts +1 -0
- package/dist/foundation/structured-agent-runtime/state.js +1 -0
- package/dist/foundation/supervision/main.js +1 -1
- package/dist/foundation/supervision/server.d.ts +1 -0
- package/dist/foundation/supervision/server.js +4 -6
- package/dist/integrations/pi/components/conformance.d.ts +1 -0
- package/dist/integrations/pi/components/conformance.js +1 -0
- package/dist/integrations/pi/components/shell-footer-status.d.ts +1 -1
- package/dist/integrations/pi/components/shell-footer-status.js +8 -7
- package/dist/integrations/pi/components/shell-shared-facade.js +1 -1
- package/dist/integrations/pi/engine/adapter.d.ts +7 -0
- package/dist/integrations/pi/engine/adapter.js +37 -35
- package/dist/integrations/pi/engine/conformance.d.ts +2 -0
- package/dist/integrations/pi/engine/conformance.js +2 -0
- package/dist/integrations/pi/engine/http-dispatcher.js +1 -1
- package/dist/integrations/pi/engine/model-auth-integration.d.ts +1 -0
- package/dist/integrations/pi/engine/model-auth-integration.js +1 -0
- package/dist/integrations/pi/engine/package-integration.js +1 -1
- package/dist/integrations/pi/engine/project-trust-preflight.js +1 -1
- package/dist/integrations/pi/engine/resource-extension-integration.d.ts +1 -0
- package/dist/integrations/pi/engine/resource-extension-integration.js +1 -0
- package/dist/integrations/pi/engine/session-integration.d.ts +1 -0
- package/dist/integrations/pi/engine/session-integration.js +2 -1
- package/dist/integrations/pi/engine/settings-effects.d.ts +13 -2
- package/dist/integrations/pi/engine/settings-effects.js +62 -42
- package/dist/integrations/pi/engine/settings-integration.js +4 -4
- package/dist/integrations/pi/engine/workflow-controllers.d.ts +1 -0
- package/dist/integrations/pi/engine/workflow-controllers.js +1 -0
- package/dist/integrations/pi/session-ui/index.d.ts +1 -0
- package/dist/integrations/pi/session-ui/index.js +1 -0
- package/dist/integrations/pi/session-ui/prompt-chips.js +1 -1
- package/dist/integrations/pi/session-ui/session-shell-root.d.ts +30 -2
- package/dist/integrations/pi/session-ui/session-shell-root.js +133 -72
- package/dist/integrations/pi/session-ui/session-shell.d.ts +9 -2
- package/dist/integrations/pi/session-ui/session-shell.js +112 -37
- package/dist/integrations/pi/session-ui/session-viewport-controller.d.ts +5 -0
- package/dist/integrations/pi/session-ui/session-viewport-controller.js +44 -11
- package/dist/integrations/pi/session-ui/stream-presentation-coalescer.d.ts +29 -0
- package/dist/integrations/pi/session-ui/stream-presentation-coalescer.js +79 -0
- package/dist/integrations/pi/session-ui/system-clipboard.js +6 -6
- package/dist/integrations/pi/tui-runtime/adapter.d.ts +2 -0
- package/dist/integrations/pi/tui-runtime/adapter.js +138 -8
- package/dist/integrations/pi/tui-runtime/contracts.d.ts +25 -0
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +63 -0
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +240 -0
- package/dist/integrations/pi/tui-runtime/index.d.ts +2 -0
- package/dist/integrations/pi/tui-runtime/index.js +2 -0
- package/dist/integrations/pi/tui-runtime/input-presentation-coordinator.d.ts +39 -0
- package/dist/integrations/pi/tui-runtime/input-presentation-coordinator.js +139 -0
- package/dist/native/darwin-arm64/manifest.json +1 -1
- package/dist/native/linux-x64/manifest.json +1 -1
- package/dist/native/win32-x64/manifest.json +2 -2
- package/dist/native/win32-x64/process-guardian.exe +0 -0
- package/dist/ui/apps/host.js +5 -9
- package/dist/ui/apps/registry.d.ts +1 -0
- package/dist/ui/apps/registry.js +1 -0
- package/dist/ui/components/dialog-panel.js +5 -3
- package/dist/ui/components/frame.d.ts +1 -0
- package/dist/ui/components/frame.js +1 -0
- package/dist/ui/components/index.d.ts +1 -0
- package/dist/ui/components/index.js +1 -0
- package/dist/ui/components/line-input.d.ts +1 -6
- package/dist/ui/components/line-input.js +4 -9
- package/dist/ui/components/list-view.d.ts +0 -6
- package/dist/ui/components/list-view.js +14 -7
- package/dist/ui/components/progress-status.d.ts +2 -0
- package/dist/ui/components/progress-status.js +4 -0
- package/dist/ui/components/scrollbar.js +1 -1
- package/dist/ui/components/shortcuts.d.ts +1 -0
- package/dist/ui/components/shortcuts.js +1 -0
- package/dist/ui/components/spans.d.ts +0 -5
- package/dist/ui/components/spans.js +3 -8
- package/dist/ui/components/surface.d.ts +0 -5
- package/dist/ui/components/surface.js +1 -5
- package/dist/ui/components/text-selection.d.ts +10 -1
- package/dist/ui/components/text-selection.js +96 -29
- package/dist/ui/components/text.js +3 -3
- package/dist/ui/components/transcript-viewport.d.ts +42 -0
- package/dist/ui/components/transcript-viewport.js +287 -39
- package/dist/ui/settings/sections.d.ts +0 -2
- package/dist/ui/settings/sections.js +10 -16
- package/dist/ui/settings/session.js +5 -4
- package/dist/ui/settings/store.d.ts +1 -0
- package/dist/ui/settings/store.js +2 -1
- package/docs/architecture/code-documentation.md +77 -0
- package/docs/architecture/project-structure.md +1 -1
- package/docs/architecture/ui-reference-provenance.md +23 -3
- package/docs/ci-release-runbook.md +30 -4
- package/docs/manual-owned-ui-checkpoint.md +28 -1
- package/docs/manual-terminal-colour-check.md +4 -3
- package/package.json +7 -2
package/bin/cli.js
CHANGED
|
@@ -5,7 +5,7 @@ const { fileURLToPath } = await import("node:url");
|
|
|
5
5
|
const { readFile } = await import("node:fs/promises");
|
|
6
6
|
const { cliCapabilities, dispatchCli } = await import("../dist/cli/index.js");
|
|
7
7
|
|
|
8
|
-
//
|
|
8
|
+
// Compatibility: which commands this build exposes follows from the build's own version, so a
|
|
9
9
|
// released a1 cannot be argued into offering the development profiles.
|
|
10
10
|
const capabilities = cliCapabilities(JSON.parse(await readFile(new URL("package.json", packageRoot), "utf8")).version);
|
|
11
11
|
|
|
@@ -16,7 +16,7 @@ process.exitCode = await dispatchCli(process.argv.slice(2), {
|
|
|
16
16
|
import("../dist/foundation/release/index.js"),
|
|
17
17
|
import("./module-identity.js"),
|
|
18
18
|
]);
|
|
19
|
-
//
|
|
19
|
+
// Compatibility: self-heal the installed tree before the release store copies it: npm 12
|
|
20
20
|
// blocks install scripts by default, so the postinstall that normally
|
|
21
21
|
// repairs module identity may never have run (see bin/module-identity.js).
|
|
22
22
|
const packageRootPath = fileURLToPath(packageRoot);
|
package/bin/sync-pi-tui-proxy.js
CHANGED
|
@@ -35,7 +35,7 @@ const RE_EXPORT_LINE = /^export \* from "[^"]+";$/m;
|
|
|
35
35
|
* pinned Pi resolves. Returns a discriminated outcome; never throws.
|
|
36
36
|
*/
|
|
37
37
|
export function syncPiTuiProxy(packageRoot) {
|
|
38
|
-
// resolvePinnedPiTui answers with a canonical real path, so the directory the
|
|
38
|
+
// Platform: resolvePinnedPiTui answers with a canonical real path, so the directory the
|
|
39
39
|
// relative specifier is computed from must be canonical too (Windows short
|
|
40
40
|
// names, symlinked installs).
|
|
41
41
|
const canonicalRoot = canonical(packageRoot);
|
package/bin/ui.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const { assertSinglePiTuiModuleAtLaunch } = await import("./module-identity.js");
|
|
4
4
|
const { fileURLToPath } = await import("node:url");
|
|
5
5
|
|
|
6
|
-
//
|
|
6
|
+
// Compatibility: before the composition loads pinned Pi's terminal stack: confirm A1 and Pi
|
|
7
7
|
// resolve it to the same copy, so extensions and the owned UI share one module
|
|
8
8
|
// identity (see bin/module-identity.js for the full story). Nothing is repaired
|
|
9
9
|
// here — A1's package manifest decides which copy wins, and this only reports
|
package/dist/cli/dispatch.js
CHANGED
|
@@ -85,7 +85,7 @@ export function parseCliCommand(arguments_, capabilities) {
|
|
|
85
85
|
return parseUpdate(rest);
|
|
86
86
|
if (command?.startsWith("update:"))
|
|
87
87
|
return { kind: "noop" };
|
|
88
|
-
//
|
|
88
|
+
// Rationale: unsupported and reserved command spaces are deliberately quiet. Help is
|
|
89
89
|
// explicit, and a typo must never start an interactive or maintenance path.
|
|
90
90
|
return { kind: "noop" };
|
|
91
91
|
}
|
|
@@ -98,7 +98,7 @@ function parseUpdate(rest) {
|
|
|
98
98
|
if (rest.length === 0)
|
|
99
99
|
return { kind: "update", channel: "stable" };
|
|
100
100
|
const [selector, ...values] = rest;
|
|
101
|
-
//
|
|
101
|
+
// Compatibility: removed notation is unsupported rather than deprecated.
|
|
102
102
|
if (selector === "self")
|
|
103
103
|
return { kind: "noop" };
|
|
104
104
|
if (selector === "--develop") {
|
|
@@ -121,7 +121,7 @@ function parseUpdate(rest) {
|
|
|
121
121
|
return pinnedPiUpdateError();
|
|
122
122
|
if (selector !== undefined && selector.startsWith("-"))
|
|
123
123
|
return unknownOption(selector, "update");
|
|
124
|
-
//
|
|
124
|
+
// Rationale: positional update targets are reserved for a future A1-native plugin model.
|
|
125
125
|
return { kind: "noop" };
|
|
126
126
|
}
|
|
127
127
|
function isDevelopmentTarget(target) {
|
package/dist/cli/packages.js
CHANGED
|
@@ -40,7 +40,7 @@ async function runVerb(port, request) {
|
|
|
40
40
|
return request.verb === "install" ? await port.install(request.source) : await port.remove(request.source);
|
|
41
41
|
}
|
|
42
42
|
export function renderPackageOutcome(outcome, profileRoot, style = chalk) {
|
|
43
|
-
//
|
|
43
|
+
// Compatibility: model refresh remains an A1 top-level command. The `a1 pi` compatibility
|
|
44
44
|
// transcript applies to package operations only.
|
|
45
45
|
if (outcome.operation === "refresh-models") {
|
|
46
46
|
if (outcome.status === "failed") {
|
|
@@ -20,7 +20,7 @@ export async function runVersionStats(options) {
|
|
|
20
20
|
output.stderr(`${PRODUCT_TEXT.diagnostic(`could not read its installed version: ${message(error)}`)}\n`);
|
|
21
21
|
return 1;
|
|
22
22
|
}
|
|
23
|
-
//
|
|
23
|
+
// Compatibility: match Pi's release behavior: stable builds print only their installed version.
|
|
24
24
|
// Development builds retain channel visibility for preview comparison and updates.
|
|
25
25
|
if (prerelease(installed) === null) {
|
|
26
26
|
output.stdout(`${installed}\n`);
|
|
@@ -32,7 +32,7 @@ export async function runVersionStats(options) {
|
|
|
32
32
|
output.stderr(`${PRODUCT_TEXT.diagnostic(`could not resolve npm dist-tags: ${remote.error}`)}\n`);
|
|
33
33
|
return 0;
|
|
34
34
|
}
|
|
35
|
-
// npm view respects the user's .npmrc registry and proxy, so it stays primary; the direct
|
|
35
|
+
// Rationale: npm view respects the user's .npmrc registry and proxy, so it stays primary; the direct
|
|
36
36
|
// registry fetch below covers npm CLI versions whose --json output shape we cannot parse.
|
|
37
37
|
async function queryDistTags(runner, fetcher) {
|
|
38
38
|
const fromNpm = await queryDistTagsViaNpm(runner);
|
|
@@ -55,7 +55,7 @@ async function queryDistTagsViaNpm(runner) {
|
|
|
55
55
|
return unavailable(`npm exited with status ${result.code ?? "unknown"}`);
|
|
56
56
|
try {
|
|
57
57
|
const parsed = JSON.parse(result.stdout);
|
|
58
|
-
// npm 12 wraps `npm view <pkg> dist-tags --json` output in a one-element array; older npm returns the bare object.
|
|
58
|
+
// Compatibility: npm 12 wraps `npm view <pkg> dist-tags --json` output in a one-element array; older npm returns the bare object.
|
|
59
59
|
const metadata = Array.isArray(parsed) && parsed.length === 1 ? parsed[0] : parsed;
|
|
60
60
|
return parseDistTags(metadata, "npm");
|
|
61
61
|
}
|
|
@@ -26,7 +26,7 @@ export async function composeOwnedUi(options = {}) {
|
|
|
26
26
|
store: new OwnedUiSettingsStore({ configDir: resolveProductPaths().configDir, profileId: options.profileId }),
|
|
27
27
|
agentProvider: () => adapter.settingsPort(),
|
|
28
28
|
});
|
|
29
|
-
//
|
|
29
|
+
// Compatibility: bare A1 intentionally ships one visual target while its UI is being completed:
|
|
30
30
|
// dark, regardless of terminal detection or a previously stored Pi theme. The
|
|
31
31
|
// comparison profile keeps Pi's configured theme behavior and settings surface.
|
|
32
32
|
applyConfiguredPiTheme(ownedSurfaces ? "dark" : adapter.configuredTheme());
|
|
@@ -61,13 +61,15 @@ function pinnedTheme() {
|
|
|
61
61
|
return {
|
|
62
62
|
fg: (token, text) => piTheme().fg(token, text),
|
|
63
63
|
bold: (text) => piTheme().bold(text),
|
|
64
|
-
//
|
|
64
|
+
// Rationale: unpainted, so a list reads against the terminal the reader actually has
|
|
65
65
|
// rather than against the background the configured theme was built for.
|
|
66
66
|
plain: (text) => text,
|
|
67
|
-
//
|
|
67
|
+
// Rationale: quiet, and quieter again: the terminal's own faint attribute over the
|
|
68
68
|
// dimmest colour the theme has.
|
|
69
69
|
disabled: (text) => faint(piTheme().fg("dim", text)),
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
// Rationale: physical review requires the shared value menu to read as a floating
|
|
71
|
+
// product surface instead of blending into the settings rows behind it.
|
|
72
|
+
highlight: (text) => `\u001b[48;2;82;82;82m\u001b[97m${text}\u001b[39m\u001b[49m`,
|
|
73
|
+
panel: (text) => `\u001b[48;2;55;55;55m${text}\u001b[49m`,
|
|
72
74
|
};
|
|
73
75
|
}
|
|
@@ -12,7 +12,7 @@ export function resolveDevelopmentLaunchEnvironment(canonicalPackageRoot, releas
|
|
|
12
12
|
const selectedDevelopmentRoot = source[PRODUCT_IDENTITY.environment.developmentRoot];
|
|
13
13
|
const developmentRoot = resolve(selectedDevelopmentRoot
|
|
14
14
|
?? join(checkoutRoot, releaseId, "instances", instanceId));
|
|
15
|
-
//
|
|
15
|
+
// Rationale: runtime/data remain instance-isolated, but product settings are user
|
|
16
16
|
// preferences and must survive a fresh local launch (and a rebuilt candidate).
|
|
17
17
|
// An explicit development root retains its historical self-contained policy.
|
|
18
18
|
const persistentConfigDir = selectedDevelopmentRoot
|
|
@@ -12,6 +12,7 @@ export interface OwnedCommandHandlerContext {
|
|
|
12
12
|
readonly correlationId: string;
|
|
13
13
|
}
|
|
14
14
|
export type OwnedCommandHandler = (context: OwnedCommandHandlerContext) => OwnedUiCommand | Promise<OwnedUiCommand>;
|
|
15
|
+
/** Registers owned UI commands and assigns a monotonic correlation identifier to each dispatch. */
|
|
15
16
|
export declare class OwnedCommandSurface {
|
|
16
17
|
#private;
|
|
17
18
|
register(name: string, handler: OwnedCommandHandler): () => void;
|
|
@@ -22,6 +23,7 @@ export interface ResolvedOwnedUiSlot {
|
|
|
22
23
|
readonly customization: OwnedUiCustomization;
|
|
23
24
|
readonly implementation: OwnedUiSlotImplementation;
|
|
24
25
|
}
|
|
26
|
+
/** Resolves one customization per slot by precedence and version while preserving registration identity. */
|
|
25
27
|
export declare class OwnedUiCustomizationRegistry {
|
|
26
28
|
#private;
|
|
27
29
|
register(customization: OwnedUiCustomization, implementation: OwnedUiSlotImplementation): () => void;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { assertOwnedUiCustomization, } from "../../contracts/owned-ui/index.js";
|
|
2
|
+
/** Registers owned UI commands and assigns a monotonic correlation identifier to each dispatch. */
|
|
2
3
|
export class OwnedCommandSurface {
|
|
3
4
|
#handlers = new Map();
|
|
4
5
|
#sequence = 0;
|
|
@@ -17,6 +18,7 @@ export class OwnedCommandSurface {
|
|
|
17
18
|
return handler({ sessionId, correlationId: `ui-command-${this.#sequence}` });
|
|
18
19
|
}
|
|
19
20
|
}
|
|
21
|
+
/** Resolves one customization per slot by precedence and version while preserving registration identity. */
|
|
20
22
|
export class OwnedUiCustomizationRegistry {
|
|
21
23
|
#registrations = new Map();
|
|
22
24
|
register(customization, implementation) {
|
|
@@ -17,6 +17,7 @@ export interface OwnedUiDiagnosticsSnapshot {
|
|
|
17
17
|
readonly resources: OwnedUiResourceObservation | null;
|
|
18
18
|
readonly terminalRestorationFailed: boolean;
|
|
19
19
|
}
|
|
20
|
+
/** Retains bounded, redacted UI diagnostics together with frame and resource observations. */
|
|
20
21
|
export declare class OwnedUiDiagnosticsRecorder {
|
|
21
22
|
#private;
|
|
22
23
|
readonly maximumEntries: number;
|
|
@@ -4,17 +4,22 @@ export interface OwnedProjectTrustPromptRequest {
|
|
|
4
4
|
readonly defaultDecision: "ask" | "always" | "never";
|
|
5
5
|
}
|
|
6
6
|
export type OwnedProjectTrustPrompt = (request: OwnedProjectTrustPromptRequest) => Promise<boolean | null>;
|
|
7
|
+
interface RawTtyInput extends Readable {
|
|
8
|
+
readonly isTTY?: boolean;
|
|
9
|
+
readonly isRaw?: boolean;
|
|
10
|
+
setRawMode?(enabled: boolean): this;
|
|
11
|
+
}
|
|
7
12
|
export interface ConsoleProjectTrustPromptOptions {
|
|
8
|
-
readonly input?:
|
|
9
|
-
readonly isTTY?: boolean;
|
|
10
|
-
};
|
|
13
|
+
readonly input?: RawTtyInput;
|
|
11
14
|
readonly output?: Writable & {
|
|
12
15
|
readonly isTTY?: boolean;
|
|
16
|
+
readonly columns?: number;
|
|
13
17
|
};
|
|
14
18
|
}
|
|
15
19
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
20
|
+
* Pre-resource startup selector. It uses only fixed product wording and terminal
|
|
21
|
+
* controls: no project setting, theme, extension, prompt, package, or skill is
|
|
22
|
+
* consulted before the trust result exists.
|
|
19
23
|
*/
|
|
20
24
|
export declare function createConsoleProjectTrustPrompt(options?: ConsoleProjectTrustPromptOptions): OwnedProjectTrustPrompt;
|
|
25
|
+
export {};
|
|
@@ -1,8 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
const ENTER_ALTERNATE_SCREEN = "\u001b[?1049h";
|
|
2
|
+
const LEAVE_ALTERNATE_SCREEN = "\u001b[?1049l";
|
|
3
|
+
const HIDE_CURSOR = "\u001b[?25l";
|
|
4
|
+
const SHOW_CURSOR = "\u001b[?25h";
|
|
5
|
+
const CLEAR_HOME = "\u001b[2J\u001b[H";
|
|
6
|
+
const ACCENT = "\u001b[38;2;138;190;183m";
|
|
7
|
+
const MUTED = "\u001b[38;2;128;128;128m";
|
|
8
|
+
const DIM = "\u001b[38;2;102;102;102m";
|
|
9
|
+
const RESET_FG = "\u001b[39m";
|
|
10
|
+
const BOLD = "\u001b[1m";
|
|
11
|
+
const RESET_BOLD = "\u001b[22m";
|
|
2
12
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
13
|
+
* Pre-resource startup selector. It uses only fixed product wording and terminal
|
|
14
|
+
* controls: no project setting, theme, extension, prompt, package, or skill is
|
|
15
|
+
* consulted before the trust result exists.
|
|
6
16
|
*/
|
|
7
17
|
export function createConsoleProjectTrustPrompt(options = {}) {
|
|
8
18
|
const input = options.input ?? process.stdin;
|
|
@@ -11,22 +21,129 @@ export function createConsoleProjectTrustPrompt(options = {}) {
|
|
|
11
21
|
if (input.isTTY !== true || output.isTTY !== true) {
|
|
12
22
|
throw new Error("an interactive terminal is unavailable");
|
|
13
23
|
}
|
|
14
|
-
const
|
|
24
|
+
const wasRaw = input.isRaw === true;
|
|
25
|
+
let selected = 0;
|
|
26
|
+
let restored = false;
|
|
27
|
+
const restore = () => {
|
|
28
|
+
if (restored)
|
|
29
|
+
return;
|
|
30
|
+
restored = true;
|
|
31
|
+
input.setRawMode?.(wasRaw);
|
|
32
|
+
output.write(`${CLEAR_HOME}${SHOW_CURSOR}${LEAVE_ALTERNATE_SCREEN}`);
|
|
33
|
+
};
|
|
34
|
+
const render = () => {
|
|
35
|
+
const width = Math.max(20, output.columns ?? 80);
|
|
36
|
+
const lines = [
|
|
37
|
+
`${BOLD}${ACCENT}Trust project folder?${RESET_FG}${RESET_BOLD}`,
|
|
38
|
+
cwd,
|
|
39
|
+
"",
|
|
40
|
+
"This allows A1 to load project settings and resources, install missing project packages, and execute project extensions.",
|
|
41
|
+
"",
|
|
42
|
+
optionRow("Trust", selected === 0),
|
|
43
|
+
optionRow("Do not trust", selected === 1),
|
|
44
|
+
"",
|
|
45
|
+
`${DIM} ↑/↓ to navigate · Enter to select · Esc to cancel${RESET_FG}`,
|
|
46
|
+
];
|
|
47
|
+
output.write(`${CLEAR_HOME}${lines.map(line => clipAnsiSafe(line, width)).join("\n")}`);
|
|
48
|
+
};
|
|
15
49
|
try {
|
|
16
|
-
output.write(
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
50
|
+
output.write(`${ENTER_ALTERNATE_SCREEN}${HIDE_CURSOR}`);
|
|
51
|
+
input.setRawMode?.(true);
|
|
52
|
+
render();
|
|
53
|
+
return await new Promise((resolve, reject) => {
|
|
54
|
+
let settled = false;
|
|
55
|
+
const finish = (value) => {
|
|
56
|
+
if (settled)
|
|
57
|
+
return;
|
|
58
|
+
settled = true;
|
|
59
|
+
cleanup();
|
|
60
|
+
restore();
|
|
61
|
+
resolve(value);
|
|
62
|
+
};
|
|
63
|
+
const fail = (error) => {
|
|
64
|
+
if (settled)
|
|
65
|
+
return;
|
|
66
|
+
settled = true;
|
|
67
|
+
cleanup();
|
|
68
|
+
restore();
|
|
69
|
+
reject(error);
|
|
70
|
+
};
|
|
71
|
+
const onData = (chunk) => {
|
|
72
|
+
const data = chunk.toString();
|
|
73
|
+
for (let index = 0; index < data.length;) {
|
|
74
|
+
if (data.startsWith("\u001b[A", index)) {
|
|
75
|
+
selected = 0;
|
|
76
|
+
index += 3;
|
|
77
|
+
render();
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (data.startsWith("\u001b[B", index) || data[index] === "\t") {
|
|
81
|
+
selected = selected === 0 ? 1 : 0;
|
|
82
|
+
index += data[index] === "\t" ? 1 : 3;
|
|
83
|
+
render();
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
const key = data[index] ?? "";
|
|
87
|
+
index += 1;
|
|
88
|
+
if (key === "\r" || key === "\n") {
|
|
89
|
+
finish(selected === 0);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (key === "\u001b" || key === "\u0003") {
|
|
93
|
+
finish(null);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
// Compatibility: retain y/n aliases for terminals or automation that cannot send
|
|
97
|
+
// navigation keys; the visible interaction remains selector-first.
|
|
98
|
+
if (key === "y" || key === "Y") {
|
|
99
|
+
finish(true);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (key === "n" || key === "N") {
|
|
103
|
+
finish(false);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
const onEnd = () => finish(null);
|
|
109
|
+
const onError = (error) => fail(error);
|
|
110
|
+
const cleanup = () => {
|
|
111
|
+
input.off("data", onData);
|
|
112
|
+
input.off("end", onEnd);
|
|
113
|
+
input.off("error", onError);
|
|
114
|
+
};
|
|
115
|
+
input.on("data", onData);
|
|
116
|
+
input.once("end", onEnd);
|
|
117
|
+
input.once("error", onError);
|
|
118
|
+
input.resume();
|
|
119
|
+
});
|
|
27
120
|
}
|
|
28
121
|
finally {
|
|
29
|
-
|
|
122
|
+
restore();
|
|
30
123
|
}
|
|
31
124
|
};
|
|
32
125
|
}
|
|
126
|
+
function optionRow(label, selected) {
|
|
127
|
+
return selected
|
|
128
|
+
? `${ACCENT}→ ${label}${RESET_FG}`
|
|
129
|
+
: ` ${label}`;
|
|
130
|
+
}
|
|
131
|
+
/** Avoid replaying or manufacturing control payloads while keeping fixed SGR. */
|
|
132
|
+
function clipAnsiSafe(line, width) {
|
|
133
|
+
let visible = 0;
|
|
134
|
+
let output = "";
|
|
135
|
+
for (let index = 0; index < line.length && visible < width;) {
|
|
136
|
+
if (line[index] === "\u001b") {
|
|
137
|
+
const match = line.slice(index).match(/^\u001b\[[0-9;:]*m/);
|
|
138
|
+
if (match !== null) {
|
|
139
|
+
output += match[0];
|
|
140
|
+
index += match[0].length;
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
output += line[index];
|
|
145
|
+
index += 1;
|
|
146
|
+
visible += 1;
|
|
147
|
+
}
|
|
148
|
+
return `${output}${RESET_FG}${RESET_BOLD}`;
|
|
149
|
+
}
|