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
@@ -5,9 +5,9 @@ const path = require('path');
5
5
  const { createTargetGuard, resolveOwnedPath, sha256Buffer } = require('./ownership');
6
6
 
7
7
  // Clio owns integrity, provenance, drift and enable/disable for an installed
8
- // plugin. WTF-P owns two much smaller things: the exact bytes it publishes
9
- // (its v2 receipt) and the guarantee that the tree handed to Clio is the
10
- // generated bundle and nothing else.
8
+ // plugin or extension. WTF-P owns two much smaller things: the exact bytes it
9
+ // publishes (its v2 receipt) and the guarantee that each tree handed to Clio
10
+ // is the generated package and nothing else.
11
11
  function treeFiles(root) {
12
12
  const files = new Map();
13
13
  function visit(directory) {
@@ -37,10 +37,11 @@ function scopeOptions(targetDir, options) {
37
37
  return { ...options, cwd, scope: project ? 'project' : 'user' };
38
38
  }
39
39
 
40
- function generatedBundle(root) {
40
+ function generatedBundle(root, target = 'portable-plugin') {
41
41
  const inventoryPath = path.join(root, '.wtfp-generated.json');
42
+ if (!fs.existsSync(inventoryPath)) return null;
42
43
  const inventory = JSON.parse(fs.readFileSync(inventoryPath, 'utf8'));
43
- if (inventory.schema !== 'wtfp.generated-adapter/v1' || inventory.target !== 'portable-plugin') {
44
+ if (inventory.schema !== 'wtfp.generated-adapter/v1' || inventory.target !== target) {
44
45
  return null;
45
46
  }
46
47
  const expected = new Map(inventory.files.map(file => [file.path, file.sha256]));
@@ -108,42 +109,110 @@ function installedListEntry(stdout, targetDir, native, scope) {
108
109
  return matches[0];
109
110
  }
110
111
 
111
- // Registration is what WTF-P is responsible for. Whether the operator has the
112
- // plugin switched on is Clio's state and their decision, so it is reported,
112
+ function installedExtensionEntry(stdout, targetDir, native, scope) {
113
+ const listing = JSON.parse(stdout);
114
+ if (!listing || !Array.isArray(listing.extensions)) {
115
+ throw new Error('Clio extensions list did not return an extensions array');
116
+ }
117
+ for (const entry of listing.extensions) {
118
+ if (!installedRecord(entry)) throw new Error('Clio extensions list returned a malformed installed extension');
119
+ }
120
+ const matches = listing.extensions.filter(entry => entry.id === native.id && entry.scope === scope &&
121
+ sameRoot(entry.rootPath, path.join(targetDir, native.source)));
122
+ if (matches.length > 1) throw new Error('Clio extensions list returned duplicate installed extension identities');
123
+ return matches[0];
124
+ }
125
+
126
+ // The two Clio packages WTF-P installs, plugin first. Each is its own Clio
127
+ // install with its own lifecycle command, generated inventory and checks.
128
+ function clioPackages(native) {
129
+ const plugin = {
130
+ noun: 'plugin', command: 'library', id: native.id, source: native.source, inventory: 'portable-plugin',
131
+ deferral: 'Clio activation requires an intact generated bundle without extra or modified files',
132
+ list: () => ['library', 'list', '--kind', 'plugin', '--json'],
133
+ listed: (stdout, targetDir, scope) => installedListEntry(stdout, targetDir, native, scope),
134
+ // `inspect` returns the installed record for the explicitly selected scope.
135
+ verify: scope => ['library', 'inspect', native.id, `--${scope}`, '--json'],
136
+ verified: (stdout, targetDir, scope) => verifiedEntry(stdout, targetDir, native, scope)
137
+ };
138
+ if (!native.extension) return [plugin];
139
+ const extension = native.extension;
140
+ const listed = (stdout, targetDir, scope) => installedExtensionEntry(stdout, targetDir, extension, scope);
141
+ return [plugin, {
142
+ noun: 'extension', command: 'extensions', id: extension.id, source: extension.source, inventory: 'clio-extension',
143
+ deferral: 'Clio extension activation requires an intact generated extension without extra or modified files',
144
+ list: scope => ['extensions', 'list', `--${scope}`, '--json'],
145
+ listed,
146
+ verify: scope => ['extensions', 'list', `--${scope}`, '--json'],
147
+ verified: listed
148
+ }];
149
+ }
150
+
151
+ // Registration is what WTF-P is responsible for. Whether the operator has a
152
+ // package switched on is Clio's state and their decision, so it is reported,
113
153
  // never asserted and never changed.
114
154
  function registered(entry) {
115
155
  return Boolean(entry) && entry.valid === true &&
116
156
  Array.isArray(entry.diagnostics) && entry.diagnostics.length === 0;
117
157
  }
118
158
 
119
- function disabledNotice(native, scope) {
120
- return `Clio reports ${native.id} as installed but disabled. WTF-P does not change that preference; run clio-coder library enable ${native.id} --${scope} to switch it back on.`;
159
+ function disabledNotice(pkg, scope) {
160
+ return `Clio reports ${pkg.id} as installed but disabled. WTF-P does not change that preference; run clio-coder ${pkg.command} enable ${pkg.id} --${scope} to switch it back on.`;
121
161
  }
122
162
 
163
+ // Install the plugin, then the extension. A failure in the second compensates
164
+ // the first, and the returned compensator undoes both in reverse order.
123
165
  function activateClio(targetDir, native, suppliedOptions) {
124
166
  const options = scopeOptions(targetDir, suppliedOptions);
167
+ const activated = [];
168
+ try {
169
+ for (const pkg of clioPackages(native)) {
170
+ const result = activatePackage(targetDir, pkg, options);
171
+ activated.push(result);
172
+ if (result.status !== 'registered') break;
173
+ }
174
+ } catch (error) {
175
+ const failures = activated.reverse().flatMap(result => typeof result.rollback === 'function' ? result.rollback() : []);
176
+ if (failures.length) error.nativeRollbackFailures = [...(error.nativeRollbackFailures || []), ...failures];
177
+ throw error;
178
+ }
179
+ if (activated.length === 1) return activated[0];
180
+ const last = activated[activated.length - 1];
181
+ const notices = activated.map(result => result.notice).filter(Boolean);
182
+ return {
183
+ status: last.status, executable: 'clio-coder',
184
+ ...(last.reason ? { reason: last.reason } : {}),
185
+ results: activated.flatMap(result => result.results),
186
+ ...(notices.length ? { notice: notices.join(' ') } : {}),
187
+ rollback() {
188
+ return [...activated].reverse().flatMap(result => typeof result.rollback === 'function' ? result.rollback() : []);
189
+ },
190
+ commit() {
191
+ const warnings = activated.map(result => typeof result.commit === 'function' ? result.commit() : undefined).filter(Boolean);
192
+ return warnings.length ? warnings.join('; ') : undefined;
193
+ }
194
+ };
195
+ }
196
+
197
+ function activatePackage(targetDir, pkg, options) {
125
198
  const { execute, environment } = options;
126
199
  const guard = createTargetGuard(targetDir);
127
- const root = resolveOwnedPath(targetDir, native.source, guard);
200
+ const root = resolveOwnedPath(targetDir, pkg.source, guard);
128
201
  const publishedFiles = treeFiles(root);
129
- const expected = generatedBundle(root);
202
+ const expected = generatedBundle(root, pkg.inventory);
130
203
  if (!expected || !sameTree(expected, publishedFiles)) {
131
- return {
132
- status: 'deferred',
133
- reason: 'Clio activation requires an intact generated bundle without extra or modified files',
134
- results: []
135
- };
204
+ return { status: 'deferred', reason: pkg.deferral, results: [] };
136
205
  }
137
206
 
138
207
  const results = [];
139
- const priorList = execute('clio-coder', ['library', 'list', '--kind', 'plugin', '--json'], environment, options);
208
+ const priorList = execute('clio-coder', pkg.list(options.scope), environment, options);
140
209
  if (priorList.status === 'unavailable') return { status: 'unavailable', executable: 'clio-coder', results };
141
210
  results.push(priorList);
142
- const priorEntry = installedListEntry(priorList.stdout, targetDir, native, options.scope);
211
+ const priorEntry = pkg.listed(priorList.stdout, targetDir, options.scope);
143
212
  if (registered(priorEntry)) {
144
213
  return {
145
214
  status: 'registered', executable: 'clio-coder', results,
146
- ...(priorEntry.enabled === false ? { notice: disabledNotice(native, options.scope) } : {})
215
+ ...(priorEntry.enabled === false ? { notice: disabledNotice(pkg, options.scope) } : {})
147
216
  };
148
217
  }
149
218
 
@@ -152,7 +221,7 @@ function activateClio(targetDir, native, suppliedOptions) {
152
221
  // until the receipt is durable lets a failed registration put the previous
153
222
  // installation back before the file transaction rolls it back.
154
223
  const staging = fs.mkdtempSync(path.join(path.dirname(root), '.wtfp-staged-'));
155
- const source = path.join(staging, 'wtfp');
224
+ const source = path.join(staging, pkg.id);
156
225
  fs.renameSync(root, source);
157
226
  let finished = false;
158
227
 
@@ -163,15 +232,15 @@ function activateClio(targetDir, native, suppliedOptions) {
163
232
  if (!sameTree(publishedFiles, treeFiles(root))) {
164
233
  throw new Error('Clio content changed concurrently; recovery tree preserved');
165
234
  }
166
- const removal = execute('clio-coder', ['library', 'remove', native.id, `--${options.scope}`, '--json'], environment,
235
+ const removal = execute('clio-coder', [pkg.command, 'remove', pkg.id, `--${options.scope}`, '--json'], environment,
167
236
  { ...options, allowAlreadyAbsent: true });
168
237
  results.push(removal);
169
238
  if (removal.status === 'unavailable') throw new Error('Clio became unavailable during rollback');
170
239
  }
171
240
  if (fs.existsSync(root)) throw new Error('Clio rollback did not remove the replacement');
172
- const after = execute('clio-coder', ['library', 'list', '--kind', 'plugin', '--json'], environment, options);
241
+ const after = execute('clio-coder', pkg.list(options.scope), environment, options);
173
242
  results.push(after);
174
- if (after.status === 'unavailable' || installedListEntry(after.stdout, targetDir, native, options.scope)) {
243
+ if (after.status === 'unavailable' || pkg.listed(after.stdout, targetDir, options.scope)) {
175
244
  throw new Error('Clio rollback did not clear the replacement registration');
176
245
  }
177
246
  fs.renameSync(source, root);
@@ -184,22 +253,22 @@ function activateClio(targetDir, native, suppliedOptions) {
184
253
  }
185
254
 
186
255
  try {
187
- const installation = execute('clio-coder', ['library', 'install', source, `--${options.scope}`, '--json'], environment, options);
256
+ const installation = execute('clio-coder', [pkg.command, 'install', source, `--${options.scope}`, '--json'], environment, options);
188
257
  results.push(installation);
189
258
  if (installation.status === 'unavailable') throw new Error('Clio became unavailable during installation');
190
- const inspected = execute('clio-coder', ['library', 'inspect', native.id, `--${options.scope}`, '--json'], environment, options);
259
+ const inspected = execute('clio-coder', pkg.verify(options.scope), environment, options);
191
260
  results.push(inspected);
192
261
  if (inspected.status === 'unavailable') throw new Error('Clio became unavailable during verification');
193
- const entry = verifiedEntry(inspected.stdout, targetDir, native, options.scope);
262
+ const entry = pkg.verified(inspected.stdout, targetDir, options.scope);
194
263
  if (!registered(entry) || !sameTree(publishedFiles, treeFiles(root))) {
195
- throw new Error('Clio did not report the exact WTF-P plugin as installed and valid with zero diagnostics');
264
+ throw new Error(`Clio did not report the exact WTF-P ${pkg.noun} as installed and valid with zero diagnostics`);
196
265
  }
197
266
  if (priorEntry && priorEntry.enabled !== entry.enabled) {
198
- throw new Error('Clio installation changed the existing WTF-P enabled preference');
267
+ throw new Error(`Clio installation changed the existing WTF-P ${pkg.noun} enabled preference`);
199
268
  }
200
269
  return {
201
270
  status: 'registered', executable: 'clio-coder', results, rollback,
202
- ...(entry.enabled === false ? { notice: disabledNotice(native, options.scope) } : {}),
271
+ ...(entry.enabled === false ? { notice: disabledNotice(pkg, options.scope) } : {}),
203
272
  commit() {
204
273
  // Only the private held copy is removed; Clio owns its installed tree.
205
274
  finished = true;
@@ -217,27 +286,49 @@ function activateClio(targetDir, native, suppliedOptions) {
217
286
  }
218
287
  }
219
288
 
289
+ // Remove the extension, then the plugin, each only when the receipt proves it.
290
+ // `ownedFiles` maps receipt paths below the target to their published hashes.
220
291
  function deactivateClio(targetDir, native, suppliedOptions) {
221
292
  const options = scopeOptions(targetDir, suppliedOptions);
293
+ const removed = [];
294
+ for (const pkg of clioPackages(native).reverse()) {
295
+ const prefix = `${pkg.source}/`;
296
+ const ownedFiles = options.ownedFiles && new Map([...options.ownedFiles]
297
+ .filter(([file]) => file.startsWith(prefix))
298
+ .map(([file, hash]) => [file.slice(prefix.length), hash]));
299
+ const result = deactivatePackage(targetDir, pkg, { ...options, ownedFiles });
300
+ if (result.status === 'unavailable') return result;
301
+ removed.push(result);
302
+ }
303
+ if (removed.length === 1) return removed[0];
304
+ const deferred = removed.find(result => result.status === 'deferred');
305
+ const results = removed.flatMap(result => result.results);
306
+ if (deferred) return { status: 'deferred', reason: deferred.reason, results };
307
+ return removed.some(result => result.status === 'unregistered')
308
+ ? { status: 'unregistered', executable: 'clio-coder', results }
309
+ : { status: 'not-required', results };
310
+ }
311
+
312
+ function deactivatePackage(targetDir, pkg, options) {
222
313
  const { execute, environment } = options;
223
314
  const guard = createTargetGuard(targetDir);
224
- const listing = execute('clio-coder', ['library', 'list', '--kind', 'plugin', '--json'], environment, options);
315
+ const listing = execute('clio-coder', pkg.list(options.scope), environment, options);
225
316
  if (listing.status === 'unavailable') return { status: 'unavailable', executable: 'clio-coder', results: [] };
226
- if (!installedListEntry(listing.stdout, targetDir, native, options.scope)) {
317
+ if (!pkg.listed(listing.stdout, targetDir, options.scope)) {
227
318
  return { status: 'not-required', results: [listing] };
228
319
  }
229
320
 
230
321
  // Native removal is recursive. Run it only when the receipt proves that every
231
322
  // file below the installed root is one WTF-P published and nobody changed.
232
- const root = resolveOwnedPath(targetDir, native.source, guard);
323
+ const root = resolveOwnedPath(targetDir, pkg.source, guard);
233
324
  const ownedFiles = options.ownedFiles;
234
325
  if (!ownedFiles || !sameTree(treeFiles(root), ownedFiles)) {
235
- return { status: 'deferred', reason: 'Clio native removal would include unowned or modified plugin files', results: [listing] };
326
+ return { status: 'deferred', reason: `Clio native removal would include unowned or modified ${pkg.noun} files`, results: [listing] };
236
327
  }
237
- const result = execute('clio-coder', ['library', 'remove', native.id, `--${options.scope}`, '--json'], environment, options);
328
+ const result = execute('clio-coder', [pkg.command, 'remove', pkg.id, `--${options.scope}`, '--json'], environment, options);
238
329
  if (result.status === 'unavailable') return { status: 'unavailable', executable: 'clio-coder', results: [listing] };
239
- const after = execute('clio-coder', ['library', 'list', '--kind', 'plugin', '--json'], environment, options);
240
- if (after.status === 'unavailable' || fs.existsSync(root) || installedListEntry(after.stdout, targetDir, native, options.scope)) {
330
+ const after = execute('clio-coder', pkg.list(options.scope), environment, options);
331
+ if (after.status === 'unavailable' || fs.existsSync(root) || pkg.listed(after.stdout, targetDir, options.scope)) {
241
332
  throw new Error('Clio removal did not clear WTF-P content and registration');
242
333
  }
243
334
  return { status: 'unregistered', executable: 'clio-coder', results: [listing, result, after] };
@@ -67,8 +67,9 @@ const MANIFEST = {
67
67
  source: 'marketplaces/wtfp'
68
68
  }
69
69
  },
70
- // Clio consumes the canonical Agent Plugins bundle through its own plugin
71
- // lifecycle. There is no second WTF-P packaging for this host.
70
+ // Clio consumes the canonical Agent Plugins bundle through its plugin
71
+ // lifecycle and the desk through its extension lifecycle: two packages, two
72
+ // Clio installs, one WTF-P receipt.
72
73
  clio: {
73
74
  name: 'Clio Coder',
74
75
  configDirEnv: 'CLIO_CODER_CONFIG_DIR',
@@ -80,6 +81,12 @@ const MANIFEST = {
80
81
  src: path.join(ROOT, 'vendors', 'plugin'),
81
82
  dest: 'plugins/wtfp',
82
83
  type: 'dir'
84
+ },
85
+ {
86
+ id: 'extension',
87
+ src: path.join(ROOT, 'vendors', 'clio-extension'),
88
+ dest: 'extensions/wtfp',
89
+ type: 'dir'
83
90
  }
84
91
  ],
85
92
  discovery: {
@@ -89,7 +96,8 @@ const MANIFEST = {
89
96
  native: {
90
97
  kind: 'clio-plugin',
91
98
  id: 'wtfp',
92
- source: 'plugins/wtfp'
99
+ source: 'plugins/wtfp',
100
+ extension: { id: 'wtfp', source: 'extensions/wtfp' }
93
101
  }
94
102
  },
95
103
  codex: {
package/bin/uninstall.js CHANGED
@@ -780,9 +780,10 @@ async function uninstall(runtime, options, out) {
780
780
  vendorConfig.native,
781
781
  { ...(vendorKey === 'clio' && plan.receipt.scope === 'project'
782
782
  ? { scope: 'project', cwd: path.dirname(targetDir) } : {}),
783
+ // Receipt paths below the target; Clio checks each package root against them.
783
784
  ownedFiles: new Map(plan.items
784
- .filter(item => item.path.startsWith(`${vendorConfig.native.source}/`) && item.state === 'unchanged')
785
- .map(item => [item.path.slice(vendorConfig.native.source.length + 1), item.entry.sha256])) }
785
+ .filter(item => item.state === 'unchanged')
786
+ .map(item => [item.path, item.entry.sha256])) }
786
787
  );
787
788
  if (nativeRemoval.status === 'unavailable' && !options.hasQuiet) {
788
789
  out.warn(`${nativeRemoval.executable} is unavailable; removing the WTF-P-owned staging files without changing the client's native registry.`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wtf-p",
3
- "version": "0.7.4",
3
+ "version": "0.8.0",
4
4
  "description": "Portable, evidence-grounded academic writing workflows (papers, proposals, posters, presentations) for Clio Coder, Claude Code, Codex, GitHub Copilot CLI, OpenCode, Antigravity CLI, and Gemini CLI.",
5
5
  "bin": {
6
6
  "wtfp": "bin/install.js",
@@ -2,7 +2,7 @@
2
2
  "schema": "wtfp.generated-adapter/v1",
3
3
  "generatorVersion": 5,
4
4
  "target": "antigravity",
5
- "sourceHash": "e6be36fb1d333a4a58170b6ea1066f3ccc8306e0b86b164e0eabca2aaa5f168a",
5
+ "sourceHash": "c2e93ea50f26a53402f100fe9157834a3841748eebd8cc212648cd615738278d",
6
6
  "files": [
7
7
  {
8
8
  "path": "actions/add-todo.json",
@@ -362,7 +362,7 @@
362
362
  },
363
363
  {
364
364
  "path": "plugin.json",
365
- "sha256": "198d10a8df114d382642abc9f200ef30826f5ed28c5698b8d33030f9d78349a1"
365
+ "sha256": "9898153f5524eeea64715c41f2c6fe68f90a312e7f2c2ed08485a448da5ff989"
366
366
  },
367
367
  {
368
368
  "path": "project/README.md",
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "$schema": "https://antigravity.google/schemas/v1/plugin.json",
3
3
  "name": "wtfp",
4
- "description": "Portable academic research and writing workflows (WTF-P 0.7.4)."
4
+ "description": "Portable academic research and writing workflows (WTF-P 0.8.0)."
5
5
  }
@@ -5,14 +5,14 @@
5
5
  },
6
6
  "metadata": {
7
7
  "description": "WTF-P evidence-grounded academic workflow plugin.",
8
- "version": "0.7.4"
8
+ "version": "0.8.0"
9
9
  },
10
10
  "plugins": [
11
11
  {
12
12
  "name": "wtfp",
13
13
  "source": "./",
14
14
  "description": "Portable academic research and writing workflows.",
15
- "version": "0.7.4",
15
+ "version": "0.8.0",
16
16
  "author": {
17
17
  "name": "akougkas"
18
18
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wtfp",
3
- "version": "0.7.4",
3
+ "version": "0.8.0",
4
4
  "description": "Portable academic research and writing workflows with stable wtfp actions.",
5
5
  "author": {
6
6
  "name": "akougkas",
@@ -2,15 +2,15 @@
2
2
  "schema": "wtfp.generated-adapter/v1",
3
3
  "generatorVersion": 5,
4
4
  "target": "claude",
5
- "sourceHash": "9f59216dd7c84459a7ac468a2e4b53afbc747b2b159d830bff660a6f6e784562",
5
+ "sourceHash": "21f3c778ba3384293f5b8d107edbda1d09b927b4c47550cd348ebc51c21921f9",
6
6
  "files": [
7
7
  {
8
8
  "path": ".claude-plugin/marketplace.json",
9
- "sha256": "f0bd66a2076c4301269f4077e673b43449c4f43a76fd6974890ceb7ba065d628"
9
+ "sha256": "993e95f1576cf98d92e562f75ff126b6a2832f73ca27610de05145e802605f9c"
10
10
  },
11
11
  {
12
12
  "path": ".claude-plugin/plugin.json",
13
- "sha256": "06d93546610469be4076195c9c4ff95ddde74910ccbbb3f8de0a627677249876"
13
+ "sha256": "9b8391fc30f1b454b4795cb94c5de6b0ef6fb7accc1546221c3239f2b7ffeaae"
14
14
  },
15
15
  {
16
16
  "path": "actions/add-todo.json",
@@ -306,7 +306,7 @@
306
306
  },
307
307
  {
308
308
  "path": "ai.iowarp.clio/prompts/wtfp/help.md",
309
- "sha256": "54b10ac95db9428017fc9511c753dcc9820c701fbeb8e2b1557e0559692d9727"
309
+ "sha256": "921118815b4cce6cac7a74388191265d56eeb68378096997f112f08de525a0e6"
310
310
  },
311
311
  {
312
312
  "path": "ai.iowarp.clio/prompts/wtfp/insert-section.md",
@@ -574,7 +574,7 @@
574
574
  },
575
575
  {
576
576
  "path": "plugin.json",
577
- "sha256": "b5427e46af32758733b35fafc5757a4ec5dbdd6d03d48a0489187907907b9bf8"
577
+ "sha256": "5cd012f727ce4dfd33819323a828d78e64ca2a1d09e11e289dcb51648cb23502"
578
578
  },
579
579
  {
580
580
  "path": "project/README.md",
@@ -4,7 +4,7 @@ display-only: true
4
4
  ---
5
5
 
6
6
  ```text
7
- WTF-P 0.7.4 on Clio Coder: evidence-grounded academic writing
7
+ WTF-P 0.8.0 on Clio Coder: evidence-grounded academic writing
8
8
 
9
9
  Start here
10
10
  /wtfp:new-paper [input]
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
3
3
  "name": "wtfp",
4
- "version": "0.7.4",
4
+ "version": "0.8.0",
5
5
  "description": "Portable, evidence-grounded academic research and writing workflows.",
6
6
  "author": {
7
7
  "name": "akougkas"