@cruxy/cli 1.11.1 → 1.11.3
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/agent/instruction-loss.js +204 -0
- package/dist/agent/prompts.js +25 -4
- package/dist/agent/session.js +165 -33
- package/dist/agent/status.js +18 -0
- package/dist/checkpoint/service.js +44 -3
- package/dist/cli/commands/pr.js +14 -0
- package/dist/cli/commands/run.js +35 -0
- package/dist/cli/commands/sessions.js +8 -0
- package/dist/cli/session-commands.js +3 -1
- package/dist/cli/session-factory.js +54 -6
- package/dist/config/schema.js +9 -0
- package/dist/errors/constructors.js +15 -6
- package/dist/errors/types.js +7 -0
- package/dist/indexing/embedder.js +34 -11
- package/dist/indexing/model-cache.js +399 -0
- package/dist/mcp/bounds.js +8 -1
- package/dist/plan/execute.js +4 -1
- package/dist/plan/service.js +42 -5
- package/dist/plan/step-message.js +49 -0
- package/dist/render/context-view.js +44 -1
- package/dist/render/status-view.js +13 -0
- package/dist/session/index.js +7 -3
- package/dist/session/log.js +163 -2
- package/dist/session/owner.js +123 -0
- package/dist/session/prune.js +11 -0
- package/dist/session/recorded-runs.js +56 -0
- package/dist/session/replay.js +75 -1
- package/dist/session/resume.js +110 -3
- package/dist/session/types.js +158 -0
- package/dist/subagent/orchestrator.js +2 -2
- package/dist/subagent/registry-scope.js +28 -5
- package/dist/testing/run-tests-tool.js +3 -1
- package/dist/tools/create-pull-request.js +8 -1
- package/dist/tools/file/apply-patch.js +53 -23
- package/dist/tools/file/edit-file.js +19 -1
- package/dist/tools/file/snapshot.js +68 -0
- package/dist/tools/file/write-file.js +31 -5
- package/dist/tools/registry.js +39 -8
- package/dist/tools/schema-depth.js +79 -6
- package/dist/tools/shell/exec.js +7 -0
- package/dist/tools/shell/run-command.js +45 -21
- package/dist/utils/process-owner.js +107 -0
- package/dist/vcs/generate.js +48 -6
- package/dist/verification/index.js +15 -0
- package/dist/verification/ledger.js +99 -0
- package/dist/verification/types.js +26 -0
- package/dist/verification/view.js +87 -0
- package/package.json +3 -2
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The verification record (P2 verification): what ran, and how it exited.
|
|
3
|
+
*
|
|
4
|
+
* The loop's only completion criterion is "the model emitted no tool calls"
|
|
5
|
+
* (`agent/loop.ts`). Nothing checks that tests ran, a build passed, or a diff
|
|
6
|
+
* was reviewed, and the system prompt's instruction to verify is exactly that:
|
|
7
|
+
* an instruction. This module makes the absence VISIBLE without making the
|
|
8
|
+
* presence MANDATORY — C.13 shipped voluntary verification and delegated the
|
|
9
|
+
* iteration to the ordinary loop, and that decision stands. Three reasons it
|
|
10
|
+
* is not reversed here:
|
|
11
|
+
*
|
|
12
|
+
* - `run_tests`' failing-run breaker latches for the turn after
|
|
13
|
+
* `test.maxIterations` runs, so a turn that MUST end green could never end.
|
|
14
|
+
* - A project with no test command has no defensible verdict: the coded
|
|
15
|
+
* not-found error already tells the model to ask the user, not to guess.
|
|
16
|
+
* - Enforcement changes the one-shot exit contract — "completed but
|
|
17
|
+
* unverified" would be a new stop kind, and CI reads that exit code today.
|
|
18
|
+
*
|
|
19
|
+
* So this is EVIDENCE: a record of each run that actually executed, keyed to
|
|
20
|
+
* the turn it ran in, read back by the surfaces a user checks afterwards. What
|
|
21
|
+
* it never does is INFER. `passed` is the exit code and nothing else; nothing
|
|
22
|
+
* here decides that a command was "a build" or "the tests" from its text. The
|
|
23
|
+
* record says what ran and how it exited; the reader judges.
|
|
24
|
+
*/
|
|
25
|
+
/** Most failure names kept per record — an index, not a transcript. */
|
|
26
|
+
export const MAX_FAILURE_NAMES = 5;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { formatDuration } from "../render/test-view.js";
|
|
2
|
+
/**
|
|
3
|
+
* Rendering the verification record — the shared formatter behind every
|
|
4
|
+
* surface that reads it, so the one-shot summary, `/status`, the resume
|
|
5
|
+
* notice and the PR body all describe a run the same way.
|
|
6
|
+
*
|
|
7
|
+
* The honesty rules are `verification/types`'s, carried through rather than
|
|
8
|
+
* re-derived: the exit code is the fact, the tool and command are named as
|
|
9
|
+
* they ran, and nothing here calls a run "the build" or "the tests" from its
|
|
10
|
+
* text. A non-zero exit is shown as that exit — never as "1 test failed"
|
|
11
|
+
* unless a parser actually counted one.
|
|
12
|
+
*/
|
|
13
|
+
/** `run_tests pnpm test → exit 0 (4.2s)`, coloured by exit. */
|
|
14
|
+
export function describeRun(rec, t) {
|
|
15
|
+
const exit = rec.exitCode === null ? "no exit code" : `exit ${rec.exitCode}`;
|
|
16
|
+
const verdict = rec.passed ? t.muted(exit) : t.danger(exit);
|
|
17
|
+
const counts = countClause(rec);
|
|
18
|
+
return (`${t.muted(rec.tool)} ${rec.command} ${t.glyph.arrow} ${verdict}` +
|
|
19
|
+
(counts ? ` ${t.danger(counts)}` : "") +
|
|
20
|
+
` ${t.muted(`(${formatDuration(rec.durationMs)})`)}`);
|
|
21
|
+
}
|
|
22
|
+
/** "3 of 128 failed" / "3 failures" / "" — only what a parser actually counted. */
|
|
23
|
+
function countClause(rec) {
|
|
24
|
+
if (rec.passed)
|
|
25
|
+
return "";
|
|
26
|
+
if (rec.total !== undefined && rec.failureCount > 0)
|
|
27
|
+
return `${rec.failureCount} of ${rec.total} failed`;
|
|
28
|
+
if (rec.failureCount > 0)
|
|
29
|
+
return `${rec.failureCount} failure${rec.failureCount === 1 ? "" : "s"}`;
|
|
30
|
+
return "";
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The one-shot summary's block (the CI reader). Printed next to the exit code
|
|
34
|
+
* CI already trusts, for BOTH a completed run and one that gave up, so the
|
|
35
|
+
* line that says "completed" is never read on its own.
|
|
36
|
+
*
|
|
37
|
+
* "none ran this turn" is a sentence, not an omitted row: the whole point of
|
|
38
|
+
* the record is that the absence of verification is visible.
|
|
39
|
+
*/
|
|
40
|
+
export function verificationTurnLines(turn, t) {
|
|
41
|
+
const lines = [];
|
|
42
|
+
const key = t.strong("verification");
|
|
43
|
+
if (turn.verifications.length === 0) {
|
|
44
|
+
lines.push(`${key} ${t.warning("none ran this turn")}`);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
turn.verifications.forEach((rec, i) => {
|
|
48
|
+
lines.push(`${i === 0 ? key : " ".repeat(12)} ${describeRun(rec, t)}`);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
turn.externalChanges.forEach((change, i) => {
|
|
52
|
+
lines.push(`${i === 0 ? t.strong("refused") : " ".repeat(7)} ${t.warning(`${change.path} ${change.what} — nothing was written`)}`);
|
|
53
|
+
});
|
|
54
|
+
return lines;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The `## Verification` section for a PR body, from the runs a session
|
|
58
|
+
* recorded — newest first, with their timestamps, so a run from before the
|
|
59
|
+
* last edit is dated rather than presented as current. Returns `null` when
|
|
60
|
+
* nothing ran: a missing section is the honest shape for missing evidence.
|
|
61
|
+
*
|
|
62
|
+
* `from` names where the runs were read from when it is NOT the live session
|
|
63
|
+
* — `cruxy pr` runs outside any session and reads the project's latest log —
|
|
64
|
+
* so the header never says "this session" about a session that has ended.
|
|
65
|
+
*/
|
|
66
|
+
export function verificationMarkdown(runs, opts = {}) {
|
|
67
|
+
if (runs.length === 0)
|
|
68
|
+
return null;
|
|
69
|
+
const shown = [...runs].reverse().slice(0, opts.limit ?? MARKDOWN_LIMIT);
|
|
70
|
+
const items = shown.map((rec) => {
|
|
71
|
+
const exit = rec.exitCode === null ? "no exit code" : `exit ${rec.exitCode}`;
|
|
72
|
+
const counts = countClause(rec);
|
|
73
|
+
return (`- \`${rec.command}\` — ${exit}${counts ? ` (${counts})` : ""}, ` +
|
|
74
|
+
`${formatDuration(rec.durationMs)}, via ${rec.tool} at ${rec.at}`);
|
|
75
|
+
});
|
|
76
|
+
const omitted = runs.length - shown.length;
|
|
77
|
+
return [
|
|
78
|
+
`Runs recorded by cruxy ${opts.from ?? "this session"}, newest first (exit codes as observed; nothing inferred):`,
|
|
79
|
+
"",
|
|
80
|
+
...items,
|
|
81
|
+
...(omitted > 0
|
|
82
|
+
? ["", `…and ${omitted} earlier run${omitted === 1 ? "" : "s"}.`]
|
|
83
|
+
: []),
|
|
84
|
+
].join("\n");
|
|
85
|
+
}
|
|
86
|
+
/** Most runs listed in a PR body. */
|
|
87
|
+
export const MARKDOWN_LIMIT = 8;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cruxy/cli",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.3",
|
|
4
4
|
"description": "an agentic coding CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -32,8 +32,9 @@
|
|
|
32
32
|
"commander": "^12.1.0",
|
|
33
33
|
"fastembed": "^2.1.0",
|
|
34
34
|
"picocolors": "^1.1.1",
|
|
35
|
+
"tar": "^7.5.22",
|
|
35
36
|
"tinyglobby": "^0.2.10",
|
|
36
|
-
"undici": "^6.
|
|
37
|
+
"undici": "^6.28.1",
|
|
37
38
|
"zod": "^3.23.8",
|
|
38
39
|
"zod-to-json-schema": "^3.23.5",
|
|
39
40
|
"@cruxy/sdk": "0.8.0"
|