@cratylus/canon 0.2.0 → 0.3.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.
@@ -4,7 +4,7 @@
4
4
  // phase-STATE, not a static value: the `⟨resting · phase-state⟩` residue declares
5
5
  // this as the RESTING / initial position (a session opens in orientation, intent
6
6
  // the operator's to set) while marking that the live position shifts —
7
- // `carry-on` elevates it to out-of-the-loop, held until the bound praxis
7
+ // `carry-on` elevates it to out-of-the-loop, held until the bound plan
8
8
  // completes or an unresolvable fork re-enters on-the-loop. See skills/carry-on.
9
9
  export const humanOnTheLoop = `human-on-the-loop ⟨resting · phase-state⟩`;
10
10
  //# sourceMappingURL=human-on-the-loop.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"human-on-the-loop.js","sourceRoot":"","sources":["../../../src/dimensions/autonomy/human-on-the-loop.ts"],"names":[],"mappings":"AAEA,4EAA4E;AAC5E,kFAAkF;AAClF,+EAA+E;AAC/E,kFAAkF;AAClF,iFAAiF;AACjF,uEAAuE;AACvE,yEAAyE;AACzE,gFAAgF;AAChF,MAAM,CAAC,MAAM,cAAc,GAAa,2CAA2C,CAAC"}
1
+ {"version":3,"file":"human-on-the-loop.js","sourceRoot":"","sources":["../../../src/dimensions/autonomy/human-on-the-loop.ts"],"names":[],"mappings":"AAEA,4EAA4E;AAC5E,kFAAkF;AAClF,+EAA+E;AAC/E,kFAAkF;AAClF,iFAAiF;AACjF,uEAAuE;AACvE,uEAAuE;AACvE,gFAAgF;AAChF,MAAM,CAAC,MAAM,cAAc,GAAa,2CAA2C,CAAC"}
@@ -6,8 +6,11 @@
6
6
  // (claude adapter: `turn.end` → Stop, `subagent.end` → SubagentStop) and carries
7
7
  // their VERBATIM worker payloads so the projector stages them under `hooks/<id>/`
8
8
  // (no file copy — the bytes come from the cell). Only `harness`-substrate cells
9
- // register in settings.json; a `git`-substrate cell (praxis-continuity) fires in
10
- // git's process and is byte-locked but not serialized here.
9
+ // register in settings.json, and every surviving cell is one: the corpus's single
10
+ // `git`-substrate cell, `praxis-continuity`, retired with the praxis plan mirror it
11
+ // nudged about. The routing for a non-harness substrate is not hypothetical — it is
12
+ // exercised the moment such a cell exists again — but nothing carries it today, and
13
+ // a header claiming a live example is a claim a reader cannot check.
11
14
  //
12
15
  // The cell shapes are the schema's type kernel (`@cratylus/schema`); this
13
16
  // module is the composition root that NAMES the concrete cells and nothing more.
@@ -1 +1 @@
1
- {"version":3,"file":"hook-cells.js","sourceRoot":"","sources":["../src/hook-cells.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,2EAA2E;AAC3E,kFAAkF;AAClF,mFAAmF;AACnF,4EAA4E;AAC5E,iFAAiF;AACjF,kFAAkF;AAClF,gFAAgF;AAChF,iFAAiF;AACjF,4DAA4D;AAC5D,EAAE;AACF,0EAA0E;AAC1E,iFAAiF;AACjF,oFAAoF;AACpF,iFAAiF;AACjF,+EAA+E;AAE/E,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAG9D,wFAAwF;AACxF,MAAM,CAAC,MAAM,gBAAgB,GAAwB;IACnD,eAAe;IACf,kBAAkB;IAClB,iBAAiB;CAClB,CAAC"}
1
+ {"version":3,"file":"hook-cells.js","sourceRoot":"","sources":["../src/hook-cells.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,2EAA2E;AAC3E,kFAAkF;AAClF,mFAAmF;AACnF,4EAA4E;AAC5E,iFAAiF;AACjF,kFAAkF;AAClF,gFAAgF;AAChF,kFAAkF;AAClF,oFAAoF;AACpF,oFAAoF;AACpF,oFAAoF;AACpF,qEAAqE;AACrE,EAAE;AACF,0EAA0E;AAC1E,iFAAiF;AACjF,oFAAoF;AACpF,iFAAiF;AACjF,+EAA+E;AAE/E,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAG9D,wFAAwF;AACxF,MAAM,CAAC,MAAM,gBAAgB,GAAwB;IACnD,eAAe;IACf,kBAAkB;IAClB,iBAAiB;CAClB,CAAC"}
@@ -33,7 +33,7 @@
33
33
  // copy with nothing further to say. That is not hypothetical and it is not rare —
34
34
  // it is the ORDINARY shape of work here, where a session edits a cell, projects it,
35
35
  // and keeps going under the version it just replaced. The 16-hour-old projection of
36
- // an agent's own governing cell was this; so was a `praxis` edit that landed under a
36
+ // an agent's own governing cell was this; so was a `plan` edit that landed under a
37
37
  // running session hours later.
38
38
  //
39
39
  // `prompt.submit` IS THE RE-ARM, and it is the same question at a finer grain rather
@@ -1 +1 @@
1
- {"version":3,"file":"deploy-drift-notice.js","sourceRoot":"","sources":["../../src/hooks/deploy-drift-notice.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"deploy-drift-notice.js","sourceRoot":"","sources":["../../src/hooks/deploy-drift-notice.ts"],"names":[],"mappings":"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"}
@@ -46,9 +46,9 @@ export const stanceGuardrailPre = {
46
46
  # ambiguity, a substantive intent-extracted dispatch.
47
47
  #
48
48
  # SAFETY MODEL (mirrors stance-guardrail):
49
- # - OFF BY DEFAULT (git config agentfactory.stanceGuard true).
50
- # - AGENT-SCOPED (agent_type in the allowlist; default: nico mav). agent_type is
51
- # present only for subagents / --agent mode; a top-level session call fails open.
49
+ # - SCOPE-ENROLLED, exactly as its twin: a scope carrying a stance manifest is judged and
50
+ # every other scope is silent. No repo opt-in, no allowlist — the projection that places a
51
+ # persona also enrolls it, and declining the guard means declining the persona.
52
52
  # - FAILS OPEN. Any error (no jq, judge failure, bad input) -> exit 0 (allow the call).
53
53
  # - LOOP-SAFE. A re-entry cap: never deny an identical tool_input twice (there is no
54
54
  # stop_hook_active analog for PreToolUse), so it can never wedge a call.
@@ -98,27 +98,22 @@ input="$(cat)"
98
98
  [ -n "$input" ] || allow
99
99
  command -v jq >/dev/null 2>&1 || allow # no jq -> cannot parse -> fail open
100
100
 
101
- # --- opt-in gate (off by default) -----------------------------------------------------------
102
- # Per-repo, lives in .git/config, never checked in. Resolve relative to the hook's cwd.
101
+ # The per-repo opt-in is GONE, for the reason its twin states: it asked whether a guard may run in
102
+ # a DIRECTORY, and a stance belongs to the agent, not the checkout. \`cwd\` survives it — the worker
103
+ # still runs where the session runs.
103
104
  cwd="$(printf '%s' "$input" | jq -r '.cwd // empty' 2>/dev/null || true)"
104
105
  [ -n "$cwd" ] && cd "$cwd" 2>/dev/null || true
105
- enabled="$(git config --bool agentfactory.stanceGuard 2>/dev/null || echo false)"
106
- [ "$enabled" = "true" ] || allow
107
-
108
- # --- agent-scope gate -----------------------------------------------------------------------
109
- # Only enforce for the configured agents (default: the principal-self agents).
110
- # agent_type is present only for a subagent / --agent tool call; absent for the top-level
111
- # session -> fail open (unless STANCE_GUARD_AGENTS=*), exactly like the Stop guard.
112
- agent_type="$(printf '%s' "$input" | jq -r '.agent_type // empty' 2>/dev/null || true)"
113
- allowlist="\${STANCE_GUARD_AGENTS:-$(git config agentfactory.stanceGuardAgents 2>/dev/null || echo 'nico mav')}"
114
- if [ "$allowlist" != "*" ]; then
115
- [ -n "$agent_type" ] || allow # cannot identify the agent -> fail open
116
- in_scope=false
117
- for a in $allowlist; do
118
- [ "$a" = "$agent_type" ] && in_scope=true && break
119
- done
120
- [ "$in_scope" = true ] || allow
121
- fi
106
+
107
+ # --- scope gate: the persona's OWN stance manifest -------------------------------------------
108
+ # The twin of the turn-end guard's gate, and inverted for the same reason: an allowlist here was
109
+ # a runtime self-filter over an enrollment the corpus already derives, and it had drifted the way
110
+ # such a list always drifts. Presence of a manifest in this persona's own scope IS enrollment.
111
+ # Absent → silence, never an error, so an unenrolled launch is untouched.
112
+ stance_scope="$(printf '%s' "$input" | jq -r '.stance_scope // empty' 2>/dev/null || true)"
113
+ [ -n "$stance_scope" ] || allow
114
+ manifest="$stance_scope/stance/manifest.json"
115
+ [ -f "$manifest" ] || allow
116
+ agent_type="$(jq -r '.agent // empty' "$manifest" 2>/dev/null || true)"
122
117
 
123
118
  # --- extract the judged payload, branched by tool -------------------------------------------
124
119
  tool_name="$(printf '%s' "$input" | jq -r '.tool_name // empty' 2>/dev/null || true)"
@@ -1 +1 @@
1
- {"version":3,"file":"stance-guardrail-pre.js","sourceRoot":"","sources":["../../src/hooks/stance-guardrail-pre.ts"],"names":[],"mappings":"AAEA,sFAAsF;AACtF,mFAAmF;AACnF,uFAAuF;AACvF,SAAS;AACT,wFAAwF;AACxF,6FAA6F;AAC7F,0FAA0F;AAC1F,uFAAuF;AACvF,qEAAqE;AACrE,EAAE;AACF,wEAAwE;AACxE,sFAAsF;AACtF,iFAAiF;AACjF,mFAAmF;AACnF,sFAAsF;AACtF,qFAAqF;AACrF,sFAAsF;AACtF,sFAAsF;AACtF,mEAAmE;AACnE,2DAA2D;AAC3D,mDAAmD;AAEnD,MAAM,CAAC,MAAM,kBAAkB,GAAa;IAC1C,EAAE,EAAE,sBAAsB;IAC1B,OAAO,EACL,iWAAiW;IACnW,SAAS,EAAE,SAAS;IACpB,KAAK,EAAE,CAAC;IACR,MAAM,EAAE,CAAC,sBAAsB,EAAE,uBAAuB,CAAC;IACzD,KAAK,EAAE,yBAAyB;IAChC,OAAO,EAAE,EAAE;IACX,IAAI,EAAE,EAAE;IACR,OAAO,EAAE;QACP;YACE,QAAQ,EAAE,yBAAyB;YACnC,UAAU,EAAE,0DAA0D;YACtE,UAAU,EAAE,IAAI;YAChB,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiKd;SACI;KACF;CACF,CAAC"}
1
+ {"version":3,"file":"stance-guardrail-pre.js","sourceRoot":"","sources":["../../src/hooks/stance-guardrail-pre.ts"],"names":[],"mappings":"AAEA,sFAAsF;AACtF,mFAAmF;AACnF,uFAAuF;AACvF,SAAS;AACT,wFAAwF;AACxF,6FAA6F;AAC7F,0FAA0F;AAC1F,uFAAuF;AACvF,qEAAqE;AACrE,EAAE;AACF,wEAAwE;AACxE,sFAAsF;AACtF,iFAAiF;AACjF,mFAAmF;AACnF,sFAAsF;AACtF,qFAAqF;AACrF,sFAAsF;AACtF,sFAAsF;AACtF,mEAAmE;AACnE,2DAA2D;AAC3D,mDAAmD;AAEnD,MAAM,CAAC,MAAM,kBAAkB,GAAa;IAC1C,EAAE,EAAE,sBAAsB;IAC1B,OAAO,EACL,iWAAiW;IACnW,SAAS,EAAE,SAAS;IACpB,KAAK,EAAE,CAAC;IACR,MAAM,EAAE,CAAC,sBAAsB,EAAE,uBAAuB,CAAC;IACzD,KAAK,EAAE,yBAAyB;IAChC,OAAO,EAAE,EAAE;IACX,IAAI,EAAE,EAAE;IACR,OAAO,EAAE;QACP;YACE,QAAQ,EAAE,yBAAyB;YACnC,UAAU,EAAE,0DAA0D;YACtE,UAAU,EAAE,IAAI;YAChB,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4Jd;SACI;KACF;CACF,CAAC"}
@@ -49,8 +49,13 @@ export const stanceGuardrail = {
49
49
  # electing the session's objective is supplying intent, not sequencing — the operator's to own
50
50
  #
51
51
  # SAFETY MODEL:
52
- # - OFF BY DEFAULT. Does nothing unless the repo opts in (git config agentfactory.stanceGuard true).
53
- # - AGENT-SCOPED. Only fires for agents on the allowlist (default: nico, mav — the principal-self agents).
52
+ # - SCOPE-ENROLLED. Fires for a scope carrying a stance manifest, and for no other. Enrollment
53
+ # is PRESENCE: the projection places a manifest in each persona's own scope, so composing the
54
+ # cell enrolls the persona and nothing central lists anybody. A bare launch carries the
55
+ # dispatcher and no manifest, and is therefore silent by placement.
56
+ # - NO REPO OPT-IN. There was one, per-repo in .git/config, and it asked the wrong question:
57
+ # whether a guard may run in a DIRECTORY. The off switch is launching \`omp\` rather than a
58
+ # persona — declining to BE the agent, instead of being it unjudged.
54
59
  # - FAILS OPEN, BUT NEVER SILENTLY-CLEAN. Any error → exit 0 (allow stop): a guardrail that
55
60
  # wedges work on its own flakiness is worse than a missed block. But once the guard is
56
61
  # ENABLED and in scope, a failure that prevents judging (no transcript, judge unreachable)
@@ -85,6 +90,9 @@ JUDGE_CMD="\${STANCE_JUDGE_CMD:-sh $SELF_DIR/stance-judge.sh}"
85
90
  # a host and point outside a sandboxed deploy, which is the class of bug that put
86
91
  # \`\$HOME/.claude\` in the sibling worker and made it read another harness's tree.
87
92
  NEUTRAL_ROOT="$(dirname -- "$(dirname -- "$(dirname -- "$SELF_DIR")")")/.agents"
93
+ # The DEFAULT rubric. A persona's own manifest may name another — that is the
94
+ # strategy seam: one opinionated implementation, each persona free to bind a
95
+ # different contract without the dispatcher learning anything about either.
88
96
  RUBRIC="\${STANCE_RUBRIC:-$NEUTRAL_ROOT/stance-guardrail/stance-judge-prompt.md}"
89
97
 
90
98
  # A Stop hook must never break a session. Trap any unexpected error → allow the stop.
@@ -102,6 +110,15 @@ allow_stop() { exit 0; } # emit nothing; the agent is permitted to stop.
102
110
  # turn. Reached only AFTER the opt-in and allowlist checks, so a repo that never enabled
103
111
  # the guard stays silent.
104
112
  dark() {
113
+ # THE HEARTBEAT, and the reason the log is worth keeping. A VERDICT row and a
114
+ # DARK row are both evidence the guard RAN; only an EMPTY log means it never
115
+ # did. Recording judged turns alone made "not judged" and "no session" read
116
+ # identically — measured on a live host: an endpoint behind the advisor role
117
+ # accepted connections and never answered, and five hours of one session were
118
+ # unjudged while leaving no trace whatsoever to notice it by.
119
+ if [ -n "\${verdict_log:-}" ]; then
120
+ printf 'DARK\\t\\t%s\\n' "\$1" >> "\$verdict_log" 2>/dev/null || true
121
+ fi
105
122
  printf 'STANCE GUARDRAIL — DARK: %s. This turn was NOT judged; the absence of a block is an absence of a verdict, not a clean one.\\n' "\$1"
106
123
  exit 0
107
124
  }
@@ -138,32 +155,55 @@ verdict_log="$state_dir/$session.verdicts"
138
155
  block_count="$(cat "$count_file" 2>/dev/null || echo 0)"
139
156
  case "$block_count" in *[!0-9]*) block_count=0 ;; esac
140
157
 
141
- # --- opt-in gate (off by default) -----------------------------------------------------------
142
- # Per-repo, lives in .git/config, never checked in. A fresh clone is opted out.
143
- # Resolve relative to the hook's cwd (the project), which is where the flag lives.
158
+ # The per-repo opt-in is GONE, and its absence is the point. It answered "may a guard run in this
159
+ # DIRECTORY", which is a category error: a stance is a property of the agent, not of the checkout
160
+ # it happens to be standing in. Worse, it made the stance OPTIONAL AT RUNTIME for an agent already
161
+ # launched as itself — the ambient form, when the whole reason this harness half exists is that
162
+ # identity alone erodes. The off switch is launching \`omp\` instead of \`mav\`: declining to be the
163
+ # persona, rather than being it unjudged.
144
164
  cwd="$(printf '%s' "$input" | jq -r '.cwd // empty' 2>/dev/null || true)"
145
165
  [ -n "$cwd" ] && cd "$cwd" 2>/dev/null || true
146
- enabled="$(git config --bool agentfactory.stanceGuard 2>/dev/null || echo false)"
147
- [ "$enabled" = "true" ] || allow_stop
148
-
149
- # --- agent-scope gate -----------------------------------------------------------------------
150
- # Only enforce the stance for the configured agents (the principal-self agents by default).
151
- # agent_type identifies the agent (verified by an introspective-hook capture): it is PRESENT for an
152
- # --agent / @mention launch — top-level INCLUDED (a session started as @nico reports agent_type=nico)
153
- # — and for every SubagentStop; it is ABSENT only for a DEFAULT top-level session (plain claude, no
154
- # --agent). When absent we do NOT enforce: a session that never declared itself a principal should not
155
- # get the principal rubric. STANCE_GUARD_AGENTS=* overrides to enforce on everyone (a blunt instrument).
156
- agent_type="$(printf '%s' "$input" | jq -r '.agent_type // empty' 2>/dev/null || true)"
157
- allowlist="\${STANCE_GUARD_AGENTS:-$(git config agentfactory.stanceGuardAgents 2>/dev/null || echo 'nico mav')}"
158
-
159
- if [ "$allowlist" != "*" ]; then
160
- [ -n "$agent_type" ] || allow_stop # cannot identify the agent → fail open
161
- in_scope=false
162
- for a in $allowlist; do
163
- [ "$a" = "$agent_type" ] && in_scope=true && break
164
- done
165
- [ "$in_scope" = true ] || allow_stop
166
- fi
166
+
167
+ # --- scope gate: the persona's OWN stance manifest -------------------------------------------
168
+ # COMPOSITION IS THE SCOPE, NOT A RUNTIME SELF-FILTER — MODEL.md's ENFORCED clause, and this
169
+ # gate used to violate it outright. It read an allowlist, \`nico mav\` by default and overridable
170
+ # by \`STANCE_GUARD_AGENTS\`, which is precisely the runtime self-filter that clause forbids: a
171
+ # module asking WHO IS RUNNING rather than being placed where only the right launch reaches it.
172
+ #
173
+ # It had already drifted, in the direction such a list always drifts. Every agent in the corpus
174
+ # composes \`handoff\`, so \`Binding.agents\` DERIVES all six as bound, and six persona scopes are
175
+ # deployed to prove it — while the list enforced two. \`architect\` and \`kino\` held principal
176
+ # authority and were never once judged, and nothing surfaced the gap because the two facts were
177
+ # written in different languages in different files.
178
+ #
179
+ # Enrollment is now PRESENCE. Each bound persona's projection lands a manifest in that persona's
180
+ # own scope, and the dispatcher — which lives in that same scope and therefore already knows it
181
+ # — passes it in the envelope. A manifest means enrolled, and carries THIS agent's contract: its
182
+ # rubric, its moments, its handoff laws. No manifest means not enrolled, which is silence rather
183
+ # than an error, so a plain session that never declared itself anything stays untouched exactly
184
+ # as it was. Adding a persona enrolls it; adding a gated dimension edits one persona's manifest;
185
+ # neither is a line in this file.
186
+ stance_scope="$(printf '%s' "$input" | jq -r '.stance_scope // empty' 2>/dev/null || true)"
187
+ [ -n "$stance_scope" ] || allow_stop
188
+ manifest="$stance_scope/stance/manifest.json"
189
+ [ -f "$manifest" ] || allow_stop
190
+
191
+ # The persona's own contract, each field falling back to the shipped default. A manifest that
192
+ # names nothing still enrolls: presence is the assertion, the fields are the refinement.
193
+ agent_type="$(jq -r '.agent // empty' "$manifest" 2>/dev/null || true)"
194
+ manifest_rubric="$(jq -r '.rubric // empty' "$manifest" 2>/dev/null || true)"
195
+ # An OVERRIDE that does not resolve is a defect and goes DARK — a persona that asked to be judged
196
+ # against its own contract and is silently judged against someone else's has been mis-scored, not
197
+ # spared. The DEFAULT is not checked here: a judge backend need not read the file at all (the
198
+ # fixture judge does not), and refusing to run because a path the manifest never named is absent
199
+ # would fail closed on a case the manifest made no claim about.
200
+ case "$manifest_rubric" in
201
+ '') ;;
202
+ /*) RUBRIC="$manifest_rubric" ;;
203
+ *) RUBRIC="$stance_scope/stance/$manifest_rubric" ;;
204
+ esac
205
+ [ -z "$manifest_rubric" ] || [ -f "$RUBRIC" ] || \\
206
+ dark "the rubric named by $manifest is not readable at '\$RUBRIC'"
167
207
 
168
208
  # --- extract the last assistant turn from the transcript ------------------------------------
169
209
  transcript="$(printf '%s' "$input" | jq -r '.transcript_path // empty' 2>/dev/null || true)"
@@ -500,7 +540,24 @@ if [ -n "$evidence" ] && [ "\${#evidence}" -ge 12 ]; then
500
540
  # 3/5 on identical payloads — i.e. the record of WHY a turn was blocked was reconstructible only
501
541
  # by a non-deterministic process. Appended, never rotated by this hook; the state dir is tmp.
502
542
  printf '%s\\t%s\\t%s\\n' "$decision" "$evidence" "$reason" >> "$verdict_log" 2>/dev/null || true
503
- if ! printf '%s' "$asst_close" | tr '\\n' ' ' | grep -qF "$evidence"; then
543
+ # NORMALIZED ON BOTH SIDES, and with \`--\`, because this check had two ways to
544
+ # throw away a correct block — and both of them fired on the SAME shape, which is
545
+ # the one shape this guard most exists to catch.
546
+ #
547
+ # 1. \`grep -qF "$evidence"\` with no \`--\`: an evidence span opening with a markdown
548
+ # bullet is read as an OPTION. \`grep: invalid option -- ' '\`, non-zero, block
549
+ # discarded. A tail-enumeration collapse IS a bullet list, so its evidence always
550
+ # begins \`- \`, and the rule could never convict the shape it was written for.
551
+ # 2. A judge quoting several bullets joins them with spaces and drops the markers,
552
+ # so a verbatim-substring test fails on punctuation while every word is present.
553
+ #
554
+ # The proposition worth authenticating is that the judge quoted THIS TURN'S WORDS,
555
+ # not that it reproduced its list syntax. So both sides are flattened the same way:
556
+ # newlines to spaces, runs of whitespace to one, list markers dropped. Symmetric, so
557
+ # nothing is accepted on one side that would be rejected on the other.
558
+ ev_norm="$(printf '%s' "$evidence" | tr '\\n' ' ' | sed -e 's/[[:space:]][[:space:]]*/ /g' -e 's/^[-*][[:space:]]//' -e 's/ [-*] / /g')"
559
+ close_norm="$(printf '%s' "$asst_close" | tr '\\n' ' ' | sed -e 's/[[:space:]][[:space:]]*/ /g' -e 's/^[-*][[:space:]]//' -e 's/ [-*] / /g')"
560
+ if ! printf '%s' "$close_norm" | grep -qF -- "$ev_norm"; then
504
561
  printf 'stance-guardrail: DISCARDING block — judge quoted a span that is not in the turn'"'"'s CLOSE (mid-turn preamble, or confabulated): %s\\n' "$evidence" >&2
505
562
  allow_stop
506
563
  fi
@@ -1 +1 @@
1
- {"version":3,"file":"stance-guardrail.js","sourceRoot":"","sources":["../../src/hooks/stance-guardrail.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,mCAAmC,CAAC;AAG5D,wEAAwE;AACxE,8EAA8E;AAC9E,2EAA2E;AAC3E,2EAA2E;AAC3E,8EAA8E;AAC9E,gFAAgF;AAEhF,MAAM,CAAC,MAAM,eAAe,GAAa;IACvC,EAAE,EAAE,kBAAkB;IACtB,OAAO,EACL,8UAA8U;IAChV,SAAS,EAAE,SAAS;IACpB,KAAK,EAAE,CAAC;IACR,MAAM,EAAE,CAAC,UAAU,EAAE,cAAc,CAAC;IACpC,KAAK,EAAE,qBAAqB;IAC5B,OAAO,EAAE,EAAE;IACX,IAAI,EAAE,EAAE;IACR,OAAO,EAAE;QACP;YACE,QAAQ,EAAE,qBAAqB;YAC/B,UAAU,EAAE,sDAAsD;YAClE,UAAU,EAAE,IAAI;YAChB,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+jBd;SACI;QACD;YACE,QAAQ,EAAE,iBAAiB;YAC3B,UAAU,EAAE,kDAAkD;YAC9D,UAAU,EAAE,IAAI;YAChB,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmFd;SACI;QACD;YACE,QAAQ,EAAE,wBAAwB;YAClC,UAAU,EAAE,yDAAyD;YACrE,UAAU,EAAE,KAAK;YACjB,yEAAyE;YACzE,sEAAsE;YACtE,0EAA0E;YAC1E,2EAA2E;YAC3E,yEAAyE;YACzE,yEAAyE;YACzE,MAAM,EAAE,IAAI;YACZ,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAsNX,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyLV;SACI;KACF;CACF,CAAC"}
1
+ {"version":3,"file":"stance-guardrail.js","sourceRoot":"","sources":["../../src/hooks/stance-guardrail.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,mCAAmC,CAAC;AAG5D,wEAAwE;AACxE,8EAA8E;AAC9E,2EAA2E;AAC3E,2EAA2E;AAC3E,8EAA8E;AAC9E,gFAAgF;AAEhF,MAAM,CAAC,MAAM,eAAe,GAAa;IACvC,EAAE,EAAE,kBAAkB;IACtB,OAAO,EACL,8UAA8U;IAChV,SAAS,EAAE,SAAS;IACpB,KAAK,EAAE,CAAC;IACR,MAAM,EAAE,CAAC,UAAU,EAAE,cAAc,CAAC;IACpC,KAAK,EAAE,qBAAqB;IAC5B,OAAO,EAAE,EAAE;IACX,IAAI,EAAE,EAAE;IACR,OAAO,EAAE;QACP;YACE,QAAQ,EAAE,qBAAqB;YAC/B,UAAU,EAAE,sDAAsD;YAClE,UAAU,EAAE,IAAI;YAChB,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwnBd;SACI;QACD;YACE,QAAQ,EAAE,iBAAiB;YAC3B,UAAU,EAAE,kDAAkD;YAC9D,UAAU,EAAE,IAAI;YAChB,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmFd;SACI;QACD;YACE,QAAQ,EAAE,wBAAwB;YAClC,UAAU,EAAE,yDAAyD;YACrE,UAAU,EAAE,KAAK;YACjB,yEAAyE;YACzE,sEAAsE;YACtE,0EAA0E;YAC1E,2EAA2E;YAC3E,yEAAyE;YACzE,yEAAyE;YACzE,MAAM,EAAE,IAAI;YACZ,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAsNX,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyLV;SACI;KACF;CACF,CAAC"}
@@ -1,14 +1,14 @@
1
1
  /** The plan-layout state folders, in task-file lifecycle order. */
2
2
  export declare const PLAN_STATES: readonly ["pending", "ready", "active", "completed"];
3
3
  /** `frontier(P)` — the states a shard sits in when the plan is workable AT it
4
- * (praxis: `{ t | state(t) ∈ { ready, active } }`, where the plan IS, not merely
4
+ * (`{ t | state(t) ∈ { ready, active } }`, where the plan IS, not merely
5
5
  * what is dispatchable). A subset of {@link PLAN_STATES} and not derivable from
6
6
  * their ORDER: `pending` is open too, and is not frontier. */
7
7
  export declare const PLAN_FRONTIER: readonly ["ready", "active"];
8
8
  /**
9
9
  * The plan-tier dotfile MARKERS whose only home is here.
10
10
  *
11
- * A relation with no on-disk carrier is not readable — the reading `praxis.sh`
11
+ * A relation with no on-disk carrier is not readable — the reading `plan-set.sh`
12
12
  * states in its own words when it explains why `.landed` exists ("exactly parallel
13
13
  * to `.superseded-by`"). These are the two markers a reader of the plan set needs
14
14
  * that have no other TypeScript home: `.superseded-by` already has one
@@ -16,7 +16,7 @@ export declare const PLAN_FRONTIER: readonly ["ready", "active"];
16
16
  *
17
17
  * `.ruling-owed` is the third carrier this corpus has minted on that reading, and
18
18
  * it carries the concept the corpus ALREADY signifies as a ruling owed — "a
19
- * decision nobody has taken", which the `praxis` cell distinguishes from a
19
+ * decision nobody has taken", which the retired praxis cell distinguished from a
20
20
  * dependency ("a dep waits itself out, a ruling needs a human"). At the SHARD tier
21
21
  * that concept is `ruling-owed(t)`, and it gates `ready`; at the
22
22
  * PLAN tier it had no carrier at all, so a fork the principal cannot resolve —
@@ -12,7 +12,7 @@
12
12
  /** The plan-layout state folders, in task-file lifecycle order. */
13
13
  export const PLAN_STATES = ['pending', 'ready', 'active', 'completed'];
14
14
  /** `frontier(P)` — the states a shard sits in when the plan is workable AT it
15
- * (praxis: `{ t | state(t) ∈ { ready, active } }`, where the plan IS, not merely
15
+ * (`{ t | state(t) ∈ { ready, active } }`, where the plan IS, not merely
16
16
  * what is dispatchable). A subset of {@link PLAN_STATES} and not derivable from
17
17
  * their ORDER: `pending` is open too, and is not frontier. */
18
18
  export const PLAN_FRONTIER = [
@@ -22,7 +22,7 @@ export const PLAN_FRONTIER = [
22
22
  /**
23
23
  * The plan-tier dotfile MARKERS whose only home is here.
24
24
  *
25
- * A relation with no on-disk carrier is not readable — the reading `praxis.sh`
25
+ * A relation with no on-disk carrier is not readable — the reading `plan-set.sh`
26
26
  * states in its own words when it explains why `.landed` exists ("exactly parallel
27
27
  * to `.superseded-by`"). These are the two markers a reader of the plan set needs
28
28
  * that have no other TypeScript home: `.superseded-by` already has one
@@ -30,7 +30,7 @@ export const PLAN_FRONTIER = [
30
30
  *
31
31
  * `.ruling-owed` is the third carrier this corpus has minted on that reading, and
32
32
  * it carries the concept the corpus ALREADY signifies as a ruling owed — "a
33
- * decision nobody has taken", which the `praxis` cell distinguishes from a
33
+ * decision nobody has taken", which the retired praxis cell distinguished from a
34
34
  * dependency ("a dep waits itself out, a ruling needs a human"). At the SHARD tier
35
35
  * that concept is `ruling-owed(t)`, and it gates `ready`; at the
36
36
  * PLAN tier it had no carrier at all, so a fork the principal cannot resolve —
@@ -8,8 +8,8 @@
8
8
  // plan. "Carry on with what we just discussed" is the same utterance doing the same
9
9
  // work over a discussion, and a cell bound to `praxis` cannot serve it.
10
10
  //
11
- // The COMPOSITION is the operator's, at the utterance: "carry on with the praxis
12
- // execution" is carry-on ∘ praxis, and the pairing lives in what was said, not in
11
+ // The COMPOSITION is the operator's, at the utterance: "carry on with the plan
12
+ // execution" is carry-on ∘ plan, and the pairing lives in what was said, not in
13
13
  // this module's import list. A cell that names one context forecloses the rest.
14
14
  //
15
15
  // THE MECHANISM WENT WITH THE COUPLING, and that is a real loss recorded rather than
@@ -1 +1 @@
1
- {"version":3,"file":"skill.js","sourceRoot":"","sources":["../../../src/skills/carry-on/skill.ts"],"names":[],"mappings":"AAEA,mEAAmE;AACnE,EAAE;AACF,6EAA6E;AAC7E,oFAAoF;AACpF,kFAAkF;AAClF,qFAAqF;AACrF,mFAAmF;AACnF,oFAAoF;AACpF,wEAAwE;AACxE,EAAE;AACF,iFAAiF;AACjF,kFAAkF;AAClF,gFAAgF;AAChF,EAAE;AACF,qFAAqF;AACrF,qFAAqF;AACrF,kFAAkF;AAClF,sFAAsF;AACtF,kFAAkF;AAClF,oFAAoF;AACpF,mFAAmF;AACnF,2CAA2C;AAE3C,MAAM,eAAe,GACnB;;;;;;;;;;;;;;;;;;;;;CAqBkB,CAAC;AAErB,MAAM,CAAC,MAAM,OAAO,GAAU;IAC5B,IAAI,EAAE,UAAU;IAChB,WAAW,EAAE,woBAAwoB;IACrpB,WAAW,EAAE,eAAe;IAC5B,WAAW,EAAE,GAAG,EAAE,CAAC,EAAE;CACtB,CAAC"}
1
+ {"version":3,"file":"skill.js","sourceRoot":"","sources":["../../../src/skills/carry-on/skill.ts"],"names":[],"mappings":"AAEA,mEAAmE;AACnE,EAAE;AACF,6EAA6E;AAC7E,oFAAoF;AACpF,kFAAkF;AAClF,qFAAqF;AACrF,mFAAmF;AACnF,oFAAoF;AACpF,wEAAwE;AACxE,EAAE;AACF,+EAA+E;AAC/E,gFAAgF;AAChF,gFAAgF;AAChF,EAAE;AACF,qFAAqF;AACrF,qFAAqF;AACrF,kFAAkF;AAClF,sFAAsF;AACtF,kFAAkF;AAClF,oFAAoF;AACpF,mFAAmF;AACnF,2CAA2C;AAE3C,MAAM,eAAe,GACnB;;;;;;;;;;;;;;;;;;;;;CAqBkB,CAAC;AAErB,MAAM,CAAC,MAAM,OAAO,GAAU;IAC5B,IAAI,EAAE,UAAU;IAChB,WAAW,EAAE,woBAAwoB;IACrpB,WAAW,EAAE,eAAe;IAC5B,WAAW,EAAE,GAAG,EAAE,CAAC,EAAE;CACtB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cratylus/canon",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "The canonical corpus of discovered optimal-signifiers — agents, skills, dimensions and rules as typed TS source. Markdown is a projection of these modules.",
5
5
  "license": "MIT",
6
6
  "engines": {
@@ -21,7 +21,7 @@
21
21
  "@cratylus/schema": "0.2.0"
22
22
  },
23
23
  "devDependencies": {
24
- "@cratylus/forge": "0.5.0",
24
+ "@cratylus/forge": "0.6.0",
25
25
  "@cratylus/runtime": "0.2.0",
26
26
  "@cratylus/tooling": "0.0.0",
27
27
  "@types/node": "^22.0.0",
@@ -55,13 +55,10 @@
55
55
  "scripts": {
56
56
  "build": "pnpm run clean && tsc -p tsconfig.build.json",
57
57
  "clean": "rm -rf dist",
58
- "continuity": "sh targets/continuity/continuity-hook.sh",
59
58
  "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput",
60
- "oracle": "sh tooling/render-oracle/render-oracle.sh check",
61
- "oracle:update": "sh tooling/render-oracle/render-oracle.sh update",
62
59
  "pack:smoke": "tsx tooling/pack-smoke/pack-smoke-cli.ts",
63
60
  "plan-set": "tsx tooling/plan-set-cli.ts",
64
- "praxis": "sh tooling/praxis/praxis.sh",
61
+ "plan": "sh tooling/plan-set/plan-set.sh",
65
62
  "project:targets": "tsx tooling/project-targets-cli.ts",
66
63
  "scaffold": "tsx tooling/scaffold-cli.ts",
67
64
  "stance-guard:test": "sh test/support/guardrail/test-stance-guardrail.sh",
@@ -1,2 +0,0 @@
1
- import type { HookCell } from '../manifest.js';
2
- export declare const praxisContinuity: HookCell;
@@ -1,132 +0,0 @@
1
- // praxis-continuity — the repo-level post-commit reminder. A scope-activated source
2
- // cell on the GIT substrate: `vcs.commit.post` is an ordinary member of this
3
- // corpus's `CANONICAL_EVENTS` carrying `substrate: 'git'`, so it is routed rather
4
- // than refused — the `.husky/post-commit` dispatcher runs the committed worker
5
- // directly and nothing reaches `settings.json`. Its `workers[].content` are the
6
- // byte-anchors the committed `targets/continuity/` workers regenerate from
7
- // (byte-locked).
8
- //
9
- // THE REVIEW THIS CELL WAS FLAGGED FOR IS CLOSED. The note read "not in FORGE's
10
- // `CanonicalEvent` taxonomy" — stale by one package before it was stale by two, and
11
- // it asked for either an addition to the taxonomy or a named exception. Neither was
12
- // owed: the event was never exceptional, only unliterable, because the taxonomy was
13
- // a closed union in `schema` that a git moment had no member to be. The vocabulary
14
- // now lives where signification lives, `EventName` is open, and this cell names its
15
- // moment exactly as a harness cell names its own.
16
- export const praxisContinuity = {
17
- id: 'praxis-continuity',
18
- residue: 'post-commit detector ⟨task-file crosses state-folder ⇒ plan-mirror stale⟩ · nudge re-mirror · ¬edit · opt-in ↾ clone · exit-0 ⟨reminder ¬fail-commit⟩',
19
- substrate: 'git',
20
- events: ['vcs.commit.post'],
21
- // git substrate: the entry is still named, never spelled as a path. Which
22
- // directory git invokes it from is git's projection to make, not this cell's.
23
- entry: 'praxis-advance-nudge.sh',
24
- refs: [],
25
- workers: [
26
- {
27
- filename: 'continuity-hook.sh',
28
- targetPath: 'packages/canon/targets/continuity/continuity-hook.sh',
29
- executable: true,
30
- content: `#!/usr/bin/env sh
31
- # continuity-hook — opt this repo in/out of the post-commit continuity ritual.
32
- #
33
- # The opt-in flag is a per-repo git config (agentfactory.continuity) living in .git/config,
34
- # which is NOT checked in — so opting in is local to your clone and a fresh clone is
35
- # opted out by default. The .husky/post-commit dispatcher reads this flag.
36
- #
37
- # pnpm run continuity:install → set agentfactory.continuity true
38
- # pnpm run continuity:uninstall → unset (back to default off)
39
- # pnpm run continuity:status → show current state
40
- #
41
- # Usage: continuity-hook.sh {install|uninstall|status}
42
-
43
- set -e
44
-
45
- cmd="\${1:-status}"
46
-
47
- case "$cmd" in
48
- install | on | true)
49
- git config --bool agentfactory.continuity true
50
- printf 'continuity: ENABLED for this repo (agentfactory.continuity=true).\\n'
51
- printf ' Commits touching plans/**/{pending,ready,active,completed}/ now print a /praxis re-mirror reminder.\\n'
52
- ;;
53
- uninstall | off | false)
54
- git config --unset agentfactory.continuity 2>/dev/null || true
55
- printf 'continuity: DISABLED for this repo (agentfactory.continuity unset → default off).\\n'
56
- ;;
57
- status)
58
- state=$(git config --bool agentfactory.continuity 2>/dev/null || echo "false")
59
- printf 'continuity: %s (agentfactory.continuity=%s)\\n' \\
60
- "$([ "$state" = "true" ] && echo ENABLED || echo "disabled (default)")" "$state"
61
- ;;
62
- *)
63
- printf 'usage: continuity-hook.sh {install|uninstall|status}\\n' >&2
64
- exit 2
65
- ;;
66
- esac
67
- `,
68
- },
69
- {
70
- filename: 'praxis-advance-nudge.sh',
71
- targetPath: 'packages/canon/targets/continuity/praxis-advance-nudge.sh',
72
- executable: true,
73
- content: `#!/usr/bin/env sh
74
- # praxis-advance-nudge — the repo-level continuity ritual, as a post-commit reminder.
75
- #
76
- # WHAT IT DOES (and deliberately does NOT do):
77
- # When a commit moves plan task-files between their state folders
78
- # (plans/**/{pending,ready,active,completed}/), PLAN.md — the hand-authored
79
- # mirror of that folder-state — may now be stale. This script DETECTS that and
80
- # PRINTS A REMINDER to re-mirror via /praxis. It never edits PLAN.md: the mirror
81
- # is hand-authored prose; auto-rewriting it is out of scope (a future "mechanized
82
- # PLAN.md generation" task). Detect → remind, never edit. (doc-mirrors-runtime-truth:
83
- # the folders are the truth; this only flags that the mirror lagged.)
84
- #
85
- # SCOPE: praxis-advance is the ONE repo-level continuity ritual. Per-agent memory
86
- # operations (the \`memory\` runtime capability's sidecar state under
87
- # ~/.claude/agents/<name>/*) are not repo state — a git hook can't meaningfully
88
- # fire them — so they are out of this hook's scope.
89
- #
90
- # OPT-IN: this runs only when \`git config --bool agentfactory.continuity\` is true. A fresh
91
- # clone is opted out, so default commit behavior is unchanged. See continuity-hook.sh.
92
- #
93
- # POSIX sh; no deps beyond git. Exits 0 always — a reminder must never fail a commit.
94
-
95
- set -e
96
-
97
- # The commit just made (post-commit runs after HEAD has advanced).
98
- git rev-parse HEAD >/dev/null 2>&1 || exit 0
99
-
100
- # Files changed by HEAD. For a root commit (no parent) diff against the root.
101
- if git rev-parse --verify --quiet HEAD^ >/dev/null 2>&1; then
102
- changed=$(git diff-tree --no-commit-id --name-only -r HEAD 2>/dev/null) || exit 0
103
- else
104
- changed=$(git diff-tree --no-commit-id --name-only -r --root HEAD 2>/dev/null) || exit 0
105
- fi
106
-
107
- # Did this commit touch any plan state-folder? Match the four canonical states under
108
- # any plans/ subtree (works whether or not a tasks/ or {concern} wrapper is present).
109
- touched=$(printf '%s\\n' "$changed" \\
110
- | grep -E '^plans/.*/(pending|ready|active|completed)/' || true)
111
-
112
- [ -z "$touched" ] && exit 0
113
-
114
- # Which plan dirs were touched (dedup to the plan root: plans/<plan>/).
115
- plans=$(printf '%s\\n' "$touched" \\
116
- | sed -E 's#^(plans/[^/]+)/.*#\\1#' | sort -u)
117
-
118
- printf '\\n'
119
- printf 'continuity · praxis-advance — plan state changed in this commit:\\n'
120
- printf '%s\\n' "$plans" | sed 's/^/ /'
121
- printf '\\n'
122
- printf ' PLAN.md mirrors the task-folder state; it may now be stale.\\n'
123
- printf ' Re-mirror with /praxis (advance the task, re-sync PLAN.md), then amend or follow-up commit.\\n'
124
- printf ' (This is a reminder only — nothing was edited. Disable: pnpm run continuity:uninstall)\\n'
125
- printf '\\n'
126
-
127
- exit 0
128
- `,
129
- },
130
- ],
131
- };
132
- //# sourceMappingURL=praxis-continuity.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"praxis-continuity.js","sourceRoot":"","sources":["../../src/hooks/praxis-continuity.ts"],"names":[],"mappings":"AAEA,oFAAoF;AACpF,6EAA6E;AAC7E,kFAAkF;AAClF,+EAA+E;AAC/E,gFAAgF;AAChF,2EAA2E;AAC3E,iBAAiB;AACjB,EAAE;AACF,gFAAgF;AAChF,oFAAoF;AACpF,oFAAoF;AACpF,oFAAoF;AACpF,mFAAmF;AACnF,oFAAoF;AACpF,kDAAkD;AAElD,MAAM,CAAC,MAAM,gBAAgB,GAAa;IACxC,EAAE,EAAE,mBAAmB;IACvB,OAAO,EACL,uJAAuJ;IACzJ,SAAS,EAAE,KAAK;IAChB,MAAM,EAAE,CAAC,iBAAiB,CAAC;IAC3B,0EAA0E;IAC1E,8EAA8E;IAC9E,KAAK,EAAE,yBAAyB;IAChC,IAAI,EAAE,EAAE;IACR,OAAO,EAAE;QACP;YACE,QAAQ,EAAE,oBAAoB;YAC9B,UAAU,EAAE,sDAAsD;YAClE,UAAU,EAAE,IAAI;YAChB,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqCd;SACI;QACD;YACE,QAAQ,EAAE,yBAAyB;YACnC,UAAU,EAAE,2DAA2D;YACvE,UAAU,EAAE,IAAI;YAChB,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuDd;SACI;KACF;CACF,CAAC"}