@dzhechkov/harness-cli 0.3.260 → 0.3.262
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/.dz-manifest.json +7 -7
- package/README.md +13 -3
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +20 -8
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/sbom.json +6 -6
- package/src/cli.ts +19 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dzhechkov/harness-cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.262",
|
|
4
4
|
"description": "The dz CLI — install AI skills for Claude Code, Codex, OpenCode, Hermes, OpenClaude, GitHub Copilot. 35 commands, 13 presets, 6 platform targets.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
package/sbom.json
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"hashes": [
|
|
26
26
|
{
|
|
27
27
|
"alg": "SHA-256",
|
|
28
|
-
"content": "
|
|
28
|
+
"content": "af18869081f5141177b6427e812d724e15995d49b10cf67f24803eb5e1d79cb5"
|
|
29
29
|
}
|
|
30
30
|
]
|
|
31
31
|
},
|
|
@@ -105,7 +105,7 @@
|
|
|
105
105
|
"hashes": [
|
|
106
106
|
{
|
|
107
107
|
"alg": "SHA-256",
|
|
108
|
-
"content": "
|
|
108
|
+
"content": "02a2ba1def8a57e1d4dcde048d5a62af19ab4cd825c98bcfbe8ac0df7de2062c"
|
|
109
109
|
}
|
|
110
110
|
]
|
|
111
111
|
},
|
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
"hashes": [
|
|
116
116
|
{
|
|
117
117
|
"alg": "SHA-256",
|
|
118
|
-
"content": "
|
|
118
|
+
"content": "8d3674dc681dc2493886534c8a30e124664a158fd4f7f2da476f5ff2ec615edd"
|
|
119
119
|
}
|
|
120
120
|
]
|
|
121
121
|
},
|
|
@@ -125,7 +125,7 @@
|
|
|
125
125
|
"hashes": [
|
|
126
126
|
{
|
|
127
127
|
"alg": "SHA-256",
|
|
128
|
-
"content": "
|
|
128
|
+
"content": "3975feb3b9102aad34cdcc070315a7756ef9241aa2bb618759a1bbac25ec7951"
|
|
129
129
|
}
|
|
130
130
|
]
|
|
131
131
|
},
|
|
@@ -185,7 +185,7 @@
|
|
|
185
185
|
"hashes": [
|
|
186
186
|
{
|
|
187
187
|
"alg": "SHA-256",
|
|
188
|
-
"content": "
|
|
188
|
+
"content": "3e9deb36cf53245aaae26a72de359a7f57e9691d52454266ffe32f61dc963a27"
|
|
189
189
|
}
|
|
190
190
|
]
|
|
191
191
|
},
|
|
@@ -205,7 +205,7 @@
|
|
|
205
205
|
"hashes": [
|
|
206
206
|
{
|
|
207
207
|
"alg": "SHA-256",
|
|
208
|
-
"content": "
|
|
208
|
+
"content": "9549a9864fddc36eb99a172f3f0e7c7e72ae32d36aebadaf826b58af0bed16b4"
|
|
209
209
|
}
|
|
210
210
|
]
|
|
211
211
|
},
|
package/src/cli.ts
CHANGED
|
@@ -2251,6 +2251,14 @@ async function cmdRecall(options: Map<string, string>, flags: Set<string>, cwd:
|
|
|
2251
2251
|
// never receive its promised lift — the feature was weakest in exactly the case it
|
|
2252
2252
|
// exists for (foreign-domain dilution pushing a relevant lesson just past the cut).
|
|
2253
2253
|
// Fetch a bounded surplus, re-rank, then trim to the limit the caller asked for.
|
|
2254
|
+
// EVERY value that reaches an output line goes through this, not just stored fields.
|
|
2255
|
+
// Round 5: `pattern` and `domain` were sanitised but the QUERY and the requested
|
|
2256
|
+
// domain were not, so a caller-supplied newline could still forge a line that looks
|
|
2257
|
+
// like the tool's own — including the boost note a peer reads as a capability probe.
|
|
2258
|
+
// The rule is "one line out per line of output", and it has to hold for every field.
|
|
2259
|
+
const oneLine = (v: string): string => String(v).replace(/[\r\n\u2028\u2029\u0085\v\f]+/g, ' ⏎ ');
|
|
2260
|
+
const shownQuery = oneLine(query);
|
|
2261
|
+
const shownDomain = wantedDomain === undefined ? undefined : oneLine(wantedDomain);
|
|
2254
2262
|
const fetchLimit = wantedDomain !== undefined ? Math.min(limit * 3, limit + 20) : limit;
|
|
2255
2263
|
const result = await recallHybrid(projectRoot, query, { limit: fetchLimit, mode });
|
|
2256
2264
|
|
|
@@ -2278,18 +2286,18 @@ async function cmdRecall(options: Map<string, string>, flags: Set<string>, cwd:
|
|
|
2278
2286
|
}
|
|
2279
2287
|
|
|
2280
2288
|
if (hits.length === 0) {
|
|
2281
|
-
write(`dz recall "${
|
|
2289
|
+
write(`dz recall "${shownQuery}"`);
|
|
2282
2290
|
write(` No matching patterns (teach some with \`dz teach\`, or consolidate sessions).`);
|
|
2283
2291
|
// The domain note must print here too (Codex QE #10): a --domain run with zero hits
|
|
2284
2292
|
// silently said nothing about the domain, so the reader could not tell whether the
|
|
2285
2293
|
// boost had been applied and found nothing, or had not run at all.
|
|
2286
|
-
if (boost !== null &&
|
|
2294
|
+
if (boost !== null && shownDomain !== undefined) write(renderDomainBoostNote(boost, shownDomain));
|
|
2287
2295
|
return 0;
|
|
2288
2296
|
}
|
|
2289
2297
|
const vectorOn = result.vectorEngine !== 'none' && result.vectorError === undefined && mode !== 'lexical';
|
|
2290
2298
|
const lexLabel = result.lexicalBackend === 'sqlite' ? 'SQLite FTS5' : 'keyword (JSON)';
|
|
2291
2299
|
const ranking = vectorOn ? `${lexLabel} + vector (${result.vectorEngine}) ranking` : `${lexLabel} ranking (lexical)`;
|
|
2292
|
-
write(`dz recall "${
|
|
2300
|
+
write(`dz recall "${shownQuery}" — ${hits.length} hit(s), ${ranking}`);
|
|
2293
2301
|
let sawQuarantined = false;
|
|
2294
2302
|
for (const h of hits) {
|
|
2295
2303
|
const backendTag = vectorOn ? ` ⟨${h.backend}⟩` : '';
|
|
@@ -2300,17 +2308,21 @@ async function cmdRecall(options: Map<string, string>, flags: Set<string>, cwd:
|
|
|
2300
2308
|
// the domain-boost note that learning_bridge.py reads as a capability probe. Any
|
|
2301
2309
|
// consumer that parses this output line-wise has the same exposure, so the fix
|
|
2302
2310
|
// belongs at the point of rendering rather than in each reader.
|
|
2303
|
-
|
|
2304
|
-
|
|
2311
|
+
// Sanitise EVERY stored field that reaches the line, and every character a reader
|
|
2312
|
+
// might treat as a break — not just CR/LF. Round 4 forged the domain-boost note
|
|
2313
|
+
// twice over: once through `domain`, which was rendered raw, and once through a
|
|
2314
|
+
// U+2028 that Python's splitlines() honours and this replace did not.
|
|
2315
|
+
const shown = oneLine(h.pattern.pattern).slice(0, 80);
|
|
2316
|
+
write(` [${h.pattern.reward.toFixed(2)}] (${oneLine(h.pattern.domain)})${backendTag}${qTag} ${shown}`);
|
|
2305
2317
|
}
|
|
2306
2318
|
if (sawQuarantined) {
|
|
2307
2319
|
// The loop stays VISIBLE (ADR D2): a quarantined hit is shown, marked, and explained.
|
|
2308
2320
|
write(' ⚠q = quarantined (unproven hypothesis, rank damped) — confirm with dz teach --reinforce, or dz recall --promote <dzId> --apply');
|
|
2309
2321
|
}
|
|
2310
|
-
if (boost !== null &&
|
|
2322
|
+
if (boost !== null && shownDomain !== undefined) {
|
|
2311
2323
|
// Say what the boost did — INCLUDING when it did nothing. A silent reorder would
|
|
2312
2324
|
// let the reader believe the ranking was domain-aware when it had no match to work with.
|
|
2313
|
-
write(renderDomainBoostNote(boost,
|
|
2325
|
+
write(renderDomainBoostNote(boost, shownDomain));
|
|
2314
2326
|
const cutNote = renderDomainCutNote(displaced, limit);
|
|
2315
2327
|
if (cutNote !== '') write(cutNote);
|
|
2316
2328
|
}
|