codiedev 0.9.72 → 0.9.73
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 +13 -0
- package/dist/commands/traces.d.ts +68 -0
- package/dist/commands/traces.js +292 -0
- package/dist/utils.js +1 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -30,6 +30,7 @@ const share_1 = require("./commands/share");
|
|
|
30
30
|
const send_1 = require("./commands/send");
|
|
31
31
|
const capture_1 = require("./commands/capture");
|
|
32
32
|
const pack_1 = require("./commands/pack");
|
|
33
|
+
const traces_1 = require("./commands/traces");
|
|
33
34
|
// --- starter packs phase 2 ---
|
|
34
35
|
const hookGate_1 = require("./packs/hookGate");
|
|
35
36
|
const sync_1 = require("./packs/sync");
|
|
@@ -91,6 +92,14 @@ Starter packs:
|
|
|
91
92
|
detected tool
|
|
92
93
|
codiedev pack status Installed packs, up to date or not
|
|
93
94
|
|
|
95
|
+
Traces (agents on the gateway):
|
|
96
|
+
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)
|
|
99
|
+
into this repo for your coding agent to
|
|
100
|
+
run, optionally on another model
|
|
101
|
+
codiedev traces report <results.json> Send the results back to Traces
|
|
102
|
+
|
|
94
103
|
Discovery:
|
|
95
104
|
codiedev search "<query>" Semantic search across the team's
|
|
96
105
|
captured sessions and artifacts
|
|
@@ -152,6 +161,7 @@ status sync never weakens it.
|
|
|
152
161
|
`.trim();
|
|
153
162
|
const COMMAND_HELP = {
|
|
154
163
|
pack: pack_1.PACK_HELP,
|
|
164
|
+
traces: traces_1.TRACES_HELP,
|
|
155
165
|
connect: `
|
|
156
166
|
codiedev connect — link your agent CLI to Codiedev
|
|
157
167
|
|
|
@@ -515,6 +525,9 @@ async function main() {
|
|
|
515
525
|
case "ls":
|
|
516
526
|
await (0, library_1.runLibrary)(rest);
|
|
517
527
|
return;
|
|
528
|
+
case "traces":
|
|
529
|
+
await (0, traces_1.runTraces)(rest);
|
|
530
|
+
return;
|
|
518
531
|
case "share":
|
|
519
532
|
await (0, share_1.runShare)(rest);
|
|
520
533
|
return;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { CodiedevConfig } from "../utils";
|
|
2
|
+
export declare const TRACES_HELP: string;
|
|
3
|
+
interface CaseStep {
|
|
4
|
+
model: string;
|
|
5
|
+
finishReason?: string;
|
|
6
|
+
statusCode: number;
|
|
7
|
+
request?: string;
|
|
8
|
+
reply?: string;
|
|
9
|
+
toolCalls?: Array<{
|
|
10
|
+
name: string;
|
|
11
|
+
arguments: string;
|
|
12
|
+
}>;
|
|
13
|
+
}
|
|
14
|
+
interface CaseRow {
|
|
15
|
+
id: string;
|
|
16
|
+
name: string;
|
|
17
|
+
suite: string | null;
|
|
18
|
+
runId: string;
|
|
19
|
+
kind: "fix" | "keep";
|
|
20
|
+
flags: string[];
|
|
21
|
+
note: string | null;
|
|
22
|
+
expected: string | null;
|
|
23
|
+
createdAt: string;
|
|
24
|
+
steps: CaseStep[];
|
|
25
|
+
}
|
|
26
|
+
interface CasesResponse {
|
|
27
|
+
ok: boolean;
|
|
28
|
+
/** The suite pulled, when --suite was given. */
|
|
29
|
+
suite: string | null;
|
|
30
|
+
/** How the suite is judged, when it has settings. */
|
|
31
|
+
judge: {
|
|
32
|
+
model: string | null;
|
|
33
|
+
rubric: string | null;
|
|
34
|
+
} | null;
|
|
35
|
+
agent: {
|
|
36
|
+
id: string;
|
|
37
|
+
name: string;
|
|
38
|
+
description: string | null;
|
|
39
|
+
promptDays: number | null;
|
|
40
|
+
};
|
|
41
|
+
cases: CaseRow[];
|
|
42
|
+
}
|
|
43
|
+
/** What `report` sends, and what `cases` writes for the coding agent to fill in. */
|
|
44
|
+
export interface ResultsFile {
|
|
45
|
+
agent: string;
|
|
46
|
+
suite: string | null;
|
|
47
|
+
model: string;
|
|
48
|
+
judgeModel: string | null;
|
|
49
|
+
harness: string | null;
|
|
50
|
+
results: Array<{
|
|
51
|
+
caseId: string;
|
|
52
|
+
name: string;
|
|
53
|
+
passes: number | null;
|
|
54
|
+
tries: number;
|
|
55
|
+
note: string | null;
|
|
56
|
+
output: string | null;
|
|
57
|
+
}>;
|
|
58
|
+
}
|
|
59
|
+
export declare function slugify(name: string): string;
|
|
60
|
+
/** The brief a coding agent follows to run the cases and report back. */
|
|
61
|
+
export declare function casesBrief(res: CasesResponse, casesFile: string, opts?: {
|
|
62
|
+
model?: string;
|
|
63
|
+
resultsFile?: string;
|
|
64
|
+
}): string;
|
|
65
|
+
/** The results.json a run starts from: every case, passes to be filled in. */
|
|
66
|
+
export declare function resultsTemplate(res: CasesResponse, model: string | undefined): ResultsFile;
|
|
67
|
+
export declare function runTraces(args: string[], configOverride?: CodiedevConfig): Promise<void>;
|
|
68
|
+
export {};
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// `codiedev traces agents`
|
|
3
|
+
// `codiedev traces cases <agent> [--suite name] [--model id] [--out dir] [--json]`
|
|
4
|
+
// `codiedev traces report <results.json> [--harness name]`
|
|
5
|
+
//
|
|
6
|
+
// Test cases are runs an engineer saved from Codiedev → Traces. They run in
|
|
7
|
+
// the engineer's coding agent, not in the portal: `cases` writes them into the
|
|
8
|
+
// repo with a brief the agent follows to replay each one against the agent's
|
|
9
|
+
// own code, optionally on another model (a regression check before a model
|
|
10
|
+
// swap), and a results.json for `report` to send back so Traces shows pass
|
|
11
|
+
// rates by model.
|
|
12
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
15
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
16
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
17
|
+
}
|
|
18
|
+
Object.defineProperty(o, k2, desc);
|
|
19
|
+
}) : (function(o, m, k, k2) {
|
|
20
|
+
if (k2 === undefined) k2 = k;
|
|
21
|
+
o[k2] = m[k];
|
|
22
|
+
}));
|
|
23
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
24
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
25
|
+
}) : function(o, v) {
|
|
26
|
+
o["default"] = v;
|
|
27
|
+
});
|
|
28
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
29
|
+
var ownKeys = function(o) {
|
|
30
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
31
|
+
var ar = [];
|
|
32
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
33
|
+
return ar;
|
|
34
|
+
};
|
|
35
|
+
return ownKeys(o);
|
|
36
|
+
};
|
|
37
|
+
return function (mod) {
|
|
38
|
+
if (mod && mod.__esModule) return mod;
|
|
39
|
+
var result = {};
|
|
40
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
41
|
+
__setModuleDefault(result, mod);
|
|
42
|
+
return result;
|
|
43
|
+
};
|
|
44
|
+
})();
|
|
45
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
|
+
exports.TRACES_HELP = void 0;
|
|
47
|
+
exports.slugify = slugify;
|
|
48
|
+
exports.casesBrief = casesBrief;
|
|
49
|
+
exports.resultsTemplate = resultsTemplate;
|
|
50
|
+
exports.runTraces = runTraces;
|
|
51
|
+
const fs = __importStar(require("fs"));
|
|
52
|
+
const path = __importStar(require("path"));
|
|
53
|
+
const shared_1 = require("./shared");
|
|
54
|
+
exports.TRACES_HELP = `
|
|
55
|
+
codiedev traces — test cases saved from Codiedev → Traces
|
|
56
|
+
|
|
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
|
|
60
|
+
the cases named) into this repo, default
|
|
61
|
+
.codiedev/traces/<agent>[/<suite>]/, then
|
|
62
|
+
ask your coding agent to run them.
|
|
63
|
+
--model runs them on another model, e.g.
|
|
64
|
+
the replacement for a retiring one
|
|
65
|
+
codiedev traces report <results.json> [--harness name]
|
|
66
|
+
Send the filled-in results back, so
|
|
67
|
+
Traces shows the pass rate for that model
|
|
68
|
+
|
|
69
|
+
<agent> is the agent's name (its API key name) or id. Only an agent's
|
|
70
|
+
maintainers can pull its cases or report on them.
|
|
71
|
+
`.trim();
|
|
72
|
+
const FLAG_LABEL = {
|
|
73
|
+
budget_block: "refused for budget",
|
|
74
|
+
errors: "model call failed",
|
|
75
|
+
tool_loop: "repeated the same tool call",
|
|
76
|
+
truncated: "reply cut off at max_tokens",
|
|
77
|
+
context_overflow: "prompt over 70% of the context window",
|
|
78
|
+
};
|
|
79
|
+
const TRIES = 3;
|
|
80
|
+
const plural = (n, word) => `${n} ${word}${n === 1 ? "" : "s"}`;
|
|
81
|
+
const recordedModel = (res) => res.cases.flatMap((c) => c.steps.map((s) => s.model))[0] ?? "the recorded model";
|
|
82
|
+
function slugify(name) {
|
|
83
|
+
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "agent";
|
|
84
|
+
}
|
|
85
|
+
/** The brief a coding agent follows to run the cases and report back. */
|
|
86
|
+
function casesBrief(res, casesFile, opts = {}) {
|
|
87
|
+
const fix = res.cases.filter((c) => c.kind === "fix");
|
|
88
|
+
const keep = res.cases.filter((c) => c.kind === "keep");
|
|
89
|
+
const withBodies = res.cases.filter((c) => c.steps.some((s) => s.request)).length;
|
|
90
|
+
const target = opts.model;
|
|
91
|
+
const results = opts.resultsFile ? path.basename(opts.resultsFile) : "results.json";
|
|
92
|
+
const lines = [
|
|
93
|
+
`# Test cases for ${res.agent.name}${res.suite ? ` · ${res.suite}` : ""}${target ? ` on ${target}` : ""}`,
|
|
94
|
+
"",
|
|
95
|
+
res.agent.description ? `${res.agent.description}\n` : "",
|
|
96
|
+
`Saved from Codiedev → Traces. ${plural(res.cases.length, "case")} in \`${path.basename(casesFile)}\` (one JSON object per line):`,
|
|
97
|
+
`- **${fix.length} to fix**: production runs that failed. The fix should make them pass.`,
|
|
98
|
+
`- **${keep.length} to keep passing**: good runs. They should still pass after any change.`,
|
|
99
|
+
"",
|
|
100
|
+
];
|
|
101
|
+
if (target) {
|
|
102
|
+
lines.push("## This is a model check", "", `Run every case on **${target}** instead of ${recordedModel(res)} (the model the cases were recorded on). Change only the model the agent asks the gateway for; keep its prompts and tools as they are, so the result says how ${target} does on the same work.`, "");
|
|
103
|
+
}
|
|
104
|
+
lines.push("## How to run them", "", "1. Find where this agent builds its model requests and calls the Codiedev gateway.", `2. For each case, replay \`steps[0].request\` (the first prompt the agent sent) through the agent's own code path, so tools and prompts are the current version, not the recorded one${target ? `, with the model set to ${target}` : ""}.`, "3. Judge each try against the case:", " - A case's `expected`, when present, is what a passing answer looks like (a reference reply or criteria). It wins over everything below.", " - `fix` cases: the run must not reproduce its `flags` (listed below), and must finish (no failed call, no `finish_reason: \"length\"`, no repeated identical tool call).", " - `keep` cases: the final reply must still do what the recorded final reply did. Compare meaning, not wording.", " - A case's `note`, when present, is the engineer's extra context.");
|
|
105
|
+
if (res.judge?.model || res.judge?.rubric) {
|
|
106
|
+
lines.push(` - Where passing needs judgement, judge with **${res.judge.model ?? "a strong model"}** through the gateway${res.judge.rubric ? `, using this rubric: "${res.judge.rubric}"` : ""}. Use the same judge for every model so results compare.`);
|
|
107
|
+
}
|
|
108
|
+
lines.push(`4. Run each case ${TRIES} times: agents are stochastic, so report a pass rate per case, not a single result.`, `5. Fill in \`${results}\`: for each case set \`passes\` (out of \`tries\`), \`output\` (the agent's final reply on one try, so it can be compared side by side with other models) and a one-line \`note\` on any failure. Set \`harness\` to the coding agent you are (claude-code, codex, cursor, copilot, …).`, `6. Send it back: \`codiedev traces report ${opts.resultsFile ? path.relative(process.cwd(), opts.resultsFile) || results : results}\`. Then show a table: case, kind, passes out of ${TRIES}, and the failure note.`, "", "Send real model calls through the gateway with the agent's usual key and `X-Codiedev-Run-Id: case-<id>-<try>`, so the replays show up in Traces too.", "");
|
|
109
|
+
if (withBodies < res.cases.length) {
|
|
110
|
+
lines.push(`Note: ${plural(res.cases.length - withBodies, "case")} ${res.cases.length - withBodies === 1 ? "has" : "have"} no recorded prompt (the agent wasn't keeping prompts then). For those, rebuild the input from the case's \`expected\` or \`note\`, or skip them and say so.`, "");
|
|
111
|
+
}
|
|
112
|
+
lines.push("## Cases", "");
|
|
113
|
+
for (const c of res.cases) {
|
|
114
|
+
const flags = c.flags.length ? c.flags.map((f) => FLAG_LABEL[f] ?? f).join(", ") : "no flags";
|
|
115
|
+
lines.push(`- \`${c.id}\` · ${c.name} · ${c.kind} · ${flags} · ${plural(c.steps.length, "model call")}${c.expected ? ` · expected: "${c.expected.replace(/\s+/g, " ").slice(0, 200)}"` : ""}${c.note ? ` · note: "${c.note}"` : ""}`);
|
|
116
|
+
}
|
|
117
|
+
return lines.filter((line, i, all) => !(line === "" && all[i - 1] === "")).join("\n") + "\n";
|
|
118
|
+
}
|
|
119
|
+
/** The results.json a run starts from: every case, passes to be filled in. */
|
|
120
|
+
function resultsTemplate(res, model) {
|
|
121
|
+
return {
|
|
122
|
+
agent: res.agent.name,
|
|
123
|
+
suite: res.suite,
|
|
124
|
+
model: model ?? recordedModel(res),
|
|
125
|
+
judgeModel: res.judge?.model ?? null,
|
|
126
|
+
harness: null,
|
|
127
|
+
results: res.cases.map((c) => ({ caseId: c.id, name: c.name, passes: null, tries: TRIES, note: null, output: null })),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function flag(args, i, name) {
|
|
131
|
+
const a = args[i];
|
|
132
|
+
if (a === name && i + 1 < args.length)
|
|
133
|
+
return { value: args[i + 1], skip: 1 };
|
|
134
|
+
if (a.startsWith(`${name}=`))
|
|
135
|
+
return { value: a.slice(name.length + 1), skip: 0 };
|
|
136
|
+
return { skip: -1 };
|
|
137
|
+
}
|
|
138
|
+
function parseCasesArgs(args) {
|
|
139
|
+
const parsed = { json: false };
|
|
140
|
+
for (let i = 0; i < args.length; i++) {
|
|
141
|
+
const a = args[i];
|
|
142
|
+
let matched = false;
|
|
143
|
+
for (const [name, key] of [["--out", "out"], ["-o", "out"], ["--suite", "suite"], ["--model", "model"], ["--case", "caseIds"]]) {
|
|
144
|
+
const f = flag(args, i, name);
|
|
145
|
+
if (f.skip >= 0) {
|
|
146
|
+
parsed[key] = f.value;
|
|
147
|
+
i += f.skip;
|
|
148
|
+
matched = true;
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (matched)
|
|
153
|
+
continue;
|
|
154
|
+
if (a === "--json")
|
|
155
|
+
parsed.json = true;
|
|
156
|
+
else if (!a.startsWith("-") && !parsed.agent)
|
|
157
|
+
parsed.agent = a;
|
|
158
|
+
}
|
|
159
|
+
return parsed;
|
|
160
|
+
}
|
|
161
|
+
async function runAgents(config) {
|
|
162
|
+
const start = Date.now();
|
|
163
|
+
let res;
|
|
164
|
+
try {
|
|
165
|
+
res = await (0, shared_1.apiRequest)("GET", "/api/cli/traces/agents", { config });
|
|
166
|
+
}
|
|
167
|
+
catch (err) {
|
|
168
|
+
const e = err;
|
|
169
|
+
(0, shared_1.recordAgentEvent)(config, { tool: "codiedev_traces_agents", ok: false, latencyMs: Date.now() - start, error: e.message });
|
|
170
|
+
console.error(`Couldn't list agents: ${e.message}`);
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}
|
|
173
|
+
(0, shared_1.recordAgentEvent)(config, { tool: "codiedev_traces_agents", ok: true, latencyMs: Date.now() - start });
|
|
174
|
+
if (!res.agents.length) {
|
|
175
|
+
console.log("You don't maintain any agents yet. Connect one in Codiedev → Traces → How it works.");
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
for (const agent of res.agents) {
|
|
179
|
+
const capture = agent.promptDays ? `prompts kept ${agent.promptDays} days` : "metadata only";
|
|
180
|
+
console.log(`${agent.name.padEnd(28)} ${plural(agent.cases, "case").padStart(9)} ${capture}`);
|
|
181
|
+
}
|
|
182
|
+
console.log("\nPull one: codiedev traces cases <agent>");
|
|
183
|
+
}
|
|
184
|
+
async function runCases(args, config) {
|
|
185
|
+
const { agent, suite, model, caseIds, out, json } = parseCasesArgs(args);
|
|
186
|
+
if (!agent) {
|
|
187
|
+
console.error("Usage: codiedev traces cases <agent> [--suite name] [--model id] [--out dir] [--json]");
|
|
188
|
+
process.exit(1);
|
|
189
|
+
}
|
|
190
|
+
const start = Date.now();
|
|
191
|
+
let res;
|
|
192
|
+
try {
|
|
193
|
+
res = await (0, shared_1.apiRequest)("GET", "/api/cli/traces/cases", { config, query: { agent, ...(suite ? { suite } : {}), ...(caseIds ? { case: caseIds } : {}) } });
|
|
194
|
+
}
|
|
195
|
+
catch (err) {
|
|
196
|
+
const e = err;
|
|
197
|
+
(0, shared_1.recordAgentEvent)(config, { tool: "codiedev_traces_cases", ok: false, latencyMs: Date.now() - start, error: e.message });
|
|
198
|
+
if (e.status === 404)
|
|
199
|
+
console.error(`No agent called "${agent}". See your agents with: codiedev traces agents`);
|
|
200
|
+
else if (e.status === 403)
|
|
201
|
+
console.error(`Only ${agent}'s maintainers can pull its test cases.`);
|
|
202
|
+
else
|
|
203
|
+
console.error(`Couldn't pull cases: ${e.message}`);
|
|
204
|
+
process.exit(1);
|
|
205
|
+
}
|
|
206
|
+
(0, shared_1.recordAgentEvent)(config, { tool: "codiedev_traces_cases", ok: true, latencyMs: Date.now() - start });
|
|
207
|
+
if (json) {
|
|
208
|
+
process.stdout.write(JSON.stringify(res, null, 2) + "\n");
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
if (!res.cases.length) {
|
|
212
|
+
console.log(suite
|
|
213
|
+
? `${res.agent.name} has no test cases in "${suite}". See your suites in Codiedev → Traces → Test cases.`
|
|
214
|
+
: `${res.agent.name} has no saved test cases. Open a run in Codiedev → Traces and click "Save as test case".`);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
const dir = path.resolve(process.cwd(), out ?? path.join(".codiedev", "traces", slugify(res.agent.name), ...(res.suite ? [slugify(res.suite)] : []), ...(caseIds && res.cases.length === 1 ? [slugify(res.cases[0].name)] : []), ...(model ? [slugify(model)] : [])));
|
|
218
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
219
|
+
const casesFile = path.join(dir, "cases.jsonl");
|
|
220
|
+
fs.writeFileSync(casesFile, res.cases.map((c) => JSON.stringify(c)).join("\n") + "\n", "utf8");
|
|
221
|
+
const resultsFile = path.join(dir, "results.json");
|
|
222
|
+
fs.writeFileSync(resultsFile, JSON.stringify(resultsTemplate(res, model), null, 2) + "\n", "utf8");
|
|
223
|
+
const briefFile = path.join(dir, "RUN_CASES.md");
|
|
224
|
+
fs.writeFileSync(briefFile, casesBrief(res, casesFile, { model, resultsFile }), "utf8");
|
|
225
|
+
const fix = res.cases.filter((c) => c.kind === "fix").length;
|
|
226
|
+
const rel = (file) => path.relative(process.cwd(), file) || file;
|
|
227
|
+
console.log(`✓ ${plural(res.cases.length, "case")} for ${res.agent.name}${res.suite ? ` · ${res.suite}` : ""}${model ? ` on ${model}` : ""} (${fix} to fix, ${res.cases.length - fix} to keep passing)`);
|
|
228
|
+
console.log(` ${rel(casesFile)}`);
|
|
229
|
+
console.log(` ${rel(briefFile)}`);
|
|
230
|
+
console.log(` ${rel(resultsFile)} (filled in by your coding agent, then: codiedev traces report ${rel(resultsFile)})`);
|
|
231
|
+
console.log(`\nNext: ask your coding agent to "run the test cases in ${rel(briefFile)}"`);
|
|
232
|
+
}
|
|
233
|
+
async function runReport(args, config) {
|
|
234
|
+
let file;
|
|
235
|
+
let harness;
|
|
236
|
+
for (let i = 0; i < args.length; i++) {
|
|
237
|
+
const f = flag(args, i, "--harness");
|
|
238
|
+
if (f.skip >= 0) {
|
|
239
|
+
harness = f.value;
|
|
240
|
+
i += f.skip;
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
if (!args[i].startsWith("-") && !file)
|
|
244
|
+
file = args[i];
|
|
245
|
+
}
|
|
246
|
+
if (!file) {
|
|
247
|
+
console.error("Usage: codiedev traces report <results.json> [--harness name]");
|
|
248
|
+
process.exit(1);
|
|
249
|
+
}
|
|
250
|
+
let body;
|
|
251
|
+
try {
|
|
252
|
+
body = JSON.parse(fs.readFileSync(path.resolve(process.cwd(), file), "utf8"));
|
|
253
|
+
}
|
|
254
|
+
catch (err) {
|
|
255
|
+
console.error(`Couldn't read ${file}: ${err.message}`);
|
|
256
|
+
process.exit(1);
|
|
257
|
+
}
|
|
258
|
+
const missing = body.results.filter((r) => typeof r.passes !== "number");
|
|
259
|
+
if (missing.length) {
|
|
260
|
+
console.error(`${plural(missing.length, "case")} in ${file} ${missing.length === 1 ? "has" : "have"} no "passes" yet: ${missing.slice(0, 5).map((r) => r.name).join(", ")}. Run them first.`);
|
|
261
|
+
process.exit(1);
|
|
262
|
+
}
|
|
263
|
+
const start = Date.now();
|
|
264
|
+
try {
|
|
265
|
+
const res = await (0, shared_1.apiRequest)("POST", "/api/cli/traces/results", {
|
|
266
|
+
config,
|
|
267
|
+
body: { ...body, harness: harness ?? body.harness ?? undefined },
|
|
268
|
+
});
|
|
269
|
+
(0, shared_1.recordAgentEvent)(config, { tool: "codiedev_traces_report", ok: true, latencyMs: Date.now() - start });
|
|
270
|
+
const passed = body.results.filter((r) => r.passes === r.tries).length;
|
|
271
|
+
console.log(`✓ Reported ${body.agent}${body.suite ? ` · ${body.suite}` : ""} on ${body.model}: ${Math.round(res.passRate * 100)}% of tries passed, ${passed}/${body.results.length} cases passed every try.`);
|
|
272
|
+
console.log(" See it next to other models in Codiedev → Traces → Test cases.");
|
|
273
|
+
}
|
|
274
|
+
catch (err) {
|
|
275
|
+
const e = err;
|
|
276
|
+
(0, shared_1.recordAgentEvent)(config, { tool: "codiedev_traces_report", ok: false, latencyMs: Date.now() - start, error: e.message });
|
|
277
|
+
console.error(e.status === 403 ? `Only ${body.agent}'s maintainers can report its results.` : `Couldn't report: ${e.message}`);
|
|
278
|
+
process.exit(1);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
async function runTraces(args, configOverride) {
|
|
282
|
+
const [sub, ...rest] = args;
|
|
283
|
+
if (sub === "agents")
|
|
284
|
+
return runAgents(configOverride ?? (0, shared_1.requireConfig)());
|
|
285
|
+
if (sub === "cases")
|
|
286
|
+
return runCases(rest, configOverride ?? (0, shared_1.requireConfig)());
|
|
287
|
+
if (sub === "report")
|
|
288
|
+
return runReport(rest, configOverride ?? (0, shared_1.requireConfig)());
|
|
289
|
+
console.log(exports.TRACES_HELP);
|
|
290
|
+
if (sub && sub !== "help")
|
|
291
|
+
process.exit(1);
|
|
292
|
+
}
|
package/dist/utils.js
CHANGED
|
@@ -1681,6 +1681,7 @@ 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
1685
|
|
|
1685
1686
|
**Just push the file — we'll figure out where it goes.** Every artifact
|
|
1686
1687
|
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.
|
|
3
|
+
"version": "0.9.73",
|
|
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",
|