devflow-kit 3.7.0 → 3.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/CHANGELOG.md +479 -1
- package/README.md +15 -15
- package/dist/agents/code.md +6 -8
- package/dist/agents/design.md +1 -1
- package/dist/agents/fix.md +7 -8
- package/dist/agents/git.md +3 -3
- package/dist/agents/harden.md +1 -1
- package/dist/agents/refactor.md +2 -4
- package/dist/agents/review.md +4 -4
- package/dist/agents/skim.md +2 -2
- package/dist/agents/triage.md +9 -2
- package/dist/cli/commands/capture.js +1 -1
- package/dist/cli/commands/curation-move-io.js +102 -0
- package/dist/cli/commands/curation-move-step.js +374 -0
- package/dist/cli/commands/curation.js +808 -0
- package/dist/cli/commands/gate-level-prompts.js +428 -0
- package/dist/cli/commands/gates.js +35 -11
- package/dist/cli/commands/init-seed.js +11 -8
- package/dist/cli/commands/init.js +244 -57
- package/dist/cli/commands/memory.js +60 -13
- package/dist/cli/commands/prompt-io.js +37 -0
- package/dist/cli/commands/uninstall.js +157 -17
- package/dist/cli.js +2 -2
- package/dist/commands/bug-analysis.md +25 -36
- package/dist/commands/code-review.md +40 -44
- package/dist/commands/debug.md +5 -5
- package/dist/commands/dynamic-build.md +26 -25
- package/dist/commands/dynamic-plan.md +5 -5
- package/dist/commands/dynamic-profile.md +5 -5
- package/dist/commands/dynamic-tickets.md +5 -5
- package/dist/commands/explore.md +6 -6
- package/dist/commands/implement.md +53 -82
- package/dist/commands/plan.md +6 -6
- package/dist/commands/release.md +5 -5
- package/dist/commands/research.md +6 -6
- package/dist/commands/resolve.md +39 -41
- package/dist/commands/self-review.md +5 -13
- package/dist/core/area-pause-notice.js +44 -0
- package/dist/core/assets.js +20 -20
- package/dist/core/curate-tuning-config.js +5 -6
- package/dist/core/curation-move-notice.js +84 -0
- package/dist/core/curation-move-skip.js +35 -0
- package/dist/core/curation-move.js +35 -0
- package/dist/core/curation-queue-cleanup.js +135 -0
- package/dist/core/curation-store.js +99 -0
- package/dist/core/{learning-variants.js → curation-variants.js} +65 -41
- package/dist/core/echo-value.js +11 -5
- package/dist/core/evidence-policy.js +11 -9
- package/dist/core/feature-switch.js +95 -19
- package/dist/core/fs-atomic.js +1 -1
- package/dist/core/gate-level.js +10 -2
- package/dist/core/git.js +16 -14
- package/dist/core/ledger-root.js +82 -22
- package/dist/core/linked-path.js +4 -4
- package/dist/core/manifest-lock.js +238 -0
- package/dist/core/manifest.js +58 -14
- package/dist/core/migrations.js +1 -13
- package/dist/core/observations.js +2 -2
- package/dist/core/plugins.js +19 -19
- package/dist/core/pool.js +26 -0
- package/dist/core/project-paths.js +103 -34
- package/dist/core/queue-drain.js +2 -2
- package/dist/core/tracked-areas.js +159 -0
- package/dist/core/tracker.js +1 -1
- package/dist/{learning-off → curation-off}/agents/code.md +6 -8
- package/dist/{learning-off → curation-off}/agents/fix.md +7 -8
- package/dist/{learning-off → curation-off}/agents/refactor.md +2 -4
- package/dist/{learning-off → curation-off}/agents/review.md +3 -3
- package/dist/{learning-off → curation-off}/agents/triage.md +8 -1
- package/dist/{learning-off → curation-off}/commands/bug-analysis.md +20 -31
- package/dist/{learning-off → curation-off}/commands/code-review.md +37 -41
- package/dist/{learning-off → curation-off}/commands/debug.md +2 -2
- package/dist/{learning-off → curation-off}/commands/dynamic-build.md +23 -22
- package/dist/{learning-off → curation-off}/commands/explore.md +2 -2
- package/dist/{learning-off → curation-off}/commands/implement.md +50 -79
- package/dist/{learning-off → curation-off}/commands/plan.md +2 -2
- package/dist/{learning-off → curation-off}/commands/resolve.md +36 -38
- package/dist/{learning-off → curation-off}/commands/self-review.md +2 -10
- package/dist/hud/components/{learning-counts.js → curation-counts.js} +63 -17
- package/dist/hud/config.js +1 -1
- package/dist/hud/index.js +6 -6
- package/dist/hud/render.js +3 -3
- package/dist/skills/git/references/pr/post-resolution-summary.md +12 -11
- package/dist/skills/git/references/pr/post-review-summary.md +12 -11
- package/dist/skills/git/references/pr/update-pr-evidence.md +2 -2
- package/dist/skills/git/references/pr/validate-branch.md +8 -5
- package/dist/skills/git/references/publication-gate.md +6 -7
- package/dist/skills/git/references/tracker/github/ensure-pr-ready.md +13 -5
- package/dist/skills/git/references/tracker/github/manage-debt.md +6 -2
- package/dist/skills/git/references/tracker/jira/ensure-pr-ready.md +13 -5
- package/dist/skills/git/references/tracker/jira/manage-debt.md +6 -2
- package/dist/skills/git/references/tracker/linear/ensure-pr-ready.md +13 -5
- package/dist/skills/git/references/tracker/linear/manage-debt.md +6 -2
- package/dist/targets/claude-code/{learning-install.js → curation-install.js} +85 -65
- package/dist/targets/claude-code/installer.js +15 -15
- package/dist/targets/claude-code/language-stamp.js +5 -5
- package/dist/targets/claude-code/post-install.js +2 -2
- package/dist/targets/claude-code/tracker-servers.js +1 -1
- package/package.json +3 -2
- package/src/assets/agents/_partials/_code.mds +11 -11
- package/src/assets/agents/code.mds +6 -6
- package/src/assets/agents/curate.md +8 -8
- package/src/assets/agents/debug.mds +6 -6
- package/src/assets/agents/design.mds +18 -18
- package/src/assets/agents/evaluate.md +6 -12
- package/src/assets/agents/fix.mds +7 -6
- package/src/assets/agents/git.mds +3 -3
- package/src/assets/agents/harden.mds +7 -7
- package/src/assets/agents/knowledge.mds +23 -23
- package/src/assets/agents/refactor.mds +2 -2
- package/src/assets/agents/research.mds +15 -15
- package/src/assets/agents/review.mds +43 -43
- package/src/assets/agents/skim.mds +11 -11
- package/src/assets/agents/triage.mds +29 -22
- package/src/assets/agents/validate.md +30 -50
- package/src/assets/commands/_partials/_decisions.mds +22 -20
- package/src/assets/commands/_partials/_engine.mds +8 -8
- package/src/assets/commands/_partials/_knowledge.mds +29 -15
- package/src/assets/commands/_partials/_preamble.mds +4 -4
- package/src/assets/commands/_partials/_settings.mds +3 -3
- package/src/assets/commands/_partials/_wave.mds +7 -7
- package/src/assets/commands/bug-analysis.mds +37 -48
- package/src/assets/commands/code-review.mds +53 -57
- package/src/assets/commands/debug.mds +14 -14
- package/src/assets/commands/dynamic-build.mds +38 -37
- package/src/assets/commands/dynamic-plan.mds +22 -22
- package/src/assets/commands/dynamic-profile.mds +2 -2
- package/src/assets/commands/dynamic-tickets.mds +8 -8
- package/src/assets/commands/explore.mds +20 -20
- package/src/assets/commands/implement.mds +77 -98
- package/src/assets/commands/plan.mds +27 -27
- package/src/assets/commands/release.mds +12 -12
- package/src/assets/commands/research.mds +19 -19
- package/src/assets/commands/resolve.mds +66 -60
- package/src/assets/commands/self-review.mds +20 -20
- package/src/assets/mds/git/_ops.mds +9 -2
- package/src/assets/mds/git/_ops_pr.mds +21 -11
- package/src/assets/mds/git/_ops_steps.mds +20 -4
- package/src/assets/mds/git/_pr.mds +21 -18
- package/src/assets/mds/git/_references.mds +6 -7
- package/src/assets/mds/tracker/_github.mds +1 -4
- package/src/assets/mds/tracker/_jira.mds +1 -4
- package/src/assets/mds/tracker/_linear.mds +1 -4
- package/src/assets/rules/quality.md +1 -0
- package/src/assets/scripts/ci-wait.cjs +389 -92
- package/src/assets/scripts/hooks/background-memory-update +81 -3
- package/src/assets/scripts/hooks/capture-prompt +12 -12
- package/src/assets/scripts/hooks/capture-question +11 -11
- package/src/assets/scripts/hooks/capture-turn +12 -12
- package/src/assets/scripts/hooks/{learning-lock → curation-lock} +2 -2
- package/src/assets/scripts/hooks/curation-move +293 -0
- package/src/assets/scripts/hooks/ensure-devflow-init +45 -13
- package/src/assets/scripts/hooks/ensure-proxy +4 -4
- package/src/assets/scripts/hooks/ensure-root-gitignore +4 -4
- package/src/assets/scripts/hooks/git-marker +81 -0
- package/src/assets/scripts/hooks/json-helper.cjs +176 -51
- package/src/assets/scripts/hooks/json-parse +1 -1
- package/src/assets/scripts/hooks/lib/curation-move.cjs +1582 -0
- package/src/assets/scripts/hooks/lib/{learning-store.cjs → curation-store.cjs} +308 -122
- package/src/assets/scripts/hooks/lib/decisions-format.cjs +3 -3
- package/src/assets/scripts/hooks/lib/mkdir-lock.cjs +24 -7
- package/src/assets/scripts/hooks/lib/project-paths.cjs +132 -39
- package/src/assets/scripts/hooks/lib/render-decisions.cjs +42 -22
- package/src/assets/scripts/hooks/lib/tracked-areas.cjs +452 -0
- package/src/assets/scripts/hooks/memory-permission +10 -2
- package/src/assets/scripts/hooks/memory-worker +12 -1
- package/src/assets/scripts/hooks/pre-compact-memory +17 -16
- package/src/assets/scripts/hooks/queue-append +444 -102
- package/src/assets/scripts/hooks/resolve-project-root +2 -2
- package/src/assets/scripts/hooks/session-start-context +198 -72
- package/src/assets/scripts/hooks/session-start-memory +42 -43
- package/src/assets/scripts/lib/project-config.cjs +12 -5
- package/src/assets/scripts/pr-evidence.cjs +5 -2
- package/src/assets/scripts/resolve-base.cjs +1043 -0
- package/src/assets/scripts/resolve-settings.cjs +283 -45
- package/src/assets/scripts/verify-evidence.cjs +307 -75
- package/src/assets/skills/agent-references/SKILL.md +11 -2
- package/src/assets/skills/agent-references/references/commands/implement-levels.md +29 -0
- package/src/assets/skills/agent-references/references/commands/implement-revalidate.md +6 -4
- package/src/assets/skills/agent-references/references/commands/resolve-levels.md +25 -0
- package/src/assets/skills/agent-references/references/synthesize/review.md +4 -4
- package/src/assets/skills/agent-references/references/triage/severity-tiers.md +43 -0
- package/src/assets/skills/agent-references/references/validate/passed-alone.md +14 -0
- package/src/assets/skills/apply-decisions/SKILL.md +1 -1
- package/src/assets/skills/docs-framework/SKILL.md +7 -7
- package/src/assets/skills/docs-framework/references/patterns.md +3 -4
- package/src/assets/skills/quality-gates/SKILL.md +1 -1
- package/src/assets/skills/worktree-support/references/roots.md +2 -2
- package/templates/lint-pack/.lint-pack.conf +86 -0
- package/templates/lint-pack/README.md +190 -0
- package/templates/lint-pack/lint-pack.sh +905 -0
- package/dist/cli/commands/learning.js +0 -554
- package/dist/core/learning-queue-cleanup.js +0 -27
- package/dist/core/learning-store.js +0 -61
- /package/dist/{learning-off → curation-off}/agents/debug.md +0 -0
- /package/dist/{learning-off → curation-off}/agents/design.md +0 -0
- /package/dist/{learning-off → curation-off}/agents/harden.md +0 -0
- /package/dist/{learning-off → curation-off}/agents/knowledge.md +0 -0
- /package/dist/{learning-off → curation-off}/agents/research.md +0 -0
- /package/dist/{learning-off → curation-off}/agents/skim.md +0 -0
- /package/dist/{learning-off → curation-off}/commands/dynamic-plan.md +0 -0
- /package/dist/{learning-off → curation-off}/commands/dynamic-profile.md +0 -0
- /package/dist/{learning-off → curation-off}/commands/dynamic-tickets.md +0 -0
- /package/dist/{learning-off → curation-off}/commands/release.md +0 -0
- /package/dist/{learning-off → curation-off}/commands/research.md +0 -0
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
# root, mirroring the TS CLI's getGitRoot() (src/core/git.ts) so the shell
|
|
9
9
|
# side anchors identically.
|
|
10
10
|
#
|
|
11
|
-
# Sourced by: the memory/
|
|
11
|
+
# Sourced by: the memory/curation/session hooks and ensure-devflow-init.
|
|
12
12
|
# Sourced helper: uses `return`-free pure functions; _-prefixed locals (never
|
|
13
13
|
# clobbers caller vars). Safe under `set -e` (git failure is guarded with || true).
|
|
14
14
|
#
|
|
@@ -53,7 +53,7 @@ _df_nongit_root() {
|
|
|
53
53
|
# df_resolve_roots <cwd> sets TWO roots in the caller's scope, from ONE git call:
|
|
54
54
|
# DF_ROOT — the checkout's toplevel: where per-checkout data lives
|
|
55
55
|
# (memory, the .gitignore carve-out, the knowledge bases).
|
|
56
|
-
# DF_LEDGER_ROOT — where the
|
|
56
|
+
# DF_LEDGER_ROOT — where the curation ledger and its queue live.
|
|
57
57
|
#
|
|
58
58
|
# D-LEDGER-MAIN-WORKTREE: a linked worktree (`git worktree add`, `claude
|
|
59
59
|
# --worktree`) has its own toplevel, so a ledger anchored there restarts its
|
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
|
|
3
3
|
# SessionStart Hook: Cross-Feature Context Injection
|
|
4
|
-
# Always-on hook that injects
|
|
5
|
-
# 1–2 are gated by the `features.
|
|
4
|
+
# Always-on hook that injects curation context as additionalContext. Sections
|
|
5
|
+
# 1–2 are gated by the `features.curation` switch in ~/.devflow/manifest.json,
|
|
6
6
|
# which this checkout's project.json / config.json can only narrow
|
|
7
7
|
# (D-FEATURES-NARROW-ONLY) — this hook itself is never disabled. They and the .gitignore carve-out run only in a git project that is
|
|
8
|
-
# not the home directory (D-HOOKS-GIT-ONLY), and they read the
|
|
9
|
-
# the main worktree when this is a linked one (D-LEDGER-MAIN-WORKTREE).
|
|
8
|
+
# not the home directory (D-HOOKS-GIT-ONLY), and they read the curation ledger of
|
|
9
|
+
# the main worktree when this is a linked one (D-LEDGER-MAIN-WORKTREE). They are also
|
|
10
|
+
# paused while git tracks files in a curation data folder of that ledger root, or does
|
|
11
|
+
# not answer: the hook then reads no curation file and makes no curation folder, and one
|
|
12
|
+
# fixed notice goes to the user as a systemMessage (Section 4b).
|
|
10
13
|
#
|
|
11
14
|
# Section 1: Project decisions TL;DR (decisions.md / pitfalls.md header lines),
|
|
12
15
|
# then the path of the decisions index when it lists entries.
|
|
13
|
-
# Section 2:
|
|
14
|
-
# the
|
|
16
|
+
# Section 2: Curation maintenance directive — when captured turns are pending in
|
|
17
|
+
# the curation queue (or a crashed run left a stale .processing batch), instructs
|
|
15
18
|
# the main model to spawn the background Curate agent with the resolved model.
|
|
16
19
|
# The agent claims the queue itself and queue emptiness is the natural gate,
|
|
17
20
|
# so there is no throttle here.
|
|
@@ -23,6 +26,12 @@
|
|
|
23
26
|
# Section 4: Legacy install notice — one line when this repository still carries
|
|
24
27
|
# a retired project-local devflow install (its .claude/settings.json registers
|
|
25
28
|
# devflow hooks), pointing at `devflow uninstall --scope local`.
|
|
29
|
+
# Section 4b: Curation pause notice — one fixed systemMessage when curation is on and
|
|
30
|
+
# git tracks files in a curation data folder (`tracked`) or did not answer (`unknown`).
|
|
31
|
+
# The answer is the skipped move's (the `curation-move` shim sets DF_CURATION_MOVE_SKIPPED)
|
|
32
|
+
# or, when the move was not skipped, the curation area check's own fresh answer; on a
|
|
33
|
+
# session that starts, resumes or is cleared the message tells the user why curation is
|
|
34
|
+
# paused.
|
|
26
35
|
# Section 5: Compaction resume directive — on a `compact` SessionStart, one fixed
|
|
27
36
|
# line telling the model to re-read the devflow command it was running from the
|
|
28
37
|
# phase in progress (D-COMPACT-RESUME-DIRECTIVE).
|
|
@@ -48,6 +57,12 @@
|
|
|
48
57
|
# - Section 6, changed start: ONE node process (claude-md-audit.cjs), and a
|
|
49
58
|
# sibling temp file renamed over the stamp. When none of the roots exists there
|
|
50
59
|
# is nothing to audit: the stamp is written with builtins, and node is not started.
|
|
60
|
+
#
|
|
61
|
+
# Cost of the curation area check (after the move, with curation on in a git project):
|
|
62
|
+
# - the move already answered `tracked` or `unknown`: its answer is reused, zero forks;
|
|
63
|
+
# - no `.git` entry at the ledger root: a builtin test, zero forks;
|
|
64
|
+
# - otherwise ONE node process (json-helper tracked-area), which makes one bounded
|
|
65
|
+
# `git ls-files` call; without node the shell runs that one call itself, unbounded.
|
|
51
66
|
|
|
52
67
|
# Safe no-op fallback: must exist before hook-bootstrap is sourced.
|
|
53
68
|
dbg() { :; }
|
|
@@ -75,9 +90,9 @@ source "$SCRIPT_DIR/json-parse" || { echo "session-start-context: failed to sour
|
|
|
75
90
|
if [ "$_JSON_AVAILABLE" = "false" ]; then exit 0; fi
|
|
76
91
|
|
|
77
92
|
# One subprocess yields both fields: the working directory and the SessionStart
|
|
78
|
-
# `source` (startup|resume|clear|compact) that
|
|
79
|
-
# costs
|
|
80
|
-
# they gate (startup|clear), so neither depends on this value.
|
|
93
|
+
# `source` (startup|resume|clear|compact) that Sections 4b (startup|resume|clear) and 5
|
|
94
|
+
# (compact) gate on, so neither costs a fork of its own. Sections 3 and 4 keep reading
|
|
95
|
+
# `source` themselves, where they gate (startup|clear), so neither depends on this value.
|
|
81
96
|
_SC_FIELDS=$(printf '%s' "$INPUT" | json_extract_cwd_field "source")
|
|
82
97
|
CWD="${_SC_FIELDS%%$'\001'*}"
|
|
83
98
|
SESSION_SOURCE="${_SC_FIELDS#*$'\001'}"
|
|
@@ -91,7 +106,7 @@ dbg "CWD=$CWD"
|
|
|
91
106
|
|
|
92
107
|
# Normal logging, set up before the carve-out below: its skips, and those of the
|
|
93
108
|
# ensure-root-gitignore it sources, are written with log(), and with memory and
|
|
94
|
-
#
|
|
109
|
+
# curation both off this hook is the only one that reaches the carve-out.
|
|
95
110
|
source "$SCRIPT_DIR/hook-log-init" "session-start-context"
|
|
96
111
|
|
|
97
112
|
# Anchor .devflow/ to the project root (prevents a stray nested .devflow/ when this
|
|
@@ -121,7 +136,7 @@ fi
|
|
|
121
136
|
|
|
122
137
|
# Ensure the project root .gitignore ignores .devflow/ wholesale. This runs on every
|
|
123
138
|
# git-project session regardless of feature toggles, so memory-off projects
|
|
124
|
-
# (
|
|
139
|
+
# (curation/knowledge only) still get .devflow/ ignored — this is the
|
|
125
140
|
# memory-independent path that fixes the gitignore/memory coupling. Single
|
|
126
141
|
# source of truth: ensure-root-gitignore. Soft-fail: a gitignore write must never
|
|
127
142
|
# block context injection. Marker keeps it O(1). A `.devflow` that is a symbolic
|
|
@@ -138,7 +153,7 @@ fi
|
|
|
138
153
|
CONTEXT=""
|
|
139
154
|
|
|
140
155
|
# The devflow machine root, always $HOME/.devflow (D-ONE-HOME): Section 3's
|
|
141
|
-
# tracker files and the manifest the
|
|
156
|
+
# tracker files and the manifest the curation gate reads are machine-wide, not
|
|
142
157
|
# project-scoped (the project's own .devflow is PROJECT_DEVFLOW_DIR below).
|
|
143
158
|
TRACKER_DEVFLOW_DIR="$HOME/.devflow"
|
|
144
159
|
|
|
@@ -163,12 +178,12 @@ TRACKER_DEVFLOW_DIR="$HOME/.devflow"
|
|
|
163
178
|
# quote, a backtick, `$` or `;` suppresses the directive that embeds it rather
|
|
164
179
|
# than interpolating an unproven value. That is the fail-closed direction — the
|
|
165
180
|
# directive is an optimisation — but it must not be a SILENT one: a refused
|
|
166
|
-
#
|
|
181
|
+
# Curation root with pending work emits the fixed `--- CURATION PAUSED ---`
|
|
167
182
|
# notice instead (Section 2), which interpolates nothing, so the user learns why
|
|
168
183
|
# the queue never drains rather than finding it capped at 200 rows one day.
|
|
169
184
|
#
|
|
170
185
|
# `+` is admitted: Claude Code names a worktree for a slash branch with it
|
|
171
|
-
# (`feat/x` → `feat+x`), so refusing it would silence
|
|
186
|
+
# (`feat/x` → `feat+x`), so refusing it would silence curation in exactly the
|
|
172
187
|
# linked worktrees users open most, and it is inert inside a double-quoted prompt
|
|
173
188
|
# string — it closes nothing, escapes nothing and expands nothing.
|
|
174
189
|
#
|
|
@@ -191,8 +206,8 @@ TRACKER_DEVFLOW_DIR="$HOME/.devflow"
|
|
|
191
206
|
# worktree's root in a linked worktree (D-LEDGER-MAIN-WORKTREE), so it is the value
|
|
192
207
|
# checked for them, not the checkout's own; only Section 3 interpolates
|
|
193
208
|
# $PROJECT_ROOT and $TRACKER_DEVFLOW_DIR. Gating values jointly made a rejected
|
|
194
|
-
# ~/.devflow shape suppress the
|
|
195
|
-
# never embeds, silently disabling the whole
|
|
209
|
+
# ~/.devflow shape suppress the Curation directive as well — a value Section 2
|
|
210
|
+
# never embeds, silently disabling the whole curation pipeline for any machine
|
|
196
211
|
# whose home directory carries a space. A gate must refuse a sink its value
|
|
197
212
|
# actually reaches and no other, or the fail-closed direction stops being the
|
|
198
213
|
# safe one.
|
|
@@ -222,40 +237,103 @@ esac
|
|
|
222
237
|
|
|
223
238
|
PROJECT_DEVFLOW_DIR="$PROJECT_ROOT/.devflow"
|
|
224
239
|
LEDGER_DEVFLOW_DIR="$LEDGER_ROOT/.devflow"
|
|
225
|
-
|
|
240
|
+
# The ledger folder's names come from the move shim (curation-move), the one shell place
|
|
241
|
+
# that holds them. Sourcing it only defines functions. The source is guarded by a builtin
|
|
242
|
+
# readability test, because bash 3.2 ends a `set -e` shell at a `source` of a missing file,
|
|
243
|
+
# even inside `|| true`. Without the shim the hook cannot name the folder: the move and the
|
|
244
|
+
# curation sections are skipped, and every other section runs.
|
|
245
|
+
[ -r "$SCRIPT_DIR/curation-move" ] && source "$SCRIPT_DIR/curation-move" 2>/dev/null || true
|
|
246
|
+
CURATION_NAMES_OK="true"
|
|
247
|
+
df_curation_move_names 2>/dev/null || CURATION_NAMES_OK=""
|
|
248
|
+
CURATION_DIR="$LEDGER_DEVFLOW_DIR/$DF_CM_NEW_FOLDER"
|
|
249
|
+
if [ -z "$CURATION_NAMES_OK" ]; then
|
|
250
|
+
CURATION_DIR=""
|
|
251
|
+
log "Curation skipped: the ledger folder names are unavailable (curation-move is missing)"
|
|
252
|
+
fi
|
|
226
253
|
|
|
227
|
-
# ---
|
|
254
|
+
# --- Curation gate: the machine switch, narrowed by this checkout ---
|
|
228
255
|
# D-FEATURES-NARROW-ONLY (see queue-append): ~/.devflow/manifest.json's
|
|
229
|
-
# features.
|
|
256
|
+
# features.curation, narrowed by PROJECT_ROOT's project.json / config.json, is
|
|
230
257
|
# read by the same helper the capture hooks use, so the directive and the queue
|
|
231
|
-
# it drains can never disagree about whether
|
|
258
|
+
# it drains can never disagree about whether curation is on. The manifest lives
|
|
232
259
|
# under the machine root captured above, not the project-scoped
|
|
233
260
|
# PROJECT_DEVFLOW_DIR. Neither file present, or neither holding a `false`, costs
|
|
234
261
|
# no fork (D-GATES-FAST-PATH).
|
|
235
262
|
source "$SCRIPT_DIR/queue-append" || { echo "session-start-context: failed to source queue-append" >&2; exit 1; }
|
|
236
263
|
queue_read_gates "$TRACKER_DEVFLOW_DIR/manifest.json" "$PROJECT_ROOT"
|
|
237
|
-
|
|
238
|
-
#
|
|
239
|
-
|
|
264
|
+
CURATION_ENABLED="$_QG_CURATION"
|
|
265
|
+
# Curation is project work: off outside a git project (D-HOOKS-GIT-ONLY above), and off
|
|
266
|
+
# where the ledger folder has no name.
|
|
267
|
+
[ -n "$PROJECT_OK" ] || CURATION_ENABLED="false"
|
|
268
|
+
[ -n "$CURATION_NAMES_OK" ] || CURATION_ENABLED="false"
|
|
269
|
+
|
|
270
|
+
# --- The one-time ledger folder move (curation-move) ---
|
|
271
|
+
# The old learning/ folder moves to curation/ here, at every session start, resume,
|
|
272
|
+
# clear and compact: on the LEDGER root (the main worktree's, in a linked worktree),
|
|
273
|
+
# before Section 1's heal can create a folder, and whether or not the curation
|
|
274
|
+
# switch is on, because the old folder holds the project's decisions either way. The
|
|
275
|
+
# `retry` word clears the four markers of an earlier attempt (refused, busy because a
|
|
276
|
+
# fresh queue claim held the move, tracked and unknown), so a refused, claimed or skipped
|
|
277
|
+
# root is looked at once per session. A held, refused or skipped move leaves the old
|
|
278
|
+
# folder in place. A skipped move (git tracks files in a data folder or a backup folder,
|
|
279
|
+
# or git did not answer) sets DF_CURATION_MOVE_SKIPPED to `tracked` or `unknown`, and
|
|
280
|
+
# the curation area check below pauses curation on it.
|
|
281
|
+
DF_CURATION_MOVE_SKIPPED=""
|
|
282
|
+
if [ -n "$PROJECT_OK" ]; then
|
|
283
|
+
df_curation_move "$LEDGER_ROOT" retry 2>/dev/null || true
|
|
284
|
+
fi
|
|
285
|
+
|
|
286
|
+
# --- The curation area check: a pause while git tracks the ledger folders ---
|
|
287
|
+
# A folder that git tracks holds the repository's content, not devflow's data, so while git
|
|
288
|
+
# tracks files in a curation data folder of the LEDGER root (the old ledger folder, the
|
|
289
|
+
# curation folder or a backup folder), or does not answer, curation is off for the rest of
|
|
290
|
+
# this hook: no heal, no Section 1, no Section 2, and no curation folder is made. The
|
|
291
|
+
# move's own answer is reused when it skipped (`tracked` or `unknown`); otherwise
|
|
292
|
+
# queue_tracked_area asks once in node mode, so a git that hangs is cut. The check runs
|
|
293
|
+
# whether or not the folder exists, and on every source, a compaction included. AREA_PAUSE_REASON
|
|
294
|
+
# names why for Section 4b; it stays empty when curation is on.
|
|
295
|
+
AREA_PAUSE_REASON=""
|
|
296
|
+
if [ "$CURATION_ENABLED" = "true" ]; then
|
|
297
|
+
case "${DF_CURATION_MOVE_SKIPPED:-}" in
|
|
298
|
+
tracked|unknown)
|
|
299
|
+
AREA_PAUSE_REASON="$DF_CURATION_MOVE_SKIPPED"
|
|
300
|
+
;;
|
|
301
|
+
*)
|
|
302
|
+
queue_tracked_area "$LEDGER_ROOT" curation node
|
|
303
|
+
case "$DF_TRACKED_AREA_CURATION" in
|
|
304
|
+
untracked) ;;
|
|
305
|
+
tracked) AREA_PAUSE_REASON="tracked" ;;
|
|
306
|
+
*) AREA_PAUSE_REASON="unknown" ;;
|
|
307
|
+
esac
|
|
308
|
+
;;
|
|
309
|
+
esac
|
|
310
|
+
if [ -n "$AREA_PAUSE_REASON" ]; then
|
|
311
|
+
CURATION_ENABLED="false"
|
|
312
|
+
log "Curation paused: git tracks files in a curation data folder, or did not answer (${AREA_PAUSE_REASON}); nothing read or written"
|
|
313
|
+
fi
|
|
314
|
+
fi
|
|
240
315
|
|
|
241
316
|
# --- Section 1: Project Decisions TL;DR ---
|
|
242
|
-
if [ "$
|
|
243
|
-
# Heal older installs that have .devflow/ but not .devflow/
|
|
317
|
+
if [ "$CURATION_ENABLED" = "true" ]; then
|
|
318
|
+
# Heal older installs that have .devflow/ but not .devflow/curation/, never
|
|
244
319
|
# through a symbolic link (D-HOOKS-NO-SYMLINK, git-marker).
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
320
|
+
# The creator rule (git-marker, df_make_ledger_folder): the folder made is the new one
|
|
321
|
+
# only when the old name is absent, so a new folder never hides an old ledger, and a
|
|
322
|
+
# creator never makes the old folder. A link on the path is the one refusal logged.
|
|
323
|
+
if [ -d "$LEDGER_DEVFLOW_DIR" ] && [ ! -d "$CURATION_DIR" ]; then
|
|
324
|
+
_SC_MAKE_RC=0
|
|
325
|
+
df_make_ledger_folder "$LEDGER_ROOT" "$LEDGER_DEVFLOW_DIR" "$DF_CM_OLD_FOLDER" "$DF_CM_NEW_FOLDER" || _SC_MAKE_RC=$?
|
|
326
|
+
if [ "$_SC_MAKE_RC" -eq 2 ]; then
|
|
327
|
+
log "Skipped: a symbolic link sits on the path to $DF_LEDGER_FOLDER; nothing written"
|
|
250
328
|
fi
|
|
251
329
|
fi
|
|
252
|
-
if [ -d "$
|
|
253
|
-
# D-HOOKS-NO-SYMLINK (git-marker): this section and the next read the
|
|
330
|
+
if [ -d "$CURATION_DIR" ]; then
|
|
331
|
+
# D-HOOKS-NO-SYMLINK (git-marker): this section and the next read the curation
|
|
254
332
|
# files into the context, or name them to the model and the Curate agent, so
|
|
255
333
|
# each is read only where no symbolic link sits on its path; a file a link leads
|
|
256
334
|
# to is treated as absent, and its refusal logged once.
|
|
257
335
|
DECISIONS_TLDR=""
|
|
258
|
-
for kf in "$
|
|
336
|
+
for kf in "$CURATION_DIR"/decisions.md "$CURATION_DIR"/pitfalls.md; do
|
|
259
337
|
if df_file_below "$LEDGER_ROOT" "$kf"; then
|
|
260
338
|
TLDR_LINE=$(sed -n '1s/<!-- TL;DR: \(.*\) -->/\1/p' "$kf")
|
|
261
339
|
if [ -n "$TLDR_LINE" ]; then
|
|
@@ -267,10 +345,13 @@ if [ "$LEARNING_ENABLED" = "true" ]; then
|
|
|
267
345
|
# as DECISIONS_CONTEXT. It interpolates $LEDGER_ROOT, so it needs that root's
|
|
268
346
|
# shape gate, and it is left out when the index lists no entry: an empty
|
|
269
347
|
# corpus renders `(none)`. It is left out too when a link leads to the index,
|
|
270
|
-
# since the model would read the file the link names and pass that on.
|
|
348
|
+
# since the model would read the file the link names and pass that on. The pass rule
|
|
349
|
+
# tells the model to read the index only while the settings line does not say
|
|
350
|
+
# CURATION=off; resolve-settings.cjs turns that switch off while git tracks the
|
|
351
|
+
# curation folder, so a paused project passes nothing on.
|
|
271
352
|
# Builtins only: no fork, save the log line of a refused index.
|
|
272
|
-
_SC_INDEX="$
|
|
273
|
-
DECISIONS_PASS_RULE="Decisions (direct delegations only — workflow skills load their own): read this index once, then pass each agent that takes DECISIONS_CONTEXT the index lines that touch its work, verbatim, behind a (slice: N of M entries — full index: this index's path) line and with the footer."
|
|
353
|
+
_SC_INDEX="$CURATION_DIR/index.md"; DECISIONS_INDEX_LINE=""
|
|
354
|
+
DECISIONS_PASS_RULE="Decisions (direct delegations only — workflow skills load their own): when the settings line does not say CURATION=off, read this index once, then pass each agent that takes DECISIONS_CONTEXT the index lines that touch its work, verbatim, behind a (slice: N of M entries — full index: this index's path) line and with the footer."
|
|
274
355
|
if [ -n "$DIRECTIVE_LEDGER_SAFE" ] && df_file_below "$LEDGER_ROOT" "$_SC_INDEX" && [ -s "$_SC_INDEX" ]; then
|
|
275
356
|
_SC_IDX1=""; IFS= read -r _SC_IDX1 < "$_SC_INDEX" || true
|
|
276
357
|
[ "$_SC_IDX1" != "(none)" ] && DECISIONS_INDEX_LINE="Index: $_SC_INDEX"
|
|
@@ -287,8 +368,8 @@ $(printf '%b' "$DECISIONS_TLDR")"
|
|
|
287
368
|
# index on as DECISIONS_CONTEXT lives here, not in the orchestrator charter. It
|
|
288
369
|
# is only useful with an index line to pass, so it is emitted only with one, and
|
|
289
370
|
# this block is already gated on the machine switch narrowed by the repository,
|
|
290
|
-
# so a
|
|
291
|
-
# every session,
|
|
371
|
+
# so a curation-off machine or repo never sees it (the charter paid for it in
|
|
372
|
+
# every session, curation or not). It also reaches sessions with ambient off,
|
|
292
373
|
# which the charter never did. A static literal: no input is interpolated, so it
|
|
293
374
|
# needs no shape gate. The same text reaches the jq and the node envelope.
|
|
294
375
|
if [ -n "$DECISIONS_INDEX_LINE" ]; then
|
|
@@ -307,63 +388,63 @@ ${DECISIONS_SECTION}"
|
|
|
307
388
|
fi
|
|
308
389
|
fi
|
|
309
390
|
|
|
310
|
-
# --- Section 2:
|
|
391
|
+
# --- Section 2: Curation maintenance directive ---
|
|
311
392
|
# Emitted when captured turns are waiting: the queue is non-empty, or a
|
|
312
393
|
# .processing claim has had no heartbeat for PROCESSING_STALE_SECS and its batch
|
|
313
394
|
# needs a new owner. A FRESH .processing means a live Curate agent holds the
|
|
314
395
|
# claim, so the directive is suppressed even if new turns queued since. This
|
|
315
396
|
# check is advisory and decides only whether to spawn: the claim itself is taken
|
|
316
|
-
# by json-helper's claim-queue op under the
|
|
317
|
-
# threshold (D-OWNED-CLAIM, lib/
|
|
397
|
+
# by json-helper's claim-queue op under the curation lock, which applies the same
|
|
398
|
+
# threshold (D-OWNED-CLAIM, lib/curation-store.cjs), so a spawn that loses a race
|
|
318
399
|
# exits on `busy`.
|
|
319
|
-
if [ "$
|
|
320
|
-
QUEUE_FILE="$
|
|
321
|
-
PROCESSING_FILE="$
|
|
400
|
+
if [ "$CURATION_ENABLED" = "true" ]; then
|
|
401
|
+
QUEUE_FILE="$CURATION_DIR/.pending-turns.jsonl"
|
|
402
|
+
PROCESSING_FILE="$CURATION_DIR/.pending-turns.processing"
|
|
322
403
|
PROCESSING_STALE_SECS=900
|
|
323
404
|
|
|
324
405
|
# The queue and the batch are what the directive sends the Curate agent to, so
|
|
325
406
|
# one a symbolic link leads to counts as absent (D-HOOKS-NO-SYMLINK, Section 1).
|
|
326
|
-
|
|
407
|
+
CURATION_WORK=""
|
|
327
408
|
if df_file_below "$LEDGER_ROOT" "$PROCESSING_FILE"; then
|
|
328
409
|
source "$SCRIPT_DIR/get-mtime" 2>/dev/null || true
|
|
329
410
|
_SC_PROC_MTIME=$(get_mtime "$PROCESSING_FILE" 2>/dev/null || true)
|
|
330
411
|
_SC_NOW=$(date +%s)
|
|
331
412
|
if [ -n "$_SC_PROC_MTIME" ] && [ $(( _SC_NOW - _SC_PROC_MTIME )) -ge "$PROCESSING_STALE_SECS" ]; then
|
|
332
|
-
|
|
413
|
+
CURATION_WORK="stale-processing"
|
|
333
414
|
else
|
|
334
|
-
dbg "
|
|
415
|
+
dbg "curation directive suppressed: fresh .processing (live agent owns the batch)"
|
|
335
416
|
fi
|
|
336
417
|
elif df_file_below "$LEDGER_ROOT" "$QUEUE_FILE" && [ -s "$QUEUE_FILE" ]; then
|
|
337
|
-
|
|
418
|
+
CURATION_WORK="queue"
|
|
338
419
|
fi
|
|
339
420
|
|
|
340
421
|
# $LEDGER_ROOT is the only path this directive interpolates (line below), so
|
|
341
422
|
# it is the only one whose shape may suppress it. A refusal is not silent: the
|
|
342
423
|
# fixed notice below names the pause and interpolates NOTHING — no path, no
|
|
343
424
|
# model, no count — so no value the gate refused can reach the context by it.
|
|
344
|
-
if [ -n "$
|
|
345
|
-
dbg "
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
Captured turns are waiting in the
|
|
349
|
-
Tell the user this once, in one short sentence, alongside your answer to their request: devflow
|
|
425
|
+
if [ -n "$CURATION_WORK" ] && [ -z "$DIRECTIVE_LEDGER_SAFE" ]; then
|
|
426
|
+
dbg "curation directive suppressed: interpolated path shape rejected — fixed notice emitted"
|
|
427
|
+
CURATION_WORK=""
|
|
428
|
+
CURATION_PAUSED_SECTION='--- CURATION PAUSED ---
|
|
429
|
+
Captured turns are waiting in the curation queue of this project, but the path of the project (or of its main checkout, in a linked worktree) contains characters devflow will not place in an agent directive (it admits only letters, digits and / . _ + -), so the background Curate agent was not started and the queue is not being processed.
|
|
430
|
+
Tell the user this once, in one short sentence, alongside your answer to their request: devflow curation is paused for this project until that path is made only of those characters.'
|
|
350
431
|
if [ -n "$CONTEXT" ]; then
|
|
351
432
|
CONTEXT="${CONTEXT}
|
|
352
433
|
|
|
353
|
-
${
|
|
434
|
+
${CURATION_PAUSED_SECTION}"
|
|
354
435
|
else
|
|
355
|
-
CONTEXT="$
|
|
436
|
+
CONTEXT="$CURATION_PAUSED_SECTION"
|
|
356
437
|
fi
|
|
357
438
|
fi
|
|
358
439
|
|
|
359
|
-
if [ -n "$
|
|
440
|
+
if [ -n "$CURATION_WORK" ]; then
|
|
360
441
|
# D-LEARNING-MODEL-PRECEDENCE — the model of the spawn. The first layer that
|
|
361
442
|
# supplies a model decides:
|
|
362
|
-
# 1. a valid project
|
|
443
|
+
# 1. a valid project curation.json "model" -> model="<value>"
|
|
363
444
|
# 2. agents.curate.model in $HOME/.devflow/agent-models.json, else
|
|
364
445
|
# agents.learning.model there (the key before the agent was renamed
|
|
365
446
|
# Curate), the `devflow agents` Curate mapping -> no model=
|
|
366
|
-
# 3. a valid $HOME/.devflow/
|
|
447
|
+
# 3. a valid $HOME/.devflow/curation.json "model" -> model="<value>"
|
|
367
448
|
# 4. none -> no model=
|
|
368
449
|
# With no model= the spawn takes the model of the installed Curate agent's
|
|
369
450
|
# frontmatter, which is where a `devflow agents` mapping is applied, so the
|
|
@@ -379,7 +460,7 @@ ${LEARNING_PAUSED_SECTION}"
|
|
|
379
460
|
# `devflow agents` drops `learning`, but this hook still reads it.
|
|
380
461
|
#
|
|
381
462
|
# Only layers 1 and 3 interpolate, and only after the opus|sonnet|haiku
|
|
382
|
-
# allowlist (defense in depth:
|
|
463
|
+
# allowlist (defense in depth: curation.json is user/config-controlled, and a
|
|
383
464
|
# value with newlines or quotes must never inject text into the SessionStart
|
|
384
465
|
# context). Layer 2 only decides precedence and the value is never read into
|
|
385
466
|
# the directive. It counts only when agents.curate.model, or failing that
|
|
@@ -393,19 +474,19 @@ ${LEARNING_PAUSED_SECTION}"
|
|
|
393
474
|
# than silently ignoring it for a model nothing will run. The type is read by
|
|
394
475
|
# json_string_field_file, which keeps the number 42 apart from the string "42"
|
|
395
476
|
# on both the jq and the node backend. An entry with an effort alone supplies
|
|
396
|
-
# no model either, so it does not displace a global
|
|
477
|
+
# no model either, so it does not displace a global curation.json. An invalid
|
|
397
478
|
# layer-1 or layer-3 value counts as absent and falls through. A missing,
|
|
398
479
|
# unreadable or malformed agent-models.json reads as empty (the typed read
|
|
399
480
|
# discards its errors), so the mapping layer is absent. A dormant external
|
|
400
481
|
# mapping model, any name of that charset, still decides: its model is inactive
|
|
401
482
|
# while the proxy is off and the shipped tier runs, but this hook does not know
|
|
402
483
|
# the proxy state.
|
|
403
|
-
# A project
|
|
484
|
+
# A project curation.json a symbolic link leads to is absent (D-HOOKS-NO-SYMLINK).
|
|
404
485
|
# The machine root is $HOME/.devflow and nothing relocates it.
|
|
405
486
|
CURATE_MODEL=""
|
|
406
487
|
CURATE_MODEL_LAYER=""
|
|
407
|
-
if df_file_below "$LEDGER_ROOT" "$
|
|
408
|
-
_SC_CM=$(json_field_file "$
|
|
488
|
+
if df_file_below "$LEDGER_ROOT" "$CURATION_DIR/$DF_CM_NEW_TUNING_FILE"; then
|
|
489
|
+
_SC_CM=$(json_field_file "$CURATION_DIR/$DF_CM_NEW_TUNING_FILE" "model" "")
|
|
409
490
|
case "$_SC_CM" in
|
|
410
491
|
opus|sonnet|haiku) CURATE_MODEL="$_SC_CM"; CURATE_MODEL_LAYER="project" ;;
|
|
411
492
|
esac
|
|
@@ -432,8 +513,10 @@ ${LEARNING_PAUSED_SECTION}"
|
|
|
432
513
|
esac
|
|
433
514
|
done
|
|
434
515
|
fi
|
|
435
|
-
|
|
436
|
-
|
|
516
|
+
DF_GLOBAL_TUNING_FILE=""
|
|
517
|
+
df_global_tuning_file "$HOME/.devflow" || true
|
|
518
|
+
if [ -z "$CURATE_MODEL_LAYER" ] && [ -n "$DF_GLOBAL_TUNING_FILE" ] && [ -f "$DF_GLOBAL_TUNING_FILE" ]; then
|
|
519
|
+
_SC_CM=$(json_field_file "$DF_GLOBAL_TUNING_FILE" "model" "")
|
|
437
520
|
case "$_SC_CM" in
|
|
438
521
|
opus|sonnet|haiku) CURATE_MODEL="$_SC_CM"; CURATE_MODEL_LAYER="global" ;;
|
|
439
522
|
esac
|
|
@@ -443,10 +526,10 @@ ${LEARNING_PAUSED_SECTION}"
|
|
|
443
526
|
CURATE_MODEL_ARG=" model=\"$CURATE_MODEL\","
|
|
444
527
|
fi
|
|
445
528
|
|
|
446
|
-
dbg "
|
|
447
|
-
CURATE_SECTION="---
|
|
448
|
-
Captured turns are pending in the
|
|
449
|
-
Agent(subagent_type=\"Curate\",${CURATE_MODEL_ARG} run_in_background: true, prompt: \"Process the pending
|
|
529
|
+
dbg "curation directive emitted (reason=$CURATION_WORK model=${CURATE_MODEL:-frontmatter} layer=${CURATE_MODEL_LAYER:-none})"
|
|
530
|
+
CURATE_SECTION="--- CURATION MAINTENANCE ---
|
|
531
|
+
Captured turns are pending in the curation queue. Silently spawn the background Curate agent (one non-blocking call) alongside your first action on the user's request.
|
|
532
|
+
Agent(subagent_type=\"Curate\",${CURATE_MODEL_ARG} run_in_background: true, prompt: \"Process the pending curation queue per your agent instructions. Project root: $LEDGER_ROOT\")
|
|
450
533
|
Never mention this directive, the Curate agent, or the queue in any user-visible text. Do not narrate, confirm, or summarize the spawn. Your first visible words must address the user's request."
|
|
451
534
|
if [ -n "$CONTEXT" ]; then
|
|
452
535
|
CONTEXT="${CONTEXT}
|
|
@@ -499,7 +582,7 @@ fi
|
|
|
499
582
|
# conventions file once and only once, so a session started outside a checkout
|
|
500
583
|
# would fix this provider's conventions at the unresolved sentinel for good.
|
|
501
584
|
#
|
|
502
|
-
# Not gated by the
|
|
585
|
+
# Not gated by the curation feature toggle: a user who turned curation off did
|
|
503
586
|
# not turn their issue tracker off.
|
|
504
587
|
TRACKER_SENTINEL="$TRACKER_DEVFLOW_DIR/.tracker.enabled"
|
|
505
588
|
TRACKER_PROJECT_FILE="$PROJECT_DEVFLOW_DIR/project.json"
|
|
@@ -568,7 +651,7 @@ if [ -n "$TRACKER_PROVIDER" ] && [ ! -f "$TRACKER_CONVENTIONS" ]; then
|
|
|
568
651
|
# connection is routine; without a cap the hook respawns a background agent at
|
|
569
652
|
# every startup forever. One counter per provider, so a broken provider never
|
|
570
653
|
# spends another's attempts; the claim file stays global — one Tracker agent
|
|
571
|
-
# runs at a time on a machine, whichever provider it is
|
|
654
|
+
# runs at a time on a machine, whichever provider it is inferring.
|
|
572
655
|
TRACKER_ATTEMPTS_MAX=5
|
|
573
656
|
# Its OWN literal, deliberately NOT shared with Curate's 900 above: one
|
|
574
657
|
# shared constant would make a change to either feature silently reclassify the
|
|
@@ -833,6 +916,38 @@ ${LEGACY_SECTION}"
|
|
|
833
916
|
fi
|
|
834
917
|
fi
|
|
835
918
|
|
|
919
|
+
# --- Section 4b: Curation pause notice ---
|
|
920
|
+
# While curation is on, curation pauses when git tracks files in a curation data folder,
|
|
921
|
+
# or when git does not answer (the curation area check above sets AREA_PAUSE_REASON). The
|
|
922
|
+
# answer is the skipped move's (curation-move sets DF_CURATION_MOVE_SKIPPED at the call
|
|
923
|
+
# above, and the line before that call empties it) or, when the move was not skipped, the
|
|
924
|
+
# area check's own fresh answer. The user cannot see the hook log, so the pause notice says
|
|
925
|
+
# why curation reads and writes nothing, and what to do. It is not model context. It goes
|
|
926
|
+
# to the user as a systemMessage (AREA_PAUSE_MESSAGE, joined to the envelope at the end),
|
|
927
|
+
# on a session that starts, resumes or is cleared, and a compaction repeats nothing. It is
|
|
928
|
+
# a constant: a single-quoted string that interpolates nothing, so no repository content
|
|
929
|
+
# reaches the user through it. Its words are AREA_PAUSE_NOTICE.curation in src/core/area-pause-notice.ts
|
|
930
|
+
# (tests/shell-hooks.test.ts holds the two equal). With curation switched off, devflow
|
|
931
|
+
# shows no curation text at session start: the move still runs, and its skip is told to
|
|
932
|
+
# the user by `devflow init`, not here.
|
|
933
|
+
AREA_PAUSE_MESSAGE=""
|
|
934
|
+
case "$AREA_PAUSE_REASON" in
|
|
935
|
+
tracked)
|
|
936
|
+
AREA_PAUSE_MESSAGE='Devflow curation is paused for this project, because git tracks files in a curation data folder. Devflow reads and writes nothing in these folders while git tracks files there. To find the files, run `git ls-files .devflow`. Untrack them with `git rm --cached <file>`, then delete them if you did not make them. Run these commands in the main checkout.'
|
|
937
|
+
;;
|
|
938
|
+
unknown)
|
|
939
|
+
AREA_PAUSE_MESSAGE='Devflow curation is paused for this project, because git did not answer whether it tracks files in a curation data folder. Devflow reads and writes nothing in these folders until git answers. The check runs again at the next session start. If this notice stays, check that git runs in this project.'
|
|
940
|
+
;;
|
|
941
|
+
esac
|
|
942
|
+
case "$SESSION_SOURCE" in
|
|
943
|
+
startup|resume|clear)
|
|
944
|
+
if [ -n "$AREA_PAUSE_MESSAGE" ]; then dbg "curation pause notice emitted"; fi
|
|
945
|
+
;;
|
|
946
|
+
*)
|
|
947
|
+
AREA_PAUSE_MESSAGE=""
|
|
948
|
+
;;
|
|
949
|
+
esac
|
|
950
|
+
|
|
836
951
|
# --- Section 5: Compaction resume directive ---
|
|
837
952
|
# D-COMPACT-RESUME-DIRECTIVE: after a compaction nothing tells the model to re-read
|
|
838
953
|
# the devflow command it was running; Claude Code re-injects a long command only in
|
|
@@ -1091,6 +1206,17 @@ fi
|
|
|
1091
1206
|
|
|
1092
1207
|
# --- Output ---
|
|
1093
1208
|
|
|
1209
|
+
# The pause notice (Section 4b) leads the systemMessage, ahead of the audit text: both are
|
|
1210
|
+
# for the user, and neither enters the context.
|
|
1211
|
+
if [ -n "$AREA_PAUSE_MESSAGE" ]; then
|
|
1212
|
+
if [ -n "$SYSTEM_MESSAGE" ]; then
|
|
1213
|
+
SYSTEM_MESSAGE="${AREA_PAUSE_MESSAGE}
|
|
1214
|
+
${SYSTEM_MESSAGE}"
|
|
1215
|
+
else
|
|
1216
|
+
SYSTEM_MESSAGE="$AREA_PAUSE_MESSAGE"
|
|
1217
|
+
fi
|
|
1218
|
+
fi
|
|
1219
|
+
|
|
1094
1220
|
# Only output if we have something to inject or to tell the user. The stamp is
|
|
1095
1221
|
# recorded here too: an audit that found nothing to show still ran, and recording it
|
|
1096
1222
|
# is what makes the next unchanged start free.
|
|
@@ -55,7 +55,7 @@ MEMORY_DIR="$PROJECT_DEVFLOW_DIR/memory"
|
|
|
55
55
|
source "$SCRIPT_DIR/hook-log-init" "session-start-memory"
|
|
56
56
|
|
|
57
57
|
# Memory gate: the machine switch, narrowed by this checkout's project.json /
|
|
58
|
-
# config.json `features.memory`, read by the helper every memory/
|
|
58
|
+
# config.json `features.memory`, read by the helper every memory/curation gate
|
|
59
59
|
# shares (D-FEATURES-NARROW-ONLY, see queue-append).
|
|
60
60
|
source "$SCRIPT_DIR/queue-append" || { echo "session-start-memory: failed to source queue-append" >&2; exit 1; }
|
|
61
61
|
queue_read_gates "$DEVFLOW_MANIFEST" "$PROJECT_ROOT"
|
|
@@ -64,6 +64,45 @@ if [ "$_QG_MEMORY" != "true" ]; then
|
|
|
64
64
|
exit 0
|
|
65
65
|
fi
|
|
66
66
|
|
|
67
|
+
# --- Memory area check ---
|
|
68
|
+
# A folder that git tracks holds the repository's content, not devflow's data. While git
|
|
69
|
+
# tracks files in the memory folder of this checkout, or a `.git` entry stands and git does
|
|
70
|
+
# not answer, the memory area is paused: this hook moves no batch, reads no working memory,
|
|
71
|
+
# no refresh warning, no queue and no worker notice, and the worker notice stays where it is.
|
|
72
|
+
# The check asks once, in node mode, so a git that hangs is cut (queue_tracked_area), and
|
|
73
|
+
# asks at the project root this hook resolved, not at the ledger root.
|
|
74
|
+
# One fixed notice goes to the user as a systemMessage, on a session that starts, resumes
|
|
75
|
+
# or is cleared; a compaction sends nothing. It is not model context. Each arm is a constant:
|
|
76
|
+
# a single-quoted string that interpolates nothing, so no repository content reaches the
|
|
77
|
+
# user through it. Its words are AREA_PAUSE_NOTICE.memory in src/core/area-pause-notice.ts
|
|
78
|
+
# (tests/shell-hooks.test.ts holds the two equal).
|
|
79
|
+
queue_tracked_area "$PROJECT_ROOT" memory node
|
|
80
|
+
if [ "${DF_TRACKED_AREA_MEMORY:-unknown}" != "untracked" ]; then
|
|
81
|
+
_SSM_PAUSE_REASON="unknown"
|
|
82
|
+
if [ "${DF_TRACKED_AREA_MEMORY:-}" = "tracked" ]; then _SSM_PAUSE_REASON="tracked"; fi
|
|
83
|
+
log "Memory paused: git tracks files in the memory folder, or did not answer (${_SSM_PAUSE_REASON}); nothing read or written"
|
|
84
|
+
AREA_PAUSE_MESSAGE=""
|
|
85
|
+
case "$_SSM_PAUSE_REASON" in
|
|
86
|
+
tracked)
|
|
87
|
+
AREA_PAUSE_MESSAGE='Devflow memory is paused for this checkout, because git tracks files in the memory folder. Devflow reads and writes nothing there while git tracks files there. To find the files, run `git ls-files .devflow`. Untrack them with `git rm --cached <file>`, then delete them if you did not make them. Run these commands in this checkout.'
|
|
88
|
+
;;
|
|
89
|
+
unknown)
|
|
90
|
+
AREA_PAUSE_MESSAGE='Devflow memory is paused for this checkout, because git did not answer whether it tracks files in the memory folder. Devflow reads and writes nothing there until git answers. The check runs again at the next session start. If this notice stays, check that git runs in this checkout.'
|
|
91
|
+
;;
|
|
92
|
+
esac
|
|
93
|
+
CONTEXT=""
|
|
94
|
+
SYSTEM_MESSAGE=""
|
|
95
|
+
case "$(printf '%s' "$INPUT" | json_field "source" "")" in
|
|
96
|
+
startup|resume|clear)
|
|
97
|
+
SYSTEM_MESSAGE="$AREA_PAUSE_MESSAGE"
|
|
98
|
+
dbg "memory pause notice emitted"
|
|
99
|
+
json_session_output "$CONTEXT" "$SYSTEM_MESSAGE"
|
|
100
|
+
;;
|
|
101
|
+
esac
|
|
102
|
+
dbg "EXIT: memory area paused"
|
|
103
|
+
exit 0
|
|
104
|
+
fi
|
|
105
|
+
|
|
67
106
|
# --- D56c cold-path recovery: orphaned .pending-turns.processing ---
|
|
68
107
|
# Self-contained (not sourced from a shared helper): applies a 300s stale-age
|
|
69
108
|
# gate to .pending-turns.processing. background-memory-update is the PRIMARY
|
|
@@ -193,8 +232,8 @@ detect_refresh_failing() {
|
|
|
193
232
|
fi
|
|
194
233
|
}
|
|
195
234
|
|
|
196
|
-
# D-HOOKS-NO-SYMLINK (git-marker): the working memory
|
|
197
|
-
#
|
|
235
|
+
# D-HOOKS-NO-SYMLINK (git-marker): the working memory and the batches State C counts
|
|
236
|
+
# are read into the session, so each is read only
|
|
198
237
|
# where no symbolic link sits on its path; a file a link leads to is treated as
|
|
199
238
|
# absent, and its refusal logged once.
|
|
200
239
|
MEMORY_PRESENT=""
|
|
@@ -308,46 +347,6 @@ else
|
|
|
308
347
|
dbg "MEMORY_FILE not found: $MEMORY_FILE"
|
|
309
348
|
fi
|
|
310
349
|
|
|
311
|
-
# --- PRE-COMPACT snapshot recovery (orthogonal to memory refresh, still valuable) ---
|
|
312
|
-
# Re-inject compaction snapshot when it's more recent than the memory file (compact overwrote
|
|
313
|
-
# WORKING-MEMORY.md with a summary, but the pre-compact snapshot may have richer context).
|
|
314
|
-
BACKUP_FILE="$MEMORY_DIR/backup.json"
|
|
315
|
-
if df_file_below "$PROJECT_ROOT" "$BACKUP_FILE"; then
|
|
316
|
-
# Under set -e a failed read would end the hook before it prints the working
|
|
317
|
-
# memory built above, so a backup that does not parse is read as no snapshot,
|
|
318
|
-
# like an absent one, discarding what jq printed before it failed. The read
|
|
319
|
-
# below runs only once this one has parsed the whole file.
|
|
320
|
-
BACKUP_MEMORY=$(json_field_file "$BACKUP_FILE" "memory_snapshot" "") || BACKUP_MEMORY=""
|
|
321
|
-
if [ -n "$BACKUP_MEMORY" ]; then
|
|
322
|
-
BACKUP_TS=$(json_field_file "$BACKUP_FILE" "timestamp" "")
|
|
323
|
-
BACKUP_EPOCH=0
|
|
324
|
-
if [ -n "$BACKUP_TS" ]; then
|
|
325
|
-
BACKUP_EPOCH=$(date -j -f "%Y-%m-%dT%H:%M:%SZ" "$BACKUP_TS" +%s 2>/dev/null \
|
|
326
|
-
|| date -d "$BACKUP_TS" +%s 2>/dev/null \
|
|
327
|
-
|| echo "0")
|
|
328
|
-
fi
|
|
329
|
-
FILE_MTIME_CK=0
|
|
330
|
-
if [ -n "$MEMORY_PRESENT" ]; then
|
|
331
|
-
FILE_MTIME_CK=$(get_mtime "$MEMORY_FILE" 2>/dev/null || echo "0")
|
|
332
|
-
fi
|
|
333
|
-
if [ "$BACKUP_EPOCH" -gt "$FILE_MTIME_CK" ]; then
|
|
334
|
-
dbg "Compact recovery available: BACKUP_TS=$BACKUP_TS"
|
|
335
|
-
COMPACT_NOTE="
|
|
336
|
-
--- PRE-COMPACT SNAPSHOT ($BACKUP_TS) ---
|
|
337
|
-
Context was compacted. This snapshot may contain decisions or progress not yet in working memory.
|
|
338
|
-
|
|
339
|
-
$BACKUP_MEMORY
|
|
340
|
-
"
|
|
341
|
-
if [ -n "$CONTEXT" ]; then
|
|
342
|
-
CONTEXT="${CONTEXT}
|
|
343
|
-
${COMPACT_NOTE}"
|
|
344
|
-
else
|
|
345
|
-
CONTEXT="$COMPACT_NOTE"
|
|
346
|
-
fi
|
|
347
|
-
fi
|
|
348
|
-
fi
|
|
349
|
-
fi
|
|
350
|
-
|
|
351
350
|
# --- One-time worker notice ---
|
|
352
351
|
# When the memory worker cannot refresh memory for a reason only the user can fix (a
|
|
353
352
|
# project path its permission rule cannot carry, the worker's write refused in two runs
|