codiedev 0.9.75 → 0.9.77
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/codieLauncher.d.ts +7 -1
- package/dist/codieLauncher.js +24 -4
- package/dist/commands/doctor.js +4 -2
- package/dist/piRuntime.d.ts +1 -0
- package/dist/piRuntime.js +33 -20
- package/dist/selfUpdate.d.ts +8 -0
- package/dist/selfUpdate.js +22 -0
- package/package.json +1 -1
package/dist/codieLauncher.d.ts
CHANGED
|
@@ -69,10 +69,16 @@ export declare function resolveCapturePlugin({ homeDir, existsSync, }: {
|
|
|
69
69
|
homeDir: string;
|
|
70
70
|
existsSync: (candidate: string) => boolean;
|
|
71
71
|
}): string;
|
|
72
|
-
|
|
72
|
+
/**
|
|
73
|
+
* The account's approved models. Every `codie` session starts here, so one
|
|
74
|
+
* dropped connection or slow gateway reply would end the session before it
|
|
75
|
+
* began; anything but a definite rejection is retried once.
|
|
76
|
+
*/
|
|
77
|
+
export declare function fetchApprovedCatalog({ baseUrl, key, fetchImpl, retryDelayMs, }: {
|
|
73
78
|
baseUrl?: string;
|
|
74
79
|
key: string;
|
|
75
80
|
fetchImpl?: typeof fetch;
|
|
81
|
+
retryDelayMs?: number;
|
|
76
82
|
}): Promise<CatalogModel[]>;
|
|
77
83
|
export declare function parseCodieArgs(argv: string[]): {
|
|
78
84
|
args: string[];
|
package/dist/codieLauncher.js
CHANGED
|
@@ -349,9 +349,29 @@ function resolveCapturePlugin({ homeDir, existsSync, }) {
|
|
|
349
349
|
}
|
|
350
350
|
return (0, url_1.pathToFileURL)(capturePath).href;
|
|
351
351
|
}
|
|
352
|
-
|
|
352
|
+
// A definite answer from the gateway (harness off, token rejected): retrying
|
|
353
|
+
// can't change it.
|
|
354
|
+
class CatalogRejected extends Error {
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* The account's approved models. Every `codie` session starts here, so one
|
|
358
|
+
* dropped connection or slow gateway reply would end the session before it
|
|
359
|
+
* began; anything but a definite rejection is retried once.
|
|
360
|
+
*/
|
|
361
|
+
async function fetchApprovedCatalog({ baseUrl, key, fetchImpl = fetch, retryDelayMs = 1_000, }) {
|
|
362
|
+
try {
|
|
363
|
+
return await fetchCatalogOnce(baseUrl, key, fetchImpl);
|
|
364
|
+
}
|
|
365
|
+
catch (error) {
|
|
366
|
+
if (error instanceof CatalogRejected)
|
|
367
|
+
throw error;
|
|
368
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
|
|
369
|
+
return fetchCatalogOnce(baseUrl, key, fetchImpl);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
async function fetchCatalogOnce(baseUrl, key, fetchImpl) {
|
|
353
373
|
const controller = new AbortController();
|
|
354
|
-
const timeout = setTimeout(() => controller.abort(),
|
|
374
|
+
const timeout = setTimeout(() => controller.abort(), 10_000);
|
|
355
375
|
try {
|
|
356
376
|
const response = await fetchImpl(`${cleanBaseUrl(baseUrl)}/models`, {
|
|
357
377
|
headers: { Authorization: `Bearer ${key}` },
|
|
@@ -361,11 +381,11 @@ async function fetchApprovedCatalog({ baseUrl, key, fetchImpl = fetch, }) {
|
|
|
361
381
|
// whose gateway is still switched off. Those developers must get an
|
|
362
382
|
// answer, not an HTTP status.
|
|
363
383
|
if (response.status === 403) {
|
|
364
|
-
throw new
|
|
384
|
+
throw new CatalogRejected("The Codie harness is not enabled for your company yet. Ask your Codiedev admin to turn it on — " +
|
|
365
385
|
"your session capture keeps working in the meantime.");
|
|
366
386
|
}
|
|
367
387
|
if (response.status === 401) {
|
|
368
|
-
throw new
|
|
388
|
+
throw new CatalogRejected("Your Codiedev token was rejected. Run `codiedev connect` to relink this machine.");
|
|
369
389
|
}
|
|
370
390
|
if (!response.ok)
|
|
371
391
|
throw new Error(`model catalog returned ${response.status}`);
|
package/dist/commands/doctor.js
CHANGED
|
@@ -310,10 +310,12 @@ async function runDoctor(_args) {
|
|
|
310
310
|
const workspaceMode = workspaceScan.repoCount > 0;
|
|
311
311
|
checks.push({
|
|
312
312
|
name: "git on PATH",
|
|
313
|
-
|
|
313
|
+
// A warning, not a failure: sessions still capture without git, they just
|
|
314
|
+
// aren't tagged to a repo. Non-engineer installs often skip git entirely.
|
|
315
|
+
status: readiness.gitOnPath ? "pass" : "warn",
|
|
314
316
|
detail: readiness.gitOnPath
|
|
315
317
|
? undefined
|
|
316
|
-
: "not found — capture can't
|
|
318
|
+
: "not found — sessions still capture but can't be tagged to a repo (install git if you work in repos)",
|
|
317
319
|
});
|
|
318
320
|
checks.push({
|
|
319
321
|
name: "Inside a git work tree (current dir)",
|
package/dist/piRuntime.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ export interface PiRuntimeDeps {
|
|
|
16
16
|
rename?: (from: string, to: string) => void;
|
|
17
17
|
remove?: (target: string) => void;
|
|
18
18
|
log?: (message: string) => void;
|
|
19
|
+
sleep?: (ms: number) => void;
|
|
19
20
|
}
|
|
20
21
|
/**
|
|
21
22
|
* The pi CLI entry to run, installing the pinned version first if it is
|
package/dist/piRuntime.js
CHANGED
|
@@ -70,6 +70,10 @@ function installedPiEntry(installDir, readFile = (f) => fs.readFileSync(f, "utf8
|
|
|
70
70
|
return null;
|
|
71
71
|
}
|
|
72
72
|
}
|
|
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
|
+
const INSTALL_ATTEMPTS = 2;
|
|
76
|
+
const INSTALL_RETRY_DELAY_MS = 5_000;
|
|
73
77
|
/**
|
|
74
78
|
* The pi CLI entry to run, installing the pinned version first if it is
|
|
75
79
|
* missing or a different version. Staged then renamed, so an interrupted
|
|
@@ -85,10 +89,10 @@ function ensurePiRuntime(deps) {
|
|
|
85
89
|
const remove = deps.remove ?? ((target) => fs.rmSync(target, { recursive: true, force: true }));
|
|
86
90
|
const rename = deps.rename ?? fs.renameSync;
|
|
87
91
|
const log = deps.log ?? ((message) => console.error(message));
|
|
88
|
-
const
|
|
92
|
+
const makeStagingDir = deps.makeStagingDir ?? (() => {
|
|
89
93
|
fs.mkdirSync(deps.stateDir, { recursive: true });
|
|
90
94
|
return fs.mkdtempSync(path.join(deps.stateDir, ".runtime-pi-"));
|
|
91
|
-
})
|
|
95
|
+
});
|
|
92
96
|
const run = deps.run ?? ((args) => {
|
|
93
97
|
const result = (0, child_process_1.spawnSync)(process.platform === "win32" ? "npm.cmd" : "npm", args, {
|
|
94
98
|
encoding: "utf8", stdio: ["ignore", "ignore", "pipe"], shell: process.platform === "win32",
|
|
@@ -97,26 +101,35 @@ function ensurePiRuntime(deps) {
|
|
|
97
101
|
throw result.error;
|
|
98
102
|
return { status: result.status, stderr: result.stderr ?? "" };
|
|
99
103
|
});
|
|
104
|
+
const sleep = deps.sleep ?? ((ms) => Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms));
|
|
100
105
|
log(`Installing pi (${exports.PI_RUNTIME_SPEC}). This runs once, and only for \`codie --pi\`.`);
|
|
101
|
-
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
for (let attempt = 1;; attempt++) {
|
|
107
|
+
const staging = makeStagingDir();
|
|
108
|
+
try {
|
|
109
|
+
const result = run((0, codieRuntimeInstall_1.buildRuntimeInstallArgs)(staging, exports.PI_RUNTIME_SPEC));
|
|
110
|
+
if (result.status !== 0)
|
|
111
|
+
throw new Error(result.stderr?.trim() || `npm exited with ${result.status}`);
|
|
112
|
+
// Trust the artifact, not the exit code.
|
|
113
|
+
const staged = installedPiEntry(staging, readFile);
|
|
114
|
+
if (!staged || !exists(staged)) {
|
|
115
|
+
throw new Error(`the install did not produce pi. Check that ${exports.PI_RUNTIME_SPEC} is available from your npm registry.`);
|
|
116
|
+
}
|
|
117
|
+
remove(installDir);
|
|
118
|
+
rename(staging, installDir);
|
|
119
|
+
break;
|
|
109
120
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
121
|
+
catch (error) {
|
|
122
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
123
|
+
if (attempt >= INSTALL_ATTEMPTS)
|
|
124
|
+
throw new Error(`Couldn't install pi: ${message}`);
|
|
125
|
+
log(`pi install failed (${message.split("\n")[0]}); retrying.`);
|
|
126
|
+
}
|
|
127
|
+
finally {
|
|
128
|
+
// No-op after a successful promote; otherwise it keeps a ~200MB staging
|
|
129
|
+
// dir from being orphaned.
|
|
130
|
+
remove(staging);
|
|
131
|
+
}
|
|
132
|
+
sleep(INSTALL_RETRY_DELAY_MS);
|
|
120
133
|
}
|
|
121
134
|
const entry = installedPiEntry(installDir, readFile);
|
|
122
135
|
if (!entry)
|
package/dist/selfUpdate.d.ts
CHANGED
|
@@ -45,6 +45,14 @@ export declare function maybeSpawnSelfUpdate(hookEntry: string | undefined): voi
|
|
|
45
45
|
* one small file read. Honors the same opt-outs as the self-update.
|
|
46
46
|
*/
|
|
47
47
|
export declare function maybeRefreshInstructions(refresh?: () => string[]): void;
|
|
48
|
+
export declare const BIN_NAMES: readonly ["codiedev", "codiedev-hook", "codie"];
|
|
49
|
+
/**
|
|
50
|
+
* The .ps1 shims missing from a Windows npm prefix. The IT kit deletes them so
|
|
51
|
+
* PowerShell falls back to the .cmd shims, which run under the Restricted
|
|
52
|
+
* execution policy Windows client machines default to; `npm i -g` puts them
|
|
53
|
+
* back, so an update must delete again exactly the ones that were gone.
|
|
54
|
+
*/
|
|
55
|
+
export declare function missingPs1Shims(prefix: string, exists?: (p: string) => boolean): string[];
|
|
48
56
|
/**
|
|
49
57
|
* Where the just-installed copy lives. npm/bun reinstall in place. pnpm's
|
|
50
58
|
* `root -g` is <root>/node_modules up to v10 but the bare global/v11 parent
|
package/dist/selfUpdate.js
CHANGED
|
@@ -44,11 +44,13 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
44
44
|
};
|
|
45
45
|
})();
|
|
46
46
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
47
|
+
exports.BIN_NAMES = void 0;
|
|
47
48
|
exports.planSelfUpdate = planSelfUpdate;
|
|
48
49
|
exports.isSelfUpdateDue = isSelfUpdateDue;
|
|
49
50
|
exports.readSelfUpdateState = readSelfUpdateState;
|
|
50
51
|
exports.maybeSpawnSelfUpdate = maybeSpawnSelfUpdate;
|
|
51
52
|
exports.maybeRefreshInstructions = maybeRefreshInstructions;
|
|
53
|
+
exports.missingPs1Shims = missingPs1Shims;
|
|
52
54
|
exports.findInstalledHookScript = findInstalledHookScript;
|
|
53
55
|
exports.runSelfUpdate = runSelfUpdate;
|
|
54
56
|
const fs = __importStar(require("fs"));
|
|
@@ -290,6 +292,17 @@ function installCommand(plan, version, env) {
|
|
|
290
292
|
return null;
|
|
291
293
|
}
|
|
292
294
|
}
|
|
295
|
+
// package.json "bin" names. npm writes a .cmd, a .ps1 and a bare shim for each.
|
|
296
|
+
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
|
+
function missingPs1Shims(prefix, exists = fs.existsSync) {
|
|
304
|
+
return exports.BIN_NAMES.map((name) => path.join(prefix, `${name}.ps1`)).filter((p) => !exists(p));
|
|
305
|
+
}
|
|
293
306
|
function readVersionAt(hookScript) {
|
|
294
307
|
try {
|
|
295
308
|
const pkg = JSON.parse(fs.readFileSync(path.join(path.dirname(path.dirname(hookScript)), "package.json"), "utf8"));
|
|
@@ -397,6 +410,7 @@ async function runSelfUpdate(hookEntry) {
|
|
|
397
410
|
const install = installCommand(plan, latest, env);
|
|
398
411
|
if (!install)
|
|
399
412
|
return finish("skip:no-installer");
|
|
413
|
+
const droppedShims = plan.kind === "npm" && process.platform === "win32" ? missingPs1Shims(plan.prefix) : [];
|
|
400
414
|
const result = (0, child_process_1.spawnSync)(install.cmd, install.args, {
|
|
401
415
|
stdio: "ignore",
|
|
402
416
|
timeout: INSTALL_TIMEOUT_MS,
|
|
@@ -407,6 +421,14 @@ async function runSelfUpdate(hookEntry) {
|
|
|
407
421
|
if (result.error || result.status !== 0) {
|
|
408
422
|
return finish(`error:install-exit-${result.status ?? "spawn"}`, { toVersion: latest });
|
|
409
423
|
}
|
|
424
|
+
for (const shim of droppedShims) {
|
|
425
|
+
try {
|
|
426
|
+
fs.rmSync(shim, { force: true });
|
|
427
|
+
}
|
|
428
|
+
catch {
|
|
429
|
+
// Best-effort: a leftover .ps1 only matters under a Restricted policy.
|
|
430
|
+
}
|
|
431
|
+
}
|
|
410
432
|
// Re-point the launcher. npm/bun reinstall in place; pnpm lands in a new
|
|
411
433
|
// hashed dir. Only switch once the new copy is on disk at the new version,
|
|
412
434
|
// so a half-finished install can never strand the hooks.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codiedev",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.77",
|
|
4
4
|
"description": "Connect Claude Code, Codex, Cursor, OpenCode, or VS Code Copilot to Codiedev for team session capture and artifact collaboration — and run the governed Codie harness",
|
|
5
5
|
"bin": {
|
|
6
6
|
"codiedev": "dist/cli.js",
|