@useshifu/coding-harness 0.3.19 → 0.3.20

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # Shifu coding-harness connector
2
2
 
3
- `@useshifu/coding-harness` connects Codex, Claude Code, or OpenCode to Shifu and watches one local input folder. Coding-session sync reads final-assistant notes, never user prompts or raw transcripts, and sends incremental redacted activity through durable checkpoints. Folder files are sent over TLS for server-side parsing, sanitization, and user-attribution checks; the local runner does not redact file contents.
3
+ `@useshifu/coding-harness` connects Codex, Claude Code, or OpenCode to Shifu and watches one local input folder. Session sync includes coding work and non-coding work chats: research, planning, writing, marketing, career development, leadership, and learning discussions. It reads final-assistant notes, never sends user prompts or raw transcripts, and sends incremental redacted activity through durable checkpoints. Folder files are sent over TLS for server-side parsing, sanitization, and user-attribution checks; the local runner does not redact file contents.
4
4
 
5
5
  ## Connect
6
6
 
@@ -32,6 +32,8 @@ To disconnect this device, run `npx --yes @useshifu/coding-harness disconnect --
32
32
 
33
33
  ## Operate
34
34
 
35
+ Version `0.3.20` expands the shared extractor to capture recognized work discussions and explanatory final answers without requiring code changes or completed-action wording. Discussion evidence uses neutral wording and excludes measured outcomes from explanations; proposals remain separate from adopted decisions. Automatic extraction uses controlled topics and details, so unfamiliar subjects may still need semantic review through the sync skill. Previously checkpointed chats are not replayed by an upgrade; an explicit force sync can re-review missed content.
36
+
35
37
  Version `0.3.11` adds rolling days-based windows and explicit force replacement of reviewed segments. Force replacement requires backend migration 049 and the matching connector endpoints to be deployed first.
36
38
 
37
39
  Version `0.3.12` makes force sync independent of local and server checkpoints, creates missing work, and protects automatic retries from overwriting a newer force sync. Deploy backend migrations 049 and 050 before using it.
@@ -112,7 +114,7 @@ Setup preserves other instruction text and MCP settings. Package installation re
112
114
  The context branch adds a remote MCP connection using the same saved Codex key:
113
115
 
114
116
  ```sh
115
- npx --yes @useshifu/coding-harness@0.3.19 mcp-setup --harness codex --mcp-url https://YOUR-BRANCH-HOST/mcp
117
+ npx --yes @useshifu/coding-harness@0.3.20 mcp-setup --harness codex --mcp-url https://YOUR-BRANCH-HOST/mcp
116
118
  ```
117
119
 
118
120
  For development, install dependencies and run from the checkout root:
@@ -143,7 +145,7 @@ Official configuration reference: https://learn.chatgpt.com/docs/config-file/con
143
145
  OpenCode uses the same `/mcp` endpoint and three tools, authenticated with its own saved OpenCode connection key:
144
146
 
145
147
  ```sh
146
- npx --yes @useshifu/coding-harness@0.3.19 mcp-setup --harness opencode --mcp-url https://YOUR-SHIFU-HOST/mcp
148
+ npx --yes @useshifu/coding-harness@0.3.20 mcp-setup --harness opencode --mcp-url https://YOUR-SHIFU-HOST/mcp
147
149
  ```
148
150
 
149
151
  For checkout usage, install dependencies with `npm ci --prefix packages/shifu-coding-harness --ignore-scripts` from the checkout root, then run the checkout CLI with the same arguments. Setup preserves existing sync settings and other MCP servers, checks authenticated initialization and tool discovery, and installs the `shifu-context` usage instructions. A missing OpenCode connection prompts for its key in the terminal. A Codex key cannot authorize an OpenCode connection.
@@ -159,7 +161,7 @@ Official references: [MCP servers](https://docs.opencode.ai/docs/mcp-servers/) a
159
161
  Claude Code connects to the same `/mcp` endpoint and three tools with its own saved connection key:
160
162
 
161
163
  ```sh
162
- npx --yes @useshifu/coding-harness@0.3.19 mcp-setup --harness claude_code --mcp-url https://YOUR-SHIFU-HOST/mcp
164
+ npx --yes @useshifu/coding-harness@0.3.20 mcp-setup --harness claude_code --mcp-url https://YOUR-SHIFU-HOST/mcp
163
165
  ```
164
166
 
165
167
  For checkout usage, install dependencies as above and run the checkout CLI with these arguments. Setup checks the existing Claude Code key, authenticated initialization and tool discovery, and installs the `shifu-context` skill. It preserves the sync endpoint, schedule, checkpoints and other MCP servers. A missing connection prompts for a Claude Code key in the terminal; do not substitute a Codex or OpenCode key.
@@ -40,7 +40,7 @@ const MAX_TURNS_PER_SEGMENT = 12;
40
40
  const MAX_TITLE_LENGTH = 160;
41
41
  const MAX_WORK_DETAIL_LENGTH = 600;
42
42
  const CONFIG_VERSION = 2;
43
- const RUNNER_VERSION = "0.3.19";
43
+ const RUNNER_VERSION = "0.3.20";
44
44
  const REDACTION_VERSION = 4;
45
45
  const DEFAULT_INTERVAL_HOURS = 1;
46
46
  const LEGACY_INTERVAL_HOURS = 4;
@@ -608,6 +608,10 @@ const WORK_ACTIONS = [
608
608
  { key: "rejected", title: "Rejected", pattern: /^(?:I\s+|We\s+)?(?:rejected|ruled out)\b/i },
609
609
  { key: "proposed", title: "Proposed", pattern: /^(?:I\s+|We\s+)?(?:proposed|recommended|suggested)\b/i },
610
610
  { key: "learned", title: "Learned", pattern: /^(?:I\s+|We\s+)?(?:learned|learnt)\b/i },
611
+ { key: "discussed", title: "Discussed", pattern: /^(?:I\s+|We\s+)?(?:discussed|explored)\b/i },
612
+ { key: "explained", title: "Explained", pattern: /^(?:I\s+|We\s+)?(?:explained|clarified)\b/i },
613
+ { key: "outlined", title: "Outlined", pattern: /^(?:I\s+|We\s+)?outlined\b/i },
614
+ { key: "analyzed", title: "Analyzed", pattern: /^(?:I\s+|We\s+)?analy[sz]ed\b/i },
611
615
  ];
612
616
 
613
617
  const WORK_OBJECTS = [
@@ -642,6 +646,11 @@ const WORK_OBJECTS = [
642
646
  { key: "security", title: "security controls", pattern: /\b(?:security|vulnerability|secret handling)\b/i },
643
647
  { key: "research", title: "product research", pattern: /\b(?:product discovery|user research|customer research)\b/i },
644
648
  { key: "planning", title: "project plan", pattern: /\b(?:roadmap|project plan|delivery plan)\b/i },
649
+ { key: "marketing", title: "marketing strategy", pattern: /\b(?:marketing|go.to.market|customer acquisition|content strategy)\b/i },
650
+ { key: "business", title: "business planning", pattern: /\b(?:business plan|business strategy|pricing strategy|market positioning)\b/i },
651
+ { key: "career", title: "career planning", pattern: /\b(?:career|job search|interview preparation|resume|résumé)\b/i },
652
+ { key: "leadership", title: "leadership practices", pattern: /\b(?:leadership|team management|mentoring|delegation)\b/i },
653
+ { key: "architecture", title: "system design", pattern: /\b(?:architecture|system design|service boundaries)\b/i },
645
654
  ];
646
655
 
647
656
  // Only controlled feature descriptions leave the device during unattended sync.
@@ -664,6 +673,13 @@ const WORK_CONTEXTS = [
664
673
  ];
665
674
 
666
675
  const WORK_DETAILS = [
676
+ { title: "target audience", pattern: /\btarget audience\b/i },
677
+ { title: "customer needs", pattern: /\bcustomer needs\b/i },
678
+ { title: "prioritization", pattern: /\b(?:prioriti[sz]ation|priorities)\b/i },
679
+ { title: "tradeoffs", pattern: /\btrade.?offs?\b/i },
680
+ { title: "goals", pattern: /\bgoals?\b/i },
681
+ { title: "risks", pattern: /\brisks?\b/i },
682
+ { title: "constraints", pattern: /\bconstraints?\b/i },
667
683
  { title: "timeouts", pattern: /\btimeouts?\b/i },
668
684
  { title: "duplicates", pattern: /\bduplicat(?:e|es|ed|ion)\b/i },
669
685
  { title: "stale data", pattern: /\bstale (?:data|results?|cache)\b/i },
@@ -766,7 +782,7 @@ function controlledDetails(text) {
766
782
 
767
783
  const ORGANIZATION_WORK_WORDS = new Set([
768
784
  "acceptance", "commitment", "commitments", "approval", "approves", "approved", "requirements", "support",
769
- "research", "experience", "onboarding", "billing", "flow", "plan", "planning", "management",
785
+ "research", "needs", "experience", "onboarding", "billing", "flow", "plan", "planning", "management",
770
786
  "implementation", "status", "owner", "ownership", "named",
771
787
  ]);
772
788
 
@@ -866,12 +882,21 @@ function safeActivityEvidence(notes) {
866
882
  continue;
867
883
  }
868
884
  if (rawLine.trimEnd().endsWith("?")) continue;
869
- for (const [segmentIndex, line] of activitySegments(rawLine).entries()) {
885
+ if (/^\s*(?:>|["“'])/.test(rawLine)) continue;
886
+ const text = rawLine.replace(/\*\*|`/g, "");
887
+ const activities = activitySegments(text);
888
+ // A conversation is useful context without implying adoption or completion.
889
+ const discussion = activities.length === 0;
890
+ if (discussion && (text.trim().split(/\s+/).length < 5 ||
891
+ /^\s*(?:[-*]\s+)?(?:no\b|nothing\b|not\b|(?:I|we)\s+(?:cannot|can't|did not|didn't|have not|haven't)\b)/i.test(text) ||
892
+ /\b(?:will|can|could|would|should|might)\s+(?:discuss|explore|explain|analy[sz]e|outline|review|talk|research|plan|learn)\b/i.test(text))) continue;
893
+ for (const [segmentIndex, line] of (discussion ? [`Discussed ${text}`] : activities).entries()) {
870
894
  const clauses = line.split(/\s+(?:and|but|while)\s+|[;—]\s*/i);
871
895
  const nextAction = clauses.findIndex((clause, index) => index > 0 && WORK_ACTIONS.some((item) => item.pattern.test(clause)));
872
896
  const workClause = withoutNamedLabels(nextAction > 0 ? clauses.slice(0, nextAction).join(" and ") : line);
873
897
  let action = WORK_ACTIONS.find((item) => item.pattern.test(line));
874
898
  if (action?.key === "decided" && /^(?:I\s+|We\s+)?decided\s+not\s+to\b/i.test(line)) action = WORK_ACTIONS.find((item) => item.key === "rejected");
899
+ const conversational = discussion || ["discussed", "explained", "outlined", "analyzed"].includes(action?.key);
875
900
  const detailSource = workClause.split(/\b(?:about|titled|instead of|rather than)\b/i, 1)[0];
876
901
  const contexts = controlledContexts(detailSource);
877
902
  const featureContexts = contexts === null ? [] : contexts.length ? contexts : sectionContexts;
@@ -882,6 +907,7 @@ function safeActivityEvidence(notes) {
882
907
  if (match && match.index < objectPosition) { object = item; objectPosition = match.index; }
883
908
  }
884
909
  object ||= featureContexts[0];
910
+ if (!object && conversational) object = TECHNICAL_DETAILS.find((item) => item.pattern.test(detailSource));
885
911
  if (!action || !object) continue;
886
912
  const context = ["interview_feedback", "professional_post"].includes(object.key) ? [] : featureContexts.filter((item) => item !== object);
887
913
  if (["test", "docs"].includes(object.key) && !context.length) {
@@ -889,11 +915,12 @@ function safeActivityEvidence(notes) {
889
915
  const distinct = subjects.filter((item, index) => subjects.findIndex((subject) => subject.key === item.key) === index);
890
916
  if (distinct.length <= 2) context.push(...distinct.map((item) => ({ ...item, phrase: item.title })));
891
917
  }
892
- const details = controlledDetails(detailSource).filter((detail) => !object.title.includes(detail));
893
- if (["test", "docs", "research", "planning"].includes(object.key) && !context.length && !details.length) continue;
918
+ const details = controlledDetails(detailSource).filter((detail) => !object.title.includes(detail) &&
919
+ (!conversational || [...WORK_DETAILS, ...TECHNICAL_DETAILS].some((item) => item.title === detail && !["staging measurement", "production impact not measured"].includes(detail))));
920
+ if ((discussion || ["test", "docs", "research", "planning"].includes(object.key)) && !context.length && !details.length) continue;
894
921
  const title = `${action.title} ${object.title}${context.length ? ` for ${context.map((item) => item.phrase).join(" and ")}` : ""}`;
895
922
  let statement = `${title}${details.length ? ` (${details.join(", ")})` : ""}.`;
896
- for (const detail of controlledPlanningContext(withoutNamedLabels(line), action.key)) {
923
+ for (const detail of conversational ? [] : controlledPlanningContext(withoutNamedLabels(line), action.key)) {
897
924
  if (statement.length + detail.length + 2 <= MAX_WORK_DETAIL_LENGTH) statement += ` ${detail}.`;
898
925
  }
899
926
  const identity = `${turn}:${statement}`;
@@ -2,6 +2,8 @@
2
2
  description: Inspect or sync redacted OpenCode activity using the saved Shifu policy.
3
3
  ---
4
4
 
5
+ Include non-coding work chats as well as implementation sessions. Read final answers semantically and retain useful research, planning, marketing, career, leadership, and learning context even without code changes or completed-action wording. Use neutral discussion evidence for explanations; proposals are not adopted decisions, and explanations do not prove completed work or demonstrated learning.
6
+
5
7
  Before sync, the runner installs Shifu's exact `recommendedPackageVersion` only if its current version is older. Equal or newer versions are left alone. Update failures allow sync to continue; do not independently install npm latest.
6
8
 
7
9
  Run `npx --yes @useshifu/coding-harness status --harness opencode` first.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@useshifu/coding-harness",
3
- "version": "0.3.19",
3
+ "version": "0.3.20",
4
4
  "description": "Scheduled, redacted coding-harness activity sync for Shifu",
5
5
  "bin": {
6
6
  "coding-harness": "bin/shifu-harness.js",
@@ -10,7 +10,7 @@ description: Consult Shifu when a choice depends on missing user or project hist
10
10
  When asked to connect Shifu context, run:
11
11
 
12
12
  ```sh
13
- npx --yes @useshifu/coding-harness@0.3.19 mcp-setup --harness codex
13
+ npx --yes @useshifu/coding-harness@0.3.20 mcp-setup --harness codex
14
14
  ```
15
15
 
16
16
  For a branch deployment, append `--mcp-url` with the user's supplied HTTPS endpoint ending in `/mcp`. Keep the existing sync API endpoint. The CLI reuses this harness's saved key, checks the authenticated tools, and preserves existing settings. Codex and Claude Code use local credential helpers; OpenCode uses its native `{file:...}` substitution pointing to a private credential file. The key is never placed literally in MCP configuration. If no connection exists, the CLI asks for this harness's key in the terminal. Never request or print the key in chat or place it in command arguments. When input is unavailable, have the user run the command in an interactive terminal. Do not substitute plaintext credentials for an unsupported credential mechanism.
@@ -7,7 +7,9 @@ description: Connect, configure, inspect, or sync coding-harness activity, AI Pr
7
7
 
8
8
  Before manual or scheduled sync, the runner checks Shifu's `recommendedPackageVersion`. It automatically installs that exact release only when the installed version is older; equal or newer versions are left alone. Do not independently install npm latest. If the check or update fails, continue syncing with the current runner. Connection settings, pending work, checkpoints, and the schedule are preserved.
9
9
 
10
- Shifu records useful work completed through the harness. Work may be engineering, product discovery, writing, interview feedback, research, planning, or another user-directed activity. Do not force non-engineering work into engineering categories.
10
+ Shifu records useful work and work discussions through the harness. Include non-coding chat sessions about research, planning, writing, marketing, career development, leadership, decisions, and learning; code changes and tool calls are not required. Do not force non-engineering work into engineering categories.
11
+
12
+ Read final answers semantically, including explanatory prose without completed-action wording. Retain supported discussion topics, constraints, alternatives, rationale, and conclusions as activity context. Use neutral wording such as "Discussed" or "Explained" when the notes support a conversation rather than completed work. Keep recommendations and proposals distinct from adopted decisions; do not assert that the user learned, implemented, or achieved something merely because the assistant described it. Skip casual chat without durable work context.
11
13
 
12
14
  Never include user prompts, raw transcripts, tool output, source code, commands, credentials, URLs, file paths, company or person names, customer details, or proprietary identifiers in a coding-session payload. Synthesize descriptive project labels from their purpose rather than copying a raw name. The local coding runner reads final assistant notes for career activity and scans user turns locally for fixed AI Profile signals; it sends neither raw source. Files placed in the user's chosen Shifu input folder are a separate path: the runner sends supported files over TLS for server-side parsing and sanitization. Do not describe folder files as locally redacted.
13
15