wtf-p 0.7.4 → 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 (109) hide show
  1. package/README.md +10 -10
  2. package/bin/commands/install-logic.js +1 -1
  3. package/bin/lib/adapter-compiler.js +163 -55
  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/vendors/antigravity/.wtfp-generated.json +2 -2
  9. package/vendors/antigravity/plugin.json +1 -1
  10. package/vendors/claude/.claude-plugin/marketplace.json +2 -2
  11. package/vendors/claude/.claude-plugin/plugin.json +1 -1
  12. package/vendors/claude/.wtfp-generated.json +5 -5
  13. package/vendors/claude/ai.iowarp.clio/prompts/wtfp/help.md +1 -1
  14. package/vendors/claude/plugin.json +1 -1
  15. package/vendors/clio-extension/.wtfp-generated.json +228 -0
  16. package/vendors/clio-extension/actions/add-todo.json +52 -0
  17. package/vendors/clio-extension/actions/analyze-bib.json +97 -0
  18. package/vendors/clio-extension/actions/audit-milestone.json +63 -0
  19. package/vendors/clio-extension/actions/check-refs.json +80 -0
  20. package/vendors/clio-extension/actions/check-todos.json +52 -0
  21. package/vendors/clio-extension/actions/checkpoint.json +76 -0
  22. package/vendors/clio-extension/actions/contribute.json +57 -0
  23. package/vendors/clio-extension/actions/create-outline.json +84 -0
  24. package/vendors/clio-extension/actions/create-poster.json +54 -0
  25. package/vendors/clio-extension/actions/create-slides.json +54 -0
  26. package/vendors/clio-extension/actions/discuss-section.json +76 -0
  27. package/vendors/clio-extension/actions/execute-outline.json +116 -0
  28. package/vendors/clio-extension/actions/export-latex.json +65 -0
  29. package/vendors/clio-extension/actions/help.json +30 -0
  30. package/vendors/clio-extension/actions/insert-section.json +61 -0
  31. package/vendors/clio-extension/actions/list-assumptions.json +35 -0
  32. package/vendors/clio-extension/actions/map-project.json +71 -0
  33. package/vendors/clio-extension/actions/new-paper.json +70 -0
  34. package/vendors/clio-extension/actions/pause-writing.json +71 -0
  35. package/vendors/clio-extension/actions/plan-milestone-gaps.json +57 -0
  36. package/vendors/clio-extension/actions/plan-revision.json +58 -0
  37. package/vendors/clio-extension/actions/plan-section.json +100 -0
  38. package/vendors/clio-extension/actions/polish-prose.json +69 -0
  39. package/vendors/clio-extension/actions/progress.json +51 -0
  40. package/vendors/clio-extension/actions/quick.json +70 -0
  41. package/vendors/clio-extension/actions/remove-section.json +63 -0
  42. package/vendors/clio-extension/actions/report-bug.json +47 -0
  43. package/vendors/clio-extension/actions/request-feature.json +47 -0
  44. package/vendors/clio-extension/actions/research-gap.json +102 -0
  45. package/vendors/clio-extension/actions/resume-writing.json +65 -0
  46. package/vendors/clio-extension/actions/review-section.json +83 -0
  47. package/vendors/clio-extension/actions/settings.json +47 -0
  48. package/vendors/clio-extension/actions/submit-milestone.json +77 -0
  49. package/vendors/clio-extension/actions/update.json +42 -0
  50. package/vendors/clio-extension/actions/verify-work.json +63 -0
  51. package/vendors/clio-extension/actions/write-section.json +115 -0
  52. package/vendors/clio-extension/clio-coder-extension.yaml +53 -0
  53. package/vendors/clio-extension/compatibility/action-availability.json +295 -0
  54. package/vendors/clio-extension/project/schemas/checkpoint.schema.json +102 -0
  55. package/vendors/clio-extension/project/schemas/common.schema.json +33 -0
  56. package/vendors/clio-extension/project/schemas/config.schema.json +69 -0
  57. package/vendors/clio-extension/project/schemas/decisions.schema.json +31 -0
  58. package/vendors/clio-extension/project/schemas/evidence.schema.json +48 -0
  59. package/vendors/clio-extension/project/schemas/manifest.schema.json +102 -0
  60. package/vendors/clio-extension/project/schemas/outline.schema.json +67 -0
  61. package/vendors/clio-extension/project/schemas/section.schema.json +95 -0
  62. package/vendors/clio-extension/project/schemas/source.schema.json +73 -0
  63. package/vendors/clio-extension/project/schemas/state.schema.json +58 -0
  64. package/vendors/clio-extension/project/schemas/validation.schema.json +74 -0
  65. package/vendors/clio-extension/runtime/extension.test.ts +248 -0
  66. package/vendors/clio-extension/runtime/extension.ts +1321 -0
  67. package/vendors/clio-extension/runtime/json-schema.cjs +304 -0
  68. package/vendors/clio-extension/runtime/package.json +3 -0
  69. package/vendors/clio-extension/runtime/write-guard.json +21 -0
  70. package/vendors/clio-extension/skins/wtfp.json +20 -0
  71. package/vendors/codex/plugins/wtfp/.codex-plugin/plugin.json +1 -1
  72. package/vendors/codex/plugins/wtfp/.wtfp-generated.json +3 -3
  73. package/vendors/codex/plugins/wtfp/plugin.json +1 -1
  74. package/vendors/copilot/.wtfp-generated.json +2 -2
  75. package/vendors/copilot/marketplace.json +2 -2
  76. package/vendors/copilot/plugins/wtfp/.claude-plugin/plugin.json +1 -1
  77. package/vendors/copilot/plugins/wtfp/.wtfp-generated.json +2 -2
  78. package/vendors/gemini/.wtfp-generated.json +2 -2
  79. package/vendors/gemini/gemini-extension.json +1 -1
  80. package/vendors/plugin/.wtfp-generated.json +30 -30
  81. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/add-todo.md +6 -12
  82. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/analyze-bib.md +7 -19
  83. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/audit-milestone.md +7 -25
  84. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/check-refs.md +7 -15
  85. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/check-todos.md +9 -13
  86. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/checkpoint.md +7 -27
  87. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/create-outline.md +7 -25
  88. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/discuss-section.md +7 -17
  89. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/execute-outline.md +8 -27
  90. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/help.md +2 -2
  91. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/insert-section.md +7 -13
  92. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/map-project.md +6 -14
  93. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/new-paper.md +7 -17
  94. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/pause-writing.md +6 -18
  95. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/plan-milestone-gaps.md +7 -15
  96. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/plan-section.md +7 -27
  97. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/polish-prose.md +8 -15
  98. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/quick.md +8 -15
  99. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/research-gap.md +7 -21
  100. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/resume-writing.md +7 -23
  101. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/review-section.md +7 -19
  102. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/settings.md +7 -9
  103. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/submit-milestone.md +7 -25
  104. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/verify-work.md +7 -15
  105. package/vendors/plugin/ai.iowarp.clio/prompts/wtfp/write-section.md +8 -28
  106. package/vendors/plugin/compatibility/action-availability.json +16 -1
  107. package/vendors/plugin/plugin.json +7 -7
  108. /package/vendors/plugin/ai.iowarp.clio/{fleets → playbooks}/wtfp-draft-review.md +0 -0
  109. /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
+ }));