@schoolai/shipyard 3.7.0 → 3.8.0-rc.20260529.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.
- package/dist/{auth-SS7LV5XK.js → auth-EXHO3AG5.js} +4 -4
- package/dist/capability-detector-worker.js +142 -0
- package/dist/capability-detector-worker.js.map +1 -0
- package/dist/{chunk-DKMDBOFU.js → chunk-2CNIEBKO.js} +21 -11
- package/dist/chunk-2CNIEBKO.js.map +1 -0
- package/dist/chunk-422NIGWV.js +6963 -0
- package/dist/chunk-422NIGWV.js.map +1 -0
- package/dist/chunk-4T2OQAVL.js +51 -0
- package/dist/chunk-4T2OQAVL.js.map +1 -0
- package/dist/chunk-5ER6ZHA2.js +46 -0
- package/dist/chunk-5ER6ZHA2.js.map +1 -0
- package/dist/chunk-7LSEE26O.js +24227 -0
- package/dist/chunk-7LSEE26O.js.map +1 -0
- package/dist/{chunk-7AHRFPAL.js → chunk-7YOU7MBN.js} +183 -17
- package/dist/chunk-7YOU7MBN.js.map +1 -0
- package/dist/chunk-CMGJGK6R.js +382 -0
- package/dist/chunk-CMGJGK6R.js.map +1 -0
- package/dist/{chunk-VPMN47TL.js → chunk-CNR7O5YH.js} +1 -2
- package/dist/{chunk-2J3WSIAF.js → chunk-EF2DAODF.js} +18 -3
- package/dist/chunk-EF2DAODF.js.map +1 -0
- package/dist/chunk-HQ43PHOH.js +1203 -0
- package/dist/chunk-HQ43PHOH.js.map +1 -0
- package/dist/chunk-KITSAHTX.js +134 -0
- package/dist/chunk-KITSAHTX.js.map +1 -0
- package/dist/{chunk-LW2MS4T5.js → chunk-LMJFHKRD.js} +15 -12
- package/dist/chunk-LMJFHKRD.js.map +1 -0
- package/dist/{chunk-SNYEQHUK.js → chunk-NACJENDW.js} +14 -21
- package/dist/chunk-NACJENDW.js.map +1 -0
- package/dist/{chunk-IISLTKYY.js → chunk-TU63KZFW.js} +2 -2
- package/dist/chunk-TX6DK4PK.js +186 -0
- package/dist/chunk-TX6DK4PK.js.map +1 -0
- package/dist/chunk-UQVXWOPT.js +48 -0
- package/dist/chunk-UQVXWOPT.js.map +1 -0
- package/dist/{chunk-3MNPDCO5.js → chunk-WBB4XHLH.js} +139 -140
- package/dist/chunk-WBB4XHLH.js.map +1 -0
- package/dist/chunk-X3MULCV5.js +11 -0
- package/dist/chunk-X3MULCV5.js.map +1 -0
- package/dist/chunk-YZ3Z3ZYI.js +787 -0
- package/dist/chunk-YZ3Z3ZYI.js.map +1 -0
- package/dist/{chunk-2UN5AR7V.js → chunk-ZAOPND5G.js} +2 -2
- package/dist/chunk-ZFKJAYAN.js +542 -0
- package/dist/chunk-ZFKJAYAN.js.map +1 -0
- package/dist/cursor-hook-shim.js +316 -0
- package/dist/cursor-hook-shim.js.map +1 -0
- package/dist/cursor-runner.js +358 -0
- package/dist/cursor-runner.js.map +1 -0
- package/dist/electron-utility.js +111 -0
- package/dist/electron-utility.js.map +1 -0
- package/dist/git-pool-V73Q53NX.js +18 -0
- package/dist/{git-repo-VRT57DGC.js → git-repo-TN3VZXQV.js} +9 -6
- package/dist/index.js +12 -12
- package/dist/index.js.map +1 -1
- package/dist/{logger-GQCSLSZH.js → logger-QHPTO22N.js} +4 -4
- package/dist/login-Q7SZI7JJ.js +20 -0
- package/dist/{logout-VUNCW5B2.js → logout-O4AVMO5S.js} +6 -6
- package/dist/mcp-servers-F64M5T4I.js +24 -0
- package/dist/{roi-Y3MX5UW4.js → roi-EYDLPOCS.js} +5 -5
- package/dist/rss-worker.js +159 -0
- package/dist/rss-worker.js.map +1 -0
- package/dist/{serve-O53FNK64.js → serve-GMRVBGVV.js} +89872 -103000
- package/dist/{serve-O53FNK64.js.map → serve-GMRVBGVV.js.map} +1 -1
- package/dist/skills-ZHEPSBHW.js +11 -0
- package/dist/{start-IDFDHRD6.js → start-4UCUZPIV.js} +229 -27
- package/dist/start-4UCUZPIV.js.map +1 -0
- package/dist/vault-crypto-BKDOA65F.js +13 -0
- package/dist/vault-crypto-BKDOA65F.js.map +1 -0
- package/dist/worker.js +6 -3
- package/dist/worker.js.map +1 -1
- package/package.json +17 -10
- package/dist/chunk-2J3WSIAF.js.map +0 -1
- package/dist/chunk-3MNPDCO5.js.map +0 -1
- package/dist/chunk-66OBOZ3X.js +0 -79
- package/dist/chunk-66OBOZ3X.js.map +0 -1
- package/dist/chunk-7AHRFPAL.js.map +0 -1
- package/dist/chunk-DKMDBOFU.js.map +0 -1
- package/dist/chunk-L2WQMPWS.js +0 -666
- package/dist/chunk-L2WQMPWS.js.map +0 -1
- package/dist/chunk-LW2MS4T5.js.map +0 -1
- package/dist/chunk-PI77CUEP.js +0 -49
- package/dist/chunk-PI77CUEP.js.map +0 -1
- package/dist/chunk-RXI4637N.js +0 -395
- package/dist/chunk-RXI4637N.js.map +0 -1
- package/dist/chunk-SNYEQHUK.js.map +0 -1
- package/dist/chunk-VBPHGPBR.js +0 -126
- package/dist/chunk-VBPHGPBR.js.map +0 -1
- package/dist/index.d.ts +0 -2
- package/dist/login-L4BBPUYO.js +0 -20
- package/dist/mcp-servers-MXS5VAWI.js +0 -18
- package/dist/shell-V36EX2IJ.js +0 -27
- package/dist/skills-GPGRNV4R.js +0 -9
- package/dist/start-IDFDHRD6.js.map +0 -1
- package/dist/worker.d.ts +0 -49
- /package/dist/{auth-SS7LV5XK.js.map → auth-EXHO3AG5.js.map} +0 -0
- /package/dist/{chunk-VPMN47TL.js.map → chunk-CNR7O5YH.js.map} +0 -0
- /package/dist/{chunk-IISLTKYY.js.map → chunk-TU63KZFW.js.map} +0 -0
- /package/dist/{chunk-2UN5AR7V.js.map → chunk-ZAOPND5G.js.map} +0 -0
- /package/dist/{git-repo-VRT57DGC.js.map → git-pool-V73Q53NX.js.map} +0 -0
- /package/dist/{logger-GQCSLSZH.js.map → git-repo-TN3VZXQV.js.map} +0 -0
- /package/dist/{login-L4BBPUYO.js.map → logger-QHPTO22N.js.map} +0 -0
- /package/dist/{mcp-servers-MXS5VAWI.js.map → login-Q7SZI7JJ.js.map} +0 -0
- /package/dist/{logout-VUNCW5B2.js.map → logout-O4AVMO5S.js.map} +0 -0
- /package/dist/{shell-V36EX2IJ.js.map → mcp-servers-F64M5T4I.js.map} +0 -0
- /package/dist/{roi-Y3MX5UW4.js.map → roi-EYDLPOCS.js.map} +0 -0
- /package/dist/{skills-GPGRNV4R.js.map → skills-ZHEPSBHW.js.map} +0 -0
|
@@ -5,9 +5,9 @@ import {
|
|
|
5
5
|
loadAuthToken,
|
|
6
6
|
readConfig,
|
|
7
7
|
writeConfig
|
|
8
|
-
} from "./chunk-
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-
|
|
8
|
+
} from "./chunk-EF2DAODF.js";
|
|
9
|
+
import "./chunk-KITSAHTX.js";
|
|
10
|
+
import "./chunk-CNR7O5YH.js";
|
|
11
11
|
import "./chunk-2H7UOFLK.js";
|
|
12
12
|
export {
|
|
13
13
|
deleteConfig,
|
|
@@ -16,4 +16,4 @@ export {
|
|
|
16
16
|
readConfig,
|
|
17
17
|
writeConfig
|
|
18
18
|
};
|
|
19
|
-
//# sourceMappingURL=auth-
|
|
19
|
+
//# sourceMappingURL=auth-EXHO3AG5.js.map
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
MCPTokenStore,
|
|
4
|
+
detectCapabilities,
|
|
5
|
+
refreshMcpServers,
|
|
6
|
+
registerBuiltInProfiles
|
|
7
|
+
} from "./chunk-422NIGWV.js";
|
|
8
|
+
import {
|
|
9
|
+
getRepoMetadata
|
|
10
|
+
} from "./chunk-YZ3Z3ZYI.js";
|
|
11
|
+
import "./chunk-4T2OQAVL.js";
|
|
12
|
+
import "./chunk-HQ43PHOH.js";
|
|
13
|
+
import "./chunk-CMGJGK6R.js";
|
|
14
|
+
import "./chunk-ZFKJAYAN.js";
|
|
15
|
+
import "./chunk-7LSEE26O.js";
|
|
16
|
+
import "./chunk-7YOU7MBN.js";
|
|
17
|
+
import "./chunk-EHQITHQX.js";
|
|
18
|
+
import "./chunk-X3MULCV5.js";
|
|
19
|
+
import {
|
|
20
|
+
flushLogger,
|
|
21
|
+
logger
|
|
22
|
+
} from "./chunk-ZAOPND5G.js";
|
|
23
|
+
import "./chunk-KITSAHTX.js";
|
|
24
|
+
import "./chunk-CNR7O5YH.js";
|
|
25
|
+
import "./chunk-2H7UOFLK.js";
|
|
26
|
+
|
|
27
|
+
// src/shared/capabilities/detector-runner/worker.ts
|
|
28
|
+
import { parentPort } from "worker_threads";
|
|
29
|
+
|
|
30
|
+
// src/services/cwd-capability-refresh.ts
|
|
31
|
+
async function buildCwdScopedPatch(deps) {
|
|
32
|
+
const { newCwd, environments, preferredAuth, tokenStore, lastKnownMcpServers } = deps;
|
|
33
|
+
const alreadyKnown = environments.some((e) => e.path === newCwd);
|
|
34
|
+
const meta = alreadyKnown ? null : await getRepoMetadata(newCwd);
|
|
35
|
+
const nextEnvironments = meta ? [...environments, meta] : environments;
|
|
36
|
+
const mcpPatch = await refreshMcpServers({
|
|
37
|
+
environments: nextEnvironments,
|
|
38
|
+
tokenStore,
|
|
39
|
+
preferredAuth,
|
|
40
|
+
lastKnown: lastKnownMcpServers,
|
|
41
|
+
/**
|
|
42
|
+
* Incremental scope: only the new cwd's `.claude/settings.json` (and
|
|
43
|
+
* sibling project-tier configs) need a fresh read. The other 180+ env
|
|
44
|
+
* scans were the dominant cost (4-10s combined across the worktree-
|
|
45
|
+
* creation flow's 4 back-to-back scoped refreshes); now they reuse
|
|
46
|
+
* `lastKnownMcpServers` for project entries from unchanged envs.
|
|
47
|
+
*/
|
|
48
|
+
changedCwd: newCwd
|
|
49
|
+
});
|
|
50
|
+
return {
|
|
51
|
+
...meta ? { environments: nextEnvironments } : {},
|
|
52
|
+
...mcpPatch
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// src/shared/capabilities/detector-runner/worker.ts
|
|
57
|
+
function tokenStoreFromHome(home) {
|
|
58
|
+
return home ? new MCPTokenStore(home) : void 0;
|
|
59
|
+
}
|
|
60
|
+
function ensureCapabilityDetectorWorkerProfilesRegistered() {
|
|
61
|
+
registerBuiltInProfiles();
|
|
62
|
+
}
|
|
63
|
+
async function runRequest(request, abortSignal) {
|
|
64
|
+
ensureCapabilityDetectorWorkerProfilesRegistered();
|
|
65
|
+
switch (request.kind) {
|
|
66
|
+
case "detectFull":
|
|
67
|
+
return detectCapabilities(
|
|
68
|
+
tokenStoreFromHome(request.tokenStoreHome),
|
|
69
|
+
request.methodHint,
|
|
70
|
+
request.lastKnownAuth,
|
|
71
|
+
request.lastKnownAgents,
|
|
72
|
+
request.lastKnownCapabilities,
|
|
73
|
+
request.codexMethodHint,
|
|
74
|
+
request.lastKnownCodexAuth,
|
|
75
|
+
abortSignal
|
|
76
|
+
);
|
|
77
|
+
case "refreshMcpServers":
|
|
78
|
+
return refreshMcpServers({
|
|
79
|
+
environments: request.environments,
|
|
80
|
+
tokenStore: tokenStoreFromHome(request.tokenStoreHome),
|
|
81
|
+
preferredAuth: request.preferredAuth,
|
|
82
|
+
lastKnown: request.lastKnown
|
|
83
|
+
});
|
|
84
|
+
case "buildCwdScopedPatch":
|
|
85
|
+
return buildCwdScopedPatch({
|
|
86
|
+
newCwd: request.newCwd,
|
|
87
|
+
environments: request.environments,
|
|
88
|
+
preferredAuth: request.preferredAuth,
|
|
89
|
+
tokenStore: tokenStoreFromHome(request.tokenStoreHome),
|
|
90
|
+
lastKnownMcpServers: request.lastKnownMcpServers
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
async function handleCapabilityDetectorMessage(request, port, flush = flushLogger, abortSignal = new AbortController().signal) {
|
|
95
|
+
const requestId = request.requestId ?? "";
|
|
96
|
+
try {
|
|
97
|
+
const data = await runRequest(request, abortSignal);
|
|
98
|
+
await flush();
|
|
99
|
+
port.postMessage({ requestId, ok: true, data });
|
|
100
|
+
} catch (err) {
|
|
101
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
102
|
+
logger.warn({
|
|
103
|
+
event: "capability_detector_worker_request_failed",
|
|
104
|
+
kind: request.kind,
|
|
105
|
+
error
|
|
106
|
+
});
|
|
107
|
+
await flush();
|
|
108
|
+
port.postMessage({ requestId, ok: false, error });
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function handleShutdownSignal(requestAbortControllers, exit = process.exit) {
|
|
112
|
+
for (const ctrl of requestAbortControllers) ctrl.abort();
|
|
113
|
+
requestAbortControllers.clear();
|
|
114
|
+
exit(0);
|
|
115
|
+
}
|
|
116
|
+
if (parentPort !== null) {
|
|
117
|
+
const port = parentPort;
|
|
118
|
+
const requestAbortControllers = /* @__PURE__ */ new Set();
|
|
119
|
+
port.on("close", () => {
|
|
120
|
+
for (const ctrl of requestAbortControllers) ctrl.abort();
|
|
121
|
+
requestAbortControllers.clear();
|
|
122
|
+
});
|
|
123
|
+
port.on("message", (request) => {
|
|
124
|
+
if (request.kind === "shutdown") {
|
|
125
|
+
handleShutdownSignal(requestAbortControllers);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const controller = new AbortController();
|
|
129
|
+
requestAbortControllers.add(controller);
|
|
130
|
+
void handleCapabilityDetectorMessage(request, port, flushLogger, controller.signal).finally(
|
|
131
|
+
() => {
|
|
132
|
+
requestAbortControllers.delete(controller);
|
|
133
|
+
}
|
|
134
|
+
);
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
export {
|
|
138
|
+
ensureCapabilityDetectorWorkerProfilesRegistered,
|
|
139
|
+
handleCapabilityDetectorMessage,
|
|
140
|
+
handleShutdownSignal
|
|
141
|
+
};
|
|
142
|
+
//# sourceMappingURL=capability-detector-worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shared/capabilities/detector-runner/worker.ts","../src/services/cwd-capability-refresh.ts"],"sourcesContent":["import { parentPort } from 'node:worker_threads';\nimport type { MachineCapabilities } from '@shipyard/session';\nimport { buildCwdScopedPatch } from '../../../services/cwd-capability-refresh.js';\nimport { registerBuiltInProfiles } from '../../../services/session/profiles/profile-registry.js';\nimport { flushLogger, logger } from '../../logger.js';\nimport { MCPTokenStore } from '../../mcp/token-store.js';\nimport { detectCapabilities } from '../index.js';\nimport { refreshMcpServers, type ScopedCapabilitiesPatch } from '../refresh-helpers.js';\nimport type {\n CapabilityDetectorReply,\n CapabilityDetectorRequest,\n CapabilityDetectorWorkRequest,\n} from './runner.js';\n\nfunction tokenStoreFromHome(home: string | undefined): MCPTokenStore | undefined {\n return home ? new MCPTokenStore(home) : undefined;\n}\n\nexport function ensureCapabilityDetectorWorkerProfilesRegistered(): void {\n /**\n * Worker threads get a fresh module graph, so the main daemon's\n * registerBuiltInProfiles() call does not populate this process singleton.\n */\n registerBuiltInProfiles();\n}\n\nasync function runRequest(\n request: CapabilityDetectorWorkRequest,\n abortSignal: AbortSignal\n): Promise<MachineCapabilities | ScopedCapabilitiesPatch> {\n ensureCapabilityDetectorWorkerProfilesRegistered();\n switch (request.kind) {\n case 'detectFull':\n return detectCapabilities(\n tokenStoreFromHome(request.tokenStoreHome),\n request.methodHint,\n request.lastKnownAuth,\n request.lastKnownAgents,\n request.lastKnownCapabilities,\n request.codexMethodHint,\n request.lastKnownCodexAuth,\n abortSignal\n );\n case 'refreshMcpServers':\n return refreshMcpServers({\n environments: request.environments,\n tokenStore: tokenStoreFromHome(request.tokenStoreHome),\n preferredAuth: request.preferredAuth,\n lastKnown: request.lastKnown,\n });\n case 'buildCwdScopedPatch':\n return buildCwdScopedPatch({\n newCwd: request.newCwd,\n environments: request.environments,\n preferredAuth: request.preferredAuth,\n tokenStore: tokenStoreFromHome(request.tokenStoreHome),\n lastKnownMcpServers: request.lastKnownMcpServers,\n });\n }\n}\n\ninterface WorkerPort {\n postMessage: (reply: CapabilityDetectorReply) => void;\n}\n\n/**\n * Handle one incoming request message. Exported for testing — the flush\n * ordering contract (flushLogger before postMessage) is verified there.\n *\n * Root cause context: runner.ts calls worker.terminate() shortly after\n * receiving the reply, which can kill pino's transport worker before it\n * drains — dropping the bootstrap_phase_end log. Flushing before postMessage\n * ensures buffered log entries reach disk before the runner tears the thread.\n *\n * Accepts an `abortSignal` so the runtime caller can wire it to the parent\n * port's `'close'` event; tests pass an unused fresh AbortController.\n */\nexport async function handleCapabilityDetectorMessage(\n request: CapabilityDetectorWorkRequest,\n port: WorkerPort,\n flush: () => Promise<void> = flushLogger,\n abortSignal: AbortSignal = new AbortController().signal\n): Promise<void> {\n const requestId = request.requestId ?? '';\n try {\n const data = await runRequest(request, abortSignal);\n await flush();\n port.postMessage({ requestId, ok: true, data } satisfies CapabilityDetectorReply);\n } catch (err: unknown) {\n const error = err instanceof Error ? err.message : String(err);\n logger.warn({\n event: 'capability_detector_worker_request_failed',\n kind: request.kind,\n error,\n });\n await flush();\n port.postMessage({ requestId, ok: false, error } satisfies CapabilityDetectorReply);\n }\n}\n\n/**\n * Handle a 'shutdown' signal from the runner. Aborts all in-flight requests\n * and exits the worker process cleanly, avoiding the c-ares destructor SIGTRAP\n * that fires when worker.terminate() abruptly tears down the V8 isolate while\n * DNS queries are still pending.\n *\n * Exported for testing — callers inject the abort controller set and the exit\n * function so neither I/O side-effect is required in unit tests.\n */\nexport function handleShutdownSignal(\n requestAbortControllers: Set<AbortController>,\n exit: (code: number) => void = process.exit\n): void {\n for (const ctrl of requestAbortControllers) ctrl.abort();\n requestAbortControllers.clear();\n exit(0);\n}\n\nif (parentPort !== null) {\n const port = parentPort;\n /**\n * Outer worker timeout terminates this thread without warning. The\n * port 'close' event is our only signal; abort all in-flight phases so\n * each stuck `bootstrapPhase` emits `outcome:'worker_killed'` before the\n * thread dies. Without it, the log shows `_start` but never `_end` for\n * the stuck phase.\n */\n const requestAbortControllers = new Set<AbortController>();\n port.on('close', () => {\n for (const ctrl of requestAbortControllers) ctrl.abort();\n requestAbortControllers.clear();\n });\n port.on('message', (request: CapabilityDetectorRequest) => {\n if (request.kind === 'shutdown') {\n handleShutdownSignal(requestAbortControllers);\n return;\n }\n const controller = new AbortController();\n requestAbortControllers.add(controller);\n void handleCapabilityDetectorMessage(request, port, flushLogger, controller.signal).finally(\n () => {\n requestAbortControllers.delete(controller);\n }\n );\n });\n}\n","import type { AnthropicAuthMethod } from '@shipyard/loro-schema';\nimport type { GitRepoInfo, MCPServerInfo } from '@shipyard/session';\nimport { getRepoMetadata } from '../shared/capabilities/git-repo.js';\nimport {\n refreshMcpServers,\n type ScopedCapabilitiesPatch,\n} from '../shared/capabilities/refresh-helpers.js';\nimport type { MCPTokenStore } from '../shared/mcp/token-store.js';\n\n/**\n * Pure helper: build the scoped capability patch for a cwd change.\n *\n * Only the cwd-dependent slices are populated — `environments` (so the new\n * cwd appears in the broadcast snapshot if it isn't already there) and\n * `mcpServers` (which scan project-level `.claude/settings.json` in each\n * environment). All other capability slices refresh via the FSEvents-driven\n * capability-watcher and the safety-net backstop tick — re-running them on\n * every task switch wasted ~25min CPU per 10.8h on the 24h log window and\n * accounted for 70% of event-loop stalls (P50 696ms, P99 15.6s).\n */\nexport async function buildCwdScopedPatch(deps: {\n newCwd: string;\n environments: GitRepoInfo[];\n preferredAuth: AnthropicAuthMethod | null | undefined;\n tokenStore: MCPTokenStore | undefined;\n lastKnownMcpServers: MCPServerInfo[] | undefined;\n}): Promise<ScopedCapabilitiesPatch> {\n const { newCwd, environments, preferredAuth, tokenStore, lastKnownMcpServers } = deps;\n const alreadyKnown = environments.some((e) => e.path === newCwd);\n const meta = alreadyKnown ? null : await getRepoMetadata(newCwd);\n const nextEnvironments = meta ? [...environments, meta] : environments;\n const mcpPatch = await refreshMcpServers({\n environments: nextEnvironments,\n tokenStore,\n preferredAuth,\n lastKnown: lastKnownMcpServers,\n /**\n * Incremental scope: only the new cwd's `.claude/settings.json` (and\n * sibling project-tier configs) need a fresh read. The other 180+ env\n * scans were the dominant cost (4-10s combined across the worktree-\n * creation flow's 4 back-to-back scoped refreshes); now they reuse\n * `lastKnownMcpServers` for project entries from unchanged envs.\n */\n changedCwd: newCwd,\n });\n return {\n ...(meta ? { environments: nextEnvironments } : {}),\n ...mcpPatch,\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -16,7 +16,8 @@ var TaskStartedEventSchema = EventBase.extend({
|
|
|
16
16
|
kind: external_exports.literal("task_started"),
|
|
17
17
|
activeTaskCount: external_exports.number().int().nonnegative(),
|
|
18
18
|
taskType: external_exports.string().max(50).optional(),
|
|
19
|
-
mode: external_exports.string().max(50)
|
|
19
|
+
mode: external_exports.string().max(50),
|
|
20
|
+
runtimeId: external_exports.string().min(1).default("claude-code")
|
|
20
21
|
});
|
|
21
22
|
var TaskEndedEventSchema = EventBase.extend({
|
|
22
23
|
kind: external_exports.literal("task_ended"),
|
|
@@ -24,7 +25,8 @@ var TaskEndedEventSchema = EventBase.extend({
|
|
|
24
25
|
totalCostUsd: external_exports.number().nonnegative(),
|
|
25
26
|
totalOutputTokens: external_exports.number().int().nonnegative(),
|
|
26
27
|
turnCount: external_exports.number().int().nonnegative(),
|
|
27
|
-
durationMs: external_exports.number().int().nonnegative()
|
|
28
|
+
durationMs: external_exports.number().int().nonnegative(),
|
|
29
|
+
runtimeId: external_exports.string().min(1).default("claude-code")
|
|
28
30
|
});
|
|
29
31
|
var AttributionTypeSchema = external_exports.enum(["originated", "amended", "extended"]);
|
|
30
32
|
var CommitAttributedEventSchema = EventBase.extend({
|
|
@@ -36,13 +38,15 @@ var CommitAttributedEventSchema = EventBase.extend({
|
|
|
36
38
|
tokens: external_exports.number().int().nonnegative(),
|
|
37
39
|
costUsd: external_exports.number().nonnegative(),
|
|
38
40
|
turnCount: external_exports.number().int().nonnegative(),
|
|
39
|
-
attributionType: AttributionTypeSchema
|
|
41
|
+
attributionType: AttributionTypeSchema,
|
|
42
|
+
runtimeId: external_exports.string().min(1).default("claude-code")
|
|
40
43
|
});
|
|
41
44
|
var PrAttributedEventSchema = EventBase.extend({
|
|
42
45
|
kind: external_exports.literal("pr_attributed"),
|
|
43
46
|
prUrl: external_exports.string().url(),
|
|
44
47
|
prNumber: external_exports.number().int().positive(),
|
|
45
|
-
repo: external_exports.string().min(1)
|
|
48
|
+
repo: external_exports.string().min(1),
|
|
49
|
+
runtimeId: external_exports.string().min(1).default("claude-code")
|
|
46
50
|
});
|
|
47
51
|
var MergeMethodSchema = external_exports.enum(["github_native", "graphite_queue"]);
|
|
48
52
|
var PrMergedEventSchema = EventBase.extend({
|
|
@@ -53,7 +57,8 @@ var PrMergedEventSchema = EventBase.extend({
|
|
|
53
57
|
/** Null for Graphite merge queue — Graphite closes PRs as 'closed' rather than 'merged' and the mergeCommitSha is not exposed by the GitHub API for those. Null still means "this task's work landed in trunk", discoverable via the Shipyard-Task-Id trailer grep. */
|
|
54
58
|
mergeCommitSha: external_exports.string().nullable(),
|
|
55
59
|
mergeMethod: MergeMethodSchema,
|
|
56
|
-
mergedAt: external_exports.number().int().positive()
|
|
60
|
+
mergedAt: external_exports.number().int().positive(),
|
|
61
|
+
runtimeId: external_exports.string().min(1).default("claude-code")
|
|
57
62
|
});
|
|
58
63
|
var RoiEventSchema = external_exports.discriminatedUnion("kind", [
|
|
59
64
|
TaskStartedEventSchema,
|
|
@@ -81,7 +86,8 @@ function emitCommitAttributed(collector, input) {
|
|
|
81
86
|
tokens: input.tokens,
|
|
82
87
|
costUsd: input.costUsd,
|
|
83
88
|
turnCount: input.turnCount,
|
|
84
|
-
attributionType: input.attributionType
|
|
89
|
+
attributionType: input.attributionType,
|
|
90
|
+
runtimeId: input.runtimeId
|
|
85
91
|
};
|
|
86
92
|
const parsed = CommitAttributedEventSchema.safeParse(candidate);
|
|
87
93
|
if (!parsed.success) return;
|
|
@@ -98,7 +104,8 @@ function emitPrAttributed(collector, input) {
|
|
|
98
104
|
timestamp: input.timestamp ?? Date.now(),
|
|
99
105
|
prUrl: input.prUrl,
|
|
100
106
|
prNumber: input.prNumber,
|
|
101
|
-
repo: input.repo
|
|
107
|
+
repo: input.repo,
|
|
108
|
+
...input.runtimeId !== void 0 ? { runtimeId: input.runtimeId } : {}
|
|
102
109
|
};
|
|
103
110
|
const parsed = PrAttributedEventSchema.safeParse(candidate);
|
|
104
111
|
if (!parsed.success) return;
|
|
@@ -118,7 +125,8 @@ function emitPrMerged(collector, input) {
|
|
|
118
125
|
repo: input.repo,
|
|
119
126
|
mergeCommitSha: input.mergeCommitSha,
|
|
120
127
|
mergeMethod: input.mergeMethod,
|
|
121
|
-
mergedAt: input.mergedAt
|
|
128
|
+
mergedAt: input.mergedAt,
|
|
129
|
+
...input.runtimeId !== void 0 ? { runtimeId: input.runtimeId } : {}
|
|
122
130
|
};
|
|
123
131
|
const parsed = PrMergedEventSchema.safeParse(candidate);
|
|
124
132
|
if (!parsed.success) return;
|
|
@@ -137,7 +145,8 @@ function emitTaskEnded(collector, input) {
|
|
|
137
145
|
totalCostUsd: input.totalCostUsd,
|
|
138
146
|
totalOutputTokens: input.totalOutputTokens,
|
|
139
147
|
turnCount: input.turnCount,
|
|
140
|
-
durationMs: input.durationMs
|
|
148
|
+
durationMs: input.durationMs,
|
|
149
|
+
runtimeId: input.runtimeId
|
|
141
150
|
};
|
|
142
151
|
const parsed = TaskEndedEventSchema.safeParse(candidate);
|
|
143
152
|
if (!parsed.success) return;
|
|
@@ -154,7 +163,8 @@ function emitTaskStarted(collector, input) {
|
|
|
154
163
|
timestamp: input.timestamp ?? Date.now(),
|
|
155
164
|
activeTaskCount: input.activeTaskCount,
|
|
156
165
|
mode: input.mode,
|
|
157
|
-
taskType: input.taskType
|
|
166
|
+
taskType: input.taskType,
|
|
167
|
+
runtimeId: input.runtimeId
|
|
158
168
|
};
|
|
159
169
|
const parsed = TaskStartedEventSchema.safeParse(candidate);
|
|
160
170
|
if (!parsed.success) return;
|
|
@@ -317,4 +327,4 @@ export {
|
|
|
317
327
|
hasShipyardTrailer,
|
|
318
328
|
appendTrailerToMessage
|
|
319
329
|
};
|
|
320
|
-
//# sourceMappingURL=chunk-
|
|
330
|
+
//# sourceMappingURL=chunk-2CNIEBKO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../packages/roi-aggregator/src/schemas/events.ts","../../../packages/roi-aggregator/src/emit/commit-attributed.ts","../../../packages/roi-aggregator/src/emit/pr-attributed.ts","../../../packages/roi-aggregator/src/emit/pr-merged.ts","../../../packages/roi-aggregator/src/emit/task-ended.ts","../../../packages/roi-aggregator/src/emit/task-started.ts","../../../packages/roi-aggregator/src/schemas/report.ts","../../../packages/roi-aggregator/src/schemas/trailers.ts"],"sourcesContent":["import { z } from 'zod';\n\nexport const ROI_EVENT_TYPE = 'shipyard.roi' as const;\n\nexport const ROI_EVENT_SCHEMA_VERSION = 2 as const;\n\nconst EventBase = z.object({\n version: z.literal(ROI_EVENT_SCHEMA_VERSION),\n taskId: z.string().min(1),\n userId: z.string().min(1),\n timestamp: z.number().int().positive(),\n});\n\nexport const TaskStartedEventSchema = EventBase.extend({\n kind: z.literal('task_started'),\n activeTaskCount: z.number().int().nonnegative(),\n taskType: z.string().max(50).optional(),\n mode: z.string().max(50),\n runtimeId: z.string().min(1).default('claude-code'),\n});\nexport type TaskStartedEvent = z.infer<typeof TaskStartedEventSchema>;\n\nexport const TaskEndedEventSchema = EventBase.extend({\n kind: z.literal('task_ended'),\n finalStatus: z.enum(['completed', 'canceled', 'input_required']),\n totalCostUsd: z.number().nonnegative(),\n totalOutputTokens: z.number().int().nonnegative(),\n turnCount: z.number().int().nonnegative(),\n durationMs: z.number().int().nonnegative(),\n runtimeId: z.string().min(1).default('claude-code'),\n});\nexport type TaskEndedEvent = z.infer<typeof TaskEndedEventSchema>;\n\nexport const AttributionTypeSchema = z.enum(['originated', 'amended', 'extended']);\nexport type AttributionType = z.infer<typeof AttributionTypeSchema>;\n\nexport const CommitAttributedEventSchema = EventBase.extend({\n kind: z.literal('commit_attributed'),\n commitSha: z.string().regex(/^[0-9a-f]{7,40}$/, 'expected hex SHA'),\n repo: z.string().min(1),\n branch: z.string().min(1),\n model: z.string().min(1),\n tokens: z.number().int().nonnegative(),\n costUsd: z.number().nonnegative(),\n turnCount: z.number().int().nonnegative(),\n attributionType: AttributionTypeSchema,\n runtimeId: z.string().min(1).default('claude-code'),\n});\nexport type CommitAttributedEvent = z.infer<typeof CommitAttributedEventSchema>;\n\nexport const PrAttributedEventSchema = EventBase.extend({\n kind: z.literal('pr_attributed'),\n prUrl: z.string().url(),\n prNumber: z.number().int().positive(),\n repo: z.string().min(1),\n runtimeId: z.string().min(1).default('claude-code'),\n});\nexport type PrAttributedEvent = z.infer<typeof PrAttributedEventSchema>;\n\nexport const MergeMethodSchema = z.enum(['github_native', 'graphite_queue']);\nexport type MergeMethod = z.infer<typeof MergeMethodSchema>;\n\nexport const PrMergedEventSchema = EventBase.extend({\n kind: z.literal('pr_merged'),\n prUrl: z.string().url(),\n prNumber: z.number().int().positive(),\n repo: z.string().min(1),\n /** Null for Graphite merge queue — Graphite closes PRs as 'closed' rather than 'merged' and the mergeCommitSha is not exposed by the GitHub API for those. Null still means \"this task's work landed in trunk\", discoverable via the Shipyard-Task-Id trailer grep. */\n mergeCommitSha: z.string().nullable(),\n mergeMethod: MergeMethodSchema,\n mergedAt: z.number().int().positive(),\n runtimeId: z.string().min(1).default('claude-code'),\n});\nexport type PrMergedEvent = z.infer<typeof PrMergedEventSchema>;\n\nexport const RoiEventSchema = z.discriminatedUnion('kind', [\n TaskStartedEventSchema,\n TaskEndedEventSchema,\n CommitAttributedEventSchema,\n PrAttributedEventSchema,\n PrMergedEventSchema,\n]);\nexport type RoiEvent = z.infer<typeof RoiEventSchema>;\n\nexport type RoiEventKind = RoiEvent['kind'];\n\nexport function isRoiEvent(value: unknown): value is RoiEvent {\n return RoiEventSchema.safeParse(value).success;\n}\n\nexport function assertNeverEvent(event: never): never {\n throw new Error(`unhandled ROI event kind: ${JSON.stringify(event)}`);\n}\n","import type { AttributionType } from '../schemas/events';\nimport {\n CommitAttributedEventSchema,\n ROI_EVENT_SCHEMA_VERSION,\n ROI_EVENT_TYPE,\n} from '../schemas/events';\nimport type { MetricsCapture } from './types';\n\nexport interface CommitAttributedInput {\n taskId: string;\n userId: string;\n commitSha: string;\n repo: string;\n branch: string;\n model: string;\n tokens: number;\n costUsd: number;\n turnCount: number;\n attributionType: AttributionType;\n runtimeId: string;\n timestamp?: number;\n}\n\nexport function emitCommitAttributed(\n collector: MetricsCapture,\n input: CommitAttributedInput\n): void {\n const candidate = {\n version: ROI_EVENT_SCHEMA_VERSION,\n kind: 'commit_attributed' as const,\n taskId: input.taskId,\n userId: input.userId,\n timestamp: input.timestamp ?? Date.now(),\n commitSha: input.commitSha,\n repo: input.repo,\n branch: input.branch,\n model: input.model,\n tokens: input.tokens,\n costUsd: input.costUsd,\n turnCount: input.turnCount,\n attributionType: input.attributionType,\n runtimeId: input.runtimeId,\n };\n const parsed = CommitAttributedEventSchema.safeParse(candidate);\n if (!parsed.success) return;\n collector.capture(ROI_EVENT_TYPE, parsed.data);\n}\n","import {\n PrAttributedEventSchema,\n ROI_EVENT_SCHEMA_VERSION,\n ROI_EVENT_TYPE,\n} from '../schemas/events';\nimport type { MetricsCapture } from './types';\n\nexport interface PrAttributedInput {\n taskId: string;\n userId: string;\n prUrl: string;\n prNumber: number;\n repo: string;\n runtimeId?: string;\n timestamp?: number;\n}\n\nexport function emitPrAttributed(collector: MetricsCapture, input: PrAttributedInput): void {\n const candidate = {\n version: ROI_EVENT_SCHEMA_VERSION,\n kind: 'pr_attributed' as const,\n taskId: input.taskId,\n userId: input.userId,\n timestamp: input.timestamp ?? Date.now(),\n prUrl: input.prUrl,\n prNumber: input.prNumber,\n repo: input.repo,\n ...(input.runtimeId !== undefined ? { runtimeId: input.runtimeId } : {}),\n };\n const parsed = PrAttributedEventSchema.safeParse(candidate);\n if (!parsed.success) return;\n collector.capture(ROI_EVENT_TYPE, parsed.data);\n}\n","import {\n type MergeMethod,\n PrMergedEventSchema,\n ROI_EVENT_SCHEMA_VERSION,\n ROI_EVENT_TYPE,\n} from '../schemas/events';\nimport type { MetricsCapture } from './types';\n\nexport interface PrMergedInput {\n taskId: string;\n userId: string;\n prUrl: string;\n prNumber: number;\n repo: string;\n mergeCommitSha: string | null;\n mergeMethod: MergeMethod;\n mergedAt: number;\n runtimeId?: string;\n timestamp?: number;\n}\n\nexport function emitPrMerged(collector: MetricsCapture, input: PrMergedInput): void {\n const candidate = {\n version: ROI_EVENT_SCHEMA_VERSION,\n kind: 'pr_merged' as const,\n taskId: input.taskId,\n userId: input.userId,\n timestamp: input.timestamp ?? Date.now(),\n prUrl: input.prUrl,\n prNumber: input.prNumber,\n repo: input.repo,\n mergeCommitSha: input.mergeCommitSha,\n mergeMethod: input.mergeMethod,\n mergedAt: input.mergedAt,\n ...(input.runtimeId !== undefined ? { runtimeId: input.runtimeId } : {}),\n };\n const parsed = PrMergedEventSchema.safeParse(candidate);\n if (!parsed.success) return;\n collector.capture(ROI_EVENT_TYPE, parsed.data);\n}\n","import { ROI_EVENT_SCHEMA_VERSION, ROI_EVENT_TYPE, TaskEndedEventSchema } from '../schemas/events';\nimport type { MetricsCapture } from './types';\n\nexport interface TaskEndedInput {\n taskId: string;\n userId: string;\n finalStatus: 'completed' | 'canceled' | 'input_required';\n totalCostUsd: number;\n totalOutputTokens: number;\n turnCount: number;\n durationMs: number;\n runtimeId: string;\n timestamp?: number;\n}\n\nexport function emitTaskEnded(collector: MetricsCapture, input: TaskEndedInput): void {\n const candidate = {\n version: ROI_EVENT_SCHEMA_VERSION,\n kind: 'task_ended' as const,\n taskId: input.taskId,\n userId: input.userId,\n timestamp: input.timestamp ?? Date.now(),\n finalStatus: input.finalStatus,\n totalCostUsd: input.totalCostUsd,\n totalOutputTokens: input.totalOutputTokens,\n turnCount: input.turnCount,\n durationMs: input.durationMs,\n runtimeId: input.runtimeId,\n };\n const parsed = TaskEndedEventSchema.safeParse(candidate);\n if (!parsed.success) return;\n collector.capture(ROI_EVENT_TYPE, parsed.data);\n}\n","import {\n ROI_EVENT_SCHEMA_VERSION,\n ROI_EVENT_TYPE,\n TaskStartedEventSchema,\n} from '../schemas/events';\nimport type { MetricsCapture } from './types';\n\nexport interface TaskStartedInput {\n taskId: string;\n userId: string;\n activeTaskCount: number;\n mode: string;\n taskType?: string;\n runtimeId: string;\n timestamp?: number;\n}\n\nexport function emitTaskStarted(collector: MetricsCapture, input: TaskStartedInput): void {\n const candidate = {\n version: ROI_EVENT_SCHEMA_VERSION,\n kind: 'task_started' as const,\n taskId: input.taskId,\n userId: input.userId,\n timestamp: input.timestamp ?? Date.now(),\n activeTaskCount: input.activeTaskCount,\n mode: input.mode,\n taskType: input.taskType,\n runtimeId: input.runtimeId,\n };\n const parsed = TaskStartedEventSchema.safeParse(candidate);\n if (!parsed.success) return;\n collector.capture(ROI_EVENT_TYPE, parsed.data);\n}\n","import { z } from 'zod';\n\nexport const REPORT_SCHEMA_VERSION = 1 as const;\n\nexport const TimeWindowSchema = z.object({\n since: z.string(),\n until: z.string(),\n});\nexport type TimeWindow = z.infer<typeof TimeWindowSchema>;\n\nexport const TimeSeriesPointSchema = z.object({\n bucket: z.string(),\n value: z.number(),\n denominator: z.number().int().nonnegative().optional(),\n});\nexport type TimeSeriesPoint = z.infer<typeof TimeSeriesPointSchema>;\n\nexport const TimeSeriesMetricSchema = z.object({\n metric: z.string(),\n unit: z.string(),\n bucketSize: z.enum(['day', 'week', 'month']),\n series: z.array(TimeSeriesPointSchema),\n});\nexport type TimeSeriesMetric = z.infer<typeof TimeSeriesMetricSchema>;\n\nexport const TaskOutcomeFunnelSchema = z.object({\n tasksStarted: z.number().int().nonnegative(),\n producedCommits: z.number().int().nonnegative(),\n openedPr: z.number().int().nonnegative(),\n merged: z.number().int().nonnegative(),\n abandoned: z.number().int().nonnegative(),\n revertedWithin30d: z.number().int().nonnegative(),\n});\nexport type TaskOutcomeFunnel = z.infer<typeof TaskOutcomeFunnelSchema>;\n\nexport const EngineerScorecardRowSchema = z.object({\n userId: z.string(),\n prsPerWeekDelta: z.number().optional(),\n cycleTimeDelta: z.number().optional(),\n peakParallel: z.number().nonnegative(),\n costPerPrUsd: z.number().nonnegative(),\n revertRate: z.number().min(0).max(1),\n sampleSize: z.number().int().nonnegative(),\n signal: z.enum(['strong', 'modest', 'low-adoption', 'outlier-high', 'insufficient-data']),\n});\nexport type EngineerScorecardRow = z.infer<typeof EngineerScorecardRowSchema>;\n\nexport const FacetBreakdownSchema = z.object({\n facet: z.string(),\n rows: z.array(\n z.object({\n key: z.string(),\n count: z.number().int().nonnegative(),\n costUsd: z.number().nonnegative(),\n mergedPct: z.number().min(0).max(1).optional(),\n abandonedPct: z.number().min(0).max(1).optional(),\n revertedPct: z.number().min(0).max(1).optional(),\n })\n ),\n});\nexport type FacetBreakdown = z.infer<typeof FacetBreakdownSchema>;\n\nexport const RoiTotalsSchema = z.object({\n tasksStarted: z.number().int().nonnegative(),\n tasksAbandoned: z.number().int().nonnegative(),\n tasksShipped: z.number().int().nonnegative(),\n costUsd: z.number().nonnegative(),\n tokens: z.number().int().nonnegative(),\n engineersActive: z.number().int().nonnegative(),\n});\nexport type RoiTotals = z.infer<typeof RoiTotalsSchema>;\n\nexport const RoiKpisSchema = z.object({\n costPerMergedPr: z.number().nonnegative(),\n peakLeverageAvg: z.number().nonnegative(),\n peakLeverageHumanBaseline: z.number().nonnegative().default(1.0),\n revertRateShipyard: z.number().min(0).max(1),\n revertRateManualBaseline: z.number().min(0).max(1).optional(),\n});\nexport type RoiKpis = z.infer<typeof RoiKpisSchema>;\n\nexport const RoiWarningSchema = z.object({\n code: z.string(),\n message: z.string(),\n context: z.record(z.unknown()).default({}),\n});\nexport type RoiWarning = z.infer<typeof RoiWarningSchema>;\n\nexport const RoiReportSchema = z.object({\n schemaVersion: z.literal(REPORT_SCHEMA_VERSION),\n generatedAt: z.string(),\n window: TimeWindowSchema,\n totals: RoiTotalsSchema,\n kpis: RoiKpisSchema,\n series: z.object({\n tokensPerPrWeekly: TimeSeriesMetricSchema,\n concurrentTasksWeekly: TimeSeriesMetricSchema,\n }),\n funnel: TaskOutcomeFunnelSchema,\n byEngineer: z.array(EngineerScorecardRowSchema),\n facets: z.array(FacetBreakdownSchema),\n warnings: z.array(RoiWarningSchema),\n});\nexport type RoiReport = z.infer<typeof RoiReportSchema>;\n","import { z } from 'zod';\nimport { type AttributionType, AttributionTypeSchema } from './events';\n\nexport const TRAILER_SCHEMA_VERSION = 2 as const;\n\nexport const SHIPYARD_COAUTHOR = 'Shipyard <bot@shipyard.dev>' as const;\n\nexport const GitTrailerV2Schema = z.object({\n version: z.literal(TRAILER_SCHEMA_VERSION),\n taskId: z.string().min(1),\n sessionId: z.string().min(1),\n model: z.string().min(1),\n tokens: z.number().int().nonnegative(),\n costUsd: z.number().nonnegative(),\n turnCount: z.number().int().nonnegative(),\n attributionType: AttributionTypeSchema,\n clientVersion: z.string().min(1),\n});\nexport type GitTrailerV2 = z.infer<typeof GitTrailerV2Schema>;\n\nconst HEADERS: Record<keyof GitTrailerV2, string> = {\n version: 'Shipyard-Version',\n taskId: 'Shipyard-Task-Id',\n sessionId: 'Shipyard-Session-Id',\n model: 'Shipyard-Model',\n tokens: 'Shipyard-Tokens',\n costUsd: 'Shipyard-Cost-Usd',\n turnCount: 'Shipyard-Turn-Count',\n attributionType: 'Shipyard-Attribution-Type',\n clientVersion: 'Shipyard-Client-Version',\n};\n\nexport function formatTrailer(trailer: GitTrailerV2): string {\n const lines = [\n `${HEADERS.version}: ${trailer.version}`,\n `${HEADERS.taskId}: ${trailer.taskId}`,\n `${HEADERS.sessionId}: ${trailer.sessionId}`,\n `${HEADERS.model}: ${trailer.model}`,\n `${HEADERS.tokens}: ${trailer.tokens}`,\n `${HEADERS.costUsd}: ${trailer.costUsd.toFixed(4)}`,\n `${HEADERS.turnCount}: ${trailer.turnCount}`,\n `${HEADERS.attributionType}: ${trailer.attributionType}`,\n `${HEADERS.clientVersion}: ${trailer.clientVersion}`,\n '',\n `Co-Authored-By: ${SHIPYARD_COAUTHOR}`,\n ];\n return lines.join('\\n');\n}\n\nexport type ParseTrailerResult =\n | { success: true; trailer: GitTrailerV2 }\n | { success: false; error: string };\n\nconst NUMERIC_FIELDS: Record<string, 'int' | 'float'> = {\n [HEADERS.version]: 'int',\n [HEADERS.tokens]: 'int',\n [HEADERS.costUsd]: 'float',\n [HEADERS.turnCount]: 'int',\n};\n\ntype ExtractFieldResult =\n | { ok: true; key: string; value: string | number }\n | { ok: false; error: string }\n | { ok: 'skip' };\n\nfunction extractField(rawLine: string): ExtractFieldResult {\n const line = rawLine.trimEnd();\n if (!line.startsWith('Shipyard-')) return { ok: 'skip' };\n const colonIdx = line.indexOf(':');\n if (colonIdx === -1) return { ok: 'skip' };\n\n const header = line.slice(0, colonIdx).trim();\n const value = line.slice(colonIdx + 1).trim();\n const numericKind = NUMERIC_FIELDS[header];\n\n if (numericKind === undefined) {\n return { ok: true, key: header, value };\n }\n const n = numericKind === 'int' ? Number.parseInt(value, 10) : Number.parseFloat(value);\n if (Number.isNaN(n)) {\n return { ok: false, error: `non-numeric ${header}: ${value}` };\n }\n return { ok: true, key: header, value: n };\n}\n\nexport function parseTrailer(commitMessage: string): ParseTrailerResult {\n const fields: Record<string, string | number> = {};\n for (const rawLine of commitMessage.split(/\\r?\\n/)) {\n const result = extractField(rawLine);\n if (result.ok === false) return { success: false, error: result.error };\n if (result.ok === 'skip') continue;\n fields[result.key] = result.value;\n }\n\n const candidate = {\n version: fields[HEADERS.version],\n taskId: fields[HEADERS.taskId],\n sessionId: fields[HEADERS.sessionId],\n model: fields[HEADERS.model],\n tokens: fields[HEADERS.tokens],\n costUsd: fields[HEADERS.costUsd],\n turnCount: fields[HEADERS.turnCount],\n attributionType: fields[HEADERS.attributionType],\n clientVersion: fields[HEADERS.clientVersion],\n };\n\n const parsed = GitTrailerV2Schema.safeParse(candidate);\n if (!parsed.success) {\n return { success: false, error: parsed.error.issues.map((i) => i.message).join('; ') };\n }\n return { success: true, trailer: parsed.data };\n}\n\nexport function hasShipyardTrailer(commitMessage: string): boolean {\n return commitMessage.includes(`${HEADERS.taskId}:`);\n}\n\nexport function appendTrailerToMessage(originalMessage: string, trailer: GitTrailerV2): string {\n const body = originalMessage.trimEnd();\n return `${body}\\n\\n${formatTrailer(trailer)}\\n`;\n}\n\nexport { AttributionTypeSchema };\nexport type { AttributionType };\n"],"mappings":"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","names":[]}
|