liteagents 2.22.1 → 2.24.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/CHANGELOG.md +203 -1
- package/README.md +7 -5
- package/package.json +1 -1
- package/packages/ampcode/commands/branch-review.md +180 -14
- package/packages/ampcode/commands/docs-builder/docs-builder.cjs +47 -2
- package/packages/ampcode/commands/refactor.md +71 -3
- package/packages/ampcode/commands/release.md +49 -9
- package/packages/ampcode/commands/remember/AGENT_RULES.md +12 -3
- package/packages/ampcode/commands/remember/friction.cjs +32 -3
- package/packages/ampcode/commands/remember.md +40 -7
- package/packages/ampcode/commands/ship.md +16 -0
- package/packages/claude/commands/branch-review.md +180 -14
- package/packages/claude/commands/docs-builder/docs-builder.cjs +47 -2
- package/packages/claude/commands/refactor.md +71 -3
- package/packages/claude/commands/release.md +49 -9
- package/packages/claude/commands/remember/AGENT_RULES.md +12 -3
- package/packages/claude/commands/remember/friction.cjs +32 -3
- package/packages/claude/commands/remember.md +40 -7
- package/packages/claude/commands/ship.md +16 -0
- package/packages/claude/plugins/live-canvas-marketplace/plugins/live-canvas-channel/package-lock.json +19 -18
- package/packages/droid/commands/branch-review.md +180 -14
- package/packages/droid/commands/docs-builder/docs-builder.cjs +47 -2
- package/packages/droid/commands/refactor.md +71 -3
- package/packages/droid/commands/release.md +49 -9
- package/packages/droid/commands/remember/AGENT_RULES.md +12 -3
- package/packages/droid/commands/remember/friction.cjs +32 -3
- package/packages/droid/commands/remember.md +40 -7
- package/packages/droid/commands/ship.md +16 -0
- package/packages/opencode/command/branch-review.md +180 -14
- package/packages/opencode/command/docs-builder/docs-builder.cjs +47 -2
- package/packages/opencode/command/refactor.md +71 -3
- package/packages/opencode/command/release.md +49 -9
- package/packages/opencode/command/remember/AGENT_RULES.md +12 -3
- package/packages/opencode/command/remember/friction.cjs +32 -3
- package/packages/opencode/command/remember.md +40 -7
- package/packages/opencode/command/ship.md +16 -0
|
@@ -1765,8 +1765,26 @@ function extractToolsFromTurn(event) {
|
|
|
1765
1765
|
const toolName = block.name || 'unknown';
|
|
1766
1766
|
tools.push({ tool: toolName, action: 'call' });
|
|
1767
1767
|
} else if (block.type === 'tool_result') {
|
|
1768
|
-
|
|
1769
|
-
|
|
1768
|
+
// The transcript marks a failed tool call with `is_error`; a success
|
|
1769
|
+
// carries no sentinel in the result text. Reading the text for
|
|
1770
|
+
// 'Exit code 0' matched 1 block in 2623 sampled from the real
|
|
1771
|
+
// corpus, so `result` was 'unknown' on 31 of 34 clusters — and the
|
|
1772
|
+
// case this field exists for is a CLAIMED success the user is
|
|
1773
|
+
// contradicting, which is the one that never fired. Content is also
|
|
1774
|
+
// sometimes an array of blocks (403/2623), which String() turned
|
|
1775
|
+
// into "[object Object]" so no pattern could match it.
|
|
1776
|
+
//
|
|
1777
|
+
// A block with no `is_error` stays unknown on purpose: those are
|
|
1778
|
+
// harness meta-results (skill/agent launches, question answers —
|
|
1779
|
+
// 560/2624 sampled) and calling them success would inflate the very
|
|
1780
|
+
// signal this field is here to detect.
|
|
1781
|
+
const raw = block.content;
|
|
1782
|
+
const result = Array.isArray(raw)
|
|
1783
|
+
? raw.map(b => (b && typeof b === 'object' ? (b.text || '') : String(b || ''))).join('\n')
|
|
1784
|
+
: String(raw || '');
|
|
1785
|
+
if (block.is_error === true) {
|
|
1786
|
+
tools.push({ tool: 'result', action: 'error' });
|
|
1787
|
+
} else if (typeof block.is_error === 'boolean') {
|
|
1770
1788
|
tools.push({ tool: 'result', action: 'success' });
|
|
1771
1789
|
} else if (/Exit code [1-9]|Traceback|Error/.test(result)) {
|
|
1772
1790
|
tools.push({ tool: 'result', action: 'error' });
|
|
@@ -2142,6 +2160,7 @@ function clusterCandidates(allCandidates, canonicalGroups) {
|
|
|
2142
2160
|
errors: b.errors,
|
|
2143
2161
|
peak: b.peak,
|
|
2144
2162
|
texts: b.texts,
|
|
2163
|
+
files: [...b.files],
|
|
2145
2164
|
preceding: b.preceding,
|
|
2146
2165
|
anySelf: b.selfVotes > 0, // at least one self-correction → warn, LLM confirms target
|
|
2147
2166
|
};
|
|
@@ -2166,7 +2185,7 @@ function clusterCandidates(allCandidates, canonicalGroups) {
|
|
|
2166
2185
|
if (best) {
|
|
2167
2186
|
cl = best;
|
|
2168
2187
|
} else {
|
|
2169
|
-
cl = { sig: new Set(), seedSig: new Set(ss.sig), shCount: new Map(), sessions: {}, signals: {}, contexts: [], errors: [], peaks: [], anySelf: false, preceding: null };
|
|
2188
|
+
cl = { sig: new Set(), seedSig: new Set(ss.sig), shCount: new Map(), sessions: {}, signals: {}, contexts: [], errors: [], peaks: [], anySelf: false, preceding: null, files: new Set() };
|
|
2170
2189
|
clusters.push(cl);
|
|
2171
2190
|
}
|
|
2172
2191
|
for (const s of ss.sig) { cl.sig.add(s); cl.shCount.set(s, (cl.shCount.get(s) || 0) + 1); }
|
|
@@ -2178,6 +2197,15 @@ function clusterCandidates(allCandidates, canonicalGroups) {
|
|
|
2178
2197
|
cl.peaks.push(ss.peak);
|
|
2179
2198
|
if (ss.anySelf) cl.anySelf = true;
|
|
2180
2199
|
if (ss.preceding && (!cl.preceding || (ss.preceding.action !== 'none' || ss.preceding.error))) cl.preceding = ss.preceding;
|
|
2200
|
+
// The file referents a cluster's sessions touched. Measured on a 34-cluster real
|
|
2201
|
+
// corpus as the one channel that actually separates clusters: file basenames gave 28
|
|
2202
|
+
// distinct signatures at a 3.7% collision rate, against 13 / 19.3% for the preceding
|
|
2203
|
+
// action+result pair and 10 / 25.8% for tool_sequence. Matching an incoming cluster
|
|
2204
|
+
// to a ledger entry otherwise runs on class_hints alone, and those ARE fragments of
|
|
2205
|
+
// the entry's own evidence quotes — one channel, where identity and proof are the
|
|
2206
|
+
// same strings. These paths are mechanical, so carrying them adds a second channel
|
|
2207
|
+
// without reintroducing an LLM distillation step.
|
|
2208
|
+
for (const f of ss.files) cl.files.add(f);
|
|
2181
2209
|
}
|
|
2182
2210
|
|
|
2183
2211
|
const out = clusters.map(cl => {
|
|
@@ -2251,6 +2279,7 @@ function clusterCandidates(allCandidates, canonicalGroups) {
|
|
|
2251
2279
|
max_peak: peaks[peaks.length - 1],
|
|
2252
2280
|
contexts: cl.contexts,
|
|
2253
2281
|
errors: cl.errors,
|
|
2282
|
+
files: [...cl.files].sort().slice(0, 8), // referents: the discriminative match channel (see merge above)
|
|
2254
2283
|
preceding: cl.preceding, // #4: agent action + result just before the reaction
|
|
2255
2284
|
self_suspect: allSelf || cl.anySelf, // #3: a self-correction is present — LLM confirms target (advisory)
|
|
2256
2285
|
top_keywords: topSh.slice(0, 10),
|
|
@@ -133,6 +133,14 @@ Reads all raw material (`.opencode/stash/*.md` + `.opencode/remember/friction/an
|
|
|
133
133
|
Re-processing a stash whose episode is already filed must not create a near-duplicate
|
|
134
134
|
pair. Every older episode is **folded, then deleted**: its lesson becomes a fact (handed
|
|
135
135
|
to the rewrite above); the narrative is removed. No archive — git has the history.
|
|
136
|
+
**Specify the operation once.** The keep-10 rule is the rule; the set to remove is
|
|
137
|
+
*derived* from it, never supplied alongside it as a second list. Given both, an agent
|
|
138
|
+
applies both and removes their union — observed in the field: a run told to keep 10 and
|
|
139
|
+
handed a 5-entry delete list removed 7, and the 2 extras were never folded, so one
|
|
140
|
+
lesson left memory with nothing carrying it. **No episode is removed whose lesson has
|
|
141
|
+
not been folded into a fact first**, and the two sets must match: state the count
|
|
142
|
+
before, the count after, and name each episode removed. Removed-but-not-folded is a
|
|
143
|
+
defect to report, not a tidy-up.
|
|
136
144
|
- **Antigens section**: only update from friction output (step 4)
|
|
137
145
|
- Write merged result to `.opencode/remember/MEMORY.md` in the format under step 5.
|
|
138
146
|
|
|
@@ -276,7 +284,11 @@ Reads all raw material (`.opencode/stash/*.md` + `.opencode/remember/friction/an
|
|
|
276
284
|
recurrence; a single occurrence has none to track yet. Friction re-scans every
|
|
277
285
|
session log every run, so a later run matches it back to 2+ sessions and seeds it
|
|
278
286
|
then — this does not change matching against an EXISTING entry, which is recurrence
|
|
279
|
-
regardless of the matching cluster's own session count.
|
|
287
|
+
regardless of the matching cluster's own session count. **A match is not an
|
|
288
|
+
increment.** Whether it counts as a new conversation is decided in 4c by
|
|
289
|
+
`friction.cjs count`, which is a no-op when that session hash is already stored — so
|
|
290
|
+
several matches against one entry routinely produce zero increments, and that is
|
|
291
|
+
correct, not a miscount.
|
|
280
292
|
- For `new:<theme>` groups with no ledger match: distinct conversations = distinct
|
|
281
293
|
cluster indices in the group (within one classify batch, no two cluster indices
|
|
282
294
|
share a session hash). `sessions < 2` → writes nothing. `sessions >= 2` → new entry,
|
|
@@ -346,18 +358,39 @@ Reads all raw material (`.opencode/stash/*.md` + `.opencode/remember/friction/an
|
|
|
346
358
|
inline duplication is needed
|
|
347
359
|
- If `.opencode/remember/AGENT_RULES.md` exists (bootstrapped in step 1), compose a second,
|
|
348
360
|
independent section between `<!-- AGENT_RULES:START -->` and `<!-- AGENT_RULES:END -->`
|
|
349
|
-
markers. Unlike MEMORY.md above,
|
|
350
|
-
|
|
351
|
-
|
|
361
|
+
markers. Unlike MEMORY.md above, the file itself is **never `@`-referenced** — an
|
|
362
|
+
`@`-reference hot-loads all ~300 lines into every session, and it is a standards guide
|
|
363
|
+
to consult when designing/building something new, not hot context. The section carries
|
|
364
|
+
a path pointer plus exactly two inline rules: the ones that change what you TYPE, which
|
|
365
|
+
you cannot look up because you do not know you need them. Everything else stays behind
|
|
366
|
+
the pointer. Write the section verbatim, rules first:
|
|
352
367
|
```
|
|
353
368
|
<!-- AGENT_RULES:START -->
|
|
369
|
+
**One writer per piece of state.** One function assigns each field; everything else
|
|
370
|
+
calls it. Grep who writes it before you write it — and if a write can land from a
|
|
371
|
+
callback, thread, or lifecycle, the reader must tell stale from fresh.
|
|
372
|
+
|
|
373
|
+
**Surgical changes only.** Touch what the task requires. Dead code, nits, bugs you
|
|
374
|
+
pass: if it's inside or affects the code you're already changing and the fix changes
|
|
375
|
+
no behavior, fix it and say so — otherwise report it and say what it costs to leave
|
|
376
|
+
it. A problem you don't fix goes in the report, never in a comment.
|
|
377
|
+
|
|
354
378
|
Standards guide (read when designing/building something new, not hot context):
|
|
355
379
|
.opencode/remember/AGENT_RULES.md
|
|
356
380
|
<!-- AGENT_RULES:END -->
|
|
357
381
|
```
|
|
358
|
-
- Each marker pair is independent: if AGENTS.md
|
|
359
|
-
|
|
360
|
-
containing whichever section(s) apply
|
|
382
|
+
- Each marker pair is independent: if AGENTS.md lacks a given pair, append it at the
|
|
383
|
+
end; if a given pair already exists, replace its content in place; if no AGENTS.md
|
|
384
|
+
exists, create one containing whichever section(s) apply.
|
|
385
|
+
- **An existing AGENT_RULES pair is left alone — bootstrap once, never overwrite.** The
|
|
386
|
+
block above is what to write when creating it, not a template to re-impose every run.
|
|
387
|
+
Users trim this section deliberately (a pointer-only variant is common), and rewriting
|
|
388
|
+
it silently re-adds text they removed, on every single run, forever. Observed in the
|
|
389
|
+
field: a run restored the inline rules into a AGENTS.md whose owner had cut them, and
|
|
390
|
+
the edit had to be reverted by hand. This matches how `AGENT_RULES.md` itself is
|
|
391
|
+
handled — bootstrapped once, never overwritten after.
|
|
392
|
+
- If an existing pair is present but its **path pointer** is missing or wrong, that is
|
|
393
|
+
load-bearing: **report it and stop**, do not silently rewrite the section around it.
|
|
361
394
|
|
|
362
395
|
```markdown
|
|
363
396
|
# Project Memory
|
|
@@ -20,6 +20,22 @@ its exit code**. A check you did not run is a **fail**, never a pass. **N/A
|
|
|
20
20
|
requires a stated reason** ("no build script in `package.json`") — N/A must
|
|
21
21
|
never stand in for "didn't get to it."
|
|
22
22
|
|
|
23
|
+
**Capture the exit code of the command itself, never of a pipeline.** Run the
|
|
24
|
+
bare command, then read `$?` on the next line:
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
node "$f" > /tmp/out 2>&1; e=$?
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`$?` after a pipe is the *last element's* status, so the common shape
|
|
31
|
+
`out=$(cmd 2>&1 | tail -1); echo "exit=$?"` reports `tail`'s success — `0` —
|
|
32
|
+
for a suite that exited `2`. Reproduced: a check printing "exit 2:
|
|
33
|
+
prerequisites missing" was recorded as a pass by exactly that loop. Nor does
|
|
34
|
+
`${PIPESTATUS[0]}` rescue it inside a command substitution; it is empty by
|
|
35
|
+
the time you read it. This is the rule the whole gate rests on, and the
|
|
36
|
+
piped form is the natural way to write a multi-suite loop, so it fails
|
|
37
|
+
silently and in the unsafe direction.
|
|
38
|
+
|
|
23
39
|
## Checklist
|
|
24
40
|
- [ ] **Tests pass** — run the project's real test command (`npm test`,
|
|
25
41
|
`pytest`, `go test ./...`, `cargo test`, `make test`).
|