@yagni-app/code-staging 0.1.0-staging.997.1 → 0.2.0-staging.1025.1

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.
Files changed (64) hide show
  1. package/README.md +58 -9
  2. package/dist/claudeCompat.d.ts +36 -5
  3. package/dist/claudeCompat.js +85 -23
  4. package/dist/claudePlugins.d.ts +109 -0
  5. package/dist/claudePlugins.js +336 -0
  6. package/dist/cli.js +14 -4
  7. package/dist/crashReport.d.ts +135 -0
  8. package/dist/crashReport.js +291 -0
  9. package/dist/doctor.d.ts +21 -0
  10. package/dist/doctor.js +52 -0
  11. package/dist/extension/askAdvisorTool.js +7 -1
  12. package/dist/extension/bless.js +16 -3
  13. package/dist/extension/boostCommand.d.ts +144 -0
  14. package/dist/extension/boostCommand.js +263 -0
  15. package/dist/extension/branding.d.ts +31 -0
  16. package/dist/extension/branding.js +37 -0
  17. package/dist/extension/chipEditor.js +7 -3
  18. package/dist/extension/claudeRules.d.ts +54 -0
  19. package/dist/extension/claudeRules.js +180 -0
  20. package/dist/extension/config.d.ts +61 -0
  21. package/dist/extension/config.js +86 -0
  22. package/dist/extension/costHud.d.ts +128 -15
  23. package/dist/extension/costHud.js +189 -19
  24. package/dist/extension/crashReport.d.ts +89 -0
  25. package/dist/extension/crashReport.js +241 -0
  26. package/dist/extension/index.d.ts +43 -4
  27. package/dist/extension/index.js +241 -32
  28. package/dist/extension/initPass.d.ts +65 -47
  29. package/dist/extension/initPass.js +145 -145
  30. package/dist/extension/mcpTools.d.ts +57 -0
  31. package/dist/extension/mcpTools.js +132 -0
  32. package/dist/extension/pipeline/eval.d.ts +42 -5
  33. package/dist/extension/pipeline/eval.js +44 -0
  34. package/dist/extension/pipeline/goCommand.d.ts +18 -0
  35. package/dist/extension/pipeline/goCommand.js +139 -26
  36. package/dist/extension/pipeline/goCompareCommand.d.ts +18 -8
  37. package/dist/extension/pipeline/goCompareCommand.js +42 -23
  38. package/dist/extension/pipeline/orchestrator.js +9 -0
  39. package/dist/extension/pipeline/runCostTable.d.ts +37 -0
  40. package/dist/extension/pipeline/runCostTable.js +165 -0
  41. package/dist/extension/pipeline/runState.d.ts +19 -0
  42. package/dist/extension/pipeline/runState.js +11 -0
  43. package/dist/extension/pipeline/runner.d.ts +19 -0
  44. package/dist/extension/pipeline/runner.js +13 -1
  45. package/dist/extension/pipeline/scrubSecrets.js +2 -2
  46. package/dist/extension/pipeline/stages.d.ts +3 -1
  47. package/dist/extension/pipeline/stages.js +3 -1
  48. package/dist/extension/pipeline/types.d.ts +7 -4
  49. package/dist/extension/pipeline/verify.js +6 -1
  50. package/dist/extension/pipeline/worktree.js +3 -1
  51. package/dist/extension/provider.d.ts +7 -1
  52. package/dist/extension/provider.js +8 -1
  53. package/dist/extension/recall.js +5 -2
  54. package/dist/extension/rerouteNotice.d.ts +42 -0
  55. package/dist/extension/rerouteNotice.js +67 -0
  56. package/dist/extension/sessionRuns.d.ts +45 -0
  57. package/dist/extension/sessionRuns.js +77 -0
  58. package/dist/extension/subagents.d.ts +17 -7
  59. package/dist/extension/subagents.js +52 -7
  60. package/dist/launch.d.ts +17 -3
  61. package/dist/launch.js +22 -9
  62. package/dist/login.d.ts +7 -0
  63. package/dist/login.js +3 -1
  64. package/package.json +2 -2
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Crash reporting for the pi extension: a sanitized, fire-and-forget POST to
3
+ * the YAGNI backend's /api/yagni-code/crash. No third-party telemetry SDK —
4
+ * crash reports are the only thing that phones home, they contain no code and
5
+ * no prompts, and `YAGNI_DISABLE_CRASH_REPORTS=1` turns them off.
6
+ *
7
+ * Two report paths use this module:
8
+ * - `uncaughtExceptionMonitor` (installed by index.ts): the MONITOR hook is
9
+ * chosen deliberately — unlike an `uncaughtException` listener it never
10
+ * changes crash semantics in pi's process (which YAGNI does not own); it
11
+ * only observes the crash that is already happening. This is also the
12
+ * "tool error that indicates a crash, not a user error" discriminator:
13
+ * a user-visible tool failure is caught and rendered by pi, while
14
+ * anything reaching the monitor was about to kill the session.
15
+ * - the /go pipeline's terminal catch (goCommand.ts), where a thrown error
16
+ * — not a verdict-shaped failure — ends the run.
17
+ *
18
+ * Everything is fail-soft: never throws, never retries, single short-timeout
19
+ * attempt, and reporting can never affect the user's session.
20
+ *
21
+ * The sanitizer (env-value redaction + path collapse + caps around the shared
22
+ * scrubSecrets patterns) is kept in sync with
23
+ * `yagni-code-cli/src/crashReport.ts`; the backend re-runs its own copy in
24
+ * `backend/src/yagniCode/crashReports.ts`. Spec:
25
+ * docs/superpowers/specs/2026-08-08-crash-reporting-design.md
26
+ */
27
+ export declare const CRASH_REPORT_DISABLE_ENV = "YAGNI_DISABLE_CRASH_REPORTS";
28
+ export declare const CRASH_REPORT_TIMEOUT_MS = 1500;
29
+ export declare const MAX_CRASH_MESSAGE = 512;
30
+ export declare const MAX_CRASH_ERROR_CLASS = 128;
31
+ export declare const MAX_CRASH_STACK = 8000;
32
+ export declare const MAX_CRASH_STACK_FRAMES = 40;
33
+ export declare const MAX_CRASH_PAYLOAD_BYTES = 16384;
34
+ /** Same truthiness rule as the CLI's YAGNI_DISABLE_* family. */
35
+ export declare function crashReportsDisabled(env?: NodeJS.ProcessEnv): boolean;
36
+ export interface SanitizeCrashOptions {
37
+ env?: NodeJS.ProcessEnv;
38
+ repoRoot?: string;
39
+ }
40
+ /** Env values → [ENV:NAME], scrubSecrets patterns, ~-collapse, repo-relative, basename. */
41
+ export declare function sanitizeCrashText(text: string, opts?: SanitizeCrashOptions): string;
42
+ export interface SanitizedCrash {
43
+ errorClass: string;
44
+ message: string;
45
+ stack?: string;
46
+ }
47
+ /** Reads ONLY name/message/stack; custom error fields are never touched. */
48
+ export declare function sanitizeCrashError(err: unknown, opts?: SanitizeCrashOptions): SanitizedCrash;
49
+ export interface CrashReporterOpts {
50
+ baseUrl: string;
51
+ getToken: () => string | undefined;
52
+ fetchImpl?: typeof fetch;
53
+ env?: NodeJS.ProcessEnv;
54
+ timeoutMs?: number;
55
+ }
56
+ export type CrashReporter = (error: unknown, context?: string, repoRoot?: string) => Promise<void>;
57
+ /**
58
+ * Build the fail-soft reporter. The extension runs inside pi's process, so
59
+ * the client label follows the surface: `desktop` under the desktop shell
60
+ * (YAGNI_SURFACE=desktop), `cli` in the terminal. Version comes from
61
+ * `YAGNI_CODE_VERSION` (forwarded by the launcher; the bundled extension has
62
+ * no package.json on disk). Resolves on every outcome; never throws.
63
+ */
64
+ export declare function makeCrashReporter(opts: CrashReporterOpts): CrashReporter;
65
+ export type SpawnLike = (command: string, args: string[], options: {
66
+ detached: boolean;
67
+ stdio: "ignore";
68
+ env: Record<string, string | undefined>;
69
+ }) => {
70
+ unref: () => void;
71
+ };
72
+ export interface FatalCrashOpts extends CrashReporterOpts {
73
+ /** Spawn seam for tests (defaults to node:child_process spawn). */
74
+ spawnImpl?: SpawnLike;
75
+ }
76
+ /**
77
+ * Deliver a crash report from a process that is about to die: build the
78
+ * sanitized payload in-process (cheap, synchronous), then spawn a detached
79
+ * one-shot sender that outlives the crash. Never throws.
80
+ */
81
+ export declare function reportFatalCrash(error: unknown, opts: FatalCrashOpts, context?: string): void;
82
+ /**
83
+ * Observe (never alter) a fatal crash in pi's process. Uses
84
+ * `uncaughtExceptionMonitor`, which fires before the process dies without
85
+ * installing a handler that would change node's default crash behavior —
86
+ * YAGNI does not own pi's process, so crash semantics must stay untouched.
87
+ */
88
+ export declare function installUncaughtExceptionMonitor(opts: FatalCrashOpts, proc?: Pick<NodeJS.Process, "on">): void;
89
+ //# sourceMappingURL=crashReport.d.ts.map
@@ -0,0 +1,241 @@
1
+ /**
2
+ * Crash reporting for the pi extension: a sanitized, fire-and-forget POST to
3
+ * the YAGNI backend's /api/yagni-code/crash. No third-party telemetry SDK —
4
+ * crash reports are the only thing that phones home, they contain no code and
5
+ * no prompts, and `YAGNI_DISABLE_CRASH_REPORTS=1` turns them off.
6
+ *
7
+ * Two report paths use this module:
8
+ * - `uncaughtExceptionMonitor` (installed by index.ts): the MONITOR hook is
9
+ * chosen deliberately — unlike an `uncaughtException` listener it never
10
+ * changes crash semantics in pi's process (which YAGNI does not own); it
11
+ * only observes the crash that is already happening. This is also the
12
+ * "tool error that indicates a crash, not a user error" discriminator:
13
+ * a user-visible tool failure is caught and rendered by pi, while
14
+ * anything reaching the monitor was about to kill the session.
15
+ * - the /go pipeline's terminal catch (goCommand.ts), where a thrown error
16
+ * — not a verdict-shaped failure — ends the run.
17
+ *
18
+ * Everything is fail-soft: never throws, never retries, single short-timeout
19
+ * attempt, and reporting can never affect the user's session.
20
+ *
21
+ * The sanitizer (env-value redaction + path collapse + caps around the shared
22
+ * scrubSecrets patterns) is kept in sync with
23
+ * `yagni-code-cli/src/crashReport.ts`; the backend re-runs its own copy in
24
+ * `backend/src/yagniCode/crashReports.ts`. Spec:
25
+ * docs/superpowers/specs/2026-08-08-crash-reporting-design.md
26
+ */
27
+ import { spawn } from "node:child_process";
28
+ import { scrubSecrets } from "./pipeline/scrubSecrets.js";
29
+ import { isDesktopSurface } from "./surface.js";
30
+ const defaultSpawn = (command, args, options) => spawn(command, args, options);
31
+ export const CRASH_REPORT_DISABLE_ENV = "YAGNI_DISABLE_CRASH_REPORTS";
32
+ export const CRASH_REPORT_TIMEOUT_MS = 1_500;
33
+ export const MAX_CRASH_MESSAGE = 512;
34
+ export const MAX_CRASH_ERROR_CLASS = 128;
35
+ export const MAX_CRASH_STACK = 8_000;
36
+ export const MAX_CRASH_STACK_FRAMES = 40;
37
+ export const MAX_CRASH_PAYLOAD_BYTES = 16_384;
38
+ /** Same truthiness rule as the CLI's YAGNI_DISABLE_* family. */
39
+ export function crashReportsDisabled(env = process.env) {
40
+ const value = env[CRASH_REPORT_DISABLE_ENV];
41
+ return value !== undefined && value !== "" && value !== "0";
42
+ }
43
+ const HOME_DIR_RE = /(?:\/(?:Users|home)\/|[A-Za-z]:\\Users\\)[^\s/\\]+/g;
44
+ // Spaces deliberately allowed inside the token (real directories contain
45
+ // them); prose after a path may fold into the kept basename — over-redacts
46
+ // rather than under-redacts. Keep in sync with the CLI copy.
47
+ const PATH_TOKEN_RE = /(?<![\w.~/\\])(?:~\/|\/|[A-Za-z]:\\)[^\n():'",]+/g;
48
+ const MIN_ENV_VALUE_LENGTH = 8;
49
+ function isPathLikeValue(value) {
50
+ return value.startsWith("/") || value.startsWith("~") || /^[A-Za-z]:\\/.test(value);
51
+ }
52
+ function collapsePathToken(token) {
53
+ const nm = token.lastIndexOf("node_modules/");
54
+ if (nm >= 0)
55
+ return token.slice(nm);
56
+ const cut = Math.max(token.lastIndexOf("/"), token.lastIndexOf("\\"));
57
+ const base = cut >= 0 ? token.slice(cut + 1) : token;
58
+ return base.length > 0 ? base : token;
59
+ }
60
+ /** Env values → [ENV:NAME], scrubSecrets patterns, ~-collapse, repo-relative, basename. */
61
+ export function sanitizeCrashText(text, opts = {}) {
62
+ let out = text;
63
+ const env = opts.env ?? process.env;
64
+ const entries = Object.entries(env)
65
+ .filter((entry) => typeof entry[1] === "string" &&
66
+ entry[1].length >= MIN_ENV_VALUE_LENGTH &&
67
+ !isPathLikeValue(entry[1]))
68
+ .sort((a, b) => b[1].length - a[1].length);
69
+ for (const [name, value] of entries) {
70
+ if (out.includes(value))
71
+ out = out.split(value).join(`[ENV:${name}]`);
72
+ }
73
+ out = scrubSecrets(out);
74
+ out = out.replace(HOME_DIR_RE, "~");
75
+ if (opts.repoRoot) {
76
+ const root = opts.repoRoot.replace(HOME_DIR_RE, "~").replace(/\/+$/, "");
77
+ if (root.length > 1)
78
+ out = out.split(`${root}/`).join("");
79
+ }
80
+ out = out.replace(PATH_TOKEN_RE, collapsePathToken);
81
+ return out;
82
+ }
83
+ /** Reads ONLY name/message/stack; custom error fields are never touched. */
84
+ export function sanitizeCrashError(err, opts = {}) {
85
+ let errorClass = "Error";
86
+ let message;
87
+ let stack;
88
+ if (err instanceof Error) {
89
+ errorClass = err.name || "Error";
90
+ message = err.message;
91
+ stack = typeof err.stack === "string" ? err.stack : undefined;
92
+ }
93
+ else {
94
+ try {
95
+ message = String(err);
96
+ }
97
+ catch {
98
+ message = "unstringifiable thrown value";
99
+ }
100
+ }
101
+ const cappedStack = stack !== undefined
102
+ ? sanitizeCrashText(stack, opts)
103
+ .split("\n")
104
+ .slice(0, MAX_CRASH_STACK_FRAMES)
105
+ .join("\n")
106
+ .slice(0, MAX_CRASH_STACK)
107
+ : undefined;
108
+ return {
109
+ errorClass: sanitizeCrashText(errorClass, opts).slice(0, MAX_CRASH_ERROR_CLASS),
110
+ message: sanitizeCrashText(message, opts).slice(0, MAX_CRASH_MESSAGE),
111
+ ...(cappedStack !== undefined ? { stack: cappedStack } : {}),
112
+ };
113
+ }
114
+ /**
115
+ * Build the fail-soft reporter. The extension runs inside pi's process, so
116
+ * the client label follows the surface: `desktop` under the desktop shell
117
+ * (YAGNI_SURFACE=desktop), `cli` in the terminal. Version comes from
118
+ * `YAGNI_CODE_VERSION` (forwarded by the launcher; the bundled extension has
119
+ * no package.json on disk). Resolves on every outcome; never throws.
120
+ */
121
+ export function makeCrashReporter(opts) {
122
+ return async (error, context, repoRoot) => {
123
+ try {
124
+ const env = opts.env ?? process.env;
125
+ if (crashReportsDisabled(env))
126
+ return;
127
+ const token = opts.getToken();
128
+ if (!token)
129
+ return;
130
+ const sanitized = sanitizeCrashError(error, { env, repoRoot });
131
+ const payload = {
132
+ client: isDesktopSurface() ? "desktop" : "cli",
133
+ clientVersion: env.YAGNI_CODE_VERSION?.trim() || "unknown",
134
+ platform: `${process.platform} ${process.arch}`,
135
+ ...sanitized,
136
+ ...(context !== undefined ? { context } : {}),
137
+ timestamp: new Date().toISOString(),
138
+ };
139
+ if (JSON.stringify(payload).length > MAX_CRASH_PAYLOAD_BYTES) {
140
+ delete payload.stack;
141
+ }
142
+ const fetchImpl = opts.fetchImpl ?? fetch;
143
+ const controller = new AbortController();
144
+ const timer = setTimeout(() => controller.abort(), opts.timeoutMs ?? CRASH_REPORT_TIMEOUT_MS);
145
+ timer.unref?.();
146
+ try {
147
+ await fetchImpl(`${opts.baseUrl.replace(/\/$/, "")}/api/yagni-code/crash`, {
148
+ method: "POST",
149
+ headers: {
150
+ "content-type": "application/json",
151
+ authorization: `Bearer ${token}`,
152
+ },
153
+ body: JSON.stringify(payload),
154
+ signal: controller.signal,
155
+ });
156
+ }
157
+ finally {
158
+ clearTimeout(timer);
159
+ }
160
+ }
161
+ catch {
162
+ // fail-soft by contract
163
+ }
164
+ };
165
+ }
166
+ /**
167
+ * One-shot sender source for the detached delivery child. A fatal uncaught
168
+ * exception kills pi's process before any in-process fetch could connect, so
169
+ * the monitor path hands the (already sanitized) payload to a detached
170
+ * `node -e` child that survives the parent's death, POSTs once with a hard
171
+ * timeout, and exits. No retries, nothing written to disk. The payload, URL
172
+ * and token travel via the child's env — the same channel the launcher
173
+ * already uses to hand pi its YAGNI_TOKEN.
174
+ */
175
+ const DETACHED_SENDER_SRC = [
176
+ "const done = () => process.exit(0);",
177
+ "setTimeout(done, 5000).unref?.();",
178
+ "fetch(process.env.YAGNI_CRASH_URL, {",
179
+ " method: 'POST',",
180
+ " headers: {",
181
+ " 'content-type': 'application/json',",
182
+ " authorization: 'Bearer ' + process.env.YAGNI_CRASH_TOKEN,",
183
+ " },",
184
+ " body: process.env.YAGNI_CRASH_PAYLOAD,",
185
+ " signal: AbortSignal.timeout(4000),",
186
+ "}).catch(() => {}).finally(done);",
187
+ ].join("\n");
188
+ /**
189
+ * Deliver a crash report from a process that is about to die: build the
190
+ * sanitized payload in-process (cheap, synchronous), then spawn a detached
191
+ * one-shot sender that outlives the crash. Never throws.
192
+ */
193
+ export function reportFatalCrash(error, opts, context) {
194
+ try {
195
+ const env = opts.env ?? process.env;
196
+ if (crashReportsDisabled(env))
197
+ return;
198
+ const token = opts.getToken();
199
+ if (!token)
200
+ return;
201
+ const sanitized = sanitizeCrashError(error, { env });
202
+ const payload = {
203
+ client: isDesktopSurface() ? "desktop" : "cli",
204
+ clientVersion: env.YAGNI_CODE_VERSION?.trim() || "unknown",
205
+ platform: `${process.platform} ${process.arch}`,
206
+ ...sanitized,
207
+ ...(context !== undefined ? { context } : {}),
208
+ timestamp: new Date().toISOString(),
209
+ };
210
+ if (JSON.stringify(payload).length > MAX_CRASH_PAYLOAD_BYTES) {
211
+ delete payload.stack;
212
+ }
213
+ const spawnImpl = opts.spawnImpl ?? defaultSpawn;
214
+ const child = spawnImpl(process.execPath, ["-e", DETACHED_SENDER_SRC], {
215
+ detached: true,
216
+ stdio: "ignore",
217
+ env: {
218
+ // Minimal env: the sender needs nothing from the parent beyond these.
219
+ YAGNI_CRASH_URL: `${opts.baseUrl.replace(/\/$/, "")}/api/yagni-code/crash`,
220
+ YAGNI_CRASH_TOKEN: token,
221
+ YAGNI_CRASH_PAYLOAD: JSON.stringify(payload),
222
+ },
223
+ });
224
+ child.unref();
225
+ }
226
+ catch {
227
+ // a crash reporter must never add its own crash
228
+ }
229
+ }
230
+ /**
231
+ * Observe (never alter) a fatal crash in pi's process. Uses
232
+ * `uncaughtExceptionMonitor`, which fires before the process dies without
233
+ * installing a handler that would change node's default crash behavior —
234
+ * YAGNI does not own pi's process, so crash semantics must stay untouched.
235
+ */
236
+ export function installUncaughtExceptionMonitor(opts, proc = process) {
237
+ proc.on("uncaughtExceptionMonitor", (err) => {
238
+ reportFatalCrash(err, opts, "uncaught-exception");
239
+ });
240
+ }
241
+ //# sourceMappingURL=crashReport.js.map
@@ -1,5 +1,7 @@
1
1
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
+ import { type SpendResponse } from "./costHud.js";
2
3
  import { runInitPass as defaultRunInitPass } from "./initPass.js";
4
+ import { fetchMcpServers as defaultFetchMcpServers } from "./mcpTools.js";
3
5
  import { type FlushOutcome, type SpoolClientOpts } from "./spool.js";
4
6
  import { type TokenProvider } from "./tokenProvider.js";
5
7
  import { type ContextBrief, type ModelEntry } from "./config.js";
@@ -35,6 +37,12 @@ export interface RegisterYagniDeps {
35
37
  getToken: () => string | undefined;
36
38
  fetchImpl?: typeof fetch;
37
39
  }) => Promise<ContextBrief | null>;
40
+ /**
41
+ * Workspace MCP server list seam (YAG-446). The default hits
42
+ * `/api/yagni-code/mcp/servers` and is fail-soft: older backends and
43
+ * un-rescoped tokens yield `[]`, never a startup error.
44
+ */
45
+ fetchMcpServers?: typeof defaultFetchMcpServers;
38
46
  /**
39
47
  * The CLI init pass (Onramp Door B). Injectable so tests assert it fires on a
40
48
  * fresh-workspace first-run and is skipped otherwise, without a network or disk.
@@ -57,6 +65,35 @@ export interface RegisterYagniDeps {
57
65
  flushSpool?: (opts: SpoolClientOpts) => Promise<FlushOutcome>;
58
66
  env?: NodeJS.ProcessEnv;
59
67
  }
68
+ /**
69
+ * Build GET /api/yagni-code/spend's URL. Pure (no fetch), exported for tests.
70
+ *
71
+ * YAG-383: a `/go` run's dispatches bill under its OWN run id
72
+ * (`llm_usage.session_id` holds the run id, not the driver session id — see
73
+ * attributionHeaders in config.ts), so `sessionId=` alone misses every run
74
+ * this session launched. `runIds` (comma-separated) widens the same query to
75
+ * include them; empty is omitted entirely rather than sent as `runIds=`.
76
+ */
77
+ export declare function buildSpendUrl(baseUrl: string, sessionId: string, runIds: readonly string[]): string;
78
+ /**
79
+ * Build GET /api/yagni-code/spend's URL for ONE `/go` run's own spend
80
+ * (`?runId=`, the sibling of {@link buildSpendUrl}'s session-wide
81
+ * `?sessionId=&runIds=`). Pure (no fetch), exported for tests. The backend
82
+ * route treats `runId` and `sessionId` as aliases into the same lookup (see
83
+ * routes/yagniCode.ts's `/spend` handler), so this is just the more honest
84
+ * query param name for "this one run" rather than reusing `buildSpendUrl`
85
+ * with the run id awkwardly standing in for a session id.
86
+ */
87
+ export declare function buildRunSpendUrl(baseUrl: string, runId: string): string;
88
+ /**
89
+ * Validate + narrow a `GET /api/yagni-code/spend` response body before
90
+ * trusting it as a {@link SpendResponse}. A network response is untyped at
91
+ * runtime, so this is the ONE shared guard both the session-wide `/cost`
92
+ * fetch and the per-run `/go` fetch rely on (drift-risk fix: they used to
93
+ * each carry their own copy of this same check). Pure, exported for tests.
94
+ * Returns null on anything that doesn't look like the real shape.
95
+ */
96
+ export declare function parseSpendResponse(data: unknown): SpendResponse | null;
60
97
  export declare function registerYagni(pi: ExtensionAPI, deps?: RegisterYagniDeps): Promise<void>;
61
98
  export default function (pi: ExtensionAPI): Promise<void>;
62
99
  export { makeAskYagniTool } from "./askYagniTool.js";
@@ -73,11 +110,11 @@ export { makeSuggestNextWorkTool, defaultNextAction } from "./nextWorkTool.js";
73
110
  export type { MakeNextWorkToolOptions, DefaultNextAction, NextActionOption, } from "./nextWorkTool.js";
74
111
  export { recordDecision } from "./recordDecisionTool.js";
75
112
  export type { RecordDecisionParams } from "./recordDecisionTool.js";
76
- export { runInitPass, isFreshWorkspace, readRepoIntake, draftEngineering, summarizeDraft, FRESH_BRIEF_MIN_CHARS, } from "./initPass.js";
77
- export type { RunInitPassDeps, InitPassOutcome, RepoIntake, RepoIntakeFs, RepoAdr, EngineeringDraft, DraftTeam, } from "./initPass.js";
113
+ export { runInitPass, runTeamSetup, registerTeamSetupCommand, isFreshWorkspace, readRepoIntake, draftEngineering, summarizeDraft, FRESH_BRIEF_MIN_CHARS, } from "./initPass.js";
114
+ export type { RunInitPassDeps, InitPassOutcome, RunTeamSetupDeps, TeamSetupOutcome, RepoIntake, RepoIntakeFs, EngineeringDraft, DraftTeam, } from "./initPass.js";
78
115
  export { isInitDone, markInitDone, initDoneMarkerFile, _setInitDoneHomeForTest } from "./initDone.js";
79
- export { brandSystemPrompt, YAGNI_IDENTITY, BRAND_NAME } from "./branding.js";
80
- export { fetchCatalog, getToken, getWorkspaceId, resolveBaseUrl } from "./config.js";
116
+ export { brandSystemPrompt, YAGNI_IDENTITY, YAGNI_IDENTITY_DRIVER, BRAND_NAME } from "./branding.js";
117
+ export { attributionHeaders, isDriverCaller, fetchCatalog, getToken, getWorkspaceId, resolveBaseUrl, sanitizeCallerSegment, } from "./config.js";
81
118
  export type { FetchCatalogOptions, ModelEntry } from "./config.js";
82
119
  export { buildYagniProvider } from "./provider.js";
83
120
  export { registerGoCommand } from "./pipeline/goCommand.js";
@@ -113,4 +150,6 @@ export { makeTokenProvider, makeAuthedFetch, persistRotationToProfile, PROACTIVE
113
150
  export type { TokenProvider, TokenProviderDeps, ScheduleFn } from "./tokenProvider.js";
114
151
  export { appendToSpool, loadSpool, flushSpool, sendOrSpool, spoolFile, MAX_SPOOL_AGE_MS, _setSpoolHomeForTest, } from "./spool.js";
115
152
  export type { SpoolEntry, SpoolClientOpts, FlushOutcome, JudgmentWriteOutcome } from "./spool.js";
153
+ export { crashReportsDisabled, installUncaughtExceptionMonitor, makeCrashReporter, reportFatalCrash, sanitizeCrashError, sanitizeCrashText, } from "./crashReport.js";
154
+ export type { CrashReporter, CrashReporterOpts, FatalCrashOpts, SanitizedCrash } from "./crashReport.js";
116
155
  //# sourceMappingURL=index.d.ts.map