devflow-kit 2.4.0 → 3.0.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 +229 -0
- package/README.md +111 -18
- package/dist/agents/git.md +822 -0
- package/dist/cli/commands/agents.js +6 -1
- package/dist/cli/commands/ambient.js +160 -145
- package/dist/cli/commands/attribution-prompts.js +1 -1
- package/dist/cli/commands/capture.js +29 -55
- package/dist/cli/commands/compliance-prompts.js +1 -1
- package/dist/cli/commands/compliance.js +48 -55
- package/dist/cli/commands/context.js +17 -32
- package/dist/cli/commands/debug.js +65 -26
- package/dist/cli/commands/flags.js +3 -3
- package/dist/cli/commands/hud.js +34 -10
- package/dist/cli/commands/init-seed.js +61 -27
- package/dist/cli/commands/init.js +649 -240
- package/dist/cli/commands/install-report.js +200 -0
- package/dist/cli/commands/knowledge/index.js +2 -2
- package/dist/cli/commands/knowledge/toggle.js +35 -37
- package/dist/cli/commands/learning.js +79 -57
- package/dist/cli/commands/legacy-hooks.js +11 -14
- package/dist/cli/commands/memory.js +134 -135
- package/dist/cli/commands/prompt-io.js +4 -4
- package/dist/cli/commands/proxy.js +23 -41
- package/dist/cli/commands/security.js +81 -29
- package/dist/cli/commands/skills.js +71 -7
- package/dist/cli/commands/tracker-prompts.js +145 -0
- package/dist/cli/commands/tracker.js +277 -0
- package/dist/cli/commands/uninstall.js +520 -169
- package/dist/cli.js +2 -0
- package/dist/commands/bug-analysis.md +58 -14
- package/dist/commands/code-review.md +110 -32
- package/dist/commands/debug.md +55 -11
- package/dist/commands/dynamic-build.md +344 -73
- package/dist/commands/dynamic-plan.md +77 -27
- package/dist/commands/dynamic-profile.md +25 -11
- package/dist/commands/dynamic-tickets.md +76 -15
- package/dist/commands/explore.md +37 -7
- package/dist/commands/implement.md +314 -62
- package/dist/commands/plan.md +146 -32
- package/dist/commands/release.md +64 -17
- package/dist/commands/research.md +34 -8
- package/dist/commands/resolve.md +196 -68
- package/dist/commands/self-review.md +45 -9
- package/dist/core/agent-models.js +55 -12
- package/dist/core/assets.js +58 -2
- package/dist/core/compliance-compose.js +27 -27
- package/dist/core/evidence-policy.js +363 -0
- package/dist/core/feature-config.js +200 -65
- package/dist/core/feature-switch.js +112 -0
- package/dist/core/flags.js +34 -6
- package/dist/core/fs-atomic.js +27 -0
- package/dist/core/hook-log-dirs.js +104 -0
- package/dist/core/learning-tuning-config.js +5 -3
- package/dist/core/ledger-root.js +102 -0
- package/dist/core/manifest.js +38 -10
- package/dist/core/mds-variants.js +798 -0
- package/dist/core/migrations.js +49 -23
- package/dist/core/model-discovery.js +12 -1
- package/dist/core/plugins.js +361 -12
- package/dist/core/project-paths.js +1 -18
- package/dist/core/proxy-log.js +8 -6
- package/dist/core/proxy-state.js +11 -8
- package/dist/core/reference-sweep.js +136 -0
- package/dist/core/same-location.js +25 -0
- package/dist/core/tracker.js +494 -0
- package/dist/hud/components/config-counts.js +15 -4
- package/dist/hud/components/learning-counts.js +14 -0
- package/dist/hud/config.js +2 -1
- package/dist/hud/cost-history.js +2 -4
- package/dist/hud/git.js +52 -7
- package/dist/hud/index.js +7 -9
- package/dist/skills/git/references/decision-markers.md +19 -0
- package/dist/skills/git/references/learn-conventions.md +56 -0
- package/dist/skills/git/references/pr/check-ci-status.md +14 -0
- package/dist/skills/git/references/pr/check-merge-readiness.md +28 -0
- package/dist/skills/git/references/pr/ensure-pr-ready.md +24 -0
- package/dist/skills/git/references/pr/fetch-review-threads.md +22 -0
- package/dist/skills/git/references/pr/post-resolution-summary.md +40 -0
- package/dist/skills/git/references/pr/post-review-summary.md +42 -0
- package/dist/skills/git/references/pr/resolve-review-threads.md +35 -0
- package/dist/skills/git/references/pr/update-pr-evidence.md +14 -0
- package/dist/skills/git/references/pr/validate-branch.md +18 -0
- package/dist/skills/git/references/publication-gate.md +13 -0
- package/dist/skills/git/references/tracker/_mcp.md +153 -0
- package/dist/skills/git/references/tracker/github/associate-release.md +18 -0
- package/dist/skills/git/references/tracker/github/backlink-shipped-issues.md +40 -0
- package/dist/skills/git/references/tracker/github/create-release.md +11 -0
- package/dist/skills/git/references/tracker/github/ensure-pr-ready.md +16 -0
- package/dist/skills/git/references/tracker/github/ensure-traceable-issue.md +69 -0
- package/dist/skills/git/references/tracker/github/fetch-issue.md +32 -0
- package/dist/skills/git/references/tracker/github/fetch-issues-batch.md +17 -0
- package/dist/skills/git/references/tracker/github/gather-release-evidence.md +19 -0
- package/dist/skills/git/references/tracker/github/manage-debt.md +101 -0
- package/dist/skills/git/references/tracker/github/post-wave-report.md +28 -0
- package/dist/skills/git/references/tracker/github/setup-task.md +26 -0
- package/dist/skills/git/references/tracker/jira/associate-release.md +18 -0
- package/dist/skills/git/references/tracker/jira/backlink-shipped-issues.md +49 -0
- package/dist/skills/git/references/tracker/jira/create-release.md +17 -0
- package/dist/skills/git/references/tracker/jira/ensure-pr-ready.md +22 -0
- package/dist/skills/git/references/tracker/jira/ensure-traceable-issue.md +53 -0
- package/dist/skills/git/references/tracker/jira/fetch-issue.md +14 -0
- package/dist/skills/git/references/tracker/jira/fetch-issues-batch.md +15 -0
- package/dist/skills/git/references/tracker/jira/gather-release-evidence.md +18 -0
- package/dist/skills/git/references/tracker/jira/manage-debt.md +37 -0
- package/dist/skills/git/references/tracker/jira/post-wave-report.md +33 -0
- package/dist/skills/git/references/tracker/jira/setup-task.md +31 -0
- package/dist/skills/git/references/tracker/linear/associate-release.md +18 -0
- package/dist/skills/git/references/tracker/linear/backlink-shipped-issues.md +53 -0
- package/dist/skills/git/references/tracker/linear/create-release.md +17 -0
- package/dist/skills/git/references/tracker/linear/ensure-pr-ready.md +22 -0
- package/dist/skills/git/references/tracker/linear/ensure-traceable-issue.md +53 -0
- package/dist/skills/git/references/tracker/linear/fetch-issue.md +14 -0
- package/dist/skills/git/references/tracker/linear/fetch-issues-batch.md +15 -0
- package/dist/skills/git/references/tracker/linear/gather-release-evidence.md +18 -0
- package/dist/skills/git/references/tracker/linear/manage-debt.md +37 -0
- package/dist/skills/git/references/tracker/linear/post-wave-report.md +33 -0
- package/dist/skills/git/references/tracker/linear/setup-task.md +32 -0
- package/dist/skills/git/references/trust-rule.md +7 -0
- package/dist/targets/claude-code/claude-paths.js +59 -57
- package/dist/targets/claude-code/compliance-install.js +49 -65
- package/dist/targets/claude-code/hooks.js +108 -3
- package/dist/targets/claude-code/installer.js +1187 -32
- package/dist/targets/claude-code/legacy.js +5 -0
- package/dist/targets/claude-code/post-install.js +366 -151
- package/dist/targets/claude-code/tracker-install.js +134 -0
- package/package.json +8 -6
- package/src/assets/agents/code.md +45 -6
- package/src/assets/agents/design.md +2 -1
- package/src/assets/agents/git.mds +825 -0
- package/src/assets/agents/knowledge.md +3 -3
- package/src/assets/agents/learning.md +11 -0
- package/src/assets/agents/review.md +3 -1
- package/src/assets/agents/synthesize.md +1 -1
- package/src/assets/agents/test.md +16 -5
- package/src/assets/agents/tracker.md +474 -0
- package/src/assets/agents/validate.md +7 -5
- package/src/assets/commands/_partials/_compliance.mds +19 -1
- package/src/assets/commands/_partials/_decisions.mds +15 -3
- package/src/assets/commands/_partials/_docs_root.mds +35 -0
- package/src/assets/commands/_partials/_engine.mds +13 -11
- package/src/assets/commands/_partials/_evidence_policy.mds +30 -0
- package/src/assets/commands/_partials/_factory.mds +1 -1
- package/src/assets/commands/_partials/_knowledge.mds +27 -9
- package/src/assets/commands/_partials/_plan_contract.mds +22 -7
- package/src/assets/commands/_partials/_preamble.mds +2 -2
- package/src/assets/commands/_partials/_publication.mds +8 -2
- package/src/assets/commands/_partials/_settings.mds +28 -0
- package/src/assets/commands/_partials/_ticket_template.mds +3 -2
- package/src/assets/commands/_partials/_tracker.mds +18 -0
- package/src/assets/commands/_partials/_wave.mds +16 -10
- package/src/assets/commands/bug-analysis.mds +31 -19
- package/src/assets/commands/code-review.mds +67 -41
- package/src/assets/commands/debug.mds +13 -7
- package/src/assets/commands/dynamic-build.mds +274 -66
- package/src/assets/commands/dynamic-plan.mds +50 -23
- package/src/assets/commands/dynamic-profile.mds +24 -11
- package/src/assets/commands/dynamic-tickets.mds +63 -16
- package/src/assets/commands/explore.mds +4 -5
- package/src/assets/commands/implement.mds +234 -67
- package/src/assets/commands/plan.mds +91 -33
- package/src/assets/commands/release.md +64 -17
- package/src/assets/commands/research.mds +11 -9
- package/src/assets/commands/resolve.mds +150 -78
- package/src/assets/commands/self-review.mds +24 -25
- package/src/assets/mds/git/_pr.mds +331 -0
- package/src/assets/mds/git/_references.mds +135 -0
- package/src/assets/mds/tracker/_common.mds +156 -0
- package/src/assets/mds/tracker/_github.mds +472 -0
- package/src/assets/mds/tracker/_jira.mds +407 -0
- package/src/assets/mds/tracker/_linear.mds +449 -0
- package/src/assets/mds/tracker/_mcp.mds +305 -0
- package/src/assets/scripts/hooks/assets/orchestrator-charter.md +5 -8
- package/src/assets/scripts/hooks/background-memory-update +40 -19
- package/src/assets/scripts/hooks/capture-prompt +18 -8
- package/src/assets/scripts/hooks/capture-question +18 -8
- package/src/assets/scripts/hooks/capture-turn +27 -13
- package/src/assets/scripts/hooks/debug-trace +11 -6
- package/src/assets/scripts/hooks/ensure-devflow-init +33 -6
- package/src/assets/scripts/hooks/ensure-proxy +9 -8
- package/src/assets/scripts/hooks/ensure-root-gitignore +236 -60
- package/src/assets/scripts/hooks/git-marker +48 -0
- package/src/assets/scripts/hooks/hook-log-init +3 -1
- package/src/assets/scripts/hooks/json-helper.cjs +228 -5
- package/src/assets/scripts/hooks/lib/project-paths.cjs +1 -20
- package/src/assets/scripts/hooks/log-paths +80 -0
- package/src/assets/scripts/hooks/memory-worker +22 -13
- package/src/assets/scripts/hooks/pre-compact-memory +44 -15
- package/src/assets/scripts/hooks/preamble +1 -4
- package/src/assets/scripts/hooks/queue-append +146 -28
- package/src/assets/scripts/hooks/resolve-project-root +101 -7
- package/src/assets/scripts/hooks/session-start-context +534 -20
- package/src/assets/scripts/hooks/session-start-memory +38 -15
- package/src/assets/scripts/lib/project-config.cjs +633 -0
- package/src/assets/scripts/pr-evidence.cjs +1961 -0
- package/src/assets/scripts/redact-secrets.cjs +490 -62
- package/src/assets/scripts/release-trace.cjs +1143 -0
- package/src/assets/scripts/resolve-evidence-policy.cjs +1145 -0
- package/src/assets/scripts/resolve-settings.cjs +1054 -0
- package/src/assets/scripts/verify-evidence.cjs +1822 -0
- package/src/assets/skills/compliance/SKILL.md +4 -2
- package/src/assets/skills/docs-framework/SKILL.md +11 -10
- package/src/assets/skills/docs-framework/references/patterns.md +10 -17
- package/src/assets/skills/gap-analysis/SKILL.md +2 -2
- package/src/assets/skills/git/SKILL.md +8 -78
- package/src/assets/skills/git/references/github-api.md +179 -141
- package/src/assets/skills/git/references/patterns.md +11 -6
- package/src/assets/skills/review-methodology/SKILL.md +1 -1
- package/src/assets/skills/review-methodology/references/patterns.md +6 -61
- package/src/assets/skills/review-methodology/references/violations.md +14 -22
- package/src/assets/skills/worktree-support/SKILL.md +1 -1
- package/src/assets/skills/worktree-support/references/roots.md +29 -0
- package/src/targets/claude-code/templates/managed-settings.json +25 -9
- package/src/assets/agents/git.md +0 -938
|
@@ -22,18 +22,55 @@
|
|
|
22
22
|
# queue_append_both <memory_queue> <learning_queue> <memory_enabled> <learning_enabled> <role> <content> <ts>
|
|
23
23
|
# Calls queue_append_row for each queue whose *_enabled flag is "true". Each
|
|
24
24
|
# queue is gated independently -- callers compute memory_enabled/learning_enabled
|
|
25
|
-
#
|
|
26
|
-
# combined read that keeps this to a single config subprocess per hook).
|
|
25
|
+
# themselves (see queue_read_gates below for the at-most-one-fork read of both).
|
|
27
26
|
#
|
|
28
|
-
# queue_read_gates <
|
|
29
|
-
# Reads BOTH
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
# caller's scope.
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
#
|
|
27
|
+
# queue_read_gates <manifest_path> [<root>]
|
|
28
|
+
# Reads BOTH switches, `memory` and `learning`, in at most ONE subprocess fork
|
|
29
|
+
# (AC-P1 -- at most one gate-read fork per capture hook, not two; none when
|
|
30
|
+
# the fast paths settle it). Sets _QG_MEMORY and _QG_LEARNING ("true"/"false")
|
|
31
|
+
# in the caller's scope. The two values are newline-separated
|
|
32
|
+
# rather than using a control-character delimiter: they are always the literal
|
|
33
|
+
# strings "true"/"false", never arbitrary content, so a plain newline split is
|
|
34
|
+
# unambiguous and easy to review (no invisible bytes hiding in the source).
|
|
35
|
+
#
|
|
36
|
+
# D-FEATURES-NARROW-ONLY (src/core/feature-switch.ts): a switch is on iff the
|
|
37
|
+
# machine switch is on AND neither repository file sets `features.<name>` to
|
|
38
|
+
# the literal `false` -- the rule resolve-settings.cjs folds, held to the same
|
|
39
|
+
# answers by the shared table tests/fixtures/settings-switch-table.ts (TP-49).
|
|
40
|
+
# A repository can switch memory or learning off for itself, never back on.
|
|
41
|
+
# machine <manifest_path>, the ~/.devflow/manifest.json `devflow init` and
|
|
42
|
+
# `devflow memory|learning --enable/--disable` write. Only an
|
|
43
|
+
# explicit boolean `false` switches a feature off -- an absent,
|
|
44
|
+
# unreadable or malformed manifest, a missing key, or a non-boolean
|
|
45
|
+
# value leaves it ON (fail-open, ADR-028), the rule
|
|
46
|
+
# isMachineFeatureOn() applies in the CLI.
|
|
47
|
+
# project <root>/.devflow/project.json (team-committed) and
|
|
48
|
+
# personal <root>/.devflow/config.json (this worktree's own), read ONLY under
|
|
49
|
+
# `features.memory` / `features.learning`. The retired top-level
|
|
50
|
+
# keys (`memory`, `learning`, `decisions`) and `features.decisions`
|
|
51
|
+
# narrow nothing (#378: reading them let a feature run in every repo
|
|
52
|
+
# but one). An invalid file -- unparseable, over 4096 bytes, a BOM,
|
|
53
|
+
# a symlink, a duplicated key -- narrows nothing.
|
|
54
|
+
# <root> is the checkout's toplevel (DF_ROOT, which every caller holds as
|
|
55
|
+
# $PROJECT_ROOT), for learning too: project.json is committed per branch and
|
|
56
|
+
# config.json lives per worktree, so both are read where the session runs, as
|
|
57
|
+
# resolve-settings.cjs reads them -- never at DF_LEDGER_ROOT, which only says
|
|
58
|
+
# where the queue lands. Without <root> (or with an empty one) no repository
|
|
59
|
+
# file is read.
|
|
60
|
+
#
|
|
61
|
+
# D-LEARNING-LEGACY-DECISIONS: in the MANIFEST only, learning reads
|
|
62
|
+
# `features.learning` when it is a boolean, else the pre-rename
|
|
63
|
+
# `features.decisions` (ADR-011) -- readManifest's migration precedence
|
|
64
|
+
# exactly, so a legacy `decisions: false` switches learning off before any
|
|
65
|
+
# command has healed the file. Only a boolean `false` in whichever key decides
|
|
66
|
+
# is off, as above.
|
|
67
|
+
#
|
|
68
|
+
# Every hook that gates on memory or learning reads it through here: the
|
|
69
|
+
# capture hooks, session-start-context (Sections 1-2), memory-worker,
|
|
70
|
+
# session-start-memory, pre-compact-memory and background-memory-update. The
|
|
71
|
+
# callers pass <manifest_path> as $HOME/.devflow/manifest.json, the machine
|
|
72
|
+
# root (D-ONE-HOME); memory-worker hands its resolved path to the background
|
|
73
|
+
# worker it spawns.
|
|
37
74
|
|
|
38
75
|
queue_append_row() {
|
|
39
76
|
local _qar_file="$1" _qar_role="$2" _qar_content="$3" _qar_ts="$4"
|
|
@@ -83,34 +120,115 @@ queue_append_both() {
|
|
|
83
120
|
fi
|
|
84
121
|
}
|
|
85
122
|
|
|
123
|
+
# _qg_repo_file_can_narrow <file> -- succeeds when <file> COULD set
|
|
124
|
+
# features.memory or features.learning to false, so only the parser can decide
|
|
125
|
+
# it; fails when it certainly cannot. Builtins only: no fork.
|
|
126
|
+
#
|
|
127
|
+
# D-GATES-FAST-PATH (repository files): the read is bounded -- `-n 4097`, which
|
|
128
|
+
# bash 3.2 supports -- and `read -d ''` succeeds only when it stops short of the
|
|
129
|
+
# end of the file: at a NUL byte (never valid in JSON) or at 4097 characters,
|
|
130
|
+
# which is more than MAX_CONFIG_BYTES (4096) bytes. Either way the parser would
|
|
131
|
+
# call the file invalid, and an invalid file narrows nothing. `-f` follows a
|
|
132
|
+
# symlink and refuses a directory or FIFO, so nothing here can block; the parser
|
|
133
|
+
# itself refuses the symlink. A `\u` escape is the only JSON spelling of a
|
|
134
|
+
# letter other than the letter itself, so without one a narrowing file shows
|
|
135
|
+
# `"features"`, then `{`, then `"memory"` or `"learning"`, then `false`,
|
|
136
|
+
# literally and in that order. `.` spans newlines (POSIX ERE without
|
|
137
|
+
# REG_NEWLINE), so the match can only over-report -- an over-report costs one
|
|
138
|
+
# fork and the parser's answer, never a wrong one. No `"decisions"` and no
|
|
139
|
+
# top-level key before `features` is ever matched.
|
|
140
|
+
_qg_repo_file_can_narrow() {
|
|
141
|
+
local _qgf_text=""
|
|
142
|
+
local _qgf_re='"features"[[:space:]]*:[[:space:]]*[{].*"(memory|learning)"[[:space:]]*:[[:space:]]*false'
|
|
143
|
+
[ -f "$1" ] || return 1
|
|
144
|
+
if IFS= read -r -d '' -n 4097 _qgf_text 2>/dev/null < "$1"; then return 1; fi
|
|
145
|
+
case "$_qgf_text" in *'\u'*) return 0 ;; esac
|
|
146
|
+
[[ $_qgf_text =~ $_qgf_re ]]
|
|
147
|
+
}
|
|
148
|
+
|
|
86
149
|
queue_read_gates() {
|
|
87
|
-
local
|
|
150
|
+
local _qg_manifest="${1:-}" _qg_root="${2:-}" _qg_text="" _qg_parse="false" _qg_repo="false" _qg_fields=""
|
|
88
151
|
_QG_MEMORY="true"
|
|
89
152
|
_QG_LEARNING="true"
|
|
90
153
|
|
|
91
|
-
if [ -f "$
|
|
92
|
-
|
|
154
|
+
if [ -n "$_qg_manifest" ] && [ -f "$_qg_manifest" ]; then
|
|
155
|
+
# D-GATES-FAST-PATH: every capture hook and every session start pays this
|
|
156
|
+
# read, and on most machines both switches are on. Only a JSON boolean
|
|
157
|
+
# `false` under a "memory", "learning" or "decisions" key can switch anything
|
|
158
|
+
# off, and a `\u` escape is the only JSON spelling of a letter other than the
|
|
159
|
+
# letter itself, so without one such a key appears literally. A text holding
|
|
160
|
+
# no `\u` and no key-then-`false` sequence therefore cannot switch anything
|
|
161
|
+
# off -- valid or not, it reads both-on either way -- and is settled by shell
|
|
162
|
+
# builtins (read, case, [[ =~ ]]) with no jq/node fork; everything else takes
|
|
163
|
+
# the full parse below. `read -d ''` succeeds only on reaching a NUL byte,
|
|
164
|
+
# i.e. before the end of the file, so a text it cut short is parsed in full
|
|
165
|
+
# too. An unreadable file reads empty and fails open, as the parser would.
|
|
166
|
+
local _qg_re='"(memory|learning|decisions)"[[:space:]]*:[[:space:]]*false'
|
|
167
|
+
IFS= read -r -d '' _qg_text 2>/dev/null < "$_qg_manifest" && _qg_parse="true"
|
|
168
|
+
case "$_qg_text" in *'\u'*) _qg_parse="true" ;; esac
|
|
169
|
+
if [[ $_qg_text =~ $_qg_re ]]; then _qg_parse="true"; fi
|
|
170
|
+
fi
|
|
171
|
+
|
|
172
|
+
if [ -n "$_qg_root" ]; then
|
|
173
|
+
if _qg_repo_file_can_narrow "$_qg_root/.devflow/project.json" \
|
|
174
|
+
|| _qg_repo_file_can_narrow "$_qg_root/.devflow/config.json"; then
|
|
175
|
+
_qg_repo="true"
|
|
176
|
+
fi
|
|
177
|
+
fi
|
|
178
|
+
|
|
179
|
+
if [ "$_qg_repo" = "true" ]; then
|
|
180
|
+
# The ONE fork when a repository file can narrow: node on the resolver's own
|
|
181
|
+
# readRepoLayers + foldSettings (resolve-settings.cjs, a sibling of this
|
|
182
|
+
# hooks/ directory), so every file rule -- symlink, size, BOM, fatal UTF-8,
|
|
183
|
+
# duplicate keys -- is the parser's, not a shell copy of it. It folds the
|
|
184
|
+
# manifest too, read only when the fast path above flagged it (an unflagged
|
|
185
|
+
# manifest is both-on), so a false in all three layers still costs one fork.
|
|
186
|
+
# jq cannot see duplicate keys, so this path is node whatever _HAS_JQ says.
|
|
187
|
+
local _qg_scripts="${BASH_SOURCE[0]%/*}/.." _qg_manifest_arg=""
|
|
188
|
+
[ "$_qg_parse" = "true" ] && _qg_manifest_arg="$_qg_manifest"
|
|
189
|
+
_qg_fields=$(node -e "
|
|
190
|
+
const S = require(require('path').resolve(process.argv[1], 'resolve-settings.cjs'));
|
|
191
|
+
let m;
|
|
192
|
+
if (process.argv[2] !== '') {
|
|
193
|
+
try { m = JSON.parse(require('fs').readFileSync(process.argv[2], 'utf8')); } catch (_) { m = undefined; }
|
|
194
|
+
}
|
|
195
|
+
const w = S.foldSettings(Object.assign({ manifest: m }, S.readRepoLayers(process.argv[3]))).switches;
|
|
196
|
+
process.stdout.write(String(w.memory.on) + String.fromCharCode(10) + String(w.learning.on));
|
|
197
|
+
" -- "$_qg_scripts" "$_qg_manifest_arg" "$_qg_root" 2>/dev/null) || _qg_fields=""
|
|
198
|
+
fi
|
|
199
|
+
|
|
200
|
+
# The manifest-only parse: when no repository file can narrow, or when the
|
|
201
|
+
# fork above failed (the manifest's answer still stands; the repository's is
|
|
202
|
+
# lost, which fails open like every other unreadable layer).
|
|
203
|
+
if [ -z "$_qg_fields" ] && [ "$_qg_parse" = "true" ]; then
|
|
93
204
|
if [ "$_HAS_JQ" = "true" ]; then
|
|
94
|
-
#
|
|
95
|
-
#
|
|
96
|
-
#
|
|
205
|
+
# `try` covers a manifest whose top level or `features` is not an object; a
|
|
206
|
+
# parse failure empties the output, which reads as "not switched off". The
|
|
207
|
+
# comma produces two raw-output lines (newline-separated) in one jq process.
|
|
97
208
|
_qg_fields=$(jq -r '
|
|
98
|
-
(if (.memory
|
|
99
|
-
(if (.learning | type) == "
|
|
100
|
-
|
|
209
|
+
(if (try .features.memory catch null) == false then "false" else "true" end),
|
|
210
|
+
(if (try (.features | if (.learning | type) == "boolean" then .learning else .decisions end) catch null) == false
|
|
211
|
+
then "false" else "true" end)
|
|
212
|
+
' "$_qg_manifest" 2>/dev/null) || _qg_fields=""
|
|
101
213
|
else
|
|
102
214
|
_qg_fields=$(node -e "
|
|
103
|
-
const
|
|
104
|
-
const
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
215
|
+
const m = JSON.parse(require('fs').readFileSync(process.argv[1], 'utf8'));
|
|
216
|
+
const f = m !== null && typeof m === 'object' ? m.features : undefined;
|
|
217
|
+
const isObj = f !== null && typeof f === 'object';
|
|
218
|
+
const on = (k) => !(isObj && f[k] === false);
|
|
219
|
+
const learnKey = isObj && typeof f.learning !== 'boolean' ? 'decisions' : 'learning';
|
|
220
|
+
process.stdout.write(String(on('memory')) + String.fromCharCode(10) + String(on(learnKey)));
|
|
221
|
+
" -- "$_qg_manifest" 2>/dev/null) || _qg_fields=""
|
|
108
222
|
fi
|
|
109
|
-
|
|
223
|
+
fi
|
|
224
|
+
|
|
225
|
+
# Only the four well-formed answers are taken; anything else is fail-open.
|
|
226
|
+
case "$_qg_fields" in
|
|
227
|
+
true$'\n'true|true$'\n'false|false$'\n'true|false$'\n'false)
|
|
110
228
|
_QG_MEMORY="${_qg_fields%%$'\n'*}"
|
|
111
229
|
_QG_LEARNING="${_qg_fields#*$'\n'}"
|
|
112
|
-
|
|
113
|
-
|
|
230
|
+
;;
|
|
231
|
+
esac
|
|
114
232
|
|
|
115
233
|
# Explicit return: this function's meaning is "populate _QG_* outputs," not a
|
|
116
234
|
# success/failure signal, so its exit status must never leak the truthiness of
|
|
@@ -9,13 +9,19 @@
|
|
|
9
9
|
# side anchors identically.
|
|
10
10
|
#
|
|
11
11
|
# Sourced by: the memory/learning/session hooks and ensure-devflow-init.
|
|
12
|
-
# Sourced helper: uses `return`-free pure
|
|
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
|
#
|
|
15
15
|
# Usage:
|
|
16
16
|
# source resolve-project-root
|
|
17
|
-
# PROJECT_ROOT="$(df_resolve_root "$CWD")"
|
|
17
|
+
# PROJECT_ROOT="$(df_resolve_root "$CWD")" # one root
|
|
18
|
+
# df_resolve_roots "$CWD" # sets DF_ROOT and DF_LEDGER_ROOT
|
|
18
19
|
#
|
|
20
|
+
# df_resolve_roots needs df_is_project_root, so this helper sources its sibling
|
|
21
|
+
# git-marker itself rather than trusting every caller to have done so first.
|
|
22
|
+
|
|
23
|
+
source "${BASH_SOURCE[0]%/*}/git-marker" 2>/dev/null || true
|
|
24
|
+
|
|
19
25
|
# df_resolve_root <cwd> prints the project root for <cwd>:
|
|
20
26
|
# 1. git top-level — git walks up to the real repo root even from a
|
|
21
27
|
# .devflow/-nested subdir, so the nested case is fixed for git repos.
|
|
@@ -27,11 +33,99 @@ df_resolve_root() {
|
|
|
27
33
|
# the caller (e.g. a non-git path). Empty output then routes to the fallback.
|
|
28
34
|
_root="$(git -C "$_cwd" rev-parse --show-toplevel 2>/dev/null || true)"
|
|
29
35
|
if [ -z "$_root" ]; then
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
*/.devflow) _root="${_cwd%/.devflow}" ;;
|
|
33
|
-
*) _root="$_cwd" ;;
|
|
34
|
-
esac
|
|
36
|
+
_df_nongit_root "$_cwd"
|
|
37
|
+
_root="$_DF_NONGIT_ROOT"
|
|
35
38
|
fi
|
|
36
39
|
printf '%s\n' "$_root"
|
|
37
40
|
}
|
|
41
|
+
|
|
42
|
+
# _df_nongit_root <cwd> sets _DF_NONGIT_ROOT to the non-git fallback root: <cwd>
|
|
43
|
+
# with its first /.devflow/ segment onward (or a trailing /.devflow) stripped.
|
|
44
|
+
# A variable rather than stdout, so a caller pays no `$(...)` subshell for it.
|
|
45
|
+
_df_nongit_root() {
|
|
46
|
+
case "$1" in
|
|
47
|
+
*/.devflow/*) _DF_NONGIT_ROOT="${1%%/.devflow/*}" ;;
|
|
48
|
+
*/.devflow) _DF_NONGIT_ROOT="${1%/.devflow}" ;;
|
|
49
|
+
*) _DF_NONGIT_ROOT="$1" ;;
|
|
50
|
+
esac
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
# df_resolve_roots <cwd> sets TWO roots in the caller's scope, from ONE git call:
|
|
54
|
+
# DF_ROOT — the checkout's toplevel: where per-checkout data lives
|
|
55
|
+
# (memory, the .gitignore carve-out, the knowledge bases).
|
|
56
|
+
# DF_LEDGER_ROOT — where the learning ledger and its queue live.
|
|
57
|
+
#
|
|
58
|
+
# D-LEDGER-MAIN-WORKTREE: a linked worktree (`git worktree add`, `claude
|
|
59
|
+
# --worktree`) has its own toplevel, so a ledger anchored there restarts at
|
|
60
|
+
# ADR-001 — main's decisions are invisible in it, and the IDs it mints collide
|
|
61
|
+
# with main's (in a repo whose collision guard refuses, the Learning agent stops
|
|
62
|
+
# for good). The ledger is one per REPOSITORY, not per checkout: DF_LEDGER_ROOT
|
|
63
|
+
# is the main worktree — the parent of `--git-common-dir` — when that common dir
|
|
64
|
+
# is a `<dir>/.git` directory AND `<dir>/.devflow` already exists; otherwise it is
|
|
65
|
+
# DF_ROOT. The existence test keeps a main checkout that never ran devflow from
|
|
66
|
+
# being scaffolded by a worktree session. A main worktree at HOME (a dotfiles
|
|
67
|
+
# repository) is refused as well (df_is_project_root, D-HOOKS-GIT-ONLY): its
|
|
68
|
+
# `.devflow` is the machine root, which always exists, so the existence test alone
|
|
69
|
+
# would put the ledger inside `~/.devflow`. A common dir that is not `/.git`
|
|
70
|
+
# (a bare repository, `--separate-git-dir`, a submodule's modules/ dir) has no
|
|
71
|
+
# main checkout to name, so it stays per checkout. Memory stays at DF_ROOT on
|
|
72
|
+
# purpose: working memory describes the branch in front of you. A worktree that
|
|
73
|
+
# already grew its own ledger before this rule keeps it — local data is left in
|
|
74
|
+
# place, and the worktree simply stops appending to it.
|
|
75
|
+
#
|
|
76
|
+
# The one call asks for both answers at once:
|
|
77
|
+
# git rev-parse --path-format=absolute --show-toplevel --git-common-dir
|
|
78
|
+
# and its output is accepted only when it is EXACTLY two lines, each an absolute
|
|
79
|
+
# path. `--path-format` arrived in git 2.31; an older git echoes the unknown
|
|
80
|
+
# flag back as a line of its own (three lines, the first not absolute), and that
|
|
81
|
+
# falls back to df_resolve_root, so the ledger stays at the toplevel exactly as
|
|
82
|
+
# before this rule. A failed call prints nothing: `--show-toplevel` itself failed
|
|
83
|
+
# (not a work tree), so asking git again could only fail the same way, and the
|
|
84
|
+
# non-git fallback applies directly. Inside a checkout git refuses (dubious
|
|
85
|
+
# ownership, GIT_CEILING_DIRECTORIES) that fallback is the raw cwd, which may be a
|
|
86
|
+
# subdirectory; df_is_project_root refuses any root without its own `.git`
|
|
87
|
+
# (D-HOOKS-TOPLEVEL-ONLY), so no hook scaffolds there. Parsing is parameter expansion and `case`
|
|
88
|
+
# only: one git call on the success path and on the non-git path alike.
|
|
89
|
+
df_resolve_roots() {
|
|
90
|
+
local _cwd="$1" _out="" _top="" _common="" _main=""
|
|
91
|
+
DF_ROOT=""
|
|
92
|
+
DF_LEDGER_ROOT=""
|
|
93
|
+
_out="$(git -C "$_cwd" rev-parse --path-format=absolute --show-toplevel --git-common-dir 2>/dev/null || true)"
|
|
94
|
+
_top="${_out%%$'\n'*}"
|
|
95
|
+
if [ "$_top" != "$_out" ]; then
|
|
96
|
+
_common="${_out#*$'\n'}"
|
|
97
|
+
fi
|
|
98
|
+
case "$_top" in /*) ;; *) _top="" ;; esac
|
|
99
|
+
case "$_common" in
|
|
100
|
+
*$'\n'*) _common="" ;;
|
|
101
|
+
/*) ;;
|
|
102
|
+
*) _common="" ;;
|
|
103
|
+
esac
|
|
104
|
+
if [ -z "$_out" ]; then
|
|
105
|
+
_df_nongit_root "$_cwd"
|
|
106
|
+
DF_ROOT="$_DF_NONGIT_ROOT"
|
|
107
|
+
[ -n "$DF_ROOT" ] || DF_ROOT="$_cwd"
|
|
108
|
+
DF_LEDGER_ROOT="$DF_ROOT"
|
|
109
|
+
return 0
|
|
110
|
+
fi
|
|
111
|
+
if [ -z "$_top" ] || [ -z "$_common" ]; then
|
|
112
|
+
DF_ROOT="$(df_resolve_root "$_cwd")"
|
|
113
|
+
[ -n "$DF_ROOT" ] || DF_ROOT="$_cwd"
|
|
114
|
+
DF_LEDGER_ROOT="$DF_ROOT"
|
|
115
|
+
return 0
|
|
116
|
+
fi
|
|
117
|
+
DF_ROOT="$_top"
|
|
118
|
+
DF_LEDGER_ROOT="$_top"
|
|
119
|
+
case "$_common" in
|
|
120
|
+
*/.git)
|
|
121
|
+
_main="${_common%/.git}"
|
|
122
|
+
# df_is_project_root forks nothing (builtin `cd -P` walks). Unavailable —
|
|
123
|
+
# git-marker failed to source — it is a command not found, which keeps the
|
|
124
|
+
# ledger in this checkout: the conservative answer.
|
|
125
|
+
if [ -n "$_main" ] && [ -d "$_main/.devflow" ] && df_is_project_root "$_main" 2>/dev/null; then
|
|
126
|
+
DF_LEDGER_ROOT="$_main"
|
|
127
|
+
fi
|
|
128
|
+
;;
|
|
129
|
+
esac
|
|
130
|
+
return 0
|
|
131
|
+
}
|