wtf-p 0.7.3 → 0.8.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 (241) hide show
  1. package/README.md +16 -12
  2. package/bin/commands/install-logic.js +1 -1
  3. package/bin/lib/adapter-compiler.js +175 -56
  4. package/bin/lib/clio-registration.js +127 -36
  5. package/bin/lib/manifest.js +11 -3
  6. package/bin/uninstall.js +3 -2
  7. package/package.json +1 -1
  8. package/protocol/actions/research-gap.json +1 -1
  9. package/protocol/roles/research-synthesizer.md +1 -1
  10. package/protocol/skills/wtfp-plan-section/references/actions.md +1 -1
  11. package/protocol/skills/wtfp-research-literature/references/actions.md +1 -1
  12. package/protocol/skills/wtfp-write-section/references/actions.md +1 -1
  13. package/protocol/workflows/plan-section.md +3 -2
  14. package/protocol/workflows/research-gap.md +2 -2
  15. package/protocol/workflows/write-section.md +1 -1
  16. package/vendors/antigravity/.wtfp-generated.json +18 -14
  17. package/vendors/antigravity/actions/research-gap.json +1 -1
  18. package/vendors/antigravity/agents/wtfp-research-synthesizer.md +1 -1
  19. package/vendors/antigravity/commands/wtfp-plan-section.md +3 -2
  20. package/vendors/antigravity/commands/wtfp-write-section.md +1 -1
  21. package/vendors/antigravity/plugin.json +1 -1
  22. package/vendors/antigravity/roles/research-synthesizer.md +1 -1
  23. package/vendors/antigravity/skills/wtfp-plan-section/references/actions.md +1 -1
  24. package/vendors/antigravity/skills/wtfp-research-literature/references/actions.md +1 -1
  25. package/vendors/antigravity/skills/wtfp-write-section/references/actions.md +1 -1
  26. package/vendors/antigravity/tools/README.md +1 -1
  27. package/vendors/antigravity/tools/package.json +1 -0
  28. package/vendors/antigravity/workflows/plan-section.md +3 -2
  29. package/vendors/antigravity/workflows/research-gap.md +2 -2
  30. package/vendors/antigravity/workflows/write-section.md +1 -1
  31. package/vendors/claude/.claude-plugin/marketplace.json +2 -2
  32. package/vendors/claude/.claude-plugin/plugin.json +1 -1
  33. package/vendors/claude/.wtfp-generated.json +33 -29
  34. package/vendors/claude/actions/research-gap.json +1 -1
  35. package/vendors/claude/agents/wtfp-research-synthesizer.md +1 -1
  36. package/vendors/claude/ai.iowarp.clio/agents/wtfp-research-synthesizer.md +1 -1
  37. package/vendors/claude/ai.iowarp.clio/prompts/wtfp/analyze-bib.md +2 -0
  38. package/vendors/claude/ai.iowarp.clio/prompts/wtfp/check-refs.md +2 -0
  39. package/vendors/claude/ai.iowarp.clio/prompts/wtfp/create-outline.md +2 -0
  40. package/vendors/claude/ai.iowarp.clio/prompts/wtfp/execute-outline.md +2 -0
  41. package/vendors/claude/ai.iowarp.clio/prompts/wtfp/help.md +1 -1
  42. package/vendors/claude/ai.iowarp.clio/prompts/wtfp/plan-section.md +5 -2
  43. package/vendors/claude/ai.iowarp.clio/prompts/wtfp/polish-prose.md +2 -0
  44. package/vendors/claude/ai.iowarp.clio/prompts/wtfp/quick.md +2 -0
  45. package/vendors/claude/ai.iowarp.clio/prompts/wtfp/research-gap.md +8 -2
  46. package/vendors/claude/ai.iowarp.clio/prompts/wtfp/review-section.md +2 -0
  47. package/vendors/claude/ai.iowarp.clio/prompts/wtfp/write-section.md +3 -1
  48. package/vendors/claude/commands/plan-section.md +3 -2
  49. package/vendors/claude/commands/research-gap.md +2 -2
  50. package/vendors/claude/commands/write-section.md +1 -1
  51. package/vendors/claude/plugin.json +1 -1
  52. package/vendors/claude/roles/research-synthesizer.md +1 -1
  53. package/vendors/claude/skills/wtfp-plan-section/references/actions.md +1 -1
  54. package/vendors/claude/skills/wtfp-research-literature/references/actions.md +1 -1
  55. package/vendors/claude/skills/wtfp-write-section/references/actions.md +1 -1
  56. package/vendors/claude/tools/README.md +1 -1
  57. package/vendors/claude/tools/package.json +1 -0
  58. package/vendors/claude/workflows/plan-section.md +3 -2
  59. package/vendors/claude/workflows/research-gap.md +2 -2
  60. package/vendors/claude/workflows/write-section.md +1 -1
  61. package/vendors/clio-extension/.wtfp-generated.json +228 -0
  62. package/vendors/clio-extension/actions/add-todo.json +52 -0
  63. package/vendors/clio-extension/actions/analyze-bib.json +97 -0
  64. package/vendors/clio-extension/actions/audit-milestone.json +63 -0
  65. package/vendors/clio-extension/actions/check-refs.json +80 -0
  66. package/vendors/clio-extension/actions/check-todos.json +52 -0
  67. package/vendors/clio-extension/actions/checkpoint.json +76 -0
  68. package/vendors/clio-extension/actions/contribute.json +57 -0
  69. package/vendors/clio-extension/actions/create-outline.json +84 -0
  70. package/vendors/clio-extension/actions/create-poster.json +54 -0
  71. package/vendors/clio-extension/actions/create-slides.json +54 -0
  72. package/vendors/clio-extension/actions/discuss-section.json +76 -0
  73. package/vendors/clio-extension/actions/execute-outline.json +116 -0
  74. package/vendors/clio-extension/actions/export-latex.json +65 -0
  75. package/vendors/clio-extension/actions/help.json +30 -0
  76. package/vendors/clio-extension/actions/insert-section.json +61 -0
  77. package/vendors/clio-extension/actions/list-assumptions.json +35 -0
  78. package/vendors/clio-extension/actions/map-project.json +71 -0
  79. package/vendors/clio-extension/actions/new-paper.json +70 -0
  80. package/vendors/clio-extension/actions/pause-writing.json +71 -0
  81. package/vendors/clio-extension/actions/plan-milestone-gaps.json +57 -0
  82. package/vendors/clio-extension/actions/plan-revision.json +58 -0
  83. package/vendors/clio-extension/actions/plan-section.json +100 -0
  84. package/vendors/clio-extension/actions/polish-prose.json +69 -0
  85. package/vendors/clio-extension/actions/progress.json +51 -0
  86. package/vendors/clio-extension/actions/quick.json +70 -0
  87. package/vendors/clio-extension/actions/remove-section.json +63 -0
  88. package/vendors/clio-extension/actions/report-bug.json +47 -0
  89. package/vendors/clio-extension/actions/request-feature.json +47 -0
  90. package/vendors/clio-extension/actions/research-gap.json +102 -0
  91. package/vendors/clio-extension/actions/resume-writing.json +65 -0
  92. package/vendors/clio-extension/actions/review-section.json +83 -0
  93. package/vendors/clio-extension/actions/settings.json +47 -0
  94. package/vendors/clio-extension/actions/submit-milestone.json +77 -0
  95. package/vendors/clio-extension/actions/update.json +42 -0
  96. package/vendors/clio-extension/actions/verify-work.json +63 -0
  97. package/vendors/clio-extension/actions/write-section.json +115 -0
  98. package/vendors/clio-extension/clio-coder-extension.yaml +53 -0
  99. package/vendors/clio-extension/compatibility/action-availability.json +295 -0
  100. package/vendors/clio-extension/project/schemas/checkpoint.schema.json +102 -0
  101. package/vendors/clio-extension/project/schemas/common.schema.json +33 -0
  102. package/vendors/clio-extension/project/schemas/config.schema.json +69 -0
  103. package/vendors/clio-extension/project/schemas/decisions.schema.json +31 -0
  104. package/vendors/clio-extension/project/schemas/evidence.schema.json +48 -0
  105. package/vendors/clio-extension/project/schemas/manifest.schema.json +102 -0
  106. package/vendors/clio-extension/project/schemas/outline.schema.json +67 -0
  107. package/vendors/clio-extension/project/schemas/section.schema.json +95 -0
  108. package/vendors/clio-extension/project/schemas/source.schema.json +73 -0
  109. package/vendors/clio-extension/project/schemas/state.schema.json +58 -0
  110. package/vendors/clio-extension/project/schemas/validation.schema.json +74 -0
  111. package/vendors/clio-extension/runtime/extension.test.ts +248 -0
  112. package/vendors/clio-extension/runtime/extension.ts +1321 -0
  113. package/vendors/clio-extension/runtime/json-schema.cjs +304 -0
  114. package/vendors/clio-extension/runtime/package.json +3 -0
  115. package/vendors/clio-extension/runtime/write-guard.json +21 -0
  116. package/vendors/clio-extension/skins/wtfp.json +20 -0
  117. package/vendors/codex/plugins/wtfp/.codex-plugin/plugin.json +1 -1
  118. package/vendors/codex/plugins/wtfp/.wtfp-generated.json +17 -13
  119. package/vendors/codex/plugins/wtfp/actions/research-gap.json +1 -1
  120. package/vendors/codex/plugins/wtfp/agents/wtfp-research-synthesizer.toml +1 -1
  121. package/vendors/codex/plugins/wtfp/plugin.json +1 -1
  122. package/vendors/codex/plugins/wtfp/roles/research-synthesizer.md +1 -1
  123. package/vendors/codex/plugins/wtfp/skills/wtfp-plan-section/references/actions.md +1 -1
  124. package/vendors/codex/plugins/wtfp/skills/wtfp-research-literature/references/actions.md +1 -1
  125. package/vendors/codex/plugins/wtfp/skills/wtfp-write-section/references/actions.md +1 -1
  126. package/vendors/codex/plugins/wtfp/tools/README.md +1 -1
  127. package/vendors/codex/plugins/wtfp/tools/package.json +1 -0
  128. package/vendors/codex/plugins/wtfp/workflows/plan-section.md +3 -2
  129. package/vendors/codex/plugins/wtfp/workflows/research-gap.md +2 -2
  130. package/vendors/codex/plugins/wtfp/workflows/write-section.md +1 -1
  131. package/vendors/copilot/.wtfp-generated.json +14 -14
  132. package/vendors/copilot/marketplace.json +2 -2
  133. package/vendors/copilot/plugins/wtfp/.claude-plugin/plugin.json +1 -1
  134. package/vendors/copilot/plugins/wtfp/.wtfp-generated.json +18 -14
  135. package/vendors/copilot/plugins/wtfp/actions/research-gap.json +1 -1
  136. package/vendors/copilot/plugins/wtfp/agents/wtfp-research-synthesizer.md +1 -1
  137. package/vendors/copilot/plugins/wtfp/commands/wtfp-plan-section.md +3 -2
  138. package/vendors/copilot/plugins/wtfp/commands/wtfp-write-section.md +1 -1
  139. package/vendors/copilot/plugins/wtfp/roles/research-synthesizer.md +1 -1
  140. package/vendors/copilot/plugins/wtfp/skills/wtfp-plan-section/references/actions.md +1 -1
  141. package/vendors/copilot/plugins/wtfp/skills/wtfp-research-literature/references/actions.md +1 -1
  142. package/vendors/copilot/plugins/wtfp/skills/wtfp-write-section/references/actions.md +1 -1
  143. package/vendors/copilot/plugins/wtfp/tools/README.md +1 -1
  144. package/vendors/copilot/plugins/wtfp/tools/package.json +1 -0
  145. package/vendors/copilot/plugins/wtfp/workflows/plan-section.md +3 -2
  146. package/vendors/copilot/plugins/wtfp/workflows/research-gap.md +2 -2
  147. package/vendors/copilot/plugins/wtfp/workflows/write-section.md +1 -1
  148. package/vendors/copilot/project/.github/agents/wtfp-research-synthesizer.agent.md +1 -1
  149. package/vendors/copilot/project/.github/skills/wtfp-plan-section/references/actions.md +1 -1
  150. package/vendors/copilot/project/.github/skills/wtfp-research-literature/references/actions.md +1 -1
  151. package/vendors/copilot/project/.github/skills/wtfp-write-section/references/actions.md +1 -1
  152. package/vendors/copilot/project/.github/wtfp/actions/research-gap.json +1 -1
  153. package/vendors/copilot/project/.github/wtfp/roles/research-synthesizer.md +1 -1
  154. package/vendors/copilot/project/.github/wtfp/skills/wtfp-plan-section/references/actions.md +1 -1
  155. package/vendors/copilot/project/.github/wtfp/skills/wtfp-research-literature/references/actions.md +1 -1
  156. package/vendors/copilot/project/.github/wtfp/skills/wtfp-write-section/references/actions.md +1 -1
  157. package/vendors/copilot/project/.github/wtfp/workflows/plan-section.md +3 -2
  158. package/vendors/copilot/project/.github/wtfp/workflows/research-gap.md +2 -2
  159. package/vendors/copilot/project/.github/wtfp/workflows/write-section.md +1 -1
  160. package/vendors/gemini/.wtfp-generated.json +24 -20
  161. package/vendors/gemini/actions/research-gap.json +1 -1
  162. package/vendors/gemini/agents/wtfp-research-synthesizer.md +1 -1
  163. package/vendors/gemini/commands/wtfp/discuss-section.toml +1 -1
  164. package/vendors/gemini/commands/wtfp/execute-outline.toml +1 -1
  165. package/vendors/gemini/commands/wtfp/insert-section.toml +1 -1
  166. package/vendors/gemini/commands/wtfp/list-assumptions.toml +1 -1
  167. package/vendors/gemini/commands/wtfp/plan-revision.toml +1 -1
  168. package/vendors/gemini/commands/wtfp/plan-section.toml +4 -3
  169. package/vendors/gemini/commands/wtfp/quick.toml +1 -1
  170. package/vendors/gemini/commands/wtfp/write-section.toml +2 -2
  171. package/vendors/gemini/gemini-extension.json +1 -1
  172. package/vendors/gemini/roles/research-synthesizer.md +1 -1
  173. package/vendors/gemini/skills/wtfp-plan-section/references/actions.md +1 -1
  174. package/vendors/gemini/skills/wtfp-research-literature/references/actions.md +1 -1
  175. package/vendors/gemini/skills/wtfp-write-section/references/actions.md +1 -1
  176. package/vendors/gemini/tools/README.md +1 -1
  177. package/vendors/gemini/tools/package.json +1 -0
  178. package/vendors/gemini/workflows/plan-section.md +3 -2
  179. package/vendors/gemini/workflows/research-gap.md +2 -2
  180. package/vendors/gemini/workflows/write-section.md +1 -1
  181. package/vendors/opencode/.wtfp-generated.json +23 -19
  182. package/vendors/opencode/actions/research-gap.json +1 -1
  183. package/vendors/opencode/agents/wtfp/research-synthesizer.md +1 -1
  184. package/vendors/opencode/commands/wtfp/discuss-section.md +1 -1
  185. package/vendors/opencode/commands/wtfp/execute-outline.md +1 -1
  186. package/vendors/opencode/commands/wtfp/insert-section.md +1 -1
  187. package/vendors/opencode/commands/wtfp/list-assumptions.md +1 -1
  188. package/vendors/opencode/commands/wtfp/plan-revision.md +1 -1
  189. package/vendors/opencode/commands/wtfp/plan-section.md +4 -3
  190. package/vendors/opencode/commands/wtfp/quick.md +1 -1
  191. package/vendors/opencode/commands/wtfp/write-section.md +2 -2
  192. package/vendors/opencode/roles/research-synthesizer.md +1 -1
  193. package/vendors/opencode/skills/wtfp-plan-section/references/actions.md +1 -1
  194. package/vendors/opencode/skills/wtfp-research-literature/references/actions.md +1 -1
  195. package/vendors/opencode/skills/wtfp-write-section/references/actions.md +1 -1
  196. package/vendors/opencode/tools/README.md +1 -1
  197. package/vendors/opencode/tools/package.json +1 -0
  198. package/vendors/opencode/workflows/plan-section.md +3 -2
  199. package/vendors/opencode/workflows/research-gap.md +2 -2
  200. package/vendors/opencode/workflows/write-section.md +1 -1
  201. package/vendors/plugin/.wtfp-generated.json +44 -40
  202. package/vendors/plugin/actions/research-gap.json +1 -1
  203. package/vendors/plugin/ai.iowarp.clio/agents/wtfp-research-synthesizer.md +1 -1
  204. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/add-todo.md +6 -12
  205. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/analyze-bib.md +9 -19
  206. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/audit-milestone.md +7 -25
  207. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/check-refs.md +9 -15
  208. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/check-todos.md +9 -13
  209. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/checkpoint.md +7 -27
  210. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/create-outline.md +9 -25
  211. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/discuss-section.md +7 -17
  212. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/execute-outline.md +10 -27
  213. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/help.md +2 -2
  214. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/insert-section.md +7 -13
  215. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/map-project.md +6 -14
  216. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/new-paper.md +7 -17
  217. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/pause-writing.md +6 -18
  218. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/plan-milestone-gaps.md +7 -15
  219. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/plan-section.md +12 -29
  220. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/polish-prose.md +10 -15
  221. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/quick.md +10 -15
  222. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/research-gap.md +15 -23
  223. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/resume-writing.md +7 -23
  224. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/review-section.md +9 -19
  225. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/settings.md +7 -9
  226. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/submit-milestone.md +7 -25
  227. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/verify-work.md +7 -15
  228. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/write-section.md +11 -29
  229. package/vendors/plugin/compatibility/action-availability.json +16 -1
  230. package/vendors/plugin/plugin.json +7 -7
  231. package/vendors/plugin/roles/research-synthesizer.md +1 -1
  232. package/vendors/plugin/skills/wtfp-plan-section/references/actions.md +1 -1
  233. package/vendors/plugin/skills/wtfp-research-literature/references/actions.md +1 -1
  234. package/vendors/plugin/skills/wtfp-write-section/references/actions.md +1 -1
  235. package/vendors/plugin/tools/README.md +1 -1
  236. package/vendors/plugin/tools/package.json +1 -0
  237. package/vendors/plugin/workflows/plan-section.md +3 -2
  238. package/vendors/plugin/workflows/research-gap.md +2 -2
  239. package/vendors/plugin/workflows/write-section.md +1 -1
  240. /package/vendors/plugin/ai.iowarp.clio/{fleets → playbooks}/wtfp-draft-review.md +0 -0
  241. /package/vendors/plugin/ai.iowarp.clio/{fleets → playbooks}/wtfp-plan-section.md +0 -0
@@ -0,0 +1,248 @@
1
+ // Generated by WTF-P adapter compiler v5 from clio/runtime/extension.test.ts; do not edit.
2
+ /**
3
+ * Package tests for the WTF-P desk, run by `clio-coder extensions test
4
+ * vendors/clio-extension`. One case per runtime tool, the write guard, the
5
+ * desk workspace and the desk without its plugin, each against a small valid
6
+ * project in a task-owned TMPDIR. The kit serves no plugin unless a case
7
+ * passes one.
8
+ */
9
+ import assert from "node:assert/strict";
10
+ import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
11
+ import path from "node:path";
12
+ import { test } from "node:test";
13
+ import { fileURLToPath } from "node:url";
14
+ import { createExtensionTestHost } from "@iowarp/clio-coder/extensions/testing";
15
+
16
+ const ROOT = fileURLToPath(new URL("../", import.meta.url));
17
+ const PROJECT = "desk-test";
18
+ const AT = "2026-10-01T12:00:00Z";
19
+ const GATE = "checkpoint-framing";
20
+
21
+ function project(): string {
22
+ assert.ok(process.env.TMPDIR, "Tests need a task-owned TMPDIR.");
23
+ const workspace = mkdtempSync(path.join(process.env.TMPDIR, "wtfp-desk-test-"));
24
+ const put = (relative: string, value: unknown): void => {
25
+ mkdirSync(path.dirname(path.join(workspace, relative)), { recursive: true });
26
+ writeFileSync(path.join(workspace, relative), typeof value === "string" ? value : `${JSON.stringify(value, null, 2)}\n`);
27
+ };
28
+ put(".planning/project.json", {
29
+ schema: "wtfp.project.manifest/v1",
30
+ protocol_version: 1,
31
+ id: PROJECT,
32
+ title: "Logging on Shared Memory",
33
+ document_type: "research-article",
34
+ core_argument: "Shared memory removes the flush bottleneck without weakening durability.",
35
+ target: { audience: "Storage researchers", word_limit: 100 },
36
+ requirements: { must_have: [], should_have: [], out_of_scope: [] },
37
+ created_at: AT,
38
+ updated_at: AT,
39
+ artifacts: {
40
+ manifest: "project://manifest",
41
+ config: "project://config",
42
+ state: "project://state",
43
+ decisions: "project://decisions",
44
+ outline: "project://structure/outline",
45
+ materials: [],
46
+ manuscripts: [],
47
+ deliverables: [],
48
+ archives: [],
49
+ },
50
+ });
51
+ put(".planning/config.json", {
52
+ schema: "wtfp.project.config/v1",
53
+ project_id: PROJECT,
54
+ interaction_mode: "standard",
55
+ depth: "standard",
56
+ output_format: "markdown",
57
+ language: "en-US",
58
+ citation_style: "author-date",
59
+ gates: { confirm_outline: true, confirm_plan: true, confirm_write: true, confirm_review: true, confirm_delivery: true },
60
+ workflow: { research: true, plan_validation: true, argument_validation: true, coherence_validation: true },
61
+ safety: { destructive_requires_authorization: true, external_publish_requires_authorization: true, backup_before_major_edits: true },
62
+ parallelism: { enabled: false, max_workers: 1 },
63
+ });
64
+ put(".planning/state.json", {
65
+ schema: "wtfp.project.state/v1",
66
+ project_id: PROJECT,
67
+ revision: 3,
68
+ phase: "writing",
69
+ status: "active",
70
+ current_section_uri: "project://sections/introduction",
71
+ progress: { sections_total: 1, sections_complete: 0, word_target: 100, word_count: 0 },
72
+ active_checkpoint_uris: [`project://checkpoints/${GATE}`],
73
+ last_transition: { from: "planning", to: "writing", reason: "The plan is approved.", at: AT },
74
+ updated_at: AT,
75
+ });
76
+ put(".planning/structure/outline.json", {
77
+ schema: "wtfp.project.outline/v1",
78
+ project_id: PROJECT,
79
+ revision: 1,
80
+ thesis: "Shared memory removes the flush bottleneck without weakening durability.",
81
+ target_words: 100,
82
+ sections: [
83
+ {
84
+ id: "introduction",
85
+ title: "Introduction",
86
+ goal: "State the flush bottleneck and the contribution.",
87
+ argument_role: "setup",
88
+ word_target: 100,
89
+ wave: 1,
90
+ depends_on: [],
91
+ claim_ids: [],
92
+ research: { required: false, topics: [] },
93
+ },
94
+ ],
95
+ updated_at: AT,
96
+ });
97
+ put(".planning/sections/introduction/section.json", {
98
+ schema: "wtfp.project.section/v1",
99
+ id: "introduction",
100
+ project_id: PROJECT,
101
+ outline_uri: "project://structure/outline",
102
+ title: "Introduction",
103
+ goal: "State the flush bottleneck and the contribution.",
104
+ status: "planned",
105
+ word_target: 100,
106
+ word_count: 0,
107
+ wave: 1,
108
+ depends_on: [],
109
+ claims: [],
110
+ artifacts: {
111
+ context: "project://sections/introduction/context",
112
+ research: "project://sections/introduction/research",
113
+ plans: ["project://sections/introduction/plans/initial"],
114
+ reviews: [],
115
+ manuscript: "project://paper/introduction",
116
+ },
117
+ checkpoint_uris: [`project://checkpoints/${GATE}`],
118
+ validation_uris: [],
119
+ updated_at: AT,
120
+ });
121
+ put(`.planning/checkpoints/${GATE}.json`, {
122
+ schema: "wtfp.project.checkpoint/v1",
123
+ id: GATE,
124
+ project_id: PROJECT,
125
+ kind: "decision",
126
+ status: "pending",
127
+ blocking: true,
128
+ scope_uri: "project://sections/introduction",
129
+ request: "Lead with the protocol or with the workflow?",
130
+ options: [
131
+ { id: "protocol-first", label: "Protocol first", implication: "Lead with interoperability." },
132
+ { id: "workflow-first", label: "Workflow first", implication: "Lead with the end-to-end process." },
133
+ ],
134
+ resume_action: "write-section",
135
+ created_at: AT,
136
+ });
137
+ // Eleven body words: front matter, the heading, the citation key and the code block do not count.
138
+ put(
139
+ "paper/introduction.md",
140
+ "---\ntitle: Introduction\n---\n# Introduction\n\nShared memory changes the cost of logging [@smith2024]. It's a well-known trade-off.\n\n```c\nint flush = 1;\n```\n",
141
+ );
142
+ return workspace;
143
+ }
144
+
145
+ type Json = Record<string, unknown>;
146
+ const read = (workspace: string, relative: string): Json => JSON.parse(readFileSync(path.join(workspace, relative), "utf8")) as Json;
147
+
148
+ const SERVED = { id: "wtfp", prompts: ["wtfp:check-todos", "wtfp:plan-section", "wtfp:progress", "wtfp:write-section"] };
149
+
150
+ async function withDesk(
151
+ run: (host: Awaited<ReturnType<typeof createExtensionTestHost>>, workspace: string) => Promise<void>,
152
+ plugin: typeof SERVED | null = null,
153
+ ): Promise<void> {
154
+ const workspace = project();
155
+ const host = await createExtensionTestHost(ROOT, { workspace, plugin });
156
+ try {
157
+ await run(host, workspace);
158
+ } finally {
159
+ await host.dispose();
160
+ rmSync(workspace, { recursive: true, force: true });
161
+ }
162
+ }
163
+
164
+ test("record writes a validated record at the revision the caller read and refuses a stale or invalid one", () =>
165
+ withDesk(async (host, workspace) => {
166
+ const state = read(workspace, ".planning/state.json");
167
+ const written = await host.tool("record", { uri: "project://state", record: { ...state, phase: "reviewing" }, expect_revision: 3 });
168
+ assert.equal(written.isError, undefined, written.text);
169
+ assert.deepEqual(written.data, { uri: "project://state", file: ".planning/state.json", revision: 4 });
170
+ assert.equal(read(workspace, ".planning/state.json").phase, "reviewing");
171
+ const stale = await host.tool("record", { uri: "project://state", record: { ...state, phase: "ready" }, expect_revision: 3 });
172
+ assert.equal(stale.isError, true);
173
+ assert.match(stale.text, /revision 4, not 3/);
174
+ const invalid = await host.tool("record", { uri: "project://state", record: { ...state, phase: "drafting" } });
175
+ assert.equal(invalid.isError, true);
176
+ assert.match(invalid.text, /would not validate/);
177
+ assert.deepEqual([read(workspace, ".planning/state.json").phase, read(workspace, ".planning/state.json").revision], ["reviewing", 4]);
178
+ }));
179
+
180
+ test("measure_section counts body words by the desk's one method and records them in the section and state", () =>
181
+ withDesk(async (host, workspace) => {
182
+ const measured = await host.tool("measure_section", { section: "introduction" });
183
+ assert.equal(measured.isError, undefined, measured.text);
184
+ assert.deepEqual(measured.data, { words: 11, target: 100, file: "paper/introduction.md", total: 11 });
185
+ assert.equal(read(workspace, ".planning/sections/introduction/section.json").word_count, 11);
186
+ assert.equal((read(workspace, ".planning/state.json").progress as Json).word_count, 11);
187
+ }));
188
+
189
+ test("gate asks the author and records only the author's answer", () =>
190
+ withDesk(async (host, workspace) => {
191
+ const asked = await host.tool("gate", { checkpoint: GATE });
192
+ assert.equal(asked.interview?.id, "gate-one");
193
+ assert.equal(asked.interview?.step.key, GATE);
194
+ assert.equal(read(workspace, `.planning/checkpoints/${GATE}.json`).status, "pending");
195
+ const answered = await host.interview({ id: "gate-one", step: GATE, nav: "next", answers: { choice: "workflow-first" } });
196
+ assert.match("done" in answered ? answered.text : "", /Recorded the author's answer/);
197
+ const checkpoint = read(workspace, `.planning/checkpoints/${GATE}.json`);
198
+ assert.equal(checkpoint.status, "resolved");
199
+ assert.deepEqual(
200
+ [(checkpoint.resolution as Json).resolved_by, (checkpoint.resolution as Json).selected_option],
201
+ ["author", "workflow-first"],
202
+ );
203
+ assert.deepEqual(read(workspace, ".planning/state.json").active_checkpoint_uris, []);
204
+ }));
205
+
206
+ test("the write guard refuses a write outside the roots the armed action declares", () =>
207
+ withDesk(async (host) => {
208
+ const armed = await host.hook({ point: "prompt_submit", text: "/wtfp:write-section introduction" });
209
+ assert.equal(armed.effects?.[0]?.kind, "notify_operator");
210
+ const refused = await host.hook({ point: "before_tool", tool: "write", turnId: "t1", args: { path: "src/notes.md" } });
211
+ const effect = refused.effects?.[0];
212
+ assert.equal(effect?.kind, "block_tool");
213
+ assert.match(effect && "reason" in effect ? effect.reason : "", /\/wtfp:write-section may write only under \.planning, paper; refused src\/notes\.md/);
214
+ }, SERVED));
215
+
216
+ test("the desk enters with its four regions and clears its ambient UI when left in a folder with no project", async () => {
217
+ assert.ok(process.env.TMPDIR, "Tests need a task-owned TMPDIR.");
218
+ const workspace = mkdtempSync(path.join(process.env.TMPDIR, "wtfp-desk-empty-"));
219
+ const host = await createExtensionTestHost(ROOT, { workspace });
220
+ try {
221
+ const entered = await host.command("desk");
222
+ assert.deepEqual(entered.workspace, { enter: "desk" });
223
+ assert.deepEqual(Object.keys(entered.regions ?? {}), ["header", "board", "rail", "footer"]);
224
+ assert.match(JSON.stringify(entered.band), /new-paper/);
225
+ const left = await host.observe({ event: "workspace_leave", workspace: "desk" });
226
+ assert.deepEqual(left, { text: "", status: null, band: null, islands: null });
227
+ } finally {
228
+ await host.dispose();
229
+ rmSync(workspace, { recursive: true, force: true });
230
+ }
231
+ });
232
+
233
+ test("without its plugin the desk names only its own commands and never a /wtfp: prompt", () =>
234
+ withDesk(async (host) => {
235
+ const outputs: unknown[] = [];
236
+ for (const name of ["desk", "progress", "help", "check-todos", "checkpoints", "validate"]) outputs.push(await host.command(name));
237
+ for (const id of ["next", "help"]) outputs.push(await host.action(id));
238
+ outputs.push(await host.action("section", "introduction"));
239
+ outputs.push(await host.hook({ point: "prompt_submit", text: "/wtfp:write-section introduction" }));
240
+ outputs.push(await host.hook({ point: "before_tool", tool: "write", turnId: "t1", args: { path: "src/notes.md" } }));
241
+ await host.hook({ point: "prompt_submit", text: "plain text" });
242
+ outputs.push(await host.hook({ point: "before_tool", tool: "write", turnId: "t1", args: { path: "paper/introduction.md" } }));
243
+ outputs.push(await host.observe({ event: "session_open", reason: "startup" }));
244
+ const emitted = JSON.stringify(outputs);
245
+ assert.doesNotMatch(emitted, /\/wtfp:/);
246
+ assert.match(emitted, /\/ext:wtfp:check-todos/);
247
+ assert.match(emitted, /needs the WTF-P plugin|not installed and enabled/);
248
+ }));