codecartographer-pi 0.25.0 → 0.26.0
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/.codecarto/broadside/SKILL.md +4 -1
- package/.codecarto/workflow/scaffold-version.yaml +1 -1
- package/README.md +2 -2
- package/dist/core/broadside/client.d.ts +56 -0
- package/dist/core/broadside/client.js +200 -0
- package/dist/core/broadside/collect.d.ts +68 -0
- package/dist/core/broadside/collect.js +676 -0
- package/dist/core/broadside/constants.d.ts +51 -0
- package/dist/core/broadside/constants.js +74 -0
- package/dist/core/broadside/lenses.d.ts +31 -0
- package/dist/core/broadside/lenses.js +312 -0
- package/dist/core/broadside/models.d.ts +46 -0
- package/dist/core/broadside/models.js +321 -0
- package/dist/core/broadside/render.d.ts +20 -0
- package/dist/core/broadside/render.js +285 -0
- package/dist/core/broadside/repo.d.ts +58 -0
- package/dist/core/broadside/repo.js +592 -0
- package/dist/core/broadside/requests.d.ts +23 -0
- package/dist/core/broadside/requests.js +71 -0
- package/dist/core/broadside/results.d.ts +36 -0
- package/dist/core/broadside/results.js +163 -0
- package/dist/core/broadside/schemas.d.ts +2 -0
- package/dist/core/broadside/schemas.js +342 -0
- package/dist/core/broadside/state.d.ts +99 -0
- package/dist/core/broadside/state.js +384 -0
- package/dist/core/broadside/submit.d.ts +30 -0
- package/dist/core/broadside/submit.js +350 -0
- package/dist/core/broadside/types.d.ts +491 -0
- package/dist/core/broadside/types.js +107 -0
- package/dist/core/{broadside-verify.d.ts → broadside/verify.d.ts} +23 -2
- package/dist/core/{broadside-verify.js → broadside/verify.js} +43 -5
- package/dist/core/broadside.d.ts +14 -952
- package/dist/core/broadside.js +25 -3726
- package/dist/core/completion.js +91 -72
- package/dist/core/dashboard-writer.js +9 -1
- package/dist/core/index.d.ts +0 -1
- package/dist/core/index.js +0 -1
- package/dist/core/library.d.ts +24 -1
- package/dist/core/library.js +46 -15
- package/dist/core/orchestrator-config.js +22 -8
- package/dist/core/status.d.ts +42 -23
- package/dist/core/status.js +163 -137
- package/dist/core/workspace.d.ts +2 -0
- package/dist/core/workspace.js +49 -25
- package/dist/core/yaml.js +9 -3
- package/dist/extensions/codecarto/auto-runner.js +41 -23
- package/dist/extensions/codecarto/index.js +9 -4
- package/dist/extensions/codecarto/phase-compaction.js +6 -2
- package/dist/mcp-server/server.js +15 -4
- package/package.json +1 -1
|
@@ -20,7 +20,12 @@
|
|
|
20
20
|
// that only reads keeps the batch property that re-running is always safe.
|
|
21
21
|
import { readdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
22
22
|
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
23
|
-
import { BROADSIDE_DIR, BROADSIDE_LENS_IDS
|
|
23
|
+
import { BROADSIDE_DIR, BROADSIDE_LENS_IDS } from "./constants.js";
|
|
24
|
+
import { defaultReasoningFor } from "./types.js";
|
|
25
|
+
import { redactSecrets } from "../secrets.js";
|
|
26
|
+
import { isSlurpable, listRepoFiles } from "./repo.js";
|
|
27
|
+
import { broadsideDirFor, loadBroadsideConfig, loadBroadsideState, persistBroadsideRunMerging } from "./state.js";
|
|
28
|
+
import { loadSavedLensResults, parseLensJson } from "./results.js";
|
|
24
29
|
export const BROADSIDE_CHAT_URL = "https://openrouter.ai/api/v1/chat/completions";
|
|
25
30
|
/** How many findings `verify` reads by default, most severe first. */
|
|
26
31
|
export const BROADSIDE_VERIFY_DEFAULT_TOP = 10;
|
|
@@ -74,10 +79,29 @@ export function rankVerifiableFindings(stored) {
|
|
|
74
79
|
* everything {@link isSlurpable} keeps out of a lens: credential stores, build
|
|
75
80
|
* output, binaries. A path outside the repository, or one the listing does
|
|
76
81
|
* not contain, is an error the model sees, not a read.
|
|
82
|
+
*
|
|
83
|
+
* Every line the reader hands back goes through the same secret-redaction
|
|
84
|
+
* pass `submit` runs over its slices (#358): the file list keeps credential
|
|
85
|
+
* *stores* out, but a key in an ordinary source file is exactly what a
|
|
86
|
+
* finding points a verifier at, and the tool result is the upload. `redact`
|
|
87
|
+
* mirrors config.yaml's `redact_secrets`. A pattern the model greps for can
|
|
88
|
+
* still tell it that a line matched; the line it sees is redacted.
|
|
77
89
|
*/
|
|
78
|
-
export async function createRepoReader(cwd) {
|
|
90
|
+
export async function createRepoReader(cwd, opts = {}) {
|
|
79
91
|
const { files } = await listRepoFiles(cwd);
|
|
80
92
|
const readable = new Set(files.filter(isSlurpable));
|
|
93
|
+
const redact = opts.redact ?? true;
|
|
94
|
+
const redactions = { values: 0, files: new Set() };
|
|
95
|
+
const clean = (rel, line) => {
|
|
96
|
+
if (!redact)
|
|
97
|
+
return line;
|
|
98
|
+
const redaction = redactSecrets(line);
|
|
99
|
+
if (redaction.count > 0) {
|
|
100
|
+
redactions.values += redaction.count;
|
|
101
|
+
redactions.files.add(rel);
|
|
102
|
+
}
|
|
103
|
+
return redaction.text;
|
|
104
|
+
};
|
|
81
105
|
const confine = (path) => {
|
|
82
106
|
const abs = resolve(cwd, path);
|
|
83
107
|
const rel = relative(cwd, abs).split("\\").join("/");
|
|
@@ -86,6 +110,7 @@ export async function createRepoReader(cwd) {
|
|
|
86
110
|
return rel;
|
|
87
111
|
};
|
|
88
112
|
return {
|
|
113
|
+
redactions,
|
|
89
114
|
async readFile(path, startLine, endLine) {
|
|
90
115
|
const rel = confine(path);
|
|
91
116
|
if (!readable.has(rel))
|
|
@@ -96,7 +121,7 @@ export async function createRepoReader(cwd) {
|
|
|
96
121
|
const end = Math.min(lines.length, requestedEnd, start + READ_FILE_MAX_LINES - 1);
|
|
97
122
|
if (start > lines.length)
|
|
98
123
|
return `error: ${rel} has ${lines.length} lines`;
|
|
99
|
-
return lines.slice(start - 1, end).map((line, i) => `${start + i}: ${line}`).join("\n");
|
|
124
|
+
return lines.slice(start - 1, end).map((line, i) => `${start + i}: ${clean(rel, line)}`).join("\n");
|
|
100
125
|
},
|
|
101
126
|
async grep(pattern, pathPrefix) {
|
|
102
127
|
let regex;
|
|
@@ -123,7 +148,7 @@ export async function createRepoReader(cwd) {
|
|
|
123
148
|
const lines = text.split("\n");
|
|
124
149
|
for (let i = 0; i < lines.length && matches.length < GREP_MAX_MATCHES; i++) {
|
|
125
150
|
if (regex.test(lines[i]))
|
|
126
|
-
matches.push(`${rel}:${i + 1}: ${lines[i]}`);
|
|
151
|
+
matches.push(`${rel}:${i + 1}: ${clean(rel, lines[i])}`);
|
|
127
152
|
}
|
|
128
153
|
if (matches.length >= GREP_MAX_MATCHES)
|
|
129
154
|
break;
|
|
@@ -341,7 +366,11 @@ export async function runBroadsideVerify(cwd, apiKey, opts = {}) {
|
|
|
341
366
|
const model = opts.model ?? syncModelFor(run.model);
|
|
342
367
|
const maxCost = opts.maxCost ?? 0;
|
|
343
368
|
const fetcher = opts.fetcher ?? fetch;
|
|
344
|
-
|
|
369
|
+
// The same switch submit honours: a repository that turned redaction off
|
|
370
|
+
// for its slices gets raw lines here too, and one that did not never
|
|
371
|
+
// uploads a key through a tool result (#358).
|
|
372
|
+
const config = await loadBroadsideConfig(broadsideDir);
|
|
373
|
+
const reader = await createRepoReader(cwd, { redact: config.redactSecrets });
|
|
345
374
|
const selected = ranked.slice(0, top);
|
|
346
375
|
const findings = [];
|
|
347
376
|
let totalCost = 0;
|
|
@@ -376,6 +405,7 @@ export async function runBroadsideVerify(cwd, apiKey, opts = {}) {
|
|
|
376
405
|
confirmed: findings.filter((f) => f.verdict === "confirmed").length,
|
|
377
406
|
cost: totalCost,
|
|
378
407
|
at: new Date().toISOString(),
|
|
408
|
+
redactedValues: reader.redactions.values,
|
|
379
409
|
};
|
|
380
410
|
const result = {
|
|
381
411
|
runId: run.id,
|
|
@@ -386,6 +416,8 @@ export async function runBroadsideVerify(cwd, apiKey, opts = {}) {
|
|
|
386
416
|
findings,
|
|
387
417
|
totalCost,
|
|
388
418
|
...(stoppedByCost && { stoppedByCost: true }),
|
|
419
|
+
redactedValues: reader.redactions.values,
|
|
420
|
+
redactedFiles: [...reader.redactions.files].sort(),
|
|
389
421
|
};
|
|
390
422
|
await writeFile(join(runDir, "verified.json"), `${JSON.stringify({ ...entry, run_id: run.id, candidates: ranked.length, findings }, null, "\t")}\n`, "utf8");
|
|
391
423
|
await writeFile(join(runDir, "verified.md"), renderVerifiedMarkdown(result), "utf8");
|
|
@@ -407,6 +439,9 @@ export function renderVerifiedMarkdown(result) {
|
|
|
407
439
|
"is a lead worth a human's next look, not a validated claim.",
|
|
408
440
|
"",
|
|
409
441
|
];
|
|
442
|
+
if (result.redactedValues > 0) {
|
|
443
|
+
lines.push(`${result.redactedValues} secret-like value(s) were redacted from tool output before upload (${result.redactedFiles.join(", ")}).`, "");
|
|
444
|
+
}
|
|
410
445
|
for (const f of result.findings) {
|
|
411
446
|
lines.push(`## ${VERDICT_MARK[f.verdict] ?? "?"} ${f.index}. [${f.severity}] ${f.title}`, "", `- **verdict**: ${f.verdict} (${f.confidence})`, `- **location**: ${f.location}`, `- **lens**: ${f.lensId} (${f.customId})`);
|
|
412
447
|
if (f.evidence.length > 0)
|
|
@@ -428,6 +463,9 @@ export function verifyResultText(result) {
|
|
|
428
463
|
for (const f of result.findings) {
|
|
429
464
|
lines.push(` ${VERDICT_MARK[f.verdict] ?? "?"} [${f.severity}] ${f.title} @ ${f.location} — ${f.verdict}`);
|
|
430
465
|
}
|
|
466
|
+
if (result.redactedValues > 0) {
|
|
467
|
+
lines.push(` ${result.redactedValues} secret-like value(s) redacted from tool output before upload (${result.redactedFiles.join(", ")}).`);
|
|
468
|
+
}
|
|
431
469
|
lines.push(`Details in ${result.outputDir}/verified.md. A confirmed finding is a lead for a human's next look, not a validated claim.`);
|
|
432
470
|
return lines.join("\n");
|
|
433
471
|
}
|