@timurproko/a1 0.1.8-dev.546 → 0.1.8-dev.558
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/dist/features/owned-ui/project-trust-prompt.js +1 -1
- package/dist/features/owned-ui/reference-screen-app.js +3 -3
- package/dist/foundation/release/index.d.ts +2 -2
- package/dist/foundation/release/index.js +1 -1
- package/dist/foundation/release/update.d.ts +22 -1
- package/dist/foundation/release/update.js +61 -12
- package/dist/integrations/pi/components/models-dialog.js +1 -1
- package/dist/integrations/pi/components/shell-editor-autocomplete.d.ts +0 -6
- package/dist/integrations/pi/components/shell-editor-autocomplete.js +14 -5
- package/dist/integrations/pi/components/skills-dialog.js +1 -1
- package/dist/integrations/pi/components/upstream/components/scoped-models-selector.js +1 -1
- package/dist/integrations/pi/components/upstream/components/thinking-selector.js +1 -1
- package/dist/integrations/pi/components/upstream/components/tree-selector.js +2 -1
- package/dist/integrations/pi/engine/resource-catalog.js +1 -1
- 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/components/dialog-panel.js +3 -3
- package/docs/architecture/project-structure.md +6 -3
- package/package.json +1 -1
|
@@ -42,7 +42,7 @@ export function createConsoleProjectTrustPrompt(options = {}) {
|
|
|
42
42
|
optionRow("Trust", selected === 0),
|
|
43
43
|
optionRow("Do not trust", selected === 1),
|
|
44
44
|
"",
|
|
45
|
-
`${DIM}
|
|
45
|
+
`${DIM}↑/↓${MUTED} to navigate ${DIM}Enter${MUTED} to select ${DIM}Esc${MUTED} to cancel${RESET_FG}`,
|
|
46
46
|
];
|
|
47
47
|
output.write(`${CLEAR_HOME}${lines.map(line => clipAnsiSafe(line, width)).join("\n")}`);
|
|
48
48
|
};
|
|
@@ -134,11 +134,11 @@ export class ReferenceScreenApp {
|
|
|
134
134
|
: null;
|
|
135
135
|
const withRail = withScrollbarRail(body.slice(0, bodyHeight), geometry, contentWidth, theme, { presentation });
|
|
136
136
|
const hint = this.#interruptArmed
|
|
137
|
-
? theme.fg("dim", "press ctrl+c again to exit a1")
|
|
138
|
-
: renderShortcutHints(REFERENCE_SCREEN_SHORTCUTS.hintEntries(SCOPE), theme);
|
|
137
|
+
? theme.fg("dim", " press ctrl+c again to exit a1")
|
|
138
|
+
: renderShortcutHints(REFERENCE_SCREEN_SHORTCUTS.hintEntries(SCOPE), theme, 1);
|
|
139
139
|
// Compatibility: the v2 reference screen frames its document between two border-coloured rules.
|
|
140
140
|
const rule = theme.fg("border", "─".repeat(rect.width));
|
|
141
|
-
//
|
|
141
|
+
// Invariant: dialog chrome shares the title's one-cell inset; document content keeps its own layout.
|
|
142
142
|
const frame = [rule, ...withRail, rule, padToWidth(hint, rect.width)];
|
|
143
143
|
// Invariant: a rectangle too small for the chrome still gets exactly its rows, top first.
|
|
144
144
|
return frame.slice(0, rect.height).concat(Array(Math.max(0, rect.height - frame.length)).fill(""));
|
|
@@ -20,8 +20,8 @@ export { createRestartSeal, readRestartCertifiedRelease, releaseCertificationDoc
|
|
|
20
20
|
export type { RestartSeal, RestartValidationEvent } from "./restart-certification.js";
|
|
21
21
|
export { STABLE_RELEASE_SCHEMA, createStableReleaseEvidence, verifyStableRegistry } from "./stable-release.js";
|
|
22
22
|
export type { StableRegistryState, StableRegistryVerificationOptions, StableReleaseEvidence, StableReleaseEvidenceInput } from "./stable-release.js";
|
|
23
|
-
export { PRODUCT_PACKAGE, assertUpdatePerformanceBudget, createNpmProcessRunner, createUpdateLifecycleCoordinator, planUpdateOwnership, renderUpdateProgressBar, runSelfUpdate, } from "./update.js";
|
|
24
|
-
export type { ProcessRequest, ProcessResult, SelfUpdateOptions, UpdateActivationPhase, UpdateChannel, UpdateFileMetadata, UpdateFileSystem, UpdateLifecycleCoordinator, UpdateMaterializationProgress, UpdateMeasuredPhase, UpdateOutput, UpdateOwnershipAction, UpdatePackageReplacementInput, UpdatePerformanceEvidence, UpdatePhaseTimingEvent, UpdateProcessRunner, UpdateTransactionJournal, } from "./update.js";
|
|
23
|
+
export { PACKAGE_UNLOCK_PATIENCE_MS, PRODUCT_PACKAGE, assertUpdatePerformanceBudget, createNpmProcessRunner, createUpdateLifecycleCoordinator, isPackageLockError, lockedPackageDiagnostic, planUpdateOwnership, renderUpdateProgressBar, runSelfUpdate, } from "./update.js";
|
|
24
|
+
export type { ProcessRequest, ProcessResult, SelfUpdateOptions, UpdateActivationPhase, UpdateChannel, UpdateFileMetadata, UpdateFileSystem, UpdateLifecycleCoordinator, UpdateMaterializationProgress, UpdateMeasuredPhase, UpdateOutput, UpdateOwnershipAction, UpdatePackageReplacementInput, UpdatePerformanceEvidence, UpdatePhaseTimingEvent, UpdateProcessRunner, UpdateTransactionJournal, UpdateUnlockPatience, } from "./update.js";
|
|
25
25
|
export { UPDATE_ACTIVATION_CONTRACT, UPDATE_ACTIVATION_ENTRY, UPDATE_ACTIVATION_MANIFEST_FIELD, activateInstalledRelease, delegateActivation, readActivationContracts, runActivationEntry, } from "./update-activation.js";
|
|
26
26
|
export type { UpdateActivationCallbacks, UpdateActivationEvent, UpdateActivationRequest } from "./update-activation.js";
|
|
27
27
|
export { selectSupervisorLaunchReleaseId, selectUpdateLaunchRelease } from "./update-launch.js";
|
|
@@ -9,7 +9,7 @@ export { collectRelease, prepareReleaseCleanup, runBoundedReleaseCleanup, runRel
|
|
|
9
9
|
export { RELEASE_MANIFEST_FILENAME, assertImmutableExecutionRoot, consumeMaterializationProof, materializeRelease, readCertifiedReleaseManifest, readMaterializedRelease, resolveReleaseEntryPoint, verifyMaterializedRelease, } from "./release-store.js";
|
|
10
10
|
export { createRestartSeal, readRestartCertifiedRelease, releaseCertificationDocument, restartSealDigest } from "./restart-certification.js";
|
|
11
11
|
export { STABLE_RELEASE_SCHEMA, createStableReleaseEvidence, verifyStableRegistry } from "./stable-release.js";
|
|
12
|
-
export { PRODUCT_PACKAGE, assertUpdatePerformanceBudget, createNpmProcessRunner, createUpdateLifecycleCoordinator, planUpdateOwnership, renderUpdateProgressBar, runSelfUpdate, } from "./update.js";
|
|
12
|
+
export { PACKAGE_UNLOCK_PATIENCE_MS, PRODUCT_PACKAGE, assertUpdatePerformanceBudget, createNpmProcessRunner, createUpdateLifecycleCoordinator, isPackageLockError, lockedPackageDiagnostic, planUpdateOwnership, renderUpdateProgressBar, runSelfUpdate, } from "./update.js";
|
|
13
13
|
export { UPDATE_ACTIVATION_CONTRACT, UPDATE_ACTIVATION_ENTRY, UPDATE_ACTIVATION_MANIFEST_FIELD, activateInstalledRelease, delegateActivation, readActivationContracts, runActivationEntry, } from "./update-activation.js";
|
|
14
14
|
export { selectSupervisorLaunchReleaseId, selectUpdateLaunchRelease } from "./update-launch.js";
|
|
15
15
|
export { UPDATE_RECOVERY_SCHEMA, cleanupUpdateRecoveryCapsules, inspectUpdateLauncherSet, npmPrefixForGlobalRoot, prepareUpdateRecoveryCapsule, readUpdateRecoveryCapsule, removeUpdateRecoveryCapsule, runProtectedPackageReplacement, updateLauncherPaths, updateNpmInstallArguments, } from "./update-recovery.js";
|
|
@@ -23,6 +23,16 @@ export interface UpdateFileSystem {
|
|
|
23
23
|
realpath(path: string): Promise<string>;
|
|
24
24
|
lstat?(path: string): Promise<UpdateFileMetadata>;
|
|
25
25
|
access?(path: string): Promise<void>;
|
|
26
|
+
rename?(from: string, to: string): Promise<void>;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* How long the update keeps checking that nothing holds the package tree, and the clock it
|
|
30
|
+
* checks with. Tests inject a clock; the product waits in real time.
|
|
31
|
+
*/
|
|
32
|
+
export interface UpdateUnlockPatience {
|
|
33
|
+
readonly windowMs?: number;
|
|
34
|
+
readonly sleep?: (durationMs: number) => Promise<void>;
|
|
35
|
+
readonly now?: () => number;
|
|
26
36
|
}
|
|
27
37
|
export interface UpdateOutput {
|
|
28
38
|
stdout(message: string): void;
|
|
@@ -103,6 +113,17 @@ export interface UpdatePackageReplacementInput {
|
|
|
103
113
|
readonly environment: NodeJS.ProcessEnv;
|
|
104
114
|
readonly onRecoveryState: (state: UpdateRecoveryState) => Promise<void>;
|
|
105
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* The package tree is checked for holders by renaming it and renaming it back, because on
|
|
118
|
+
* Windows that is the one operation that fails while any file under it is open. A holder is
|
|
119
|
+
* usually brief: a scanner, an indexer, a file browser, or a session still shutting down.
|
|
120
|
+
* The update therefore keeps checking for this long before it calls the package locked.
|
|
121
|
+
*/
|
|
122
|
+
export declare const PACKAGE_UNLOCK_PATIENCE_MS = 15000;
|
|
123
|
+
/** Whether a rename failure means something holds the tree, as opposed to the tree being wrong. */
|
|
124
|
+
export declare function isPackageLockError(error: unknown): boolean;
|
|
125
|
+
/** What the user reads when the package stayed held for the whole patience window. */
|
|
126
|
+
export declare function lockedPackageDiagnostic(packageRoot: string, waitedMs: number, attempts: number, error: unknown): string;
|
|
106
127
|
/** Bound on the child diagnostics an update keeps: enough for npm's failure reason, never a log. */
|
|
107
128
|
export declare const CHILD_DIAGNOSTIC_LIMIT = 8000;
|
|
108
129
|
export declare function createNpmProcessRunner(platform?: NodeJS.Platform): UpdateProcessRunner;
|
|
@@ -114,7 +135,7 @@ export type UpdateOwnershipAction = "clean-dead-record" | "leave-running" | "end
|
|
|
114
135
|
* because that installation is exactly what is about to be replaced under it.
|
|
115
136
|
*/
|
|
116
137
|
export declare function planUpdateOwnership(ownership: "live-verified" | "dead", runsFromRetainedRelease: boolean): UpdateOwnershipAction;
|
|
117
|
-
export declare function createUpdateLifecycleCoordinator(environment?: NodeJS.ProcessEnv, fileSystem?: UpdateFileSystem, output?: UpdateOutput): UpdateLifecycleCoordinator;
|
|
138
|
+
export declare function createUpdateLifecycleCoordinator(environment?: NodeJS.ProcessEnv, fileSystem?: UpdateFileSystem, output?: UpdateOutput, patience?: UpdateUnlockPatience): UpdateLifecycleCoordinator;
|
|
118
139
|
/** Renders the terminal-only update meter; the visual preview shares this exact frame. */
|
|
119
140
|
export declare function renderUpdateProgressBar(percent: number): string;
|
|
120
141
|
export declare function runSelfUpdate(options: SelfUpdateOptions): Promise<number>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
-
import { access, lstat, readFile, realpath } from "node:fs/promises";
|
|
2
|
+
import { access, lstat, readFile, realpath, rename } from "node:fs/promises";
|
|
3
3
|
import { connect } from "node:net";
|
|
4
4
|
import { dirname, isAbsolute, relative, resolve, sep } from "node:path";
|
|
5
5
|
import crossSpawn from "cross-spawn";
|
|
@@ -23,7 +23,32 @@ const defaultFileSystem = {
|
|
|
23
23
|
realpath,
|
|
24
24
|
lstat,
|
|
25
25
|
access,
|
|
26
|
+
rename,
|
|
26
27
|
};
|
|
28
|
+
/**
|
|
29
|
+
* The package tree is checked for holders by renaming it and renaming it back, because on
|
|
30
|
+
* Windows that is the one operation that fails while any file under it is open. A holder is
|
|
31
|
+
* usually brief: a scanner, an indexer, a file browser, or a session still shutting down.
|
|
32
|
+
* The update therefore keeps checking for this long before it calls the package locked.
|
|
33
|
+
*/
|
|
34
|
+
export const PACKAGE_UNLOCK_PATIENCE_MS = 15_000;
|
|
35
|
+
const PACKAGE_UNLOCK_INITIAL_DELAY_MS = 100;
|
|
36
|
+
const PACKAGE_UNLOCK_MAX_DELAY_MS = 1_000;
|
|
37
|
+
// Platform: Windows reports a held directory as EPERM or EBUSY; EACCES and ENOTEMPTY are the other
|
|
38
|
+
// spellings a rename gives to a tree something is using. Anything else is not a lock.
|
|
39
|
+
const PACKAGE_LOCK_CODES = new Set(["EPERM", "EACCES", "EBUSY", "ENOTEMPTY"]);
|
|
40
|
+
const defaultSleep = async (durationMs) => await new Promise(resolvePromise => setTimeout(resolvePromise, durationMs));
|
|
41
|
+
/** Whether a rename failure means something holds the tree, as opposed to the tree being wrong. */
|
|
42
|
+
export function isPackageLockError(error) {
|
|
43
|
+
return error instanceof Error && "code" in error && typeof error.code === "string" && PACKAGE_LOCK_CODES.has(error.code);
|
|
44
|
+
}
|
|
45
|
+
/** What the user reads when the package stayed held for the whole patience window. */
|
|
46
|
+
export function lockedPackageDiagnostic(packageRoot, waitedMs, attempts, error) {
|
|
47
|
+
const seconds = Math.max(1, Math.round(waitedMs / 1_000));
|
|
48
|
+
return PRODUCT_TEXT.diagnostic(`package remained locked for ${seconds}s after verified shutdown (${attempts} checks): ${errorMessage(error)}. `
|
|
49
|
+
+ `Another program is holding a file under ${packageRoot}: an antivirus scan, a file browser or terminal open inside it, `
|
|
50
|
+
+ `or a session still shutting down. Close it and run the update again; nothing was changed.`);
|
|
51
|
+
}
|
|
27
52
|
const defaultOutput = {
|
|
28
53
|
stdout(message) { process.stdout.write(message); },
|
|
29
54
|
stderr(message) { process.stderr.write(message); },
|
|
@@ -79,7 +104,7 @@ async function readActiveEndpoint(paths, activeReleaseId, environment) {
|
|
|
79
104
|
const legacy = await readEndpointMetadata(legacyPaths.endpointMetadataPath);
|
|
80
105
|
return legacy ? { metadata: legacy, paths: legacyPaths } : null;
|
|
81
106
|
}
|
|
82
|
-
export function createUpdateLifecycleCoordinator(environment = process.env, fileSystem = defaultFileSystem, output = defaultOutput) {
|
|
107
|
+
export function createUpdateLifecycleCoordinator(environment = process.env, fileSystem = defaultFileSystem, output = defaultOutput, patience = {}) {
|
|
83
108
|
const paths = resolveProductPaths(environment);
|
|
84
109
|
const stateStore = new CohortStateStore(paths.dataDir);
|
|
85
110
|
return {
|
|
@@ -139,16 +164,40 @@ export function createUpdateLifecycleCoordinator(environment = process.env, file
|
|
|
139
164
|
if (fileSystem.access)
|
|
140
165
|
await fileSystem.access(packageRoot);
|
|
141
166
|
const probe = `${packageRoot}.${PRODUCT_IDENTITY.filesystem.slug}-unlock-probe`;
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
167
|
+
const renameTree = fileSystem.rename ?? rename;
|
|
168
|
+
const windowMs = patience.windowMs ?? PACKAGE_UNLOCK_PATIENCE_MS;
|
|
169
|
+
const now = patience.now ?? Date.now;
|
|
170
|
+
const sleep = patience.sleep ?? defaultSleep;
|
|
171
|
+
const startedAt = now();
|
|
172
|
+
let delay = PACKAGE_UNLOCK_INITIAL_DELAY_MS;
|
|
173
|
+
let attempts = 0;
|
|
174
|
+
// Rationale: a holder found right after ownership was released is almost always transient,
|
|
175
|
+
// so one failed rename is a reason to look again, not to abandon an update that has not
|
|
176
|
+
// yet changed anything. The wait is bounded so a genuine lock still fails clearly.
|
|
177
|
+
const withPatience = async (from, to, describeFailure) => {
|
|
178
|
+
while (true) {
|
|
179
|
+
attempts += 1;
|
|
180
|
+
try {
|
|
181
|
+
await renameTree(from, to);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
const elapsed = now() - startedAt;
|
|
186
|
+
if (!isPackageLockError(error) || elapsed >= windowMs)
|
|
187
|
+
throw describeFailure(error);
|
|
188
|
+
// Rationale: the last pause is cut to the window's edge so the wait ends when promised.
|
|
189
|
+
await sleep(Math.min(delay, windowMs - elapsed));
|
|
190
|
+
delay = Math.min(PACKAGE_UNLOCK_MAX_DELAY_MS, delay * 2);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
await withPatience(packageRoot, probe, error => isPackageLockError(error)
|
|
195
|
+
? new Error(lockedPackageDiagnostic(packageRoot, now() - startedAt, attempts, error))
|
|
196
|
+
: new Error(PRODUCT_TEXT.diagnostic(`could not verify that the package is unlocked: ${errorMessage(error)}`)));
|
|
197
|
+
// Invariant: the package tree is put back under its own name before this returns; a holder
|
|
198
|
+
// that appears while it wears the probe name is waited out the same way, and if it never
|
|
199
|
+
// lets go the diagnostic names where the tree is so the user can restore it.
|
|
200
|
+
await withPatience(probe, packageRoot, error => new Error(PRODUCT_TEXT.diagnostic(`could not restore the package after checking it was unlocked: ${errorMessage(error)}. The package is at ${probe}; rename it back to ${packageRoot} before running the update again.`)));
|
|
152
201
|
},
|
|
153
202
|
async activateInstalled(packageRoot, targetVersion, phase, onMaterializing, onWarmup) {
|
|
154
203
|
const request = { packageRoot, dataDir: paths.dataDir, targetVersion, environment };
|
|
@@ -228,7 +228,7 @@ export class ModelsDialogComponent {
|
|
|
228
228
|
push();
|
|
229
229
|
if (this.#refreshStatus !== undefined)
|
|
230
230
|
push(theme.fg(this.#refreshStatus.kind, ` ${this.#refreshStatus.message}`));
|
|
231
|
-
push(renderPiModalShortcutHints(this.#hints()
|
|
231
|
+
push(renderPiModalShortcutHints(this.#hints()));
|
|
232
232
|
push(border);
|
|
233
233
|
return lines;
|
|
234
234
|
}
|
|
@@ -16,14 +16,8 @@ export declare const PINNED_PI_BUILTIN_SLASH_COMMANDS: ({
|
|
|
16
16
|
export declare const OWNED_BUILTIN_SLASH_COMMANDS: ({
|
|
17
17
|
readonly name: "thinking";
|
|
18
18
|
readonly description: "Set thinking level";
|
|
19
|
-
readonly argumentHint: "<level>";
|
|
20
|
-
} | {
|
|
21
|
-
name: string;
|
|
22
|
-
description: string;
|
|
23
|
-
argumentHint?: never;
|
|
24
19
|
} | {
|
|
25
20
|
name: string;
|
|
26
21
|
description: string;
|
|
27
|
-
argumentHint: string;
|
|
28
22
|
})[];
|
|
29
23
|
export declare function createPiShellEditor(options: PiShellEditorOptions): PiShellEditorPort;
|
|
@@ -9,12 +9,14 @@ import { createTuiFacade, ensureTheme, isAutocompleteProvider, } from "./shell-s
|
|
|
9
9
|
import { SKILLS_COMMAND_NAME, collapseSkillCommands, createSkillsTunnelProvider, } from "./skills-command.js";
|
|
10
10
|
/** A selected autocomplete row: the accent primary column, then the aligned description. */
|
|
11
11
|
const SELECTED_DESCRIBED_ROW = /^(→ .*?\S)(\s{2,}.*)$/u;
|
|
12
|
-
const
|
|
12
|
+
const PINNED_THINKING_SLASH_COMMAND = { name: "thinking", description: "Set thinking level", argumentHint: "<level>" };
|
|
13
|
+
const OWNED_THINKING_SLASH_COMMAND = { name: "thinking", description: "Set thinking level" };
|
|
14
|
+
const OWNED_LOGIN_SLASH_COMMAND = { name: "login", description: "Configure provider authentication" };
|
|
13
15
|
export const PINNED_PI_BUILTIN_SLASH_COMMANDS = [
|
|
14
16
|
{ name: "settings", description: "Open settings menu" },
|
|
15
17
|
{ name: "model", description: "Select model (opens selector UI)", argumentHint: "<provider/model>" },
|
|
16
18
|
{ name: "tree", description: "Navigate session tree (switch branches)" },
|
|
17
|
-
|
|
19
|
+
PINNED_THINKING_SLASH_COMMAND,
|
|
18
20
|
{ name: "scoped-models", description: "Enable/disable models for Ctrl+P cycling" },
|
|
19
21
|
{ name: "export", description: "Export session (HTML default, or specify path: .html/.jsonl)" },
|
|
20
22
|
{ name: "import", description: "Import and resume a session from a JSONL file" },
|
|
@@ -36,9 +38,16 @@ export const PINNED_PI_BUILTIN_SLASH_COMMANDS = [
|
|
|
36
38
|
{ name: "quit", description: "Quit" },
|
|
37
39
|
];
|
|
38
40
|
/** Bare A1's built-in catalog: `models` replaces the pinned pair and is followed by `thinking`. */
|
|
39
|
-
export const OWNED_BUILTIN_SLASH_COMMANDS = PINNED_PI_BUILTIN_SLASH_COMMANDS.flatMap(command =>
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
export const OWNED_BUILTIN_SLASH_COMMANDS = PINNED_PI_BUILTIN_SLASH_COMMANDS.flatMap(command => {
|
|
42
|
+
if (command.name === "model") {
|
|
43
|
+
return [{ name: "models", description: "Switch models and manage scoped model cycling" }, OWNED_THINKING_SLASH_COMMAND];
|
|
44
|
+
}
|
|
45
|
+
if (command.name === "thinking" || command.name === "scoped-models")
|
|
46
|
+
return [];
|
|
47
|
+
if (command.name === "login")
|
|
48
|
+
return [OWNED_LOGIN_SLASH_COMMAND];
|
|
49
|
+
return [command];
|
|
50
|
+
});
|
|
42
51
|
export function createPiShellEditor(options) {
|
|
43
52
|
ensureTheme();
|
|
44
53
|
const tui = createTuiFacade(options);
|
|
@@ -49,7 +49,7 @@ class SkillsSelectorComponent extends Container {
|
|
|
49
49
|
{ key: "↑↓", action: "navigate" },
|
|
50
50
|
{ key: bindings.getKeys("tui.select.confirm").join("/"), action: "select" },
|
|
51
51
|
{ key: bindings.getKeys("tui.select.cancel").join("/"), action: "cancel" },
|
|
52
|
-
]
|
|
52
|
+
]), 0, 0));
|
|
53
53
|
this.addChild(new DynamicBorder());
|
|
54
54
|
this.#updateList();
|
|
55
55
|
}
|
|
@@ -179,7 +179,7 @@ export class ScopedModelsSelectorComponent extends Container {
|
|
|
179
179
|
{ key: reorderKeys, action: "reorder" },
|
|
180
180
|
{ key: keyDisplayText("app.models.save"), action: "save" },
|
|
181
181
|
{ action: countText },
|
|
182
|
-
]
|
|
182
|
+
]);
|
|
183
183
|
return this.isDirty ? `${hint} ${theme.fg("warning", "(unsaved)")}` : hint;
|
|
184
184
|
}
|
|
185
185
|
refresh() {
|
|
@@ -74,7 +74,7 @@ export class OwnedThinkingSelectorComponent extends Container {
|
|
|
74
74
|
{ key: this.keyDisplayText("tui.select.confirm"), action: "to select" },
|
|
75
75
|
{ key: this.keyDisplayText("app.thinking.save"), action: "to set as default" },
|
|
76
76
|
{ key: this.keyDisplayText("tui.select.cancel"), action: "to cancel" },
|
|
77
|
-
]
|
|
77
|
+
]), 0, 0));
|
|
78
78
|
this.addChild(new DynamicBorder((text) => piTheme().fg("border", text)));
|
|
79
79
|
}
|
|
80
80
|
keyDisplayText(keybinding) {
|
|
@@ -1080,7 +1080,8 @@ class TreeHelp {
|
|
|
1080
1080
|
return renderPiModalShortcutHints([key ? { key, action: label, ...(labelFirst === undefined ? {} : { actionFirst: labelFirst }) } : { action: label }]);
|
|
1081
1081
|
});
|
|
1082
1082
|
const availableWidth = Math.max(1, width);
|
|
1083
|
-
|
|
1083
|
+
// Match the title's Text padding plus its two-cell authored inset.
|
|
1084
|
+
const indent = " ";
|
|
1084
1085
|
const separator = " ";
|
|
1085
1086
|
const lines = [];
|
|
1086
1087
|
let currentLine = "";
|
|
@@ -178,7 +178,7 @@ export class PiResourceCatalog {
|
|
|
178
178
|
{
|
|
179
179
|
name: "login",
|
|
180
180
|
description: "Configure provider authentication",
|
|
181
|
-
argumentHint: "<provider>",
|
|
181
|
+
...(this.#productMode === "comparison" ? { argumentHint: "<provider>" } : {}),
|
|
182
182
|
argumentOptions: this.#contexts.loginOptions().map(option => ({ ...option, id: option.id.split(":").at(-1) ?? option.id })),
|
|
183
183
|
source: "builtin",
|
|
184
184
|
},
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"platform": "darwin",
|
|
6
6
|
"architecture": "arm64",
|
|
7
7
|
"capability": "supported",
|
|
8
|
-
"builtAt": "2026-09-
|
|
8
|
+
"builtAt": "2026-09-23T10:26:02.976Z",
|
|
9
9
|
"artifact": {
|
|
10
10
|
"filename": "process-guardian",
|
|
11
11
|
"sha256": "9db1726bbe3fc2e8292f2ead1e7e9d0fd4d7d0dc9217b372582bf354b0f565dc",
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"platform": "linux",
|
|
6
6
|
"architecture": "x64",
|
|
7
7
|
"capability": "supported",
|
|
8
|
-
"builtAt": "2026-09-
|
|
8
|
+
"builtAt": "2026-09-23T10:25:44.532Z",
|
|
9
9
|
"artifact": {
|
|
10
10
|
"filename": "process-guardian",
|
|
11
11
|
"sha256": "d8cda6b0c7cb36c0cc41e90802aceebf6c02eaebbc08a83d7d963d2e918dbd7a",
|
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
"platform": "win32",
|
|
6
6
|
"architecture": "x64",
|
|
7
7
|
"capability": "supported",
|
|
8
|
-
"builtAt": "2026-09-
|
|
8
|
+
"builtAt": "2026-09-23T10:26:28.697Z",
|
|
9
9
|
"artifact": {
|
|
10
10
|
"filename": "process-guardian.exe",
|
|
11
|
-
"sha256": "
|
|
11
|
+
"sha256": "3350a8cef128cf5a794ff0f9bb46eb6c99dd10f390f40a9083f4b5c13f0e7d62",
|
|
12
12
|
"size": 177664
|
|
13
13
|
},
|
|
14
14
|
"provenance": {
|
|
Binary file
|
|
@@ -27,9 +27,9 @@ export function renderDialogPanel(state, width, theme) {
|
|
|
27
27
|
});
|
|
28
28
|
const description = state.rows[state.index]?.description ?? "";
|
|
29
29
|
const hint = typeof state.hint === "string"
|
|
30
|
-
? theme.fg("dim", `
|
|
31
|
-
: renderShortcutHints(state.hint, theme,
|
|
32
|
-
const plainHint = typeof state.hint === "string" ? `
|
|
30
|
+
? theme.fg("dim", ` ${state.hint}`)
|
|
31
|
+
: renderShortcutHints(state.hint, theme, 1);
|
|
32
|
+
const plainHint = typeof state.hint === "string" ? ` ${state.hint}` : shortcutHintsText(state.hint, 1);
|
|
33
33
|
return [
|
|
34
34
|
rule,
|
|
35
35
|
...rows,
|
|
@@ -92,15 +92,18 @@ Build output mirrors the production namespaces directly under ignored `dist/`, w
|
|
|
92
92
|
|
|
93
93
|
Every task worktree must be created at `{working-dir}/.worktrees/<task-id>`, where `{working-dir}` is the agent session's initial working directory. The `.worktrees` directory is inside that working directory, not beside it. For working directory `D:/Git/a1`, `D:/Git/a1/.worktrees/<task-id>` is correct and `D:/Git/a1-<task-id>` is forbidden.
|
|
94
94
|
|
|
95
|
-
From the initial working directory, create and
|
|
95
|
+
From the initial working directory, create the task branch and worktree, run `a1 session link-worktree <absolute-worktree>` from the owning A1 session, and continue to address it explicitly:
|
|
96
96
|
|
|
97
97
|
```sh
|
|
98
98
|
git fetch origin develop
|
|
99
|
-
git worktree add
|
|
99
|
+
git worktree add -b <type>/<short-description> .worktrees/<task-id> origin/develop
|
|
100
|
+
a1 session link-worktree <absolute-worktree>
|
|
100
101
|
git -C .worktrees/<task-id> status
|
|
101
102
|
```
|
|
102
103
|
|
|
103
|
-
|
|
104
|
+
A successful link response confirming the exact canonical worktree is required before planning, implementation, test, or delivery-documentation edits. If linking fails or confirms another path, stop task edits and report the blocker instead of continuing with primary-checkout footer metadata. A session resuming an existing delivery or switching streams links the exact owned worktree before editing it.
|
|
105
|
+
|
|
106
|
+
The association switches bare A1's footer repository context and pull-request discovery; it does not change process or tool cwd and does not register, claim, release, or authorize cleanup of the worktree. Repository commands therefore keep an explicit worktree path. The primary worktree stays on `develop` for integration and must not be used for task edits. Do not edit, adopt, move, or remove another session's worktree.
|
|
104
107
|
|
|
105
108
|
## Documentation and comments
|
|
106
109
|
|
package/package.json
CHANGED