codiedev 0.9.80 → 0.10.0-beta.10
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/README.md +12 -5
- package/dist/backup/cache.js +1 -5
- package/dist/backup/match.js +0 -6
- package/dist/backup/run.js +3 -35
- package/dist/captureExclusions.js +0 -12
- package/dist/captureLog.js +0 -28
- package/dist/captureReadiness.js +0 -58
- package/dist/captureSignals.js +0 -11
- package/dist/cli.js +11 -33
- package/dist/cliSession.js +3 -60
- package/dist/codexHookTrust.js +0 -28
- package/dist/codexLimitScan.js +0 -107
- package/dist/codie.js +64 -57
- package/dist/codieBrandInstall.js +0 -18
- package/dist/codieLauncher.js +1 -72
- package/dist/codieRuntime.js +27 -32
- package/dist/codieRuntimeInstall.js +11 -43
- package/dist/codieUsage.js +0 -49
- package/dist/commands/agentTemplates.generated.js +136 -0
- package/dist/commands/agents.js +1088 -0
- package/dist/commands/agentsSdk.generated.js +7 -0
- package/dist/commands/ask.js +0 -3
- package/dist/commands/capture.js +0 -2
- package/dist/commands/createTicket.js +0 -10
- package/dist/commands/doctor.js +2 -72
- package/dist/commands/evals.js +3 -9
- package/dist/commands/inbox.js +0 -2
- package/dist/commands/library.js +0 -3
- package/dist/commands/pack.js +0 -29
- package/dist/commands/ping.js +0 -2
- package/dist/commands/pull.js +0 -9
- package/dist/commands/push.js +0 -12
- package/dist/commands/search.js +0 -4
- package/dist/commands/send.js +0 -5
- package/dist/commands/share.js +0 -4
- package/dist/commands/shared.js +0 -35
- package/dist/commands/traces.js +0 -13
- package/dist/commands/tracesLabel.js +0 -8
- package/dist/configDir.js +1 -18
- package/dist/connect.js +3 -75
- package/dist/connectFlow.js +0 -15
- package/dist/copilotHooks.js +0 -67
- package/dist/copilotInstallation.js +0 -1
- package/dist/cursorHooks.js +1 -11
- package/dist/cursorLifecycle.js +1 -7
- package/dist/detection.js +0 -30
- package/dist/harnessDirs.js +0 -19
- package/dist/hook.js +43 -293
- package/dist/inboxFormat.js +0 -24
- package/dist/launchContext.js +0 -50
- package/dist/launcher.js +0 -33
- package/dist/limitEvent.js +2 -34
- package/dist/managedPi.js +2 -50
- package/dist/mcp.js +0 -48
- package/dist/nativeSteering.js +1 -4
- package/dist/packs/codie.js +0 -15
- package/dist/packs/harnesses.js +1 -38
- package/dist/packs/hookGate.js +0 -33
- package/dist/packs/install.js +0 -20
- package/dist/packs/manifest.js +1 -15
- package/dist/packs/paths.js +0 -8
- package/dist/packs/shim.js +0 -8
- package/dist/packs/store.js +0 -12
- package/dist/packs/sync.js +0 -20
- package/dist/piHooks.js +4 -45
- package/dist/piRuntime.js +0 -18
- package/dist/repoResolver.js +0 -19
- package/dist/secret.js +0 -3
- package/dist/selfUpdate.js +2 -77
- package/dist/skillMarker.js +0 -14
- package/dist/subagents.js +0 -18
- package/dist/teamSkillContext.js +0 -1
- package/dist/transcriptModels.js +0 -8
- package/dist/upgradeNudge.js +1 -30
- package/dist/utils.js +165 -768
- package/dist/version.js +0 -10
- package/dist/versionCheck.js +0 -33
- package/package.json +13 -8
- package/dist/backup/cache.d.ts +0 -14
- package/dist/backup/match.d.ts +0 -2
- package/dist/backup/run.d.ts +0 -25
- package/dist/captureExclusions.d.ts +0 -30
- package/dist/captureLog.d.ts +0 -20
- package/dist/captureReadiness.d.ts +0 -65
- package/dist/captureSignals.d.ts +0 -47
- package/dist/cli.d.ts +0 -15
- package/dist/cliSession.d.ts +0 -108
- package/dist/codexHookTrust.d.ts +0 -49
- package/dist/codexLimitScan.d.ts +0 -64
- package/dist/codie.d.ts +0 -2
- package/dist/codieBrandInstall.d.ts +0 -11
- package/dist/codieLauncher.d.ts +0 -87
- package/dist/codieRuntime.d.ts +0 -35
- package/dist/codieRuntimeInstall.d.ts +0 -56
- package/dist/codieUsage.d.ts +0 -64
- package/dist/commands/ask.d.ts +0 -1
- package/dist/commands/capture.d.ts +0 -14
- package/dist/commands/createTicket.d.ts +0 -27
- package/dist/commands/delete.d.ts +0 -1
- package/dist/commands/doctor.d.ts +0 -9
- package/dist/commands/evals.d.ts +0 -3
- package/dist/commands/inbox.d.ts +0 -3
- package/dist/commands/library.d.ts +0 -2
- package/dist/commands/note.d.ts +0 -1
- package/dist/commands/pack.d.ts +0 -54
- package/dist/commands/ping.d.ts +0 -1
- package/dist/commands/pull.d.ts +0 -2
- package/dist/commands/push.d.ts +0 -33
- package/dist/commands/search.d.ts +0 -2
- package/dist/commands/send.d.ts +0 -2
- package/dist/commands/share.d.ts +0 -2
- package/dist/commands/shared.d.ts +0 -64
- package/dist/commands/traces.d.ts +0 -72
- package/dist/commands/tracesLabel.d.ts +0 -24
- package/dist/configDir.d.ts +0 -10
- package/dist/connect.d.ts +0 -1
- package/dist/connectFlow.d.ts +0 -34
- package/dist/copilotHooks.d.ts +0 -85
- package/dist/copilotInstallation.d.ts +0 -10
- package/dist/cursorHooks.d.ts +0 -13
- package/dist/cursorLifecycle.d.ts +0 -2
- package/dist/detection.d.ts +0 -30
- package/dist/harnessDirs.d.ts +0 -15
- package/dist/hook.d.ts +0 -6
- package/dist/inboxFormat.d.ts +0 -38
- package/dist/launchContext.d.ts +0 -46
- package/dist/launcher.d.ts +0 -25
- package/dist/limitEvent.d.ts +0 -15
- package/dist/limitEventReporter.d.ts +0 -21
- package/dist/managedPi.d.ts +0 -48
- package/dist/mcp.d.ts +0 -12
- package/dist/nativeSteering.d.ts +0 -5
- package/dist/packs/codie.d.ts +0 -45
- package/dist/packs/harnesses.d.ts +0 -74
- package/dist/packs/hookGate.d.ts +0 -53
- package/dist/packs/install.d.ts +0 -46
- package/dist/packs/manifest.d.ts +0 -52
- package/dist/packs/paths.d.ts +0 -17
- package/dist/packs/shim.d.ts +0 -26
- package/dist/packs/store.d.ts +0 -42
- package/dist/packs/sync.d.ts +0 -40
- package/dist/piHooks.d.ts +0 -22
- package/dist/piRuntime.d.ts +0 -26
- package/dist/repoResolver.d.ts +0 -17
- package/dist/secret.d.ts +0 -1
- package/dist/selfUpdate.d.ts +0 -64
- package/dist/skillMarker.d.ts +0 -6
- package/dist/subagents.d.ts +0 -36
- package/dist/teamSkillContext.d.ts +0 -9
- package/dist/transcriptModels.d.ts +0 -20
- package/dist/upgradeNudge.d.ts +0 -24
- package/dist/utils.d.ts +0 -396
- package/dist/version.d.ts +0 -1
- package/dist/versionCheck.d.ts +0 -68
package/dist/packs/sync.js
CHANGED
|
@@ -42,11 +42,6 @@ exports.decideSync = decideSync;
|
|
|
42
42
|
exports.cliEntry = cliEntry;
|
|
43
43
|
exports.maybeSpawnPackSync = maybeSpawnPackSync;
|
|
44
44
|
exports.packNagLine = packNagLine;
|
|
45
|
-
// Background auto-update and the "pack has updates" nudge.
|
|
46
|
-
//
|
|
47
|
-
// Hot-path rule: maybeSpawnPackSync and packNagLine run inside session-start
|
|
48
|
-
// hooks and every `codiedev` command, so they only stat/read tiny local files
|
|
49
|
-
// and, at most once an hour, spawn a detached child. No network here, ever.
|
|
50
45
|
const fs = __importStar(require("fs"));
|
|
51
46
|
const os = __importStar(require("os"));
|
|
52
47
|
const path = __importStar(require("path"));
|
|
@@ -54,16 +49,11 @@ const child_process_1 = require("child_process");
|
|
|
54
49
|
const paths_1 = require("./paths");
|
|
55
50
|
const store_1 = require("./store");
|
|
56
51
|
exports.SYNC_INTERVAL_MS = 60 * 60 * 1000;
|
|
57
|
-
/** CI mode: a pack-scoped CI key (`cdvci_…`) or CI=true. No auto-sync, no
|
|
58
|
-
* nudge, no server writes, no pruning — CI machines are ephemeral and CI keys
|
|
59
|
-
* can only read packs. */
|
|
60
52
|
function isPackCiMode(env = process.env) {
|
|
61
53
|
const ci = (env.CI ?? "").trim().toLowerCase();
|
|
62
54
|
return (env.CODIEDEV_TOKEN ?? "").trim().startsWith("cdvci_") || ci === "true" || ci === "1";
|
|
63
55
|
}
|
|
64
56
|
exports.NAG_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
65
|
-
// With nothing installed and a fresh "your team has no packs" answer, only
|
|
66
|
-
// re-ask once a day so a newly assigned pack still arrives.
|
|
67
57
|
exports.EMPTY_RECHECK_MS = 24 * 60 * 60 * 1000;
|
|
68
58
|
function readStatusCache(root) {
|
|
69
59
|
try {
|
|
@@ -85,7 +75,6 @@ function writeStatusCache(root, cache) {
|
|
|
85
75
|
(0, store_1.writeFileAtomic)((0, paths_1.statusCachePath)(root), JSON.stringify(cache) + "\n");
|
|
86
76
|
}
|
|
87
77
|
catch {
|
|
88
|
-
// best-effort
|
|
89
78
|
}
|
|
90
79
|
}
|
|
91
80
|
function mtime(file) {
|
|
@@ -97,7 +86,6 @@ function mtime(file) {
|
|
|
97
86
|
}
|
|
98
87
|
}
|
|
99
88
|
function registryNonEmpty(root) {
|
|
100
|
-
// installed.json is tiny; `{"packs":{}}` means nothing is installed.
|
|
101
89
|
try {
|
|
102
90
|
const parsed = JSON.parse(fs.readFileSync((0, paths_1.registryPath)(root), "utf8"));
|
|
103
91
|
return Boolean(parsed?.packs && Object.keys(parsed.packs).length > 0);
|
|
@@ -110,7 +98,6 @@ function autosyncDisabled(env) {
|
|
|
110
98
|
const v = (env.CODIEDEV_PACK_AUTOSYNC ?? "").trim().toLowerCase();
|
|
111
99
|
return v === "0" || v === "false" || v === "off" || v === "no";
|
|
112
100
|
}
|
|
113
|
-
/** Pure decision for the hourly background sync. */
|
|
114
101
|
function decideSync(root, env, now) {
|
|
115
102
|
const last = mtime((0, paths_1.lastSyncPath)(root));
|
|
116
103
|
if (last !== null && now - last < exports.SYNC_INTERVAL_MS && last <= now)
|
|
@@ -120,15 +107,11 @@ function decideSync(root, env, now) {
|
|
|
120
107
|
if (cache && cache.available === 0 && now - cache.checkedAt < exports.EMPTY_RECHECK_MS)
|
|
121
108
|
return "no-packs";
|
|
122
109
|
}
|
|
123
|
-
// Opted out of auto-install: still refresh the cached status (read-only,
|
|
124
|
-
// no install, no pruning) so the outdated nudge can tell them.
|
|
125
110
|
return autosyncDisabled(env) ? "spawn-check" : "spawn-install";
|
|
126
111
|
}
|
|
127
112
|
function cliEntry() {
|
|
128
|
-
// dist/packs/sync.js → dist/cli.js
|
|
129
113
|
return path.join(__dirname, "..", "cli.js");
|
|
130
114
|
}
|
|
131
|
-
/** Called from session-start hooks. Never throws, never waits. */
|
|
132
115
|
function maybeSpawnPackSync(options = {}) {
|
|
133
116
|
try {
|
|
134
117
|
if (options.connected === false)
|
|
@@ -141,7 +124,6 @@ function maybeSpawnPackSync(options = {}) {
|
|
|
141
124
|
const decision = decideSync(root, env, now);
|
|
142
125
|
if (decision !== "spawn-install" && decision !== "spawn-check")
|
|
143
126
|
return decision;
|
|
144
|
-
// Stamp first so concurrent session starts don't each spawn a sync.
|
|
145
127
|
fs.mkdirSync(root, { recursive: true });
|
|
146
128
|
fs.writeFileSync((0, paths_1.lastSyncPath)(root), String(now));
|
|
147
129
|
const time = new Date(now);
|
|
@@ -162,8 +144,6 @@ function maybeSpawnPackSync(options = {}) {
|
|
|
162
144
|
return "error";
|
|
163
145
|
}
|
|
164
146
|
}
|
|
165
|
-
/** One-line nudge when the cached status shows an outdated pack, at most once
|
|
166
|
-
* a day. Returns null (and records nothing) when there's nothing to say. */
|
|
167
147
|
function packNagLine(options = {}) {
|
|
168
148
|
try {
|
|
169
149
|
const env = options.env ?? process.env;
|
package/dist/piHooks.js
CHANGED
|
@@ -39,21 +39,9 @@ exports.isPiTranscriptEmpty = isPiTranscriptEmpty;
|
|
|
39
39
|
exports.piLaunchFromArgv = piLaunchFromArgv;
|
|
40
40
|
exports.piExtensionPath = piExtensionPath;
|
|
41
41
|
exports.inspectPiExtension = inspectPiExtension;
|
|
42
|
-
// pi (@mariozechner/pi-coding-agent). pi has no hook config; it loads
|
|
43
|
-
// TypeScript extensions from <agentDir>/extensions/, so Codiedev installs one
|
|
44
|
-
// there (see installPiExtension in utils.ts) that forwards pi's events to the
|
|
45
|
-
// same hook subcommands every other harness uses.
|
|
46
|
-
//
|
|
47
|
-
// pi writes its own session JSONL (<agentDir>/sessions/--<cwd>--/<ts>_<id>.jsonl)
|
|
48
|
-
// and the extension passes that path as transcript_path. This file turns it
|
|
49
|
-
// into the Claude Code shape the shared capture pipeline parses.
|
|
50
|
-
//
|
|
51
|
-
// Imports only node built-ins and harnessDirs (no utils.ts) so hook.ts,
|
|
52
|
-
// utils.ts and securityInstall.ts can all import it without a cycle.
|
|
53
42
|
const fs = __importStar(require("fs"));
|
|
54
43
|
const path = __importStar(require("path"));
|
|
55
44
|
const harnessDirs_1 = require("./harnessDirs");
|
|
56
|
-
/** customType of the context message the Codiedev extension injects. */
|
|
57
45
|
exports.PI_CONTEXT_CUSTOM_TYPE = "codiedev";
|
|
58
46
|
const SKILL_EXPANSION = /^<skill name="([^"]{1,200})" location="[^"]*">/;
|
|
59
47
|
const num = (n) => (typeof n === "number" && Number.isFinite(n) ? Math.max(0, n) : 0);
|
|
@@ -74,36 +62,20 @@ function userBlocks(content) {
|
|
|
74
62
|
return [];
|
|
75
63
|
return content.flatMap((block) => block?.type === "text" && typeof block.text === "string"
|
|
76
64
|
? [{ type: "text", text: block.text }]
|
|
77
|
-
// Image bytes never leave the machine; keep that one was attached.
|
|
78
65
|
: block?.type === "image" ? [{ type: "text", text: "[image]" }] : []);
|
|
79
66
|
}
|
|
80
|
-
/** `/x/skills/review/SKILL.md` → "review". pi's agent loads a listed skill by
|
|
81
|
-
* reading its SKILL.md; that read IS the invocation (docs/skills.md). */
|
|
82
67
|
function skillFromPath(value) {
|
|
83
68
|
if (typeof value !== "string")
|
|
84
69
|
return null;
|
|
85
70
|
const m = value.replace(/\\/g, "/").match(/\/([^/]+)\/SKILL\.md$/);
|
|
86
71
|
return m ? m[1] : null;
|
|
87
72
|
}
|
|
88
|
-
/** A provider error's HTTP status, when pi kept it at the front ("429 …"). */
|
|
89
73
|
function errorCode(message) {
|
|
90
74
|
return message.match(/^\s*(\d{3})\b/)?.[1] ?? "";
|
|
91
75
|
}
|
|
92
|
-
/**
|
|
93
|
-
* pi session JSONL → Claude Code-shaped JSONL.
|
|
94
|
-
*
|
|
95
|
-
* Every message entry is kept in file order, abandoned /tree branches
|
|
96
|
-
* included: they were real model calls and real tokens. Usage is pi's own
|
|
97
|
-
* per-call record (`input` is already the uncached part). Skill runs, user
|
|
98
|
-
* interrupts and provider errors become the records the shared parsers read:
|
|
99
|
-
* `pi.skill_invoked`, Claude's interrupt marker and a native `agent.error`.
|
|
100
|
-
*/
|
|
101
76
|
function normalizePiTranscript(content) {
|
|
102
77
|
const out = [];
|
|
103
78
|
const skillReads = new Map();
|
|
104
|
-
// pi retries a failed provider call on its own (and fires agent_end after
|
|
105
|
-
// each try). Every error in one retry streak carries the streak's first
|
|
106
|
-
// time, so limit events, which dedupe on time, count the hit once.
|
|
107
79
|
let errorStreakAt;
|
|
108
80
|
const push = (record) => out.push(JSON.stringify(record));
|
|
109
81
|
for (const line of content.split("\n")) {
|
|
@@ -114,7 +86,7 @@ function normalizePiTranscript(content) {
|
|
|
114
86
|
entry = JSON.parse(line);
|
|
115
87
|
}
|
|
116
88
|
catch {
|
|
117
|
-
continue;
|
|
89
|
+
continue;
|
|
118
90
|
}
|
|
119
91
|
if (!entry || typeof entry !== "object")
|
|
120
92
|
continue;
|
|
@@ -150,7 +122,6 @@ function normalizePiTranscript(content) {
|
|
|
150
122
|
}
|
|
151
123
|
const usage = message.usage ?? {};
|
|
152
124
|
const tokens = num(usage.input) + num(usage.output) + num(usage.cacheRead) + num(usage.cacheWrite);
|
|
153
|
-
// A failed call records all-zero usage; it was not a billed request.
|
|
154
125
|
const measured = tokens > 0 || message.stopReason !== "error";
|
|
155
126
|
push({
|
|
156
127
|
type: "assistant",
|
|
@@ -175,8 +146,6 @@ function normalizePiTranscript(content) {
|
|
|
175
146
|
push({ type: "user", timestamp, message: { role: "user", content: [{ type: "text", text: "[Request interrupted by user]" }] } });
|
|
176
147
|
}
|
|
177
148
|
if (message.stopReason === "error" && typeof message.errorMessage === "string") {
|
|
178
|
-
// The call's own time, not the entry's write time, so interim and
|
|
179
|
-
// final captures agree.
|
|
180
149
|
errorStreakAt ??= typeof message.timestamp === "number" ? new Date(message.timestamp).toISOString() : timestamp;
|
|
181
150
|
push({
|
|
182
151
|
type: "agent.error",
|
|
@@ -202,18 +171,15 @@ function normalizePiTranscript(content) {
|
|
|
202
171
|
});
|
|
203
172
|
continue;
|
|
204
173
|
}
|
|
205
|
-
// `!cmd` typed by the user: shown to the model like any user turn.
|
|
206
174
|
if (message.role === "bashExecution" && typeof message.command === "string") {
|
|
207
175
|
push({ type: "user", uuid, timestamp, message: { role: "user", content: [{ type: "text", text: `<bash-input>${message.command}</bash-input>` }] } });
|
|
208
176
|
}
|
|
209
177
|
}
|
|
210
178
|
return out.join("\n") + (out.length ? "\n" : "");
|
|
211
179
|
}
|
|
212
|
-
/** pi writes the session header at startup; no message yet means nothing to capture. */
|
|
213
180
|
function isPiTranscriptEmpty(content) {
|
|
214
181
|
return !content.split("\n").some((line) => line.includes('"type":"message"'));
|
|
215
182
|
}
|
|
216
|
-
/** How pi was launched, from its own argv (the extension runs in pi's process). */
|
|
217
183
|
function piLaunchFromArgv(argv) {
|
|
218
184
|
for (let i = 0; i < argv.length; i++) {
|
|
219
185
|
const a = argv[i];
|
|
@@ -232,8 +198,7 @@ function piLaunchFromArgv(argv) {
|
|
|
232
198
|
function piExtensionPath(agentDir = (0, harnessDirs_1.piAgentDir)()) {
|
|
233
199
|
return path.join(agentDir, "extensions", "codiedev.ts");
|
|
234
200
|
}
|
|
235
|
-
|
|
236
|
-
function inspectPiExtension(file = piExtensionPath(), security = false) {
|
|
201
|
+
function inspectPiExtension(file = piExtensionPath()) {
|
|
237
202
|
if (!fs.existsSync(file))
|
|
238
203
|
return { status: "not-installed", detail: `${file} not found` };
|
|
239
204
|
let source;
|
|
@@ -243,15 +208,9 @@ function inspectPiExtension(file = piExtensionPath(), security = false) {
|
|
|
243
208
|
catch {
|
|
244
209
|
return { status: "fail", detail: `${file} unreadable` };
|
|
245
210
|
}
|
|
246
|
-
const expected =
|
|
247
|
-
? ["discover-pi", "security-pre-pi", "security-post-pi"]
|
|
248
|
-
: ["session-start-pi", "backup-pi", "capture-pi-final"];
|
|
249
|
-
// Quoted: "backup-pi" must not match inside some longer subcommand.
|
|
211
|
+
const expected = ["session-start-pi", "backup-pi", "capture-pi-final"];
|
|
250
212
|
const missing = expected.filter((subcommand) => !source.includes(JSON.stringify(subcommand)));
|
|
251
213
|
if (missing.length)
|
|
252
214
|
return { status: "fail", detail: `missing ${missing.join(", ")} — re-run \`codiedev connect\`` };
|
|
253
|
-
|
|
254
|
-
return { status: "fail", detail: "installed with agent security off — re-run `codiedev connect`" };
|
|
255
|
-
}
|
|
256
|
-
return { status: "pass", detail: security ? "prompt guard and tool telemetry installed" : `session start, capture and backup events (${(0, harnessDirs_1.displayPath)(file)})` };
|
|
215
|
+
return { status: "pass", detail: `session start, capture and backup events (${(0, harnessDirs_1.displayPath)(file)})` };
|
|
257
216
|
}
|
package/dist/piRuntime.js
CHANGED
|
@@ -37,13 +37,6 @@ exports.PI_RUNTIME_SPEC = exports.PI_VERSION = exports.PI_PACKAGE = void 0;
|
|
|
37
37
|
exports.piRuntimeDir = piRuntimeDir;
|
|
38
38
|
exports.installedPiEntry = installedPiEntry;
|
|
39
39
|
exports.ensurePiRuntime = ensurePiRuntime;
|
|
40
|
-
// pi for `codie --pi`, installed on first use like the Codie engine
|
|
41
|
-
// (codieRuntimeInstall.ts): developers never run a second npm install, and
|
|
42
|
-
// every machine runs the version Codiedev tested its capture against.
|
|
43
|
-
//
|
|
44
|
-
// pi is plain JavaScript, so it runs on the same Node as `codie` from its
|
|
45
|
-
// package entry: no PATH lookup, no Windows .cmd shim, and no dependency on
|
|
46
|
-
// whatever `pi` (if any) the developer installed globally.
|
|
47
40
|
const fs = __importStar(require("fs"));
|
|
48
41
|
const path = __importStar(require("path"));
|
|
49
42
|
const child_process_1 = require("child_process");
|
|
@@ -57,7 +50,6 @@ function piRuntimeDir(stateDir) {
|
|
|
57
50
|
function packageDir(installDir) {
|
|
58
51
|
return path.join(installDir, "node_modules", ...exports.PI_PACKAGE.split("/"));
|
|
59
52
|
}
|
|
60
|
-
/** The installed pi's CLI entry, when it is the pinned version. */
|
|
61
53
|
function installedPiEntry(installDir, readFile = (f) => fs.readFileSync(f, "utf8")) {
|
|
62
54
|
try {
|
|
63
55
|
const pkg = JSON.parse(readFile(path.join(packageDir(installDir), "package.json")));
|
|
@@ -70,15 +62,8 @@ function installedPiEntry(installDir, readFile = (f) => fs.readFileSync(f, "utf8
|
|
|
70
62
|
return null;
|
|
71
63
|
}
|
|
72
64
|
}
|
|
73
|
-
// One retry rides out a dropped connection or registry blip; a second
|
|
74
|
-
// failure is a real problem (offline, blocked registry) and is reported.
|
|
75
65
|
const INSTALL_ATTEMPTS = 2;
|
|
76
66
|
const INSTALL_RETRY_DELAY_MS = 5_000;
|
|
77
|
-
/**
|
|
78
|
-
* The pi CLI entry to run, installing the pinned version first if it is
|
|
79
|
-
* missing or a different version. Staged then renamed, so an interrupted
|
|
80
|
-
* download never leaves a half-installed pi that looks ready.
|
|
81
|
-
*/
|
|
82
67
|
function ensurePiRuntime(deps) {
|
|
83
68
|
const installDir = piRuntimeDir(deps.stateDir);
|
|
84
69
|
const exists = deps.exists ?? fs.existsSync;
|
|
@@ -109,7 +94,6 @@ function ensurePiRuntime(deps) {
|
|
|
109
94
|
const result = run((0, codieRuntimeInstall_1.buildRuntimeInstallArgs)(staging, exports.PI_RUNTIME_SPEC));
|
|
110
95
|
if (result.status !== 0)
|
|
111
96
|
throw new Error(result.stderr?.trim() || `npm exited with ${result.status}`);
|
|
112
|
-
// Trust the artifact, not the exit code.
|
|
113
97
|
const staged = installedPiEntry(staging, readFile);
|
|
114
98
|
if (!staged || !exists(staged)) {
|
|
115
99
|
throw new Error(`the install did not produce pi. Check that ${exports.PI_RUNTIME_SPEC} is available from your npm registry.`);
|
|
@@ -125,8 +109,6 @@ function ensurePiRuntime(deps) {
|
|
|
125
109
|
log(`pi install failed (${message.split("\n")[0]}); retrying.`);
|
|
126
110
|
}
|
|
127
111
|
finally {
|
|
128
|
-
// No-op after a successful promote; otherwise it keeps a ~200MB staging
|
|
129
|
-
// dir from being orphaned.
|
|
130
112
|
remove(staging);
|
|
131
113
|
}
|
|
132
114
|
sleep(INSTALL_RETRY_DELAY_MS);
|
package/dist/repoResolver.js
CHANGED
|
@@ -1,12 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// Pure resolver — given a captured remoteUrl, an optional client-cached
|
|
3
|
-
// repoId, and the company's current repo list, decide which repoId (if any)
|
|
4
|
-
// the session belongs to. Used both inline by the CLI hook and (mirrored
|
|
5
|
-
// in convex/repoResolver.ts) by the /api/captureSession endpoint so that
|
|
6
|
-
// repos added after the user's last `connect` still get matched.
|
|
7
|
-
//
|
|
8
|
-
// "unmatched" is intentional — the backend will accept the session anyway
|
|
9
|
-
// and surface it for triage rather than silently dropping it.
|
|
10
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
3
|
exports.resolveRepoForCapture = resolveRepoForCapture;
|
|
12
4
|
function parseRemoteUrl(url) {
|
|
@@ -17,12 +9,6 @@ function parseRemoteUrl(url) {
|
|
|
17
9
|
if (https) {
|
|
18
10
|
return { host: https[1].toLowerCase(), ownerName: https[2].toLowerCase() };
|
|
19
11
|
}
|
|
20
|
-
// Codie strips SSH userinfo before putting a remote in the gateway header,
|
|
21
|
-
// so `git@gitlab.com:owner/repo.git` arrives here as
|
|
22
|
-
// `gitlab.com:owner/repo.git`. Accept both forms; otherwise every SSH-cloned
|
|
23
|
-
// Harness checkout loses its repoId even though transcript capture can
|
|
24
|
-
// resolve the same raw remote correctly. Check this after URL forms so the
|
|
25
|
-
// colon in `https://` is never mistaken for an SCP separator.
|
|
26
12
|
const scp = s.match(/^(?:[^@\s]+@)?([^:/\s]+):([^/]+\/.+)$/);
|
|
27
13
|
if (scp) {
|
|
28
14
|
return { host: scp[1].toLowerCase(), ownerName: scp[2].toLowerCase() };
|
|
@@ -31,11 +17,6 @@ function parseRemoteUrl(url) {
|
|
|
31
17
|
}
|
|
32
18
|
function resolveRepoForCapture(input) {
|
|
33
19
|
const { remoteUrl, providedRepoId, companyRepos } = input;
|
|
34
|
-
// The remoteUrl is the ground truth of where the work happened — resolve it
|
|
35
|
-
// FIRST. A buggy client can send a wrong-but-valid providedRepoId (the Sonifi
|
|
36
|
-
// case: client matchRepo stamped every session with the org's first repo), so
|
|
37
|
-
// we must not blindly trust it over the URL. Keep providedRepoId only when it
|
|
38
|
-
// AGREES with the URL match, or when the URL can't be resolved at all.
|
|
39
20
|
const parsed = remoteUrl ? parseRemoteUrl(remoteUrl) : null;
|
|
40
21
|
const urlMatch = parsed
|
|
41
22
|
? companyRepos.find((r) => `${r.owner}/${r.name}`.toLowerCase() === parsed.ownerName)
|
package/dist/secret.js
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// Display helpers for credential-shaped strings. Use anywhere a token /
|
|
3
|
-
// secret might end up in user-visible output (logs, success lines, error
|
|
4
|
-
// messages) so a stray `console.log` can't leak the full value.
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.maskToken = maskToken;
|
|
7
4
|
const PREFIX_LEN = 12;
|
package/dist/selfUpdate.js
CHANGED
|
@@ -1,15 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// Background self-update for the hook path.
|
|
3
|
-
//
|
|
4
|
-
// Onboarded developers never run `connect`/`doctor`/`codie` again — only the
|
|
5
|
-
// harness hooks fire — so the interactive nudges in upgradeNudge.ts never
|
|
6
|
-
// reach them. This module lets any hook invocation spawn a detached child
|
|
7
|
-
// (at most once per day) that upgrades the exact install the hook is running
|
|
8
|
-
// from. Harness configs bake the absolute path to dist/hook.js, so the next
|
|
9
|
-
// hook call picks up the new code with no config change.
|
|
10
|
-
//
|
|
11
|
-
// Split like versionCheck.ts: `planSelfUpdate` is pure and unit-tested; the IO
|
|
12
|
-
// (state file, lock, registry fetch, package-manager spawn) is below it.
|
|
13
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
14
3
|
if (k2 === undefined) k2 = k;
|
|
15
4
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -63,16 +52,10 @@ const captureLog_1 = require("./captureLog");
|
|
|
63
52
|
const launcher_1 = require("./launcher");
|
|
64
53
|
const utils_1 = require("./utils");
|
|
65
54
|
const PKG = "codiedev";
|
|
66
|
-
const
|
|
55
|
+
const SELF_UPDATE_INTERVAL_MS = 2 * 60 * 60 * 1000;
|
|
67
56
|
const LOCK_STALE_MS = 10 * 60 * 1000;
|
|
68
57
|
const INSTALL_TIMEOUT_MS = 5 * 60 * 1000;
|
|
69
58
|
const FETCH_TIMEOUT_MS = 5_000;
|
|
70
|
-
/**
|
|
71
|
-
* Decide which package manager owns this install, from where hook.js really
|
|
72
|
-
* lives. We only ever upgrade the install we are running from: running
|
|
73
|
-
* whatever `npm` is first on PATH would, under nvm/Homebrew mixes, upgrade a
|
|
74
|
-
* different global tree than the one the harness config points at.
|
|
75
|
-
*/
|
|
76
59
|
function planSelfUpdate(deps) {
|
|
77
60
|
const { env } = deps;
|
|
78
61
|
if (env.CODIEDEV_NO_UPDATE_CHECK || env.CODIEDEV_NO_AUTO_UPDATE) {
|
|
@@ -89,30 +72,21 @@ function planSelfUpdate(deps) {
|
|
|
89
72
|
const pkgDir = path.dirname(path.dirname(deps.hookScriptReal));
|
|
90
73
|
if (!deps.isWritable(pkgDir))
|
|
91
74
|
return { kind: "skip", reason: "readonly" };
|
|
92
|
-
// pnpm puts every global install in a fresh hashed dir
|
|
93
|
-
// (global/v11/<hash>/node_modules/codiedev). That is only safe to upgrade
|
|
94
|
-
// when the hook runs through the stable launcher, which runSelfUpdate
|
|
95
|
-
// re-points at the new dir; a direct-path config would stay on the old copy.
|
|
96
75
|
if (/\/\.pnpm\/|\/pnpm\/global\/|\/global\/v\d+\/[^/]+\/node_modules\/codiedev\/|\/store\/v\d+\/links\//.test(p)) {
|
|
97
76
|
return deps.viaLauncher ? { kind: "pnpm" } : { kind: "skip", reason: "pnpm-direct" };
|
|
98
77
|
}
|
|
99
|
-
// $BUN_INSTALL/install/global — ~/.bun by default, but BUN_INSTALL is often
|
|
100
|
-
// customized, so match the layout rather than the directory name.
|
|
101
78
|
if (/\/install\/global\/node_modules\/codiedev\/dist\/hook\.js$/.test(p))
|
|
102
79
|
return { kind: "bun" };
|
|
103
|
-
// npm global: <prefix>/lib/node_modules/codiedev/dist/hook.js on unix,
|
|
104
|
-
// <prefix>/node_modules/codiedev/dist/hook.js on Windows.
|
|
105
80
|
const unix = p.match(/^(.*)\/lib\/node_modules\/codiedev\/dist\/hook\.js$/);
|
|
106
81
|
if (unix && deps.platform !== "win32")
|
|
107
82
|
return { kind: "npm", prefix: unix[1] };
|
|
108
83
|
const win = p.match(/^(.*)\/node_modules\/codiedev\/dist\/hook\.js$/);
|
|
109
84
|
if (win && deps.platform === "win32")
|
|
110
85
|
return { kind: "npm", prefix: win[1] };
|
|
111
|
-
// A repo checkout, a project-local install, or a layout we don't know.
|
|
112
86
|
return { kind: "skip", reason: "unmanaged" };
|
|
113
87
|
}
|
|
114
88
|
function isSelfUpdateDue(state, nowMs) {
|
|
115
|
-
return !state || nowMs - state.lastAttemptAt >
|
|
89
|
+
return !state || nowMs - state.lastAttemptAt > SELF_UPDATE_INTERVAL_MS;
|
|
116
90
|
}
|
|
117
91
|
function statePath() {
|
|
118
92
|
return path.join((0, configDir_1.codiedevStateDir)(), ".self-update.json");
|
|
@@ -139,11 +113,6 @@ function writeState(state) {
|
|
|
139
113
|
return false;
|
|
140
114
|
}
|
|
141
115
|
}
|
|
142
|
-
/**
|
|
143
|
-
* Called on every hook invocation, so the not-due path is one small file read.
|
|
144
|
-
* Stamps the attempt before spawning so a burst of parallel hooks spawns one
|
|
145
|
-
* child, not one each; the child's lock covers whatever still slips through.
|
|
146
|
-
*/
|
|
147
116
|
function maybeSpawnSelfUpdate(hookEntry) {
|
|
148
117
|
try {
|
|
149
118
|
if (!hookEntry || process.env.CODIEDEV_NO_AUTO_UPDATE || process.env.CODIEDEV_NO_UPDATE_CHECK)
|
|
@@ -156,24 +125,16 @@ function maybeSpawnSelfUpdate(hookEntry) {
|
|
|
156
125
|
const child = (0, child_process_1.spawn)(process.execPath, [hookEntry, "self-update"], {
|
|
157
126
|
detached: true,
|
|
158
127
|
stdio: "ignore",
|
|
159
|
-
// detached on Windows opens a console window unless hidden.
|
|
160
128
|
windowsHide: true,
|
|
161
129
|
});
|
|
162
130
|
child.unref();
|
|
163
131
|
}
|
|
164
132
|
catch {
|
|
165
|
-
// Best-effort; a failed spawn retries tomorrow.
|
|
166
133
|
}
|
|
167
134
|
}
|
|
168
135
|
function instructionsVersionPath() {
|
|
169
136
|
return path.join((0, configDir_1.codiedevStateDir)(), ".instructions-version");
|
|
170
137
|
}
|
|
171
|
-
/**
|
|
172
|
-
* First hook call on a new CLI version (self-updated or installed by hand)
|
|
173
|
-
* re-renders the codiedev block in the harness instruction files, so they
|
|
174
|
-
* stop listing commands this version no longer has. The steady-state cost is
|
|
175
|
-
* one small file read. Honors the same opt-outs as the self-update.
|
|
176
|
-
*/
|
|
177
138
|
function maybeRefreshInstructions(refresh = utils_1.refreshInstalledInstructions) {
|
|
178
139
|
if (process.env.CODIEDEV_NO_AUTO_UPDATE || process.env.CODIEDEV_NO_UPDATE_CHECK)
|
|
179
140
|
return;
|
|
@@ -184,7 +145,6 @@ function maybeRefreshInstructions(refresh = utils_1.refreshInstalledInstructions
|
|
|
184
145
|
return;
|
|
185
146
|
}
|
|
186
147
|
catch {
|
|
187
|
-
// No marker yet: first run on a version that ships this check.
|
|
188
148
|
}
|
|
189
149
|
const refreshed = refresh();
|
|
190
150
|
fs.mkdirSync((0, configDir_1.codiedevStateDir)(), { recursive: true });
|
|
@@ -199,7 +159,6 @@ function maybeRefreshInstructions(refresh = utils_1.refreshInstalledInstructions
|
|
|
199
159
|
}
|
|
200
160
|
}
|
|
201
161
|
catch {
|
|
202
|
-
// Best-effort; retried on the next hook call.
|
|
203
162
|
}
|
|
204
163
|
}
|
|
205
164
|
function acquireLock() {
|
|
@@ -217,7 +176,6 @@ function acquireLock() {
|
|
|
217
176
|
}
|
|
218
177
|
}
|
|
219
178
|
catch {
|
|
220
|
-
// Lost the race to another child.
|
|
221
179
|
}
|
|
222
180
|
return false;
|
|
223
181
|
}
|
|
@@ -225,8 +183,6 @@ function acquireLock() {
|
|
|
225
183
|
function detectContainer(env) {
|
|
226
184
|
if (env.KUBERNETES_SERVICE_HOST)
|
|
227
185
|
return true;
|
|
228
|
-
// /run/.containerenv is podman's marker (e.g. Sonifi's dev containers);
|
|
229
|
-
// cgroup v2 hosts report a bare "0::/" there, so the cgroup probe misses it.
|
|
230
186
|
if (fs.existsSync("/.dockerenv") || fs.existsSync("/run/.containerenv"))
|
|
231
187
|
return true;
|
|
232
188
|
try {
|
|
@@ -262,18 +218,11 @@ async function fetchLatest(env) {
|
|
|
262
218
|
}
|
|
263
219
|
function installCommand(plan, version, env) {
|
|
264
220
|
const spec = `${PKG}@${version}`;
|
|
265
|
-
// Pass an env-level registry override explicitly so the install always
|
|
266
|
-
// hits the registry fetchLatest just read from (not every manager honors
|
|
267
|
-
// npm_config_registry for global installs).
|
|
268
221
|
const configured = env.npm_config_registry || env.NPM_CONFIG_REGISTRY;
|
|
269
222
|
const registry = configured ? ["--registry", registryBase(env)] : [];
|
|
270
223
|
switch (plan.kind) {
|
|
271
224
|
case "npm": {
|
|
272
225
|
const args = ["i", "-g", "--prefix", plan.prefix, "--no-fund", "--no-audit", ...registry, spec];
|
|
273
|
-
// Run the npm that ships beside the node running us (it owns this
|
|
274
|
-
// prefix even when PATH resolves a different node), through its JS
|
|
275
|
-
// entry. That avoids spawning npm.cmd, which on Windows needs a shell
|
|
276
|
-
// and would split a prefix like C:\Users\First Last\… on the space.
|
|
277
226
|
const execDir = path.dirname(process.execPath);
|
|
278
227
|
const npmCli = [
|
|
279
228
|
path.join(execDir, "node_modules", "npm", "bin", "npm-cli.js"),
|
|
@@ -284,7 +233,6 @@ function installCommand(plan, version, env) {
|
|
|
284
233
|
return { cmd: process.platform === "win32" ? "npm.cmd" : "npm", args, shell: process.platform === "win32" };
|
|
285
234
|
}
|
|
286
235
|
case "pnpm":
|
|
287
|
-
// pnpm on Windows is usually a .cmd shim; these args carry no paths.
|
|
288
236
|
return { cmd: "pnpm", args: ["add", "-g", ...registry, spec], shell: process.platform === "win32" };
|
|
289
237
|
case "bun":
|
|
290
238
|
return { cmd: "bun", args: ["add", "-g", ...registry, spec] };
|
|
@@ -292,14 +240,7 @@ function installCommand(plan, version, env) {
|
|
|
292
240
|
return null;
|
|
293
241
|
}
|
|
294
242
|
}
|
|
295
|
-
// package.json "bin" names. npm writes a .cmd, a .ps1 and a bare shim for each.
|
|
296
243
|
exports.BIN_NAMES = ["codiedev", "codiedev-hook", "codie"];
|
|
297
|
-
/**
|
|
298
|
-
* The .ps1 shims missing from a Windows npm prefix. The IT kit deletes them so
|
|
299
|
-
* PowerShell falls back to the .cmd shims, which run under the Restricted
|
|
300
|
-
* execution policy Windows client machines default to; `npm i -g` puts them
|
|
301
|
-
* back, so an update must delete again exactly the ones that were gone.
|
|
302
|
-
*/
|
|
303
244
|
function missingPs1Shims(prefix, exists = fs.existsSync) {
|
|
304
245
|
return exports.BIN_NAMES.map((name) => path.join(prefix, `${name}.ps1`)).filter((p) => !exists(p));
|
|
305
246
|
}
|
|
@@ -312,12 +253,6 @@ function readVersionAt(hookScript) {
|
|
|
312
253
|
return null;
|
|
313
254
|
}
|
|
314
255
|
}
|
|
315
|
-
/**
|
|
316
|
-
* Where the just-installed copy lives. npm/bun reinstall in place. pnpm's
|
|
317
|
-
* `root -g` is <root>/node_modules up to v10 but the bare global/v11 parent
|
|
318
|
-
* from v11 on, with each install in a hashed child — so check both shapes and
|
|
319
|
-
* take the copy that is actually at the version we just installed.
|
|
320
|
-
*/
|
|
321
256
|
function findInstalledHookScript(plan, hookEntry, version, pnpmRoot = pnpmGlobalRoot) {
|
|
322
257
|
if (plan.kind !== "pnpm")
|
|
323
258
|
return readVersionAt(hookEntry) === version ? hookEntry : null;
|
|
@@ -331,7 +266,6 @@ function findInstalledHookScript(plan, hookEntry, version, pnpmRoot = pnpmGlobal
|
|
|
331
266
|
}
|
|
332
267
|
}
|
|
333
268
|
catch {
|
|
334
|
-
// root vanished between calls
|
|
335
269
|
}
|
|
336
270
|
for (const candidate of candidates) {
|
|
337
271
|
if (readVersionAt(candidate) !== version)
|
|
@@ -340,7 +274,6 @@ function findInstalledHookScript(plan, hookEntry, version, pnpmRoot = pnpmGlobal
|
|
|
340
274
|
return fs.realpathSync(candidate);
|
|
341
275
|
}
|
|
342
276
|
catch {
|
|
343
|
-
// dangling link; keep looking
|
|
344
277
|
}
|
|
345
278
|
}
|
|
346
279
|
return null;
|
|
@@ -355,7 +288,6 @@ function pnpmGlobalRoot() {
|
|
|
355
288
|
const dir = root.status === 0 ? root.stdout.trim() : "";
|
|
356
289
|
return dir || null;
|
|
357
290
|
}
|
|
358
|
-
/** Body of the detached `codiedev-hook self-update` child. Never throws. */
|
|
359
291
|
async function runSelfUpdate(hookEntry) {
|
|
360
292
|
const env = process.env;
|
|
361
293
|
const now = Date.now();
|
|
@@ -396,8 +328,6 @@ async function runSelfUpdate(hookEntry) {
|
|
|
396
328
|
if (plan.kind === "skip")
|
|
397
329
|
return finish(`skip:${plan.reason}`);
|
|
398
330
|
if (!acquireLock()) {
|
|
399
|
-
// Another child is mid-install and owns the state file; overwriting it
|
|
400
|
-
// here would report "skip:locked" while that install is still running.
|
|
401
331
|
(0, captureLog_1.appendCaptureLog)({ stage: "self-update", sessionId: undefined, outcome: "ok", detail: "result=skip:locked" });
|
|
402
332
|
return { lastAttemptAt: now, lastResult: "skip:locked" };
|
|
403
333
|
}
|
|
@@ -426,12 +356,8 @@ async function runSelfUpdate(hookEntry) {
|
|
|
426
356
|
fs.rmSync(shim, { force: true });
|
|
427
357
|
}
|
|
428
358
|
catch {
|
|
429
|
-
// Best-effort: a leftover .ps1 only matters under a Restricted policy.
|
|
430
359
|
}
|
|
431
360
|
}
|
|
432
|
-
// Re-point the launcher. npm/bun reinstall in place; pnpm lands in a new
|
|
433
|
-
// hashed dir. Only switch once the new copy is on disk at the new version,
|
|
434
|
-
// so a half-finished install can never strand the hooks.
|
|
435
361
|
const installed = findInstalledHookScript(plan, hookScriptReal, latest);
|
|
436
362
|
if (!installed) {
|
|
437
363
|
return finish("error:not-found-after-install", { toVersion: latest });
|
|
@@ -445,7 +371,6 @@ async function runSelfUpdate(hookEntry) {
|
|
|
445
371
|
fs.rmSync(lockPath(), { recursive: true, force: true });
|
|
446
372
|
}
|
|
447
373
|
catch {
|
|
448
|
-
// A stale lock self-expires after LOCK_STALE_MS.
|
|
449
374
|
}
|
|
450
375
|
}
|
|
451
376
|
}
|
package/dist/skillMarker.js
CHANGED
|
@@ -1,33 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// Skill identity marker. Two authors can each publish a skill with the same
|
|
3
|
-
// name ("/ticket"); a session's transcript only records the name it ran. A
|
|
4
|
-
// company skill written to disk therefore carries the artifact it came from:
|
|
5
|
-
//
|
|
6
|
-
// <!-- codiedev:artifact=<artifact id> -->
|
|
7
|
-
//
|
|
8
|
-
// appended after the body (frontmatter untouched, invisible when rendered).
|
|
9
|
-
// When the harness loads the skill, the marker lands in the transcript and
|
|
10
|
-
// parseCaptureSignals reports it as signals.skillInvocationArtifacts, so the
|
|
11
|
-
// portal attributes the run to the exact skill. `push` strips it, so a
|
|
12
|
-
// re-pushed copy never claims someone else's artifact id.
|
|
13
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
3
|
exports.looksLikeSkill = looksLikeSkill;
|
|
15
4
|
exports.stripSkillMarker = stripSkillMarker;
|
|
16
5
|
exports.stampSkillMarker = stampSkillMarker;
|
|
17
6
|
const ID = /^[a-z0-9]{16,64}$/i;
|
|
18
7
|
const LINE = /^[ \t]*<!--\s*codiedev:artifact=[a-z0-9]+\s*-->[ \t]*(?:\r?\n|$)/gim;
|
|
19
|
-
/** Is this a SKILL.md-style file (frontmatter with name + description)? */
|
|
20
8
|
function looksLikeSkill(markdown) {
|
|
21
9
|
const fm = markdown.match(/^?---\r?\n([\s\S]*?)\r?\n---/);
|
|
22
10
|
if (!fm)
|
|
23
11
|
return false;
|
|
24
12
|
return /^name\s*:/im.test(fm[1]) && /^description\s*:/im.test(fm[1]);
|
|
25
13
|
}
|
|
26
|
-
/** Remove every marker line (idempotent). */
|
|
27
14
|
function stripSkillMarker(markdown) {
|
|
28
15
|
return markdown.replace(LINE, "");
|
|
29
16
|
}
|
|
30
|
-
/** Stamp (or re-stamp) the marker. Leaves the text alone for a bad id. */
|
|
31
17
|
function stampSkillMarker(markdown, artifactId) {
|
|
32
18
|
if (!artifactId || !ID.test(artifactId))
|
|
33
19
|
return markdown;
|
package/dist/subagents.js
CHANGED
|
@@ -12,27 +12,12 @@ const node_fs_1 = __importDefault(require("node:fs"));
|
|
|
12
12
|
const node_path_1 = __importDefault(require("node:path"));
|
|
13
13
|
const captureSignals_1 = require("./captureSignals");
|
|
14
14
|
const transcriptModels_1 = require("./transcriptModels");
|
|
15
|
-
/**
|
|
16
|
-
* Claude Code writes each subagent's transcript next to its parent's:
|
|
17
|
-
*
|
|
18
|
-
* ~/.claude/projects/<project>/<sessionId>.jsonl (parent)
|
|
19
|
-
* ~/.claude/projects/<project>/<sessionId>/subagents/agent-*.jsonl
|
|
20
|
-
*
|
|
21
|
-
* Lines there carry `isSidechain: true` and the parent's sessionId. They are
|
|
22
|
-
* part of the parent session's work, not sessions of their own: their skill
|
|
23
|
-
* runs, tool calls and token usage fold into the parent's signals and usage,
|
|
24
|
-
* and they are never uploaded separately. Other harnesses (Codex, Codie,
|
|
25
|
-
* Cursor) keep sub-agents inside the one transcript or don't have them, so
|
|
26
|
-
* this is Claude Code only.
|
|
27
|
-
*/
|
|
28
15
|
exports.SUBAGENT_LIMITS = { files: 20, bytes: 20 * 1024 * 1024 };
|
|
29
16
|
function subagentDir(transcriptPath, sessionId) {
|
|
30
17
|
const dir = node_path_1.default.dirname(transcriptPath);
|
|
31
18
|
const id = sessionId || node_path_1.default.basename(transcriptPath).replace(/\.jsonl$/i, "");
|
|
32
19
|
return node_path_1.default.join(dir, id, "subagents");
|
|
33
20
|
}
|
|
34
|
-
/** Read the session's subagent transcripts in full, up to 20 files / 20 MB
|
|
35
|
-
* in total (oldest first); anything past that is counted as truncated. */
|
|
36
21
|
function readSubagentTranscripts(transcriptPath, sessionId, limits = exports.SUBAGENT_LIMITS) {
|
|
37
22
|
const dir = subagentDir(transcriptPath, sessionId);
|
|
38
23
|
let names;
|
|
@@ -73,8 +58,6 @@ function readSubagentTranscripts(transcriptPath, sessionId, limits = exports.SUB
|
|
|
73
58
|
}
|
|
74
59
|
return { contents, count: files.length, truncated };
|
|
75
60
|
}
|
|
76
|
-
/** Parent signals plus every subagent's skill runs, pulls and tool calls.
|
|
77
|
-
* Launch values, timing and record counts stay the parent's own. */
|
|
78
61
|
function foldSubagentSignals(parent, subs, source) {
|
|
79
62
|
if (subs.count === 0)
|
|
80
63
|
return parent;
|
|
@@ -121,7 +104,6 @@ function foldSubagentSignals(parent, subs, source) {
|
|
|
121
104
|
truncated,
|
|
122
105
|
};
|
|
123
106
|
}
|
|
124
|
-
/** Parent model usage plus each subagent's, summed per model. */
|
|
125
107
|
function foldSubagentModelUsage(parent, subs, source) {
|
|
126
108
|
if (subs.contents.length === 0)
|
|
127
109
|
return parent;
|
package/dist/teamSkillContext.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.TEAM_SKILL_CONTEXT = void 0;
|
|
4
4
|
exports.teamSkillSessionOutput = teamSkillSessionOutput;
|
|
5
|
-
/** Session-start context uses each client's supported output contract. */
|
|
6
5
|
exports.TEAM_SKILL_CONTEXT = `This machine is connected to Codiedev, the team's artifact and skill library.
|
|
7
6
|
Before a substantial coding task, run codiedev search "<brief task description>" and reuse a relevant team skill by running codiedev pull <exact-key> and following its instructions. If no skill fits, continue the task.
|
|
8
7
|
Use codiedev push <file.md> to share an artifact when asked, codiedev ask "<question>" for team knowledge, and codiedev inbox to check messages. Use codiedev --help for other commands. If codiedev is unavailable, use npx codiedev@latest.`;
|