@cluesmith/codev 3.2.2 → 3.2.4
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/dashboard-dist/assets/index-BZ1x7x1X.js.map +1 -1
- package/dist/agent-farm/cli.d.ts.map +1 -1
- package/dist/agent-farm/cli.js +31 -0
- package/dist/agent-farm/cli.js.map +1 -1
- package/dist/agent-farm/commands/attach.js +2 -2
- package/dist/agent-farm/commands/attach.js.map +1 -1
- package/dist/agent-farm/commands/send.d.ts +2 -2
- package/dist/agent-farm/commands/send.js +3 -3
- package/dist/agent-farm/commands/send.js.map +1 -1
- package/dist/agent-farm/commands/setup.d.ts +4 -1
- package/dist/agent-farm/commands/setup.d.ts.map +1 -1
- package/dist/agent-farm/commands/setup.js +8 -4
- package/dist/agent-farm/commands/setup.js.map +1 -1
- package/dist/agent-farm/commands/spawn-worktree.d.ts +11 -0
- package/dist/agent-farm/commands/spawn-worktree.d.ts.map +1 -1
- package/dist/agent-farm/commands/spawn-worktree.js +64 -16
- package/dist/agent-farm/commands/spawn-worktree.js.map +1 -1
- package/dist/agent-farm/commands/status.d.ts.map +1 -1
- package/dist/agent-farm/commands/status.js +26 -2
- package/dist/agent-farm/commands/status.js.map +1 -1
- package/dist/agent-farm/commands/tower-sweep-husks.d.ts +6 -0
- package/dist/agent-farm/commands/tower-sweep-husks.d.ts.map +1 -0
- package/dist/agent-farm/commands/tower-sweep-husks.js +77 -0
- package/dist/agent-farm/commands/tower-sweep-husks.js.map +1 -0
- package/dist/agent-farm/commands/tower.d.ts.map +1 -1
- package/dist/agent-farm/commands/tower.js +34 -0
- package/dist/agent-farm/commands/tower.js.map +1 -1
- package/dist/agent-farm/commands/whoami.d.ts +65 -0
- package/dist/agent-farm/commands/whoami.d.ts.map +1 -0
- package/dist/agent-farm/commands/whoami.js +196 -0
- package/dist/agent-farm/commands/whoami.js.map +1 -0
- package/dist/agent-farm/commands/workspace-recover.d.ts +31 -0
- package/dist/agent-farm/commands/workspace-recover.d.ts.map +1 -1
- package/dist/agent-farm/commands/workspace-recover.js +70 -30
- package/dist/agent-farm/commands/workspace-recover.js.map +1 -1
- package/dist/agent-farm/db/index.d.ts.map +1 -1
- package/dist/agent-farm/db/index.js +8 -2
- package/dist/agent-farm/db/index.js.map +1 -1
- package/dist/agent-farm/lib/tower-client.d.ts +1 -1
- package/dist/agent-farm/lib/tower-client.d.ts.map +1 -1
- package/dist/agent-farm/lib/tower-client.js.map +1 -1
- package/dist/agent-farm/servers/architect-session-holder.d.ts +133 -0
- package/dist/agent-farm/servers/architect-session-holder.d.ts.map +1 -0
- package/dist/agent-farm/servers/architect-session-holder.js +268 -0
- package/dist/agent-farm/servers/architect-session-holder.js.map +1 -0
- package/dist/agent-farm/servers/process-census.d.ts +41 -0
- package/dist/agent-farm/servers/process-census.d.ts.map +1 -0
- package/dist/agent-farm/servers/process-census.js +62 -0
- package/dist/agent-farm/servers/process-census.js.map +1 -0
- package/dist/agent-farm/servers/send-buffer.d.ts.map +1 -1
- package/dist/agent-farm/servers/send-buffer.js +13 -0
- package/dist/agent-farm/servers/send-buffer.js.map +1 -1
- package/dist/agent-farm/servers/session-log-sweep.d.ts +93 -0
- package/dist/agent-farm/servers/session-log-sweep.d.ts.map +1 -0
- package/dist/agent-farm/servers/session-log-sweep.js +165 -0
- package/dist/agent-farm/servers/session-log-sweep.js.map +1 -0
- package/dist/agent-farm/servers/shellper-husk-sweep.d.ts +87 -0
- package/dist/agent-farm/servers/shellper-husk-sweep.d.ts.map +1 -0
- package/dist/agent-farm/servers/shellper-husk-sweep.js +129 -0
- package/dist/agent-farm/servers/shellper-husk-sweep.js.map +1 -0
- package/dist/agent-farm/servers/tower-instances.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-instances.js +203 -36
- package/dist/agent-farm/servers/tower-instances.js.map +1 -1
- package/dist/agent-farm/servers/tower-routes.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-routes.js +147 -4
- package/dist/agent-farm/servers/tower-routes.js.map +1 -1
- package/dist/agent-farm/servers/tower-server.js +95 -1
- package/dist/agent-farm/servers/tower-server.js.map +1 -1
- package/dist/agent-farm/servers/tower-terminals.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-terminals.js +66 -8
- package/dist/agent-farm/servers/tower-terminals.js.map +1 -1
- package/dist/agent-farm/servers/tower-utils.d.ts +106 -4
- package/dist/agent-farm/servers/tower-utils.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-utils.js +155 -19
- package/dist/agent-farm/servers/tower-utils.js.map +1 -1
- package/dist/agent-farm/state.d.ts +13 -1
- package/dist/agent-farm/state.d.ts.map +1 -1
- package/dist/agent-farm/state.js +17 -2
- package/dist/agent-farm/state.js.map +1 -1
- package/dist/agent-farm/utils/claude-session-discovery.d.ts +12 -0
- package/dist/agent-farm/utils/claude-session-discovery.d.ts.map +1 -1
- package/dist/agent-farm/utils/claude-session-discovery.js +42 -4
- package/dist/agent-farm/utils/claude-session-discovery.js.map +1 -1
- package/dist/agent-farm/utils/harness.d.ts +15 -3
- package/dist/agent-farm/utils/harness.d.ts.map +1 -1
- package/dist/agent-farm/utils/harness.js +4 -1
- package/dist/agent-farm/utils/harness.js.map +1 -1
- package/dist/commands/adopt.d.ts +3 -2
- package/dist/commands/adopt.d.ts.map +1 -1
- package/dist/commands/adopt.js +7 -6
- package/dist/commands/adopt.js.map +1 -1
- package/dist/commands/consult/agy-auth-cache.d.ts +97 -0
- package/dist/commands/consult/agy-auth-cache.d.ts.map +1 -0
- package/dist/commands/consult/agy-auth-cache.js +320 -0
- package/dist/commands/consult/agy-auth-cache.js.map +1 -0
- package/dist/commands/consult/index.d.ts.map +1 -1
- package/dist/commands/consult/index.js +59 -0
- package/dist/commands/consult/index.js.map +1 -1
- package/dist/commands/doctor.d.ts +28 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +187 -3
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.d.ts +3 -2
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +7 -6
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/porch/index.d.ts.map +1 -1
- package/dist/commands/porch/index.js +11 -8
- package/dist/commands/porch/index.js.map +1 -1
- package/dist/commands/update.d.ts +4 -4
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +9 -11
- package/dist/commands/update.js.map +1 -1
- package/dist/lib/config.d.ts +1 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/default-branch.d.ts +1 -1
- package/dist/lib/default-branch.js +1 -1
- package/dist/lib/gitignore.d.ts +25 -2
- package/dist/lib/gitignore.d.ts.map +1 -1
- package/dist/lib/gitignore.js +70 -0
- package/dist/lib/gitignore.js.map +1 -1
- package/dist/lib/migration-backup-audit.d.ts +64 -0
- package/dist/lib/migration-backup-audit.d.ts.map +1 -0
- package/dist/lib/migration-backup-audit.js +145 -0
- package/dist/lib/migration-backup-audit.js.map +1 -0
- package/dist/lib/protocol-drift-audit.d.ts +118 -0
- package/dist/lib/protocol-drift-audit.d.ts.map +1 -0
- package/dist/lib/protocol-drift-audit.js +217 -0
- package/dist/lib/protocol-drift-audit.js.map +1 -0
- package/dist/lib/scaffold.d.ts +10 -3
- package/dist/lib/scaffold.d.ts.map +1 -1
- package/dist/lib/scaffold.js +29 -26
- package/dist/lib/scaffold.js.map +1 -1
- package/dist/terminal/pty-manager.d.ts +7 -0
- package/dist/terminal/pty-manager.d.ts.map +1 -1
- package/dist/terminal/pty-manager.js +16 -0
- package/dist/terminal/pty-manager.js.map +1 -1
- package/dist/terminal/pty-session.d.ts +25 -4
- package/dist/terminal/pty-session.d.ts.map +1 -1
- package/dist/terminal/pty-session.js +83 -11
- package/dist/terminal/pty-session.js.map +1 -1
- package/dist/terminal/session-manager.d.ts +109 -0
- package/dist/terminal/session-manager.d.ts.map +1 -1
- package/dist/terminal/session-manager.js +314 -45
- package/dist/terminal/session-manager.js.map +1 -1
- package/dist/terminal/shellper-client.d.ts +19 -4
- package/dist/terminal/shellper-client.d.ts.map +1 -1
- package/dist/terminal/shellper-client.js +70 -8
- package/dist/terminal/shellper-client.js.map +1 -1
- package/dist/terminal/shellper-process.d.ts.map +1 -1
- package/dist/terminal/shellper-process.js +20 -5
- package/dist/terminal/shellper-process.js.map +1 -1
- package/dist/terminal/shellper-protocol.d.ts +40 -2
- package/dist/terminal/shellper-protocol.d.ts.map +1 -1
- package/dist/terminal/shellper-protocol.js +72 -5
- package/dist/terminal/shellper-protocol.js.map +1 -1
- package/package.json +8 -8
- package/skeleton/.claude/skills/afx/SKILL.md +13 -0
- package/skeleton/.claude/skills/arch-init/SKILL.md +122 -0
- package/skeleton/.claude/skills/codev/SKILL.md +2 -2
- package/skeleton/.codex/skills/afx/SKILL.md +157 -0
- package/skeleton/.codex/skills/arch-init/SKILL.md +122 -0
- package/skeleton/.codex/skills/codev/SKILL.md +59 -0
- package/skeleton/.codex/skills/consult/SKILL.md +96 -0
- package/skeleton/.codex/skills/generate-image/SKILL.md +45 -0
- package/skeleton/.codex/skills/porch/SKILL.md +60 -0
- package/skeleton/.codex/skills/update-arch-docs/SKILL.md +132 -0
- package/skeleton/protocols/pir/prompts/implement.md +1 -1
- package/skeleton/protocols/pir/prompts/review.md +1 -1
- package/skeleton/protocols/pir/protocol.md +3 -3
- package/skeleton/resources/commands/agent-farm.md +89 -0
- package/skeleton/resources/commands/codev.md +5 -0
- package/skeleton/resources/commands/consult.md +26 -0
- package/skeleton/roles/architect.md +11 -0
package/dist/commands/adopt.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* codev adopt - Add codev to an existing project
|
|
3
3
|
*
|
|
4
|
-
* Creates
|
|
5
|
-
*
|
|
4
|
+
* Creates the minimal user-owned Codev structure and materializes missing
|
|
5
|
+
* provider skills, root instructions, and governance starters from the
|
|
6
|
+
* embedded skeleton. Framework files resolve from the package at runtime.
|
|
6
7
|
*/
|
|
7
8
|
import * as fs from 'node:fs';
|
|
8
9
|
import * as path from 'node:path';
|
|
@@ -94,14 +95,14 @@ export async function adopt(options = {}) {
|
|
|
94
95
|
// Framework files (protocols, roles, consult-types, templates) are NOT copied.
|
|
95
96
|
// They resolve at runtime from the installed npm package via the unified file resolver.
|
|
96
97
|
// Existing local copies in codev/ are left in place — they take precedence via the resolution chain.
|
|
97
|
-
// Copy
|
|
98
|
+
// Copy provider-native skills, preserving existing skill directories.
|
|
98
99
|
const skillsResult = copySkills(targetDir, skeletonDir, { skipExisting: true });
|
|
99
|
-
|
|
100
|
-
console.log(chalk.green(' +'),
|
|
100
|
+
for (const directory of skillsResult.directoriesCreated) {
|
|
101
|
+
console.log(chalk.green(' +'), directory);
|
|
101
102
|
fileCount++;
|
|
102
103
|
}
|
|
103
104
|
for (const skill of skillsResult.copied) {
|
|
104
|
-
console.log(chalk.green(' +'),
|
|
105
|
+
console.log(chalk.green(' +'), skill);
|
|
105
106
|
fileCount++;
|
|
106
107
|
}
|
|
107
108
|
// Copy root files with conflict handling
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adopt.js","sourceRoot":"","sources":["../../src/commands/adopt.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"adopt.js","sourceRoot":"","sources":["../../src/commands/adopt.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-process auth-state cache for the Antigravity CLI (`agy`) — Issue #1077.
|
|
3
|
+
*
|
|
4
|
+
* ## Why this exists
|
|
5
|
+
*
|
|
6
|
+
* An unauthenticated `agy --print` opens an OAuth browser tab *before* it prints
|
|
7
|
+
* the OAuth URL that `AGY_OAUTH_MARKERS` detection keys off. So by the time the
|
|
8
|
+
* gemini consult lane recognises "not signed in" and kills the child, the tab is
|
|
9
|
+
* already on screen. A CMAP burst runs N consults as N separate OS processes, so
|
|
10
|
+
* N tabs land — 12-15 stranded tabs were observed in the wild.
|
|
11
|
+
*
|
|
12
|
+
* A module-level memo cannot help: each `consult` invocation is its own process.
|
|
13
|
+
* The state has to be shared through the filesystem.
|
|
14
|
+
*
|
|
15
|
+
* ## The protocol
|
|
16
|
+
*
|
|
17
|
+
* 1. Read `~/.cache/codev/agy-auth.json`. A *fresh* entry decides immediately:
|
|
18
|
+
* `unauth` → skip without spawning; `auth` → spawn as usual.
|
|
19
|
+
* 2. Cold or expired cache → race for an exclusive lock. Exactly one process
|
|
20
|
+
* wins and becomes the **prober**: it spawns agy for real and publishes the
|
|
21
|
+
* verdict the moment it is knowable (see `runAgyConsultation`).
|
|
22
|
+
* 3. Losers do **not** block on the lock — the prober may hold it for minutes on
|
|
23
|
+
* a real review. They poll the cache for a few seconds and act on the verdict
|
|
24
|
+
* as soon as it appears.
|
|
25
|
+
*
|
|
26
|
+
* ## Fail-open bias
|
|
27
|
+
*
|
|
28
|
+
* Only positive OAuth-marker evidence records `unauth`. A waiter that never sees
|
|
29
|
+
* a verdict proceeds with its spawn. Both choices push failures toward "one
|
|
30
|
+
* unnecessary browser tab" (the status quo) and away from "silently skipped a
|
|
31
|
+
* working reviewer", which would corrupt a CMAP round.
|
|
32
|
+
*/
|
|
33
|
+
export type AgyAuthState = 'auth' | 'unauth';
|
|
34
|
+
/**
|
|
35
|
+
* Opt-out escape hatch: restores the pre-#1077 always-spawn behaviour.
|
|
36
|
+
*
|
|
37
|
+
* Also inert under a test runner unless the suite names a cache directory. This
|
|
38
|
+
* cache is a *user-global* side effect: without the guard, any test that reaches
|
|
39
|
+
* `doctor()` or the gemini lane would record a verdict into the developer's real
|
|
40
|
+
* `~/.cache/codev` and, worse, later tests would silently take the cached branch
|
|
41
|
+
* and stop spawning what they assert on. Suites that mean to exercise the cache
|
|
42
|
+
* set `CODEV_AGY_AUTH_CACHE_DIR` and get the full behaviour.
|
|
43
|
+
*/
|
|
44
|
+
export declare function agyAuthCacheDisabled(): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Cache directory. `CODEV_AGY_AUTH_CACHE_DIR` keeps tests off the real user
|
|
47
|
+
* cache; otherwise XDG_CACHE_HOME, else `~/.cache`.
|
|
48
|
+
*/
|
|
49
|
+
export declare function agyAuthCacheDir(): string;
|
|
50
|
+
/**
|
|
51
|
+
* The cached auth state for `agyBinPath`, or null when there is nothing
|
|
52
|
+
* trustworthy to act on (cold, expired, different binary, or a credential file
|
|
53
|
+
* changed since the probe).
|
|
54
|
+
*/
|
|
55
|
+
export declare function checkCachedAgyAuth(agyBinPath: string): AgyAuthState | null;
|
|
56
|
+
/**
|
|
57
|
+
* Persist a verdict. Written via a temp file + rename so a concurrent reader
|
|
58
|
+
* never observes a half-written JSON document.
|
|
59
|
+
*/
|
|
60
|
+
export declare function recordAgyAuthState(state: AgyAuthState, agyBinPath: string): void;
|
|
61
|
+
/** Test/diagnostic helper: drop the cache file and any lock. */
|
|
62
|
+
export declare function clearAgyAuthCache(): void;
|
|
63
|
+
/**
|
|
64
|
+
* Poll for the prober's verdict. Resolves with the state as soon as one lands,
|
|
65
|
+
* or null if the wait elapses first.
|
|
66
|
+
*
|
|
67
|
+
* Polls the *cache* rather than waiting on the lock: the prober holds the lock
|
|
68
|
+
* for its entire agy run, which can be minutes, but publishes its verdict within
|
|
69
|
+
* seconds.
|
|
70
|
+
*/
|
|
71
|
+
export declare function waitForAgyAuthState(agyBinPath: string, timeoutMs?: number): Promise<AgyAuthState | null>;
|
|
72
|
+
export interface AgyAuthPreflight {
|
|
73
|
+
/** `skip` → do not spawn agy at all; `proceed` → spawn. */
|
|
74
|
+
action: 'skip' | 'proceed';
|
|
75
|
+
/** Skip reason, suitable for a user-facing message. Set iff action is `skip`. */
|
|
76
|
+
reason?: string;
|
|
77
|
+
/**
|
|
78
|
+
* True when this process won the probe lock. Such a process MUST report what
|
|
79
|
+
* it learns via `publish` — every other process is waiting on it.
|
|
80
|
+
*/
|
|
81
|
+
isProber: boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Record a verdict and release the lock. Idempotent, and a no-op for
|
|
84
|
+
* non-probers, so callers can invoke it from every exit path unconditionally.
|
|
85
|
+
*/
|
|
86
|
+
publish: (state: AgyAuthState) => void;
|
|
87
|
+
/** Release the lock without recording anything (abnormal exits). Idempotent. */
|
|
88
|
+
release: () => void;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Decide whether to spawn agy, before spawning it.
|
|
92
|
+
*
|
|
93
|
+
* Callers that receive `proceed` with `isProber: true` are on the hook to
|
|
94
|
+
* `publish` what the spawn reveals; see the module header for the full protocol.
|
|
95
|
+
*/
|
|
96
|
+
export declare function preflightAgyAuth(agyBinPath: string): Promise<AgyAuthPreflight>;
|
|
97
|
+
//# sourceMappingURL=agy-auth-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agy-auth-cache.d.ts","sourceRoot":"","sources":["../../../src/commands/consult/agy-auth-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAMH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,QAAQ,CAAC;AAiE7C;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAI9C;AAED;;;GAGG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAKxC;AA6CD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAW1E;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAiBhF;AAED,gEAAgE;AAChE,wBAAgB,iBAAiB,IAAI,IAAI,CAIxC;AAmCD;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,MAAM,EAClB,SAAS,SAA0D,GAClE,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAQ9B;AAED,MAAM,WAAW,gBAAgB;IAC/B,2DAA2D;IAC3D,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,QAAQ,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,OAAO,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IACvC,gFAAgF;IAChF,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAKD;;;;;GAKG;AACH,wBAAsB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAyCpF"}
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-process auth-state cache for the Antigravity CLI (`agy`) — Issue #1077.
|
|
3
|
+
*
|
|
4
|
+
* ## Why this exists
|
|
5
|
+
*
|
|
6
|
+
* An unauthenticated `agy --print` opens an OAuth browser tab *before* it prints
|
|
7
|
+
* the OAuth URL that `AGY_OAUTH_MARKERS` detection keys off. So by the time the
|
|
8
|
+
* gemini consult lane recognises "not signed in" and kills the child, the tab is
|
|
9
|
+
* already on screen. A CMAP burst runs N consults as N separate OS processes, so
|
|
10
|
+
* N tabs land — 12-15 stranded tabs were observed in the wild.
|
|
11
|
+
*
|
|
12
|
+
* A module-level memo cannot help: each `consult` invocation is its own process.
|
|
13
|
+
* The state has to be shared through the filesystem.
|
|
14
|
+
*
|
|
15
|
+
* ## The protocol
|
|
16
|
+
*
|
|
17
|
+
* 1. Read `~/.cache/codev/agy-auth.json`. A *fresh* entry decides immediately:
|
|
18
|
+
* `unauth` → skip without spawning; `auth` → spawn as usual.
|
|
19
|
+
* 2. Cold or expired cache → race for an exclusive lock. Exactly one process
|
|
20
|
+
* wins and becomes the **prober**: it spawns agy for real and publishes the
|
|
21
|
+
* verdict the moment it is knowable (see `runAgyConsultation`).
|
|
22
|
+
* 3. Losers do **not** block on the lock — the prober may hold it for minutes on
|
|
23
|
+
* a real review. They poll the cache for a few seconds and act on the verdict
|
|
24
|
+
* as soon as it appears.
|
|
25
|
+
*
|
|
26
|
+
* ## Fail-open bias
|
|
27
|
+
*
|
|
28
|
+
* Only positive OAuth-marker evidence records `unauth`. A waiter that never sees
|
|
29
|
+
* a verdict proceeds with its spawn. Both choices push failures toward "one
|
|
30
|
+
* unnecessary browser tab" (the status quo) and away from "silently skipped a
|
|
31
|
+
* working reviewer", which would corrupt a CMAP round.
|
|
32
|
+
*/
|
|
33
|
+
import fs from 'node:fs';
|
|
34
|
+
import path from 'node:path';
|
|
35
|
+
import { homedir } from 'node:os';
|
|
36
|
+
/**
|
|
37
|
+
* `unauth` expires fast: a user who signs in elsewhere should get the lane back
|
|
38
|
+
* without clearing anything by hand. `auth` lasts longer because re-probing a
|
|
39
|
+
* working agy is pure overhead.
|
|
40
|
+
*/
|
|
41
|
+
const DEFAULT_TTL_UNAUTH_MS = 5 * 60 * 1000;
|
|
42
|
+
const DEFAULT_TTL_AUTH_MS = 30 * 60 * 1000;
|
|
43
|
+
/** How long a waiter polls for the prober's verdict before failing open. */
|
|
44
|
+
const DEFAULT_WAIT_MS = 6000;
|
|
45
|
+
const WAIT_POLL_INTERVAL_MS = 100;
|
|
46
|
+
/**
|
|
47
|
+
* A lock older than this is treated as abandoned (prober crashed / was killed
|
|
48
|
+
* mid-run) and reclaimed. Generous enough to cover a prober that is still
|
|
49
|
+
* deciding, short enough that a crash does not wedge the lane for a whole TTL.
|
|
50
|
+
*/
|
|
51
|
+
const LOCK_STALE_MS = 60 * 1000;
|
|
52
|
+
/**
|
|
53
|
+
* Files agy plausibly writes when an OAuth login completes. Purely a *hint*: a
|
|
54
|
+
* changed mtime invalidates the cache early, so a sign-in is picked up before
|
|
55
|
+
* the TTL lapses. agy's credential location is not documented and has moved
|
|
56
|
+
* between releases, so this list is best-effort by design and every entry is
|
|
57
|
+
* optional — when none exist, `agyAuthMtime` is null and the TTL is the only
|
|
58
|
+
* recovery window (which is sufficient on its own).
|
|
59
|
+
*
|
|
60
|
+
* Deliberately excludes general settings/state files: those churn for unrelated
|
|
61
|
+
* reasons, and a spurious invalidation costs a browser tab.
|
|
62
|
+
*/
|
|
63
|
+
const AGY_CREDENTIAL_CANDIDATES = [
|
|
64
|
+
['.antigravity', 'credentials.json'],
|
|
65
|
+
['Library', 'Application Support', 'Antigravity', 'credentials.json'],
|
|
66
|
+
['.gemini', 'antigravity-cli', 'credentials.json'],
|
|
67
|
+
['.gemini', 'antigravity-cli', 'oauth_creds.json'],
|
|
68
|
+
['.gemini', 'oauth_creds.json'],
|
|
69
|
+
['.gemini', 'google_accounts.json'],
|
|
70
|
+
];
|
|
71
|
+
function envInt(name, fallback) {
|
|
72
|
+
const raw = process.env[name];
|
|
73
|
+
if (!raw)
|
|
74
|
+
return fallback;
|
|
75
|
+
const parsed = Number.parseInt(raw, 10);
|
|
76
|
+
return Number.isFinite(parsed) && parsed >= 0 ? parsed : fallback;
|
|
77
|
+
}
|
|
78
|
+
function ttlFor(state) {
|
|
79
|
+
return state === 'unauth'
|
|
80
|
+
? envInt('CODEV_AGY_AUTH_CACHE_TTL_UNAUTH_MS', DEFAULT_TTL_UNAUTH_MS)
|
|
81
|
+
: envInt('CODEV_AGY_AUTH_CACHE_TTL_AUTH_MS', DEFAULT_TTL_AUTH_MS);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Opt-out escape hatch: restores the pre-#1077 always-spawn behaviour.
|
|
85
|
+
*
|
|
86
|
+
* Also inert under a test runner unless the suite names a cache directory. This
|
|
87
|
+
* cache is a *user-global* side effect: without the guard, any test that reaches
|
|
88
|
+
* `doctor()` or the gemini lane would record a verdict into the developer's real
|
|
89
|
+
* `~/.cache/codev` and, worse, later tests would silently take the cached branch
|
|
90
|
+
* and stop spawning what they assert on. Suites that mean to exercise the cache
|
|
91
|
+
* set `CODEV_AGY_AUTH_CACHE_DIR` and get the full behaviour.
|
|
92
|
+
*/
|
|
93
|
+
export function agyAuthCacheDisabled() {
|
|
94
|
+
const raw = process.env.CODEV_AGY_AUTH_CACHE_DISABLE;
|
|
95
|
+
if (raw === '1' || raw === 'true')
|
|
96
|
+
return true;
|
|
97
|
+
return Boolean(process.env.VITEST) && !process.env.CODEV_AGY_AUTH_CACHE_DIR;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Cache directory. `CODEV_AGY_AUTH_CACHE_DIR` keeps tests off the real user
|
|
101
|
+
* cache; otherwise XDG_CACHE_HOME, else `~/.cache`.
|
|
102
|
+
*/
|
|
103
|
+
export function agyAuthCacheDir() {
|
|
104
|
+
const override = process.env.CODEV_AGY_AUTH_CACHE_DIR;
|
|
105
|
+
if (override)
|
|
106
|
+
return override;
|
|
107
|
+
const xdg = process.env.XDG_CACHE_HOME;
|
|
108
|
+
return path.join(xdg && xdg.startsWith('/') ? xdg : path.join(homedir(), '.cache'), 'codev');
|
|
109
|
+
}
|
|
110
|
+
function cacheFilePath() {
|
|
111
|
+
return path.join(agyAuthCacheDir(), 'agy-auth.json');
|
|
112
|
+
}
|
|
113
|
+
function lockFilePath() {
|
|
114
|
+
return path.join(agyAuthCacheDir(), 'agy-auth.lock');
|
|
115
|
+
}
|
|
116
|
+
/** Newest mtime across the candidate credential files; null when none exist. */
|
|
117
|
+
function currentAgyAuthMtime() {
|
|
118
|
+
let newest = null;
|
|
119
|
+
for (const parts of AGY_CREDENTIAL_CANDIDATES) {
|
|
120
|
+
try {
|
|
121
|
+
const stat = fs.statSync(path.join(homedir(), ...parts));
|
|
122
|
+
const mtime = stat.mtimeMs;
|
|
123
|
+
if (newest === null || mtime > newest)
|
|
124
|
+
newest = mtime;
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
// Absent or unreadable — this list is a hint, not a requirement.
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return newest;
|
|
131
|
+
}
|
|
132
|
+
function readEntry() {
|
|
133
|
+
try {
|
|
134
|
+
const parsed = JSON.parse(fs.readFileSync(cacheFilePath(), 'utf-8'));
|
|
135
|
+
if (!parsed || typeof parsed !== 'object')
|
|
136
|
+
return null;
|
|
137
|
+
const e = parsed;
|
|
138
|
+
if (e.state !== 'auth' && e.state !== 'unauth')
|
|
139
|
+
return null;
|
|
140
|
+
if (typeof e.checkedAt !== 'number' || !Number.isFinite(e.checkedAt))
|
|
141
|
+
return null;
|
|
142
|
+
if (typeof e.agyBinPath !== 'string')
|
|
143
|
+
return null;
|
|
144
|
+
return {
|
|
145
|
+
state: e.state,
|
|
146
|
+
checkedAt: e.checkedAt,
|
|
147
|
+
agyBinPath: e.agyBinPath,
|
|
148
|
+
agyAuthMtime: typeof e.agyAuthMtime === 'number' ? e.agyAuthMtime : null,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
// Missing, truncated, or concurrently-rewritten file — treat as cold.
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* The cached auth state for `agyBinPath`, or null when there is nothing
|
|
158
|
+
* trustworthy to act on (cold, expired, different binary, or a credential file
|
|
159
|
+
* changed since the probe).
|
|
160
|
+
*/
|
|
161
|
+
export function checkCachedAgyAuth(agyBinPath) {
|
|
162
|
+
if (agyAuthCacheDisabled())
|
|
163
|
+
return null;
|
|
164
|
+
const entry = readEntry();
|
|
165
|
+
if (!entry)
|
|
166
|
+
return null;
|
|
167
|
+
// A reinstall or a CODEV_AGY_BIN change means the verdict describes a
|
|
168
|
+
// different binary than the one we are about to run.
|
|
169
|
+
if (entry.agyBinPath !== agyBinPath)
|
|
170
|
+
return null;
|
|
171
|
+
if (Date.now() - entry.checkedAt >= ttlFor(entry.state))
|
|
172
|
+
return null;
|
|
173
|
+
// Credentials moved under us → someone signed in (or out); re-probe.
|
|
174
|
+
if (entry.agyAuthMtime !== currentAgyAuthMtime())
|
|
175
|
+
return null;
|
|
176
|
+
return entry.state;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Persist a verdict. Written via a temp file + rename so a concurrent reader
|
|
180
|
+
* never observes a half-written JSON document.
|
|
181
|
+
*/
|
|
182
|
+
export function recordAgyAuthState(state, agyBinPath) {
|
|
183
|
+
if (agyAuthCacheDisabled())
|
|
184
|
+
return;
|
|
185
|
+
const entry = {
|
|
186
|
+
state,
|
|
187
|
+
checkedAt: Date.now(),
|
|
188
|
+
agyBinPath,
|
|
189
|
+
agyAuthMtime: currentAgyAuthMtime(),
|
|
190
|
+
};
|
|
191
|
+
try {
|
|
192
|
+
const dir = agyAuthCacheDir();
|
|
193
|
+
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
194
|
+
const tmp = path.join(dir, `agy-auth.${process.pid}.tmp`);
|
|
195
|
+
fs.writeFileSync(tmp, JSON.stringify(entry), { mode: 0o600 });
|
|
196
|
+
fs.renameSync(tmp, cacheFilePath());
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
// A cache we cannot write is a missed optimisation, never a failed consult.
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/** Test/diagnostic helper: drop the cache file and any lock. */
|
|
203
|
+
export function clearAgyAuthCache() {
|
|
204
|
+
for (const p of [cacheFilePath(), lockFilePath()]) {
|
|
205
|
+
try {
|
|
206
|
+
fs.unlinkSync(p);
|
|
207
|
+
}
|
|
208
|
+
catch { /* already gone */ }
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Try to become the prober. Returns a release function on success, null when
|
|
213
|
+
* another process holds the lock. An abandoned lock (older than LOCK_STALE_MS)
|
|
214
|
+
* is reclaimed once.
|
|
215
|
+
*/
|
|
216
|
+
function acquireProbeLock() {
|
|
217
|
+
const lockPath = lockFilePath();
|
|
218
|
+
const attempt = () => {
|
|
219
|
+
try {
|
|
220
|
+
fs.mkdirSync(agyAuthCacheDir(), { recursive: true, mode: 0o700 });
|
|
221
|
+
// 'wx' fails when the file exists — the atomic test-and-set we need.
|
|
222
|
+
const fd = fs.openSync(lockPath, 'wx', 0o600);
|
|
223
|
+
fs.writeSync(fd, `${process.pid} ${Date.now()}\n`);
|
|
224
|
+
fs.closeSync(fd);
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
if (attempt())
|
|
232
|
+
return () => { try {
|
|
233
|
+
fs.unlinkSync(lockPath);
|
|
234
|
+
}
|
|
235
|
+
catch { /* already gone */ } };
|
|
236
|
+
try {
|
|
237
|
+
if (Date.now() - fs.statSync(lockPath).mtimeMs > LOCK_STALE_MS) {
|
|
238
|
+
fs.unlinkSync(lockPath);
|
|
239
|
+
if (attempt())
|
|
240
|
+
return () => { try {
|
|
241
|
+
fs.unlinkSync(lockPath);
|
|
242
|
+
}
|
|
243
|
+
catch { /* already gone */ } };
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
catch {
|
|
247
|
+
// Lock vanished mid-inspection (holder finished) — fall through to waiting.
|
|
248
|
+
}
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Poll for the prober's verdict. Resolves with the state as soon as one lands,
|
|
253
|
+
* or null if the wait elapses first.
|
|
254
|
+
*
|
|
255
|
+
* Polls the *cache* rather than waiting on the lock: the prober holds the lock
|
|
256
|
+
* for its entire agy run, which can be minutes, but publishes its verdict within
|
|
257
|
+
* seconds.
|
|
258
|
+
*/
|
|
259
|
+
export async function waitForAgyAuthState(agyBinPath, timeoutMs = envInt('CODEV_AGY_AUTH_CACHE_WAIT_MS', DEFAULT_WAIT_MS)) {
|
|
260
|
+
const deadline = Date.now() + timeoutMs;
|
|
261
|
+
for (;;) {
|
|
262
|
+
const state = checkCachedAgyAuth(agyBinPath);
|
|
263
|
+
if (state)
|
|
264
|
+
return state;
|
|
265
|
+
if (Date.now() >= deadline)
|
|
266
|
+
return null;
|
|
267
|
+
await new Promise((r) => setTimeout(r, WAIT_POLL_INTERVAL_MS));
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
const SKIP_REASON_CACHED_UNAUTH = 'agy unauthenticated (cached); run `agy` once to sign in';
|
|
271
|
+
/**
|
|
272
|
+
* Decide whether to spawn agy, before spawning it.
|
|
273
|
+
*
|
|
274
|
+
* Callers that receive `proceed` with `isProber: true` are on the hook to
|
|
275
|
+
* `publish` what the spawn reveals; see the module header for the full protocol.
|
|
276
|
+
*/
|
|
277
|
+
export async function preflightAgyAuth(agyBinPath) {
|
|
278
|
+
const inert = {
|
|
279
|
+
action: 'proceed',
|
|
280
|
+
isProber: false,
|
|
281
|
+
publish: () => { },
|
|
282
|
+
release: () => { },
|
|
283
|
+
};
|
|
284
|
+
if (agyAuthCacheDisabled())
|
|
285
|
+
return inert;
|
|
286
|
+
const cached = checkCachedAgyAuth(agyBinPath);
|
|
287
|
+
if (cached === 'unauth') {
|
|
288
|
+
return { ...inert, action: 'skip', reason: SKIP_REASON_CACHED_UNAUTH };
|
|
289
|
+
}
|
|
290
|
+
if (cached === 'auth')
|
|
291
|
+
return inert;
|
|
292
|
+
const release = acquireProbeLock();
|
|
293
|
+
if (release) {
|
|
294
|
+
let done = false;
|
|
295
|
+
const finish = (state) => {
|
|
296
|
+
if (done)
|
|
297
|
+
return;
|
|
298
|
+
done = true;
|
|
299
|
+
if (state)
|
|
300
|
+
recordAgyAuthState(state, agyBinPath);
|
|
301
|
+
release();
|
|
302
|
+
};
|
|
303
|
+
return {
|
|
304
|
+
action: 'proceed',
|
|
305
|
+
isProber: true,
|
|
306
|
+
publish: (state) => finish(state),
|
|
307
|
+
release: () => finish(),
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
// Another process is probing. Wait briefly for its verdict rather than adding
|
|
311
|
+
// a spawn (and a browser tab) of our own.
|
|
312
|
+
const observed = await waitForAgyAuthState(agyBinPath);
|
|
313
|
+
if (observed === 'unauth') {
|
|
314
|
+
return { ...inert, action: 'skip', reason: SKIP_REASON_CACHED_UNAUTH };
|
|
315
|
+
}
|
|
316
|
+
// `auth`, or no verdict in time: proceed. Failing open keeps a slow or crashed
|
|
317
|
+
// prober from silently dropping a reviewer that would have worked.
|
|
318
|
+
return inert;
|
|
319
|
+
}
|
|
320
|
+
//# sourceMappingURL=agy-auth-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agy-auth-cache.js","sourceRoot":"","sources":["../../../src/commands/consult/agy-auth-cache.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/consult/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/consult/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -20,6 +20,7 @@ import { getResolver, GitRefResolver } from '../porch/artifacts.js';
|
|
|
20
20
|
import { MetricsDB } from './metrics.js';
|
|
21
21
|
import { extractUsage, extractReviewText } from './usage-extractor.js';
|
|
22
22
|
import { executeForgeCommandSync } from '../../lib/forge.js';
|
|
23
|
+
import { preflightAgyAuth, recordAgyAuthState } from './agy-auth-cache.js';
|
|
23
24
|
const MODEL_CONFIGS = {
|
|
24
25
|
// gemini dispatches to the Antigravity CLI (`agy`) via runAgyConsultation —
|
|
25
26
|
// this entry exists only for model validation and the `pro` alias; its
|
|
@@ -519,6 +520,14 @@ const AGY_PRINT_TIMEOUT = '5m'; // passed to `agy --print-timeout`
|
|
|
519
520
|
const AGY_TIMEOUT_MS = 6 * 60 * 1000; // Codev-owned hard cap (> agy's own timeout)
|
|
520
521
|
// OAuth banner appears before any review text; only scan the early stream.
|
|
521
522
|
const AGY_MARKER_SCAN_LIMIT = 8192;
|
|
523
|
+
/**
|
|
524
|
+
* How long a prober waits, marker-free, before publishing `auth` to the shared
|
|
525
|
+
* cache (#1077). The OAuth banner is the very first thing an unauthenticated agy
|
|
526
|
+
* emits, so silence this far in is good evidence we are signed in — and it lets
|
|
527
|
+
* the processes waiting on our verdict get moving instead of stalling behind a
|
|
528
|
+
* review that may run for minutes.
|
|
529
|
+
*/
|
|
530
|
+
const AGY_AUTH_GRACE_MS = 3000;
|
|
522
531
|
// agy's own print-timeout message: on an agentic task that outruns --print-timeout,
|
|
523
532
|
// it returns this (often with a "monitoring the task" note) instead of a review.
|
|
524
533
|
// Treat it as a non-response → non-blocking skip rather than a garbage "review".
|
|
@@ -661,6 +670,20 @@ async function runAgyConsultation(queryText, role, workspaceRoot, outputPath, me
|
|
|
661
670
|
console.error(`\n[gemini (agy) skipped: ${reason}]`);
|
|
662
671
|
return;
|
|
663
672
|
}
|
|
673
|
+
// Pre-flight the shared auth cache BEFORE spawning (#1077). An unauthenticated
|
|
674
|
+
// agy opens a browser tab before it prints the OAuth URL we detect below, so
|
|
675
|
+
// post-spawn detection cannot prevent the tab — only not spawning can. Across a
|
|
676
|
+
// CMAP burst this collapses N stranded tabs into at most one per TTL window.
|
|
677
|
+
const preflight = await preflightAgyAuth(bin);
|
|
678
|
+
if (preflight.action === 'skip') {
|
|
679
|
+
const reason = preflight.reason ?? 'agy unauthenticated (cached)';
|
|
680
|
+
const content = agySkipContent(reason);
|
|
681
|
+
process.stdout.write(content);
|
|
682
|
+
writeConsultOutput(outputPath, content);
|
|
683
|
+
recordAgyMetrics(metricsCtx, startTime, 0, reason);
|
|
684
|
+
console.error(`\n[gemini (agy) skipped without spawning: ${reason}]`);
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
664
687
|
// agy has no system-prompt flag — fold the role into the prompt (hermes precedent).
|
|
665
688
|
// Prepend strict constraint directive to force agy to remain on-task, prevent exploratory actions
|
|
666
689
|
// that lead to wandering off-task, and avoid unrelated local skills/directories (Issue #1032).
|
|
@@ -712,6 +735,20 @@ async function runAgyConsultation(queryText, role, workspaceRoot, outputPath, me
|
|
|
712
735
|
const outChunks = [];
|
|
713
736
|
let scanBuf = '';
|
|
714
737
|
let settled = false;
|
|
738
|
+
// When we hold the probe lock, other consult processes are polling the cache
|
|
739
|
+
// for our verdict — publish it as soon as it is knowable, and always release
|
|
740
|
+
// the lock, whatever this run turns into.
|
|
741
|
+
const graceTimer = preflight.isProber
|
|
742
|
+
? setTimeout(() => preflight.publish('auth'), AGY_AUTH_GRACE_MS)
|
|
743
|
+
: null;
|
|
744
|
+
const publishAuth = (state) => {
|
|
745
|
+
if (graceTimer)
|
|
746
|
+
clearTimeout(graceTimer);
|
|
747
|
+
if (state)
|
|
748
|
+
preflight.publish(state);
|
|
749
|
+
else
|
|
750
|
+
preflight.release();
|
|
751
|
+
};
|
|
715
752
|
const settleSkip = (reason, exitCode = 0) => {
|
|
716
753
|
if (settled)
|
|
717
754
|
return;
|
|
@@ -722,6 +759,10 @@ async function runAgyConsultation(queryText, role, workspaceRoot, outputPath, me
|
|
|
722
759
|
}
|
|
723
760
|
catch { /* already gone */ }
|
|
724
761
|
cleanup();
|
|
762
|
+
// No-op if a verdict was already published (e.g. the OAuth-marker path);
|
|
763
|
+
// otherwise this just releases the lock — a timeout or a spawn failure is
|
|
764
|
+
// not evidence either way about authentication.
|
|
765
|
+
publishAuth();
|
|
725
766
|
const content = agySkipContent(reason);
|
|
726
767
|
process.stdout.write(content);
|
|
727
768
|
writeConsultOutput(outputPath, content);
|
|
@@ -736,6 +777,19 @@ async function runAgyConsultation(queryText, role, workspaceRoot, outputPath, me
|
|
|
736
777
|
if (scanBuf.length < AGY_MARKER_SCAN_LIMIT) {
|
|
737
778
|
scanBuf += buf.toString('utf-8');
|
|
738
779
|
if (AGY_OAUTH_MARKERS.some((m) => scanBuf.includes(m))) {
|
|
780
|
+
// The one place we have positive proof of being signed out, so it is
|
|
781
|
+
// written unconditionally rather than through the once-only publish:
|
|
782
|
+
// - If our own grace timer already guessed `auth` (agy took longer
|
|
783
|
+
// than AGY_AUTH_GRACE_MS to emit its banner), that guess would
|
|
784
|
+
// otherwise stand for the full auth TTL and every burst in that
|
|
785
|
+
// window would spawn tabs again.
|
|
786
|
+
// - A non-prober that failed open and spawned holds real evidence
|
|
787
|
+
// too; discarding it would leave a misfired guess uncorrected
|
|
788
|
+
// until the TTL lapsed, instead of on the very next spawn.
|
|
789
|
+
// recordAgyAuthState carries its own disabled-guard, so this is safe
|
|
790
|
+
// on every path.
|
|
791
|
+
recordAgyAuthState('unauth', bin);
|
|
792
|
+
publishAuth('unauth');
|
|
739
793
|
settleSkip('agy not authenticated — run `agy` once to sign in (OAuth)', 1);
|
|
740
794
|
}
|
|
741
795
|
}
|
|
@@ -753,6 +807,9 @@ async function runAgyConsultation(queryText, role, workspaceRoot, outputPath, me
|
|
|
753
807
|
cleanup();
|
|
754
808
|
const raw = Buffer.concat(outChunks).toString('utf-8').trim();
|
|
755
809
|
if (code !== 0 || raw.length === 0 || raw.includes(AGY_NONRESPONSE_MARKER)) {
|
|
810
|
+
// A broken run tells us nothing about auth — release without a verdict
|
|
811
|
+
// and let the next call re-probe.
|
|
812
|
+
publishAuth();
|
|
756
813
|
const reason = code !== 0
|
|
757
814
|
? `agy exited with code ${code}`
|
|
758
815
|
: raw.includes(AGY_NONRESPONSE_MARKER)
|
|
@@ -766,6 +823,8 @@ async function runAgyConsultation(queryText, role, workspaceRoot, outputPath, me
|
|
|
766
823
|
resolve();
|
|
767
824
|
return;
|
|
768
825
|
}
|
|
826
|
+
// A real review is conclusive proof agy is signed in.
|
|
827
|
+
publishAuth('auth');
|
|
769
828
|
// Plain-text stdout IS the review.
|
|
770
829
|
process.stdout.write(raw);
|
|
771
830
|
writeConsultOutput(outputPath, raw);
|