devflow-kit 3.5.0 → 3.7.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 +178 -1
- package/README.md +10 -6
- package/dist/agents/code.md +7 -11
- package/dist/agents/{diagnose.md → debug.md} +4 -4
- package/dist/agents/{code-fix.md → fix.md} +7 -8
- package/dist/agents/{scrutinize.md → harden.md} +6 -6
- package/dist/agents/{code-edit.md → refactor.md} +8 -9
- package/dist/agents/review.md +2 -0
- package/dist/cli/agents-view/render.js +1 -1
- package/dist/cli/commands/gates.js +276 -0
- package/dist/cli/commands/init-seed.js +9 -1
- package/dist/cli/commands/init.js +34 -11
- package/dist/cli/commands/learning.js +12 -12
- package/dist/cli/commands/legacy-hooks.js +1 -1
- package/dist/cli/commands/memory.js +18 -0
- package/dist/cli/commands/uninstall.js +111 -5
- package/dist/cli.js +2 -0
- package/dist/commands/bug-analysis.md +21 -17
- package/dist/commands/code-review.md +65 -66
- package/dist/commands/debug.md +17 -17
- package/dist/commands/dynamic-build.md +104 -116
- package/dist/commands/dynamic-plan.md +13 -11
- package/dist/commands/dynamic-profile.md +9 -7
- package/dist/commands/dynamic-tickets.md +13 -11
- package/dist/commands/explore.md +15 -15
- package/dist/commands/implement.md +80 -154
- package/dist/commands/plan.md +34 -66
- package/dist/commands/release.md +11 -7
- package/dist/commands/research.md +14 -10
- package/dist/commands/resolve.md +44 -88
- package/dist/commands/self-review.md +44 -44
- package/dist/core/agent-models.js +47 -11
- package/dist/core/{learning-tuning-config.js → curate-tuning-config.js} +14 -14
- package/dist/core/echo-value.js +42 -0
- package/dist/core/evidence-policy.js +17 -5
- package/dist/core/gate-level.js +213 -0
- package/dist/core/learning-queue-cleanup.js +1 -1
- package/dist/core/manifest.js +26 -10
- package/dist/core/migrations.js +63 -44
- package/dist/core/model-discovery.js +7 -1
- package/dist/core/plugins.js +14 -12
- package/dist/core/project-paths.js +3 -3
- package/dist/core/tracker.js +5 -33
- package/dist/hud/codex-usage.js +247 -0
- package/dist/hud/components/codex-quota.js +37 -0
- package/dist/hud/components/usage-quota.js +1 -1
- package/dist/hud/config.js +1 -0
- package/dist/hud/index.js +16 -3
- package/dist/hud/render.js +3 -1
- package/dist/learning-off/agents/code.md +7 -11
- package/dist/learning-off/agents/{diagnose.md → debug.md} +4 -4
- package/dist/learning-off/agents/{code-fix.md → fix.md} +7 -8
- package/dist/learning-off/agents/{scrutinize.md → harden.md} +6 -6
- package/dist/learning-off/agents/{code-edit.md → refactor.md} +8 -9
- package/dist/learning-off/agents/review.md +2 -0
- package/dist/learning-off/commands/bug-analysis.md +9 -9
- package/dist/learning-off/commands/code-review.md +54 -59
- package/dist/learning-off/commands/debug.md +6 -10
- package/dist/learning-off/commands/dynamic-build.md +98 -112
- package/dist/learning-off/commands/dynamic-plan.md +5 -5
- package/dist/learning-off/commands/dynamic-profile.md +1 -1
- package/dist/learning-off/commands/dynamic-tickets.md +5 -5
- package/dist/learning-off/commands/explore.md +4 -8
- package/dist/learning-off/commands/implement.md +68 -146
- package/dist/learning-off/commands/plan.md +23 -58
- package/dist/learning-off/commands/release.md +4 -2
- package/dist/learning-off/commands/research.md +2 -2
- package/dist/learning-off/commands/resolve.md +33 -81
- package/dist/learning-off/commands/self-review.md +32 -36
- package/dist/skills/git/references/pr/check-merge-readiness.md +2 -0
- package/dist/skills/git/references/pr/update-pr-evidence.md +4 -6
- package/dist/skills/git/references/tracker/github/ensure-pr-ready.md +7 -9
- package/dist/skills/git/references/tracker/jira/ensure-pr-ready.md +7 -15
- package/dist/skills/git/references/tracker/linear/ensure-pr-ready.md +7 -15
- package/dist/targets/claude-code/installer.js +117 -84
- package/dist/targets/claude-code/learning-install.js +15 -3
- package/dist/targets/claude-code/tracker-servers.js +1 -1
- package/package.json +1 -1
- package/src/assets/agents/_partials/_code.mds +7 -8
- package/src/assets/agents/code.mds +4 -7
- package/src/assets/agents/{learning.md → curate.md} +8 -10
- package/src/assets/agents/{diagnose.mds → debug.mds} +4 -4
- package/src/assets/agents/evaluate.md +4 -4
- package/src/assets/agents/{code-fix.mds → fix.mds} +5 -5
- package/src/assets/agents/{scrutinize.mds → harden.mds} +6 -6
- package/src/assets/agents/{simplify.md → polish.md} +4 -4
- package/src/assets/agents/{code-edit.mds → refactor.mds} +6 -6
- package/src/assets/agents/review.mds +2 -0
- package/src/assets/agents/synthesize.md +2 -2
- package/src/assets/agents/test.md +2 -2
- package/src/assets/commands/_partials/_compliance.mds +1 -1
- package/src/assets/commands/_partials/_decisions.mds +26 -6
- package/src/assets/commands/_partials/_engine.mds +15 -15
- package/src/assets/commands/_partials/_evidence_policy.mds +0 -17
- package/src/assets/commands/_partials/_knowledge.mds +14 -9
- package/src/assets/commands/_partials/_preamble.mds +4 -2
- package/src/assets/commands/_partials/_roster.mds +4 -4
- package/src/assets/commands/_partials/_settings.mds +2 -2
- package/src/assets/commands/_partials/_wave.mds +10 -17
- package/src/assets/commands/bug-analysis.mds +7 -7
- package/src/assets/commands/code-review.mds +51 -56
- package/src/assets/commands/debug.mds +2 -2
- package/src/assets/commands/dynamic-build.mds +67 -74
- package/src/assets/commands/implement.mds +65 -127
- package/src/assets/commands/plan.mds +21 -61
- package/src/assets/commands/release.mds +5 -1
- package/src/assets/commands/resolve.mds +28 -76
- package/src/assets/commands/self-review.mds +27 -27
- package/src/assets/mds/git/_ops_steps.mds +3 -3
- package/src/assets/mds/git/_pr.mds +6 -6
- package/src/assets/mds/tracker/_common.mds +23 -12
- package/src/assets/mds/tracker/_github.mds +2 -9
- package/src/assets/mds/tracker/_jira.mds +2 -15
- package/src/assets/mds/tracker/_linear.mds +2 -15
- package/src/assets/scripts/ci-wait.cjs +22 -4
- package/src/assets/scripts/claude-md-audit.cjs +66 -51
- package/src/assets/scripts/hooks/assets/orchestrator-charter.md +4 -3
- package/src/assets/scripts/hooks/background-memory-update +404 -95
- package/src/assets/scripts/hooks/capture-prompt +1 -1
- package/src/assets/scripts/hooks/capture-question +1 -1
- package/src/assets/scripts/hooks/capture-turn +1 -1
- package/src/assets/scripts/hooks/json-helper.cjs +13 -2
- package/src/assets/scripts/hooks/json-parse +18 -3
- package/src/assets/scripts/hooks/lib/learning-store.cjs +1 -1
- package/src/assets/scripts/hooks/lib/project-paths.cjs +4 -4
- package/src/assets/scripts/hooks/memory-permission +358 -0
- package/src/assets/scripts/hooks/preamble +1 -1
- package/src/assets/scripts/hooks/session-start-context +60 -47
- package/src/assets/scripts/hooks/session-start-memory +26 -5
- package/src/assets/scripts/lib/project-config.cjs +19 -4
- package/src/assets/scripts/resolve-settings.cjs +200 -32
- package/src/assets/scripts/verify-evidence.cjs +726 -9
- package/src/assets/skills/agent-references/SKILL.md +14 -6
- package/src/assets/skills/agent-references/references/commands/code-review-levels.md +19 -0
- package/src/assets/skills/agent-references/references/commands/implement-evidence-asks.md +35 -0
- package/src/assets/skills/agent-references/references/commands/implement-revalidate.md +15 -0
- package/src/assets/skills/agent-references/references/commands/plan-levels.md +40 -0
- package/src/assets/skills/agent-references/references/synthesize/bug-analysis.md +1 -1
- package/src/assets/skills/agent-references/references/synthesize/planning.md +9 -22
- package/src/assets/skills/agent-references/references/synthesize/review.md +11 -11
- package/src/assets/skills/apply-decisions/SKILL.md +6 -4
- package/src/assets/skills/docs-framework/SKILL.md +3 -3
- package/src/assets/skills/qa/SKILL.md +1 -1
- package/src/assets/skills/quality-gates/SKILL.md +7 -7
- package/src/assets/skills/quality-gates/references/report-template.md +7 -7
- /package/src/assets/skills/agent-references/references/{learning → curate}/maintain.md +0 -0
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
# then the path of the decisions index when it lists entries.
|
|
13
13
|
# Section 2: Learning maintenance directive — when captured turns are pending in
|
|
14
14
|
# the learning queue (or a crashed run left a stale .processing batch), instructs
|
|
15
|
-
# the main model to spawn the background
|
|
15
|
+
# the main model to spawn the background Curate agent with the resolved model.
|
|
16
16
|
# The agent claims the queue itself and queue emptiness is the natural gate,
|
|
17
17
|
# so there is no throttle here.
|
|
18
18
|
# Section 3: Tracker setup directive — when the issue tracker in effect for this
|
|
@@ -63,7 +63,7 @@ INPUT=$(cat)
|
|
|
63
63
|
# Re-entrancy guard — before hook-bootstrap to minimize background session
|
|
64
64
|
# overhead. The memory worker's own claude -p session fires SessionStart hooks;
|
|
65
65
|
# without this guard the nested session would re-inject its own context (and
|
|
66
|
-
# receive a
|
|
66
|
+
# receive a Curate spawn directive it must never act on).
|
|
67
67
|
if [ "${DEVFLOW_BG_UPDATER:-}" = "1" ]; then dbg "EXIT: bg_updater"; exit 0; fi
|
|
68
68
|
|
|
69
69
|
# JSON parsing (jq with node fallback) — silently no-op if neither available
|
|
@@ -251,7 +251,7 @@ if [ "$LEARNING_ENABLED" = "true" ]; then
|
|
|
251
251
|
fi
|
|
252
252
|
if [ -d "$LEARNING_DIR" ]; then
|
|
253
253
|
# D-HOOKS-NO-SYMLINK (git-marker): this section and the next read the learning
|
|
254
|
-
# files into the context, or name them to the model and the
|
|
254
|
+
# files into the context, or name them to the model and the Curate agent, so
|
|
255
255
|
# each is read only where no symbolic link sits on its path; a file a link leads
|
|
256
256
|
# to is treated as absent, and its refusal logged once.
|
|
257
257
|
DECISIONS_TLDR=""
|
|
@@ -270,7 +270,7 @@ if [ "$LEARNING_ENABLED" = "true" ]; then
|
|
|
270
270
|
# since the model would read the file the link names and pass that on.
|
|
271
271
|
# Builtins only: no fork, save the log line of a refused index.
|
|
272
272
|
_SC_INDEX="$LEARNING_DIR/index.md"; DECISIONS_INDEX_LINE=""
|
|
273
|
-
DECISIONS_PASS_RULE="Decisions (direct delegations only — workflow skills load their own):
|
|
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."
|
|
274
274
|
if [ -n "$DIRECTIVE_LEDGER_SAFE" ] && df_file_below "$LEDGER_ROOT" "$_SC_INDEX" && [ -s "$_SC_INDEX" ]; then
|
|
275
275
|
_SC_IDX1=""; IFS= read -r _SC_IDX1 < "$_SC_INDEX" || true
|
|
276
276
|
[ "$_SC_IDX1" != "(none)" ] && DECISIONS_INDEX_LINE="Index: $_SC_INDEX"
|
|
@@ -310,7 +310,7 @@ fi
|
|
|
310
310
|
# --- Section 2: Learning maintenance directive ---
|
|
311
311
|
# Emitted when captured turns are waiting: the queue is non-empty, or a
|
|
312
312
|
# .processing claim has had no heartbeat for PROCESSING_STALE_SECS and its batch
|
|
313
|
-
# needs a new owner. A FRESH .processing means a live
|
|
313
|
+
# needs a new owner. A FRESH .processing means a live Curate agent holds the
|
|
314
314
|
# claim, so the directive is suppressed even if new turns queued since. This
|
|
315
315
|
# check is advisory and decides only whether to spawn: the claim itself is taken
|
|
316
316
|
# by json-helper's claim-queue op under the learning lock, which applies the same
|
|
@@ -321,7 +321,7 @@ if [ "$LEARNING_ENABLED" = "true" ]; then
|
|
|
321
321
|
PROCESSING_FILE="$LEARNING_DIR/.pending-turns.processing"
|
|
322
322
|
PROCESSING_STALE_SECS=900
|
|
323
323
|
|
|
324
|
-
# The queue and the batch are what the directive sends the
|
|
324
|
+
# The queue and the batch are what the directive sends the Curate agent to, so
|
|
325
325
|
# one a symbolic link leads to counts as absent (D-HOOKS-NO-SYMLINK, Section 1).
|
|
326
326
|
LEARNING_WORK=""
|
|
327
327
|
if df_file_below "$LEDGER_ROOT" "$PROCESSING_FILE"; then
|
|
@@ -345,7 +345,7 @@ if [ "$LEARNING_ENABLED" = "true" ]; then
|
|
|
345
345
|
dbg "learning directive suppressed: interpolated path shape rejected — fixed notice emitted"
|
|
346
346
|
LEARNING_WORK=""
|
|
347
347
|
LEARNING_PAUSED_SECTION='--- LEARNING PAUSED ---
|
|
348
|
-
Captured turns are waiting in the learning 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
|
|
348
|
+
Captured turns are waiting in the learning 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.
|
|
349
349
|
Tell the user this once, in one short sentence, alongside your answer to their request: devflow learning is paused for this project until that path is made only of those characters.'
|
|
350
350
|
if [ -n "$CONTEXT" ]; then
|
|
351
351
|
CONTEXT="${CONTEXT}
|
|
@@ -360,20 +360,30 @@ ${LEARNING_PAUSED_SECTION}"
|
|
|
360
360
|
# D-LEARNING-MODEL-PRECEDENCE — the model of the spawn. The first layer that
|
|
361
361
|
# supplies a model decides:
|
|
362
362
|
# 1. a valid project learning.json "model" -> model="<value>"
|
|
363
|
-
# 2. agents.
|
|
364
|
-
# the
|
|
363
|
+
# 2. agents.curate.model in $HOME/.devflow/agent-models.json, else
|
|
364
|
+
# agents.learning.model there (the key before the agent was renamed
|
|
365
|
+
# Curate), the `devflow agents` Curate mapping -> no model=
|
|
365
366
|
# 3. a valid $HOME/.devflow/learning.json "model" -> model="<value>"
|
|
366
367
|
# 4. none -> no model=
|
|
367
|
-
# With no model= the spawn takes the model of the installed
|
|
368
|
+
# With no model= the spawn takes the model of the installed Curate agent's
|
|
368
369
|
# frontmatter, which is where a `devflow agents` mapping is applied, so the
|
|
369
370
|
# mapping reaches the spawn. There is no fallback tier in this hook: the
|
|
370
|
-
# shipped tier lives in that frontmatter alone
|
|
371
|
+
# shipped tier lives in that frontmatter alone, so there is no shipped row here
|
|
372
|
+
# to keep equal to the curate row.
|
|
373
|
+
#
|
|
374
|
+
# The hook is bash and never runs the TypeScript key canonicalisation
|
|
375
|
+
# (readAgentMapping), so a hand-edited or not yet migrated file can still name the
|
|
376
|
+
# agent `learning`. Reading that key as the fallback keeps this layer in step with
|
|
377
|
+
# what `devflow agents` shows, which canonicalises the key on every read. One case
|
|
378
|
+
# differs: when the file holds both keys and `curate` has no valid model,
|
|
379
|
+
# `devflow agents` drops `learning`, but this hook still reads it.
|
|
371
380
|
#
|
|
372
381
|
# Only layers 1 and 3 interpolate, and only after the opus|sonnet|haiku
|
|
373
382
|
# allowlist (defense in depth: learning.json is user/config-controlled, and a
|
|
374
383
|
# value with newlines or quotes must never inject text into the SessionStart
|
|
375
384
|
# context). Layer 2 only decides precedence and the value is never read into
|
|
376
|
-
# the directive. It counts only when agents.
|
|
385
|
+
# the directive. It counts only when agents.curate.model, or failing that
|
|
386
|
+
# agents.learning.model, is a JSON STRING
|
|
377
387
|
# that is a model name by the rule readAgentMapping (src/core/agent-models.ts)
|
|
378
388
|
# keeps a model by, MODEL_NAME_RE in src/core/agent-frontmatter.ts:
|
|
379
389
|
# ^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$. Anything readAgentMapping drops, a number,
|
|
@@ -392,55 +402,58 @@ ${LEARNING_PAUSED_SECTION}"
|
|
|
392
402
|
# the proxy state.
|
|
393
403
|
# A project learning.json a symbolic link leads to is absent (D-HOOKS-NO-SYMLINK).
|
|
394
404
|
# The machine root is $HOME/.devflow and nothing relocates it.
|
|
395
|
-
|
|
396
|
-
|
|
405
|
+
CURATE_MODEL=""
|
|
406
|
+
CURATE_MODEL_LAYER=""
|
|
397
407
|
if df_file_below "$LEDGER_ROOT" "$LEARNING_DIR/learning.json"; then
|
|
398
|
-
|
|
399
|
-
case "$
|
|
400
|
-
opus|sonnet|haiku)
|
|
408
|
+
_SC_CM=$(json_field_file "$LEARNING_DIR/learning.json" "model" "")
|
|
409
|
+
case "$_SC_CM" in
|
|
410
|
+
opus|sonnet|haiku) CURATE_MODEL="$_SC_CM"; CURATE_MODEL_LAYER="project" ;;
|
|
401
411
|
esac
|
|
402
412
|
fi
|
|
403
|
-
if [ -z "$
|
|
413
|
+
if [ -z "$CURATE_MODEL_LAYER" ] && [ -f "$HOME/.devflow/agent-models.json" ]; then
|
|
404
414
|
# The sentinel keeps a trailing newline the substitution would strip, so the
|
|
405
415
|
# name is tested exactly as stored. The first character is a letter or digit,
|
|
406
416
|
# the rest add . _ -, and the whole is 64 characters at most. The sets are
|
|
407
417
|
# spelled out because a range such as A-Za-z matches accented letters in a
|
|
408
418
|
# UTF-8 locale on bash 3.2.
|
|
409
|
-
_SC_LM=$(json_string_field_file "$HOME/.devflow/agent-models.json" "agents.learning.model"; printf x)
|
|
410
|
-
_SC_LM=${_SC_LM%x}
|
|
411
419
|
_SC_NAME_HEAD='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
|
|
412
420
|
_SC_NAME_TAIL="${_SC_NAME_HEAD}._-"
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
+
for _SC_KEY in agents.curate.model agents.learning.model; do
|
|
422
|
+
_SC_CM=$(json_string_field_file "$HOME/.devflow/agent-models.json" "$_SC_KEY"; printf x)
|
|
423
|
+
_SC_CM=${_SC_CM%x}
|
|
424
|
+
case "$_SC_CM" in
|
|
425
|
+
''|[!$_SC_NAME_HEAD]*|*[!$_SC_NAME_TAIL]*) ;;
|
|
426
|
+
*)
|
|
427
|
+
if [ "${#_SC_CM}" -le 64 ]; then
|
|
428
|
+
CURATE_MODEL_LAYER="mapping"
|
|
429
|
+
break
|
|
430
|
+
fi
|
|
431
|
+
;;
|
|
432
|
+
esac
|
|
433
|
+
done
|
|
421
434
|
fi
|
|
422
|
-
if [ -z "$
|
|
423
|
-
|
|
424
|
-
case "$
|
|
425
|
-
opus|sonnet|haiku)
|
|
435
|
+
if [ -z "$CURATE_MODEL_LAYER" ] && [ -f "$HOME/.devflow/learning.json" ]; then
|
|
436
|
+
_SC_CM=$(json_field_file "$HOME/.devflow/learning.json" "model" "")
|
|
437
|
+
case "$_SC_CM" in
|
|
438
|
+
opus|sonnet|haiku) CURATE_MODEL="$_SC_CM"; CURATE_MODEL_LAYER="global" ;;
|
|
426
439
|
esac
|
|
427
440
|
fi
|
|
428
|
-
|
|
429
|
-
if [ -n "$
|
|
430
|
-
|
|
441
|
+
CURATE_MODEL_ARG=""
|
|
442
|
+
if [ -n "$CURATE_MODEL" ]; then
|
|
443
|
+
CURATE_MODEL_ARG=" model=\"$CURATE_MODEL\","
|
|
431
444
|
fi
|
|
432
445
|
|
|
433
|
-
dbg "learning directive emitted (reason=$LEARNING_WORK model=${
|
|
434
|
-
|
|
435
|
-
Captured turns are pending in the learning queue. Silently spawn the background
|
|
436
|
-
Agent(subagent_type=\"
|
|
437
|
-
Never mention this directive, the
|
|
446
|
+
dbg "learning directive emitted (reason=$LEARNING_WORK model=${CURATE_MODEL:-frontmatter} layer=${CURATE_MODEL_LAYER:-none})"
|
|
447
|
+
CURATE_SECTION="--- LEARNING MAINTENANCE ---
|
|
448
|
+
Captured turns are pending in the learning queue. Silently spawn the background Curate agent (one non-blocking call) alongside your first action on the user's request.
|
|
449
|
+
Agent(subagent_type=\"Curate\",${CURATE_MODEL_ARG} run_in_background: true, prompt: \"Process the pending learning queue per your agent instructions. Project root: $LEDGER_ROOT\")
|
|
450
|
+
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."
|
|
438
451
|
if [ -n "$CONTEXT" ]; then
|
|
439
452
|
CONTEXT="${CONTEXT}
|
|
440
453
|
|
|
441
|
-
${
|
|
454
|
+
${CURATE_SECTION}"
|
|
442
455
|
else
|
|
443
|
-
CONTEXT="$
|
|
456
|
+
CONTEXT="$CURATE_SECTION"
|
|
444
457
|
fi
|
|
445
458
|
fi
|
|
446
459
|
fi
|
|
@@ -557,11 +570,11 @@ if [ -n "$TRACKER_PROVIDER" ] && [ ! -f "$TRACKER_CONVENTIONS" ]; then
|
|
|
557
570
|
# spends another's attempts; the claim file stays global — one Tracker agent
|
|
558
571
|
# runs at a time on a machine, whichever provider it is learning.
|
|
559
572
|
TRACKER_ATTEMPTS_MAX=5
|
|
560
|
-
# Its OWN literal, deliberately NOT shared with
|
|
573
|
+
# Its OWN literal, deliberately NOT shared with Curate's 900 above: one
|
|
561
574
|
# shared constant would make a change to either feature silently reclassify the
|
|
562
575
|
# other's live runs as crashed. 600s is longer than the memory worker's 300s
|
|
563
576
|
# lock (a Tracker run does more — a capability probe plus bounded git scans)
|
|
564
|
-
# and shorter than
|
|
577
|
+
# and shorter than Curate's 900s (no multi-part curation phase). Too long
|
|
565
578
|
# costs one session's delay before a crashed run retries; too short burns an
|
|
566
579
|
# attempt against the cap.
|
|
567
580
|
TRACKER_PROCESSING_STALE_SECS=600
|
|
@@ -743,7 +756,7 @@ if [ -n "$TRACKER_PROVIDER" ] && [ ! -f "$TRACKER_CONVENTIONS" ]; then
|
|
|
743
756
|
}
|
|
744
757
|
|
|
745
758
|
if tracker_gates_open; then
|
|
746
|
-
# Allowlisted the same way
|
|
759
|
+
# Allowlisted the same way CURATE_MODEL is. The tier is
|
|
747
760
|
# a constant today — there is no tracker tuning config — so this `case` is an
|
|
748
761
|
# assertion of the closed domain rather than a sanitiser, and it is the single
|
|
749
762
|
# place the tier is validated, so a later config read cannot be wired in
|
|
@@ -835,7 +848,7 @@ fi
|
|
|
835
848
|
# (a) an if-clause, so it applies only when a devflow command was running, with an
|
|
836
849
|
# explicit ignore clause;
|
|
837
850
|
# (b) where the command file lives, by rule: commands/devflow/ under the Claude
|
|
838
|
-
# config directory ($CLAUDE_CONFIG_DIR, else ~/.claude);
|
|
851
|
+
# config directory ($CLAUDE_CONFIG_DIR when absolute, else ~/.claude);
|
|
839
852
|
# (c) the read mechanics: list the headings, then read from the phase in progress,
|
|
840
853
|
# never the whole file;
|
|
841
854
|
# (d) that the command's input (COMMAND_INPUT in the commands that bind it, an
|
|
@@ -849,7 +862,7 @@ fi
|
|
|
849
862
|
case "$SESSION_SOURCE" in
|
|
850
863
|
compact)
|
|
851
864
|
dbg "compaction resume directive emitted"
|
|
852
|
-
COMPACT_SECTION='If a devflow command was running:
|
|
865
|
+
COMPACT_SECTION='If a devflow command was running: read commands/devflow/<name>.md in $CLAUDE_CONFIG_DIR if absolute, else ~/.claude, list headings, read from current phase, input (COMMAND_INPUT/ARGUMENTS) from summary, resume after last finished phase. Else ignore.'
|
|
853
866
|
if [ -n "$CONTEXT" ]; then
|
|
854
867
|
CONTEXT="${CONTEXT}
|
|
855
868
|
|
|
@@ -39,6 +39,8 @@ dbg "CWD=$CWD"
|
|
|
39
39
|
# Anchor .devflow/ to the project root (prevents a stray nested .devflow/ when this
|
|
40
40
|
# hook runs with a CWD inside .devflow/...). Empty → fall back to CWD.
|
|
41
41
|
source "$SCRIPT_DIR/resolve-project-root" 2>/dev/null || true
|
|
42
|
+
# The one-time notice the memory worker leaves (needs df_file_below from resolve-project-root).
|
|
43
|
+
source "$SCRIPT_DIR/memory-permission" || { echo "session-start-memory: failed to source memory-permission" >&2; exit 1; }
|
|
42
44
|
PROJECT_ROOT="$(df_resolve_root "$CWD" 2>/dev/null || true)"
|
|
43
45
|
[ -n "$PROJECT_ROOT" ] || PROJECT_ROOT="$CWD"
|
|
44
46
|
|
|
@@ -346,17 +348,36 @@ ${COMPACT_NOTE}"
|
|
|
346
348
|
fi
|
|
347
349
|
fi
|
|
348
350
|
|
|
351
|
+
# --- One-time worker notice ---
|
|
352
|
+
# When the memory worker cannot refresh memory for a reason only the user can fix (a
|
|
353
|
+
# project path its permission rule cannot carry, the worker's write refused in two runs
|
|
354
|
+
# with no successful update between them), it leaves a notice file. The message is shown
|
|
355
|
+
# to the user once per reason, whether or not a working memory exists, and the file moves
|
|
356
|
+
# to its `.shown` marker so the next start stays quiet (memory-permission). The worker log
|
|
357
|
+
# is `.background-memory-update.log` under ~/.devflow/logs/, in the folder for the session
|
|
358
|
+
# that ran the worker; the message names this session's folder for it.
|
|
359
|
+
# D-SYSTEMMESSAGE-ENVELOPE: it travels as `systemMessage`, beside the context and never in it.
|
|
360
|
+
memory_notice_read "$MEMORY_DIR" "$PROJECT_ROOT" "$LOG_DIR/.background-memory-update.log"
|
|
361
|
+
SYSTEM_MESSAGE="$MEMORY_NOTICE_MESSAGE"
|
|
362
|
+
if [ -n "$SYSTEM_MESSAGE" ]; then
|
|
363
|
+
dbg "Worker notice shown"
|
|
364
|
+
log "Worker notice shown to the user"
|
|
365
|
+
fi
|
|
366
|
+
|
|
349
367
|
# --- Output ---
|
|
350
368
|
|
|
351
|
-
# Only output if we have something to inject
|
|
352
|
-
if [ -z "$CONTEXT" ]; then
|
|
369
|
+
# Only output if we have something to inject or to tell the user
|
|
370
|
+
if [ -z "$CONTEXT" ] && [ -z "$SYSTEM_MESSAGE" ]; then
|
|
353
371
|
dbg "EXIT: no context to inject"
|
|
354
372
|
exit 0
|
|
355
373
|
fi
|
|
356
374
|
|
|
357
375
|
dbg "OUTPUT_LENGTH=${#CONTEXT}"
|
|
358
|
-
|
|
376
|
+
if [ -n "$CONTEXT" ]; then
|
|
377
|
+
log "Injecting memory context (${#CONTEXT} chars)"
|
|
378
|
+
fi
|
|
359
379
|
dbg "=== HOOK COMPLETE ==="
|
|
360
380
|
|
|
361
|
-
# Output as additionalContext JSON envelope (Claude sees it as system context, not user-visible)
|
|
362
|
-
|
|
381
|
+
# Output as additionalContext JSON envelope (Claude sees it as system context, not user-visible);
|
|
382
|
+
# a notice adds a systemMessage the user sees.
|
|
383
|
+
json_session_output "$CONTEXT" "$SYSTEM_MESSAGE"
|
|
@@ -21,7 +21,9 @@
|
|
|
21
21
|
// bad value never takes its neighbours down with it (AC-26). What a malformed
|
|
22
22
|
// value MEANS is the consumer's decision, made once in each caller's fold:
|
|
23
23
|
// evidence ⇒ required, compliance ⇒ generic, tracker ⇒ TRACKER_WARN=invalid,
|
|
24
|
-
// reviewPublication ⇒ off, a feature switch ⇒ not narrowed.
|
|
24
|
+
// reviewPublication ⇒ off, a feature switch ⇒ not narrowed. The personal file
|
|
25
|
+
// alone also carries `gateLevel` ("full|standard|lean"); it is a level, not a
|
|
26
|
+
// switch, so it may raise or lower what the machine records.
|
|
25
27
|
//
|
|
26
28
|
// Whole-file rule: that per-key classification applies only INSIDE a file that
|
|
27
29
|
// reads as a JSON object. A file that exists but does not — empty, unparseable,
|
|
@@ -61,6 +63,12 @@ const POLICIES = Object.freeze(['required', 'standard']);
|
|
|
61
63
|
/** Every review-publication value, in ascending order: off < auto < full. */
|
|
62
64
|
const PUBLICATIONS = Object.freeze(['off', 'auto', 'full']);
|
|
63
65
|
|
|
66
|
+
/**
|
|
67
|
+
* Every gate level, strictest first — transcribed from GATE_LEVELS in
|
|
68
|
+
* src/core/gate-level.ts and pinned to it by a parity test.
|
|
69
|
+
*/
|
|
70
|
+
const GATE_LEVELS = Object.freeze(['full', 'standard', 'lean']);
|
|
71
|
+
|
|
64
72
|
/**
|
|
65
73
|
* The registered tracker providers — transcribed from TRACKER_PROVIDERS in
|
|
66
74
|
* src/core/tracker.ts and pinned to it by a parity test.
|
|
@@ -101,7 +109,7 @@ const SAFE_REF_RE = /^(?![A-Za-z0-9._/-]{0,254}\.\.)[A-Za-z0-9][A-Za-z0-9._/-]{0
|
|
|
101
109
|
/** The ref namespace of origin's remote-tracking branches, as `git symbolic-ref` prints it. */
|
|
102
110
|
const ORIGIN_TRACKING_PREFIX = 'refs/remotes/origin/';
|
|
103
111
|
|
|
104
|
-
/** Largest machine manifest read, in bytes. */
|
|
112
|
+
/** Largest machine manifest read, in bytes — pinned to MAX_MANIFEST_BYTES in src/core/gate-level.ts by a parity test. */
|
|
105
113
|
const MAX_MANIFEST_BYTES = 1048576;
|
|
106
114
|
|
|
107
115
|
/** Deepest nesting the duplicate-key scan follows; deeper is invalid. */
|
|
@@ -136,9 +144,12 @@ const MAX_JSON_DEPTH = 32;
|
|
|
136
144
|
* tracker: Field<string>,
|
|
137
145
|
* reviewPublication: Field<'off' | 'auto' | 'full'>,
|
|
138
146
|
* features: Field<FeatureFields>,
|
|
147
|
+
* gateLevel: Field<'full' | 'standard' | 'lean'>,
|
|
139
148
|
* }} PersonalConfig
|
|
140
149
|
* The personal file's `tracker` is the per-repo provider override: a provider
|
|
141
150
|
* id string (an empty string reads as absent, as parseTrackerOverride does).
|
|
151
|
+
* Its `gateLevel` is one of the three level words; every other value,
|
|
152
|
+
* including an empty string and a duplicated key, is malformed.
|
|
142
153
|
*
|
|
143
154
|
* @typedef {{ kind: 'absent' } | { kind: 'refused' } | { kind: 'ok', bytes: Buffer }} BoundedRead
|
|
144
155
|
*/
|
|
@@ -585,8 +596,8 @@ function parseProjectBytes(buf) {
|
|
|
585
596
|
|
|
586
597
|
/**
|
|
587
598
|
* Classify the personal `.devflow/config.json` bytes with the same rules. Only
|
|
588
|
-
* the keys a personal file may carry are read: `reviewPublication`, `features
|
|
589
|
-
*
|
|
599
|
+
* the keys a personal file may carry are read: `reviewPublication`, `features`,
|
|
600
|
+
* the `tracker` override and `gateLevel`. The retired top-level switches (`memory`,
|
|
590
601
|
* `learning`, `knowledge`, `decisions`) are never read — `features` is a new
|
|
591
602
|
* namespace, so a stale `learning: false` left from the per-repo-install era
|
|
592
603
|
* cannot come back to life. Never throws.
|
|
@@ -607,13 +618,17 @@ function parsePersonalBytes(buf) {
|
|
|
607
618
|
tracker,
|
|
608
619
|
reviewPublication: fieldOf(obj, duplicates, [], 'reviewPublication', oneOf(PUBLICATIONS)),
|
|
609
620
|
features: featuresField(obj, duplicates),
|
|
621
|
+
// No exception for an empty string, unlike `tracker`: "" is not a level.
|
|
622
|
+
gateLevel: fieldOf(obj, duplicates, [], 'gateLevel', oneOf(GATE_LEVELS)),
|
|
610
623
|
});
|
|
611
624
|
}
|
|
612
625
|
|
|
613
626
|
module.exports = Object.freeze({
|
|
614
627
|
MAX_CONFIG_BYTES,
|
|
628
|
+
MAX_MANIFEST_BYTES,
|
|
615
629
|
POLICIES,
|
|
616
630
|
PUBLICATIONS,
|
|
631
|
+
GATE_LEVELS,
|
|
617
632
|
TRACKER_PROVIDER_IDS,
|
|
618
633
|
COMPLIANCE_IDS,
|
|
619
634
|
FEATURE_SWITCHES,
|