@hassangameryt/freeflow 0.8.0 → 0.9.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/.agents/plugins/marketplace.json +2 -2
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +2 -2
- package/.codex-plugin/plugin.json +3 -3
- package/.cursor-plugin/plugin.json +1 -1
- package/README.md +96 -149
- package/capabilities/cognitive-routing/SKILL.md +21 -129
- package/capabilities/cognitive-routing/references/coordinator.md +163 -0
- package/capabilities/cognitive-routing/references/worker.md +38 -0
- package/capabilities/compaction/SKILL.md +3 -3
- package/capabilities/compaction/references/summary-format.md +26 -15
- package/capabilities/messaging/SKILL.md +49 -0
- package/capabilities/task-memory/SKILL.md +87 -0
- package/command-surface.json +6 -54
- package/gemini-extension.json +1 -1
- package/hooks/claude/hooks.json +13 -3
- package/hooks/codex/hooks.json +2 -1
- package/hooks/shared/runtime-context.mjs +69 -77
- package/package.json +25 -8
- package/pi-extension/dist/ask-user/ask.js +108 -0
- package/pi-extension/dist/ask-user/form.js +250 -0
- package/pi-extension/dist/ask-user/questions.js +66 -0
- package/pi-extension/dist/ask-user/tool.js +124 -0
- package/pi-extension/dist/cognitive-routing/assembler.js +35 -11
- package/pi-extension/dist/cognitive-routing/bootstrap.js +90 -0
- package/pi-extension/dist/cognitive-routing/config.js +3 -4
- package/pi-extension/dist/cognitive-routing/event-store.js +4 -1
- package/pi-extension/dist/cognitive-routing/gate.js +20 -5
- package/pi-extension/dist/cognitive-routing/handlers.js +15 -13
- package/pi-extension/dist/cognitive-routing/model-control.js +17 -8
- package/pi-extension/dist/cognitive-routing/projection.js +23 -6
- package/pi-extension/dist/cognitive-routing/provenance.js +3 -1
- package/pi-extension/dist/cognitive-routing/render.js +15 -15
- package/pi-extension/dist/cognitive-routing/runtime.js +4 -2
- package/pi-extension/dist/cognitive-routing/schemas.js +4 -4
- package/pi-extension/dist/cognitive-routing/session.js +3 -1
- package/pi-extension/dist/cognitive-routing/sources.js +29 -4
- package/pi-extension/dist/cognitive-routing/state.js +18 -8
- package/pi-extension/dist/cognitive-routing/status.js +4 -3
- package/pi-extension/dist/cognitive-routing/tools.js +29 -15
- package/pi-extension/dist/cognitive-routing/types.js +10 -1
- package/pi-extension/dist/compaction/carry.js +36 -22
- package/pi-extension/dist/compaction/config.js +4 -2
- package/pi-extension/dist/compaction/controller.js +52 -29
- package/pi-extension/dist/compaction/harness.js +19 -3
- package/pi-extension/dist/compaction/results.js +14 -13
- package/pi-extension/dist/compaction/tool.js +6 -6
- package/pi-extension/dist/host/catalog.js +20 -35
- package/pi-extension/dist/host/config-validation.js +233 -0
- package/pi-extension/dist/host/config.js +78 -91
- package/pi-extension/dist/host/inbound.js +142 -0
- package/pi-extension/dist/host/projection-tags.js +1 -1
- package/pi-extension/dist/host/prompts.js +24 -13
- package/pi-extension/dist/host/read-only-session.js +6 -1
- package/pi-extension/dist/host/request-history.js +7 -3
- package/pi-extension/dist/host/rows.js +25 -0
- package/pi-extension/dist/host/runtime-state.js +17 -2
- package/pi-extension/dist/host/section-keeper.js +85 -0
- package/pi-extension/dist/host/settings/freeflow-command.js +846 -93
- package/pi-extension/dist/host/settings/settings-view.js +27 -8
- package/pi-extension/dist/host/status.js +19 -5
- package/pi-extension/dist/index.js +638 -72
- package/pi-extension/dist/messaging/config.js +27 -0
- package/pi-extension/dist/messaging/messaging.js +398 -0
- package/pi-extension/dist/messaging/registry.js +57 -0
- package/pi-extension/dist/messaging/render.js +90 -0
- package/pi-extension/dist/messaging/tools.js +109 -0
- package/pi-extension/dist/messaging/transport.js +101 -0
- package/pi-extension/dist/provider-support/cache/keepalive.js +16 -4
- package/pi-extension/dist/task-memory/config.js +49 -0
- package/pi-extension/dist/task-memory/registry.js +119 -0
- package/pi-extension/dist/task-memory/render.js +107 -0
- package/pi-extension/dist/task-memory/runtime.js +994 -0
- package/pi-extension/dist/task-memory/tool.js +233 -0
- package/pi-extension/dist/tool-execution/apply-patch/tool.js +1 -1
- package/pi-extension/dist/tool-execution/background.js +220 -28
- package/pi-extension/dist/tool-execution/config.js +14 -3
- package/pi-extension/dist/tool-execution/file-tracking.js +24 -4
- package/pi-extension/dist/tool-execution/guidance-notices.js +124 -0
- package/pi-extension/dist/tool-execution/skill-reads.js +143 -0
- package/pi-extension/dist/tool-execution/tools.js +2 -2
- package/runtime/prompts/cognitive-routing.md +4 -4
- package/runtime/prompts/core.md +24 -14
- package/runtime/prompts/interaction-contract.md +7 -4
- package/runtime/prompts/tool-execution.md +3 -16
- package/runtime/prompts/working-method.md +16 -99
- package/skills/deliver-work/SKILL.md +76 -0
- package/skills/deliver-work/references/branch-closeout.md +134 -0
- package/skills/deliver-work/references/commit.md +83 -0
- package/skills/deliver-work/references/launch.md +94 -0
- package/skills/deliver-work/references/release.md +85 -0
- package/skills/deliver-work/scripts/commit-state.mjs +139 -0
- package/skills/deliver-work/scripts/delivery-state.mjs +107 -0
- package/skills/deliver-work/scripts/lib/git-state.mjs +178 -0
- package/skills/deliver-work/scripts/push-route.mjs +122 -0
- package/skills/deliver-work/scripts/release-preflight.mjs +177 -0
- package/skills/discuss-work/SKILL.md +148 -0
- package/skills/{discuss → discuss-work}/references/discussion-continuity.md +10 -27
- package/skills/discuss-work/references/learning-action.md +36 -0
- package/skills/discuss-work/scripts/choices.mjs +101 -0
- package/skills/discuss-work/scripts/lib/choices.mjs +159 -0
- package/skills/evaluate-behavior/SKILL.md +107 -0
- package/skills/evaluate-behavior/references/authoring.md +381 -0
- package/skills/evaluate-behavior/references/coding-tasks.md +145 -0
- package/skills/evaluate-behavior/references/conversations-pipelines-judges.md +177 -0
- package/skills/evaluate-behavior/references/design-and-measurement.md +273 -0
- package/skills/evaluate-behavior/references/running-and-evidence.md +245 -0
- package/skills/evaluate-behavior/scripts/claude-guard.mjs +76 -0
- package/skills/evaluate-behavior/scripts/guard-rules.mjs +309 -0
- package/skills/evaluate-behavior/scripts/lib/agreement.mjs +90 -0
- package/skills/evaluate-behavior/scripts/lib/arms.mjs +55 -0
- package/skills/evaluate-behavior/scripts/lib/budget.mjs +87 -0
- package/skills/evaluate-behavior/scripts/lib/build-source.mjs +287 -0
- package/skills/evaluate-behavior/scripts/lib/clear.mjs +74 -0
- package/skills/evaluate-behavior/scripts/lib/container.mjs +395 -0
- package/skills/evaluate-behavior/scripts/lib/decision.mjs +418 -0
- package/skills/evaluate-behavior/scripts/lib/definitions.mjs +1072 -0
- package/skills/evaluate-behavior/scripts/lib/freeflow.mjs +103 -0
- package/skills/evaluate-behavior/scripts/lib/grade-command.mjs +591 -0
- package/skills/evaluate-behavior/scripts/lib/grade-comparison.mjs +90 -0
- package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/grade-interaction.mjs +19 -18
- package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/grade-support.mjs +32 -5
- package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/grade-workspace.mjs +28 -12
- package/skills/evaluate-behavior/scripts/lib/grade.mjs +101 -0
- package/skills/evaluate-behavior/scripts/lib/hooks.mjs +98 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/confinement.mjs +196 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/constraints.mjs +111 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/index.mjs +48 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/isolation.mjs +74 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/launch.mjs +123 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/model-call.mjs +73 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/recorder.mjs +178 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/session.mjs +494 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/skills.mjs +81 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/index.mjs +31 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/names.mjs +3 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/pi/confinement.mjs +173 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/pi/host.mjs +148 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/pi/index.mjs +70 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/pi/isolation.mjs +81 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/pi/model-call.mjs +79 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/pi/process.mjs +241 -0
- package/skills/{evaluate-skill/scripts/lib → evaluate-behavior/scripts/lib/hosts/pi}/rpc.mjs +144 -26
- package/skills/evaluate-behavior/scripts/lib/identity.mjs +82 -0
- package/skills/evaluate-behavior/scripts/lib/judge.mjs +688 -0
- package/skills/evaluate-behavior/scripts/lib/metrics.mjs +332 -0
- package/skills/evaluate-behavior/scripts/lib/model-call.mjs +17 -0
- package/skills/evaluate-behavior/scripts/lib/participants.mjs +616 -0
- package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/process.mjs +22 -0
- package/skills/evaluate-behavior/scripts/lib/queue.mjs +54 -0
- package/skills/evaluate-behavior/scripts/lib/reference.mjs +343 -0
- package/skills/evaluate-behavior/scripts/lib/reuse.mjs +277 -0
- package/skills/evaluate-behavior/scripts/lib/review.mjs +933 -0
- package/skills/evaluate-behavior/scripts/lib/runner.mjs +732 -0
- package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/sandbox.mjs +119 -14
- package/skills/evaluate-behavior/scripts/lib/scan-shell.mjs +457 -0
- package/skills/evaluate-behavior/scripts/lib/scan.mjs +479 -0
- package/skills/evaluate-behavior/scripts/lib/seal.mjs +91 -0
- package/skills/evaluate-behavior/scripts/lib/shell.mjs +560 -0
- package/skills/evaluate-behavior/scripts/lib/source-override.mjs +64 -0
- package/skills/evaluate-behavior/scripts/lib/subject-file.mjs +88 -0
- package/skills/{evaluate-skill/scripts/lib/pi.mjs → evaluate-behavior/scripts/lib/subject.mjs} +235 -265
- package/skills/evaluate-behavior/scripts/lib/task-copy.mjs +124 -0
- package/skills/evaluate-behavior/scripts/lib/trials.mjs +524 -0
- package/skills/evaluate-behavior/scripts/lib/validity.mjs +68 -0
- package/skills/evaluate-behavior/scripts/lib/view-html.mjs +454 -0
- package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/view.mjs +159 -18
- package/skills/{evaluate-skill → evaluate-behavior}/scripts/pi-command-tool.mjs +21 -6
- package/skills/evaluate-behavior/scripts/pi-container-route.mjs +23 -0
- package/skills/evaluate-behavior/scripts/pi-guard.mjs +77 -0
- package/skills/evaluate-behavior/scripts/pi-login-refresh.mjs +31 -0
- package/skills/evaluate-behavior/scripts/skill-eval.mjs +586 -0
- package/skills/execute-work/SKILL.md +96 -104
- package/skills/execute-work/references/code-practices.md +27 -51
- package/skills/execute-work/references/design.md +271 -0
- package/skills/execute-work/references/diagnose.md +117 -0
- package/skills/execute-work/references/migration.md +108 -0
- package/skills/execute-work/references/simplify.md +65 -0
- package/skills/execute-work/scripts/self-review.mjs +422 -0
- package/skills/execute-work/scripts/touch-map.mjs +290 -0
- package/skills/review-work/SKILL.md +89 -65
- package/skills/review-work/references/adjudication.md +94 -0
- package/skills/review-work/references/artifact.md +198 -0
- package/skills/review-work/references/evals-and-judges.md +66 -0
- package/skills/review-work/references/work.md +177 -0
- package/skills/review-work/scripts/check-brief.mjs +128 -0
- package/skills/review-work/scripts/review-packet.mjs +233 -0
- package/skills/setup-freeflow/SKILL.md +68 -17
- package/skills/track-work/SKILL.md +52 -20
- package/skills/track-work/references/handoff.md +190 -0
- package/skills/track-work/references/projects.md +51 -0
- package/skills/track-work/references/working-record-format.md +36 -18
- package/skills/track-work/scripts/lib/document.mjs +17 -13
- package/skills/track-work/scripts/lib/format.mjs +2 -0
- package/skills/track-work/scripts/lib/recover.mjs +254 -0
- package/skills/track-work/scripts/lib/registry.mjs +656 -0
- package/skills/track-work/scripts/lib/search.mjs +40 -0
- package/skills/track-work/scripts/lib/store.mjs +46 -15
- package/skills/track-work/scripts/lib/views.mjs +50 -1
- package/skills/track-work/scripts/working-record.mjs +232 -13
- package/skills/verify-work/SKILL.md +45 -37
- package/skills/verify-work/references/feature-map.md +120 -0
- package/skills/verify-work/references/runtime-evidence.md +203 -0
- package/skills/verify-work/references/test-design.md +25 -6
- package/skills/verify-work/scripts/test-changes.mjs +246 -0
- package/skills/write-docs/SKILL.md +113 -25
- package/skills/write-docs/references/documentation-shapes.md +68 -3
- package/skills/write-docs/references/spec-and-plan-shapes.md +308 -0
- package/skills/write-docs/scripts/artifact-check.mjs +148 -0
- package/skills/write-docs/scripts/docs-check.mjs +96 -6
- package/skills/write-docs/scripts/plan-lint.mjs +123 -0
- package/skills/write-skill/SKILL.md +92 -52
- package/skills/write-skill/references/activation-and-wording.md +143 -0
- package/skills/write-skill/references/placement-and-dependencies.md +154 -0
- package/skills/write-skill/scripts/lib/compare.mjs +701 -0
- package/skills/write-skill/scripts/lib/skill-author.mjs +197 -3
- package/skills/write-skill/scripts/skill-author.mjs +51 -8
- package/capabilities/cognitive-routing/references/both-mode.md +0 -36
- package/capabilities/cognitive-routing/references/executor-mode.md +0 -48
- package/capabilities/cognitive-routing/references/helper-mode.md +0 -47
- package/plugin.json +0 -33
- package/skills/action-selection/SKILL.md +0 -92
- package/skills/action-selection/references/trajectory-stalls.md +0 -73
- package/skills/bypass/SKILL.md +0 -153
- package/skills/commit-work/SKILL.md +0 -93
- package/skills/commit-work/references/git-state-edges.md +0 -94
- package/skills/commit-work/references/simple-push.md +0 -94
- package/skills/commit-work/references/staging-decisions.md +0 -106
- package/skills/decision-gate/SKILL.md +0 -87
- package/skills/design-for-depth/SKILL.md +0 -108
- package/skills/design-for-depth/references/design-pressure-signals.md +0 -84
- package/skills/design-for-depth/references/implementation-decisions.md +0 -76
- package/skills/design-for-depth/references/interface-design-loop.md +0 -105
- package/skills/design-for-depth/references/module-and-dependency-design.md +0 -117
- package/skills/design-for-depth/references/state-and-failure-boundaries.md +0 -125
- package/skills/diagnose-failure/SKILL.md +0 -140
- package/skills/diagnose-failure/references/diagnostic-loop-catalog.md +0 -50
- package/skills/diagnose-failure/references/flaky-and-performance-diagnosis.md +0 -51
- package/skills/discuss/SKILL.md +0 -140
- package/skills/evaluate-skill/SKILL.md +0 -188
- package/skills/evaluate-skill/references/evaluation-definition-schema.md +0 -415
- package/skills/evaluate-skill/references/evaluation-design.md +0 -112
- package/skills/evaluate-skill/references/execution-and-evidence.md +0 -111
- package/skills/evaluate-skill/references/review-and-revision.md +0 -94
- package/skills/evaluate-skill/scripts/lib/definitions.mjs +0 -448
- package/skills/evaluate-skill/scripts/lib/grade-comparison.mjs +0 -60
- package/skills/evaluate-skill/scripts/lib/grade.mjs +0 -64
- package/skills/evaluate-skill/scripts/lib/review.mjs +0 -196
- package/skills/evaluate-skill/scripts/lib/runner.mjs +0 -405
- package/skills/evaluate-skill/scripts/lib/trials.mjs +0 -103
- package/skills/evaluate-skill/scripts/pi-guard.mjs +0 -181
- package/skills/evaluate-skill/scripts/skill-eval.mjs +0 -182
- package/skills/execute-work/references/execute-work-edges.md +0 -78
- package/skills/finish-branch/SKILL.md +0 -117
- package/skills/finish-branch/references/integration-options.md +0 -80
- package/skills/handoff/SKILL.md +0 -82
- package/skills/handoff/references/handoff-templates.md +0 -150
- package/skills/launch-work/SKILL.md +0 -116
- package/skills/launch-work/references/launch-readiness.md +0 -85
- package/skills/migration-work/SKILL.md +0 -115
- package/skills/migration-work/references/migration-lifecycle.md +0 -82
- package/skills/release-work/SKILL.md +0 -118
- package/skills/release-work/references/release-evidence.md +0 -78
- package/skills/review-artifact/SKILL.md +0 -143
- package/skills/review-artifact/references/adjudicate-artifact-review.md +0 -101
- package/skills/review-artifact/references/independent-artifact-reviewer-contract.md +0 -159
- package/skills/review-work/references/adjudicate-work-review.md +0 -97
- package/skills/review-work/references/independent-work-reviewer-contract.md +0 -139
- package/skills/review-work/references/security-risk-lens.md +0 -67
- package/skills/setup-freeflow/references/activation-contract.md +0 -103
- package/skills/setup-freeflow/references/host-setup.md +0 -67
- package/skills/simplify-code/SKILL.md +0 -85
- package/skills/simplify-code/references/simplification-patterns.md +0 -70
- package/skills/verify-work/references/browser-runtime-evidence.md +0 -51
- package/skills/verify-work/references/integration-evidence.md +0 -49
- package/skills/verify-work/references/performance-evidence.md +0 -59
- package/skills/workflow/SKILL.md +0 -171
- package/skills/workflow/references/domain-skill-composition.md +0 -45
- package/skills/write-plan/SKILL.md +0 -92
- package/skills/write-plan/references/plan-shapes.md +0 -156
- package/skills/write-skill/references/activation-boundaries.md +0 -106
- package/skills/write-skill/references/agent-first-instructions.md +0 -133
- package/skills/write-skill/references/progressive-disclosure.md +0 -129
- package/skills/write-skill/references/skill-dependency-graphs.md +0 -192
- package/skills/write-spec/SKILL.md +0 -85
- package/skills/write-spec/references/artifact-standards.md +0 -86
- package/skills/write-spec/references/decision-records.md +0 -80
- package/skills/write-spec/references/spec-shapes.md +0 -143
- /package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/evidence.mjs +0 -0
- /package/skills/{evaluate-skill → evaluate-behavior}/scripts/pi-observer.mjs +0 -0
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { dirname, isAbsolute, join, relative } from "node:path";
|
|
5
|
+
import { parseDocument, sectionContentLines } from "./document.mjs";
|
|
6
|
+
import { renderResume } from "./views.mjs";
|
|
7
|
+
|
|
8
|
+
// Recovery in one call (Track Work, "Recover After Context Loss"): the resume view, then what each defining artifact
|
|
9
|
+
// and Recovery source points to and whether it can be read now, then where live Git state disagrees with the record.
|
|
10
|
+
// It reports; reading the sources and reconciling stays the agent's work.
|
|
11
|
+
//
|
|
12
|
+
// It also finds the evidence pointers in Material updates for `validate`: files and commits a later context will
|
|
13
|
+
// rely on. A pointer inside the repository that does not resolve is a problem; one outside it is reported, not checked.
|
|
14
|
+
|
|
15
|
+
const PATH_TOKEN = /^(~\/|\/|\.{1,2}\/)?[A-Za-z0-9_@.-]+(\/[A-Za-z0-9_@.()-]+)*\/?(#[^\s]*)?$/;
|
|
16
|
+
const COMMIT = /^[0-9a-f]{7,40}$/;
|
|
17
|
+
const URL = /^[a-z][a-z0-9+.-]*:\/\//i;
|
|
18
|
+
|
|
19
|
+
function git(root, args) {
|
|
20
|
+
try {
|
|
21
|
+
return execFileSync("git", args, { cwd: root, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
22
|
+
} catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// A path names a file with an extension, a directory with a trailing "/", or starts like one (./, ../, ~/, /). Slashed
|
|
28
|
+
// words such as "lost/weakened" or "17/9" are not paths.
|
|
29
|
+
const looksLikePath = (token) =>
|
|
30
|
+
PATH_TOKEN.test(token) &&
|
|
31
|
+
!COMMIT.test(token) &&
|
|
32
|
+
!token.includes("*") &&
|
|
33
|
+
(/^(~\/|\/|\.{1,2}\/)/.test(token) ||
|
|
34
|
+
/\/$/.test(token) ||
|
|
35
|
+
(/\.[A-Za-z][A-Za-z0-9]{0,7}(#.*)?$/.test(token) && (token.includes("/") || /^[^.]+\.[A-Za-z]/.test(token))));
|
|
36
|
+
const looksLikeCommit = (token) => COMMIT.test(token) && /\d/.test(token) && /[a-f]/.test(token);
|
|
37
|
+
|
|
38
|
+
// The pointers a line names: backticked tokens, Markdown link targets, a leading "pointer — ..." token, typed
|
|
39
|
+
// trail pointers (commit:<sha>, file:<path>), and bare commit hashes.
|
|
40
|
+
export function pointersIn(line) {
|
|
41
|
+
const found = [];
|
|
42
|
+
const add = (kind, value) => {
|
|
43
|
+
if (!found.some((each) => each.kind === kind && each.value === value)) found.push({ kind, value });
|
|
44
|
+
};
|
|
45
|
+
const text = line.replace(/^\s*[-*]\s+/, "");
|
|
46
|
+
for (const match of text.matchAll(/\]\(([^)\s]+)\)/g)) classify(match[1], add);
|
|
47
|
+
for (const match of text.matchAll(/`([^`\n]+)`/g)) classify(match[1].trim(), add);
|
|
48
|
+
const lead = /^(\S+)\s+[—–-]\s/.exec(text);
|
|
49
|
+
if (lead) classify(lead[1].replace(/[,;:]$/, ""), add);
|
|
50
|
+
const prose = text.replace(/`[^`\n]*`/g, " ").replace(/\]\([^)]*\)/g, " ");
|
|
51
|
+
for (const match of prose.matchAll(/\b(?:commit|file|path):([^\s,;)]+)/g))
|
|
52
|
+
classify(match[1], add, match[0].startsWith("commit:"));
|
|
53
|
+
for (const word of prose.split(/[\s,;()[\]"'“”]+/)) {
|
|
54
|
+
const token = word.replace(/[.:]+$/, "");
|
|
55
|
+
if (looksLikeCommit(token)) add("commit", token);
|
|
56
|
+
// A bare path in prose must name a file: a slashed word ending in "/" is usually a folder named in passing.
|
|
57
|
+
else if (token.includes("/") && !token.endsWith("/") && looksLikePath(token) && !URL.test(token))
|
|
58
|
+
add("path", token.replace(/#.*$/, ""));
|
|
59
|
+
}
|
|
60
|
+
return found;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function classify(raw, add, commitOnly = false) {
|
|
64
|
+
const token = raw.replace(/^(file|path|commit):/, "");
|
|
65
|
+
if (URL.test(token)) return add("url", token);
|
|
66
|
+
if (commitOnly || looksLikeCommit(token)) return add("commit", token);
|
|
67
|
+
const range = /^([0-9a-f]{7,40})\.\.\.?([0-9a-f]{7,40}|HEAD)$/.exec(token);
|
|
68
|
+
if (range) {
|
|
69
|
+
add("commit", range[1]);
|
|
70
|
+
if (range[2] !== "HEAD") add("commit", range[2]);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (looksLikePath(token)) add("path", token.replace(/#.*$/, ""));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Where a path pointer resolves: the repository root, the task folder, or as given when absolute or home-relative.
|
|
77
|
+
export function resolvePointer(pointer, { root, taskDir }) {
|
|
78
|
+
if (pointer.startsWith("~/")) return { outside: true, path: join(homedir(), pointer.slice(2)) };
|
|
79
|
+
if (isAbsolute(pointer)) {
|
|
80
|
+
const inside = !relative(root, pointer).startsWith("..");
|
|
81
|
+
return { outside: !inside, path: pointer };
|
|
82
|
+
}
|
|
83
|
+
const candidates = [join(taskDir, pointer), join(root, pointer)];
|
|
84
|
+
const hit = candidates.find((candidate) => existsSync(candidate));
|
|
85
|
+
return { outside: false, path: hit ?? candidates[1] };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function describe(path) {
|
|
89
|
+
try {
|
|
90
|
+
const stat = statSync(path);
|
|
91
|
+
if (stat.isDirectory()) return `directory, ${readdirSync(path).length} entries`;
|
|
92
|
+
const text = readFileSync(path, "utf8");
|
|
93
|
+
return `${text.split("\n").length} lines, ${text.split(/\s+/).filter(Boolean).length} words`;
|
|
94
|
+
} catch {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function checkPointer(pointer, context) {
|
|
100
|
+
if (pointer.kind === "url") return { ...pointer, state: "not checked (URL)" };
|
|
101
|
+
if (pointer.kind === "commit") {
|
|
102
|
+
if (!context.isGit) return { ...pointer, state: "not checked (not a Git repository)" };
|
|
103
|
+
const full = git(context.root, ["rev-parse", "--verify", "--quiet", `${pointer.value}^{commit}`]);
|
|
104
|
+
return full
|
|
105
|
+
? { ...pointer, state: "resolves", commit: full }
|
|
106
|
+
: { ...pointer, state: "missing", problem: `commit ${pointer.value} is not in this repository` };
|
|
107
|
+
}
|
|
108
|
+
const where = resolvePointer(pointer.value, context);
|
|
109
|
+
const size = describe(where.path);
|
|
110
|
+
if (size) return { ...pointer, state: "resolves", size, ...(where.outside ? { outside: true } : {}) };
|
|
111
|
+
if (where.outside) return { ...pointer, state: "not checked (outside the repository)", outside: true };
|
|
112
|
+
return { ...pointer, state: "missing", problem: `${pointer.value} does not exist` };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const bullets = (lines) => lines.filter((line) => /^\s*[-*]\s+\S/.test(line));
|
|
116
|
+
|
|
117
|
+
function sourceEntries(lines, context) {
|
|
118
|
+
return bullets(lines).map((line) => {
|
|
119
|
+
const text = line.trim().replace(/^[-*]\s+/, "");
|
|
120
|
+
const trigger = /\bread (?:only )?(?:when|if) ([^.;]+)/i.exec(text)?.[1]?.trim() ?? null;
|
|
121
|
+
return { text, trigger, pointers: pointersIn(line).map((pointer) => checkPointer(pointer, context)) };
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function liveState(document, context) {
|
|
126
|
+
const { root } = context;
|
|
127
|
+
if (!context.isGit) return { git: false, mismatches: [], notes: ["not a Git repository: no live state to compare"] };
|
|
128
|
+
const branch = git(root, ["branch", "--show-current"]) || null;
|
|
129
|
+
const head = git(root, ["rev-parse", "--short=12", "HEAD"]);
|
|
130
|
+
const subject = head ? git(root, ["log", "-1", "--format=%s"]) : null;
|
|
131
|
+
const dirty = (git(root, ["status", "--porcelain"]) ?? "").split("\n").filter(Boolean).length;
|
|
132
|
+
const mismatches = [];
|
|
133
|
+
const notes = [];
|
|
134
|
+
const current = document.sections["Current Work"];
|
|
135
|
+
const sliceText = current ? document.lines.slice(current.start, current.end).join("\n") : "";
|
|
136
|
+
const contextText = sectionContentLines(document, "Current Context").join("\n");
|
|
137
|
+
const branches = (git(root, ["for-each-ref", "--format=%(refname:short)", "refs/heads"]) ?? "")
|
|
138
|
+
.split("\n")
|
|
139
|
+
.filter(Boolean);
|
|
140
|
+
const named = branches.filter((name) =>
|
|
141
|
+
new RegExp(`(^|[\\s\`(])${name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}([\\s\`),.;:]|$)`).test(
|
|
142
|
+
`${sliceText}\n${contextText}`,
|
|
143
|
+
),
|
|
144
|
+
);
|
|
145
|
+
if (!branch) mismatches.push(`HEAD is detached at ${head}`);
|
|
146
|
+
else if (named.length && !named.includes(branch))
|
|
147
|
+
mismatches.push(`the record names branch ${named.join(", ")}; HEAD is on ${branch}`);
|
|
148
|
+
const commits = [...new Set(pointersIn(sliceText.replace(/\n/g, " ")).filter((each) => each.kind === "commit"))];
|
|
149
|
+
for (const { value } of commits) {
|
|
150
|
+
const full = git(root, ["rev-parse", "--verify", "--quiet", `${value}^{commit}`]);
|
|
151
|
+
if (!full) mismatches.push(`the Current Slice names commit ${value}, which this repository does not have`);
|
|
152
|
+
else if (head && git(root, ["merge-base", "--is-ancestor", full, "HEAD"]) === null)
|
|
153
|
+
mismatches.push(`the Current Slice names commit ${value}, which is not in HEAD's history`);
|
|
154
|
+
}
|
|
155
|
+
const updated = /^Last updated:\s*(\S+)/m.exec(document.lines.slice(0, 10).join("\n"))?.[1];
|
|
156
|
+
if (updated && head) {
|
|
157
|
+
const since = (git(root, ["log", "--oneline", `--since=${updated}`, "HEAD"]) ?? "").split("\n").filter(Boolean);
|
|
158
|
+
if (since.length)
|
|
159
|
+
notes.push(
|
|
160
|
+
`${since.length} commit(s) on HEAD since the record's Last updated (${updated}); it may not describe them`,
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
if (dirty) notes.push(`${dirty} uncommitted or untracked path(s)`);
|
|
164
|
+
return { git: true, branch, head, subject, dirty, namedBranches: named, mismatches, notes };
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function contextFor(root, recordPath) {
|
|
168
|
+
return {
|
|
169
|
+
root,
|
|
170
|
+
taskDir: dirname(recordPath),
|
|
171
|
+
isGit: git(root, ["rev-parse", "--is-inside-work-tree"]) === "true",
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function gitRoot(root) {
|
|
176
|
+
return git(root, ["rev-parse", "--show-toplevel"]) ?? root;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export function renderRecover(text, { root, recordPath }) {
|
|
180
|
+
const document = parseDocument(text);
|
|
181
|
+
const context = contextFor(gitRoot(root), recordPath);
|
|
182
|
+
const defines = document.context.headings.get("What defines this task");
|
|
183
|
+
const defining = sourceEntries(document.lines.slice(defines.start, defines.end), context);
|
|
184
|
+
const sources = document.current.recoverySources;
|
|
185
|
+
const recovery = sources ? sourceEntries(document.lines.slice(sources.start, sources.end), context) : [];
|
|
186
|
+
const live = liveState(document, context);
|
|
187
|
+
const pointerLine = (pointer) =>
|
|
188
|
+
`${pointer.value}: ${pointer.state}${pointer.size ? ` (${pointer.size})` : ""}${pointer.outside && pointer.size ? ", outside the repository" : ""}`;
|
|
189
|
+
const entryLines = (entries, withTrigger) =>
|
|
190
|
+
entries.length
|
|
191
|
+
? entries.flatMap((entry) => [
|
|
192
|
+
`- ${entry.text}`,
|
|
193
|
+
...(withTrigger ? [` - ${entry.trigger ? `read when ${entry.trigger}` : "read now"}`] : []),
|
|
194
|
+
...(entry.pointers.length
|
|
195
|
+
? entry.pointers.map((pointer) => ` - ${pointerLine(pointer)}`)
|
|
196
|
+
: [" - no pointer found: recover it from the text"]),
|
|
197
|
+
])
|
|
198
|
+
: ["None."];
|
|
199
|
+
const lines = [
|
|
200
|
+
"## Recovery",
|
|
201
|
+
"",
|
|
202
|
+
"Read in this order: every defining artifact, then each Recovery source whose trigger applies, then the History entries the next action depends on (`view entry <ID>`).",
|
|
203
|
+
"",
|
|
204
|
+
"### Defining artifacts",
|
|
205
|
+
"",
|
|
206
|
+
...entryLines(defining, false),
|
|
207
|
+
"",
|
|
208
|
+
"### Recovery sources",
|
|
209
|
+
"",
|
|
210
|
+
...entryLines(recovery, true),
|
|
211
|
+
"",
|
|
212
|
+
"### Live state",
|
|
213
|
+
"",
|
|
214
|
+
...(live.git
|
|
215
|
+
? [
|
|
216
|
+
`- ${live.branch ? `branch ${live.branch}` : "detached HEAD"}, HEAD ${live.head ?? "none"}${live.subject ? ` (${live.subject})` : ""}`,
|
|
217
|
+
]
|
|
218
|
+
: []),
|
|
219
|
+
...live.notes.map((note) => `- ${note}`),
|
|
220
|
+
...(live.mismatches.length
|
|
221
|
+
? ["", "Mismatches: resolve each from sources before acting.", ...live.mismatches.map((each) => `- ${each}`)]
|
|
222
|
+
: ["- no mismatch found between the record and live Git state"]),
|
|
223
|
+
];
|
|
224
|
+
const resume = renderResume(text);
|
|
225
|
+
return `${resume.trimEnd()}${document.newline}${document.newline}${lines.join(document.newline)}${document.newline}`;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Evidence pointers in every Material updates list. An unresolved pointer inside the repository is a problem on an
|
|
229
|
+
// Evidence or Result line, which claims it exists, and a warning on any other line (an Extension may name a planned
|
|
230
|
+
// path); the caller decides whether problems fail. Pointers outside the repository are listed, not checked.
|
|
231
|
+
export function checkEvidencePointers(text, { root, recordPath }) {
|
|
232
|
+
const document = parseDocument(text);
|
|
233
|
+
const context = contextFor(gitRoot(root), recordPath);
|
|
234
|
+
const lines = document.lines;
|
|
235
|
+
const problems = [];
|
|
236
|
+
const warnings = [];
|
|
237
|
+
const outside = [];
|
|
238
|
+
let checked = 0;
|
|
239
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
240
|
+
if (!/^#####\s+Material updates\s*$/.test(lines[index])) continue;
|
|
241
|
+
for (let at = index + 1; at < lines.length && !/^#{1,5}\s/.test(lines[at]); at += 1) {
|
|
242
|
+
for (const pointer of pointersIn(lines[at])) {
|
|
243
|
+
if (pointer.kind === "url") continue;
|
|
244
|
+
const result = checkPointer(pointer, context);
|
|
245
|
+
const claims = /^\s*[-*]\s+(Evidence|Result)\b/.test(lines[at]);
|
|
246
|
+
if (result.problem) (claims ? problems : warnings).push(`line ${at + 1}: ${result.problem}`);
|
|
247
|
+
else if (result.outside || result.state.startsWith("not checked"))
|
|
248
|
+
outside.push(`line ${at + 1}: ${pointer.value}`);
|
|
249
|
+
if (!result.outside && !result.state.startsWith("not checked")) checked += 1;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return { checked, problems, warnings, outside };
|
|
254
|
+
}
|