@nanonets/graft 0.24.0 → 0.25.0
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 +26 -21
- package/dist/ask/ask.d.ts +8 -0
- package/dist/ask/ask.d.ts.map +1 -1
- package/dist/ask/ask.js +33 -12
- package/dist/ask/ask.js.map +1 -1
- package/dist/blast/render.js +1 -1
- package/dist/blast/render.js.map +1 -1
- package/dist/brand.js +1 -1
- package/dist/brand.js.map +1 -1
- package/dist/check/learning-edits.d.ts +18 -3
- package/dist/check/learning-edits.d.ts.map +1 -1
- package/dist/check/learning-edits.js +54 -10
- package/dist/check/learning-edits.js.map +1 -1
- package/dist/check/local-check.d.ts +7 -3
- package/dist/check/local-check.d.ts.map +1 -1
- package/dist/check/local-check.js +55 -11
- package/dist/check/local-check.js.map +1 -1
- package/dist/check/types.d.ts +11 -2
- package/dist/check/types.d.ts.map +1 -1
- package/dist/claude/format.d.ts +11 -7
- package/dist/claude/format.d.ts.map +1 -1
- package/dist/claude/format.js +50 -28
- package/dist/claude/format.js.map +1 -1
- package/dist/claude/hook-io.d.ts +44 -0
- package/dist/claude/hook-io.d.ts.map +1 -0
- package/dist/claude/hook-io.js +144 -0
- package/dist/claude/hook-io.js.map +1 -0
- package/dist/claude/hook-layers.d.ts +4 -2
- package/dist/claude/hook-layers.d.ts.map +1 -1
- package/dist/claude/hook-layers.js +21 -4
- package/dist/claude/hook-layers.js.map +1 -1
- package/dist/claude/hooks.d.ts +9 -32
- package/dist/claude/hooks.d.ts.map +1 -1
- package/dist/claude/hooks.js +154 -350
- package/dist/claude/hooks.js.map +1 -1
- package/dist/claude/init.d.ts.map +1 -1
- package/dist/claude/init.js +56 -18
- package/dist/claude/init.js.map +1 -1
- package/dist/claude/note-signals.d.ts +6 -0
- package/dist/claude/note-signals.d.ts.map +1 -1
- package/dist/claude/note-signals.js +14 -3
- package/dist/claude/note-signals.js.map +1 -1
- package/dist/claude/post-bash.d.ts +26 -0
- package/dist/claude/post-bash.d.ts.map +1 -0
- package/dist/claude/post-bash.js +191 -0
- package/dist/claude/post-bash.js.map +1 -0
- package/dist/claude/pre-bash-skills.d.ts +21 -0
- package/dist/claude/pre-bash-skills.d.ts.map +1 -0
- package/dist/claude/pre-bash-skills.js +253 -0
- package/dist/claude/pre-bash-skills.js.map +1 -0
- package/dist/claude/pre-bash.d.ts +50 -0
- package/dist/claude/pre-bash.d.ts.map +1 -0
- package/dist/claude/pre-bash.js +245 -0
- package/dist/claude/pre-bash.js.map +1 -0
- package/dist/claude/prompt-consent.d.ts +19 -0
- package/dist/claude/prompt-consent.d.ts.map +1 -0
- package/dist/claude/prompt-consent.js +14 -0
- package/dist/claude/prompt-consent.js.map +1 -0
- package/dist/claude/prompt-hook.d.ts +76 -0
- package/dist/claude/prompt-hook.d.ts.map +1 -0
- package/dist/claude/prompt-hook.js +303 -0
- package/dist/claude/prompt-hook.js.map +1 -0
- package/dist/claude/prompt-skills.d.ts +19 -0
- package/dist/claude/prompt-skills.d.ts.map +1 -0
- package/dist/claude/prompt-skills.js +305 -0
- package/dist/claude/prompt-skills.js.map +1 -0
- package/dist/claude/session-metrics.js +4 -4
- package/dist/claude/session-metrics.js.map +1 -1
- package/dist/claude/settings-merge.d.ts +10 -0
- package/dist/claude/settings-merge.d.ts.map +1 -1
- package/dist/claude/settings-merge.js +46 -17
- package/dist/claude/settings-merge.js.map +1 -1
- package/dist/claude/shim-template.d.ts.map +1 -1
- package/dist/claude/shim-template.js +86 -28
- package/dist/claude/shim-template.js.map +1 -1
- package/dist/claude/skill-template.d.ts +2 -0
- package/dist/claude/skill-template.d.ts.map +1 -1
- package/dist/claude/skill-template.js +53 -34
- package/dist/claude/skill-template.js.map +1 -1
- package/dist/claude/skill-use.d.ts +16 -0
- package/dist/claude/skill-use.d.ts.map +1 -0
- package/dist/claude/skill-use.js +78 -0
- package/dist/claude/skill-use.js.map +1 -0
- package/dist/claude/skills-hook-util.d.ts +25 -0
- package/dist/claude/skills-hook-util.d.ts.map +1 -0
- package/dist/claude/skills-hook-util.js +71 -0
- package/dist/claude/skills-hook-util.js.map +1 -0
- package/dist/claude/skills-wiring.d.ts +26 -0
- package/dist/claude/skills-wiring.d.ts.map +1 -0
- package/dist/claude/skills-wiring.js +110 -0
- package/dist/claude/skills-wiring.js.map +1 -0
- package/dist/claude/start-init.d.ts +13 -0
- package/dist/claude/start-init.d.ts.map +1 -0
- package/dist/claude/start-init.js +75 -0
- package/dist/claude/start-init.js.map +1 -0
- package/dist/claude/start-skills.d.ts +31 -0
- package/dist/claude/start-skills.d.ts.map +1 -0
- package/dist/claude/start-skills.js +274 -0
- package/dist/claude/start-skills.js.map +1 -0
- package/dist/claude/state.d.ts +19 -7
- package/dist/claude/state.d.ts.map +1 -1
- package/dist/claude/state.js +59 -4
- package/dist/claude/state.js.map +1 -1
- package/dist/claude/stop-skills.d.ts +23 -0
- package/dist/claude/stop-skills.d.ts.map +1 -0
- package/dist/claude/stop-skills.js +233 -0
- package/dist/claude/stop-skills.js.map +1 -0
- package/dist/claude/stop.d.ts +23 -0
- package/dist/claude/stop.d.ts.map +1 -0
- package/dist/claude/stop.js +219 -0
- package/dist/claude/stop.js.map +1 -0
- package/dist/claude/tally.d.ts +29 -41
- package/dist/claude/tally.d.ts.map +1 -1
- package/dist/claude/tally.js +111 -165
- package/dist/claude/tally.js.map +1 -1
- package/dist/claude/walls-hook.d.ts +52 -0
- package/dist/claude/walls-hook.d.ts.map +1 -0
- package/dist/claude/walls-hook.js +279 -0
- package/dist/claude/walls-hook.js.map +1 -0
- package/dist/cli-epilogue.d.ts.map +1 -1
- package/dist/cli-epilogue.js +24 -14
- package/dist/cli-epilogue.js.map +1 -1
- package/dist/cli-meta.js +3 -3
- package/dist/cli-meta.js.map +1 -1
- package/dist/cli-picker.d.ts +24 -0
- package/dist/cli-picker.d.ts.map +1 -1
- package/dist/cli-picker.js +44 -11
- package/dist/cli-picker.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +475 -390
- package/dist/cli.js.map +1 -1
- package/dist/cloud/head-learnings.d.ts +13 -0
- package/dist/cloud/head-learnings.d.ts.map +1 -0
- package/dist/cloud/head-learnings.js +84 -0
- package/dist/cloud/head-learnings.js.map +1 -0
- package/dist/cloud/lookup-activity.d.ts +18 -0
- package/dist/cloud/lookup-activity.d.ts.map +1 -0
- package/dist/cloud/lookup-activity.js +56 -0
- package/dist/cloud/lookup-activity.js.map +1 -0
- package/dist/cloud/nudge.d.ts +15 -7
- package/dist/cloud/nudge.d.ts.map +1 -1
- package/dist/cloud/nudge.js +45 -33
- package/dist/cloud/nudge.js.map +1 -1
- package/dist/cloud/onboarding.d.ts +273 -0
- package/dist/cloud/onboarding.d.ts.map +1 -0
- package/dist/cloud/onboarding.js +612 -0
- package/dist/cloud/onboarding.js.map +1 -0
- package/dist/cloud/other-repos.d.ts +39 -0
- package/dist/cloud/other-repos.d.ts.map +1 -0
- package/dist/cloud/other-repos.js +137 -0
- package/dist/cloud/other-repos.js.map +1 -0
- package/dist/cloud/pair.d.ts +86 -0
- package/dist/cloud/pair.d.ts.map +1 -0
- package/dist/cloud/pair.js +270 -0
- package/dist/cloud/pair.js.map +1 -0
- package/dist/cloud/workspace-sync.d.ts +75 -11
- package/dist/cloud/workspace-sync.d.ts.map +1 -1
- package/dist/cloud/workspace-sync.js +409 -53
- package/dist/cloud/workspace-sync.js.map +1 -1
- package/dist/cloud/workspace.d.ts +95 -10
- package/dist/cloud/workspace.d.ts.map +1 -1
- package/dist/cloud/workspace.js +112 -9
- package/dist/cloud/workspace.js.map +1 -1
- package/dist/graph/native.d.ts +2 -0
- package/dist/graph/native.d.ts.map +1 -1
- package/dist/graph/native.js +29 -4
- package/dist/graph/native.js.map +1 -1
- package/dist/hosts/claude-global.d.ts +14 -0
- package/dist/hosts/claude-global.d.ts.map +1 -1
- package/dist/hosts/claude-global.js +39 -4
- package/dist/hosts/claude-global.js.map +1 -1
- package/dist/hosts/codex-hooks.d.ts +6 -0
- package/dist/hosts/codex-hooks.d.ts.map +1 -1
- package/dist/hosts/codex-hooks.js +89 -16
- package/dist/hosts/codex-hooks.js.map +1 -1
- package/dist/hosts/codex-trust.d.ts +28 -0
- package/dist/hosts/codex-trust.d.ts.map +1 -0
- package/dist/hosts/codex-trust.js +280 -0
- package/dist/hosts/codex-trust.js.map +1 -0
- package/dist/hosts/cursor-hooks.d.ts.map +1 -1
- package/dist/hosts/cursor-hooks.js +3 -1
- package/dist/hosts/cursor-hooks.js.map +1 -1
- package/dist/init/candidates.d.ts +60 -0
- package/dist/init/candidates.d.ts.map +1 -0
- package/dist/init/candidates.js +202 -0
- package/dist/init/candidates.js.map +1 -0
- package/dist/init/claude-call.d.ts +51 -0
- package/dist/init/claude-call.d.ts.map +1 -0
- package/dist/init/claude-call.js +199 -0
- package/dist/init/claude-call.js.map +1 -0
- package/dist/init/discover-worker.d.ts +18 -0
- package/dist/init/discover-worker.d.ts.map +1 -0
- package/dist/init/discover-worker.js +111 -0
- package/dist/init/discover-worker.js.map +1 -0
- package/dist/init/handover.d.ts +16 -0
- package/dist/init/handover.d.ts.map +1 -0
- package/dist/init/handover.js +92 -0
- package/dist/init/handover.js.map +1 -0
- package/dist/init/howtos.d.ts +20 -0
- package/dist/init/howtos.d.ts.map +1 -0
- package/dist/init/howtos.js +90 -0
- package/dist/init/howtos.js.map +1 -0
- package/dist/init/init-record.d.ts +134 -0
- package/dist/init/init-record.d.ts.map +1 -0
- package/dist/init/init-record.js +339 -0
- package/dist/init/init-record.js.map +1 -0
- package/dist/init/install-paths.d.ts +6 -0
- package/dist/init/install-paths.d.ts.map +1 -0
- package/dist/init/install-paths.js +87 -0
- package/dist/init/install-paths.js.map +1 -0
- package/dist/init/install-record.d.ts +21 -0
- package/dist/init/install-record.d.ts.map +1 -0
- package/dist/init/install-record.js +144 -0
- package/dist/init/install-record.js.map +1 -0
- package/dist/init/keep-answer.d.ts +43 -0
- package/dist/init/keep-answer.d.ts.map +1 -0
- package/dist/init/keep-answer.js +118 -0
- package/dist/init/keep-answer.js.map +1 -0
- package/dist/init/keep-gate.d.ts +30 -0
- package/dist/init/keep-gate.d.ts.map +1 -0
- package/dist/init/keep-gate.js +178 -0
- package/dist/init/keep-gate.js.map +1 -0
- package/dist/init/keep-list.d.ts +67 -0
- package/dist/init/keep-list.d.ts.map +1 -0
- package/dist/init/keep-list.js +232 -0
- package/dist/init/keep-list.js.map +1 -0
- package/dist/init/keep.d.ts +52 -0
- package/dist/init/keep.d.ts.map +1 -0
- package/dist/init/keep.js +393 -0
- package/dist/init/keep.js.map +1 -0
- package/dist/init/look-back-mine.d.ts +37 -0
- package/dist/init/look-back-mine.d.ts.map +1 -0
- package/dist/init/look-back-mine.js +215 -0
- package/dist/init/look-back-mine.js.map +1 -0
- package/dist/init/look-back.d.ts +81 -0
- package/dist/init/look-back.d.ts.map +1 -0
- package/dist/init/look-back.js +170 -0
- package/dist/init/look-back.js.map +1 -0
- package/dist/init/miners.d.ts +46 -0
- package/dist/init/miners.d.ts.map +1 -0
- package/dist/init/miners.js +141 -0
- package/dist/init/miners.js.map +1 -0
- package/dist/init/name-call.d.ts +37 -0
- package/dist/init/name-call.d.ts.map +1 -0
- package/dist/init/name-call.js +151 -0
- package/dist/init/name-call.js.map +1 -0
- package/dist/init/plain-file.d.ts +11 -0
- package/dist/init/plain-file.d.ts.map +1 -0
- package/dist/init/plain-file.js +83 -0
- package/dist/init/plain-file.js.map +1 -0
- package/dist/init/prefs.d.ts +70 -0
- package/dist/init/prefs.d.ts.map +1 -0
- package/dist/init/prefs.js +282 -0
- package/dist/init/prefs.js.map +1 -0
- package/dist/init/relay.d.ts +15 -0
- package/dist/init/relay.d.ts.map +1 -0
- package/dist/init/relay.js +15 -0
- package/dist/init/relay.js.map +1 -0
- package/dist/init/replay-runs.d.ts +121 -0
- package/dist/init/replay-runs.d.ts.map +1 -0
- package/dist/init/replay-runs.js +457 -0
- package/dist/init/replay-runs.js.map +1 -0
- package/dist/init/replay-tamper.d.ts +18 -0
- package/dist/init/replay-tamper.d.ts.map +1 -0
- package/dist/init/replay-tamper.js +87 -0
- package/dist/init/replay-tamper.js.map +1 -0
- package/dist/init/review-screen.d.ts +74 -0
- package/dist/init/review-screen.d.ts.map +1 -0
- package/dist/init/review-screen.js +258 -0
- package/dist/init/review-screen.js.map +1 -0
- package/dist/init/review-tty.d.ts +29 -0
- package/dist/init/review-tty.d.ts.map +1 -0
- package/dist/init/review-tty.js +218 -0
- package/dist/init/review-tty.js.map +1 -0
- package/dist/init/review.d.ts +12 -0
- package/dist/init/review.d.ts.map +1 -0
- package/dist/init/review.js +12 -0
- package/dist/init/review.js.map +1 -0
- package/dist/init/run.d.ts +87 -0
- package/dist/init/run.d.ts.map +1 -0
- package/dist/init/run.js +347 -0
- package/dist/init/run.js.map +1 -0
- package/dist/init/sessions.d.ts +63 -0
- package/dist/init/sessions.d.ts.map +1 -0
- package/dist/init/sessions.js +377 -0
- package/dist/init/sessions.js.map +1 -0
- package/dist/init/transcript.d.ts +81 -0
- package/dist/init/transcript.d.ts.map +1 -0
- package/dist/init/transcript.js +216 -0
- package/dist/init/transcript.js.map +1 -0
- package/dist/init/types.d.ts +139 -0
- package/dist/init/types.d.ts.map +1 -0
- package/dist/init/types.js +2 -0
- package/dist/init/types.js.map +1 -0
- package/dist/mcp/brains.d.ts +72 -0
- package/dist/mcp/brains.d.ts.map +1 -0
- package/dist/mcp/brains.js +220 -0
- package/dist/mcp/brains.js.map +1 -0
- package/dist/mcp/server.d.ts +3 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +40 -5
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +7 -2
- package/dist/mcp/tools.js.map +1 -1
- package/dist/notes/cold-start.d.ts +5 -184
- package/dist/notes/cold-start.d.ts.map +1 -1
- package/dist/notes/cold-start.js +5 -575
- package/dist/notes/cold-start.js.map +1 -1
- package/dist/notes/edit-overlap.d.ts.map +1 -1
- package/dist/notes/edit-overlap.js +4 -1
- package/dist/notes/edit-overlap.js.map +1 -1
- package/dist/notes/every-repo.d.ts +18 -0
- package/dist/notes/every-repo.d.ts.map +1 -0
- package/dist/notes/every-repo.js +86 -0
- package/dist/notes/every-repo.js.map +1 -0
- package/dist/notes/guardrails.d.ts +8 -0
- package/dist/notes/guardrails.d.ts.map +1 -0
- package/dist/notes/guardrails.js +38 -0
- package/dist/notes/guardrails.js.map +1 -0
- package/dist/notes/lesson-index.d.ts +13 -0
- package/dist/notes/lesson-index.d.ts.map +1 -0
- package/dist/notes/lesson-index.js +135 -0
- package/dist/notes/lesson-index.js.map +1 -0
- package/dist/notes/linked-learnings.d.ts +8 -0
- package/dist/notes/linked-learnings.d.ts.map +1 -0
- package/dist/notes/linked-learnings.js +113 -0
- package/dist/notes/linked-learnings.js.map +1 -0
- package/dist/notes/notes.d.ts +8 -4
- package/dist/notes/notes.d.ts.map +1 -1
- package/dist/notes/notes.js +9 -7
- package/dist/notes/notes.js.map +1 -1
- package/dist/notes/pr-reviews.d.ts +4 -0
- package/dist/notes/pr-reviews.d.ts.map +1 -1
- package/dist/notes/pr-reviews.js +6 -5
- package/dist/notes/pr-reviews.js.map +1 -1
- package/dist/notes/replace.d.ts +14 -0
- package/dist/notes/replace.d.ts.map +1 -0
- package/dist/notes/replace.js +38 -0
- package/dist/notes/replace.js.map +1 -0
- package/dist/notes/repo-notes-dir.d.ts +2 -0
- package/dist/notes/repo-notes-dir.d.ts.map +1 -0
- package/dist/notes/repo-notes-dir.js +16 -0
- package/dist/notes/repo-notes-dir.js.map +1 -0
- package/dist/notes/repo-trail.d.ts +1 -1
- package/dist/notes/repo-trail.d.ts.map +1 -1
- package/dist/notes/repo-trail.js +24 -4
- package/dist/notes/repo-trail.js.map +1 -1
- package/dist/search/grep.d.ts.map +1 -1
- package/dist/search/grep.js +4 -2
- package/dist/search/grep.js.map +1 -1
- package/dist/search/user-regexp.d.ts +26 -0
- package/dist/search/user-regexp.d.ts.map +1 -0
- package/dist/search/user-regexp.js +150 -0
- package/dist/search/user-regexp.js.map +1 -0
- package/dist/skills/anchors-cli.d.ts +38 -0
- package/dist/skills/anchors-cli.d.ts.map +1 -0
- package/dist/skills/anchors-cli.js +279 -0
- package/dist/skills/anchors-cli.js.map +1 -0
- package/dist/skills/anchors-git.d.ts +29 -0
- package/dist/skills/anchors-git.d.ts.map +1 -0
- package/dist/skills/anchors-git.js +241 -0
- package/dist/skills/anchors-git.js.map +1 -0
- package/dist/skills/anchors-wide.d.ts +25 -0
- package/dist/skills/anchors-wide.d.ts.map +1 -0
- package/dist/skills/anchors-wide.js +481 -0
- package/dist/skills/anchors-wide.js.map +1 -0
- package/dist/skills/anchors.d.ts +32 -0
- package/dist/skills/anchors.d.ts.map +1 -0
- package/dist/skills/anchors.js +485 -0
- package/dist/skills/anchors.js.map +1 -0
- package/dist/skills/check-result.d.ts +26 -0
- package/dist/skills/check-result.d.ts.map +1 -0
- package/dist/skills/check-result.js +46 -0
- package/dist/skills/check-result.js.map +1 -0
- package/dist/skills/cli-skills-1b.d.ts +17 -0
- package/dist/skills/cli-skills-1b.d.ts.map +1 -0
- package/dist/skills/cli-skills-1b.js +166 -0
- package/dist/skills/cli-skills-1b.js.map +1 -0
- package/dist/skills/cli-skills-2.d.ts +35 -0
- package/dist/skills/cli-skills-2.d.ts.map +1 -0
- package/dist/skills/cli-skills-2.js +129 -0
- package/dist/skills/cli-skills-2.js.map +1 -0
- package/dist/skills/cli-skills-report-1b.d.ts +49 -0
- package/dist/skills/cli-skills-report-1b.d.ts.map +1 -0
- package/dist/skills/cli-skills-report-1b.js +191 -0
- package/dist/skills/cli-skills-report-1b.js.map +1 -0
- package/dist/skills/cli-skills-report.d.ts +86 -0
- package/dist/skills/cli-skills-report.d.ts.map +1 -0
- package/dist/skills/cli-skills-report.js +121 -0
- package/dist/skills/cli-skills-report.js.map +1 -0
- package/dist/skills/cli-skills.d.ts +30 -0
- package/dist/skills/cli-skills.d.ts.map +1 -0
- package/dist/skills/cli-skills.js +379 -0
- package/dist/skills/cli-skills.js.map +1 -0
- package/dist/skills/codex-sandbox.d.ts +6 -0
- package/dist/skills/codex-sandbox.d.ts.map +1 -0
- package/dist/skills/codex-sandbox.js +55 -0
- package/dist/skills/codex-sandbox.js.map +1 -0
- package/dist/skills/compile-split.d.ts +57 -0
- package/dist/skills/compile-split.d.ts.map +1 -0
- package/dist/skills/compile-split.js +550 -0
- package/dist/skills/compile-split.js.map +1 -0
- package/dist/skills/compile-version.d.ts +37 -0
- package/dist/skills/compile-version.d.ts.map +1 -0
- package/dist/skills/compile-version.js +56 -0
- package/dist/skills/compile-version.js.map +1 -0
- package/dist/skills/compile-waits.d.ts +12 -0
- package/dist/skills/compile-waits.d.ts.map +1 -0
- package/dist/skills/compile-waits.js +52 -0
- package/dist/skills/compile-waits.js.map +1 -0
- package/dist/skills/compile-words.d.ts +85 -0
- package/dist/skills/compile-words.d.ts.map +1 -0
- package/dist/skills/compile-words.js +445 -0
- package/dist/skills/compile-words.js.map +1 -0
- package/dist/skills/compile.d.ts +42 -0
- package/dist/skills/compile.d.ts.map +1 -0
- package/dist/skills/compile.js +505 -0
- package/dist/skills/compile.js.map +1 -0
- package/dist/skills/credit-facts.d.ts +8 -0
- package/dist/skills/credit-facts.d.ts.map +1 -0
- package/dist/skills/credit-facts.js +32 -0
- package/dist/skills/credit-facts.js.map +1 -0
- package/dist/skills/credit.d.ts +86 -0
- package/dist/skills/credit.d.ts.map +1 -0
- package/dist/skills/credit.js +259 -0
- package/dist/skills/credit.js.map +1 -0
- package/dist/skills/directive-words.d.ts +11 -0
- package/dist/skills/directive-words.d.ts.map +1 -0
- package/dist/skills/directive-words.js +33 -0
- package/dist/skills/directive-words.js.map +1 -0
- package/dist/skills/fidelity.d.ts +42 -0
- package/dist/skills/fidelity.d.ts.map +1 -0
- package/dist/skills/fidelity.js +138 -0
- package/dist/skills/fidelity.js.map +1 -0
- package/dist/skills/fold-gated.d.ts +3 -0
- package/dist/skills/fold-gated.d.ts.map +1 -0
- package/dist/skills/fold-gated.js +78 -0
- package/dist/skills/fold-gated.js.map +1 -0
- package/dist/skills/fold.d.ts +87 -0
- package/dist/skills/fold.d.ts.map +1 -0
- package/dist/skills/fold.js +348 -0
- package/dist/skills/fold.js.map +1 -0
- package/dist/skills/follow-learnings.d.ts +128 -0
- package/dist/skills/follow-learnings.d.ts.map +1 -0
- package/dist/skills/follow-learnings.js +278 -0
- package/dist/skills/follow-learnings.js.map +1 -0
- package/dist/skills/forget-notice.d.ts +44 -0
- package/dist/skills/forget-notice.d.ts.map +1 -0
- package/dist/skills/forget-notice.js +131 -0
- package/dist/skills/forget-notice.js.map +1 -0
- package/dist/skills/front-version.d.ts +12 -0
- package/dist/skills/front-version.d.ts.map +1 -0
- package/dist/skills/front-version.js +87 -0
- package/dist/skills/front-version.js.map +1 -0
- package/dist/skills/host-facts.d.ts +51 -0
- package/dist/skills/host-facts.d.ts.map +1 -0
- package/dist/skills/host-facts.js +134 -0
- package/dist/skills/host-facts.js.map +1 -0
- package/dist/skills/learning-steps.d.ts +43 -0
- package/dist/skills/learning-steps.d.ts.map +1 -0
- package/dist/skills/learning-steps.js +294 -0
- package/dist/skills/learning-steps.js.map +1 -0
- package/dist/skills/ledger.d.ts +43 -0
- package/dist/skills/ledger.d.ts.map +1 -0
- package/dist/skills/ledger.js +336 -0
- package/dist/skills/ledger.js.map +1 -0
- package/dist/skills/lesson-gate.d.ts +25 -0
- package/dist/skills/lesson-gate.d.ts.map +1 -0
- package/dist/skills/lesson-gate.js +316 -0
- package/dist/skills/lesson-gate.js.map +1 -0
- package/dist/skills/lessons.d.ts +60 -0
- package/dist/skills/lessons.d.ts.map +1 -0
- package/dist/skills/lessons.js +396 -0
- package/dist/skills/lessons.js.map +1 -0
- package/dist/skills/offer-answers.d.ts +20 -0
- package/dist/skills/offer-answers.d.ts.map +1 -0
- package/dist/skills/offer-answers.js +51 -0
- package/dist/skills/offer-answers.js.map +1 -0
- package/dist/skills/offer-drift.d.ts +35 -0
- package/dist/skills/offer-drift.d.ts.map +1 -0
- package/dist/skills/offer-drift.js +98 -0
- package/dist/skills/offer-drift.js.map +1 -0
- package/dist/skills/offer-lesson.d.ts +31 -0
- package/dist/skills/offer-lesson.d.ts.map +1 -0
- package/dist/skills/offer-lesson.js +123 -0
- package/dist/skills/offer-lesson.js.map +1 -0
- package/dist/skills/offer-lines.d.ts +40 -0
- package/dist/skills/offer-lines.d.ts.map +1 -0
- package/dist/skills/offer-lines.js +80 -0
- package/dist/skills/offer-lines.js.map +1 -0
- package/dist/skills/offer-moment.d.ts +102 -0
- package/dist/skills/offer-moment.d.ts.map +1 -0
- package/dist/skills/offer-moment.js +260 -0
- package/dist/skills/offer-moment.js.map +1 -0
- package/dist/skills/offer-repair.d.ts +36 -0
- package/dist/skills/offer-repair.d.ts.map +1 -0
- package/dist/skills/offer-repair.js +212 -0
- package/dist/skills/offer-repair.js.map +1 -0
- package/dist/skills/offer-retire.d.ts +53 -0
- package/dist/skills/offer-retire.d.ts.map +1 -0
- package/dist/skills/offer-retire.js +149 -0
- package/dist/skills/offer-retire.js.map +1 -0
- package/dist/skills/offer-update.d.ts +54 -0
- package/dist/skills/offer-update.d.ts.map +1 -0
- package/dist/skills/offer-update.js +115 -0
- package/dist/skills/offer-update.js.map +1 -0
- package/dist/skills/offer-words-1b.d.ts +32 -0
- package/dist/skills/offer-words-1b.d.ts.map +1 -0
- package/dist/skills/offer-words-1b.js +80 -0
- package/dist/skills/offer-words-1b.js.map +1 -0
- package/dist/skills/offer-words-2.d.ts +123 -0
- package/dist/skills/offer-words-2.d.ts.map +1 -0
- package/dist/skills/offer-words-2.js +194 -0
- package/dist/skills/offer-words-2.js.map +1 -0
- package/dist/skills/offer-words.d.ts +65 -0
- package/dist/skills/offer-words.d.ts.map +1 -0
- package/dist/skills/offer-words.js +205 -0
- package/dist/skills/offer-words.js.map +1 -0
- package/dist/skills/offers.d.ts +66 -0
- package/dist/skills/offers.d.ts.map +1 -0
- package/dist/skills/offers.js +284 -0
- package/dist/skills/offers.js.map +1 -0
- package/dist/skills/own-folder.d.ts +9 -0
- package/dist/skills/own-folder.d.ts.map +1 -0
- package/dist/skills/own-folder.js +36 -0
- package/dist/skills/own-folder.js.map +1 -0
- package/dist/skills/person.d.ts +34 -0
- package/dist/skills/person.d.ts.map +1 -0
- package/dist/skills/person.js +102 -0
- package/dist/skills/person.js.map +1 -0
- package/dist/skills/probe-clean.d.ts +9 -0
- package/dist/skills/probe-clean.d.ts.map +1 -0
- package/dist/skills/probe-clean.js +48 -0
- package/dist/skills/probe-clean.js.map +1 -0
- package/dist/skills/probes.d.ts +26 -0
- package/dist/skills/probes.d.ts.map +1 -0
- package/dist/skills/probes.js +225 -0
- package/dist/skills/probes.js.map +1 -0
- package/dist/skills/recall.d.ts +119 -0
- package/dist/skills/recall.d.ts.map +1 -0
- package/dist/skills/recall.js +370 -0
- package/dist/skills/recall.js.map +1 -0
- package/dist/skills/receipts.d.ts +44 -0
- package/dist/skills/receipts.d.ts.map +1 -0
- package/dist/skills/receipts.js +223 -0
- package/dist/skills/receipts.js.map +1 -0
- package/dist/skills/run-checkout.d.ts +4 -0
- package/dist/skills/run-checkout.d.ts.map +1 -0
- package/dist/skills/run-checkout.js +37 -0
- package/dist/skills/run-checkout.js.map +1 -0
- package/dist/skills/runblock.d.ts +47 -0
- package/dist/skills/runblock.d.ts.map +1 -0
- package/dist/skills/runblock.js +227 -0
- package/dist/skills/runblock.js.map +1 -0
- package/dist/skills/save-gate.d.ts +64 -0
- package/dist/skills/save-gate.d.ts.map +1 -0
- package/dist/skills/save-gate.js +354 -0
- package/dist/skills/save-gate.js.map +1 -0
- package/dist/skills/save-parse.d.ts +42 -0
- package/dist/skills/save-parse.d.ts.map +1 -0
- package/dist/skills/save-parse.js +172 -0
- package/dist/skills/save-parse.js.map +1 -0
- package/dist/skills/save-store.d.ts +12 -0
- package/dist/skills/save-store.d.ts.map +1 -0
- package/dist/skills/save-store.js +22 -0
- package/dist/skills/save-store.js.map +1 -0
- package/dist/skills/save-verify.d.ts +59 -0
- package/dist/skills/save-verify.d.ts.map +1 -0
- package/dist/skills/save-verify.js +390 -0
- package/dist/skills/save-verify.js.map +1 -0
- package/dist/skills/settings.d.ts +48 -0
- package/dist/skills/settings.d.ts.map +1 -0
- package/dist/skills/settings.js +155 -0
- package/dist/skills/settings.js.map +1 -0
- package/dist/skills/skill-diff.d.ts +40 -0
- package/dist/skills/skill-diff.d.ts.map +1 -0
- package/dist/skills/skill-diff.js +191 -0
- package/dist/skills/skill-diff.js.map +1 -0
- package/dist/skills/skill-file.d.ts +24 -0
- package/dist/skills/skill-file.d.ts.map +1 -0
- package/dist/skills/skill-file.js +97 -0
- package/dist/skills/skill-file.js.map +1 -0
- package/dist/skills/skill-rebuild.d.ts +27 -0
- package/dist/skills/skill-rebuild.d.ts.map +1 -0
- package/dist/skills/skill-rebuild.js +85 -0
- package/dist/skills/skill-rebuild.js.map +1 -0
- package/dist/skills/skillmd.d.ts +17 -0
- package/dist/skills/skillmd.d.ts.map +1 -0
- package/dist/skills/skillmd.js +219 -0
- package/dist/skills/skillmd.js.map +1 -0
- package/dist/skills/skills.d.ts +28 -8
- package/dist/skills/skills.d.ts.map +1 -1
- package/dist/skills/skills.js +106 -53
- package/dist/skills/skills.js.map +1 -1
- package/dist/skills/staleness.d.ts +27 -0
- package/dist/skills/staleness.d.ts.map +1 -0
- package/dist/skills/staleness.js +178 -0
- package/dist/skills/staleness.js.map +1 -0
- package/dist/skills/state.d.ts +36 -0
- package/dist/skills/state.d.ts.map +1 -0
- package/dist/skills/state.js +259 -0
- package/dist/skills/state.js.map +1 -0
- package/dist/skills/store-fs.d.ts +77 -0
- package/dist/skills/store-fs.d.ts.map +1 -0
- package/dist/skills/store-fs.js +194 -0
- package/dist/skills/store-fs.js.map +1 -0
- package/dist/skills/store-held.d.ts +44 -0
- package/dist/skills/store-held.d.ts.map +1 -0
- package/dist/skills/store-held.js +147 -0
- package/dist/skills/store-held.js.map +1 -0
- package/dist/skills/store.d.ts +73 -0
- package/dist/skills/store.d.ts.map +1 -0
- package/dist/skills/store.js +279 -0
- package/dist/skills/store.js.map +1 -0
- package/dist/skills/types.d.ts +8 -0
- package/dist/skills/types.d.ts.map +1 -1
- package/dist/skills/update-gate.d.ts +36 -0
- package/dist/skills/update-gate.d.ts.map +1 -0
- package/dist/skills/update-gate.js +357 -0
- package/dist/skills/update-gate.js.map +1 -0
- package/dist/skills/update-plan.d.ts +40 -0
- package/dist/skills/update-plan.d.ts.map +1 -0
- package/dist/skills/update-plan.js +196 -0
- package/dist/skills/update-plan.js.map +1 -0
- package/dist/skills/validate.d.ts +11 -0
- package/dist/skills/validate.d.ts.map +1 -0
- package/dist/skills/validate.js +112 -0
- package/dist/skills/validate.js.map +1 -0
- package/dist/skills/value-line.d.ts +94 -0
- package/dist/skills/value-line.d.ts.map +1 -0
- package/dist/skills/value-line.js +355 -0
- package/dist/skills/value-line.js.map +1 -0
- package/dist/skills/versions-fs.d.ts +45 -0
- package/dist/skills/versions-fs.d.ts.map +1 -0
- package/dist/skills/versions-fs.js +234 -0
- package/dist/skills/versions-fs.js.map +1 -0
- package/dist/skills/versions.d.ts +56 -0
- package/dist/skills/versions.d.ts.map +1 -0
- package/dist/skills/versions.js +351 -0
- package/dist/skills/versions.js.map +1 -0
- package/dist/telemetry/contract.d.ts +15 -1
- package/dist/telemetry/contract.d.ts.map +1 -1
- package/dist/telemetry/contract.js +80 -11
- package/dist/telemetry/contract.js.map +1 -1
- package/dist/telemetry/gate.js +4 -4
- package/dist/telemetry/gate.js.map +1 -1
- package/dist/telemetry/index.d.ts +1 -1
- package/dist/telemetry/index.d.ts.map +1 -1
- package/dist/telemetry/index.js +1 -1
- package/dist/telemetry/index.js.map +1 -1
- package/dist/telemetry/notice.js +5 -5
- package/dist/telemetry/notice.js.map +1 -1
- package/dist/telemetry/queue.d.ts.map +1 -1
- package/dist/telemetry/queue.js +7 -7
- package/dist/telemetry/queue.js.map +1 -1
- package/dist/telemetry/track.d.ts.map +1 -1
- package/dist/telemetry/track.js +4 -3
- package/dist/telemetry/track.js.map +1 -1
- package/dist/trace/checks.d.ts +63 -0
- package/dist/trace/checks.d.ts.map +1 -0
- package/dist/trace/checks.js +495 -0
- package/dist/trace/checks.js.map +1 -0
- package/dist/trace/claude.d.ts +124 -0
- package/dist/trace/claude.d.ts.map +1 -0
- package/dist/trace/claude.js +303 -0
- package/dist/trace/claude.js.map +1 -0
- package/dist/trace/codex-exec.d.ts +22 -0
- package/dist/trace/codex-exec.d.ts.map +1 -0
- package/dist/trace/codex-exec.js +129 -0
- package/dist/trace/codex-exec.js.map +1 -0
- package/dist/trace/codex-meta.d.ts +23 -0
- package/dist/trace/codex-meta.d.ts.map +1 -0
- package/dist/trace/codex-meta.js +112 -0
- package/dist/trace/codex-meta.js.map +1 -0
- package/dist/trace/codex.d.ts +33 -0
- package/dist/trace/codex.d.ts.map +1 -0
- package/dist/trace/codex.js +485 -0
- package/dist/trace/codex.js.map +1 -0
- package/dist/trace/cursor.d.ts +16 -0
- package/dist/trace/cursor.d.ts.map +1 -0
- package/dist/trace/cursor.js +133 -0
- package/dist/trace/cursor.js.map +1 -0
- package/dist/trace/dialect.d.ts +43 -0
- package/dist/trace/dialect.d.ts.map +1 -0
- package/dist/trace/dialect.js +95 -0
- package/dist/trace/dialect.js.map +1 -0
- package/dist/trace/epochs.d.ts +10 -0
- package/dist/trace/epochs.d.ts.map +1 -0
- package/dist/trace/epochs.js +16 -0
- package/dist/trace/epochs.js.map +1 -0
- package/dist/trace/failure.d.ts +15 -0
- package/dist/trace/failure.d.ts.map +1 -0
- package/dist/trace/failure.js +69 -0
- package/dist/trace/failure.js.map +1 -0
- package/dist/trace/gate-file.d.ts +71 -0
- package/dist/trace/gate-file.d.ts.map +1 -0
- package/dist/trace/gate-file.js +329 -0
- package/dist/trace/gate-file.js.map +1 -0
- package/dist/trace/guard-fast.d.ts +22 -0
- package/dist/trace/guard-fast.d.ts.map +1 -0
- package/dist/trace/guard-fast.js +213 -0
- package/dist/trace/guard-fast.js.map +1 -0
- package/dist/trace/housekeeping.d.ts +5 -0
- package/dist/trace/housekeeping.d.ts.map +1 -0
- package/dist/trace/housekeeping.js +93 -0
- package/dist/trace/housekeeping.js.map +1 -0
- package/dist/trace/jobs.d.ts +52 -0
- package/dist/trace/jobs.d.ts.map +1 -0
- package/dist/trace/jobs.js +182 -0
- package/dist/trace/jobs.js.map +1 -0
- package/dist/trace/known-repo.d.ts +3 -0
- package/dist/trace/known-repo.d.ts.map +1 -0
- package/dist/trace/known-repo.js +55 -0
- package/dist/trace/known-repo.js.map +1 -0
- package/dist/trace/pool.d.ts +40 -0
- package/dist/trace/pool.d.ts.map +1 -0
- package/dist/trace/pool.js +154 -0
- package/dist/trace/pool.js.map +1 -0
- package/dist/trace/repairs.d.ts +27 -0
- package/dist/trace/repairs.d.ts.map +1 -0
- package/dist/trace/repairs.js +303 -0
- package/dist/trace/repairs.js.map +1 -0
- package/dist/trace/run-calls.d.ts +82 -0
- package/dist/trace/run-calls.d.ts.map +1 -0
- package/dist/trace/run-calls.js +331 -0
- package/dist/trace/run-calls.js.map +1 -0
- package/dist/trace/run-join.d.ts +20 -0
- package/dist/trace/run-join.d.ts.map +1 -0
- package/dist/trace/run-join.js +99 -0
- package/dist/trace/run-join.js.map +1 -0
- package/dist/trace/run-sheets.d.ts +26 -0
- package/dist/trace/run-sheets.d.ts.map +1 -0
- package/dist/trace/run-sheets.js +145 -0
- package/dist/trace/run-sheets.js.map +1 -0
- package/dist/trace/run-turns.d.ts +24 -0
- package/dist/trace/run-turns.d.ts.map +1 -0
- package/dist/trace/run-turns.js +67 -0
- package/dist/trace/run-turns.js.map +1 -0
- package/dist/trace/run-verdict.d.ts +24 -0
- package/dist/trace/run-verdict.d.ts.map +1 -0
- package/dist/trace/run-verdict.js +176 -0
- package/dist/trace/run-verdict.js.map +1 -0
- package/dist/trace/runs.d.ts +54 -0
- package/dist/trace/runs.d.ts.map +1 -0
- package/dist/trace/runs.js +501 -0
- package/dist/trace/runs.js.map +1 -0
- package/dist/trace/skill-session.d.ts +64 -0
- package/dist/trace/skill-session.d.ts.map +1 -0
- package/dist/trace/skill-session.js +232 -0
- package/dist/trace/skill-session.js.map +1 -0
- package/dist/trace/tamper.d.ts +12 -0
- package/dist/trace/tamper.d.ts.map +1 -0
- package/dist/trace/tamper.js +405 -0
- package/dist/trace/tamper.js.map +1 -0
- package/dist/trace/typed.d.ts +30 -0
- package/dist/trace/typed.d.ts.map +1 -0
- package/dist/trace/typed.js +132 -0
- package/dist/trace/typed.js.map +1 -0
- package/dist/trace/wall-state.d.ts +86 -0
- package/dist/trace/wall-state.d.ts.map +1 -0
- package/dist/trace/wall-state.js +279 -0
- package/dist/trace/wall-state.js.map +1 -0
- package/dist/trace/walls.d.ts +40 -0
- package/dist/trace/walls.d.ts.map +1 -0
- package/dist/trace/walls.js +318 -0
- package/dist/trace/walls.js.map +1 -0
- package/dist/upkeep-run.d.ts.map +1 -1
- package/dist/upkeep-run.js +2 -23
- package/dist/upkeep-run.js.map +1 -1
- package/dist/upkeep.d.ts.map +1 -1
- package/dist/upkeep.js +2 -3
- package/dist/upkeep.js.map +1 -1
- package/dist/util/private-fs.d.ts +6 -0
- package/dist/util/private-fs.d.ts.map +1 -1
- package/dist/util/private-fs.js +9 -1
- package/dist/util/private-fs.js.map +1 -1
- package/dist/util/state.d.ts.map +1 -1
- package/dist/util/state.js +17 -3
- package/dist/util/state.js.map +1 -1
- package/dist/vendor/tree-sitter-swift/LICENSE +21 -0
- package/dist/vendor/tree-sitter-swift/node-types.json +30694 -0
- package/dist/vendor/tree-sitter-swift/prebuilds/darwin-arm64/tree-sitter-swift.node +0 -0
- package/dist/vendor/tree-sitter-swift/prebuilds/darwin-x64/tree-sitter-swift.node +0 -0
- package/dist/vendor/tree-sitter-swift/prebuilds/linux-arm64/tree-sitter-swift.node +0 -0
- package/dist/vendor/tree-sitter-swift/prebuilds/linux-x64/tree-sitter-swift.node +0 -0
- package/dist/vendor/tree-sitter-swift/prebuilds/win32-arm64/tree-sitter-swift.node +0 -0
- package/dist/vendor/tree-sitter-swift/prebuilds/win32-x64/tree-sitter-swift.node +0 -0
- package/package.json +6 -3
- package/scripts/stamp-telemetry-key.mjs +8 -5
- package/scripts/vendor-grammars.mjs +35 -0
|
@@ -2,31 +2,42 @@
|
|
|
2
2
|
* Keeps the workspace's copy of a repo's learnings, and its record of how
|
|
3
3
|
* they're used, in step with this machine.
|
|
4
4
|
*
|
|
5
|
-
* What goes up for a repo in the workspace is every learning in its `.trail
|
|
6
|
-
* the
|
|
7
|
-
* `git fetch`.
|
|
8
|
-
*
|
|
5
|
+
* What goes up for a repo in the workspace is every learning in its `.trail/`
|
|
6
|
+
* that git has: the ones committed at HEAD and the ones on teammates' pushed
|
|
7
|
+
* branches, after a `git fetch`. Never an uncommitted edit or an untracked
|
|
8
|
+
* file. Not just this person's, so one person is enough to cover a repo.
|
|
9
|
+
* Personal learnings in ~/.trail never go up.
|
|
9
10
|
*
|
|
10
11
|
* Uses (a search that showed learnings, a check against them) are appended to
|
|
11
12
|
* `~/.trail/outbox.jsonl` as they happen, and sent with the next sync. That's
|
|
12
|
-
* how a teammate's reuse of a learning shows on the team page.
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
13
|
+
* how a teammate's reuse of a learning shows on the team page. A use is counts
|
|
14
|
+
* and the names of the learnings shown: never what someone typed, never the
|
|
15
|
+
* files they're in. And only names the workspace already has: a learning's
|
|
16
|
+
* file name carries the first words of its title, so a personal learning, or
|
|
17
|
+
* one git doesn't have yet, is left out. Only while the machine is connected,
|
|
18
|
+
* and only for a repo in the workspace: nobody agreed to send even that for a
|
|
19
|
+
* repo they didn't pick, or from before they signed in.
|
|
16
20
|
*
|
|
17
21
|
* Commands never wait on any of this: when something changed, a detached
|
|
18
22
|
* `_trail-sync` child does it.
|
|
19
23
|
*/
|
|
20
24
|
import { createHash } from "node:crypto";
|
|
21
|
-
import { spawn } from "node:child_process";
|
|
22
|
-
import {
|
|
23
|
-
import { basename, join } from "node:path";
|
|
25
|
+
import { execFileSync, spawn } from "node:child_process";
|
|
26
|
+
import { existsSync, readdirSync, readFileSync, realpathSync, renameSync, rmSync, statSync } from "node:fs";
|
|
27
|
+
import { basename, join, relative, sep } from "node:path";
|
|
28
|
+
import { isUtf8 } from "node:buffer";
|
|
24
29
|
import { graftCliPath } from "../claude/paths.js";
|
|
25
30
|
import { readBranchCache, refreshBranches } from "../notes/branches.js";
|
|
26
31
|
import { knownRepos, repoName, repoPlace, trailHome } from "../notes/home.js";
|
|
27
32
|
import { LEARNINGS_DIR, learningFiles, readLearningFile } from "../notes/repo-trail.js";
|
|
28
33
|
import { parseNote } from "../notes/notes.js";
|
|
34
|
+
import { liveLearnings } from "../notes/learning-fields.js";
|
|
35
|
+
import { secretReason } from "../notes/secrets.js";
|
|
36
|
+
import { OWN_SKILLS, skillDirs } from "../skills/skills.js";
|
|
37
|
+
import { matter } from "../util/front-matter.js";
|
|
38
|
+
import { appendPrivateFile, ensurePrivateDir, PRIVATE_FILE_MODE, writePrivateFile } from "../util/private-file.js";
|
|
29
39
|
import { cacheDir, readJson, writeJsonAtomic } from "../util/state.js";
|
|
40
|
+
import { headLearnings } from "./head-learnings.js";
|
|
30
41
|
import { isError, postActivity, readCloud, uploadLearnings } from "./workspace.js";
|
|
31
42
|
/** A failed sync is retried after this long, not on every command. */
|
|
32
43
|
const RETRY_MS = 5 * 60 * 1000;
|
|
@@ -36,59 +47,293 @@ const OUTBOX_KEEP_LINES = 2000;
|
|
|
36
47
|
function sha256(text) {
|
|
37
48
|
return createHash("sha256").update(text).digest("hex");
|
|
38
49
|
}
|
|
50
|
+
/** A skill folder name safe to send as a path part. */
|
|
51
|
+
const SKILL_FOLDER = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
52
|
+
function inside(root, p) {
|
|
53
|
+
return p === root || p.startsWith(root + sep);
|
|
54
|
+
}
|
|
55
|
+
/** A SKILL.md bigger than this is not a skill, and is never sent. */
|
|
56
|
+
const SKILL_MAX_BYTES = 256 * 1024;
|
|
57
|
+
/** What Trail keeps of a skill's folder besides SKILL.md (the server's limits too). */
|
|
58
|
+
const SKILL_FILES_MAX = 100;
|
|
59
|
+
const SKILL_FILE_MAX_BYTES = 1024 * 1024;
|
|
60
|
+
const SKILL_FOLDER_MAX_BYTES = 4 * 1024 * 1024;
|
|
61
|
+
/** Never part of a skill, though a folder may hold them. */
|
|
62
|
+
const NOT_SKILL_FILE = /(^|\/)(node_modules|__pycache__|\.git|\.venv)(\/|$)|(^|\/)\.DS_Store$|\.(map|pyc)$/;
|
|
39
63
|
/**
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
64
|
+
* The files git tracks in a skill's folder besides SKILL.md, as they go up:
|
|
65
|
+
* text as is, anything else as base64, the executable bit kept. A file that
|
|
66
|
+
* resolves outside the checkout, or is too big, stays behind; so do the
|
|
67
|
+
* ones past the folder's limits, smallest paths first.
|
|
43
68
|
*/
|
|
44
|
-
|
|
69
|
+
function skillFolderFiles(root, folder) {
|
|
70
|
+
let rel;
|
|
71
|
+
try {
|
|
72
|
+
rel = relative(root, realpathSync(folder)).split(sep).join("/");
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return [];
|
|
76
|
+
}
|
|
45
77
|
const out = [];
|
|
78
|
+
let total = 0;
|
|
79
|
+
for (const path of [...trackedAmong(root, [rel + "/"])].sort()) {
|
|
80
|
+
const inner = path.slice(rel.length + 1);
|
|
81
|
+
if (!inner || inner === "SKILL.md" || NOT_SKILL_FILE.test(inner) || out.length === SKILL_FILES_MAX)
|
|
82
|
+
continue;
|
|
83
|
+
try {
|
|
84
|
+
const file = join(root, ...path.split("/"));
|
|
85
|
+
const st = statSync(file);
|
|
86
|
+
if (!st.isFile() || st.size > SKILL_FILE_MAX_BYTES || total + st.size > SKILL_FOLDER_MAX_BYTES)
|
|
87
|
+
continue;
|
|
88
|
+
if (!inside(root, realpathSync(file)))
|
|
89
|
+
continue;
|
|
90
|
+
const bytes = readFileSync(file);
|
|
91
|
+
const text = !bytes.includes(0) && isUtf8(bytes);
|
|
92
|
+
total += bytes.length;
|
|
93
|
+
out.push({
|
|
94
|
+
path: inner,
|
|
95
|
+
content: text ? bytes.toString("utf8") : bytes.toString("base64"),
|
|
96
|
+
...(text ? {} : { encoding: "base64" }),
|
|
97
|
+
...(st.mode & 0o111 ? { executable: true } : {}),
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
/* gone, or can't be read */
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return out;
|
|
105
|
+
}
|
|
106
|
+
/** `cut-a-release` → `Cut a release`: a skill's folder name as a title. */
|
|
107
|
+
function skillTitle(name) {
|
|
108
|
+
const words = name.replace(/[-_]+/g, " ").trim();
|
|
109
|
+
return words ? words[0].toUpperCase() + words.slice(1) : name;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Which of `paths` (relative to `root`) git tracks, by what `git ls-files` says,
|
|
113
|
+
* so a gitignored or untracked file is not among them. Empty when `root` isn't a
|
|
114
|
+
* git checkout or git fails: no skill goes up then.
|
|
115
|
+
*/
|
|
116
|
+
function trackedAmong(root, paths) {
|
|
117
|
+
if (paths.length === 0)
|
|
118
|
+
return new Set();
|
|
119
|
+
try {
|
|
120
|
+
const out = execFileSync("git", ["--literal-pathspecs", "ls-files", "-z", "--", ...paths], {
|
|
121
|
+
cwd: root,
|
|
122
|
+
encoding: "utf8",
|
|
123
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
124
|
+
timeout: 15_000,
|
|
125
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
126
|
+
});
|
|
127
|
+
return new Set(out.split("\0").filter(Boolean));
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return new Set();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* The repo's skills, as the workspace takes them: each `.claude/skills/<name>/SKILL.md`
|
|
135
|
+
* in the working tree that git tracks (an untracked or gitignored one isn't the
|
|
136
|
+
* team's, so it stays here; no git, no skills). Same item as the one init sends
|
|
137
|
+
* for a skill it just found (the server keeps one per repo and path): the body is
|
|
138
|
+
* SKILL.md without its frontmatter, the hash is of the whole file. A symlinked
|
|
139
|
+
* skill is read only when it resolves inside the checkout, and goes up when the
|
|
140
|
+
* file it resolves to is tracked. A SKILL.md that can't be read or parsed, or is
|
|
141
|
+
* over 256 KB, is skipped. Skills kept in ~/.trail are never sent.
|
|
142
|
+
*/
|
|
143
|
+
function skillItems(checkout) {
|
|
144
|
+
const dir = skillDirs(checkout).repo;
|
|
145
|
+
let root;
|
|
146
|
+
let names;
|
|
147
|
+
try {
|
|
148
|
+
root = realpathSync(join(dir, "..", ".."));
|
|
149
|
+
names = readdirSync(dir).sort();
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
return [];
|
|
153
|
+
}
|
|
154
|
+
// Each candidate that passes the cheap checks, with where its file really is.
|
|
155
|
+
const candidates = [];
|
|
156
|
+
for (const name of names) {
|
|
157
|
+
if (!SKILL_FOLDER.test(name) || OWN_SKILLS.has(name))
|
|
158
|
+
continue;
|
|
159
|
+
try {
|
|
160
|
+
const file = join(dir, name, "SKILL.md");
|
|
161
|
+
if (!statSync(join(dir, name)).isDirectory())
|
|
162
|
+
continue;
|
|
163
|
+
const st = statSync(file);
|
|
164
|
+
if (!st.isFile() || st.size > SKILL_MAX_BYTES)
|
|
165
|
+
continue;
|
|
166
|
+
const real = realpathSync(file);
|
|
167
|
+
if (!inside(root, realpathSync(join(dir, name))) || !inside(root, real))
|
|
168
|
+
continue;
|
|
169
|
+
candidates.push({ name, file, real: relative(root, real).split(sep).join("/") });
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
/* no SKILL.md here */
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
const tracked = trackedAmong(root, [...new Set(candidates.map((c) => c.real))]);
|
|
176
|
+
const out = [];
|
|
177
|
+
for (const { name, file, real } of candidates) {
|
|
178
|
+
if (!tracked.has(real))
|
|
179
|
+
continue;
|
|
180
|
+
try {
|
|
181
|
+
const text = readFileSync(file, "utf8");
|
|
182
|
+
const parsed = matter(text);
|
|
183
|
+
const d = parsed.data;
|
|
184
|
+
const description = typeof d.description === "string" ? d.description.trim().replace(/\s+/g, " ") : "";
|
|
185
|
+
const files = skillFolderFiles(root, join(dir, name));
|
|
186
|
+
out.push({
|
|
187
|
+
path: `.claude/skills/${name}/SKILL.md`,
|
|
188
|
+
kind: "skill",
|
|
189
|
+
ref: "",
|
|
190
|
+
title: skillTitle(typeof d.name === "string" && d.name.trim() ? d.name.trim() : name),
|
|
191
|
+
why: description,
|
|
192
|
+
author: typeof d.author === "string" ? d.author.trim() : "",
|
|
193
|
+
date: "",
|
|
194
|
+
touches: [],
|
|
195
|
+
body: parsed.content.trim(),
|
|
196
|
+
// The whole folder: any file changing sends the skill again.
|
|
197
|
+
hash: sha256(JSON.stringify(["folder", text, files.map((f) => [f.path, sha256(f.content), !!f.executable])])),
|
|
198
|
+
files,
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
/* a SKILL.md that can't be read or parsed */
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return out;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Every live learning in the repo's `.trail/`, as the workspace takes them:
|
|
209
|
+
* the ones committed at HEAD, then the ones only a pushed branch has (from
|
|
210
|
+
* the branch cache), then the repo's skills that git tracks (`skillItems`).
|
|
211
|
+
* Never the working tree's learnings: an uncommitted or untracked learning
|
|
212
|
+
* stays on this machine. Paths are repo-relative; nothing about this
|
|
213
|
+
* machine is sent. Null when git couldn't read HEAD: then nothing may go up,
|
|
214
|
+
* since a set without HEAD's learnings would tell the workspace they're gone.
|
|
215
|
+
*
|
|
216
|
+
* Live means what recall reads (`liveLearnings`): a retired, held or replaced
|
|
217
|
+
* learning stays behind, so the team page never shows one nobody is meant to
|
|
218
|
+
* follow. A learning on an unmerged branch replaces nothing yet.
|
|
219
|
+
*
|
|
220
|
+
* A learning or skill whose text holds a secret (`secretReason`) stays behind, every
|
|
221
|
+
* copy of it: what a sync sent is what vouches for a learning's name in a
|
|
222
|
+
* use, so its name never goes up either. It is listed in `leftOut`, so
|
|
223
|
+
* `trail workspace` can say so instead of it going missing in silence.
|
|
224
|
+
*
|
|
225
|
+
* `tree`: the working tree's learnings in place of HEAD's, for `init --pair`'s
|
|
226
|
+
* review page only, which shows the person what init just wrote before any of
|
|
227
|
+
* it is committed. A sync never reads them.
|
|
228
|
+
*/
|
|
229
|
+
export function workspaceLearnings(checkout, opts = {}) {
|
|
230
|
+
const head = opts.tree ? treeLearnings(checkout) : headLearnings(checkout);
|
|
231
|
+
if (!head)
|
|
232
|
+
return null;
|
|
233
|
+
const read = [];
|
|
234
|
+
const leftOut = [];
|
|
46
235
|
const seen = new Set();
|
|
47
236
|
const add = (name, text, ref) => {
|
|
48
237
|
if (seen.has(name))
|
|
49
238
|
return;
|
|
239
|
+
const why = secretReason(text);
|
|
240
|
+
if (why) {
|
|
241
|
+
seen.add(name);
|
|
242
|
+
leftOut.push({ name, ref, why });
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
50
245
|
const n = parseNote(text, name);
|
|
51
246
|
if (!n)
|
|
52
247
|
return;
|
|
53
248
|
seen.add(name);
|
|
54
|
-
|
|
55
|
-
path: `${LEARNINGS_DIR}/${name}`,
|
|
56
|
-
ref,
|
|
57
|
-
branch: n.branch,
|
|
58
|
-
title: n.title,
|
|
59
|
-
author: n.author,
|
|
60
|
-
date: n.date,
|
|
61
|
-
minutes: n.cost?.minutes,
|
|
62
|
-
tokens: n.cost?.tokens,
|
|
63
|
-
touches: n.touches,
|
|
64
|
-
body: n.body,
|
|
65
|
-
hash: sha256(text),
|
|
66
|
-
});
|
|
249
|
+
read.push({ ...n, scope: "repo", ...(ref ? { ref } : {}), text });
|
|
67
250
|
};
|
|
251
|
+
for (const l of head)
|
|
252
|
+
add(l.name, l.text, "");
|
|
253
|
+
for (const b of readBranchCache(checkout)?.branches ?? [])
|
|
254
|
+
for (const l of b.learnings)
|
|
255
|
+
add(l.name, l.text, b.ref);
|
|
256
|
+
const learnings = liveLearnings(read).map((n) => ({
|
|
257
|
+
path: `${LEARNINGS_DIR}/${n.path}`,
|
|
258
|
+
ref: n.ref ?? "",
|
|
259
|
+
branch: n.branch,
|
|
260
|
+
title: n.title,
|
|
261
|
+
author: n.author,
|
|
262
|
+
date: n.date,
|
|
263
|
+
minutes: n.cost?.minutes,
|
|
264
|
+
tokens: n.cost?.tokens,
|
|
265
|
+
touches: n.touches,
|
|
266
|
+
body: n.body,
|
|
267
|
+
hash: sha256(n.text),
|
|
268
|
+
}));
|
|
269
|
+
// A skill whose text holds a secret stays behind too, named like a learning is.
|
|
270
|
+
for (const skill of skillItems(checkout)) {
|
|
271
|
+
const texts = (skill.files ?? []).filter((f) => !f.encoding).map((f) => f.content);
|
|
272
|
+
const why = secretReason([skill.title, skill.why ?? "", skill.body, ...texts].join("\n"));
|
|
273
|
+
if (why)
|
|
274
|
+
leftOut.push({ name: skill.path, ref: "", why });
|
|
275
|
+
else
|
|
276
|
+
learnings.push(skill);
|
|
277
|
+
}
|
|
278
|
+
return { learnings, leftOut };
|
|
279
|
+
}
|
|
280
|
+
/** The working tree's `.trail/learnings/` files, as `headLearnings` gives HEAD's. */
|
|
281
|
+
function treeLearnings(checkout) {
|
|
282
|
+
const out = [];
|
|
68
283
|
for (const name of learningFiles(checkout)) {
|
|
69
284
|
const text = readLearningFile(checkout, name);
|
|
70
285
|
if (text)
|
|
71
|
-
|
|
286
|
+
out.push({ name, text });
|
|
72
287
|
}
|
|
73
|
-
for (const b of readBranchCache(checkout)?.branches ?? [])
|
|
74
|
-
for (const l of b.learnings)
|
|
75
|
-
add(l.name, l.text, b.ref);
|
|
76
288
|
return out;
|
|
77
289
|
}
|
|
290
|
+
/**
|
|
291
|
+
* What `init --pair` hands its review page: the working tree's live learnings
|
|
292
|
+
* (what the person's agents start from, the ones init just wrote among them),
|
|
293
|
+
* teammates' pushed ones and the repo's tracked skills, secrets left out.
|
|
294
|
+
*/
|
|
295
|
+
export function reviewPayload(checkout) {
|
|
296
|
+
return workspaceLearnings(checkout, { tree: true })?.learnings ?? [];
|
|
297
|
+
}
|
|
298
|
+
/** The learnings a sync uploads: `workspaceLearnings` without what it left out. Null when git couldn't read HEAD. */
|
|
299
|
+
export function learningsPayload(checkout) {
|
|
300
|
+
return workspaceLearnings(checkout)?.learnings ?? null;
|
|
301
|
+
}
|
|
78
302
|
function fingerprint(learnings) {
|
|
79
303
|
return sha256(JSON.stringify(learnings.map((l) => [l.path, l.hash]).sort()));
|
|
80
304
|
}
|
|
305
|
+
/** The checkout's branch, or "" when git can't say (detached HEAD, no git). */
|
|
306
|
+
function currentBranch(checkout) {
|
|
307
|
+
try {
|
|
308
|
+
const b = execFileSync("git", ["rev-parse", "--abbrev-ref", "HEAD"], { cwd: checkout, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout: 5000 }).trim();
|
|
309
|
+
return b === "HEAD" ? "" : b;
|
|
310
|
+
}
|
|
311
|
+
catch {
|
|
312
|
+
return "";
|
|
313
|
+
}
|
|
314
|
+
}
|
|
81
315
|
function statePath(repo) {
|
|
82
316
|
return join(cacheDir(repo), "trail-workspace-sync.json");
|
|
83
317
|
}
|
|
84
|
-
/**
|
|
318
|
+
/**
|
|
319
|
+
* Whether the repo at `checkout` is one of the workspace's, so its learnings
|
|
320
|
+
* and uses go up. Never on a machine connected by `trail init --connect`: that
|
|
321
|
+
* one sends a repo summary only (titles and counts, no learning bodies, no
|
|
322
|
+
* searches), whatever repos the workspace lists.
|
|
323
|
+
*/
|
|
85
324
|
export function inWorkspace(checkout, cloud = readCloud()) {
|
|
86
|
-
return !!cloud && cloud.repos.includes(repoPlace(checkout).key);
|
|
325
|
+
return !!cloud && cloud.via !== "connect" && cloud.repos.includes(repoPlace(checkout).key);
|
|
87
326
|
}
|
|
88
327
|
/**
|
|
89
328
|
* Upload the repo's learnings now, after fetching teammates' branches. Only for
|
|
90
329
|
* a repo in the workspace. Remembers what was sent so an unchanged repo isn't
|
|
91
|
-
* sent again.
|
|
330
|
+
* sent again. When git can't read HEAD nothing is sent and the sync counts as
|
|
331
|
+
* failed, so it's tried again later.
|
|
332
|
+
*
|
|
333
|
+
* A learning or skill HEAD had at the last sync on this same branch, and no
|
|
334
|
+
* longer has (deleted, or now left out for a secret), is sent as removed, so
|
|
335
|
+
* it comes down from the web. On another branch a missing file says nothing,
|
|
336
|
+
* so switching branches never takes anything down.
|
|
92
337
|
*/
|
|
93
338
|
export async function syncRepo(checkout, cloud, opts = {}) {
|
|
94
339
|
const place = repoPlace(checkout);
|
|
@@ -96,15 +341,78 @@ export async function syncRepo(checkout, cloud, opts = {}) {
|
|
|
96
341
|
return { error: "this repo isn't in your workspace" };
|
|
97
342
|
if (opts.fetch !== false)
|
|
98
343
|
refreshBranches(place.checkout);
|
|
99
|
-
const
|
|
100
|
-
const
|
|
344
|
+
const found = workspaceLearnings(place.checkout);
|
|
345
|
+
const learnings = found?.learnings ?? null;
|
|
101
346
|
const prior = readJson(statePath(place.checkout));
|
|
347
|
+
const branch = currentBranch(place.checkout);
|
|
348
|
+
const paths = (learnings ?? []).filter((l) => l.ref === "").map((l) => l.path);
|
|
349
|
+
const here = new Set(paths);
|
|
350
|
+
const removed = branch && prior?.branch === branch ? (prior.paths ?? []).filter((p) => !here.has(p)) : [];
|
|
351
|
+
const held = found?.leftOut.length ?? 0;
|
|
352
|
+
const res = learnings
|
|
353
|
+
? await uploadLearnings(cloud, { repo: { key: place.key, name: repoName(place.key, place.checkout) }, learnings, ...(removed.length ? { removed } : {}), ...(held ? { held } : {}) }, opts.fetchImpl)
|
|
354
|
+
: { error: "git couldn't read this repo's learnings at HEAD" };
|
|
102
355
|
if (isError(res))
|
|
103
356
|
writeJsonAtomic(statePath(place.checkout), { ...(prior ?? { fingerprint: "", at: 0 }), failedAt: Date.now() }, true);
|
|
104
|
-
else
|
|
105
|
-
writeJsonAtomic(statePath(place.checkout), { fingerprint: fingerprint(learnings), at: Date.now(), learnings: res.learnings }, true);
|
|
357
|
+
else if (learnings) {
|
|
358
|
+
writeJsonAtomic(statePath(place.checkout), { fingerprint: fingerprint(learnings), at: Date.now(), learnings: res.learnings, paths, branch }, true);
|
|
359
|
+
rememberSent(place.key, learnings);
|
|
360
|
+
}
|
|
106
361
|
return res;
|
|
107
362
|
}
|
|
363
|
+
/** `.claude/skills/<name>/SKILL.md` → `<name>`; "" for any other path. */
|
|
364
|
+
export function repoSkillName(path) {
|
|
365
|
+
return /^\.claude\/skills\/([^/]+)\/SKILL\.md$/.exec(path)?.[1] ?? "";
|
|
366
|
+
}
|
|
367
|
+
function sentPath(env = process.env) {
|
|
368
|
+
return join(trailHome(env), "workspace-sent.json");
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Note what the workspace now has of a repo, which is what a use may name.
|
|
372
|
+
* Two syncs of different repos at once can lose one's entry: its uses then
|
|
373
|
+
* name nothing until its next sync, an undercount, never a leak.
|
|
374
|
+
*/
|
|
375
|
+
function rememberSent(key, learnings) {
|
|
376
|
+
try {
|
|
377
|
+
const all = readJson(sentPath()) ?? {};
|
|
378
|
+
const skills = learnings.filter((l) => l.kind === "skill").map((l) => repoSkillName(l.path)).filter(Boolean);
|
|
379
|
+
all[key] = { at: Date.now(), learnings: Object.fromEntries(learnings.filter((l) => l.kind !== "skill").map((l) => [learningName(l.path), l.author])), skills };
|
|
380
|
+
ensurePrivateDir(trailHome());
|
|
381
|
+
writeJsonAtomic(sentPath(), all, true, PRIVATE_FILE_MODE);
|
|
382
|
+
}
|
|
383
|
+
catch {
|
|
384
|
+
/* uses name nothing until the next sync */
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
/** What the workspace got of each repo from this machine. Empty when nothing was sent yet. */
|
|
388
|
+
function readSent() {
|
|
389
|
+
const out = { learnings: new Map(), skills: new Map() };
|
|
390
|
+
const all = readJson(sentPath());
|
|
391
|
+
if (typeof all !== "object" || all === null)
|
|
392
|
+
return out;
|
|
393
|
+
for (const [key, v] of Object.entries(all)) {
|
|
394
|
+
const ls = v?.learnings;
|
|
395
|
+
if (typeof ls === "object" && ls !== null)
|
|
396
|
+
out.learnings.set(key, new Map(Object.entries(ls).filter((e) => typeof e[1] === "string")));
|
|
397
|
+
out.skills.set(key, new Set(asStrings(v?.skills)));
|
|
398
|
+
}
|
|
399
|
+
return out;
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* The use as it may go up: only the learnings the workspace already got of
|
|
403
|
+
* its repo, each with the author that upload gave it. A personal learning,
|
|
404
|
+
* an uncommitted or untracked one, or one an older trail queued, is dropped
|
|
405
|
+
* from it, name and author both. A skill use goes only for a skill the
|
|
406
|
+
* workspace got of that repo; any other is dropped whole.
|
|
407
|
+
*/
|
|
408
|
+
function onlySent(e, sent) {
|
|
409
|
+
if (e.kind === "skill")
|
|
410
|
+
return e.skill && sent.skills.get(e.repo)?.has(e.skill) ? e : null;
|
|
411
|
+
const has = sent.learnings.get(e.repo);
|
|
412
|
+
const names = [...new Set(e.shown_paths)].filter((n) => has?.has(n));
|
|
413
|
+
const authors = names.map((n) => has.get(n));
|
|
414
|
+
return { ...e, shown_paths: names, shown_authors: e.kind === "check" ? [...new Set(authors)] : authors };
|
|
415
|
+
}
|
|
108
416
|
/** Sync every repo of the workspace that's on this machine. Returns what went up. */
|
|
109
417
|
export async function syncWorkspaceRepos(cloud, fetchImpl) {
|
|
110
418
|
let repos = 0;
|
|
@@ -131,20 +439,58 @@ function outboxPath(env = process.env) {
|
|
|
131
439
|
function sendable(e, cloud) {
|
|
132
440
|
return cloud.repos.includes(e.repo) && Date.parse(e.at) >= (cloud.linkedAt || 0);
|
|
133
441
|
}
|
|
442
|
+
/** Whether uses of `repo` are recorded at all: connected by `pair`/login (not `connect`) and the repo is the workspace's. */
|
|
443
|
+
export function records(cloud, repo) {
|
|
444
|
+
return !!cloud && cloud.via !== "connect" && cloud.repos.includes(repo);
|
|
445
|
+
}
|
|
446
|
+
/** A skill's folder name, as Claude Code names skills. */
|
|
447
|
+
const SKILL_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
|
|
448
|
+
const asStrings = (x) => (Array.isArray(x) ? x.filter((s) => typeof s === "string") : []);
|
|
449
|
+
const asText = (x) => (typeof x === "string" ? x : "");
|
|
450
|
+
/**
|
|
451
|
+
* A use as it may be queued or sent, built field by field from what was
|
|
452
|
+
* handed in. Anything else is left behind: an older trail queued the query
|
|
453
|
+
* (for the prompt hook, the person's whole prompt) and the file paths, and
|
|
454
|
+
* neither may reach the outbox or Trail. Null when it isn't a use at all.
|
|
455
|
+
*/
|
|
456
|
+
export function activityEvent(raw) {
|
|
457
|
+
if (typeof raw !== "object" || raw === null)
|
|
458
|
+
return null;
|
|
459
|
+
const r = raw;
|
|
460
|
+
if (r.kind !== "search" && r.kind !== "check" && r.kind !== "skill")
|
|
461
|
+
return null;
|
|
462
|
+
const skill = r.kind === "skill" ? asText(r.skill) : "";
|
|
463
|
+
if (r.kind === "skill" && !SKILL_NAME.test(skill))
|
|
464
|
+
return null;
|
|
465
|
+
const count = typeof r.file_count === "number" && Number.isFinite(r.file_count) ? Math.max(0, Math.floor(r.file_count)) : asStrings(r.files).length;
|
|
466
|
+
return {
|
|
467
|
+
repo: asText(r.repo),
|
|
468
|
+
kind: r.kind,
|
|
469
|
+
...(skill ? { skill } : {}),
|
|
470
|
+
asker: asText(r.asker),
|
|
471
|
+
session: asText(r.session),
|
|
472
|
+
file_count: count,
|
|
473
|
+
shown_paths: asStrings(r.shown_paths),
|
|
474
|
+
shown_authors: asStrings(r.shown_authors),
|
|
475
|
+
...(typeof r.saved_tokens === "number" && Number.isFinite(r.saved_tokens) && r.saved_tokens > 0 ? { saved_tokens: Math.floor(r.saved_tokens) } : {}),
|
|
476
|
+
at: asText(r.at),
|
|
477
|
+
};
|
|
478
|
+
}
|
|
134
479
|
/**
|
|
135
480
|
* Remember one use of the learnings, to send with the next sync: only while
|
|
136
481
|
* this machine is connected, and only for a repo in the workspace. Not
|
|
137
482
|
* connected, or another repo, and nothing is written. Never throws.
|
|
138
483
|
*/
|
|
139
|
-
export function recordActivity(
|
|
140
|
-
|
|
484
|
+
export function recordActivity(use, cloud = readCloud()) {
|
|
485
|
+
const e = activityEvent(use);
|
|
486
|
+
if (!e || !records(cloud, e.repo))
|
|
141
487
|
return;
|
|
142
488
|
try {
|
|
143
489
|
const p = outboxPath();
|
|
144
|
-
|
|
490
|
+
appendPrivateFile(p, `${JSON.stringify(e)}\n`);
|
|
145
491
|
if (statSync(p).size > OUTBOX_MAX_BYTES) {
|
|
146
492
|
const lines = readFileSync(p, "utf8").split("\n").filter(Boolean).slice(-OUTBOX_KEEP_LINES);
|
|
147
|
-
|
|
493
|
+
writePrivateFile(p, `${lines.join("\n")}\n`);
|
|
148
494
|
}
|
|
149
495
|
}
|
|
150
496
|
catch {
|
|
@@ -152,12 +498,14 @@ export function recordActivity(e, cloud = readCloud()) {
|
|
|
152
498
|
}
|
|
153
499
|
}
|
|
154
500
|
/**
|
|
155
|
-
* Forget every use waiting to go
|
|
156
|
-
* recorded before that is ever sent
|
|
501
|
+
* Forget every use waiting to go, and what an earlier connection was sent.
|
|
502
|
+
* Run when a machine connects, so nothing recorded before that is ever sent,
|
|
503
|
+
* and only what this connection uploads vouches for a learning's name.
|
|
157
504
|
*/
|
|
158
505
|
export function dropActivity(env = process.env) {
|
|
159
506
|
try {
|
|
160
507
|
rmSync(outboxPath(env), { force: true });
|
|
508
|
+
rmSync(sentPath(env), { force: true });
|
|
161
509
|
}
|
|
162
510
|
catch {
|
|
163
511
|
/* sent-time filtering in flushActivity drops them anyway */
|
|
@@ -175,7 +523,9 @@ function outboxHasEvents() {
|
|
|
175
523
|
* Send the outbox. It's moved aside first, so events recorded while the
|
|
176
524
|
* request is out land in a fresh file; on failure they're put back. A use
|
|
177
525
|
* from before this connection, or for a repo the workspace doesn't have
|
|
178
|
-
* (left by an older trail), is dropped, never sent
|
|
526
|
+
* (left by an older trail), is dropped, never sent; so is the name of any
|
|
527
|
+
* learning the workspace didn't get from this machine's last upload of that
|
|
528
|
+
* repo, put back or sent.
|
|
179
529
|
*/
|
|
180
530
|
export async function flushActivity(cloud, fetchImpl) {
|
|
181
531
|
const p = outboxPath();
|
|
@@ -188,14 +538,16 @@ export async function flushActivity(cloud, fetchImpl) {
|
|
|
188
538
|
catch {
|
|
189
539
|
return 0;
|
|
190
540
|
}
|
|
541
|
+
const has = readSent();
|
|
191
542
|
const events = [];
|
|
192
543
|
for (const line of readFileSync(sending, "utf8").split("\n")) {
|
|
193
544
|
try {
|
|
194
545
|
if (!line.trim())
|
|
195
546
|
continue;
|
|
196
|
-
const e = JSON.parse(line);
|
|
197
|
-
|
|
198
|
-
|
|
547
|
+
const e = activityEvent(JSON.parse(line));
|
|
548
|
+
const out = e && sendable(e, cloud) ? onlySent(e, has) : null;
|
|
549
|
+
if (out)
|
|
550
|
+
events.push(out);
|
|
199
551
|
}
|
|
200
552
|
catch {
|
|
201
553
|
/* a torn line */
|
|
@@ -207,7 +559,7 @@ export async function flushActivity(cloud, fetchImpl) {
|
|
|
207
559
|
if (isError(res)) {
|
|
208
560
|
// Put back what didn't go, ahead of anything recorded since.
|
|
209
561
|
const rest = events.slice(i).map((e) => JSON.stringify(e)).join("\n");
|
|
210
|
-
|
|
562
|
+
appendPrivateFile(p, `${rest}\n`);
|
|
211
563
|
break;
|
|
212
564
|
}
|
|
213
565
|
sent += Math.min(500, events.length - i);
|
|
@@ -219,12 +571,13 @@ export async function flushActivity(cloud, fetchImpl) {
|
|
|
219
571
|
/* -------------------------------------------------------------------------- */
|
|
220
572
|
/* in the background */
|
|
221
573
|
/* -------------------------------------------------------------------------- */
|
|
222
|
-
/** Whether the repo's learnings changed since they last went up, and a retry is due. */
|
|
574
|
+
/** Whether the repo's learnings changed since they last went up, and a retry is due. Never while git can't read HEAD. */
|
|
223
575
|
export function syncIsDue(checkout, now = Date.now()) {
|
|
224
576
|
const state = readJson(statePath(checkout));
|
|
225
577
|
if (state?.failedAt && now - state.failedAt < RETRY_MS)
|
|
226
578
|
return false;
|
|
227
|
-
|
|
579
|
+
const learnings = learningsPayload(checkout);
|
|
580
|
+
return !!learnings && state?.fingerprint !== fingerprint(learnings);
|
|
228
581
|
}
|
|
229
582
|
/**
|
|
230
583
|
* Sync in a detached child when this machine is connected and either the
|
|
@@ -234,8 +587,11 @@ export function syncIsDue(checkout, now = Date.now()) {
|
|
|
234
587
|
export function maybeSyncInBackground(dir, now = Date.now()) {
|
|
235
588
|
try {
|
|
236
589
|
const cloud = readCloud();
|
|
237
|
-
if (!cloud)
|
|
590
|
+
if (!cloud) {
|
|
591
|
+
// Whatever an older trail queued here can never go: connecting drops it.
|
|
592
|
+
dropActivity();
|
|
238
593
|
return false;
|
|
594
|
+
}
|
|
239
595
|
const checkout = repoPlace(dir).checkout;
|
|
240
596
|
const due = (inWorkspace(checkout, cloud) && syncIsDue(checkout, now)) || outboxHasEvents();
|
|
241
597
|
if (!due)
|