devlyn-cli 4.3.31 → 4.3.32

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 (31) hide show
  1. package/README.md +3 -1
  2. package/bin/devlyn.js +33 -8
  3. package/bin/harness-activation.js +4 -1
  4. package/bin/harness-status.js +15 -8
  5. package/bin/skill-history.json +7 -0
  6. package/config/skills/_shared/bring-in.py +10 -0
  7. package/config/skills/_shared/task-complete.py +319 -54
  8. package/config/skills/_shared/task-completion.md +5 -5
  9. package/config/skills/_shared/warm-build-dirs.py +13 -0
  10. package/config/skills/devlyn-ideate/references/loop.md +1 -1
  11. package/config/skills/devlyn-ideate/scripts/acceptance.py +11 -0
  12. package/config/skills/devlyn-ideate/scripts/queue.py +17 -1
  13. package/native/claude/.claude-plugin/plugin.json +1 -1
  14. package/native/claude/skills/_shared/bring-in.py +10 -0
  15. package/native/claude/skills/_shared/task-complete.py +319 -54
  16. package/native/claude/skills/_shared/task-completion.md +5 -5
  17. package/native/claude/skills/_shared/warm-build-dirs.py +13 -0
  18. package/native/claude/skills/devlyn-ideate/references/loop.md +1 -1
  19. package/native/claude/skills/devlyn-ideate/scripts/acceptance.py +11 -0
  20. package/native/claude/skills/devlyn-ideate/scripts/queue.py +17 -1
  21. package/native/codex/.agents/plugins/marketplace.json +1 -1
  22. package/native/codex/plugins/devlyn/.codex-plugin/plugin.json +1 -1
  23. package/native/codex/plugins/devlyn/skills/_shared/bring-in.py +10 -0
  24. package/native/codex/plugins/devlyn/skills/_shared/task-complete.py +319 -54
  25. package/native/codex/plugins/devlyn/skills/_shared/task-completion.md +5 -5
  26. package/native/codex/plugins/devlyn/skills/_shared/warm-build-dirs.py +13 -0
  27. package/native/codex/plugins/devlyn/skills/devlyn-ideate/references/loop.md +1 -1
  28. package/native/codex/plugins/devlyn/skills/devlyn-ideate/scripts/acceptance.py +11 -0
  29. package/native/codex/plugins/devlyn/skills/devlyn-ideate/scripts/queue.py +17 -1
  30. package/package.json +1 -1
  31. package/release.json +32 -32
@@ -201,14 +201,14 @@ publication mode pushes no task commit and opens no PR. Delivery is `COMPLETE` w
201
201
  `pr` pushes the exact accepted task ref and creates/reuses its exact repository,
202
202
  head and base PR. While OPEN, it cancels owned auto-merge, reports `PR` with its URL
203
203
  and retains the checkout. Once MERGED by any method, either mode cleans released
204
- resources in that call, on resume or at the next allocation. Default `auto` also requests
205
- a `--merge --match-head-commit <accepted SHA>` merge. Repository
206
- checks/reviews and merge policy remain authoritative: no admin bypass, strategy
204
+ resources in that call, on resume or at the next allocation. Default `auto` also
205
+ merges the accepted commit. Merge policy remains authoritative: no admin bypass, strategy
207
206
  fallback or repository setting changes. When the repository disallows merge
208
- commits or refuses the request, delivery reports `PR` with `merge_refused` and
207
+ commits or refuses the merge, delivery reports `PR` with `merge_refused` and
209
208
  the PR waits for a person. Command success alone never proves merge.
210
209
 
211
- `PENDING` retains the workspace and reports a receipt-based resume command.
210
+ `PENDING` retains the workspace; its receipt-based resume command merges once
211
+ required checks or reviews pass, or a person merges it.
212
212
  `BLOCKED` names the cause and retry action; repair that condition before retrying.
213
213
  Resume reobserves Git/PR state under a per-receipt lock, reuses the original
214
214
  acceptance and performs only missing eligible effects.
@@ -706,9 +706,14 @@ class WarmTests(unittest.TestCase):
706
706
  (bin_dir / "cargo").write_text(FAKE_CARGO)
707
707
  (bin_dir / "cargo").chmod(0o755)
708
708
  self.fixture, self.log = self.root / "fixture.json", self.root / "cargo.log"
709
+ # A commit's detached automatic maintenance would still write into .git while a test reads the tree. Appended to
710
+ # the inherited GIT_CONFIG_COUNT entries, which this environment keeps.
711
+ count = int(os.environ.get("GIT_CONFIG_COUNT") or 0)
709
712
  self.environment = mock.patch.dict(os.environ, {
710
713
  "PATH": f"{bin_dir}{os.pathsep}{os.environ['PATH']}", "FAKE_CARGO": str(self.fixture),
711
714
  "FAKE_CARGO_LOG": str(self.log), "GIT_CONFIG_GLOBAL": os.devnull, "GIT_CONFIG_NOSYSTEM": "1",
715
+ "GIT_CONFIG_COUNT": str(count + 1), f"GIT_CONFIG_KEY_{count}": "maintenance.auto",
716
+ f"GIT_CONFIG_VALUE_{count}": "false",
712
717
  "PYTHONPATH": str(self.root) + os.pathsep + os.environ.get("PYTHONPATH", ""),
713
718
  "PYTHONDONTWRITEBYTECODE": "1",
714
719
  "GIT_AUTHOR_NAME": "t", "GIT_AUTHOR_EMAIL": "t@t", "GIT_COMMITTER_NAME": "t", "GIT_COMMITTER_EMAIL": "t@t"})
@@ -749,6 +754,14 @@ class WarmTests(unittest.TestCase):
749
754
  def git(self, work, *args):
750
755
  return subprocess.run(["git", "-C", str(work), *args], check=True, capture_output=True, text=True).stdout
751
756
 
757
+ def test_fixture_commit_starts_no_automatic_maintenance(self):
758
+ # Its detached child would still write into .git while a test reads the tree or cleanup removes it.
759
+ trace = self.root / "trace.json"
760
+ os.environ["GIT_TRACE2_EVENT"] = str(trace) # setUp's patch restores the environment
761
+ self.git(self.anchor, "commit", "-q", "--allow-empty", "-m", "traced")
762
+ children = [line for line in trace.read_text(encoding="utf-8").splitlines() if '"event":"child_start"' in line]
763
+ self.assertEqual(children, [])
764
+
752
765
  def write_fixture(self, **extra):
753
766
  packages = [
754
767
  {"name": "app", "source": None, "manifest_path": str(self.work / "Cargo.toml"), "targets": [{"kind": ["lib"], "name": "LIB"}]},
@@ -32,7 +32,7 @@ The host supplies the executor and maps its configured engine to the argv; the l
32
32
  6. **Derive acceptance** with `acceptance.py accept`. It binds the committed contract to the packet digests; requires the candidate to be the owned branch head with HEAD checked out on that branch, to descend from the inputs, to leave the package (its queue file included) and `docs/specs/queue.md` untouched and to have a clean worktree; executes each declared command on that source, recording raw stdout/stderr and exit, timeout or spawn outcomes (a runner result is reused only when it is wholly clean — no reasons, so no failed check and no source change during its checks — for the same source and contract digests, with unchanged streams); evaluates the file and diff guards against the inputs; confirms the source is unchanged; checks review records; and writes `.devlyn/loop/acceptance.json`. Missing checks, missing review coverage and open binding findings cannot produce `[x]`, and acceptance weakening is not repair. This establishes command outcomes and evidence completeness, not a reviewer's semantic judgment; deliberate evidence forgery is outside the trust model.
33
33
  7. **Bind before terminal metadata.** `task-complete.py accept --receipt <receipt> --acceptance <worktree>/.devlyn/loop/acceptance.json` takes evidence custody and points the recovery ref at the source. Failed results are bound the same way; they never become a frontier or a publishable product.
34
34
  8. **Commit the terminal transition** under the queue lock: one commit whose sole parent is the bound source and whose only change is this task's row in `docs/specs/<loop-id>/queue.md` (`[x]`, or `[F] — <first reason> (receipt <id>)`), validated as the only legal transition. Then `task-complete.py attach --receipt <receipt> --commit <terminal> --file docs/specs/<loop-id>/queue.md` records it separately from the source and moves the recovery ref to it.
35
- 9. **Deliver** after waiting for the executor, with `task-complete.py complete --receipt <receipt> --writers-stopped`, plus `--local-only` or, until the receipt records a mode, the packet's `--mode auto|pr`, so a per-task `--mode` persists. Local-only keeps source, custody and the recovery ref with no remote effect. `auto`/`pr` publish the terminal commit under the completion contract; a pending or refused delivery keeps product acceptance, resources and a resume command. Where writer cessation cannot be observed, or a process still uses the tree, a merged delivery settles (`COMPLETE`) with its workspace, task ref and custody retained and reported under workspace cleanup; retained cleanup never blocks the queue. Failed products are never published. The receipt's `delivery` field checkpoints the latest outcome. A local chain is never turned into stacked PRs; publishing it requires integrated acceptance of the actual publication candidate.
35
+ 9. **Deliver** after waiting for the executor, with `task-complete.py complete --receipt <receipt> --writers-stopped`, plus `--local-only` or, until the receipt records a mode, the packet's `--mode auto|pr`, so a per-task `--mode` persists. Local-only keeps source, custody and the recovery ref with no remote effect. `auto`/`pr` publish the terminal commit under the completion contract; a pending or refused delivery keeps product acceptance, resources and a resume command. A merged delivery whose cleanup is refused settles (`COMPLETE`) with what the refusal guards retained and reported under workspace cleanup; retained cleanup never blocks the queue. Failed products are never published. The receipt's `delivery` field checkpoints the latest outcome. A local chain is never turned into stacked PRs; publishing it requires integrated acceptance of the actual publication candidate.
36
36
  10. **Recover** from durable state only:
37
37
 
38
38
  | Interrupted | Resume |
@@ -515,6 +515,8 @@ class AcceptanceTests(unittest.TestCase):
515
515
  self.addCleanup(self.temp.cleanup)
516
516
  self.root = Path(self.temp.name).resolve()
517
517
  self.work = self.root / "work tree"
518
+ # A commit's detached automatic maintenance would still write into .git while a test reads the tree.
519
+ (self.root / "gitconfig").write_text("[maintenance]\n\tauto = false\n", encoding="utf-8")
518
520
  env = {"GIT_CONFIG_NOSYSTEM": "1", "GIT_CONFIG_GLOBAL": str(self.root / "gitconfig"), "GIT_AUTHOR_NAME": "Fixture",
519
521
  "GIT_AUTHOR_EMAIL": "fixture@example.invalid", "GIT_COMMITTER_NAME": "Fixture", "GIT_COMMITTER_EMAIL": "fixture@example.invalid"}
520
522
  self.saved = {key: os.environ.get(key) for key in env}
@@ -543,6 +545,15 @@ class AcceptanceTests(unittest.TestCase):
543
545
  self.g("commit", "-q", "-m", message)
544
546
  return self.g("rev-parse", "HEAD")
545
547
 
548
+ def test_fixture_commit_starts_no_automatic_maintenance(self):
549
+ # Its detached child would still write into .git while a test reads the tree or cleanup removes it.
550
+ from unittest import mock
551
+ trace = self.root / "trace.json"
552
+ with mock.patch.dict(os.environ, GIT_TRACE2_EVENT=str(trace)):
553
+ self.g("commit", "-q", "--allow-empty", "-m", "traced")
554
+ children = [line for line in trace.read_text(encoding="utf-8").splitlines() if '"event":"child_start"' in line]
555
+ self.assertEqual(children, [])
556
+
546
557
  def inputs(self, expected=None, review=()):
547
558
  base = self.g("rev-parse", "HEAD")
548
559
  files = {"docs/specs/l/meta.md": "# meta\n", "docs/specs/l/t/spec.md": "# task R1 R2\n",
@@ -1429,6 +1429,8 @@ def advance(v, row, opts):
1429
1429
  progress(identity, f"delivery {result['status']}")
1430
1430
  if result.get("merge_refused"):
1431
1431
  return f"merge refused: {result['merge_refused']}; a person merges the PR"
1432
+ if waits := result.get("merge_waits"):
1433
+ return f"merge waits: PR is {waits} ({'GitHub has not computed its mergeability yet' if waits == 'UNKNOWN' else 'required checks or reviews not passing yet'}); drain again later, or merge it"
1432
1434
  return None
1433
1435
 
1434
1436
 
@@ -1657,11 +1659,15 @@ def status_summary(v):
1657
1659
  row = next_task(v, set())
1658
1660
  annotate(v, {})
1659
1661
  tasks = [summary(v, r) for r in v["rows"] if r["identity"]]
1662
+ # A task without a resume is no pending delivery, so a cleanup it retained is named here with its own resume.
1663
+ retained = [f"{t['identity']}: {label} {t[key]}" for t in tasks if not t.get("resume")
1664
+ for key, field, label in (("cleanup", "workspace_cleanup", "workspace cleanup"), ("scratch", "scratch_cleanup", "scratch cleanup"))
1665
+ if ((v["states"][t["identity"]]["receipt"] or {}).get(field) or {}).get("reason")]
1660
1666
  return {"status": "OK", **skill_diagnostics(anchor), "counts": counts(v), "next": row["identity"] if row else None,
1661
1667
  "blockers": [f"{t['identity']}: {t['reason']}" for t in tasks if t.get("reason") and t["result"] in {"pending", "active", "blocked"}]
1662
1668
  + [f"legacy row {r['index'] + 1} needs planning: {r['text']}" for r in v["rows"] if not r["identity"] and r["mark"] == " "]
1663
1669
  + [f"unreadable receipt {item}" for item in v["unreadable"]],
1664
- "delivery": [t for t in tasks if t.get("resume")], "cleanup": v["cleanup"]}
1670
+ "delivery": [t for t in tasks if t.get("resume")], "cleanup": v["cleanup"] + retained}
1665
1671
 
1666
1672
 
1667
1673
  def status(args):
@@ -1897,6 +1903,8 @@ class QueueTests(unittest.TestCase):
1897
1903
  "import shutil\nfrom types import SimpleNamespace\n"
1898
1904
  "shutil.disk_usage = lambda path: SimpleNamespace(total=100 * 1024**3, free=100 * 1024**3)\n",
1899
1905
  encoding="utf-8")
1906
+ # A commit's detached automatic maintenance would still write into .git while a test reads the tree.
1907
+ (self.root / "gitconfig").write_text("[maintenance]\n\tauto = false\n", encoding="utf-8")
1900
1908
  self.env = {**os.environ, "GIT_CONFIG_NOSYSTEM": "1", "GIT_CONFIG_GLOBAL": str(self.root / "gitconfig"),
1901
1909
  "GIT_AUTHOR_NAME": "Fixture", "GIT_AUTHOR_EMAIL": "fixture@example.invalid",
1902
1910
  "GIT_COMMITTER_NAME": "Fixture", "GIT_COMMITTER_EMAIL": "fixture@example.invalid"}
@@ -1940,6 +1948,14 @@ class QueueTests(unittest.TestCase):
1940
1948
  path.write_text(text.replace(old, new, 1), encoding="utf-8")
1941
1949
  return mutate
1942
1950
 
1951
+ def test_fixture_commit_starts_no_automatic_maintenance(self):
1952
+ # Its detached child would still write into .git while a test reads the tree or cleanup removes it.
1953
+ trace = self.root / "trace.json"
1954
+ subprocess.run(["git", "-C", str(self.anchor), "commit", "-q", "--allow-empty", "-m", "traced"], check=True,
1955
+ env={**self.env, "GIT_TRACE2_EVENT": str(trace)})
1956
+ children = [line for line in trace.read_text(encoding="utf-8").splitlines() if '"event":"child_start"' in line]
1957
+ self.assertEqual(children, [])
1958
+
1943
1959
  def test_package_validation(self):
1944
1960
  self.assertEqual(self.cli("check", self.meta)["tasks"], ["inv.t1", "inv.t2"])
1945
1961
  manifest = json.loads(JSON_FENCE_RE.search((self.anchor / "docs/specs/inv/meta.md").read_text(encoding="utf-8")).group(1))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "devlyn-cli",
3
- "version": "4.3.31",
3
+ "version": "4.3.32",
4
4
  "description": "Loop & harness engineering for AI coding agents (Claude Code, Codex, and any AGENTS.md-driven agent) — core engineering principles for every session and a loop designer that splits one intent into tasks agents drain hands-free",
5
5
  "homepage": "https://github.com/fysoul17/devlyn-cli#readme",
6
6
  "bin": {
package/release.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "package": "devlyn-cli",
4
- "version": "4.3.31",
4
+ "version": "4.3.32",
5
5
  "principles": {
6
6
  "defaults": "config/skills/_shared/runtime-principles.md",
7
7
  "memory": {
@@ -114,7 +114,7 @@
114
114
  },
115
115
  {
116
116
  "path": "README.md",
117
- "sha256": "fa6956e7d769d1b7731b804af07f0a0d30fb775e5be7cf53e3099257f71f7ac8",
117
+ "sha256": "bbc875764d90876e032b71363bf833bc0919368940943bfd66f1fb72391306fe",
118
118
  "executable": false
119
119
  },
120
120
  {
@@ -129,7 +129,7 @@
129
129
  },
130
130
  {
131
131
  "path": "bin/devlyn.js",
132
- "sha256": "d74e237346ffc0966867bbaf3a5c411b5a25888575b6c363f9347cd6a7c90b02",
132
+ "sha256": "3a68ed60da74b66fe6303819924128cb11b1bc64a63518b947dc6b26a631325d",
133
133
  "executable": true
134
134
  },
135
135
  {
@@ -139,7 +139,7 @@
139
139
  },
140
140
  {
141
141
  "path": "bin/harness-activation.js",
142
- "sha256": "e5428bf6fb2dc40e0f7bebcc834b54573c0b8c648570fea8bd51774d5e865727",
142
+ "sha256": "8457005c714c93a31c0b65c26ccd604fdd760f7db978045dbdd1b5724532f742",
143
143
  "executable": false
144
144
  },
145
145
  {
@@ -154,7 +154,7 @@
154
154
  },
155
155
  {
156
156
  "path": "bin/harness-status.js",
157
- "sha256": "7cc1bc83594952806142a7e3bda2430d21a583ae31a3b1800aa2811a645e0ad0",
157
+ "sha256": "6b0b209d77253eef4c92d38b939c4e0828705128d37ed7158d033bdadd762280",
158
158
  "executable": false
159
159
  },
160
160
  {
@@ -174,7 +174,7 @@
174
174
  },
175
175
  {
176
176
  "path": "bin/skill-history.json",
177
- "sha256": "4a409eac690da7f3611c67a4fd5e3d9abb354199848bffff27ac441a6a491878",
177
+ "sha256": "bb5a18a5c7f846c6e3b427a141600a1699dcf01e724193d840f9a10874954057",
178
178
  "executable": false
179
179
  },
180
180
  {
@@ -204,7 +204,7 @@
204
204
  },
205
205
  {
206
206
  "path": "config/skills/_shared/bring-in.py",
207
- "sha256": "754b3892ceb611c855f814e0aa54b645b53de4a67ddec44418f254cb36774527",
207
+ "sha256": "b712de03e30b8a5b29f13f3eb9b0c3787f68edaaa980e0b25fe90885365861d5",
208
208
  "executable": false
209
209
  },
210
210
  {
@@ -274,12 +274,12 @@
274
274
  },
275
275
  {
276
276
  "path": "config/skills/_shared/task-complete.py",
277
- "sha256": "1f39a27e0dc70c727dc79d47c2b294e75bfd1efbc8df4f0492d68578a29405a2",
277
+ "sha256": "5f893064511e273258ebe721e967166485a812fbe9a9f1e818e2c605ef039abc",
278
278
  "executable": false
279
279
  },
280
280
  {
281
281
  "path": "config/skills/_shared/task-completion.md",
282
- "sha256": "3b75502d363ba5fa3b45c06a1f3e0de7c88e609d4f91c41d75287a0acccdd504",
282
+ "sha256": "26a0634d2c38753b0d226946eac7fc395b6f21b3e460433d2638b7eb6a57ad3a",
283
283
  "executable": false
284
284
  },
285
285
  {
@@ -289,7 +289,7 @@
289
289
  },
290
290
  {
291
291
  "path": "config/skills/_shared/warm-build-dirs.py",
292
- "sha256": "ccc842227dfe8d531b06e0e32a13a580c127af9c354b086548da8c547af6c2b0",
292
+ "sha256": "981cab5ea6629182aef01dca1eb2b410ab91fd4581dd500f58e0a8313b39f245",
293
293
  "executable": false
294
294
  },
295
295
  {
@@ -314,7 +314,7 @@
314
314
  },
315
315
  {
316
316
  "path": "config/skills/devlyn-ideate/references/loop.md",
317
- "sha256": "ad64d90fb775b05ef774c2457fc9d994b062e17e017da07054be0d93d83e533f",
317
+ "sha256": "1b7f48ddbe5bbdf0145d7e6797784d5e7fa1af548e751ad6e6869a96de65b58f",
318
318
  "executable": false
319
319
  },
320
320
  {
@@ -329,12 +329,12 @@
329
329
  },
330
330
  {
331
331
  "path": "config/skills/devlyn-ideate/scripts/acceptance.py",
332
- "sha256": "5e25ce6fcbd1773e988a1146f0f4a681676936dad113c43c693fdb0925aa168a",
332
+ "sha256": "1c2c173f05f9688839356898dea6e395fea83e78d5c8bc0e00b0d971a33381e9",
333
333
  "executable": false
334
334
  },
335
335
  {
336
336
  "path": "config/skills/devlyn-ideate/scripts/queue.py",
337
- "sha256": "f8447d7f1a3d04332e9aefdd363e15a9351c46ce2b165d4e75cce45906f132cf",
337
+ "sha256": "db80fd2cae92dda70e9b6183e8b9396dca9592358a38ed19fb6893ed3a531dd2",
338
338
  "executable": false
339
339
  },
340
340
  {
@@ -354,7 +354,7 @@
354
354
  },
355
355
  {
356
356
  "path": "native/claude/.claude-plugin/plugin.json",
357
- "sha256": "a70dddfa4b8c6095d52066ae94fa4c0ff2223d2c601614b825d59c3de5a313f3",
357
+ "sha256": "ff300febb5b5d8469c3258416f63e156cc05b911ee6f3cf2cd818fbf70f5e80b",
358
358
  "executable": false
359
359
  },
360
360
  {
@@ -379,7 +379,7 @@
379
379
  },
380
380
  {
381
381
  "path": "native/claude/skills/_shared/bring-in.py",
382
- "sha256": "754b3892ceb611c855f814e0aa54b645b53de4a67ddec44418f254cb36774527",
382
+ "sha256": "b712de03e30b8a5b29f13f3eb9b0c3787f68edaaa980e0b25fe90885365861d5",
383
383
  "executable": false
384
384
  },
385
385
  {
@@ -449,12 +449,12 @@
449
449
  },
450
450
  {
451
451
  "path": "native/claude/skills/_shared/task-complete.py",
452
- "sha256": "1f39a27e0dc70c727dc79d47c2b294e75bfd1efbc8df4f0492d68578a29405a2",
452
+ "sha256": "5f893064511e273258ebe721e967166485a812fbe9a9f1e818e2c605ef039abc",
453
453
  "executable": false
454
454
  },
455
455
  {
456
456
  "path": "native/claude/skills/_shared/task-completion.md",
457
- "sha256": "3b75502d363ba5fa3b45c06a1f3e0de7c88e609d4f91c41d75287a0acccdd504",
457
+ "sha256": "26a0634d2c38753b0d226946eac7fc395b6f21b3e460433d2638b7eb6a57ad3a",
458
458
  "executable": false
459
459
  },
460
460
  {
@@ -464,7 +464,7 @@
464
464
  },
465
465
  {
466
466
  "path": "native/claude/skills/_shared/warm-build-dirs.py",
467
- "sha256": "ccc842227dfe8d531b06e0e32a13a580c127af9c354b086548da8c547af6c2b0",
467
+ "sha256": "981cab5ea6629182aef01dca1eb2b410ab91fd4581dd500f58e0a8313b39f245",
468
468
  "executable": false
469
469
  },
470
470
  {
@@ -489,7 +489,7 @@
489
489
  },
490
490
  {
491
491
  "path": "native/claude/skills/devlyn-ideate/references/loop.md",
492
- "sha256": "ad64d90fb775b05ef774c2457fc9d994b062e17e017da07054be0d93d83e533f",
492
+ "sha256": "1b7f48ddbe5bbdf0145d7e6797784d5e7fa1af548e751ad6e6869a96de65b58f",
493
493
  "executable": false
494
494
  },
495
495
  {
@@ -504,22 +504,22 @@
504
504
  },
505
505
  {
506
506
  "path": "native/claude/skills/devlyn-ideate/scripts/acceptance.py",
507
- "sha256": "5e25ce6fcbd1773e988a1146f0f4a681676936dad113c43c693fdb0925aa168a",
507
+ "sha256": "1c2c173f05f9688839356898dea6e395fea83e78d5c8bc0e00b0d971a33381e9",
508
508
  "executable": false
509
509
  },
510
510
  {
511
511
  "path": "native/claude/skills/devlyn-ideate/scripts/queue.py",
512
- "sha256": "f8447d7f1a3d04332e9aefdd363e15a9351c46ce2b165d4e75cce45906f132cf",
512
+ "sha256": "db80fd2cae92dda70e9b6183e8b9396dca9592358a38ed19fb6893ed3a531dd2",
513
513
  "executable": false
514
514
  },
515
515
  {
516
516
  "path": "native/codex/.agents/plugins/marketplace.json",
517
- "sha256": "dd4ae6ddb1bad7d6670af67cbfc15de7bc1538a8a0a01c8f039bdf75bd981bd9",
517
+ "sha256": "ae244d5c77ec77f0e794c358368ef83c01a07383b86be66cd459b23324504e61",
518
518
  "executable": false
519
519
  },
520
520
  {
521
521
  "path": "native/codex/plugins/devlyn/.codex-plugin/plugin.json",
522
- "sha256": "a70dddfa4b8c6095d52066ae94fa4c0ff2223d2c601614b825d59c3de5a313f3",
522
+ "sha256": "ff300febb5b5d8469c3258416f63e156cc05b911ee6f3cf2cd818fbf70f5e80b",
523
523
  "executable": false
524
524
  },
525
525
  {
@@ -544,7 +544,7 @@
544
544
  },
545
545
  {
546
546
  "path": "native/codex/plugins/devlyn/skills/_shared/bring-in.py",
547
- "sha256": "754b3892ceb611c855f814e0aa54b645b53de4a67ddec44418f254cb36774527",
547
+ "sha256": "b712de03e30b8a5b29f13f3eb9b0c3787f68edaaa980e0b25fe90885365861d5",
548
548
  "executable": false
549
549
  },
550
550
  {
@@ -614,12 +614,12 @@
614
614
  },
615
615
  {
616
616
  "path": "native/codex/plugins/devlyn/skills/_shared/task-complete.py",
617
- "sha256": "1f39a27e0dc70c727dc79d47c2b294e75bfd1efbc8df4f0492d68578a29405a2",
617
+ "sha256": "5f893064511e273258ebe721e967166485a812fbe9a9f1e818e2c605ef039abc",
618
618
  "executable": false
619
619
  },
620
620
  {
621
621
  "path": "native/codex/plugins/devlyn/skills/_shared/task-completion.md",
622
- "sha256": "3b75502d363ba5fa3b45c06a1f3e0de7c88e609d4f91c41d75287a0acccdd504",
622
+ "sha256": "26a0634d2c38753b0d226946eac7fc395b6f21b3e460433d2638b7eb6a57ad3a",
623
623
  "executable": false
624
624
  },
625
625
  {
@@ -629,7 +629,7 @@
629
629
  },
630
630
  {
631
631
  "path": "native/codex/plugins/devlyn/skills/_shared/warm-build-dirs.py",
632
- "sha256": "ccc842227dfe8d531b06e0e32a13a580c127af9c354b086548da8c547af6c2b0",
632
+ "sha256": "981cab5ea6629182aef01dca1eb2b410ab91fd4581dd500f58e0a8313b39f245",
633
633
  "executable": false
634
634
  },
635
635
  {
@@ -654,7 +654,7 @@
654
654
  },
655
655
  {
656
656
  "path": "native/codex/plugins/devlyn/skills/devlyn-ideate/references/loop.md",
657
- "sha256": "ad64d90fb775b05ef774c2457fc9d994b062e17e017da07054be0d93d83e533f",
657
+ "sha256": "1b7f48ddbe5bbdf0145d7e6797784d5e7fa1af548e751ad6e6869a96de65b58f",
658
658
  "executable": false
659
659
  },
660
660
  {
@@ -669,12 +669,12 @@
669
669
  },
670
670
  {
671
671
  "path": "native/codex/plugins/devlyn/skills/devlyn-ideate/scripts/acceptance.py",
672
- "sha256": "5e25ce6fcbd1773e988a1146f0f4a681676936dad113c43c693fdb0925aa168a",
672
+ "sha256": "1c2c173f05f9688839356898dea6e395fea83e78d5c8bc0e00b0d971a33381e9",
673
673
  "executable": false
674
674
  },
675
675
  {
676
676
  "path": "native/codex/plugins/devlyn/skills/devlyn-ideate/scripts/queue.py",
677
- "sha256": "f8447d7f1a3d04332e9aefdd363e15a9351c46ce2b165d4e75cce45906f132cf",
677
+ "sha256": "db80fd2cae92dda70e9b6183e8b9396dca9592358a38ed19fb6893ed3a531dd2",
678
678
  "executable": false
679
679
  },
680
680
  {
@@ -1819,12 +1819,12 @@
1819
1819
  },
1820
1820
  {
1821
1821
  "path": "package.json",
1822
- "sha256": "1e85c3e53275ab575d882ab87040c79d5f5c0edc4202f1503c576cca797a0446",
1822
+ "sha256": "0c1111039515ac152abe5f3e16b60272753467645bbced1be38936fe909ad04c",
1823
1823
  "executable": false
1824
1824
  }
1825
1825
  ],
1826
1826
  "digest": {
1827
1827
  "algorithm": "sha256",
1828
- "value": "7be19f082103d694d2c85ab15c7687e43b0e6038903b8b3e997c3744f7ee647e"
1828
+ "value": "87b80d4042da531f2cccef9bde9d9d9964a3c34d061be213199d49e117a8bda2"
1829
1829
  }
1830
1830
  }