@useshifu/coding-harness 0.3.29 → 0.3.31

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.
@@ -120,7 +120,7 @@ function openCodeSources(selection, rows, scheduled = false) {
120
120
  }
121
121
 
122
122
  function sourcePacket(selection, records, scheduled) {
123
- const adapters = { codex: codexSources, claude_code: claudeSources, opencode: openCodeSources };
123
+ const adapters = { codex: codexSources, claude_code: claudeSources, opencode: openCodeSources, cursor: require("./cursor-sessions.js").sources };
124
124
  if (scheduled && selection.toTurn > completedSourceTurn(selection, records)) throw new Error("The selected original range includes an unfinished turn. Nothing was synced.");
125
125
  const { turnCount, sources } = adapters[selection.harness](selection, records, scheduled);
126
126
  if (selection.toTurn > turnCount) throw new Error("The selected original turns are unavailable locally. Nothing was reconstructed or synced.");
@@ -142,6 +142,7 @@ function scheduledSourcePacket(selection, records) {
142
142
  // A later human message closes its predecessor. The trailing human turn needs
143
143
  // explicit terminal metadata; age and intermediate text never close it.
144
144
  function completedSourceTurn(selection, records) {
145
+ if (selection.harness === "cursor") return require("./cursor-sessions.js").completedTurn(records);
145
146
  let turnCount = 0;
146
147
  let closed = false;
147
148
  if (selection.harness === "codex") {
@@ -198,4 +199,29 @@ function completedSourceTurn(selection, records) {
198
199
  return Math.max(0, turnCount - (closed ? 0 : 1));
199
200
  }
200
201
 
201
- module.exports = { selectedSourcePacket, scheduledSourcePacket, completedSourceTurn };
202
+ function continuitySourcePacket(selection, records, minimumTurn = 1) {
203
+ const packet = scheduledSourcePacket(selection, records);
204
+ let first = Math.max(1, selection.fromTurn - 6, minimumTurn);
205
+ const adapters = { codex: codexSources, claude_code: claudeSources, opencode: openCodeSources, cursor: require("./cursor-sessions.js").sources };
206
+ const references = first < selection.fromTurn
207
+ ? adapters[selection.harness]({ ...selection, fromTurn: first, toTurn: selection.fromTurn - 1 }, records, true).sources : [];
208
+ const originalFirst = first;
209
+ let referenceSources = references;
210
+ function oversized() {
211
+ return Buffer.byteLength(JSON.stringify(referenceSources)) > 64 * 1024 ||
212
+ packet.sources.length + referenceSources.length > MAX_SOURCE_MESSAGES ||
213
+ Buffer.byteLength(JSON.stringify({ ...packet, referenceSources })) + 512 > MAX_PACKET_BYTES;
214
+ }
215
+ while (referenceSources.length && oversized()) {
216
+ first = referenceSources[0].turn + 1;
217
+ referenceSources = references.filter((source) => source.turn >= first);
218
+ }
219
+ return { ...packet, referenceSources, referenceCoverage: {
220
+ fromTurn: referenceSources.length ? referenceSources[0].turn : selection.fromTurn,
221
+ toTurn: selection.fromTurn - 1,
222
+ limited: first > Math.max(1, selection.fromTurn - 6) || minimumTurn > Math.max(1, selection.fromTurn - 6),
223
+ droppedTurns: Math.max(0, first - originalFirst),
224
+ } };
225
+ }
226
+
227
+ module.exports = { selectedSourcePacket, scheduledSourcePacket, continuitySourcePacket, completedSourceTurn };
package/bin/v5-payload.js CHANGED
@@ -76,7 +76,7 @@ function itemReferences(value, count, maximum, field, index, target) {
76
76
 
77
77
  function preparedPayload(packet, output) {
78
78
  exactObject(output, ["title", "summary", "decisions", "verification", "evidence"]);
79
- if (!packet || !["codex", "claude_code", "opencode"].includes(packet.harness) || typeof packet.sessionRef !== "string" ||
79
+ if (!packet || !["codex", "claude_code", "opencode", "cursor"].includes(packet.harness) || typeof packet.sessionRef !== "string" ||
80
80
  !Number.isInteger(packet.fromTurn) || !Number.isInteger(packet.toTurn) || packet.fromTurn < 1 || packet.toTurn < packet.fromTurn ||
81
81
  packet.toTurn > 1_000_000 || packet.toTurn - packet.fromTurn >= 12 || !Array.isArray(packet.sources)) {
82
82
  throw new Error("The selected source packet has invalid trusted metadata.");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@useshifu/coding-harness",
3
- "version": "0.3.29",
3
+ "version": "0.3.31",
4
4
  "description": "Scheduled, redacted coding-harness activity sync for Shifu",
5
5
  "bin": {
6
6
  "coding-harness": "bin/shifu-harness.js",
@@ -12,7 +12,7 @@ Before first connection or MCP personalization, ask for any choices that are not
12
12
  When asked to connect Shifu context, run:
13
13
 
14
14
  ```sh
15
- npx --yes @useshifu/coding-harness@0.3.29 mcp-setup --harness codex
15
+ npx --yes @useshifu/coding-harness@0.3.30 mcp-setup --harness codex
16
16
  ```
17
17
 
18
18
  MCP setup verifies the connection and tools, saves the choices and installs instructions; it does not sync sessions or upload the selected history. History selection governs eligible work for subsequent sync. Do not start sync as part of this setup unless the user separately asks for it. If a saved connection exists, reuse its key and do not run `connect` again.
@@ -117,7 +117,7 @@ For an explicit sync request, first read `status` to determine the saved approva
117
117
 
118
118
  Use `kind: "activity"` for general harness work; it does not require a technical scope. Evidence may be empty when the reviewed source contains no durable context. Never invent impact, ownership, verification, or outcomes. A requested check, assistant proposal, or reported result must retain that status even when it is useful context.
119
119
 
120
- Make each supported item useful for later recall: retain the described action, feature or project purpose, specific problem, approach, and reported verification or outcome with its status and ownership intact. Preserve supported technologies, design patterns, configuration choices, and measured results; these are useful work details, not identifiers to redact. A descriptive project label such as "payment reconciliation service" is useful; synthesize it from the work's purpose instead of copying a raw project label that might contain a company or person's name. Preserve supported decisions and their rationale, accepted and rejected tradeoffs, lessons, and observed outcomes. Keep proposals explicitly labeled as proposals; do not turn an agent suggestion into a user-adopted decision or infer personal ownership. Use statements, per-item work context, linked decisions and verification, and permitted source metadata. Keep distinct facts separate, including two fixes in one feature that addressed different problems. Omit names of companies and people, customer details, proprietary identifiers, paths, code snippets, credentials, and unsupported impact. If a detail cannot be safely described, keep the supported parts. Prefer a summary that names the main distinct work items over a generic count alone.
120
+ Make each supported item useful for later recall: retain the described action, feature or project purpose, specific problem, approach, and reported verification or outcome with its status and ownership intact. Preserve supported technologies, design patterns, configuration choices, and measured results; these are useful work details, not identifiers to redact. A descriptive project label such as "payment reconciliation service" is useful; synthesize it from the work's purpose instead of copying a raw project label that might contain a company or person's name. Preserve supported decisions and their rationale, accepted and rejected tradeoffs, lessons, and observed outcomes. Keep proposals explicitly labeled as proposals; do not turn an agent suggestion into a user-adopted decision or infer personal ownership. Use statements, per-item work context, linked decisions and verification, and permitted source metadata. Keep distinct facts separate, including two fixes in one feature that addressed different problems. Preserve the code-permitted public technology labels Turbopuffer, PostgreSQL, Go, TypeScript, React and Node.js when grounded and relevant. This does not authorize confidential customer or employer relationships. Omit other company and person names, customer details, proprietary identifiers, paths, code snippets, credentials, and unsupported impact. If a detail cannot be safely described, keep the supported parts. Prefer a summary that names the main distinct work items over a generic count alone.
121
121
 
122
122
  ```json
123
123
  {
@@ -157,3 +157,9 @@ Only when the user explicitly asks to force-sync, add `--force` to `sessions` wi
157
157
  Re-review each returned range with `review --harness codex --session-ref <sessionRef> --force --from-turn <fromTurn> --to-turn <toTurn>` and the same window (or `--all` for explicitly selected backfill/count selection). No prior sync ID is required. Read the returned final notes semantically and synthesize meaningful, attributable work evidence; do not use `payloadForSegment` or its unattended keyword projection for force sync. Completed work remains supported when the note uses Markdown such as `**Implemented**` or names a technique in inline code such as `Rust`. Retain supported technologies, design patterns, the problem, approach, and verified result while redacting names and sensitive identifiers. Never send an empty evidence list or a title-only replacement. If the notes support no work items, report that range as not replaced and leave its existing work and checkpoints untouched. Keep the returned reference and range unchanged and include `force: true` in the prepared payload. Send with `sync --harness codex --force` (plus `--approved` only after manual approval). If accepted ranges changed and partially overlap the selection, stop and re-discover/re-review the complete ranges instead of guessing boundaries.
158
158
 
159
159
  Force sync creates missing ranges or replaces existing exact ranges, preserves sync history, and never resets or lowers checkpoints. Automatic retries preserve the accepted result even if another force sync finishes meanwhile. A new invocation is a new explicit force request. Existing AI Profile observations stay unchanged. Do not add force to scheduled sync, approval queues, or file sync. Existing conversations keep their context; start a new chat in Shifu to use the latest work context.
160
+
161
+ ## Continuity preparation and review holds
162
+
163
+ Scheduled preparation and pending review use bounded original lookback, code-bound entity placeholders and a separate local continuity outbox. Never add continuity fields to a v5 payload or rewrite a frozen queued body. `status` separates preparation, base receipt and companion attachment. A base receipt does not establish successful continuity attachment. Missing server capability leaves the frozen metadata pending. Do not guess a target sync from turn ranges.
164
+
165
+ A preparation hold survives restarts and stops after two native attempts for unchanged input. Inspect its code-owned reason. Genuine neutral empties stay valid; never create filler evidence to clear a hold. A specific authorized retry of an unqueued held range can use `retry-preparation --harness codex --session-ref <opaque-session> --from-turn <original-start>`; this cannot replay accepted history or regenerate frozen transport. Replacing the key or API endpoint quarantines old checkpoints, queues, local entity dictionaries and continuity metadata. An interrupted replacement holds sync until connect resumes with the same selected connection. Do not upload, display or copy the raw-name dictionary into chat.