devflow-kit 3.3.0 → 3.5.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 +47 -0
- package/README.md +8 -4
- package/dist/agents/code-edit.md +133 -0
- package/dist/agents/code-fix.md +165 -0
- package/dist/agents/code.md +187 -0
- package/{src/assets → dist}/agents/design.md +1 -2
- package/{src/assets → dist}/agents/diagnose.md +1 -2
- package/dist/agents/git.md +33 -722
- package/{src/assets → dist}/agents/knowledge.md +12 -5
- package/{src/assets → dist}/agents/research.md +8 -2
- package/{src/assets → dist}/agents/review.md +8 -11
- package/{src/assets → dist}/agents/scrutinize.md +4 -1
- package/dist/agents/skim.md +152 -0
- package/{src/assets → dist}/agents/triage.md +9 -2
- package/dist/cli/commands/behavior-prompts.js +77 -0
- package/dist/cli/commands/behavior.js +123 -0
- package/dist/cli/commands/flags.js +8 -2
- package/dist/cli/commands/init-seed.js +7 -3
- package/dist/cli/commands/init.js +134 -5
- package/dist/cli/commands/learning.js +38 -3
- package/dist/cli/commands/rules.js +16 -0
- package/dist/cli/commands/tracker.js +112 -15
- package/dist/cli/commands/uninstall.js +42 -1
- package/dist/cli.js +2 -0
- package/dist/commands/bug-analysis.md +35 -13
- package/dist/commands/code-review.md +155 -69
- package/dist/commands/debug.md +39 -16
- package/dist/commands/dynamic-build.md +61 -72
- package/dist/commands/dynamic-plan.md +39 -25
- package/dist/commands/dynamic-profile.md +28 -14
- package/dist/commands/dynamic-tickets.md +38 -22
- package/dist/commands/explore.md +18 -16
- package/dist/commands/implement.md +121 -150
- package/dist/commands/plan.md +51 -31
- package/dist/commands/release.md +72 -6
- package/dist/commands/research.md +49 -20
- package/dist/commands/resolve.md +54 -46
- package/dist/commands/self-review.md +38 -25
- package/dist/core/agent-frontmatter.js +101 -0
- package/dist/core/agent-models.js +43 -0
- package/dist/core/assets.js +55 -10
- package/dist/core/claude-md-audit.js +190 -0
- package/dist/core/compliance-compose.js +6 -4
- package/dist/core/feature-switch.js +41 -1
- package/dist/core/flags.js +139 -0
- package/dist/core/fs-atomic.js +8 -3
- package/dist/core/learning-variants.js +213 -0
- package/dist/core/manifest.js +73 -3
- package/dist/core/mds-variants.js +98 -19
- package/dist/core/plugins.js +111 -72
- package/dist/core/project-paths.js +0 -4
- package/dist/core/proxy-log.js +1 -1
- package/dist/core/proxy-state.js +1 -1
- package/dist/core/tracker.js +120 -2
- package/dist/learning-off/agents/code-edit.md +129 -0
- package/dist/learning-off/agents/code-fix.md +161 -0
- package/dist/learning-off/agents/code.md +183 -0
- package/dist/learning-off/agents/design.md +118 -0
- package/dist/learning-off/agents/diagnose.md +210 -0
- package/dist/learning-off/agents/knowledge.md +96 -0
- package/dist/learning-off/agents/research.md +155 -0
- package/dist/learning-off/agents/review.md +224 -0
- package/dist/learning-off/agents/scrutinize.md +120 -0
- package/{src/assets → dist/learning-off}/agents/skim.md +5 -8
- package/dist/learning-off/agents/triage.md +170 -0
- package/dist/learning-off/commands/bug-analysis.md +420 -0
- package/dist/learning-off/commands/code-review.md +530 -0
- package/dist/learning-off/commands/debug.md +314 -0
- package/dist/learning-off/commands/dynamic-build.md +1245 -0
- package/dist/learning-off/commands/dynamic-plan.md +426 -0
- package/dist/learning-off/commands/dynamic-profile.md +214 -0
- package/dist/learning-off/commands/dynamic-tickets.md +634 -0
- package/dist/learning-off/commands/explore.md +210 -0
- package/dist/learning-off/commands/implement.md +774 -0
- package/dist/learning-off/commands/plan.md +671 -0
- package/dist/learning-off/commands/release.md +311 -0
- package/dist/learning-off/commands/research.md +229 -0
- package/dist/learning-off/commands/resolve.md +842 -0
- package/dist/learning-off/commands/self-review.md +266 -0
- package/dist/skills/git/references/learn-conventions.md +27 -3
- package/dist/skills/git/references/pr/check-ci-status.md +19 -0
- package/dist/skills/git/references/pr/check-merge-readiness.md +19 -0
- package/dist/skills/git/references/pr/fetch-review-threads.md +30 -0
- package/dist/skills/git/references/pr/post-resolution-summary.md +18 -0
- package/dist/skills/git/references/pr/post-review-summary.md +20 -0
- package/dist/skills/git/references/pr/resolve-review-threads.md +28 -4
- package/dist/skills/git/references/pr/update-pr-evidence.md +13 -0
- package/dist/skills/git/references/pr/validate-branch.md +26 -0
- package/dist/skills/git/references/tracker/_contract.md +33 -0
- package/dist/skills/git/references/tracker/github/associate-release.md +24 -0
- package/dist/skills/git/references/tracker/github/backlink-shipped-issues.md +31 -1
- package/dist/skills/git/references/tracker/github/create-release.md +30 -1
- package/dist/skills/git/references/tracker/github/ensure-pr-ready.md +89 -2
- package/dist/skills/git/references/tracker/github/ensure-traceable-issue.md +16 -1
- package/dist/skills/git/references/tracker/github/fetch-issue.md +38 -1
- package/dist/skills/git/references/tracker/github/fetch-issues-batch.md +49 -1
- package/dist/skills/git/references/tracker/github/gather-release-evidence.md +29 -0
- package/dist/skills/git/references/tracker/github/manage-debt.md +21 -1
- package/dist/skills/git/references/tracker/github/post-wave-report.md +17 -1
- package/dist/skills/git/references/tracker/github/setup-task.md +53 -1
- package/dist/skills/git/references/tracker/jira/associate-release.md +25 -1
- package/dist/skills/git/references/tracker/jira/backlink-shipped-issues.md +31 -1
- package/dist/skills/git/references/tracker/jira/create-release.md +30 -1
- package/dist/skills/git/references/tracker/jira/ensure-pr-ready.md +89 -2
- package/dist/skills/git/references/tracker/jira/ensure-traceable-issue.md +16 -1
- package/dist/skills/git/references/tracker/jira/fetch-issue.md +38 -1
- package/dist/skills/git/references/tracker/jira/fetch-issues-batch.md +49 -1
- package/dist/skills/git/references/tracker/jira/gather-release-evidence.md +29 -0
- package/dist/skills/git/references/tracker/jira/manage-debt.md +21 -1
- package/dist/skills/git/references/tracker/jira/post-wave-report.md +17 -1
- package/dist/skills/git/references/tracker/jira/setup-task.md +55 -3
- package/dist/skills/git/references/tracker/linear/associate-release.md +25 -1
- package/dist/skills/git/references/tracker/linear/backlink-shipped-issues.md +31 -1
- package/dist/skills/git/references/tracker/linear/create-release.md +30 -1
- package/dist/skills/git/references/tracker/linear/ensure-pr-ready.md +89 -2
- package/dist/skills/git/references/tracker/linear/ensure-traceable-issue.md +16 -1
- package/dist/skills/git/references/tracker/linear/fetch-issue.md +38 -1
- package/dist/skills/git/references/tracker/linear/fetch-issues-batch.md +49 -1
- package/dist/skills/git/references/tracker/linear/gather-release-evidence.md +29 -0
- package/dist/skills/git/references/tracker/linear/manage-debt.md +21 -1
- package/dist/skills/git/references/tracker/linear/post-wave-report.md +17 -1
- package/dist/skills/git/references/tracker/linear/setup-task.md +55 -3
- package/dist/targets/claude-code/agent-type-owner.js +164 -0
- package/dist/targets/claude-code/behavior-install.js +111 -0
- package/dist/targets/claude-code/installer.js +140 -37
- package/dist/targets/claude-code/language-stamp.js +185 -0
- package/dist/targets/claude-code/learning-install.js +497 -0
- package/dist/targets/claude-code/tracker-install.js +33 -16
- package/dist/targets/claude-code/tracker-servers.js +107 -0
- package/package.json +4 -3
- package/src/assets/agents/_partials/_code.mds +109 -0
- package/src/assets/agents/code-edit.mds +81 -0
- package/src/assets/agents/code-fix.mds +113 -0
- package/src/assets/agents/code.mds +135 -0
- package/src/assets/agents/design.mds +148 -0
- package/src/assets/agents/diagnose.mds +225 -0
- package/src/assets/agents/evaluate.md +8 -4
- package/src/assets/agents/explore.md +58 -0
- package/src/assets/agents/git.mds +33 -722
- package/src/assets/agents/knowledge.mds +131 -0
- package/src/assets/agents/learning.md +19 -69
- package/src/assets/agents/research.mds +182 -0
- package/src/assets/agents/review.mds +282 -0
- package/src/assets/agents/scrutinize.mds +135 -0
- package/src/assets/agents/simplify.md +3 -0
- package/src/assets/agents/skim.mds +165 -0
- package/src/assets/agents/synthesize.md +26 -352
- package/src/assets/agents/test.md +8 -0
- package/src/assets/agents/tracker.md +20 -7
- package/src/assets/agents/triage.mds +201 -0
- package/src/assets/agents/validate.md +13 -6
- package/src/assets/commands/_partials/_compliance.mds +41 -4
- package/src/assets/commands/_partials/_decisions.mds +33 -2
- package/src/assets/commands/_partials/_engine.mds +14 -6
- package/src/assets/commands/_partials/_knowledge.mds +25 -12
- package/src/assets/commands/_partials/_preamble.mds +34 -10
- package/src/assets/commands/_partials/_publication.mds +5 -4
- package/src/assets/commands/_partials/_roster.mds +4 -3
- package/src/assets/commands/_partials/_settings.mds +13 -5
- package/src/assets/commands/_partials/_wave.mds +9 -1
- package/src/assets/commands/bug-analysis.mds +27 -5
- package/src/assets/commands/code-review.mds +158 -52
- package/src/assets/commands/debug.mds +41 -3
- package/src/assets/commands/dynamic-build.mds +47 -27
- package/src/assets/commands/dynamic-plan.mds +40 -9
- package/src/assets/commands/dynamic-profile.mds +9 -1
- package/src/assets/commands/dynamic-tickets.mds +21 -6
- package/src/assets/commands/explore.mds +28 -2
- package/src/assets/commands/implement.mds +126 -129
- package/src/assets/commands/plan.mds +58 -14
- package/src/assets/commands/{release.md → release.mds} +30 -26
- package/src/assets/commands/research.mds +42 -11
- package/src/assets/commands/resolve.mds +59 -15
- package/src/assets/commands/self-review.mds +30 -5
- package/src/assets/mds/.mdsroot +4 -0
- package/src/assets/mds/git/_ops.mds +383 -0
- package/src/assets/mds/git/_ops_pr.mds +201 -0
- package/src/assets/mds/git/_ops_steps.mds +147 -0
- package/src/assets/mds/git/_pr.mds +39 -44
- package/src/assets/mds/git/_references.mds +6 -3
- package/src/assets/mds/tracker/_common.mds +5 -5
- package/src/assets/mds/tracker/_contract.mds +73 -0
- package/src/assets/mds/tracker/_github.mds +73 -16
- package/src/assets/mds/tracker/_jira.mds +77 -19
- package/src/assets/mds/tracker/_linear.mds +77 -19
- package/src/assets/mds/tracker/_mcp.mds +2 -2
- package/src/assets/mds/tracker/_steps.mds +98 -0
- package/src/assets/rules/behavior.md +6 -0
- package/src/assets/rules/context-economy.md +10 -0
- package/src/assets/rules/go.md +1 -0
- package/src/assets/rules/java.md +1 -0
- package/src/assets/rules/python.md +1 -0
- package/src/assets/rules/rust.md +1 -0
- package/src/assets/rules/typescript.md +1 -0
- package/src/assets/scripts/claude-md-audit.cjs +611 -0
- package/src/assets/scripts/hooks/assets/orchestrator-charter.md +3 -3
- package/src/assets/scripts/hooks/json-helper.cjs +13 -5
- package/src/assets/scripts/hooks/json-parse +34 -10
- package/src/assets/scripts/hooks/lib/project-paths.cjs +0 -6
- package/src/assets/scripts/hooks/session-start-context +315 -7
- package/src/assets/skills/agent-references/SKILL.md +33 -0
- package/src/assets/skills/agent-references/references/learning/maintain.md +71 -0
- package/src/assets/skills/agent-references/references/synthesize/bug-analysis.md +71 -0
- package/src/assets/skills/agent-references/references/synthesize/design.md +36 -0
- package/src/assets/skills/agent-references/references/synthesize/exploration.md +38 -0
- package/src/assets/skills/agent-references/references/synthesize/planning.md +60 -0
- package/src/assets/skills/agent-references/references/synthesize/research.md +61 -0
- package/src/assets/skills/agent-references/references/synthesize/review.md +76 -0
- package/src/assets/skills/apply-decisions/SKILL.md +1 -1
- package/src/assets/skills/apply-feature-knowledge/SKILL.md +5 -5
- package/src/assets/skills/compliance/SKILL.md +1 -1
- package/src/assets/skills/docs-framework/SKILL.md +80 -83
- package/src/assets/skills/docs-framework/references/patterns.md +14 -25
- package/src/assets/skills/docs-framework/references/violations.md +7 -7
- package/src/assets/skills/feature-knowledge/SKILL.md +43 -12
- package/src/assets/skills/gap-analysis/SKILL.md +0 -16
- package/src/assets/skills/gap-analysis/references/compliance.md +19 -0
- package/src/assets/skills/quality-gates/SKILL.md +1 -1
- package/dist/skills/git/references/pr/ensure-pr-ready.md +0 -24
- package/src/assets/agents/code.md +0 -330
|
@@ -98,18 +98,42 @@ json_extract_cwd_prompt() {
|
|
|
98
98
|
|
|
99
99
|
# --- Hook output envelopes ---
|
|
100
100
|
|
|
101
|
-
# Build SessionStart output. Usage: json_session_output "$CONTEXT"
|
|
101
|
+
# Build SessionStart output. Usage: json_session_output "$CONTEXT" ["$SYSTEM_MESSAGE"]
|
|
102
|
+
#
|
|
103
|
+
# D-SYSTEMMESSAGE-ENVELOPE: the optional second argument is a message shown to the
|
|
104
|
+
# user, carried in the top-level `systemMessage` key beside (never inside)
|
|
105
|
+
# `hookSpecificOutput`; it does not enter the model's context. With ONE argument the
|
|
106
|
+
# envelope is exactly what every existing caller has always received, byte for byte
|
|
107
|
+
# (ensure-proxy, session-start-orchestrator, session-start-memory and Sections 1-5 of
|
|
108
|
+
# session-start-context pass one). With two:
|
|
109
|
+
# - a message and a context -> both keys, hookSpecificOutput first;
|
|
110
|
+
# - a message and no context -> `systemMessage` alone, with NO hookSpecificOutput key;
|
|
111
|
+
# - an empty message -> the one-argument envelope for that context.
|
|
112
|
+
# The node fallback (json-helper.cjs session-output) builds the same content, compact
|
|
113
|
+
# where jq pretty-prints.
|
|
102
114
|
json_session_output() {
|
|
103
|
-
local ctx="$1"
|
|
104
|
-
if [ "
|
|
105
|
-
|
|
106
|
-
"
|
|
107
|
-
"
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
115
|
+
local ctx="$1" msg="${2:-}"
|
|
116
|
+
if [ "$#" -lt 2 ] || [ -z "$msg" ]; then
|
|
117
|
+
if [ "$_HAS_JQ" = "true" ]; then
|
|
118
|
+
jq -n --arg ctx "$ctx" '{
|
|
119
|
+
"hookSpecificOutput": {
|
|
120
|
+
"hookEventName": "SessionStart",
|
|
121
|
+
"additionalContext": $ctx
|
|
122
|
+
}
|
|
123
|
+
}'
|
|
124
|
+
else
|
|
125
|
+
node "$_JSON_HELPER" session-output "$ctx"
|
|
126
|
+
fi
|
|
127
|
+
elif [ "$_HAS_JQ" = "true" ]; then
|
|
128
|
+
jq -n --arg ctx "$ctx" --arg msg "$msg" '
|
|
129
|
+
(if $ctx != "" then {
|
|
130
|
+
"hookSpecificOutput": {
|
|
131
|
+
"hookEventName": "SessionStart",
|
|
132
|
+
"additionalContext": $ctx
|
|
133
|
+
}
|
|
134
|
+
} else {} end) + {"systemMessage": $msg}'
|
|
111
135
|
else
|
|
112
|
-
node "$_JSON_HELPER" session-output "$ctx"
|
|
136
|
+
node "$_JSON_HELPER" session-output "$ctx" "$msg"
|
|
113
137
|
fi
|
|
114
138
|
}
|
|
115
139
|
|
|
@@ -164,11 +164,6 @@ function getResearchDir(projectRoot) {
|
|
|
164
164
|
return path.join(projectRoot, '.devflow', 'docs', 'research');
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
-
/** .devflow/docs/handoff-{branchSlug}.md — Code agent phase handoff artifact */
|
|
168
|
-
function getHandoffPath(projectRoot, branchSlug) {
|
|
169
|
-
return path.join(projectRoot, '.devflow', 'docs', `handoff-${branchSlug}.md`);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
167
|
module.exports = {
|
|
173
168
|
// Core directories
|
|
174
169
|
getMemoryDir,
|
|
@@ -201,5 +196,4 @@ module.exports = {
|
|
|
201
196
|
getReviewsDir,
|
|
202
197
|
getDesignDir,
|
|
203
198
|
getResearchDir,
|
|
204
|
-
getHandoffPath,
|
|
205
199
|
};
|
|
@@ -23,6 +23,31 @@
|
|
|
23
23
|
# Section 4: Legacy install notice — one line when this repository still carries
|
|
24
24
|
# a retired project-local devflow install (its .claude/settings.json registers
|
|
25
25
|
# devflow hooks), pointing at `devflow uninstall --scope local`.
|
|
26
|
+
# Section 5: Compaction resume directive — on a `compact` SessionStart, one fixed
|
|
27
|
+
# line telling the model to re-read the devflow command it was running from the
|
|
28
|
+
# phase in progress (D-COMPACT-RESUME-DIRECTIVE).
|
|
29
|
+
# Section 6: CLAUDE.md import audit — a top-level systemMessage (shown to the user,
|
|
30
|
+
# never part of additionalContext) naming an `@path` import that puts a large file
|
|
31
|
+
# into every thread's always-loaded context, once per finding, with a stamp that
|
|
32
|
+
# makes an unchanged start free (D-CLAUDE-MD-IMPORT-AUDIT, D-AUDIT-STAMP,
|
|
33
|
+
# D-SYSTEMMESSAGE-ENVELOPE).
|
|
34
|
+
#
|
|
35
|
+
# Sections 5 and 6 add NO new exit path: neither calls `exit`, a failure in either
|
|
36
|
+
# leaves the other sections and the directive intact, and the hook still exits as it
|
|
37
|
+
# did before (the existing exits are the bad-CWD and re-entrancy returns, the
|
|
38
|
+
# no-JSON-tool return at the top, and the two sourcing failures). With neither jq nor
|
|
39
|
+
# node the hook returns before Section 5 can run, so there is no directive then; that
|
|
40
|
+
# is accepted and documented.
|
|
41
|
+
#
|
|
42
|
+
# Cost of Sections 5 and 6 (the [DR-10] table below belongs to Section 3):
|
|
43
|
+
# - Section 5: a `case` on a value parsed with the CWD, in the same single
|
|
44
|
+
# subprocess as before; zero extra forks.
|
|
45
|
+
# - Section 6, unchanged start (the stamp's root set equals the current one and no
|
|
46
|
+
# recorded path changed): shell builtins only, one bounded read of the stamp, no
|
|
47
|
+
# fork, no node process.
|
|
48
|
+
# - Section 6, changed start: ONE node process (claude-md-audit.cjs), and a
|
|
49
|
+
# sibling temp file renamed over the stamp. When none of the roots exists there
|
|
50
|
+
# is nothing to audit: the stamp is written with builtins, and node is not started.
|
|
26
51
|
|
|
27
52
|
# Safe no-op fallback: must exist before hook-bootstrap is sourced.
|
|
28
53
|
dbg() { :; }
|
|
@@ -49,7 +74,13 @@ source "$SCRIPT_DIR/hook-bootstrap" "session-start-context"
|
|
|
49
74
|
source "$SCRIPT_DIR/json-parse" || { echo "session-start-context: failed to source json-parse" >&2; exit 1; }
|
|
50
75
|
if [ "$_JSON_AVAILABLE" = "false" ]; then exit 0; fi
|
|
51
76
|
|
|
52
|
-
|
|
77
|
+
# One subprocess yields both fields: the working directory and the SessionStart
|
|
78
|
+
# `source` (startup|resume|clear|compact) that Section 5 gates on, so the directive
|
|
79
|
+
# costs no fork of its own. Sections 3 and 4 keep reading `source` themselves, where
|
|
80
|
+
# they gate (startup|clear), so neither depends on this value.
|
|
81
|
+
_SC_FIELDS=$(printf '%s' "$INPUT" | json_extract_cwd_field "source")
|
|
82
|
+
CWD="${_SC_FIELDS%%$'\001'*}"
|
|
83
|
+
SESSION_SOURCE="${_SC_FIELDS#*$'\001'}"
|
|
53
84
|
if [ -z "$CWD" ] || [ ! -d "$CWD" ]; then
|
|
54
85
|
dbg "EXIT: bad CWD"
|
|
55
86
|
exit 0
|
|
@@ -239,6 +270,7 @@ if [ "$LEARNING_ENABLED" = "true" ]; then
|
|
|
239
270
|
# since the model would read the file the link names and pass that on.
|
|
240
271
|
# Builtins only: no fork, save the log line of a refused index.
|
|
241
272
|
_SC_INDEX="$LEARNING_DIR/index.md"; DECISIONS_INDEX_LINE=""
|
|
273
|
+
DECISIONS_PASS_RULE="Decisions (direct delegations only — workflow skills load their own): pass this index as DECISIONS_CONTEXT — its content, read once — to every agent that takes it."
|
|
242
274
|
if [ -n "$DIRECTIVE_LEDGER_SAFE" ] && df_file_below "$LEDGER_ROOT" "$_SC_INDEX" && [ -s "$_SC_INDEX" ]; then
|
|
243
275
|
_SC_IDX1=""; IFS= read -r _SC_IDX1 < "$_SC_INDEX" || true
|
|
244
276
|
[ "$_SC_IDX1" != "(none)" ] && DECISIONS_INDEX_LINE="Index: $_SC_INDEX"
|
|
@@ -250,10 +282,19 @@ if [ "$LEARNING_ENABLED" = "true" ]; then
|
|
|
250
282
|
DECISIONS_SECTION="${DECISIONS_SECTION}
|
|
251
283
|
$(printf '%b' "$DECISIONS_TLDR")"
|
|
252
284
|
fi
|
|
253
|
-
# The index line goes last.
|
|
285
|
+
# The index line goes last among the data lines, and the pass rule follows it.
|
|
286
|
+
# D-DECISIONS-CHARTER-HANDOFF: the rule that tells the main model to pass this
|
|
287
|
+
# index on as DECISIONS_CONTEXT lives here, not in the orchestrator charter. It
|
|
288
|
+
# is only useful with an index line to pass, so it is emitted only with one, and
|
|
289
|
+
# this block is already gated on the machine switch narrowed by the repository,
|
|
290
|
+
# so a learning-off machine or repo never sees it (the charter paid for it in
|
|
291
|
+
# every session, learning or not). It also reaches sessions with ambient off,
|
|
292
|
+
# which the charter never did. A static literal: no input is interpolated, so it
|
|
293
|
+
# needs no shape gate. The same text reaches the jq and the node envelope.
|
|
254
294
|
if [ -n "$DECISIONS_INDEX_LINE" ]; then
|
|
255
295
|
DECISIONS_SECTION="${DECISIONS_SECTION}
|
|
256
|
-
${DECISIONS_INDEX_LINE}
|
|
296
|
+
${DECISIONS_INDEX_LINE}
|
|
297
|
+
${DECISIONS_PASS_RULE}"
|
|
257
298
|
fi
|
|
258
299
|
if [ -n "$CONTEXT" ]; then
|
|
259
300
|
CONTEXT="${CONTEXT}
|
|
@@ -779,11 +820,270 @@ ${LEGACY_SECTION}"
|
|
|
779
820
|
fi
|
|
780
821
|
fi
|
|
781
822
|
|
|
823
|
+
# --- Section 5: Compaction resume directive ---
|
|
824
|
+
# D-COMPACT-RESUME-DIRECTIVE: after a compaction nothing tells the model to re-read
|
|
825
|
+
# the devflow command it was running; Claude Code re-injects a long command only in
|
|
826
|
+
# part (the plan records commands over about 5k tokens being truncated on re-injection,
|
|
827
|
+
# which this repository cannot verify). On the SessionStart whose source is `compact`
|
|
828
|
+
# this section adds one fixed line, appended to CONTEXT with the other sections'
|
|
829
|
+
# join, and never sent as a systemMessage.
|
|
830
|
+
#
|
|
831
|
+
# The line is a constant: a single-quoted string that interpolates nothing, so the
|
|
832
|
+
# `$CLAUDE_CONFIG_DIR` in it reaches the model as text and its bytes do not depend on
|
|
833
|
+
# the caller. It names, in at most 250 ASCII characters (tests/session-start-compact
|
|
834
|
+
# holds the cap and the numeric-floors ceiling `compact-directive-max-chars`):
|
|
835
|
+
# (a) an if-clause, so it applies only when a devflow command was running, with an
|
|
836
|
+
# explicit ignore clause;
|
|
837
|
+
# (b) where the command file lives, by rule: commands/devflow/ under the Claude
|
|
838
|
+
# config directory ($CLAUDE_CONFIG_DIR, else ~/.claude);
|
|
839
|
+
# (c) the read mechanics: list the headings, then read from the phase in progress,
|
|
840
|
+
# never the whole file;
|
|
841
|
+
# (d) that the command's input (COMMAND_INPUT in the commands that bind it, an
|
|
842
|
+
# ARGUMENTS line in the others) comes from the conversation summary, not from a
|
|
843
|
+
# placeholder in the file;
|
|
844
|
+
# (e) to resume after the last finished phase.
|
|
845
|
+
# The gate is a POSITIVE `compact` case, emitted on every compact run whatever the
|
|
846
|
+
# project (the directive does no project work), so it never becomes a denylist and a
|
|
847
|
+
# missing, absent or unrecognised source emits nothing. The model decides whether a
|
|
848
|
+
# command was running: detecting one here would be judgment, which stays out of hooks.
|
|
849
|
+
case "$SESSION_SOURCE" in
|
|
850
|
+
compact)
|
|
851
|
+
dbg "compaction resume directive emitted"
|
|
852
|
+
COMPACT_SECTION='If a devflow command was running: re-read {$CLAUDE_CONFIG_DIR or ~/.claude}/commands/devflow/<name>.md, list headings, read from current phase, take input (COMMAND_INPUT/ARGUMENTS) from the summary, resume after the last finished phase. Else ignore.'
|
|
853
|
+
if [ -n "$CONTEXT" ]; then
|
|
854
|
+
CONTEXT="${CONTEXT}
|
|
855
|
+
|
|
856
|
+
${COMPACT_SECTION}"
|
|
857
|
+
else
|
|
858
|
+
CONTEXT="$COMPACT_SECTION"
|
|
859
|
+
fi
|
|
860
|
+
;;
|
|
861
|
+
esac
|
|
862
|
+
|
|
863
|
+
# --- Section 6: CLAUDE.md import audit and its stamp ---
|
|
864
|
+
# D-CLAUDE-MD-IMPORT-AUDIT: a CLAUDE.md `@path` import loads its file into every
|
|
865
|
+
# thread at launch, so a large import is paid for in every session. This section
|
|
866
|
+
# reports the ones over the thresholds that claude-md-audit.cjs holds (and documents:
|
|
867
|
+
# grammar, bounds, thresholds, the upstream differences) in a top-level systemMessage,
|
|
868
|
+
# which the user sees and the model does not (D-SYSTEMMESSAGE-ENVELOPE, json-parse).
|
|
869
|
+
# It never enters CONTEXT, and the audit READS only: this section and init write the
|
|
870
|
+
# stamp, nothing else.
|
|
871
|
+
#
|
|
872
|
+
# D-AUDIT-STAMP: one machine-root file, $HOME/.devflow/.claude-md-audit, so a changed
|
|
873
|
+
# start costs one node process and an unchanged one costs none. Its rows are `V 1`,
|
|
874
|
+
# `R <root>` (the gated root set), `P <flag> <path>` (every path the last audit
|
|
875
|
+
# examined: 0 absent, 1 regular file, 2 exists but is not one), `K <key>` (a finding
|
|
876
|
+
# already displayed) and `E <reason>`; the format is specified in claude-md-audit.cjs.
|
|
877
|
+
# Gated roots: CLAUDE.md in the Claude config directory ($CLAUDE_CONFIG_DIR when
|
|
878
|
+
# absolute, else ~/.claude) always; in a git project that is not HOME
|
|
879
|
+
# (PROJECT_OK) also its CLAUDE.md, .claude/CLAUDE.md and CLAUDE.local.md.
|
|
880
|
+
# Fast path (builtins only, no fork): the audit is skipped when the stamp's R rows
|
|
881
|
+
# equal the current root set and every P row still holds: `-e` agrees with the
|
|
882
|
+
# flag, and a regular file is not `-nt` (newer than) the stamp. Mtimes are whole
|
|
883
|
+
# seconds. Two gaps are accepted: a file whose mtime is moved back before the stamp
|
|
884
|
+
# is missed until its next forward change, and a write landing while an audit runs
|
|
885
|
+
# can be missed the same way. The fast path decides only whether the audit runs.
|
|
886
|
+
# Slow path: ONE node process over the roots (none when no root exists: there is
|
|
887
|
+
# nothing to read, so the stamp records the absent roots with builtins). A finding is recorded as displayed
|
|
888
|
+
# only after the output below was emitted, so a lost stamp update can repeat a
|
|
889
|
+
# message and can never hide a new finding.
|
|
890
|
+
# Failure: node failing, the script missing or throwing, or output that is not the
|
|
891
|
+
# framed block shows nothing, and writes a stamp holding the R rows, the keys
|
|
892
|
+
# already displayed and an error marker; an unchanged broken state then starts no
|
|
893
|
+
# node process, and a changed root set retries. A root path holding a control byte
|
|
894
|
+
# is never recorded, so a setup with one re-audits at every start (rare).
|
|
895
|
+
# Skipped silently: no node on PATH, no ~/.devflow (a session never creates the
|
|
896
|
+
# machine root), or a stamp path that is a link or not a regular file.
|
|
897
|
+
# A stamp over 256 KiB, or one with a NUL byte, is read as absent.
|
|
898
|
+
SYSTEM_MESSAGE=""
|
|
899
|
+
AUDIT_STAMP_NEXT=""
|
|
900
|
+
AUDIT_STAMP_FILE="$TRACKER_DEVFLOW_DIR/.claude-md-audit"
|
|
901
|
+
AUDIT_SCRIPT="$SCRIPT_DIR/../claude-md-audit.cjs"
|
|
902
|
+
_SC_AUDIT_OLD_STAMP=""
|
|
903
|
+
_SC_AUDIT_ROOTS=()
|
|
904
|
+
|
|
905
|
+
# _sc_audit_stamp_blocked — succeeds when the stamp path is a link or exists and is
|
|
906
|
+
# not a regular file: the write is refused and the audit skipped (D-AUDIT-STAMP).
|
|
907
|
+
_sc_audit_stamp_blocked() {
|
|
908
|
+
if [ -L "$AUDIT_STAMP_FILE" ]; then return 0; fi
|
|
909
|
+
if [ -e "$AUDIT_STAMP_FILE" ] && [ ! -f "$AUDIT_STAMP_FILE" ]; then return 0; fi
|
|
910
|
+
return 1
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
# _sc_audit_stamp_fresh — succeeds when the audit can be skipped. Builtins only.
|
|
914
|
+
# Sets _SC_AUDIT_OLD_STAMP to the stamp text (empty when absent, over 256 KiB or
|
|
915
|
+
# holding a NUL: `read -d '' -n N` succeeds only when it stops short of the end of
|
|
916
|
+
# the file, which is a stamp the shell cannot vouch for). Ends in an explicit return
|
|
917
|
+
# so a caller running under set -e would not die on the normal path: a function's last
|
|
918
|
+
# status is the status of its call, and under errexit a non-zero one is fatal.
|
|
919
|
+
_sc_audit_stamp_fresh() {
|
|
920
|
+
local line="" have="" want="" root="" path=""
|
|
921
|
+
_SC_AUDIT_OLD_STAMP=""
|
|
922
|
+
[ -f "$AUDIT_STAMP_FILE" ] || return 1
|
|
923
|
+
if IFS= read -r -d '' -n 262145 _SC_AUDIT_OLD_STAMP 2>/dev/null < "$AUDIT_STAMP_FILE"; then
|
|
924
|
+
_SC_AUDIT_OLD_STAMP=""
|
|
925
|
+
return 1
|
|
926
|
+
fi
|
|
927
|
+
case "$_SC_AUDIT_OLD_STAMP" in
|
|
928
|
+
'V 1'|'V 1'$'\n'*) ;;
|
|
929
|
+
*) _SC_AUDIT_OLD_STAMP=""; return 1 ;;
|
|
930
|
+
esac
|
|
931
|
+
for root in "${_SC_AUDIT_ROOTS[@]}"; do
|
|
932
|
+
want="${want}R ${root}"$'\n'
|
|
933
|
+
done
|
|
934
|
+
while IFS= read -r line; do
|
|
935
|
+
case "$line" in
|
|
936
|
+
'R '*) have="${have}${line}"$'\n' ;;
|
|
937
|
+
esac
|
|
938
|
+
done <<< "$_SC_AUDIT_OLD_STAMP"
|
|
939
|
+
if [ "$have" != "$want" ]; then return 1; fi
|
|
940
|
+
while IFS= read -r line; do
|
|
941
|
+
case "$line" in
|
|
942
|
+
'P 0 '*)
|
|
943
|
+
path="${line#P 0 }"
|
|
944
|
+
if [ -e "$path" ]; then return 1; fi
|
|
945
|
+
;;
|
|
946
|
+
'P 1 '*)
|
|
947
|
+
path="${line#P 1 }"
|
|
948
|
+
if [ ! -e "$path" ] || [ "$path" -nt "$AUDIT_STAMP_FILE" ]; then return 1; fi
|
|
949
|
+
;;
|
|
950
|
+
'P 2 '*)
|
|
951
|
+
path="${line#P 2 }"
|
|
952
|
+
if [ ! -e "$path" ]; then return 1; fi
|
|
953
|
+
;;
|
|
954
|
+
esac
|
|
955
|
+
done <<< "$_SC_AUDIT_OLD_STAMP"
|
|
956
|
+
return 0
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
# _sc_audit_shell_stamp <absent|failed> — a stamp the shell writes without node, for the
|
|
960
|
+
# two cases that need no audit text. Sets AUDIT_STAMP_NEXT. The rows are the ones
|
|
961
|
+
# claude-md-audit.cjs renders for the same state (tests/session-start-compact.test.ts
|
|
962
|
+
# holds the two equal): a root with a control byte is left out, as the script leaves it
|
|
963
|
+
# out, and the keys of the previous stamp are kept.
|
|
964
|
+
# absent No root exists, so there is nothing to audit and nothing to show: the root
|
|
965
|
+
# rows and a `P 0` row each. A CLAUDE.md appearing at any of them re-audits.
|
|
966
|
+
# failed The audit could not run: the root rows and an error marker, no P rows, so
|
|
967
|
+
# only a changed root set retries.
|
|
968
|
+
_sc_audit_shell_stamp() {
|
|
969
|
+
local kind="$1" line="" root="" text='V 1'$'\n'
|
|
970
|
+
for root in "${_SC_AUDIT_ROOTS[@]}"; do
|
|
971
|
+
case "$root" in
|
|
972
|
+
*[[:cntrl:]]*) ;;
|
|
973
|
+
*) text="${text}R ${root}"$'\n' ;;
|
|
974
|
+
esac
|
|
975
|
+
done
|
|
976
|
+
if [ "$kind" = "absent" ]; then
|
|
977
|
+
for root in "${_SC_AUDIT_ROOTS[@]}"; do
|
|
978
|
+
case "$root" in
|
|
979
|
+
*[[:cntrl:]]*) ;;
|
|
980
|
+
*) text="${text}P 0 ${root}"$'\n' ;;
|
|
981
|
+
esac
|
|
982
|
+
done
|
|
983
|
+
fi
|
|
984
|
+
while IFS= read -r line; do
|
|
985
|
+
case "$line" in
|
|
986
|
+
'K '*) text="${text}${line}"$'\n' ;;
|
|
987
|
+
esac
|
|
988
|
+
done <<< "$_SC_AUDIT_OLD_STAMP"
|
|
989
|
+
if [ "$kind" = "failed" ]; then text="${text}E audit-failed"$'\n'; fi
|
|
990
|
+
AUDIT_STAMP_NEXT="$text"
|
|
991
|
+
return 0
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
# _sc_audit_no_root — succeeds when none of the gated roots exists. The common case on a
|
|
995
|
+
# machine with no CLAUDE.md anywhere, settled by `-e` tests alone: no node process.
|
|
996
|
+
_sc_audit_no_root() {
|
|
997
|
+
local root=""
|
|
998
|
+
for root in "${_SC_AUDIT_ROOTS[@]}"; do
|
|
999
|
+
if [ -e "$root" ]; then return 1; fi
|
|
1000
|
+
done
|
|
1001
|
+
return 0
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
# _sc_audit_run — the slow path: one node process, its framed block parsed with
|
|
1005
|
+
# builtins. `M ` rows are the systemMessage lines; V/R/P/K/E rows are the new stamp.
|
|
1006
|
+
# Sets SYSTEM_MESSAGE and AUDIT_STAMP_NEXT; a block that is not complete is a failure.
|
|
1007
|
+
_sc_audit_run() {
|
|
1008
|
+
local out="" line="" rc=0 magic="" end="" msg="" stamp=""
|
|
1009
|
+
out=$(node "$AUDIT_SCRIPT" hook "$HOME" "$AUDIT_STAMP_FILE" "${_SC_AUDIT_ROOTS[@]}" 2>/dev/null)
|
|
1010
|
+
rc=$?
|
|
1011
|
+
if [ "$rc" -eq 0 ]; then
|
|
1012
|
+
while IFS= read -r line; do
|
|
1013
|
+
case "$line" in
|
|
1014
|
+
'devflow-claude-md-audit 1') magic="yes" ;;
|
|
1015
|
+
'END') end="yes" ;;
|
|
1016
|
+
'M '*)
|
|
1017
|
+
if [ -n "$msg" ]; then msg="${msg}"$'\n'"${line#M }"; else msg="${line#M }"; fi
|
|
1018
|
+
;;
|
|
1019
|
+
[VRPKE]' '*) stamp="${stamp}${line}"$'\n' ;;
|
|
1020
|
+
esac
|
|
1021
|
+
done <<< "$out"
|
|
1022
|
+
fi
|
|
1023
|
+
if [ "$rc" -eq 0 ] && [ -n "$magic" ] && [ -n "$end" ] && [ -n "$stamp" ]; then
|
|
1024
|
+
SYSTEM_MESSAGE="$msg"
|
|
1025
|
+
AUDIT_STAMP_NEXT="$stamp"
|
|
1026
|
+
dbg "claude-md audit ran (message=${#msg} chars)"
|
|
1027
|
+
else
|
|
1028
|
+
dbg "claude-md audit failed — recording the failure, showing nothing"
|
|
1029
|
+
_sc_audit_shell_stamp failed
|
|
1030
|
+
fi
|
|
1031
|
+
return 0
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
# _sc_audit_record — write AUDIT_STAMP_NEXT, after the output has been emitted. A
|
|
1035
|
+
# sibling temp file (owner-only: the umask is set before the copy exists, because a rename
|
|
1036
|
+
# installs the copy's mode and not the replaced file's) is
|
|
1037
|
+
# renamed over the stamp; nothing stands at either name that is a link or not a
|
|
1038
|
+
# regular file (noclobber alone would still open a FIFO, and mv onto a linked directory
|
|
1039
|
+
# moves into it), and a failed write leaves the old stamp. Never fails the hook.
|
|
1040
|
+
_sc_audit_record() {
|
|
1041
|
+
local tmp="${AUDIT_STAMP_FILE}.tmp.$$"
|
|
1042
|
+
[ -n "$AUDIT_STAMP_NEXT" ] || return 0
|
|
1043
|
+
[ -d "$TRACKER_DEVFLOW_DIR" ] || return 0
|
|
1044
|
+
if _sc_audit_stamp_blocked; then return 0; fi
|
|
1045
|
+
if [ -e "$tmp" ] || [ -L "$tmp" ]; then return 0; fi
|
|
1046
|
+
if ( umask 077; set -o noclobber; printf '%s' "$AUDIT_STAMP_NEXT" > "$tmp" ) 2>/dev/null; then
|
|
1047
|
+
if _sc_audit_stamp_blocked; then
|
|
1048
|
+
rm -f -- "$tmp" 2>/dev/null
|
|
1049
|
+
return 0
|
|
1050
|
+
fi
|
|
1051
|
+
mv -f -- "$tmp" "$AUDIT_STAMP_FILE" 2>/dev/null || rm -f -- "$tmp" 2>/dev/null
|
|
1052
|
+
else
|
|
1053
|
+
rm -f -- "$tmp" 2>/dev/null
|
|
1054
|
+
fi
|
|
1055
|
+
return 0
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
if [ "$_HAS_NODE" = "true" ] && [ -d "$TRACKER_DEVFLOW_DIR" ]; then
|
|
1059
|
+
if _sc_audit_stamp_blocked; then
|
|
1060
|
+
dbg "claude-md audit skipped: the stamp path is a link or not a regular file"
|
|
1061
|
+
else
|
|
1062
|
+
_SC_AUDIT_CLAUDE_DIR="$HOME/.claude"
|
|
1063
|
+
case "${CLAUDE_CONFIG_DIR:-}" in /*) _SC_AUDIT_CLAUDE_DIR="$CLAUDE_CONFIG_DIR" ;; esac
|
|
1064
|
+
_SC_AUDIT_ROOTS=("$_SC_AUDIT_CLAUDE_DIR/CLAUDE.md")
|
|
1065
|
+
if [ -n "$PROJECT_OK" ]; then
|
|
1066
|
+
_SC_AUDIT_ROOTS+=("$PROJECT_ROOT/CLAUDE.md" "$PROJECT_ROOT/.claude/CLAUDE.md" "$PROJECT_ROOT/CLAUDE.local.md")
|
|
1067
|
+
fi
|
|
1068
|
+
if _sc_audit_stamp_fresh; then
|
|
1069
|
+
dbg "claude-md audit skipped: the stamp is current"
|
|
1070
|
+
elif _sc_audit_no_root; then
|
|
1071
|
+
dbg "claude-md audit skipped: no root exists — recording that"
|
|
1072
|
+
_sc_audit_shell_stamp absent
|
|
1073
|
+
else
|
|
1074
|
+
_sc_audit_run
|
|
1075
|
+
fi
|
|
1076
|
+
fi
|
|
1077
|
+
fi
|
|
1078
|
+
|
|
782
1079
|
# --- Output ---
|
|
783
1080
|
|
|
784
|
-
# Only output if we have something to inject
|
|
785
|
-
|
|
1081
|
+
# Only output if we have something to inject or to tell the user. The stamp is
|
|
1082
|
+
# recorded here too: an audit that found nothing to show still ran, and recording it
|
|
1083
|
+
# is what makes the next unchanged start free.
|
|
1084
|
+
if [ -z "$CONTEXT" ] && [ -z "$SYSTEM_MESSAGE" ]; then
|
|
786
1085
|
dbg "EXIT: no context to inject"
|
|
1086
|
+
_sc_audit_record
|
|
787
1087
|
exit 0
|
|
788
1088
|
fi
|
|
789
1089
|
|
|
@@ -791,5 +1091,13 @@ dbg "OUTPUT_LENGTH=${#CONTEXT}"
|
|
|
791
1091
|
log "Injecting context (${#CONTEXT} chars)"
|
|
792
1092
|
dbg "=== HOOK COMPLETE ==="
|
|
793
1093
|
|
|
794
|
-
# Output as additionalContext JSON envelope (Claude sees it as system context, not
|
|
795
|
-
|
|
1094
|
+
# Output as additionalContext JSON envelope (Claude sees it as system context, not
|
|
1095
|
+
# user-visible). The audit text, if any, travels in the envelope's top-level
|
|
1096
|
+
# systemMessage and never in the context (D-SYSTEMMESSAGE-ENVELOPE). With no message
|
|
1097
|
+
# the second argument is empty and the envelope is the one callers always got.
|
|
1098
|
+
json_session_output "$CONTEXT" "$SYSTEM_MESSAGE"
|
|
1099
|
+
_SC_OUT_RC=$?
|
|
1100
|
+
|
|
1101
|
+
# A finding is recorded as displayed only after it was shown (D-AUDIT-STAMP).
|
|
1102
|
+
if [ "$_SC_OUT_RC" -eq 0 ]; then _sc_audit_record; fi
|
|
1103
|
+
exit "$_SC_OUT_RC"
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agent-references
|
|
3
|
+
description: Agent-owned reference files, read by explicit path, never preloaded
|
|
4
|
+
user-invocable: false
|
|
5
|
+
disable-model-invocation: true
|
|
6
|
+
allowed-tools: Read
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Agent References
|
|
10
|
+
|
|
11
|
+
<!-- D-AGENT-REFS: a reference-only skill. It holds text that one agent mode needs and the
|
|
12
|
+
other modes do not, so the agent body stays small and the spawn reads one file on demand.
|
|
13
|
+
D-MODE-BY-PATH: Synthesize reads exactly one synthesize/{mode}.md by explicit path.
|
|
14
|
+
D-MAINTAIN-ON-DUE: Learning reads learning/maintain.md only after claim-due hands out an entry. -->
|
|
15
|
+
|
|
16
|
+
## Iron Law
|
|
17
|
+
|
|
18
|
+
> **READ BY EXPLICIT PATH ONLY; NEVER PRELOAD**
|
|
19
|
+
>
|
|
20
|
+
> An agent that owns a file here names its full path in its own body and reads it with the
|
|
21
|
+
> Read tool when its mode needs it. No agent `skills:` list and no plugin preload names this
|
|
22
|
+
> skill: a preload would put every file in every spawn and undo the saving.
|
|
23
|
+
|
|
24
|
+
## Files
|
|
25
|
+
|
|
26
|
+
| Path under `references/` | Owner | Read when |
|
|
27
|
+
|--------------------------|-------|-----------|
|
|
28
|
+
| `synthesize/{mode}.md` | Synthesize | The prompt's `Mode:` line names `{mode}` |
|
|
29
|
+
| `learning/maintain.md` | Learning | `claim-due` hands out at least one entry |
|
|
30
|
+
|
|
31
|
+
The installed directory is `${CLAUDE_CONFIG_DIR:-$HOME/.claude}/skills/devflow:agent-references/`.
|
|
32
|
+
The model never invokes this skill: `disable-model-invocation: true` keeps it out of the
|
|
33
|
+
model's own skill choices, and `user-invocable: false` keeps it out of the slash menu.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
## Part 2 — Maintain the due entries
|
|
2
|
+
|
|
3
|
+
You read this because `claim-due` handed out at least one entry. Its output is in your context.
|
|
4
|
+
|
|
5
|
+
The first line, `ref <origin/HEAD|HEAD> <sha12>`, names the verify ref: check every claim
|
|
6
|
+
at that ref (`git show <ref>:<path>`). Each further line, `<anchor> <reason> <bytes>`, is
|
|
7
|
+
one due entry. The reason is one or more integrity flags joined by `,` —
|
|
8
|
+
`duplicate-obs-id` (two active entries share one observation), `ledger-without-log` (the
|
|
9
|
+
entry's observation is gone from the log), `scope-matches-nothing` (no tracked file
|
|
10
|
+
matches its scope) — or `legacy-v1` (a v1 entry) or `verify-age` (not verified for over
|
|
11
|
+
30 days). Each entry is leased for a day, so whatever you leave unfinished comes back.
|
|
12
|
+
`ref none` means there is no commit to check against: leave every
|
|
13
|
+
due entry as it is.
|
|
14
|
+
|
|
15
|
+
**LLM judgment — the maintenance ladder.** For each due entry, run `show <anchor>`. A
|
|
16
|
+
`ledger-without-log` entry first gets its observation back: `put-observation --create`
|
|
17
|
+
under the same id, carrying the entry's content in the entry format, which re-projects
|
|
18
|
+
the entry. Then take the first rung that matches. Exactly one final action per entry;
|
|
19
|
+
when unsure, Keep.
|
|
20
|
+
|
|
21
|
+
1. **Encoded** — the codebase now enforces or states the rule, by a strict bar: a test or
|
|
22
|
+
guard that fails on a new violation anywhere in the entry's scope, or the rule stated in
|
|
23
|
+
CLAUDE.md, a rules file, or a prompt loaded for all work in that scope. One JSDoc line
|
|
24
|
+
does not count, and neither does a test pinning one instance. Find it with `git grep -P`,
|
|
25
|
+
confirm it at the ref, then retire the entry with the file and a line of it:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
cd "<project root>" && node "$HOME/.devflow/scripts/hooks/json-helper.cjs" retire-anchor <anchor> Encoded <<'EOF'
|
|
29
|
+
{"at": "<path from the repository root>", "quote": "<one line of that file, 12 to 200 characters>"}
|
|
30
|
+
EOF
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The op checks the quote in the file as committed at the verify ref. A refusal saying
|
|
34
|
+
`the quote is not in …` or `… is not a file at …` means the encoding is not there yet:
|
|
35
|
+
Keep the entry.
|
|
36
|
+
2. **No longer true at the ref** — the code the rule governs is gone or changed so the rule
|
|
37
|
+
cannot apply; `scope-matches-nothing` is a prompt to check. A missing file is not proof
|
|
38
|
+
alone: an entry that records removing or replacing something is confirmed by the
|
|
39
|
+
absence. When the lesson still applies elsewhere, rewrite it (`put-observation --update`
|
|
40
|
+
with a corrected scope) and Keep it; otherwise retire it as `Retired`.
|
|
41
|
+
3. **Duplicate** — another active entry covers the same concern; `duplicate-obs-id` always
|
|
42
|
+
means one does. Choose the survivor: the more precise entry, or the more accurate type
|
|
43
|
+
when an ADR and a PF cover one incident. Absorb what only the other says into the
|
|
44
|
+
survivor with `put-observation --update`, then retire the other as `Superseded` by the
|
|
45
|
+
survivor.
|
|
46
|
+
4. **One-off** — it recorded a single incident with no general lesson: retire it as `Retired`.
|
|
47
|
+
5. **Keep** — every other entry. Rewrite it only when it is legacy (`legacy-v1`), wrong or
|
|
48
|
+
vague: `put-observation --update` with its whole content, which also converts a v1 entry
|
|
49
|
+
to v2. Before rewriting a v1 entry, read the `flags` of its `show`: `ledger-only-content`
|
|
50
|
+
names details only its ledger row holds — carry over what is still true; history and the
|
|
51
|
+
pre-v2 backup keep the rest.
|
|
52
|
+
|
|
53
|
+
After each maintained entry, refresh the claim (Step 0).
|
|
54
|
+
|
|
55
|
+
**RETIRE BY STATUS — never hand-edit the .md.** `retire-anchor <anchor> <status>` takes one
|
|
56
|
+
JSON object on stdin, by status, and refuses a key the status does not take:
|
|
57
|
+
|
|
58
|
+
- `Retired`, `Deprecated`: `{"reason": "<why, one line, 1 to 120 characters>"}`
|
|
59
|
+
- `Superseded`: `{"by": "<anchor>"}` — an active entry other than this one, of either type
|
|
60
|
+
- `Encoded`: `at` and `quote`, as in rung 1
|
|
61
|
+
|
|
62
|
+
**Close with one batch** listing every entry you kept, rewritten or not (skip it when you
|
|
63
|
+
kept none):
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
cd "<project root>" && node "$HOME/.devflow/scripts/hooks/json-helper.cjs" refresh-anchor <anchor> [<anchor>...] --verified
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
List only active v2 entries — a v1 entry refuses the whole batch, which is why a kept v1
|
|
70
|
+
entry is rewritten first. A refused batch names each refused anchor: drop those and run
|
|
71
|
+
it once more.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
## Mode: Bug Analysis
|
|
2
|
+
|
|
3
|
+
Synthesize outputs from multiple Diagnose agents into a single actionable bug report.
|
|
4
|
+
|
|
5
|
+
**Input:**
|
|
6
|
+
- **ANALYSIS_BASE_DIR**: Timestamped directory containing `{focus}.md` files and `static-findings.md`
|
|
7
|
+
- **BRANCH**: Branch name and base branch
|
|
8
|
+
- **TIMESTAMP**: ISO timestamp for the report
|
|
9
|
+
|
|
10
|
+
**Process:**
|
|
11
|
+
1. Read all `{focus}.md` files from `${ANALYSIS_BASE_DIR}` — exclude `bug-analysis-summary.md` and `static-findings.md`
|
|
12
|
+
2. Also read `${ANALYSIS_BASE_DIR}/static-findings.md` if it exists (contains raw tool output)
|
|
13
|
+
3. Extract all bugs with their confidence percentages and static tool source (if noted)
|
|
14
|
+
4. Cross-track confidence: findings that appear in both `static-findings.md` and a focus report get +10% confidence boost (static-confirmed)
|
|
15
|
+
5. Deduplicate: same file:line from multiple analyzers → keep highest confidence, boost +10% per additional agent (cap 100%)
|
|
16
|
+
6. Merge acceptance criteria coverage tables from the functional analyzer (if present)
|
|
17
|
+
7. Sort bugs by severity (CRITICAL → HIGH → MEDIUM → LOW), then by confidence descending within each severity
|
|
18
|
+
8. Determine overall risk assessment: highest severity of any CRITICAL/HIGH bug found
|
|
19
|
+
|
|
20
|
+
**Output:**
|
|
21
|
+
**CRITICAL**: Write the summary to disk using the Write tool:
|
|
22
|
+
1. Create directory: `mkdir -p ${ANALYSIS_BASE_DIR}`
|
|
23
|
+
2. Write to `${ANALYSIS_BASE_DIR}/bug-analysis-summary.md` using Write tool
|
|
24
|
+
3. Confirm file written in final message
|
|
25
|
+
|
|
26
|
+
Report format:
|
|
27
|
+
|
|
28
|
+
```markdown
|
|
29
|
+
# Bug Analysis Summary
|
|
30
|
+
|
|
31
|
+
**Branch**: {branch} -> {base}
|
|
32
|
+
**Date**: {timestamp}
|
|
33
|
+
|
|
34
|
+
## Risk Assessment: {CRITICAL | HIGH | MEDIUM | LOW | CLEAN}
|
|
35
|
+
|
|
36
|
+
{Brief reasoning — what drives the risk level, or "No bugs found above confidence threshold."}
|
|
37
|
+
|
|
38
|
+
## Bug Summary
|
|
39
|
+
| Category | CRITICAL | HIGH | MEDIUM | LOW | Total |
|
|
40
|
+
|----------|----------|------|--------|-----|-------|
|
|
41
|
+
| Security | {n} | {n} | {n} | {n} | {n} |
|
|
42
|
+
| Functional | {n} | {n} | {n} | {n} | {n} |
|
|
43
|
+
| Integration | {n} | {n} | {n} | {n} | {n} |
|
|
44
|
+
| Usability | {n} | {n} | {n} | {n} | {n} |
|
|
45
|
+
|
|
46
|
+
## Critical & High Bugs
|
|
47
|
+
|
|
48
|
+
{For each CRITICAL and HIGH bug (sorted by severity then confidence):}
|
|
49
|
+
**{Title}** — `file:line` ({n}% confidence, {Category})
|
|
50
|
+
- Problem: {description}
|
|
51
|
+
- Fix: {suggestion}
|
|
52
|
+
|
|
53
|
+
## Acceptance Criteria Status
|
|
54
|
+
|
|
55
|
+
(Omit section if no functional analyzer produced acceptance criteria coverage)
|
|
56
|
+
|
|
57
|
+
| ID | Criterion | Status | Evidence |
|
|
58
|
+
|----|-----------|--------|----------|
|
|
59
|
+
| {id} | {criterion} | PASS / FAIL / NOT_TESTED | {file:line or note} |
|
|
60
|
+
|
|
61
|
+
## Suggestions (Lower Confidence)
|
|
62
|
+
|
|
63
|
+
{Max 5 items across all analyzers with 60-79% confidence. Brief description only.}
|
|
64
|
+
|
|
65
|
+
- **{Issue}** — `file.ts:456` ({n}%, {Category}) — {brief description}
|
|
66
|
+
|
|
67
|
+
## Action Plan
|
|
68
|
+
1. {Highest-priority fix — CRITICAL or first HIGH}
|
|
69
|
+
2. {Next priority fix}
|
|
70
|
+
3. {Additional fixes in priority order}
|
|
71
|
+
```
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
## Mode: Design
|
|
2
|
+
|
|
3
|
+
Synthesize outputs from multiple Design agents (gap analysis across different focus areas).
|
|
4
|
+
|
|
5
|
+
**Process:**
|
|
6
|
+
1. Extract findings from each Design agent
|
|
7
|
+
2. Deduplicate: If multiple Design agents flag the same issue, boost confidence by 10% per additional agent (cap at 100%). **Exception — merge, don't boost:** a compliance finding and a security finding at the same location (same file:line or same design element) identify a single gap from two regulatory angles — merge into one finding, do not apply the confidence boost. Multi-agent agreement on a compliance+security overlap is not corroboration; it is one gap seen by two lenses.
|
|
8
|
+
3. Categorize by actionability:
|
|
9
|
+
- **Blocking** (CRITICAL/HIGH): Must be resolved before implementation
|
|
10
|
+
- **Should-Address** (MEDIUM): Recommended improvements
|
|
11
|
+
- **Informational** (LOW): Noted but not actionable
|
|
12
|
+
4. Sort by severity within each category
|
|
13
|
+
|
|
14
|
+
**Output:**
|
|
15
|
+
```markdown
|
|
16
|
+
## Design Synthesis
|
|
17
|
+
|
|
18
|
+
### Blocking Gaps
|
|
19
|
+
| Gap | Focus | Severity | Confidence | Resolution |
|
|
20
|
+
|-----|-------|----------|------------|------------|
|
|
21
|
+
| {gap} | {focus area} | {CRITICAL/HIGH} | {n}% | {proposed resolution} |
|
|
22
|
+
|
|
23
|
+
### Should-Address
|
|
24
|
+
| Gap | Focus | Severity | Confidence | Recommendation |
|
|
25
|
+
|-----|-------|----------|------------|----------------|
|
|
26
|
+
| {gap} | {focus area} | MEDIUM | {n}% | {recommendation} |
|
|
27
|
+
|
|
28
|
+
### Informational
|
|
29
|
+
| Gap | Focus | Confidence | Note |
|
|
30
|
+
|-----|-------|------------|------|
|
|
31
|
+
| {gap} | {focus area} | {n}% | {note} |
|
|
32
|
+
|
|
33
|
+
### Key Insights
|
|
34
|
+
1. {cross-cutting insight}
|
|
35
|
+
2. {insight}
|
|
36
|
+
```
|