codiedev 0.9.73 → 0.9.76

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/cli.js CHANGED
@@ -31,6 +31,7 @@ const send_1 = require("./commands/send");
31
31
  const capture_1 = require("./commands/capture");
32
32
  const pack_1 = require("./commands/pack");
33
33
  const traces_1 = require("./commands/traces");
34
+ const evals_1 = require("./commands/evals");
34
35
  // --- starter packs phase 2 ---
35
36
  const hookGate_1 = require("./packs/hookGate");
36
37
  const sync_1 = require("./packs/sync");
@@ -94,11 +95,13 @@ Starter packs:
94
95
 
95
96
  Traces (agents on the gateway):
96
97
  codiedev traces agents Agents you maintain, with saved test cases
97
- codiedev traces cases <agent> [--suite name] [--model id]
98
- Pull an agent's test cases (or one suite)
98
+ codiedev traces cases <agent> [--dataset name] [--model id]
99
+ Pull an agent's test cases (or one dataset)
99
100
  into this repo for your coding agent to
100
101
  run, optionally on another model
101
102
  codiedev traces report <results.json> Send the results back to Traces
103
+ codiedev evals report <run.json> File one variant's eval scores under an experiment
104
+ codiedev evals last <subject> Latest experiment on a subject + its champion
102
105
 
103
106
  Discovery:
104
107
  codiedev search "<query>" Semantic search across the team's
@@ -162,6 +165,7 @@ status sync never weakens it.
162
165
  const COMMAND_HELP = {
163
166
  pack: pack_1.PACK_HELP,
164
167
  traces: traces_1.TRACES_HELP,
168
+ evals: evals_1.EVALS_HELP,
165
169
  connect: `
166
170
  codiedev connect — link your agent CLI to Codiedev
167
171
 
@@ -528,6 +532,9 @@ async function main() {
528
532
  case "traces":
529
533
  await (0, traces_1.runTraces)(rest);
530
534
  return;
535
+ case "evals":
536
+ await (0, evals_1.runEvals)(rest);
537
+ return;
531
538
  case "share":
532
539
  await (0, share_1.runShare)(rest);
533
540
  return;
@@ -69,10 +69,16 @@ export declare function resolveCapturePlugin({ homeDir, existsSync, }: {
69
69
  homeDir: string;
70
70
  existsSync: (candidate: string) => boolean;
71
71
  }): string;
72
- export declare function fetchApprovedCatalog({ baseUrl, key, fetchImpl, }: {
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[];
@@ -349,9 +349,29 @@ function resolveCapturePlugin({ homeDir, existsSync, }) {
349
349
  }
350
350
  return (0, url_1.pathToFileURL)(capturePath).href;
351
351
  }
352
- async function fetchApprovedCatalog({ baseUrl, key, fetchImpl = fetch, }) {
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(), 5000);
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 Error("The Codie harness is not enabled for your company yet. Ask your Codiedev admin to turn it on — " +
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 Error("Your Codiedev token was rejected. Run `codiedev connect` to relink this machine.");
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}`);
@@ -0,0 +1,3 @@
1
+ import type { CodiedevConfig } from "../utils";
2
+ export declare const EVALS_HELP: string;
3
+ export declare function runEvals(args: string[], configOverride?: CodiedevConfig): Promise<void>;
@@ -0,0 +1,193 @@
1
+ "use strict";
2
+ // `codiedev evals report <run.json> [--harness name]`
3
+ // `codiedev evals last <subject> [--json]`
4
+ //
5
+ // Evals are experiments (a question about a subject: an agent, or a workload
6
+ // like session-summaries) and the runs that answer them, one per variant. The
7
+ // eval runs wherever it runs (a script, a coding agent); `report` files the
8
+ // scores under the experiment in Codiedev → Traces → Evals, shared with the
9
+ // team. `last` is where to start the next one: the latest experiment on the
10
+ // subject, its runs, and the champion the subject runs today.
11
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ var desc = Object.getOwnPropertyDescriptor(m, k);
14
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
15
+ desc = { enumerable: true, get: function() { return m[k]; } };
16
+ }
17
+ Object.defineProperty(o, k2, desc);
18
+ }) : (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ o[k2] = m[k];
21
+ }));
22
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
23
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
24
+ }) : function(o, v) {
25
+ o["default"] = v;
26
+ });
27
+ var __importStar = (this && this.__importStar) || (function () {
28
+ var ownKeys = function(o) {
29
+ ownKeys = Object.getOwnPropertyNames || function (o) {
30
+ var ar = [];
31
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
32
+ return ar;
33
+ };
34
+ return ownKeys(o);
35
+ };
36
+ return function (mod) {
37
+ if (mod && mod.__esModule) return mod;
38
+ var result = {};
39
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
40
+ __setModuleDefault(result, mod);
41
+ return result;
42
+ };
43
+ })();
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.EVALS_HELP = void 0;
46
+ exports.runEvals = runEvals;
47
+ const fs = __importStar(require("fs"));
48
+ const path = __importStar(require("path"));
49
+ const shared_1 = require("./shared");
50
+ exports.EVALS_HELP = `
51
+ codiedev evals — experiments and their runs, shared with the team
52
+
53
+ codiedev evals report <run.json> [--harness name]
54
+ File one variant's scores under an
55
+ experiment (created on first use)
56
+ codiedev evals last <subject> [--json] The latest experiment on a subject,
57
+ its runs, and the current champion
58
+
59
+ run.json:
60
+ {
61
+ "subject": "session-summaries", // agent name or workload
62
+ "question": "Is Terra medium as good as GLM high?",
63
+ "experimentId": "…", // optional, instead of subject + question
64
+ "dataset": "30 Signal & Code sessions", // optional
65
+ "run": {
66
+ "label": "terra-med-v2", "model": "openai/gpt-6.1-terra",
67
+ "provider": "openai", "reasoningEffort": "medium", "prompt": "summary_extract_v2",
68
+ "gitSha": "…", "isControl": false, "judgeModel": "anthropic/claude-sonnet-5.5",
69
+ "casesTotal": 30, "casesScored": 30, "errors": 0,
70
+ "score": 3.85, "metrics": { "fidelity": 3.6 },
71
+ "costPerCaseUsd": 0.026, "latencyMsAvg": 21000,
72
+ "wins": 20, "losses": 8, "ties": 2, "note": "…",
73
+ "cases": [{ "key": "case-1", "score": 4, "note": "…" }]
74
+ }
75
+ }
76
+
77
+ Scores and notes only: never put prompts, transcripts or outputs in it.
78
+ `.trim();
79
+ function flag(args, i, name) {
80
+ const a = args[i];
81
+ if (a === name && i + 1 < args.length)
82
+ return { value: args[i + 1], skip: 1 };
83
+ if (a.startsWith(`${name}=`))
84
+ return { value: a.slice(name.length + 1), skip: 0 };
85
+ return { skip: -1 };
86
+ }
87
+ function variant(run) {
88
+ return [run.model, run.reasoningEffort, run.prompt].filter(Boolean).join(" · ");
89
+ }
90
+ function fmtScore(n) {
91
+ return n === null ? "–" : n.toFixed(2);
92
+ }
93
+ function fmtCost(n) {
94
+ return n === null ? "–" : `$${n.toFixed(4)}`;
95
+ }
96
+ async function runReport(args, config) {
97
+ let file;
98
+ let harness;
99
+ for (let i = 0; i < args.length; i++) {
100
+ const f = flag(args, i, "--harness");
101
+ if (f.skip >= 0) {
102
+ harness = f.value;
103
+ i += f.skip;
104
+ continue;
105
+ }
106
+ if (!args[i].startsWith("-") && !file)
107
+ file = args[i];
108
+ }
109
+ if (!file) {
110
+ console.error("Usage: codiedev evals report <run.json> [--harness name]");
111
+ process.exit(1);
112
+ }
113
+ let body;
114
+ try {
115
+ body = JSON.parse(fs.readFileSync(path.resolve(process.cwd(), file), "utf8"));
116
+ }
117
+ catch (err) {
118
+ console.error(`Couldn't read ${file}: ${err.message}`);
119
+ process.exit(1);
120
+ }
121
+ if (!body.subject || !body.question || !body.run?.label || !body.run?.model || typeof body.run?.casesTotal !== "number") {
122
+ console.error(`${file} needs subject, question, and run.label, run.model, run.casesTotal. See: codiedev evals help`);
123
+ process.exit(1);
124
+ }
125
+ const start = Date.now();
126
+ try {
127
+ const res = await (0, shared_1.apiRequest)("POST", "/api/cli/evals/runs", {
128
+ config,
129
+ body: { ...body, run: { ...body.run, harness: harness ?? body.run.harness ?? undefined } },
130
+ });
131
+ (0, shared_1.recordAgentEvent)(config, { tool: "codiedev_evals_report", ok: true, latencyMs: Date.now() - start });
132
+ console.log(`✓ Reported ${body.run.label} on ${body.subject}${res.created ? " (new experiment)" : ""}: "${body.question}"`);
133
+ console.log(` experiment ${res.experimentId}. See it in Codiedev → Traces → Evals.`);
134
+ }
135
+ catch (err) {
136
+ const e = err;
137
+ (0, shared_1.recordAgentEvent)(config, { tool: "codiedev_evals_report", ok: false, latencyMs: Date.now() - start, error: e.message });
138
+ console.error(`Couldn't report: ${e.message}`);
139
+ process.exit(1);
140
+ }
141
+ }
142
+ async function runLast(args, config) {
143
+ const json = args.includes("--json");
144
+ const subject = args.find((a) => !a.startsWith("-"));
145
+ if (!subject) {
146
+ console.error("Usage: codiedev evals last <subject> [--json]");
147
+ process.exit(1);
148
+ }
149
+ let res;
150
+ try {
151
+ res = await (0, shared_1.apiRequest)("GET", `/api/cli/evals/last?subject=${encodeURIComponent(subject)}`, { config });
152
+ }
153
+ catch (err) {
154
+ const e = err;
155
+ console.error(e.status === 404 ? `No evals on ${subject} yet.` : `Couldn't load evals: ${e.message}`);
156
+ process.exit(1);
157
+ }
158
+ if (json) {
159
+ console.log(JSON.stringify(res, null, 2));
160
+ return;
161
+ }
162
+ const { experiment, runs, champion } = res;
163
+ if (champion) {
164
+ console.log(`Champion: ${champion.run.label} (${variant(champion.run)}), score ${fmtScore(champion.run.score)}, ${fmtCost(champion.run.costPerCaseUsd)}/case`);
165
+ if (champion.decisionNote)
166
+ console.log(` Why: ${champion.decisionNote}`);
167
+ }
168
+ else {
169
+ console.log("Champion: none picked yet");
170
+ }
171
+ console.log("");
172
+ console.log(`Latest experiment (${res.experiments} on ${experiment.subject}): ${experiment.question}`);
173
+ if (experiment.dataset)
174
+ console.log(` Dataset: ${experiment.dataset}`);
175
+ console.log(` id ${experiment.id}, by ${experiment.createdBy}, updated ${new Date(experiment.updatedAt).toISOString().slice(0, 16).replace("T", " ")}`);
176
+ console.log("");
177
+ for (const run of [...runs].sort((a, b) => a.ranAt - b.ranAt)) {
178
+ const h2h = run.wins !== null ? ` · ${run.wins}W/${run.losses ?? 0}L/${run.ties ?? 0}T` : "";
179
+ console.log(` ${run.isControl ? "[control] " : ""}${run.label.padEnd(24)} ${fmtScore(run.score).padStart(5)} ${fmtCost(run.costPerCaseUsd).padStart(8)}/case${h2h} ${variant(run)}`);
180
+ }
181
+ console.log("");
182
+ console.log(`Next run on this experiment: put "experimentId": "${experiment.id}" in run.json, then codiedev evals report run.json`);
183
+ }
184
+ async function runEvals(args, configOverride) {
185
+ const [sub, ...rest] = args;
186
+ if (sub === "report")
187
+ return runReport(rest, configOverride ?? (0, shared_1.requireConfig)());
188
+ if (sub === "last")
189
+ return runLast(rest, configOverride ?? (0, shared_1.requireConfig)());
190
+ console.log(exports.EVALS_HELP);
191
+ if (sub && sub !== "help")
192
+ process.exit(1);
193
+ }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  // `codiedev traces agents`
3
- // `codiedev traces cases <agent> [--suite name] [--model id] [--out dir] [--json]`
3
+ // `codiedev traces cases <agent> [--dataset name] [--model id] [--out dir] [--json]`
4
4
  // `codiedev traces report <results.json> [--harness name]`
5
5
  //
6
6
  // Test cases are runs an engineer saved from Codiedev → Traces. They run in
@@ -55,10 +55,10 @@ exports.TRACES_HELP = `
55
55
  codiedev traces — test cases saved from Codiedev → Traces
56
56
 
57
57
  codiedev traces agents Agents you maintain, with saved case counts
58
- codiedev traces cases <agent> [--suite name] [--case id[,id]] [--model id] [--out dir] [--json]
59
- Write an agent's cases (one suite, or just
58
+ codiedev traces cases <agent> [--dataset name] [--case id[,id]] [--model id] [--out dir] [--json]
59
+ Write an agent's cases (one dataset, or just
60
60
  the cases named) into this repo, default
61
- .codiedev/traces/<agent>[/<suite>]/, then
61
+ .codiedev/traces/<agent>[/<dataset>]/, then
62
62
  ask your coding agent to run them.
63
63
  --model runs them on another model, e.g.
64
64
  the replacement for a retiring one
@@ -140,7 +140,7 @@ function parseCasesArgs(args) {
140
140
  for (let i = 0; i < args.length; i++) {
141
141
  const a = args[i];
142
142
  let matched = false;
143
- for (const [name, key] of [["--out", "out"], ["-o", "out"], ["--suite", "suite"], ["--model", "model"], ["--case", "caseIds"]]) {
143
+ for (const [name, key] of [["--out", "out"], ["-o", "out"], ["--dataset", "suite"], ["--suite", "suite"], ["--model", "model"], ["--case", "caseIds"]]) {
144
144
  const f = flag(args, i, name);
145
145
  if (f.skip >= 0) {
146
146
  parsed[key] = f.value;
@@ -184,7 +184,7 @@ async function runAgents(config) {
184
184
  async function runCases(args, config) {
185
185
  const { agent, suite, model, caseIds, out, json } = parseCasesArgs(args);
186
186
  if (!agent) {
187
- console.error("Usage: codiedev traces cases <agent> [--suite name] [--model id] [--out dir] [--json]");
187
+ console.error("Usage: codiedev traces cases <agent> [--dataset name] [--model id] [--out dir] [--json]");
188
188
  process.exit(1);
189
189
  }
190
190
  const start = Date.now();
@@ -210,7 +210,7 @@ async function runCases(args, config) {
210
210
  }
211
211
  if (!res.cases.length) {
212
212
  console.log(suite
213
- ? `${res.agent.name} has no test cases in "${suite}". See your suites in Codiedev → Traces → Test cases.`
213
+ ? `${res.agent.name} has no test cases in "${suite}". See your datasets in Codiedev → Traces → Test cases.`
214
214
  : `${res.agent.name} has no saved test cases. Open a run in Codiedev → Traces and click "Save as test case".`);
215
215
  return;
216
216
  }
@@ -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 staging = (deps.makeStagingDir ?? (() => {
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
- try {
102
- const result = run((0, codieRuntimeInstall_1.buildRuntimeInstallArgs)(staging, exports.PI_RUNTIME_SPEC));
103
- if (result.status !== 0)
104
- throw new Error(result.stderr?.trim() || `npm exited with ${result.status}`);
105
- // Trust the artifact, not the exit code.
106
- const staged = installedPiEntry(staging, readFile);
107
- if (!staged || !exists(staged)) {
108
- throw new Error(`the install did not produce pi. Check that ${exports.PI_RUNTIME_SPEC} is available from your npm registry.`);
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
- remove(installDir);
111
- rename(staging, installDir);
112
- }
113
- catch (error) {
114
- throw new Error(`Couldn't install pi: ${error instanceof Error ? error.message : String(error)}`);
115
- }
116
- finally {
117
- // No-op after a successful promote; otherwise it keeps a ~200MB staging
118
- // dir from being orphaned.
119
- remove(staging);
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/utils.js CHANGED
@@ -1681,7 +1681,8 @@ thought, use the \`codiedev\` CLI via Bash:**
1681
1681
  | "find something about X" / "has anyone solved Y?" | \`codiedev search "<query>" [--limit N]\` |
1682
1682
  | "why did we…?" / "what does the team know about X?" | \`codiedev ask "<question>"\` (synthesized answer + citations) |
1683
1683
  | "show my library" / "what artifacts exist?" | \`codiedev library [--scope mine\\|shared\\|all] [--kind doc\\|skill]\` |
1684
- | "run my agent's test cases" / "check the suite on model Y" | \`codiedev traces cases <agent> [--suite <name>] [--model <id>]\` (writes cases + RUN_CASES.md + results.json; follow it, then \`codiedev traces report <results.json>\`) |
1684
+ | "run my agent's test cases" / "check the dataset on model Y" | \`codiedev traces cases <agent> [--dataset <name>] [--model <id>]\` (writes cases + RUN_CASES.md + results.json; follow it, then \`codiedev traces report <results.json>\`) |
1685
+ | "what was the last eval on X?" / "file these eval results" | \`codiedev evals last <subject>\` before starting a related eval; \`codiedev evals report <run.json>\` after each variant runs (scores only — \`codiedev evals help\` for the shape) |
1685
1686
 
1686
1687
  **Just push the file — we'll figure out where it goes.** Every artifact
1687
1688
  is classified into one of two kinds at upload time:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codiedev",
3
- "version": "0.9.73",
3
+ "version": "0.9.76",
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",