@intutic/sync-daemon 2.9.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.
Files changed (97) hide show
  1. package/dist/disconnect/harnesses.d.ts.map +1 -1
  2. package/dist/disconnect/harnesses.js +4 -3
  3. package/dist/disconnect/harnesses.js.map +1 -1
  4. package/dist/disconnect/plan.d.ts +6 -1
  5. package/dist/disconnect/plan.d.ts.map +1 -1
  6. package/dist/disconnect/plan.js +4 -2
  7. package/dist/disconnect/plan.js.map +1 -1
  8. package/dist/harness/antigravityCliHooks.js +3 -3
  9. package/dist/harness/antigravityCliHooks.js.map +1 -1
  10. package/dist/harness/antigravityHooks.d.ts +8 -0
  11. package/dist/harness/antigravityHooks.d.ts.map +1 -1
  12. package/dist/harness/antigravityHooks.js +27 -5
  13. package/dist/harness/antigravityHooks.js.map +1 -1
  14. package/dist/harness/claudeCodeHooks.d.ts.map +1 -1
  15. package/dist/harness/claudeCodeHooks.js +58 -16
  16. package/dist/harness/claudeCodeHooks.js.map +1 -1
  17. package/dist/harness/clineHooks.d.ts.map +1 -1
  18. package/dist/harness/clineHooks.js +4 -2
  19. package/dist/harness/clineHooks.js.map +1 -1
  20. package/dist/harness/codexHooks.d.ts.map +1 -1
  21. package/dist/harness/codexHooks.js +4 -2
  22. package/dist/harness/codexHooks.js.map +1 -1
  23. package/dist/harness/cursorHooks.d.ts.map +1 -1
  24. package/dist/harness/cursorHooks.js +8 -3
  25. package/dist/harness/cursorHooks.js.map +1 -1
  26. package/dist/harness/gateBody.d.ts +177 -4
  27. package/dist/harness/gateBody.d.ts.map +1 -1
  28. package/dist/harness/gateBody.js +1658 -26
  29. package/dist/harness/gateBody.js.map +1 -1
  30. package/dist/harness/githubCopilotHooks.js +3 -3
  31. package/dist/harness/githubCopilotHooks.js.map +1 -1
  32. package/dist/harness/gooseHooks.d.ts.map +1 -1
  33. package/dist/harness/gooseHooks.js +8 -1
  34. package/dist/harness/gooseHooks.js.map +1 -1
  35. package/dist/harness/grokHooks.js +2 -2
  36. package/dist/harness/hermesHooks.js +1 -1
  37. package/dist/harness/hermesHooks.js.map +1 -1
  38. package/dist/harness/museHooks.d.ts.map +1 -1
  39. package/dist/harness/museHooks.js +4 -2
  40. package/dist/harness/museHooks.js.map +1 -1
  41. package/dist/harness/n8nHooks.js +1 -1
  42. package/dist/harness/openCodeHooks.d.ts.map +1 -1
  43. package/dist/harness/openCodeHooks.js +32 -8
  44. package/dist/harness/openCodeHooks.js.map +1 -1
  45. package/dist/harness/openclawHooks.d.ts.map +1 -1
  46. package/dist/harness/openclawHooks.js +19 -8
  47. package/dist/harness/openclawHooks.js.map +1 -1
  48. package/dist/harness/piHooks.js +7 -7
  49. package/dist/harness/windsurfHooks.js +2 -2
  50. package/dist/index.d.ts +9 -3
  51. package/dist/index.d.ts.map +1 -1
  52. package/dist/index.js +8 -2
  53. package/dist/index.js.map +1 -1
  54. package/dist/lib/approvedBypasses.d.ts +17 -4
  55. package/dist/lib/approvedBypasses.d.ts.map +1 -1
  56. package/dist/lib/approvedBypasses.js +17 -4
  57. package/dist/lib/approvedBypasses.js.map +1 -1
  58. package/dist/lib/approvedPlans.d.ts +73 -0
  59. package/dist/lib/approvedPlans.d.ts.map +1 -0
  60. package/dist/lib/approvedPlans.js +124 -0
  61. package/dist/lib/approvedPlans.js.map +1 -0
  62. package/dist/lib/decideLogs.d.ts +46 -0
  63. package/dist/lib/decideLogs.d.ts.map +1 -0
  64. package/dist/lib/decideLogs.js +160 -0
  65. package/dist/lib/decideLogs.js.map +1 -0
  66. package/dist/lib/policySnapshot.d.ts +143 -3
  67. package/dist/lib/policySnapshot.d.ts.map +1 -1
  68. package/dist/lib/policySnapshot.js +480 -14
  69. package/dist/lib/policySnapshot.js.map +1 -1
  70. package/dist/lib/refusalDetailPy.d.ts +11 -0
  71. package/dist/lib/refusalDetailPy.d.ts.map +1 -0
  72. package/dist/lib/refusalDetailPy.js +109 -0
  73. package/dist/lib/refusalDetailPy.js.map +1 -0
  74. package/dist/lib/ruleRecordPy.d.ts +11 -0
  75. package/dist/lib/ruleRecordPy.d.ts.map +1 -0
  76. package/dist/lib/ruleRecordPy.js +277 -0
  77. package/dist/lib/ruleRecordPy.js.map +1 -0
  78. package/dist/lib/scopeMatchPy.d.ts +11 -0
  79. package/dist/lib/scopeMatchPy.d.ts.map +1 -0
  80. package/dist/lib/scopeMatchPy.js +278 -0
  81. package/dist/lib/scopeMatchPy.js.map +1 -0
  82. package/dist/lib/sopFiles.d.ts.map +1 -1
  83. package/dist/lib/sopFiles.js +5 -3
  84. package/dist/lib/sopFiles.js.map +1 -1
  85. package/dist/lib/testOutcomePy.d.ts +11 -0
  86. package/dist/lib/testOutcomePy.d.ts.map +1 -0
  87. package/dist/lib/testOutcomePy.js +371 -0
  88. package/dist/lib/testOutcomePy.js.map +1 -0
  89. package/dist/skillWriter.d.ts +1 -1
  90. package/dist/skillWriter.d.ts.map +1 -1
  91. package/dist/skillWriter.js +7 -0
  92. package/dist/skillWriter.js.map +1 -1
  93. package/dist/syncCycle.d.ts +15 -2
  94. package/dist/syncCycle.d.ts.map +1 -1
  95. package/dist/syncCycle.js +15 -3
  96. package/dist/syncCycle.js.map +1 -1
  97. package/package.json +5 -5
@@ -0,0 +1,278 @@
1
+ /**
2
+ * The scope and plan match in Python, for the bash gates (their extractor already requires
3
+ * python3), emitted after the phrase matcher (`phrasesPy.ts`) in `GATE_PY_LIB`.
4
+ *
5
+ * Byte-identical to `packages/intutic-clawde/intutic_clawde/gate/scope_match.py`,
6
+ * which a test compares; edit that file and copy it here. It is the
7
+ * transliteration of `@intutic/shared-types`'s scopeMatch.ts, and both run the
8
+ * shared vectors. No backtick or dollar-brace, which this copy cannot hold.
9
+ */
10
+ export const SCOPE_MATCH_PY_SOURCE = String.raw `"""Scope and plan semantics, ported from the proxy so every surface answers
11
+ "is this change inside the scope?" and "is this run on its plan?" the same way
12
+ .
13
+
14
+ A transliteration of packages/shared-types/src/scopeMatch.ts; read that
15
+ module's docstring for each function's port of origin (detectors.rs,
16
+ sops.rs, manifest.rs). Every port runs
17
+ packages/shared-types/fixtures/scope-plan-vectors.json.
18
+
19
+ The bash hook gates emit this file after the phrase matcher's (phrases.py),
20
+ which is_file_write_call calls: imported here as a module, and found in the
21
+ emitting script's scope when it is not one. Otherwise the standard library
22
+ only, and no backtick or dollar-brace, which a TypeScript copy cannot hold.
23
+ """
24
+
25
+ try:
26
+ from .phrases import has_phrase, phrase_text
27
+ except (ImportError, KeyError): # embedded in a bash gate (exec without __name__), beside the phrase matcher's source
28
+ pass
29
+
30
+ PLAN_DEVIATION_TOLERANCE = 0.4
31
+ NARROWED_TO_NOTHING = "<none: workspace list disjoint from org ceiling>"
32
+
33
+ SCOPE_WRITE_TOOLS = ("write", "write_file", "writefile", "create_file", "createfile")
34
+ SCOPE_EDIT_TOOLS = ("edit", "edit_file", "editfile", "multiedit", "apply_patch", "str_replace", "notebookedit")
35
+ SCOPE_DELETE_TOOLS = ("delete_file", "deletefile", "remove_file", "rm_file")
36
+ SCOPE_MOVE_TOOLS = ("move_file", "movefile", "rename_file", "rename")
37
+ SCOPE_EDITOR_TOOLS = ("str_replace_editor", "text_editor", "texteditor", "str_replace_based_edit_tool")
38
+ SCOPE_PATH_KEYS = ("file_path", "filepath", "path", "filename", "target_file", "notebook_path")
39
+ SCOPE_COMMAND_KEYS = ("command", "cmd", "script")
40
+ SCOPE_SHELL_TOOLS = ("bash", "shell", "run_command", "runcommand", "execute_command", "run_shell_command",
41
+ "terminal", "execute", "exec")
42
+ SCOPE_READ_TOOLS = ("read", "readfile", "view", "cat", "open_file")
43
+ SCOPE_MOVE_FROM_KEYS = ("source", "source_path", "from", "old_path")
44
+ SCOPE_MOVE_TO_KEYS = ("destination", "destination_path", "to", "new_path")
45
+ SCOPE_TARGET_MAX_BYTES = 512
46
+ PLAN_EXEMPT_TOOLS = ("read", "readfile", "view", "cat", "open_file", "glob", "grep", "ls", "list_dir", "search",
47
+ "todowrite")
48
+ FILE_WRITE_SHELL_PHRASES = ("sed -i", "perl -i", "perl -pi", "git apply", "git am", "git checkout", "git switch",
49
+ "git restore", "git reset", "git merge", "git pull", "git rebase", "git cherry-pick",
50
+ "git revert", "git stash pop", "git stash apply", "patch -p")
51
+
52
+
53
+ def _ascii_lower(s):
54
+ return "".join(chr(ord(c) + 32) if "A" <= c <= "Z" else c for c in s)
55
+
56
+
57
+ def _tool_is(name, group):
58
+ lower = name.lower()
59
+ return any(lower == t or lower.endswith(t) for t in group)
60
+
61
+
62
+ def _keyed(inp, keys):
63
+ if not isinstance(inp, dict):
64
+ return None
65
+ for k in keys:
66
+ v = inp.get(k)
67
+ if isinstance(v, str) and v != "":
68
+ return v
69
+ return None
70
+
71
+
72
+ def _utf8_len(ch):
73
+ cp = ord(ch)
74
+ return 1 if cp < 0x80 else 2 if cp < 0x800 else 3 if cp < 0x10000 else 4
75
+
76
+
77
+ def _clip(s):
78
+ total = 0
79
+ for i, ch in enumerate(s):
80
+ n = _utf8_len(ch)
81
+ if total + n > SCOPE_TARGET_MAX_BYTES:
82
+ return s[:i] + "…"
83
+ total += n
84
+ return s
85
+
86
+
87
+ def _norm_scope(s):
88
+ t = s
89
+ while t[:2] == "./":
90
+ t = t[2:]
91
+ t = t.lstrip("/").rstrip("/")
92
+ return _ascii_lower(t)
93
+
94
+
95
+ def is_within_scope(target, scopes):
96
+ """Segment-prefix match of target against scopes, ignoring ASCII case and leading ./ or /."""
97
+ t = _norm_scope(target)
98
+ for raw in scopes:
99
+ s = _norm_scope(raw)
100
+ if s == "" or t == s or t[:len(s) + 1] == s + "/":
101
+ return True
102
+ return False
103
+
104
+
105
+ def sop_applies_to_role(roles, role):
106
+ if not roles:
107
+ return True
108
+ if role == "":
109
+ return False
110
+ return _ascii_lower(role) in roles
111
+
112
+
113
+ def collect_scope_paths(sops, role):
114
+ """The path scope in force for role (sops.rs collect_scope_paths), org ceiling included."""
115
+ workspace, org = [], []
116
+ for s in sops:
117
+ if not sop_applies_to_role(s["roles"], role):
118
+ continue
119
+ (org if s["scope"] == "org" else workspace).extend(s["scopePaths"])
120
+ if not org:
121
+ out = workspace
122
+ elif not workspace:
123
+ out = org
124
+ else:
125
+ out = [w for w in workspace if is_within_scope(w, org)] or [NARROWED_TO_NOTHING]
126
+ return sorted(set(out))
127
+
128
+
129
+ def collect_plan_steps(sops, role):
130
+ """The plan in force for role (sops.rs collect_plan_steps), org ceiling included."""
131
+ workspace, org = [], []
132
+ for s in sops:
133
+ if not sop_applies_to_role(s["roles"], role):
134
+ continue
135
+ (org if s["scope"] == "org" else workspace).extend(s["planSteps"])
136
+ if not org:
137
+ return workspace
138
+ if not workspace:
139
+ return org
140
+ allowed = {_ascii_lower(o) for o in org}
141
+ return [w for w in workspace if _ascii_lower(w) in allowed] or [NARROWED_TO_NOTHING]
142
+
143
+
144
+ def plan_off_steps(sequence, plan_steps, tolerance):
145
+ """{"offPlan", "ratio"}: the off-plan names, sorted and deduplicated, when their share is over tolerance."""
146
+ if not plan_steps or not sequence:
147
+ return {"offPlan": [], "ratio": 0}
148
+ plan = {_ascii_lower(p) for p in plan_steps}
149
+ off = [t for t in sequence if _ascii_lower(t) not in plan]
150
+ if not off:
151
+ return {"offPlan": [], "ratio": 0}
152
+ ratio = len(off) / len(sequence)
153
+ if ratio <= tolerance:
154
+ return {"offPlan": [], "ratio": ratio}
155
+ return {"offPlan": sorted(set(off)), "ratio": min(1, ratio)}
156
+
157
+
158
+ def change_targets(tool, inp):
159
+ """The mutations one tool call makes, as the proxy's change manifest records them."""
160
+ if _tool_is(tool, SCOPE_MOVE_TOOLS):
161
+ src = _keyed(inp, SCOPE_MOVE_FROM_KEYS)
162
+ dst = _keyed(inp, SCOPE_MOVE_TO_KEYS)
163
+ if src is not None or dst is not None:
164
+ return [{"op": "move", "target": _clip(t)} for t in (src, dst) if t is not None]
165
+ op = None
166
+ if _tool_is(tool, SCOPE_EDITOR_TOOLS):
167
+ command = inp.get("command") if isinstance(inp, dict) else None
168
+ command = _ascii_lower(command) if isinstance(command, str) else ""
169
+ if command == "view":
170
+ return []
171
+ op = "write" if command == "create" else "edit"
172
+ elif _tool_is(tool, SCOPE_WRITE_TOOLS):
173
+ op = "write"
174
+ elif _tool_is(tool, SCOPE_EDIT_TOOLS):
175
+ op = "edit"
176
+ elif _tool_is(tool, SCOPE_DELETE_TOOLS):
177
+ op = "delete"
178
+ if op is None:
179
+ return []
180
+ target = _keyed(inp, SCOPE_PATH_KEYS)
181
+ return [] if target is None else [{"op": op, "target": _clip(target)}]
182
+
183
+
184
+ def _diff_path(raw, prefix):
185
+ p = raw
186
+ tab = p.find("\t")
187
+ if tab != -1:
188
+ p = p[:tab]
189
+ p = p.strip(" ")
190
+ if len(p) >= 2 and p[0] == '"' and p[-1] == '"':
191
+ p = p[1:-1]
192
+ if p in ("/dev/null", ""):
193
+ return None
194
+ if prefix and p[:len(prefix)] == prefix:
195
+ p = p[len(prefix):]
196
+ return p or None
197
+
198
+
199
+ def diff_changed_paths(diff):
200
+ """The paths a diff changes, in the order first seen, each once."""
201
+ out = []
202
+
203
+ def add(p):
204
+ if p is not None and p not in out:
205
+ out.append(p)
206
+
207
+ for raw in diff.split("\n"):
208
+ line = raw[:-1] if raw.endswith("\r") else raw
209
+ if line[:11] == "diff --git ":
210
+ rest = line[11:]
211
+ if rest[:2] != "a/":
212
+ continue
213
+ first = rest.find(" b/")
214
+ if first == -1:
215
+ continue
216
+ if rest.find(" b/", first + 1) == -1:
217
+ add(_diff_path(rest[:first], "a/"))
218
+ add(_diff_path(rest[first + 1:], "b/"))
219
+ elif (len(rest) - 5) % 2 == 0:
220
+ n = (len(rest) - 5) // 2
221
+ a = rest[2:2 + n]
222
+ if rest[2 + n:5 + n] == " b/" and rest[5 + n:] == a:
223
+ add(_diff_path(a, ""))
224
+ elif line[:4] == "--- ":
225
+ add(_diff_path(line[4:], "a/"))
226
+ elif line[:4] == "+++ ":
227
+ add(_diff_path(line[4:], "b/"))
228
+ elif line[:12] == "rename from ":
229
+ add(_diff_path(line[12:], ""))
230
+ elif line[:10] == "rename to ":
231
+ add(_diff_path(line[10:], ""))
232
+ return out
233
+
234
+
235
+ def _normalise_path(p):
236
+ parts = []
237
+ for seg in p.split("/"):
238
+ if seg in ("", "."):
239
+ continue
240
+ if seg == "..":
241
+ if parts:
242
+ parts.pop()
243
+ else:
244
+ parts.append(seg)
245
+ return "/" + "/".join(parts)
246
+
247
+
248
+ def scope_relative_path(target, cwd, root):
249
+ """target relative to the workspace root, or None when outside it, under ~, or unresolvable."""
250
+ if target == "" or target[:1] == "~" or cwd[:1] != "/" or root[:1] != "/":
251
+ return None
252
+ absolute = _normalise_path(target if target[:1] == "/" else cwd + "/" + target)
253
+ base = _normalise_path(root)
254
+ if absolute == base:
255
+ return ""
256
+ head = "/" if base == "/" else base + "/"
257
+ return absolute[len(head):] if absolute[:len(head)] == head else None
258
+
259
+
260
+ def is_plan_exempt_tool(tool):
261
+ """Whether plan_approval: lets tool run before approval: a PLAN_EXEMPT_TOOLS name, bare or mcp__<server>__<name>."""
262
+ lower = tool.lower()
263
+ return any(lower == t or lower[-(len(t) + 2):] == "__" + t for t in PLAN_EXEMPT_TOOLS)
264
+
265
+
266
+ def is_file_write_call(tool, inp):
267
+ """Whether the call changed files: a mutation, or a shell command with a FILE_WRITE_SHELL_PHRASES phrase."""
268
+ if change_targets(tool, inp):
269
+ return True
270
+ if not _tool_is(tool, SCOPE_SHELL_TOOLS):
271
+ return False
272
+ command = _keyed(inp, SCOPE_COMMAND_KEYS)
273
+ if command is None:
274
+ return False
275
+ words = phrase_text(command)
276
+ return any(has_phrase(words, p) for p in FILE_WRITE_SHELL_PHRASES)
277
+ `;
278
+ //# sourceMappingURL=scopeMatchPy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scopeMatchPy.js","sourceRoot":"","sources":["../../src/lib/scopeMatchPy.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2Q9C,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"sopFiles.d.ts","sourceRoot":"","sources":["../../src/lib/sopFiles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,2CAA2C;AAC3C,MAAM,WAAW,OAAO;IACtB,qBAAqB;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,qFAAqF;IACrF,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAA;CACb;AAED;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,KAAK,IAAI,GACjD,OAAO,CAAC,OAAO,EAAE,CAAC,CA2BpB;AAqBD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAE5D;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED;;;;;;;;;GASG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAUpE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAGpG"}
1
+ {"version":3,"file":"sopFiles.d.ts","sourceRoot":"","sources":["../../src/lib/sopFiles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,2CAA2C;AAC3C,MAAM,WAAW,OAAO;IACtB,qBAAqB;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,qFAAqF;IACrF,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAA;CACb;AAED;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,KAAK,IAAI,GACjD,OAAO,CAAC,OAAO,EAAE,CAAC,CA2BpB;AAqBD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAE5D;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAI1D;AAED;;;;;;;;;GASG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAUpE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAGpG"}
@@ -58,7 +58,7 @@ export async function listSopFiles(sopsDir, onSkipped) {
58
58
  * null. Read line by line, no regex over the whole file: the content is
59
59
  * whatever an agent wrote.
60
60
  */
61
- function frontMatterValue(content, key) {
61
+ function frontMatterValue(content, key, topLevel = false) {
62
62
  const lines = content.trimStart().split('\n');
63
63
  if (lines[0]?.trim() !== '---')
64
64
  return null;
@@ -66,7 +66,7 @@ function frontMatterValue(content, key) {
66
66
  const t = line.trim();
67
67
  if (t === '---')
68
68
  return null;
69
- if (t.startsWith(key)) {
69
+ if ((topLevel ? line : t).startsWith(key)) {
70
70
  const v = t.slice(key.length).trim().replace(/^["']|["']$/g, '');
71
71
  return v || null;
72
72
  }
@@ -88,7 +88,9 @@ export function recordedSopId(content) {
88
88
  * proxy reads the same key (`pulled_but_not_enforced` in `sops.rs`).
89
89
  */
90
90
  export function markedNotEnforced(content) {
91
- return frontMatterValue(content, 'intutic_enforced:')?.toLowerCase() === 'false';
91
+ // Top level only, as `pulled_but_not_enforced` in sops.rs: a nested
92
+ // `intutic_enforced: false` must not switch a file off.
93
+ return frontMatterValue(content, 'intutic_enforced:', true)?.toLowerCase() === 'false';
92
94
  }
93
95
  /**
94
96
  * The local rule sets a session can select (`intutic loop start --sops`,
@@ -1 +1 @@
1
- {"version":3,"file":"sopFiles.js","sourceRoot":"","sources":["../../src/lib/sopFiles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,OAAO,MAAM,kBAAkB,CAAA;AAC3C,OAAO,KAAK,SAAS,MAAM,WAAW,CAAA;AAYtC;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,OAAe,EACf,SAAkD;IAElD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAA;IACvE,MAAM,MAAM,GAAG,CAAC,CAAmB,EAAE,CAAmB,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAC7G,MAAM,IAAI,GAAc,EAAE,CAAA;IAC1B,MAAM,MAAM,GAAc,EAAE,CAAA;IAC5B,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAA;QAC5C,wEAAwE;QACxE,MAAM,IAAI,GAAG,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QAChF,IAAI,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC7C,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;QACjD,CAAC;aAAM,IAAI,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1D,IAAI,KAAiC,CAAA;YACrC,IAAI,CAAC;gBACH,KAAK,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAA;YAC9D,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,SAAS,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;gBACtB,SAAQ;YACV,CAAC;YACD,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;gBACxC,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAA;gBAC7C,MAAM,QAAQ,GAAG,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;gBACxF,IAAI,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;oBAAE,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;YACjH,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,IAAI,EAAE,GAAG,MAAM,CAAC,CAAA;AAC7B,CAAC;AAED;;;;GAIG;AACH,SAAS,gBAAgB,CAAC,OAAe,EAAE,GAAW;IACpD,MAAM,KAAK,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAC7C,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,KAAK;QAAE,OAAO,IAAI,CAAA;IAC3C,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QAClC,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;QACrB,IAAI,CAAC,KAAK,KAAK;YAAE,OAAO,IAAI,CAAA;QAC5B,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACtB,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAA;YAChE,OAAO,CAAC,IAAI,IAAI,CAAA;QAClB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,OAAe;IAC3C,OAAO,gBAAgB,CAAC,OAAO,EAAE,aAAa,CAAC,CAAA;AACjD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAe;IAC/C,OAAO,gBAAgB,CAAC,OAAO,EAAE,mBAAmB,CAAC,EAAE,WAAW,EAAE,KAAK,OAAO,CAAA;AAClF,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAAe;IAC/C,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAe,CAAC,CAAA;IACtE,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAgB,CAAC,CAAC,CAAC,CAAA;IACnG,MAAM,IAAI,GAAa,EAAE,CAAA;IACzB,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,CAAC,MAAM,KAAK,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC;YAAE,SAAQ;QAClE,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;QACzE,IAAI,OAAO,KAAK,IAAI,IAAI,aAAa,CAAC,OAAO,CAAC,KAAK,IAAI;YAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;IAC5E,CAAC;IACD,OAAO,CAAC,GAAG,OAAO,EAAE,GAAG,IAAI,CAAC,CAAA;AAC9B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,IAAa,EAAE,OAAe,EAAE,SAA4B;IACzF,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IAChE,OAAO,aAAa,CAAC,OAAO,CAAC,KAAK,IAAI,IAAI,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACzE,CAAC"}
1
+ {"version":3,"file":"sopFiles.js","sourceRoot":"","sources":["../../src/lib/sopFiles.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The test outcome decision and the per-session outcome state in Python, for the bash gates (their extractor already requires
3
+ * python3), emitted after the phrase matcher (`phrasesPy.ts`) in `GATE_PY_LIB`.
4
+ *
5
+ * Byte-identical to `packages/intutic-clawde/intutic_clawde/gate/test_outcome.py`,
6
+ * which a test compares; edit that file and copy it here. It is the
7
+ * transliteration of `@intutic/shared-types`'s testOutcome.ts, and both run the
8
+ * shared vectors. No backtick or dollar-brace, which this copy cannot hold.
9
+ */
10
+ export declare const TEST_OUTCOME_PY_SOURCE: string;
11
+ //# sourceMappingURL=testOutcomePy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testOutcomePy.d.ts","sourceRoot":"","sources":["../../src/lib/testOutcomePy.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB,QAwWlC,CAAA"}