@useshifu/coding-harness 0.2.0 → 0.2.1
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/README.md +3 -3
- package/bin/shifu-harness.js +12 -8
- package/commands/shifu-sync.md +1 -1
- package/package.json +1 -1
- package/skills/shifu-sync/SKILL.md +3 -2
package/README.md
CHANGED
|
@@ -16,14 +16,14 @@ npx @useshifu/coding-harness sessions --harness codex --hours 24
|
|
|
16
16
|
npx @useshifu/coding-harness review --harness codex --session-ref opaque-session-id
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
`review` reads the next contiguous segment of at most 12 unsynced turns locally. Pass the selected `--hours` value to `review` as well; `--all` is reserved for a specifically selected session's older backlog. It shows assistant final notes and
|
|
19
|
+
`review` reads the next contiguous segment of at most 12 unsynced turns locally. Pass the selected `--hours` value to `review` as well; `--all` is reserved for a specifically selected session's older backlog. It shows assistant final notes, candidate work items, and a draft that leaves required sync and work-item titles blank for the reviewer. Candidates are suggestions, not proof or guaranteed redaction. Candidate scope is left unset until a reviewer chooses the smallest supported level. If a segment has more than 64 candidates, rerun `sessions` and `review` with `--turns 1` to narrow it before syncing. Review each work title, detail, and area, prepare any verification, and preserve an item's `itemRef` when a later segment revises the same work. User-message records are omitted, but assistant notes may quote sensitive material. Nothing is uploaded by this command. Repeat discovery after each accepted segment to continue the delta.
|
|
20
20
|
|
|
21
21
|
To submit a reviewed segment, pipe the exact payload to `sync`. The CLI prints it, asks again, and only then sends it to Shifu. Successful responses advance a local checkpoint; the server rejects out-of-order or changed retries.
|
|
22
22
|
|
|
23
23
|
```sh
|
|
24
|
-
printf '%s' '{"harness":"codex","sessionRef":"opaque-session-id","fromTurn":1,"toTurn":8,"summary":"Implemented a focused change and checked the result.","evidence":[{"kind":"implementation","statement":"Implemented a focused connector change.","scope":"service","area":"connector","itemRef":"work_1","verificationRefs":[0]}],"verification":["Focused tests passed."],"decisions":[],"redactionVersion":
|
|
24
|
+
printf '%s' '{"harness":"codex","sessionRef":"opaque-session-id","fromTurn":1,"toTurn":8,"title":"Hardened connector checkpoints","summary":"Implemented a focused change and checked the result.","evidence":[{"kind":"implementation","title":"Added checkpoint recovery","statement":"Implemented a focused connector change.","scope":"service","area":"connector","itemRef":"work_1","verificationRefs":[0]}],"verification":["Focused tests passed."],"decisions":[],"redactionVersion":3}' | npx @useshifu/coding-harness sync --harness codex
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
The server stores each approved, redacted work-item statement as a separate claim with its scope, optional area and item reference, cited verification, and source receipt.
|
|
27
|
+
The server stores each approved sync title and summary, plus every redacted work-item title and statement as a separate claim with its scope, optional area and item reference, cited verification, and source receipt. Uncited verification wording, standalone decisions, raw assistant notes, and transcripts are not retained as claim text. `area`, `itemRef`, and `verificationRefs` are optional; citing a verification item applies only to that work item and is displayed separately from its work statement. A decision becomes a claim only when it is included as an `evidence` item with `kind: "decision"`. At least one reviewed work item is required to advance a checkpoint. The complete cross-component contract is in [coding-session-sync-contract.md](../../docs/coding-session-sync-contract.md).
|
|
28
28
|
|
|
29
29
|
The default API URL is `https://api.useshifu.com`. Override it during local or self-hosted use with `--api-url` on `connect`, or `SHIFU_API_URL`.
|
package/bin/shifu-harness.js
CHANGED
|
@@ -19,14 +19,16 @@ const UNSAFE_CODE_PATTERN = /\b(?:func|class|interface|struct|package|import|sel
|
|
|
19
19
|
const CREDENTIAL_ASSIGNMENT_PATTERN = /\b(?:token|secret|password|api[_-]?key)\s*[:=]\s*\S+/i;
|
|
20
20
|
const CLOUD_CREDENTIAL_PATTERN = /\bAKIA[0-9A-Z]{16}\b|AIza[0-9A-Za-z_-]{20,}/;
|
|
21
21
|
const EVIDENCE_KINDS = new Set(["implementation", "decision"]);
|
|
22
|
-
const EVIDENCE_FIELDS = new Set(["kind", "statement", "scope", "area", "itemRef", "verificationRefs"]);
|
|
23
|
-
const SYNC_FIELDS = new Set(["harness", "sessionRef", "fromTurn", "toTurn", "summary", "evidence", "verification", "decisions", "redactionVersion"]);
|
|
22
|
+
const EVIDENCE_FIELDS = new Set(["kind", "title", "statement", "scope", "area", "itemRef", "verificationRefs"]);
|
|
23
|
+
const SYNC_FIELDS = new Set(["harness", "sessionRef", "fromTurn", "toTurn", "title", "summary", "evidence", "verification", "decisions", "redactionVersion"]);
|
|
24
24
|
const SCOPE_LEVELS = new Set(["unit", "module", "service", "system", "product"]);
|
|
25
25
|
const WORK_AREAS = new Set(["architecture", "api", "backend", "connector", "database", "documentation", "frontend", "performance", "security", "testing", "tooling"]);
|
|
26
26
|
const ITEM_REF_PATTERN = /^[A-Za-z0-9_-]{1,80}$/;
|
|
27
27
|
const MAX_EVIDENCE_ITEMS = 64;
|
|
28
28
|
const MAX_SYNC_ITEMS = 16;
|
|
29
29
|
const MAX_TURNS_PER_SEGMENT = 12;
|
|
30
|
+
const MAX_TITLE_LENGTH = 160;
|
|
31
|
+
const MAX_WORK_DETAIL_LENGTH = 600;
|
|
30
32
|
|
|
31
33
|
function configRoot() {
|
|
32
34
|
return path.join(process.env.XDG_CONFIG_HOME || path.join(os.homedir(), ".config"), "shifu", "coding-harness");
|
|
@@ -207,9 +209,9 @@ function reviewCandidates(notes) {
|
|
|
207
209
|
for (const [noteIndex, { turn, note }] of notes.entries()) {
|
|
208
210
|
for (const [lineIndex, line] of note.split("\n").entries()) {
|
|
209
211
|
const statement = line.trim().replace(/^[-*]\s+/, "");
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
if (
|
|
212
|
+
if (!textIsSafe(statement, MAX_WORK_DETAIL_LENGTH) || /\b(?:tests?|checks?|build|lint|review)\b.*\b(?:passed|pass|completed|succeeded)\.?$/i.test(statement)) continue;
|
|
213
|
+
const kind = /^(decided|chose|selected|kept|rejected)\b/i.test(statement) ? "decision" : "implementation";
|
|
214
|
+
if (seen.has(`${kind}:${statement}`)) continue;
|
|
213
215
|
seen.add(`${kind}:${statement}`);
|
|
214
216
|
const itemRef = `t${turn}_n${noteIndex + 1}_l${lineIndex + 1}`;
|
|
215
217
|
const areas = [...WORK_AREAS].filter((area) => new RegExp(`\\b${area}\\b`, "i").test(statement));
|
|
@@ -395,9 +397,10 @@ function validateSync(input, harness) {
|
|
|
395
397
|
if (!input || Object.keys(input).some((field) => !SYNC_FIELDS.has(field))) throw new Error("Remove unsupported fields from the reviewed sync payload.");
|
|
396
398
|
if (!input || input.harness !== harness || typeof input.sessionRef !== "string" || !textIsSafe(input.sessionRef, 200) || input.sessionRef.length < 8) throw new Error("Add the current opaque sessionRef before syncing.");
|
|
397
399
|
if (!Number.isInteger(input.fromTurn) || !Number.isInteger(input.toTurn) || input.fromTurn < 1 || input.toTurn < input.fromTurn || input.toTurn - input.fromTurn >= MAX_TURNS_PER_SEGMENT) throw new Error("Use a valid incremental range of at most 12 turns.");
|
|
400
|
+
if (input.redactionVersion === 3 && !textIsSafe(input.title, MAX_TITLE_LENGTH)) throw new Error("Add a concise, redacted title for this reviewed sync.");
|
|
398
401
|
if (!textIsSafe(input.summary, 1200)) throw new Error("The summary is empty, too long, or contains sensitive content. Redact it before syncing.");
|
|
399
|
-
if (!Array.isArray(input.evidence) || input.evidence.length < 1 || input.evidence.length > MAX_EVIDENCE_ITEMS || !input.evidence.every((item) => item && EVIDENCE_KINDS.has(item.kind) && SCOPE_LEVELS.has(item.scope) && textIsSafe(item.statement,
|
|
400
|
-
|
|
402
|
+
if (!Array.isArray(input.evidence) || input.evidence.length < 1 || input.evidence.length > MAX_EVIDENCE_ITEMS || !input.evidence.every((item) => item && EVIDENCE_KINDS.has(item.kind) && SCOPE_LEVELS.has(item.scope) && (input.redactionVersion !== 3 || textIsSafe(item.title, MAX_TITLE_LENGTH)) && textIsSafe(item.statement, MAX_WORK_DETAIL_LENGTH))) {
|
|
403
|
+
throw new Error(`evidence must contain 1-${MAX_EVIDENCE_ITEMS} redacted work items with title, detail, kind, and scope.`);
|
|
401
404
|
}
|
|
402
405
|
for (const field of ["verification", "decisions"]) {
|
|
403
406
|
if (!Array.isArray(input[field]) || input[field].length > MAX_SYNC_ITEMS || !input[field].every((item) => textIsSafe(item, 240))) throw new Error(`${field} must contain at most ${MAX_SYNC_ITEMS} redacted statements.`);
|
|
@@ -411,7 +414,7 @@ function validateSync(input, harness) {
|
|
|
411
414
|
item.verificationRefs.every((ref) => Number.isInteger(ref) && ref >= 0 && ref < input.verification.length))))) {
|
|
412
415
|
throw new Error("Each work item must use a supported area, safe itemRef, and distinct indexes into verification.");
|
|
413
416
|
}
|
|
414
|
-
if (input.redactionVersion !== 2) throw new Error("Use redactionVersion
|
|
417
|
+
if (input.redactionVersion !== 2 && input.redactionVersion !== 3) throw new Error("Use redactionVersion 3 for new reviewed syncs.");
|
|
415
418
|
}
|
|
416
419
|
|
|
417
420
|
function validSyncReceipt(receipt, input) {
|
|
@@ -507,6 +510,7 @@ function review(harness) {
|
|
|
507
510
|
source: "Local assistant final notes for unsynced user turns. Candidates are suggestions, not verified or guaranteed redacted; inspect them before constructing a Shifu payload.",
|
|
508
511
|
notes,
|
|
509
512
|
candidates,
|
|
513
|
+
draft: { title: null, summary: null, evidence: candidates.map((candidate) => ({ ...candidate, title: null })) },
|
|
510
514
|
candidateOverflow: candidates.length > MAX_EVIDENCE_ITEMS,
|
|
511
515
|
remainingTurns: selected.session.turnCount - toTurn,
|
|
512
516
|
}, null, 2));
|
package/commands/shifu-sync.md
CHANGED
|
@@ -8,4 +8,4 @@ Use the Shifu reviewed-sync process for the current OpenCode session. Never uplo
|
|
|
8
8
|
npx @useshifu/coding-harness sync --harness opencode
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
The payload must contain `harness`, an opaque `sessionRef`, a contiguous `fromTurn`/`toTurn` range of at most 12 turns, a concise redacted `summary`, 1–64 redacted `evidence` work items (`kind`, `statement`, `scope`), up to 16 redacted `verification` items, up to 16 redacted `decisions`, and `redactionVersion:
|
|
11
|
+
The payload must contain `harness`, an opaque `sessionRef`, a contiguous `fromTurn`/`toTurn` range of at most 12 turns, a concise redacted sync `title`, a redacted `summary`, 1–64 redacted `evidence` work items (`title`, `kind`, `statement`, `scope`), up to 16 redacted `verification` items, up to 16 redacted `decisions`, and `redactionVersion: 3`. Evidence describes the work itself; verification records how it was checked. Scope must be one of `unit`, `module`, `service`, `system`, or `product` and must be reviewed rather than guessed from the candidate. Replace names, paths, URLs, credentials, commands, prompts, source code, customer details, and proprietary identifiers with neutral descriptions.
|
package/package.json
CHANGED
|
@@ -26,11 +26,12 @@ Use this structure:
|
|
|
26
26
|
"sessionRef": "opaque-session-id",
|
|
27
27
|
"fromTurn": 1,
|
|
28
28
|
"toTurn": 12,
|
|
29
|
+
"title": "Hardened connector checkpoints",
|
|
29
30
|
"summary": "Implemented a narrow change and checked the relevant behaviour.",
|
|
30
|
-
"evidence": [{"kind": "implementation", "statement": "Implemented a focused connector change.", "scope": "service"}],
|
|
31
|
+
"evidence": [{"kind": "implementation", "title": "Added checkpoint recovery", "statement": "Implemented a focused connector change.", "scope": "service"}],
|
|
31
32
|
"verification": ["Focused tests passed."],
|
|
32
33
|
"decisions": ["Kept the change within the existing connector boundary."],
|
|
33
|
-
"redactionVersion":
|
|
34
|
+
"redactionVersion": 3
|
|
34
35
|
}
|
|
35
36
|
```
|
|
36
37
|
|