devlyn-cli 4.1.0 → 4.2.1

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 (201) hide show
  1. package/AGENTS.md +10 -94
  2. package/CLAUDE.md +7 -160
  3. package/LICENSE +21 -0
  4. package/README.md +68 -111
  5. package/bin/devlyn.js +265 -259
  6. package/bin/instruction-templates.json +43 -2
  7. package/bin/instructions.js +29 -8
  8. package/bin/skill-history.json +140 -0
  9. package/bin/skill-ownership.js +67 -0
  10. package/config/skills/_shared/adapters/claude.md +8 -85
  11. package/config/skills/_shared/adapters/codex.md +14 -34
  12. package/config/skills/_shared/adapters/omp.md +1 -11
  13. package/config/skills/_shared/codex-monitored.sh +4 -54
  14. package/config/skills/_shared/engine-doctor.sh +18 -58
  15. package/config/skills/_shared/engine-preflight.md +15 -47
  16. package/config/skills/_shared/expected-contract.py +242 -0
  17. package/config/skills/_shared/expected.schema.json +10 -95
  18. package/config/skills/_shared/invocation-receipt.py +26 -757
  19. package/config/skills/_shared/platform-support.py +37 -28
  20. package/config/skills/_shared/role-config.py +100 -421
  21. package/config/skills/_shared/runtime-principles.md +17 -93
  22. package/config/skills/_shared/task-complete.py +490 -285
  23. package/config/skills/_shared/task-completion.md +235 -0
  24. package/config/skills/devlyn-engines/SKILL.md +9 -11
  25. package/config/skills/devlyn-ideate/SKILL.md +57 -107
  26. package/config/skills/devlyn-ideate/references/elicitation.md +18 -99
  27. package/config/skills/devlyn-ideate/references/loop.md +110 -0
  28. package/config/skills/devlyn-ideate/references/package-format.md +128 -0
  29. package/config/skills/devlyn-ideate/scripts/acceptance.py +795 -0
  30. package/config/skills/devlyn-ideate/scripts/queue.py +1780 -0
  31. package/node_modules/@inquirer/ansi/LICENSE +22 -0
  32. package/node_modules/@inquirer/ansi/README.md +121 -0
  33. package/node_modules/@inquirer/ansi/dist/index.d.ts +14 -0
  34. package/node_modules/@inquirer/ansi/dist/index.js +21 -0
  35. package/node_modules/@inquirer/ansi/package.json +79 -0
  36. package/node_modules/@inquirer/checkbox/LICENSE +22 -0
  37. package/node_modules/@inquirer/checkbox/README.md +265 -0
  38. package/node_modules/@inquirer/checkbox/dist/index.d.ts +67 -0
  39. package/node_modules/@inquirer/checkbox/dist/index.js +210 -0
  40. package/node_modules/@inquirer/checkbox/package.json +93 -0
  41. package/node_modules/@inquirer/core/LICENSE +22 -0
  42. package/node_modules/@inquirer/core/README.md +424 -0
  43. package/node_modules/@inquirer/core/dist/index.d.ts +13 -0
  44. package/node_modules/@inquirer/core/dist/index.js +12 -0
  45. package/node_modules/@inquirer/core/dist/lib/Separator.d.ts +10 -0
  46. package/node_modules/@inquirer/core/dist/lib/Separator.js +21 -0
  47. package/node_modules/@inquirer/core/dist/lib/__probe/p1.d.ts +9 -0
  48. package/node_modules/@inquirer/core/dist/lib/__probe/p1.js +4 -0
  49. package/node_modules/@inquirer/core/dist/lib/__probe/p2.d.ts +9 -0
  50. package/node_modules/@inquirer/core/dist/lib/__probe/p2.js +3 -0
  51. package/node_modules/@inquirer/core/dist/lib/__probe/p3.d.ts +9 -0
  52. package/node_modules/@inquirer/core/dist/lib/__probe/p3.js +5 -0
  53. package/node_modules/@inquirer/core/dist/lib/create-prompt.d.ts +11 -0
  54. package/node_modules/@inquirer/core/dist/lib/create-prompt.js +185 -0
  55. package/node_modules/@inquirer/core/dist/lib/errors.d.ts +20 -0
  56. package/node_modules/@inquirer/core/dist/lib/errors.js +21 -0
  57. package/node_modules/@inquirer/core/dist/lib/hook-engine.d.ts +17 -0
  58. package/node_modules/@inquirer/core/dist/lib/hook-engine.js +109 -0
  59. package/node_modules/@inquirer/core/dist/lib/key.d.ts +15 -0
  60. package/node_modules/@inquirer/core/dist/lib/key.js +34 -0
  61. package/node_modules/@inquirer/core/dist/lib/make-theme.d.ts +3 -0
  62. package/node_modules/@inquirer/core/dist/lib/make-theme.js +33 -0
  63. package/node_modules/@inquirer/core/dist/lib/pagination/use-pagination.d.ts +15 -0
  64. package/node_modules/@inquirer/core/dist/lib/pagination/use-pagination.js +121 -0
  65. package/node_modules/@inquirer/core/dist/lib/screen-manager.d.ts +14 -0
  66. package/node_modules/@inquirer/core/dist/lib/screen-manager.js +84 -0
  67. package/node_modules/@inquirer/core/dist/lib/theme.d.ts +166 -0
  68. package/node_modules/@inquirer/core/dist/lib/theme.js +29 -0
  69. package/node_modules/@inquirer/core/dist/lib/use-effect.d.ts +2 -0
  70. package/node_modules/@inquirer/core/dist/lib/use-effect.js +11 -0
  71. package/node_modules/@inquirer/core/dist/lib/use-keypress.d.ts +3 -0
  72. package/node_modules/@inquirer/core/dist/lib/use-keypress.js +20 -0
  73. package/node_modules/@inquirer/core/dist/lib/use-memo.d.ts +1 -0
  74. package/node_modules/@inquirer/core/dist/lib/use-memo.js +14 -0
  75. package/node_modules/@inquirer/core/dist/lib/use-prefix.d.ts +5 -0
  76. package/node_modules/@inquirer/core/dist/lib/use-prefix.js +35 -0
  77. package/node_modules/@inquirer/core/dist/lib/use-ref.d.ts +6 -0
  78. package/node_modules/@inquirer/core/dist/lib/use-ref.js +4 -0
  79. package/node_modules/@inquirer/core/dist/lib/use-state.d.ts +7 -0
  80. package/node_modules/@inquirer/core/dist/lib/use-state.js +28 -0
  81. package/node_modules/@inquirer/core/dist/lib/utils.d.ts +13 -0
  82. package/node_modules/@inquirer/core/dist/lib/utils.js +25 -0
  83. package/node_modules/@inquirer/core/package.json +98 -0
  84. package/node_modules/@inquirer/figures/LICENSE +22 -0
  85. package/node_modules/@inquirer/figures/dist/index.d.ts +275 -0
  86. package/node_modules/@inquirer/figures/dist/index.js +315 -0
  87. package/node_modules/@inquirer/figures/package.json +81 -0
  88. package/node_modules/@inquirer/select/LICENSE +22 -0
  89. package/node_modules/@inquirer/select/README.md +258 -0
  90. package/node_modules/@inquirer/select/dist/index.d.ts +42 -0
  91. package/node_modules/@inquirer/select/dist/index.js +191 -0
  92. package/node_modules/@inquirer/select/package.json +93 -0
  93. package/node_modules/@inquirer/type/LICENSE +22 -0
  94. package/node_modules/@inquirer/type/dist/index.d.ts +2 -0
  95. package/node_modules/@inquirer/type/dist/index.js +2 -0
  96. package/node_modules/@inquirer/type/dist/inquirer.d.ts +35 -0
  97. package/node_modules/@inquirer/type/dist/inquirer.js +1 -0
  98. package/node_modules/@inquirer/type/dist/utils.d.ts +45 -0
  99. package/node_modules/@inquirer/type/dist/utils.js +16 -0
  100. package/node_modules/@inquirer/type/package.json +88 -0
  101. package/node_modules/cli-width/LICENSE +13 -0
  102. package/node_modules/cli-width/README.md +71 -0
  103. package/node_modules/cli-width/index.d.ts +13 -0
  104. package/node_modules/cli-width/index.js +49 -0
  105. package/node_modules/cli-width/package.json +40 -0
  106. package/node_modules/fast-string-truncated-width/dist/index.d.ts +4 -0
  107. package/node_modules/fast-string-truncated-width/dist/index.js +111 -0
  108. package/node_modules/fast-string-truncated-width/dist/types.d.ts +19 -0
  109. package/node_modules/fast-string-truncated-width/dist/types.js +2 -0
  110. package/node_modules/fast-string-truncated-width/dist/utils.d.ts +4 -0
  111. package/node_modules/fast-string-truncated-width/dist/utils.js +20 -0
  112. package/node_modules/fast-string-truncated-width/license +21 -0
  113. package/node_modules/fast-string-truncated-width/package.json +35 -0
  114. package/node_modules/fast-string-truncated-width/readme.md +59 -0
  115. package/node_modules/fast-string-width/dist/index.d.ts +4 -0
  116. package/node_modules/fast-string-width/dist/index.js +14 -0
  117. package/node_modules/fast-string-width/license +21 -0
  118. package/node_modules/fast-string-width/package.json +34 -0
  119. package/node_modules/fast-string-width/readme.md +42 -0
  120. package/node_modules/fast-wrap-ansi/LICENSE +23 -0
  121. package/node_modules/fast-wrap-ansi/README.md +26 -0
  122. package/node_modules/fast-wrap-ansi/lib/main.d.ts +6 -0
  123. package/node_modules/fast-wrap-ansi/lib/main.js +218 -0
  124. package/node_modules/fast-wrap-ansi/package.json +51 -0
  125. package/node_modules/mute-stream/LICENSE +15 -0
  126. package/node_modules/mute-stream/README.md +68 -0
  127. package/node_modules/mute-stream/lib/index.js +142 -0
  128. package/node_modules/mute-stream/package.json +54 -0
  129. package/node_modules/signal-exit/LICENSE.txt +16 -0
  130. package/node_modules/signal-exit/README.md +74 -0
  131. package/node_modules/signal-exit/dist/cjs/browser.d.ts +12 -0
  132. package/node_modules/signal-exit/dist/cjs/browser.d.ts.map +1 -0
  133. package/node_modules/signal-exit/dist/cjs/browser.js +10 -0
  134. package/node_modules/signal-exit/dist/cjs/browser.js.map +1 -0
  135. package/node_modules/signal-exit/dist/cjs/index.d.ts +48 -0
  136. package/node_modules/signal-exit/dist/cjs/index.d.ts.map +1 -0
  137. package/node_modules/signal-exit/dist/cjs/index.js +279 -0
  138. package/node_modules/signal-exit/dist/cjs/index.js.map +1 -0
  139. package/node_modules/signal-exit/dist/cjs/package.json +3 -0
  140. package/node_modules/signal-exit/dist/cjs/signals.d.ts +29 -0
  141. package/node_modules/signal-exit/dist/cjs/signals.d.ts.map +1 -0
  142. package/node_modules/signal-exit/dist/cjs/signals.js +42 -0
  143. package/node_modules/signal-exit/dist/cjs/signals.js.map +1 -0
  144. package/node_modules/signal-exit/dist/mjs/browser.d.ts +12 -0
  145. package/node_modules/signal-exit/dist/mjs/browser.d.ts.map +1 -0
  146. package/node_modules/signal-exit/dist/mjs/browser.js +4 -0
  147. package/node_modules/signal-exit/dist/mjs/browser.js.map +1 -0
  148. package/node_modules/signal-exit/dist/mjs/index.d.ts +48 -0
  149. package/node_modules/signal-exit/dist/mjs/index.d.ts.map +1 -0
  150. package/node_modules/signal-exit/dist/mjs/index.js +275 -0
  151. package/node_modules/signal-exit/dist/mjs/index.js.map +1 -0
  152. package/node_modules/signal-exit/dist/mjs/package.json +3 -0
  153. package/node_modules/signal-exit/dist/mjs/signals.d.ts +29 -0
  154. package/node_modules/signal-exit/dist/mjs/signals.d.ts.map +1 -0
  155. package/node_modules/signal-exit/dist/mjs/signals.js +39 -0
  156. package/node_modules/signal-exit/dist/mjs/signals.js.map +1 -0
  157. package/node_modules/signal-exit/package.json +106 -0
  158. package/package.json +17 -4
  159. package/config/commit-conventions.md +0 -28
  160. package/config/skills/_shared/adapters/README.md +0 -74
  161. package/config/skills/_shared/adapters/grok.md +0 -100
  162. package/config/skills/_shared/archive_run.py +0 -969
  163. package/config/skills/_shared/codex-config.md +0 -81
  164. package/config/skills/_shared/collect-codex-findings.py +0 -505
  165. package/config/skills/_shared/finish-gate.py +0 -521
  166. package/config/skills/_shared/grok-anchor-guard.py +0 -78
  167. package/config/skills/_shared/judge-output-parser.py +0 -200
  168. package/config/skills/_shared/judge-role-evidence.py +0 -320
  169. package/config/skills/_shared/phase-prompt-render.py +0 -183
  170. package/config/skills/_shared/process-evidence.py +0 -926
  171. package/config/skills/_shared/resolve-bootstrap.py +0 -1410
  172. package/config/skills/_shared/resolve-stop-hook.py +0 -359
  173. package/config/skills/_shared/run-bounded.py +0 -58
  174. package/config/skills/_shared/spec-verify-check.py +0 -5083
  175. package/config/skills/_shared/state-phase-write.py +0 -5989
  176. package/config/skills/_shared/terminal-claim-check.py +0 -777
  177. package/config/skills/_shared/verify-merge-findings.py +0 -3528
  178. package/config/skills/devlyn-design-ui/SKILL.md +0 -650
  179. package/config/skills/devlyn-ideate/references/from-spec-mode.md +0 -61
  180. package/config/skills/devlyn-ideate/references/project-mode.md +0 -80
  181. package/config/skills/devlyn-ideate/references/spec-template.md +0 -121
  182. package/config/skills/devlyn-ideate/references/templates/decision.md +0 -48
  183. package/config/skills/devlyn-ideate/references/templates/roadmap.md +0 -50
  184. package/config/skills/devlyn-ideate/references/templates/vision.md +0 -44
  185. package/config/skills/devlyn-queue/SKILL.md +0 -66
  186. package/config/skills/devlyn-queue/scripts/append.py +0 -94
  187. package/config/skills/devlyn-resolve/SKILL.md +0 -379
  188. package/config/skills/devlyn-resolve/references/free-form-mode.md +0 -71
  189. package/config/skills/devlyn-resolve/references/outer-loop.md +0 -23
  190. package/config/skills/devlyn-resolve/references/phases/build-gate.md +0 -75
  191. package/config/skills/devlyn-resolve/references/phases/cleanup.md +0 -33
  192. package/config/skills/devlyn-resolve/references/phases/implement.md +0 -44
  193. package/config/skills/devlyn-resolve/references/phases/plan.md +0 -39
  194. package/config/skills/devlyn-resolve/references/phases/probe-derive.md +0 -261
  195. package/config/skills/devlyn-resolve/references/phases/surface-close.md +0 -34
  196. package/config/skills/devlyn-resolve/references/phases/verify.md +0 -310
  197. package/config/skills/devlyn-resolve/references/state-schema.md +0 -152
  198. package/config/skills/devlyn-resolve/references/task-completion.md +0 -160
  199. package/config/templates/prompt-templates.md +0 -71
  200. package/config/templates/template-feature.spec.md +0 -255
  201. package/config/templates/template-product-spec.md +0 -680
@@ -1,183 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Render exact phase-prompt bytes and print their SHA-256 digest."""
3
- from __future__ import annotations
4
-
5
- import runpy
6
- import argparse
7
- import hashlib
8
- import os
9
- import pathlib
10
- import re
11
- import tempfile
12
-
13
-
14
- EXCLUDED_ADAPTER_SECTION = re.compile(
15
- rb"^## (?:Role eligibility|Invocation)(?:\r?\n|\Z).*?(?=^## |\Z)",
16
- re.MULTILINE | re.DOTALL,
17
- )
18
- EXCLUDED_ADAPTER_HEADING = re.compile(
19
- rb"^## (?:Role eligibility|Invocation)\r?$", re.MULTILINE
20
- )
21
-
22
-
23
- def project_adapter(content: bytes) -> bytes:
24
- projected = EXCLUDED_ADAPTER_SECTION.sub(b"", content)
25
- assert EXCLUDED_ADAPTER_HEADING.search(projected) is None
26
- return projected
27
-
28
-
29
- def validate_plan_context(task_context: pathlib.Path, content: bytes) -> None:
30
- if task_context.name != "plan.task-context":
31
- return
32
- working_directory = pathlib.Path.cwd()
33
- expected = (
34
- b"Working directory: "
35
- + os.fsencode(working_directory)
36
- + b"\nPlan output: "
37
- + os.fsencode(working_directory / ".devlyn" / "plan.md")
38
- + b"\n"
39
- )
40
- if not content.startswith(expected):
41
- raise SystemExit("error: invalid PLAN task-context header")
42
-
43
-
44
- def render_prompt(
45
- adapter: pathlib.Path,
46
- canonical_body: pathlib.Path,
47
- task_context: pathlib.Path,
48
- output: pathlib.Path,
49
- ) -> str:
50
- try:
51
- adapter_bytes = adapter.read_bytes()
52
- body_bytes = canonical_body.read_bytes()
53
- context_bytes = task_context.read_bytes()
54
- except OSError as exc:
55
- raise SystemExit(f"error: prompt input unreadable: {exc}") from exc
56
- projected_adapter = project_adapter(adapter_bytes)
57
- validate_plan_context(task_context, context_bytes)
58
- rendered = projected_adapter + body_bytes + context_bytes
59
- rendered = rendered.rstrip(b"\n")
60
- if not output.parent.is_dir():
61
- raise SystemExit(f"error: prompt output parent is not a directory: {output.parent}")
62
- fd, temporary = tempfile.mkstemp(dir=output.parent, prefix=output.name + ".tmp.")
63
- temporary_path = pathlib.Path(temporary)
64
- try:
65
- with os.fdopen(fd, "wb") as handle:
66
- handle.write(rendered)
67
- handle.flush()
68
- os.fsync(handle.fileno())
69
- temporary_path.replace(output)
70
- except BaseException:
71
- temporary_path.unlink(missing_ok=True)
72
- raise
73
- return hashlib.sha256(rendered).hexdigest()
74
-
75
-
76
- def self_test() -> int:
77
- with tempfile.TemporaryDirectory(prefix="phase-prompt-render-") as raw:
78
- root = pathlib.Path(raw)
79
- adapter = root / "adapter.md"
80
- body = root / "plan.md"
81
- context = root / "plan.task-context"
82
- output = root / ".devlyn" / "plan.prompt"
83
- output.parent.mkdir()
84
- original_directory = pathlib.Path.cwd()
85
- os.chdir(root)
86
- try:
87
- working_directory = pathlib.Path.cwd()
88
- adapter_bytes = (
89
- b"# Claude adapter\r\n"
90
- b"## Identity\r\nkept-identity-\xff\r\n"
91
- b"## Role eligibility\nremove-role\r\n"
92
- b"## Output discipline\r\nkept-output-\x80\n"
93
- b"## Invocation\r\nremove-invocation\n"
94
- b"## Anti-patterns\nkept-tail-without-newline"
95
- )
96
- projected_adapter = (
97
- b"# Claude adapter\r\n"
98
- b"## Identity\r\nkept-identity-\xff\r\n"
99
- b"## Output discipline\r\nkept-output-\x80\n"
100
- b"## Anti-patterns\nkept-tail-without-newline"
101
- )
102
- for metadata_free in (
103
- b"# Codex adapter\r\n## Identity\nkept-\xfe",
104
- b"# omp adapter\n## Output discipline\r\nkept\x81",
105
- ):
106
- assert project_adapter(metadata_free) == metadata_free
107
-
108
- body_bytes = b"# PHASE 1 \xe2\x80\x94 PLAN\n"
109
- context_bytes = (
110
- b"Working directory: "
111
- + os.fsencode(working_directory)
112
- + b"\nPlan output: "
113
- + os.fsencode(working_directory / ".devlyn" / "plan.md")
114
- + b"\ncontext-without-newline"
115
- )
116
- for path, content in (
117
- (adapter, adapter_bytes),
118
- (body, body_bytes),
119
- (context, context_bytes),
120
- ):
121
- path.write_bytes(content)
122
- expected = projected_adapter + body_bytes + context_bytes
123
- digest = render_prompt(adapter, body, context, output)
124
- assert output.read_bytes() == expected
125
- assert digest == hashlib.sha256(expected).hexdigest()
126
- assert render_prompt(adapter, body, context, output) == digest
127
- assert output.read_bytes() == expected
128
-
129
- context_prefix = context_bytes.removesuffix(b"context-without-newline")
130
- for terminal_lfs in (b"", b"\n", b"\n\n"):
131
- case_context = context_prefix + b"context-terminal-lf-case" + terminal_lfs
132
- context.write_bytes(case_context)
133
- expected = (projected_adapter + body_bytes + case_context).rstrip(b"\n")
134
- digest = render_prompt(adapter, body, context, output)
135
- written = output.read_bytes()
136
- assert not written.endswith(b"\n")
137
- assert digest == hashlib.sha256(written).hexdigest()
138
- assert written == expected
139
-
140
- invalid_contexts = (
141
- b"context-without-header",
142
- b"Working directory: relative\nPlan output: relative/.devlyn/plan.md\n",
143
- b"Working directory: /mismatch\nPlan output: /mismatch/.devlyn/plan.md\n",
144
- )
145
- for invalid_context in invalid_contexts:
146
- context.write_bytes(invalid_context)
147
- output.write_bytes(b"unchanged")
148
- try:
149
- render_prompt(adapter, body, context, output)
150
- except SystemExit:
151
- pass
152
- else:
153
- raise AssertionError("invalid PLAN task-context header accepted")
154
- assert output.read_bytes() == b"unchanged"
155
- finally:
156
- os.chdir(original_directory)
157
- print("SELFTEST PASS: projected exact bytes + PLAN context validation")
158
- return 0
159
-
160
-
161
- def main() -> int:
162
- parser = argparse.ArgumentParser(description=__doc__)
163
- parser.add_argument("--adapter", type=pathlib.Path)
164
- parser.add_argument("--canonical-body", type=pathlib.Path)
165
- parser.add_argument("--task-context", type=pathlib.Path)
166
- parser.add_argument("--output", type=pathlib.Path)
167
- parser.add_argument("--self-test", action="store_true")
168
- args = parser.parse_args()
169
- if args.self_test:
170
- if any((args.adapter, args.canonical_body, args.task_context, args.output)):
171
- parser.error("render paths are not allowed with --self-test")
172
- return self_test()
173
- if not all((args.adapter, args.canonical_body, args.task_context, args.output)):
174
- parser.error(
175
- "--adapter, --canonical-body, --task-context, and --output are required"
176
- )
177
- print(render_prompt(args.adapter, args.canonical_body, args.task_context, args.output))
178
- return 0
179
-
180
-
181
- if __name__ == "__main__":
182
- runpy.run_path(str(pathlib.Path(__file__).with_name("platform-support.py")))["configure_utf8"]()
183
- raise SystemExit(main())