@useshifu/coding-harness 0.3.9 → 0.3.10
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 +6 -0
- package/bin/shifu-harness.js +114 -11
- package/commands/shifu-sync.md +3 -1
- package/package.json +1 -1
- package/skills/shifu-sync/SKILL.md +3 -1
package/README.md
CHANGED
|
@@ -70,3 +70,9 @@ AI Profile observations are created automatically with each coding-session activ
|
|
|
70
70
|
The category is one of `system_design`, `detailed_design`, `implementation`, `debugging_testing`, `production_support`, `research_analysis`, `product_planning`, `writing_communication`, `marketing_growth`, `learning`, or `other`. Evidence dimensions are `task_selection`, `goal_clarity`, `context_sharing`, `constraint_setting`, `work_decomposition`, `iterative_steering`, `critical_judgment`, `verification`, `application`, and `responsible_use`. Automatic observations cite the relevant turn and never infer a limiting behavior from silence. Unsupported dimensions remain unscored.
|
|
71
71
|
|
|
72
72
|
The AI Profile page shows detected categories, model and thinking labels, and Jev scores supported by these limited observations. Local signals do not prove work quality or establish that another model setting would have performed better. Identical retries are safe.
|
|
73
|
+
|
|
74
|
+
## Recommended package updates
|
|
75
|
+
|
|
76
|
+
The connection endpoint returns `recommendedPackageVersion`, currently pinned to the latest published release, `0.3.9`. Before `sync`, `sync-files`, `approve`, or `scheduled-sync`, the runner compares its embedded release version with that property. An older runner installs the exact recommended release through npm and resumes the original command with the updated runner. Equal or newer runners continue unchanged. Explicitly recommended major releases follow the same comparison rule. Missing or invalid recommendations, connection failures, and npm failures do not block sync. The connection, pending work, checkpoints, and schedule are preserved.
|
|
77
|
+
|
|
78
|
+
This update mechanism first ships in `0.3.10`. Runners from earlier releases need a one-time installation of a release containing it (`npx --yes @useshifu/coding-harness@0.3.10 install --harness codex`, after publication). Raise the server recommendation only after the target release is published.
|
package/bin/shifu-harness.js
CHANGED
|
@@ -4,7 +4,9 @@ const fs = require("node:fs");
|
|
|
4
4
|
const { createHash } = require("node:crypto");
|
|
5
5
|
const os = require("node:os");
|
|
6
6
|
const path = require("node:path");
|
|
7
|
-
const { execFileSync } = require("node:child_process");
|
|
7
|
+
const { execFile, execFileSync, spawn } = require("node:child_process");
|
|
8
|
+
const { promisify } = require("node:util");
|
|
9
|
+
const execFileAsync = promisify(execFile);
|
|
8
10
|
const readline = require("node:readline/promises");
|
|
9
11
|
|
|
10
12
|
const DEFAULT_API_URL = "https://api.useshifu.com";
|
|
@@ -37,7 +39,7 @@ const MAX_TURNS_PER_SEGMENT = 12;
|
|
|
37
39
|
const MAX_TITLE_LENGTH = 160;
|
|
38
40
|
const MAX_WORK_DETAIL_LENGTH = 600;
|
|
39
41
|
const CONFIG_VERSION = 2;
|
|
40
|
-
const RUNNER_VERSION = "0.3.
|
|
42
|
+
const RUNNER_VERSION = "0.3.10";
|
|
41
43
|
const REDACTION_VERSION = 4;
|
|
42
44
|
const DEFAULT_INTERVAL_HOURS = 1;
|
|
43
45
|
const LEGACY_INTERVAL_HOURS = 4;
|
|
@@ -562,6 +564,7 @@ const WORK_ACTIONS = [
|
|
|
562
564
|
{ key: "reviewed", title: "Reviewed", pattern: /^(?:I\s+|We\s+)?(?:reviewed|audited)\b/i },
|
|
563
565
|
{ key: "investigated", title: "Investigated", pattern: /^(?:I\s+|We\s+)?(?:investigated|researched|evaluated|compared)\b/i },
|
|
564
566
|
{ key: "deployed", title: "Deployed", pattern: /^(?:I\s+|We\s+)?(?:deployed|published)\b/i },
|
|
567
|
+
{ key: "decided", title: "Decided", pattern: /^(?:I\s+|We\s+)?(?:decided|chose|selected)\b/i },
|
|
565
568
|
];
|
|
566
569
|
|
|
567
570
|
const WORK_OBJECTS = [
|
|
@@ -572,6 +575,11 @@ const WORK_OBJECTS = [
|
|
|
572
575
|
{ key: "claim_extraction", title: "claim extraction", pattern: /\b(?:claim extraction|claim generation|claim matching)\b/i },
|
|
573
576
|
{ key: "retry", title: "retry handling", pattern: /\b(?:retries|retry)\b/i },
|
|
574
577
|
{ key: "cache", title: "cache behavior", pattern: /\b(?:cache|caching|ttl)\b/i },
|
|
578
|
+
{ key: "outbox", title: "transactional outbox", pattern: /\b(?:transactional outbox|outbox pattern)\b/i },
|
|
579
|
+
{ key: "token_bucket", title: "token bucket limiter", pattern: /\btoken bucket limiter\b/i },
|
|
580
|
+
{ key: "actor_scheduler", title: "actor scheduler", pattern: /\bactor scheduler\b/i },
|
|
581
|
+
{ key: "quota_balancing", title: "quota balancing", pattern: /\bquota balancing\b/i },
|
|
582
|
+
{ key: "shard_rebalancing", title: "shard rebalancing", pattern: /\bshard rebalancing\b/i },
|
|
575
583
|
{ key: "navigation", title: "navigation", pattern: /\b(?:navigation|sidebar|sub.?nav)\b/i },
|
|
576
584
|
{ key: "sync", title: "sync behavior", pattern: /\b(?:sync|synchronization|checkpoint)\b/i },
|
|
577
585
|
{ key: "auth", title: "authentication", pattern: /\b(?:authentication|sign.?in|login)\b/i },
|
|
@@ -626,6 +634,39 @@ const WORK_DETAILS = [
|
|
|
626
634
|
{ title: "mobile layout", pattern: /\bmobile layout\b/i },
|
|
627
635
|
];
|
|
628
636
|
|
|
637
|
+
// These terms are safe to retain without copying surrounding private prose.
|
|
638
|
+
const TECHNICAL_DETAILS = [
|
|
639
|
+
{ title: "Redis", pattern: /\bRedis\b/i },
|
|
640
|
+
{ title: "Kafka", pattern: /\bKafka\b/i },
|
|
641
|
+
{ title: "Postgres", pattern: /\bPostgres(?:ql)?\b/i },
|
|
642
|
+
{ title: "MongoDB", pattern: /\bMongoDB\b/i },
|
|
643
|
+
{ title: "React", pattern: /\bReact\b/i },
|
|
644
|
+
{ title: "Node.js", pattern: /\bNode\.js\b/i },
|
|
645
|
+
{ title: "TypeScript", pattern: /\bTypeScript\b/i },
|
|
646
|
+
{ title: "Python", pattern: /\bPython\b/i },
|
|
647
|
+
{ title: "Spring Boot", pattern: /\bSpring Boot\b/i },
|
|
648
|
+
{ title: "Kubernetes", pattern: /\bKubernetes\b/i },
|
|
649
|
+
{ title: "Docker", pattern: /\bDocker\b/i },
|
|
650
|
+
{ title: "GraphQL", pattern: /\bGraphQL\b/i },
|
|
651
|
+
{ title: "gRPC", pattern: /\bgRPC\b/i },
|
|
652
|
+
{ title: "cache-aside", pattern: /\bcache.aside\b/i },
|
|
653
|
+
{ title: "transactional outbox", pattern: /\btransactional outbox\b/i },
|
|
654
|
+
{ title: "circuit breaker", pattern: /\bcircuit breaker\b/i },
|
|
655
|
+
{ title: "Builder Pattern", pattern: /\bBuilder Pattern\b/i },
|
|
656
|
+
{ title: "event sourcing", pattern: /\bevent sourcing\b/i },
|
|
657
|
+
{ title: "CQRS", pattern: /\bCQRS\b/i },
|
|
658
|
+
{ title: "Saga Pattern", pattern: /\bSaga Pattern\b/i },
|
|
659
|
+
{ title: "Repository Pattern", pattern: /\bRepository Pattern\b/i },
|
|
660
|
+
{ title: "Dependency Injection", pattern: /\bDependency Injection\b/i },
|
|
661
|
+
{ title: "OpenTelemetry", pattern: /\bOpenTelemetry\b/i },
|
|
662
|
+
{ title: "Temporal", pattern: /\bTemporal\b/i },
|
|
663
|
+
{ title: "Rust", pattern: /\bRust\b/i },
|
|
664
|
+
{ title: "Tokio", pattern: /\bTokio\b/i },
|
|
665
|
+
{ title: "consistent hashing", pattern: /\bconsistent hashing\b/i },
|
|
666
|
+
{ title: "virtual nodes", pattern: /\bvirtual nodes\b/i },
|
|
667
|
+
{ title: "adaptive jitter", pattern: /\badaptive jitter\b/i },
|
|
668
|
+
];
|
|
669
|
+
|
|
629
670
|
function controlledContexts(text) {
|
|
630
671
|
const matches = WORK_CONTEXTS.flatMap((item) => {
|
|
631
672
|
const match = item.pattern.exec(text);
|
|
@@ -640,15 +681,27 @@ function controlledContexts(text) {
|
|
|
640
681
|
}
|
|
641
682
|
|
|
642
683
|
function controlledDetails(text) {
|
|
643
|
-
|
|
684
|
+
const known = [...WORK_DETAILS, ...TECHNICAL_DETAILS];
|
|
685
|
+
const ttl = /\b(\d{1,3})[ -]hour TTL\b/i.exec(text);
|
|
686
|
+
const latency = /\bp(?:50|90|95|99) latency from (\d{1,4}) ms to (\d{1,4}) ms\b/i.exec(text);
|
|
687
|
+
const reductionPattern = /\b(?:cutting|cut|reducing|reduced|decreasing|decreased|lowering|lowered)\s+(queue time|memory(?: usage)?)\s+by\s*(\d{1,3}(?:\.\d{1,2})?)%(?![\d.])/i;
|
|
688
|
+
const reduction = reductionPattern.exec(text);
|
|
689
|
+
if (ttl) known.push({ title: `${ttl[1]}-hour TTL`, pattern: /\b\d{1,3}[ -]hour TTL\b/i });
|
|
690
|
+
if (latency) known.push({ title: latency[0], pattern: /\bp(?:50|90|95|99) latency from \d{1,4} ms to \d{1,4} ms\b/i });
|
|
691
|
+
if (reduction && Number(reduction[2]) <= 100) {
|
|
692
|
+
const metric = reduction[1].toLowerCase().startsWith("memory") ? "memory usage" : "queue time";
|
|
693
|
+
known.push({ title: `${metric} reduced by ${reduction[2]}%`, pattern: reductionPattern });
|
|
694
|
+
}
|
|
695
|
+
return known.map((item) => ({ item, index: item.pattern.exec(text)?.index }))
|
|
644
696
|
.filter(({ index }) => index !== undefined)
|
|
645
697
|
.sort((left, right) => left.index - right.index)
|
|
646
|
-
.
|
|
647
|
-
.
|
|
698
|
+
.map(({ item }) => item.title)
|
|
699
|
+
.filter((detail, index, details) => details.indexOf(detail) === index)
|
|
700
|
+
.slice(0, 6);
|
|
648
701
|
}
|
|
649
702
|
|
|
650
703
|
function withoutNamedLabels(text) {
|
|
651
|
-
return text.replace(/\b(?:Project|Client|Customer|Company)\s+[A-Z][A-Za-z0-9_-]*/
|
|
704
|
+
return text.replace(/\b(?:Project|Client|Customer|Company)\s+[A-Z][A-Za-z0-9_-]*/gi, "");
|
|
652
705
|
}
|
|
653
706
|
|
|
654
707
|
function safeActivityEvidence(notes) {
|
|
@@ -666,7 +719,7 @@ function safeActivityEvidence(notes) {
|
|
|
666
719
|
sectionContexts = /\b(?:project|feature|flow|service|system|product)\b/i.test(label) ? controlledContexts(label) || [] : [];
|
|
667
720
|
continue;
|
|
668
721
|
}
|
|
669
|
-
const line = rawLine.trim().replace(/^[-*]\s+/, "").split(/[
|
|
722
|
+
const line = rawLine.trim().replace(/^[-*]\s+/, "").split(/[;—]|[.!?](?=\s|$)/, 1)[0];
|
|
670
723
|
const clauses = line.split(/\s+(?:and|but|while)\s+/i);
|
|
671
724
|
const nextAction = clauses.findIndex((clause, index) => index > 0 && WORK_ACTIONS.some((item) => item.pattern.test(clause)));
|
|
672
725
|
const workClause = withoutNamedLabels(nextAction > 0 ? clauses.slice(0, nextAction).join(" and ") : line);
|
|
@@ -710,7 +763,7 @@ function payloadForSegment(harness, segment) {
|
|
|
710
763
|
summary,
|
|
711
764
|
evidence,
|
|
712
765
|
verification: [],
|
|
713
|
-
decisions:
|
|
766
|
+
decisions: evidence.filter((item) => item.title.startsWith("Decided ")).slice(0, MAX_SYNC_ITEMS).map((item) => item.statement),
|
|
714
767
|
redactionVersion: REDACTION_VERSION,
|
|
715
768
|
};
|
|
716
769
|
}
|
|
@@ -940,8 +993,14 @@ async function readSecret(input = process.stdin, output = process.stderr) {
|
|
|
940
993
|
|
|
941
994
|
function copyRunner() {
|
|
942
995
|
fs.mkdirSync(configRoot(), { recursive: true, mode: 0o700 });
|
|
943
|
-
|
|
944
|
-
|
|
996
|
+
const temporary = `${installedRunnerPath()}.${process.pid}.tmp`;
|
|
997
|
+
try {
|
|
998
|
+
fs.copyFileSync(__filename, temporary);
|
|
999
|
+
fs.chmodSync(temporary, 0o700);
|
|
1000
|
+
fs.renameSync(temporary, installedRunnerPath());
|
|
1001
|
+
} finally {
|
|
1002
|
+
fs.rmSync(temporary, { force: true });
|
|
1003
|
+
}
|
|
945
1004
|
}
|
|
946
1005
|
|
|
947
1006
|
function copyDirectory(source, destination) {
|
|
@@ -1160,6 +1219,7 @@ async function validateConnection(apiUrl, token, harness) {
|
|
|
1160
1219
|
if (!response.ok) throw new Error(`Shifu could not verify the connection key (HTTP ${response.status}). Nothing was changed.`);
|
|
1161
1220
|
const result = await response.json().catch(() => null);
|
|
1162
1221
|
if (result?.data?.connected !== true) throw new Error("Shifu returned an invalid connection check. Nothing was changed.");
|
|
1222
|
+
return result.data;
|
|
1163
1223
|
}
|
|
1164
1224
|
|
|
1165
1225
|
async function connect(harness, readKey = readSecret) {
|
|
@@ -1838,11 +1898,54 @@ function review(harness) {
|
|
|
1838
1898
|
}, null, 2));
|
|
1839
1899
|
}
|
|
1840
1900
|
|
|
1901
|
+
function olderPackageVersion(current, recommended) {
|
|
1902
|
+
const pattern = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/;
|
|
1903
|
+
if (!pattern.test(current) || !pattern.test(recommended)) return false;
|
|
1904
|
+
const left = current.split(".").map(BigInt);
|
|
1905
|
+
const right = recommended.split(".").map(BigInt);
|
|
1906
|
+
for (let index = 0; index < 3; index += 1) {
|
|
1907
|
+
if (left[index] !== right[index]) return left[index] < right[index];
|
|
1908
|
+
}
|
|
1909
|
+
return false;
|
|
1910
|
+
}
|
|
1911
|
+
|
|
1912
|
+
async function installPackageVersion(version, harness) {
|
|
1913
|
+
await execFileAsync("npm", ["exec", "--yes", `--package=@useshifu/coding-harness@${version}`, "--", "shifu-harness", "install", "--harness", harness, "--config-root", configRoot()], {
|
|
1914
|
+
timeout: 60_000,
|
|
1915
|
+
env: { ...process.env, PATH: `${process.env.PATH || ""}${path.delimiter}${path.dirname(process.execPath)}`, SHIFU_UPDATE_CHECKED: "1" },
|
|
1916
|
+
});
|
|
1917
|
+
}
|
|
1918
|
+
|
|
1919
|
+
async function updateRecommendedPackage(harness, { currentVersion = RUNNER_VERSION, fetchConnection = validateConnection, installVersion = installPackageVersion } = {}) {
|
|
1920
|
+
try {
|
|
1921
|
+
const config = readConfig(harness);
|
|
1922
|
+
const connection = await fetchConnection(config.apiUrl, config.token, harness);
|
|
1923
|
+
const recommended = connection?.recommendedPackageVersion;
|
|
1924
|
+
if (!olderPackageVersion(currentVersion, recommended)) return false;
|
|
1925
|
+
await installVersion(recommended, harness);
|
|
1926
|
+
console.error(`Updated Shifu coding harness to recommended version ${recommended}.`);
|
|
1927
|
+
return true;
|
|
1928
|
+
} catch {
|
|
1929
|
+
console.error("Could not check or install the recommended Shifu package. Continuing with the current runner.");
|
|
1930
|
+
return false;
|
|
1931
|
+
}
|
|
1932
|
+
}
|
|
1933
|
+
|
|
1841
1934
|
async function main() {
|
|
1842
1935
|
if (option("--config-root")) process.env.SHIFU_CONFIG_ROOT = path.resolve(option("--config-root"));
|
|
1843
1936
|
const command = process.argv[2];
|
|
1844
1937
|
const subCommand = process.argv[3];
|
|
1845
1938
|
const harness = requireHarness(option("--harness"));
|
|
1939
|
+
if (["sync", "sync-files", "scheduled-sync", "approve"].includes(command) && process.env.SHIFU_UPDATE_CHECKED !== "1" && await updateRecommendedPackage(harness)) {
|
|
1940
|
+
const child = spawn(process.execPath, [installedRunnerPath(), ...process.argv.slice(2)], {
|
|
1941
|
+
env: { ...process.env, SHIFU_UPDATE_CHECKED: "1" }, stdio: "inherit",
|
|
1942
|
+
});
|
|
1943
|
+
await new Promise((resolve, reject) => {
|
|
1944
|
+
child.once("error", reject);
|
|
1945
|
+
child.once("exit", (code) => code === 0 ? resolve() : reject(new Error("The updated Shifu sync failed; pending work is preserved.")));
|
|
1946
|
+
});
|
|
1947
|
+
return;
|
|
1948
|
+
}
|
|
1846
1949
|
if (command === "install") return install(harness);
|
|
1847
1950
|
if (command === "connect") return connect(harness);
|
|
1848
1951
|
if (command === "disconnect") return disconnect(harness);
|
|
@@ -1867,4 +1970,4 @@ if (require.main === module) {
|
|
|
1867
1970
|
});
|
|
1868
1971
|
}
|
|
1869
1972
|
|
|
1870
|
-
module.exports = { approvalNotificationInvocation, claudeReview, claudeSession, codexReview, codexSession, configPath, configuredSyncPolicy, connect, defaultInputFolder, disconnect, finalAssistantNote, install, installDestination, localSessions, normalizedPolicy, notificationSessionRef, opencodeQuery, opencodeReview, opencodeSessions, payloadForSegment, pendingSegments, prepareInputFolder, profileForSegment, readSecret, removeHooks, requireSafeApiUrl, reviewCandidates, schedulerArtifact, statePath, syncWorkFiles, textIsSafe, unsyncedCodexSessions, validateAIProfileObservation, validateConnection, validateInputFolder, validSyncReceipt, validateApprovalMode, validateIntervalHours, validateSync, workFiles };
|
|
1973
|
+
module.exports = { olderPackageVersion, updateRecommendedPackage, installPackageVersion, approvalNotificationInvocation, claudeReview, claudeSession, codexReview, codexSession, configPath, configuredSyncPolicy, connect, defaultInputFolder, disconnect, finalAssistantNote, install, installDestination, localSessions, normalizedPolicy, notificationSessionRef, opencodeQuery, opencodeReview, opencodeSessions, payloadForSegment, pendingSegments, prepareInputFolder, profileForSegment, readSecret, removeHooks, requireSafeApiUrl, reviewCandidates, schedulerArtifact, statePath, syncWorkFiles, textIsSafe, unsyncedCodexSessions, validateAIProfileObservation, validateConnection, validateInputFolder, validSyncReceipt, validateApprovalMode, validateIntervalHours, validateSync, workFiles };
|
package/commands/shifu-sync.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
description: Inspect or sync redacted OpenCode activity using the saved Shifu policy.
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
+
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
|
+
|
|
5
7
|
Run `npx --yes @useshifu/coding-harness status --harness opencode` first.
|
|
6
8
|
|
|
7
9
|
For an explicit Shifu input-folder sync, run `sync-files --harness opencode`. It polls unfinished jobs before submitting new or changed `.txt`, `.md`, `.rtf`, and `.docx` files up to 20 MB. Upload starts asynchronous server processing; check status on the next manual or scheduled sync. Only a final `processed`, `no_claims`, or `duplicate` result completes the local checkpoint; a `partial` result remains retryable. Completed file checkpoints from the previous runner are replayed once; existing in-flight jobs are polled before replay. Report published claims and needs-evidence suggestions separately. `no_claims` may still include suggestions, which are not verified user contributions. Unsupported files are counted but not uploaded. No claim-review step is needed. Do not treat another speaker's work or a meeting action item as the user's contribution. The server parses and sanitizes files; the local runner does not redact file contents, and file text or excerpts must not appear in logs.
|
|
@@ -12,7 +14,7 @@ For an explicit sync-now request:
|
|
|
12
14
|
|
|
13
15
|
1. For a time-window request, run `sessions --harness opencode --hours 24`, using 48 or 72 only when requested. For a request by number of recent sessions, run `sessions --harness opencode --count <count>`; this ignores the hours window and returns the most recently updated sessions first.
|
|
14
16
|
2. Review each returned segment with `review --harness opencode --session-ref <sessionRef> --hours <hours>`. For count-based selection, use `review --harness opencode --session-ref <sessionRef> --all` so older sessions are allowed.
|
|
15
|
-
3. Prepare a redaction-version-four payload from final assistant notes only. Use `activity` evidence for writing, feedback, research, planning, product work, and any work that is not clearly an engineering implementation or decision. Activity evidence has no technical scope. Preserve the supported action, feature or project purpose, specific problem, approach, and verified result. Synthesize a descriptive project label (such as "payment reconciliation service") from its purpose; never copy a raw label that could identify a company or person. Keep distinct contributions separate, including different fixes within one feature. An empty evidence list advances the checkpoint without creating a claim.
|
|
17
|
+
3. Prepare a redaction-version-four payload from final assistant notes only. Use `activity` evidence for writing, feedback, research, planning, product work, and any work that is not clearly an engineering implementation or decision. Activity evidence has no technical scope. Preserve the supported action, feature or project purpose, specific problem, approach, technologies and design patterns used, and verified result. Synthesize a descriptive project label (such as "payment reconciliation service") from its purpose; never copy a raw label that could identify a company or person. Keep distinct contributions separate, including different fixes within one feature. An empty evidence list advances the checkpoint without creating a claim.
|
|
16
18
|
4. In automatic mode, pipe the payload to `sync --harness opencode` without asking again. In manual mode, show the exact payload, ask once, and then use `sync --approved --harness opencode`.
|
|
17
19
|
5. Keep the returned session reference and turn range unchanged. Never upload prompts, raw transcripts, tool output, code, paths, commands, URLs, credentials, company or person names, customer details, or proprietary identifiers.
|
|
18
20
|
6. For a count-based sync, keep `selectedSessionRefs` from the first discovery and review only pending `sessions`. `skippedSessions` reports already-synced selections; do not replace them with older sessions. If one has remaining turns, request its next segment with `sessions --harness opencode --session-ref <sessionRef> --all`. Stop after those selected sessions are exhausted. Report completed, already-synced, and failed/pending sessions separately. Manual sync runs immediately, independently of the hourly schedule.
|
package/package.json
CHANGED
|
@@ -5,6 +5,8 @@ description: Connect, configure, inspect, or sync coding-harness activity, AI Pr
|
|
|
5
5
|
|
|
6
6
|
# Shifu sync
|
|
7
7
|
|
|
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
|
+
|
|
8
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.
|
|
9
11
|
|
|
10
12
|
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.
|
|
@@ -64,7 +66,7 @@ For an explicit sync request, first read `status` to determine the saved approva
|
|
|
64
66
|
|
|
65
67
|
Use `kind: "activity"` for general harness work; it does not require a technical scope. Use `implementation` or `decision` only when the note clearly supports that engineering classification, and then use the smallest reviewed scope among `unit`, `module`, `service`, `system`, and `product`. Evidence may be empty when the safe final note supports only a session-level title and summary. Never invent impact, ownership, verification, or outcomes.
|
|
66
68
|
|
|
67
|
-
Make each supported item useful for later recall: retain the user's action, the feature or project purpose, the specific problem, the approach, and a verified result when the final note supports each part. 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. Keep distinct contributions separate, including two fixes in one feature that addressed different problems. Omit names of companies and people, customer details, proprietary identifiers, paths, code snippets, 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.
|
|
69
|
+
Make each supported item useful for later recall: retain the user's action, the feature or project purpose, the specific problem, the approach, and a verified result when the final note supports each part. 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. Keep distinct contributions 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.
|
|
68
70
|
|
|
69
71
|
```json
|
|
70
72
|
{
|