@phyzess/pappra 0.1.0-beta.13 → 0.1.0-beta.18

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 (357) hide show
  1. package/README.md +134 -15
  2. package/assets/integrations/skills/pappra/SKILL.md +28 -7
  3. package/assets/integrations/skills/pappra/references/collaboration.md +633 -0
  4. package/assets/integrations/skills/pappra/references/environment.md +360 -0
  5. package/assets/integrations/skills/pappra/references/hosts.md +20 -0
  6. package/assets/integrations/skills/pappra/references/operations.md +36 -5
  7. package/dist/adapters/pi/recovery-extension.d.ts +65 -0
  8. package/dist/adapters/pi/recovery-extension.js +238 -0
  9. package/dist/adapters/pi/session-transition-extension.d.ts +30 -0
  10. package/dist/adapters/pi/session-transition-extension.js +265 -0
  11. package/dist/app/automatic-handoff-events.d.ts +26 -0
  12. package/dist/app/automatic-handoff-events.js +134 -0
  13. package/dist/app/bounded-file.d.ts +2 -0
  14. package/dist/app/bounded-file.js +2 -0
  15. package/dist/app/capability-evidence/claude.d.ts +37 -0
  16. package/dist/app/capability-evidence/claude.js +206 -0
  17. package/dist/app/capability-evidence/codex.d.ts +35 -0
  18. package/dist/app/capability-evidence/codex.js +193 -0
  19. package/dist/app/capability-evidence/index.d.ts +33 -0
  20. package/dist/app/capability-evidence/index.js +117 -0
  21. package/dist/app/capability-evidence/pi.d.ts +73 -0
  22. package/dist/app/capability-evidence/pi.js +669 -0
  23. package/dist/app/capability-evidence/shared.d.ts +69 -0
  24. package/dist/app/capability-evidence/shared.js +195 -0
  25. package/dist/app/collab-auto-handoff.d.ts +55 -0
  26. package/dist/app/collab-auto-handoff.js +384 -0
  27. package/dist/app/collab-bindings.d.ts +57 -0
  28. package/dist/app/collab-bindings.js +1006 -0
  29. package/dist/app/collab-bootstrap-transport.d.ts +163 -0
  30. package/dist/app/collab-bootstrap-transport.js +769 -0
  31. package/dist/app/collab-bootstrap.d.ts +137 -0
  32. package/dist/app/collab-bootstrap.js +3455 -0
  33. package/dist/app/collab-handoff.d.ts +12 -0
  34. package/dist/app/collab-handoff.js +511 -0
  35. package/dist/app/collab-messages.d.ts +2 -0
  36. package/dist/app/collab-messages.js +2 -0
  37. package/dist/app/collab-notify.d.ts +156 -0
  38. package/dist/app/collab-notify.js +1208 -0
  39. package/dist/app/collab-preflight.d.ts +34 -0
  40. package/dist/app/collab-preflight.js +96 -0
  41. package/dist/app/collab-recovery-executor.d.ts +161 -0
  42. package/dist/app/collab-recovery-executor.js +1153 -0
  43. package/dist/app/collab-recovery-projection.d.ts +103 -0
  44. package/dist/app/collab-recovery-projection.js +659 -0
  45. package/dist/app/collab-recovery.d.ts +25 -0
  46. package/dist/app/collab-recovery.js +429 -0
  47. package/dist/app/collab-resources.d.ts +16 -0
  48. package/dist/app/collab-resources.js +278 -0
  49. package/dist/app/collab-role-events.d.ts +22 -0
  50. package/dist/app/collab-role-events.js +329 -0
  51. package/dist/app/collab-role-orchestration.d.ts +53 -0
  52. package/dist/app/collab-role-orchestration.js +601 -0
  53. package/dist/app/collab-role-plan.d.ts +81 -0
  54. package/dist/app/collab-role-plan.js +504 -0
  55. package/dist/app/collab-role-repair.d.ts +109 -0
  56. package/dist/app/collab-role-repair.js +821 -0
  57. package/dist/app/collab-rollover.d.ts +263 -0
  58. package/dist/app/collab-rollover.js +1112 -0
  59. package/dist/app/collab-route.d.ts +64 -0
  60. package/dist/app/collab-route.js +240 -0
  61. package/dist/app/collab-session-transition.d.ts +221 -0
  62. package/dist/app/collab-session-transition.js +3334 -0
  63. package/dist/app/collab-state.d.ts +7 -0
  64. package/dist/app/collab-state.js +162 -0
  65. package/dist/app/collab-task-store.d.ts +22 -0
  66. package/dist/app/collab-task-store.js +204 -0
  67. package/dist/app/collab-work-execution.d.ts +127 -0
  68. package/dist/app/collab-work-execution.js +1027 -0
  69. package/dist/app/collab-work-plan.d.ts +87 -0
  70. package/dist/app/collab-work-plan.js +437 -0
  71. package/dist/app/collaboration.d.ts +8 -2
  72. package/dist/app/collaboration.js +101 -12
  73. package/dist/app/doctor.js +108 -5
  74. package/dist/app/host-mcp.js +34 -8
  75. package/dist/app/host-probe.js +4 -4
  76. package/dist/app/init.d.ts +58 -4
  77. package/dist/app/init.js +768 -155
  78. package/dist/app/managed-pi-bootstrap-admission.d.ts +14 -0
  79. package/dist/app/managed-pi-bootstrap-admission.js +104 -0
  80. package/dist/app/managed-pi-bootstrap-refresh.d.ts +10 -0
  81. package/dist/app/managed-pi-bootstrap-refresh.js +78 -0
  82. package/dist/app/managed-pi-delivery.d.ts +8 -0
  83. package/dist/app/managed-pi-delivery.js +110 -0
  84. package/dist/app/managed-pi-handoff-receiver.d.ts +15 -0
  85. package/dist/app/managed-pi-handoff-receiver.js +263 -0
  86. package/dist/app/managed-pi-handoff-reference.d.ts +3 -0
  87. package/dist/app/managed-pi-handoff-reference.js +60 -0
  88. package/dist/app/managed-pi-herdr.d.ts +21 -0
  89. package/dist/app/managed-pi-herdr.js +185 -0
  90. package/dist/app/managed-pi-initial-admission.d.ts +28 -0
  91. package/dist/app/managed-pi-initial-admission.js +416 -0
  92. package/dist/app/managed-pi-initial-launch.d.ts +5 -0
  93. package/dist/app/managed-pi-initial-launch.js +61 -0
  94. package/dist/app/managed-pi-native-observation.d.ts +36 -0
  95. package/dist/app/managed-pi-native-observation.js +191 -0
  96. package/dist/app/managed-pi-readiness.d.ts +29 -0
  97. package/dist/app/managed-pi-readiness.js +288 -0
  98. package/dist/app/managed-pi-repair-stop.d.ts +21 -0
  99. package/dist/app/managed-pi-repair-stop.js +371 -0
  100. package/dist/app/managed-pi-resume-admission.d.ts +32 -0
  101. package/dist/app/managed-pi-resume-admission.js +618 -0
  102. package/dist/app/managed-pi-retirement.d.ts +28 -0
  103. package/dist/app/managed-pi-retirement.js +112 -0
  104. package/dist/app/managed-pi-sdk-control.d.ts +7 -0
  105. package/dist/app/managed-pi-sdk-control.js +169 -0
  106. package/dist/app/managed-pi-sdk-runtime.d.ts +3 -0
  107. package/dist/app/managed-pi-sdk-runtime.js +483 -0
  108. package/dist/app/managed-pi-source-admission.d.ts +14 -0
  109. package/dist/app/managed-pi-source-admission.js +323 -0
  110. package/dist/app/managed-pi-transition-host.d.ts +36 -0
  111. package/dist/app/managed-pi-transition-host.js +292 -0
  112. package/dist/app/managed-pi.d.ts +54 -0
  113. package/dist/app/managed-pi.js +248 -0
  114. package/dist/app/shell-readiness.d.ts +66 -0
  115. package/dist/app/shell-readiness.js +368 -0
  116. package/dist/app/task-pin.d.ts +2 -23
  117. package/dist/app/task-pin.js +2 -113
  118. package/dist/cli/commands/collaboration-binding.d.ts +13 -0
  119. package/dist/cli/commands/collaboration-binding.js +118 -0
  120. package/dist/cli/commands/collaboration-bootstrap.d.ts +10 -0
  121. package/dist/cli/commands/collaboration-bootstrap.js +84 -0
  122. package/dist/cli/commands/collaboration-capabilities.d.ts +13 -0
  123. package/dist/cli/commands/collaboration-capabilities.js +127 -0
  124. package/dist/cli/commands/collaboration-handoff.d.ts +13 -0
  125. package/dist/cli/commands/collaboration-handoff.js +102 -0
  126. package/dist/cli/commands/collaboration-message.d.ts +17 -0
  127. package/dist/cli/commands/collaboration-message.js +177 -0
  128. package/dist/cli/commands/collaboration-plan.d.ts +8 -0
  129. package/dist/cli/commands/collaboration-plan.js +108 -0
  130. package/dist/cli/commands/collaboration-preflight.d.ts +10 -0
  131. package/dist/cli/commands/collaboration-preflight.js +167 -0
  132. package/dist/cli/commands/collaboration-recovery-run.d.ts +46 -0
  133. package/dist/cli/commands/collaboration-recovery-run.js +224 -0
  134. package/dist/cli/commands/collaboration-recovery.d.ts +11 -0
  135. package/dist/cli/commands/collaboration-recovery.js +104 -0
  136. package/dist/cli/commands/collaboration-resources.d.ts +11 -0
  137. package/dist/cli/commands/collaboration-resources.js +96 -0
  138. package/dist/cli/commands/collaboration-role-plan.d.ts +9 -0
  139. package/dist/cli/commands/collaboration-role-plan.js +69 -0
  140. package/dist/cli/commands/collaboration-role-run.d.ts +11 -0
  141. package/dist/cli/commands/collaboration-role-run.js +128 -0
  142. package/dist/cli/commands/collaboration-rollover.d.ts +10 -0
  143. package/dist/cli/commands/collaboration-rollover.js +103 -0
  144. package/dist/cli/commands/collaboration-state.d.ts +10 -0
  145. package/dist/cli/commands/collaboration-state.js +96 -0
  146. package/dist/cli/commands/collaboration-transition.d.ts +10 -0
  147. package/dist/cli/commands/collaboration-transition.js +75 -0
  148. package/dist/cli/commands/collaboration-work-run.d.ts +34 -0
  149. package/dist/cli/commands/collaboration-work-run.js +178 -0
  150. package/dist/cli/commands/collaboration.d.ts +4 -0
  151. package/dist/cli/commands/collaboration.js +39 -4
  152. package/dist/cli/commands/continuity.js +2 -6
  153. package/dist/cli/commands/docs.d.ts +2 -0
  154. package/dist/cli/commands/docs.js +89 -15
  155. package/dist/cli/commands/host.d.ts +7 -1
  156. package/dist/cli/commands/host.js +122 -7
  157. package/dist/cli/commands/init.d.ts +20 -3
  158. package/dist/cli/commands/init.js +897 -232
  159. package/dist/cli/commands/mcp.d.ts +1 -0
  160. package/dist/cli/commands/mcp.js +11 -5
  161. package/dist/cli/commands/repair.d.ts +12 -0
  162. package/dist/cli/commands/repair.js +41 -0
  163. package/dist/cli/commands/runtime.d.ts +1 -1
  164. package/dist/cli/commands/runtime.js +139 -38
  165. package/dist/cli/commands/session.d.ts +7 -0
  166. package/dist/cli/commands/session.js +82 -0
  167. package/dist/cli/commands/task.js +19 -5
  168. package/dist/cli/run.js +866 -24
  169. package/dist/code/identity.d.ts +7 -0
  170. package/dist/code/identity.js +7 -3
  171. package/dist/code/registration.js +7 -0
  172. package/dist/code/service.d.ts +9 -0
  173. package/dist/code/service.js +16 -3
  174. package/dist/code/text.js +19 -7
  175. package/dist/collab/admission.d.ts +91 -66
  176. package/dist/collab/admission.js +21 -6
  177. package/dist/collab/canonical.d.ts +1 -1
  178. package/dist/collab/canonical.js +44 -3
  179. package/dist/collab/envelope.d.ts +2 -2
  180. package/dist/collab/envelope.js +12 -12
  181. package/dist/collab/first-work.d.ts +3 -0
  182. package/dist/collab/first-work.js +15 -0
  183. package/dist/collab/handoff.d.ts +16 -0
  184. package/dist/collab/handoff.js +39 -5
  185. package/dist/collab/index.d.ts +97 -1
  186. package/dist/collab/index.js +9 -1
  187. package/dist/collab/messages.js +126 -3
  188. package/dist/collab/persisted-messages.d.ts +123 -0
  189. package/dist/collab/persisted-messages.js +496 -0
  190. package/dist/collab/preflight.d.ts +1 -1
  191. package/dist/collab/resources.d.ts +13 -3
  192. package/dist/collab/resources.js +37 -6
  193. package/dist/collab/rollover.d.ts +311 -0
  194. package/dist/collab/rollover.js +1024 -0
  195. package/dist/collab/store.d.ts +1 -0
  196. package/dist/collab/store.js +1 -4
  197. package/dist/collab/types.d.ts +2 -354
  198. package/dist/collab/validation.d.ts +2 -10
  199. package/dist/collab/validation.js +2 -303
  200. package/dist/collab/work-plan.d.ts +105 -0
  201. package/dist/collab/work-plan.js +843 -0
  202. package/dist/continuity/context.d.ts +11 -2
  203. package/dist/continuity/context.js +100 -13
  204. package/dist/continuity/handoff-bundle.d.ts +296 -0
  205. package/dist/continuity/handoff-bundle.js +477 -0
  206. package/dist/continuity/index.d.ts +2 -0
  207. package/dist/continuity/index.js +1 -0
  208. package/dist/continuity/paths.js +10 -2
  209. package/dist/continuity/service.js +91 -15
  210. package/dist/continuity/task-pin.d.ts +24 -0
  211. package/dist/continuity/task-pin.js +590 -0
  212. package/dist/doctor.d.ts +1 -0
  213. package/dist/doctor.js +6 -0
  214. package/dist/experimental/index.d.ts +13 -0
  215. package/dist/experimental/index.js +25 -0
  216. package/dist/experimental/pi.d.ts +4 -0
  217. package/dist/experimental/pi.js +12 -0
  218. package/dist/hosts/claude/native.js +1 -1
  219. package/dist/hosts/codex/native.js +1 -1
  220. package/dist/hosts/codex/protocol.js +1 -1
  221. package/dist/hosts/integration/bootstrap-config.d.ts +58 -0
  222. package/dist/hosts/integration/bootstrap-config.js +254 -0
  223. package/dist/hosts/integration/bundle-export.d.ts +44 -0
  224. package/dist/hosts/integration/bundle-export.js +366 -3
  225. package/dist/hosts/integration/bundle.js +3 -0
  226. package/dist/hosts/integration/hook.js +36 -9
  227. package/dist/hosts/integration/pappra-bootstrap-extension.mjs +80 -0
  228. package/dist/hosts/integration/pappra-extension-runtime.mjs +59 -24631
  229. package/dist/hosts/integration/pappra-hook.mjs +61 -24749
  230. package/dist/hosts/integration/pappra-recovery-extension.mjs +259 -0
  231. package/dist/hosts/integration/pappra-session-transition-extension.mjs +276 -0
  232. package/dist/hosts/integration/pi-bootstrap-extension.d.ts +36 -0
  233. package/dist/hosts/integration/pi-bootstrap-extension.js +101 -0
  234. package/dist/hosts/integration/pi-bootstrap-guard.d.ts +125 -0
  235. package/dist/hosts/integration/pi-bootstrap-guard.js +438 -0
  236. package/dist/hosts/integration/pi-bootstrap-runtime.d.ts +63 -0
  237. package/dist/hosts/integration/pi-bootstrap-runtime.js +223 -0
  238. package/dist/hosts/integration/pi-native-events.d.ts +112 -0
  239. package/dist/hosts/integration/pi-native-events.js +348 -0
  240. package/dist/hosts/integration/pi-rollover-extension.d.ts +166 -0
  241. package/dist/hosts/integration/pi-rollover-extension.js +431 -0
  242. package/dist/hosts/integration/recovery-config.d.ts +48 -0
  243. package/dist/hosts/integration/recovery-config.js +117 -0
  244. package/dist/hosts/integration/service.d.ts +6 -1
  245. package/dist/hosts/integration/service.js +485 -35
  246. package/dist/hosts/integration/support.d.ts +7 -0
  247. package/dist/hosts/integration/support.js +9 -1
  248. package/dist/hosts/integration/templates.d.ts +3 -0
  249. package/dist/hosts/integration/templates.js +26 -3
  250. package/dist/hosts/pi/managed-host-identity.d.ts +2 -0
  251. package/dist/hosts/pi/managed-host-identity.js +40 -0
  252. package/dist/hosts/pi/managed-provider-diagnostics.d.ts +6 -0
  253. package/dist/hosts/pi/managed-provider-diagnostics.js +184 -0
  254. package/dist/hosts/pi/managed-sdk-session.d.ts +335 -0
  255. package/dist/hosts/pi/managed-sdk-session.js +1639 -0
  256. package/dist/hosts/pi/managed-session-extension.d.ts +20 -0
  257. package/dist/hosts/pi/managed-session-extension.js +84 -0
  258. package/dist/hosts/pi/managed-session.d.ts +177 -0
  259. package/dist/hosts/pi/managed-session.js +1557 -0
  260. package/dist/hosts/pi/protocol.js +1 -1
  261. package/dist/hosts/pi/query-result.js +1 -1
  262. package/dist/hosts/pi/resume-capability.d.ts +41 -0
  263. package/dist/hosts/pi/resume-capability.js +33 -0
  264. package/dist/hosts/pi/rpc.d.ts +182 -134
  265. package/dist/hosts/pi/rpc.js +230 -37
  266. package/dist/hosts/pilot.d.ts +97 -74
  267. package/dist/hosts/pilot.js +5 -1
  268. package/dist/hosts/version.d.ts +3 -0
  269. package/dist/hosts/version.js +18 -0
  270. package/dist/index.d.ts +0 -1
  271. package/dist/index.js +0 -1
  272. package/dist/infra/bounded-file.d.ts +19 -0
  273. package/dist/infra/bounded-file.js +66 -0
  274. package/dist/infra/fs.js +10 -2
  275. package/dist/infra/git.d.ts +29 -0
  276. package/dist/infra/git.js +45 -9
  277. package/dist/infra/json-property.d.ts +2 -0
  278. package/dist/infra/json-property.js +69 -0
  279. package/dist/infra/json.d.ts +4 -0
  280. package/dist/infra/json.js +24 -0
  281. package/dist/infra/owned-process-group.js +1 -1
  282. package/dist/infra/private-lock.d.ts +16 -0
  283. package/dist/infra/private-lock.js +148 -0
  284. package/dist/infra/private-state.d.ts +7 -0
  285. package/dist/infra/private-state.js +146 -0
  286. package/dist/infra/process-identity.d.ts +12 -0
  287. package/dist/infra/process-identity.js +142 -0
  288. package/dist/infra/validation.d.ts +5 -0
  289. package/dist/infra/validation.js +15 -0
  290. package/dist/init.d.ts +1 -0
  291. package/dist/init.js +6 -0
  292. package/dist/install/apply.d.ts +9 -1
  293. package/dist/install/apply.js +176 -12
  294. package/dist/install/dependencies.d.ts +38 -0
  295. package/dist/install/dependencies.js +282 -0
  296. package/dist/install/ownership.js +30 -1
  297. package/dist/install/references.d.ts +31 -0
  298. package/dist/install/references.js +208 -0
  299. package/dist/install/repair.d.ts +37 -0
  300. package/dist/install/repair.js +798 -0
  301. package/dist/install/reset-local.d.ts +16 -0
  302. package/dist/install/reset-local.js +304 -0
  303. package/dist/install/rollback.d.ts +3 -0
  304. package/dist/install/rollback.js +9 -3
  305. package/dist/install/runtime.d.ts +10 -6
  306. package/dist/install/runtime.js +299 -59
  307. package/dist/install/source-fingerprint.d.ts +2 -0
  308. package/dist/install/source-fingerprint.js +103 -0
  309. package/dist/knowledge/catalog.d.ts +1 -0
  310. package/dist/knowledge/catalog.js +143 -10
  311. package/dist/knowledge/journal.js +17 -7
  312. package/dist/knowledge/paths.js +2 -1
  313. package/dist/knowledge/refs.js +4 -0
  314. package/dist/knowledge/register-batch.d.ts +4 -0
  315. package/dist/knowledge/register-batch.js +225 -0
  316. package/dist/knowledge/relocate.d.ts +5 -0
  317. package/dist/knowledge/relocate.js +92 -0
  318. package/dist/knowledge/scan.js +103 -47
  319. package/dist/knowledge/service.d.ts +3 -0
  320. package/dist/knowledge/service.js +33 -1
  321. package/dist/knowledge/write.d.ts +4 -1
  322. package/dist/knowledge/write.js +1 -1
  323. package/dist/mcp/server.d.ts +4 -2
  324. package/dist/mcp/server.js +87 -136
  325. package/dist/schemas/collaboration-state-validation.d.ts +6 -0
  326. package/dist/schemas/collaboration-state-validation.js +342 -0
  327. package/dist/schemas/collaboration-state.d.ts +436 -0
  328. package/dist/schemas/collaboration-state.js +1 -0
  329. package/dist/schemas/collaboration.d.ts +335 -0
  330. package/dist/schemas/collaboration.js +272 -0
  331. package/dist/schemas/continuity.d.ts +8 -0
  332. package/dist/schemas/continuity.js +13 -3
  333. package/dist/schemas/doctor.d.ts +1 -0
  334. package/dist/schemas/doctor.js +1 -0
  335. package/dist/schemas/document.d.ts +61 -0
  336. package/dist/schemas/document.js +9 -0
  337. package/dist/schemas/errors.d.ts +1 -0
  338. package/dist/schemas/errors.js +1 -0
  339. package/dist/schemas/host.d.ts +24 -0
  340. package/dist/schemas/host.js +19 -0
  341. package/dist/schemas/install.d.ts +8 -2
  342. package/dist/schemas/install.js +11 -1
  343. package/dist/schemas/managed-pi-execution.d.ts +16 -0
  344. package/dist/schemas/managed-pi-execution.js +2 -0
  345. package/dist/schemas/outcome.d.ts +9 -5
  346. package/dist/workspace/config-file.js +1 -3
  347. package/dist/workspace/documents.js +12 -2
  348. package/dist/workspace/repositories.d.ts +7 -0
  349. package/dist/workspace/repositories.js +14 -5
  350. package/package.json +35 -35
  351. package/skills/pappra/SKILL.md +28 -7
  352. package/skills/pappra/references/collaboration.md +633 -0
  353. package/skills/pappra/references/environment.md +360 -0
  354. package/skills/pappra/references/hosts.md +20 -0
  355. package/skills/pappra/references/operations.md +36 -5
  356. package/dist/app/collab-from.d.ts +0 -35
  357. package/dist/app/collab-from.js +0 -84
@@ -1,5 +1,9 @@
1
- import { discoverWorkspace } from '../workspace/discover.js';
2
- import { KnowledgeService } from './index.js';
1
+ import { discoverDocuments } from '../workspace/documents.js';
2
+ import { createDiagnostic } from '../schemas/diagnostics.js';
3
+ import { diagnosticCodes } from '../schemas/errors.js';
4
+ import { loadKnowledgeContext } from './context.js';
5
+ import { loadKnowledgeCatalogs } from './catalog.js';
6
+ import { registerDocumentBatch } from './register-batch.js';
3
7
  export function classifyScannedDocumentKind(path) {
4
8
  const lower = path.toLowerCase();
5
9
  if (lower.endsWith('agents.md') || lower.endsWith('claude.md'))
@@ -14,25 +18,69 @@ export function classifyScannedDocumentKind(path) {
14
18
  return 'plan';
15
19
  return 'architecture';
16
20
  }
21
+ function scanResult(root, mode, candidates, registered, skipped, diagnostics, nextActions, ok = !diagnostics.some((entry) => entry.severity === 'error')) {
22
+ return {
23
+ ok,
24
+ schema: 'pappra/docs-scan/1',
25
+ mode,
26
+ workspaceRoot: root,
27
+ candidates,
28
+ registered,
29
+ skipped,
30
+ nextActions,
31
+ diagnostics,
32
+ };
33
+ }
17
34
  /**
18
35
  * Registers documents discovered under the configured knowledge sources.
19
36
  * Without apply this is read-only and reports the candidates.
20
37
  */
21
38
  export async function scanDiscoveredDocuments(root, options) {
22
- const discovery = await discoverWorkspace(root);
23
- const config = discovery.config;
24
- if (config === null) {
25
- return {
26
- ok: false,
27
- message: 'docs scan requires a valid .pappra/workspace.json; run pappra init first.',
28
- };
39
+ const loaded = await loadKnowledgeContext(root);
40
+ const config = loaded.context?.config ?? null;
41
+ const diagnostics = [...loaded.diagnostics];
42
+ const discovery = loaded.context === null
43
+ ? { documents: [], diagnostics: [], truncated: false }
44
+ : await discoverDocuments({
45
+ root: loaded.context.root,
46
+ config,
47
+ configPath: loaded.context.configPath,
48
+ repositories: loaded.context.repositories,
49
+ options: {
50
+ scanDepth: 64,
51
+ maxDocuments: 10_000,
52
+ maxDirectories: 10_000,
53
+ maxEntriesPerDirectory: 10_000,
54
+ gitTimeoutMs: 5000,
55
+ },
56
+ });
57
+ diagnostics.push(...discovery.diagnostics);
58
+ if (discovery.truncated) {
59
+ diagnostics.push(createDiagnostic({
60
+ code: diagnosticCodes.discoveryLimitReached,
61
+ severity: 'warning',
62
+ message: 'Knowledge source discovery was truncated; scan coverage is incomplete.',
63
+ source: root,
64
+ pointer: null,
65
+ hint: 'Reduce the configured sources or their size, then rerun the scan for complete coverage.',
66
+ }));
67
+ }
68
+ if (config === null || loaded.context === null) {
69
+ return scanResult(root, options.apply ? 'apply' : 'plan', [], [], 0, diagnostics, [
70
+ 'Run pappra init or repair .pappra/workspace.json before scanning knowledge sources.',
71
+ ], false);
29
72
  }
30
- const service = new KnowledgeService(root);
31
- const listed = await service.list({ includePrivate: true });
32
- const registered = new Set(listed.records.flatMap((record) => record.location.kind === 'workspace' ? [record.location.path] : []));
73
+ const listed = await loadKnowledgeCatalogs(loaded.context);
74
+ diagnostics.push(...listed.diagnostics);
75
+ if (!listed.ok) {
76
+ return scanResult(root, options.apply ? 'apply' : 'plan', [], [], 0, diagnostics, [
77
+ 'Repair the knowledge catalog diagnostics before scanning; no registration was attempted.',
78
+ ], false);
79
+ }
80
+ const registered = new Set([...listed.records.values()].flatMap((record) => record.location.kind === 'workspace' ? [record.location.path] : []));
33
81
  const sources = config.knowledge.sources;
34
82
  const visibility = config.knowledge.taskVisibility === 'shared' ? 'shareable' : 'private';
35
- const candidates = [];
83
+ const discoveredCandidates = [];
36
84
  for (const document of discovery.documents ?? []) {
37
85
  const path = document.workspaceRelativePath;
38
86
  if (path === null)
@@ -42,50 +90,58 @@ export async function scanDiscoveredDocuments(root, options) {
42
90
  }
43
91
  if (registered.has(path))
44
92
  continue;
45
- candidates.push({
93
+ discoveredCandidates.push({
46
94
  path,
47
95
  kind: classifyScannedDocumentKind(path),
48
96
  visibility,
49
97
  });
50
98
  }
51
- const diagnostics = [...listed.diagnostics];
99
+ const candidates = discoveredCandidates.slice(0, 300);
100
+ if (discoveredCandidates.length > candidates.length)
101
+ diagnostics.push(createDiagnostic({
102
+ code: diagnosticCodes.discoveryLimitReached,
103
+ severity: 'warning',
104
+ message: 'This batch contains 300 new documents; rerun scan after applying to continue with the remaining documents.',
105
+ source: root,
106
+ }));
107
+ const incomplete = discovery.truncated ||
108
+ discoveredCandidates.length > candidates.length ||
109
+ diagnostics.some((entry) => entry.severity === 'error');
110
+ const privateCommand = visibility === 'private' ? 'pappra docs list --include-private' : null;
52
111
  if (!options.apply) {
53
- return {
54
- ok: true,
55
- schema: 'pappra/docs-scan/1',
56
- mode: 'plan',
57
- workspaceRoot: root,
58
- candidates,
59
- registered: [],
60
- skipped: candidates.length,
61
- nextActions: [
62
- 'Rerun with apply: true to register these documents in the knowledge catalog.',
63
- ],
64
- diagnostics,
65
- };
112
+ const nextActions = [];
113
+ if (candidates.length > 0) {
114
+ nextActions.push('Rerun with --apply to register these documents in the knowledge catalog.');
115
+ }
116
+ if (incomplete || discovery.truncated) {
117
+ nextActions.push('Correct the reported knowledge-source diagnostics, then rerun the scan for complete coverage.');
118
+ }
119
+ if (privateCommand !== null) {
120
+ nextActions.push(`After applying, review private documents with: ${privateCommand}.`);
121
+ }
122
+ return scanResult(root, 'plan', candidates, [], candidates.length, diagnostics, nextActions, !incomplete);
66
123
  }
67
124
  const registeredNow = [];
68
- for (const candidate of candidates) {
69
- const result = await service.register({
70
- location: { kind: 'workspace', path: candidate.path },
71
- kind: candidate.kind,
72
- maturity: 'draft',
73
- owner: 'human',
74
- visibility: candidate.visibility,
75
- });
125
+ const results = await registerDocumentBatch(loaded.context, candidates.map((candidate) => ({
126
+ location: { kind: 'workspace', path: candidate.path },
127
+ kind: candidate.kind,
128
+ maturity: 'draft',
129
+ owner: 'human',
130
+ visibility: candidate.visibility,
131
+ })));
132
+ for (const result of results) {
76
133
  diagnostics.push(...result.diagnostics);
77
134
  if (result.ok)
78
135
  registeredNow.push(result.record);
79
136
  }
80
- return {
81
- ok: diagnostics.every((entry) => entry.severity !== 'error'),
82
- schema: 'pappra/docs-scan/1',
83
- mode: 'apply',
84
- workspaceRoot: root,
85
- candidates,
86
- registered: registeredNow,
87
- skipped: candidates.length - registeredNow.length,
88
- nextActions: [],
89
- diagnostics,
90
- };
137
+ const nextActions = [];
138
+ if (incomplete ||
139
+ discovery.truncated ||
140
+ registeredNow.length < candidates.length) {
141
+ nextActions.push('Coverage was incomplete or some registrations failed; correct the diagnostics and rerun the scan.');
142
+ }
143
+ if (privateCommand !== null) {
144
+ nextActions.push(`Review registered private documents with: ${privateCommand}.`);
145
+ }
146
+ return scanResult(root, 'apply', candidates, registeredNow, candidates.length - registeredNow.length, diagnostics, nextActions, !incomplete && !diagnostics.some((entry) => entry.severity === 'error'));
91
147
  }
@@ -1,3 +1,4 @@
1
+ import type { DocumentLocation } from '../schemas/document.js';
1
2
  import { type FreshnessReport } from './refs.js';
2
3
  import type { ApplyWriteInput, ApplyWriteResult, ArchiveDocumentResult, DeleteExplicitInput, DeleteExplicitResult, DocumentCheckResult, ListDocumentsOptions, ListDocumentsResult, PreviewDeleteInput, PreviewDeleteResult, ProposeWriteInput, ProposeWriteResult, ReadDocumentResult, RegisterDocumentInput, RegisterDocumentResult, ShareDocumentResult, SupersedeDocumentInput, SupersedeDocumentResult, KnowledgeServiceOptions } from './types.js';
3
4
  export declare class KnowledgeService {
@@ -5,6 +6,8 @@ export declare class KnowledgeService {
5
6
  readonly root: string;
6
7
  constructor(root: string, options?: KnowledgeServiceOptions);
7
8
  register(input: RegisterDocumentInput): Promise<RegisterDocumentResult>;
9
+ relocate(documentId: string, location: DocumentLocation): Promise<RegisterDocumentResult>;
10
+ forget(documentId: string, scope?: 'shared' | 'private'): Promise<RegisterDocumentResult>;
8
11
  read(documentId: string): Promise<ReadDocumentResult>;
9
12
  list(options?: ListDocumentsOptions): Promise<ListDocumentsResult>;
10
13
  check(options?: {
@@ -5,6 +5,7 @@ import { loadKnowledgeCatalogs } from './catalog.js';
5
5
  import { inspectFreshness, findRecord } from './refs.js';
6
6
  import { resolveKnowledgeLocation, readKnowledgeFile } from './paths.js';
7
7
  import { applyWrite, proposeWrite, registerDocument } from './write.js';
8
+ import { relocateOrForgetDocument } from './relocate.js';
8
9
  import { archiveDocument, deleteExplicit, previewDelete, shareDocument, supersedeDocument, } from './lifecycle.js';
9
10
  const MAX_DOCUMENT_BYTES = 8 * 1024 * 1024;
10
11
  function outcomeDiagnostic(failure, source) {
@@ -77,8 +78,17 @@ function filteredDiagnostics(context, catalogs, includePrivate) {
77
78
  if (includePrivate)
78
79
  return diagnostics;
79
80
  const privatePrefix = `${context.root}/.pappra/local/knowledge`;
80
- return diagnostics.filter((entry) => entry.source !== privatePrefix &&
81
+ const visible = diagnostics.filter((entry) => entry.source !== privatePrefix &&
81
82
  !entry.source.startsWith(`${privatePrefix}/`));
83
+ if (!catalogs.ok && !visible.some((entry) => entry.severity === 'error'))
84
+ visible.push(createDiagnostic({
85
+ code: diagnosticCodes.document_catalog_conflict,
86
+ severity: 'error',
87
+ message: 'A private knowledge catalog conflict blocks this operation.',
88
+ source: context.configPath,
89
+ hint: 'Run pappra docs list --include-private to inspect the conflict; use docs forget to remove an obsolete registration without deleting its file.',
90
+ }));
91
+ return visible;
82
92
  }
83
93
  export class KnowledgeService {
84
94
  root;
@@ -99,6 +109,28 @@ export class KnowledgeService {
99
109
  }
100
110
  return registerDocument(loaded.context, input);
101
111
  }
112
+ async relocate(documentId, location) {
113
+ const loaded = await getContext(this.root);
114
+ if (!loaded.ok)
115
+ return {
116
+ ok: false,
117
+ status: 'failed',
118
+ record: null,
119
+ diagnostics: loaded.diagnostics,
120
+ };
121
+ return relocateOrForgetDocument(loaded.context, documentId, location);
122
+ }
123
+ async forget(documentId, scope) {
124
+ const loaded = await getContext(this.root);
125
+ if (!loaded.ok)
126
+ return {
127
+ ok: false,
128
+ status: 'failed',
129
+ record: null,
130
+ diagnostics: loaded.diagnostics,
131
+ };
132
+ return relocateOrForgetDocument(loaded.context, documentId, null, scope);
133
+ }
102
134
  async read(documentId) {
103
135
  const loaded = await getContext(this.root);
104
136
  if (!loaded.ok) {
@@ -1,7 +1,10 @@
1
- import { type DocumentWriteProposal } from '../schemas/document.js';
1
+ import { type DocumentRecord, type DocumentWriteProposal } from '../schemas/document.js';
2
+ import { type Outcome } from '../schemas/outcome.js';
2
3
  import type { KnowledgeContext } from './context.js';
4
+ import { type ResolvedKnowledgeLocation } from './paths.js';
3
5
  import type { ApplyWriteInput, ApplyWriteResult, KnowledgeServiceOptions, ProposeWriteInput, ProposeWriteResult, RegisterDocumentInput, RegisterDocumentResult } from './types.js';
4
6
  export declare function defaultVisibility(context: KnowledgeContext): 'private' | 'shareable';
7
+ export declare function validateAndBuildRecord(context: KnowledgeContext, input: RegisterDocumentInput, location: ResolvedKnowledgeLocation): Promise<Outcome<DocumentRecord>>;
5
8
  export declare function registerDocument(context: KnowledgeContext, input: RegisterDocumentInput): Promise<RegisterDocumentResult>;
6
9
  export declare function proposeWrite(context: KnowledgeContext, input: ProposeWriteInput): Promise<ProposeWriteResult>;
7
10
  export declare function applyWrite(input: ApplyWriteInput, root: string, options?: KnowledgeServiceOptions): Promise<ApplyWriteResult>;
@@ -99,7 +99,7 @@ function recordDiagnostics(record, source) {
99
99
  diagnostic(diagnosticCodes.document_record_invalid, `Document record is invalid: ${parsed.error.issues[0]?.message ?? 'unknown issue'}`, source, 'Fix the record metadata; no catalog bytes were written.'),
100
100
  ];
101
101
  }
102
- async function validateAndBuildRecord(context, input, location) {
102
+ export async function validateAndBuildRecord(context, input, location) {
103
103
  const documentId = input.documentId ?? randomUUID();
104
104
  const visibility = input.visibility ?? defaultVisibility(context);
105
105
  const sources = input.sources ?? [];
@@ -2,10 +2,12 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  export declare const MCP_SERVER_NAME = "pappra";
3
3
  export interface PappraMcpServerOptions {
4
4
  readonly root: string;
5
+ /** Trusted server-launch policy, never accepted from tool arguments. */
6
+ readonly allowWorkspaceWrites?: boolean;
5
7
  }
6
8
  /**
7
9
  * Builds the stdio MCP server for one workspace. Tools are read-only here; write
8
- * operations are added separately and must stay behind apply/confirm gates.
10
+ * operations require a trusted launch policy; tool flags only select preview/apply.
9
11
  */
10
12
  export declare function createPappraMcpServer(options: PappraMcpServerOptions): McpServer;
11
- export declare function runMcpServer(root: string): Promise<void>;
13
+ export declare function runMcpServer(root: string, allowWorkspaceWrites?: boolean): Promise<void>;
@@ -1,6 +1,7 @@
1
1
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
3
  import { z } from 'zod';
4
+ import path from 'node:path';
4
5
  import { discoverWorkspace } from '../workspace/discover.js';
5
6
  import { inspectMachineConfig, inspectWorkspaceConfig, } from '../workspace/config.js';
6
7
  import { inspectRuntimeStatePassive } from '../install/runtime.js';
@@ -10,11 +11,18 @@ import { CodeIntelligenceService } from '../code/index.js';
10
11
  import { HOST_SUPPORT } from '../hosts/integration/support.js';
11
12
  import { getPackageInfo } from '../package-info.js';
12
13
  import { scanDiscoveredDocuments } from '../knowledge/scan.js';
13
- import { installRuntime } from '../install/runtime.js';
14
- import { bindAndRecordRuntime, ensureDefaultRuntime } from '../app/init.js';
15
- import { prepareFromObjective } from '../app/collab-from.js';
16
- import { FixtureController, PiRpcController, finishStarted, startPrepared, submitResultReport, } from '../app/collaboration.js';
14
+ import { prepareCollaboration } from '../app/collaboration.js';
15
+ import { collaborationGoalSchema } from '../schemas/collaboration.js';
16
+ import { canonicalizeTarget } from '../collab/canonical.js';
17
+ import { isPathInside } from '../schemas/paths.js';
17
18
  export const MCP_SERVER_NAME = 'pappra';
19
+ function cliRequired(command) {
20
+ return {
21
+ ok: false,
22
+ status: 'cli_required',
23
+ message: `${command} requires an authorized CLI invocation. A tool-supplied apply flag is not user approval.`,
24
+ };
25
+ }
18
26
  function toolResult(value, isError = false) {
19
27
  return {
20
28
  content: [
@@ -39,10 +47,11 @@ async function errorResult(action) {
39
47
  }
40
48
  /**
41
49
  * Builds the stdio MCP server for one workspace. Tools are read-only here; write
42
- * operations are added separately and must stay behind apply/confirm gates.
50
+ * operations require a trusted launch policy; tool flags only select preview/apply.
43
51
  */
44
52
  export function createPappraMcpServer(options) {
45
53
  const root = options.root;
54
+ const allowWorkspaceWrites = options.allowWorkspaceWrites === true;
46
55
  const server = new McpServer({
47
56
  name: MCP_SERVER_NAME,
48
57
  version: getPackageInfo().version,
@@ -222,13 +231,15 @@ export function createPappraMcpServer(options) {
222
231
  provider: result.result?.provider ?? null,
223
232
  coverage: result.result?.coverage ?? null,
224
233
  items: result.result?.items ?? [],
234
+ truncated: result.result?.truncated ?? false,
235
+ reasons: result.result?.reasons ?? [],
225
236
  health: result.health,
226
237
  diagnostics: result.diagnostics,
227
238
  };
228
239
  }));
229
240
  server.registerTool('checkpoint', {
230
241
  title: 'Write a task checkpoint',
231
- description: 'Writes an advisory checkpoint for handoff. Requires apply: true; a checkpoint is context, not permission to execute.',
242
+ description: 'Writes an advisory checkpoint only when trusted server startup enables workspace writes. apply selects persistence and never grants authorization.',
232
243
  inputSchema: {
233
244
  task: z.string().min(1).max(256),
234
245
  objective: z.string().min(1).max(4000),
@@ -245,13 +256,15 @@ export function createPappraMcpServer(options) {
245
256
  nativeSession: z.string().min(1).max(256).optional(),
246
257
  apply: z.boolean(),
247
258
  },
248
- annotations: { readOnlyHint: false },
259
+ annotations: { readOnlyHint: !allowWorkspaceWrites },
249
260
  }, async (args) => errorResult(async () => {
261
+ if (!allowWorkspaceWrites)
262
+ return cliRequired('pappra checkpoint');
250
263
  if (args.apply !== true) {
251
264
  return {
252
265
  ok: false,
253
- status: 'confirmation_required',
254
- message: 'checkpoint writes state; call again with apply: true after the user agrees.',
266
+ status: 'preview',
267
+ message: 'Preview only. The trusted host has enabled workspace writes; apply selects persistence, not authorization.',
255
268
  };
256
269
  }
257
270
  const nativeRefs = args.nativeSession === undefined
@@ -308,10 +321,12 @@ export function createPappraMcpServer(options) {
308
321
  }));
309
322
  server.registerTool('docs_scan', {
310
323
  title: 'Scan knowledge sources',
311
- description: 'Registers documents discovered under the configured knowledge sources. Without apply it only reports candidates.',
324
+ description: 'Previews discovered knowledge documents. Applying requires trusted server startup workspace-write policy; tool flags do not grant it.',
312
325
  inputSchema: { apply: z.boolean().optional() },
313
- annotations: { readOnlyHint: false },
326
+ annotations: { readOnlyHint: !allowWorkspaceWrites },
314
327
  }, async (args) => errorResult(async () => {
328
+ if (args.apply === true && !allowWorkspaceWrites)
329
+ return cliRequired('pappra docs scan --apply');
315
330
  const result = await scanDiscoveredDocuments(root, {
316
331
  apply: args.apply === true,
317
332
  });
@@ -319,19 +334,21 @@ export function createPappraMcpServer(options) {
319
334
  }));
320
335
  server.registerTool('code_prepare', {
321
336
  title: 'Prepare a repository code index',
322
- description: 'Registers the selected repository index and optionally runs the external engine. Without apply it only reports the plan.',
337
+ description: 'Previews repository index preparation. Engine execution requires an authorized CLI command.',
323
338
  inputSchema: {
324
339
  repo: z.string().min(1).max(128),
325
340
  apply: z.boolean().optional(),
326
341
  rebuild: z.boolean().optional(),
327
342
  },
328
- annotations: { readOnlyHint: false },
343
+ annotations: { readOnlyHint: true },
329
344
  }, async (args) => errorResult(async () => {
345
+ if (args.apply === true)
346
+ return cliRequired('pappra code prepare --apply');
330
347
  const service = new CodeIntelligenceService(root);
331
348
  const result = await service.prepare({
332
349
  root,
333
350
  repositoryId: args.repo,
334
- apply: args.apply === true,
351
+ apply: false,
335
352
  rebuild: args.rebuild === true,
336
353
  });
337
354
  return {
@@ -345,147 +362,81 @@ export function createPappraMcpServer(options) {
345
362
  }));
346
363
  server.registerTool('runtime_install', {
347
364
  title: 'Install the durable runtime',
348
- description: 'Installs and binds a durable runtime copy. Requires apply: true; the default source is the running package.',
349
- inputSchema: {
350
- from: z.enum(['self', 'tarball', 'version']).optional(),
351
- version: z.string().min(1).max(128).optional(),
352
- tarball: z.string().min(1).max(4096).optional(),
365
+ description: 'Reports CLI guidance for runtime installation; MCP never installs or executes package code. Only from:self is accepted.',
366
+ inputSchema: z.strictObject({
367
+ from: z.literal('self').optional(),
353
368
  apply: z.boolean(),
354
- },
355
- annotations: { readOnlyHint: false },
369
+ }),
370
+ annotations: { readOnlyHint: true },
356
371
  }, async (args) => errorResult(async () => {
357
372
  const from = args.from ?? 'self';
358
- const version = args.version ?? getPackageInfo().version;
359
- if (args.apply !== true) {
360
- return {
361
- ok: false,
362
- status: 'confirmation_required',
363
- message: 'runtime_install writes a durable copy and machine.json; call again with apply: true.',
364
- version,
365
- from,
366
- };
367
- }
368
- if (from === 'self') {
369
- const result = await ensureDefaultRuntime(root, version);
370
- return {
371
- ok: result.ok && result.completion,
372
- completion: result.completion,
373
- runtime: result.runtime,
374
- diagnostics: result.diagnostics,
375
- };
376
- }
377
- const tarball = args.tarball;
378
- if (from === 'tarball' && tarball === undefined) {
379
- return {
380
- ok: false,
381
- message: 'from: tarball requires the tarball path.',
382
- };
383
- }
384
- const installed = await installRuntime({
385
- version,
386
- source: from === 'tarball' && tarball !== undefined
387
- ? { kind: 'tarball', path: tarball }
388
- : { kind: 'version' },
389
- packageName: getPackageInfo().name,
390
- });
391
- const bound = await bindAndRecordRuntime(root, installed);
373
+ const version = getPackageInfo().version;
392
374
  return {
393
- ok: bound.ok && bound.completion,
394
- completion: bound.completion,
395
- runtime: installed,
396
- diagnostics: bound.diagnostics,
375
+ ...cliRequired('pappra runtime install --from self --apply'),
376
+ version,
377
+ from,
397
378
  };
398
379
  }));
399
380
  server.registerTool('collab_prepare', {
400
381
  title: 'Prepare a bounded collaboration',
401
- description: 'Builds a collaboration goal and a declared capability card from an objective and explicit resources, then claims them. A declared card cannot authorize a work launch.',
402
- inputSchema: {
382
+ description: 'Prepares a bounded collaboration from an explicit shared pappra/collaboration-goal/1 document plus a shared domain root, then claims its resources. Identities, configuration, cwd, roles and capabilities are never inferred. No capability card is generated: derive and preflight actual runtime evidence separately before a user-authorized CLI launch. The legacy flat objective form is unsupported.',
383
+ inputSchema: z.strictObject({
403
384
  domainRoot: z.string().min(1).max(4096),
404
- objective: z.string().min(1).max(4000),
405
- task: z.string().min(1).max(128),
406
- acceptance: z.array(z.string().min(1).max(1000)).min(1).max(32),
407
- resources: z
408
- .array(z.object({
409
- path: z.string().min(1).max(4096),
410
- access: z.enum(['read', 'write']),
411
- }))
412
- .min(1)
413
- .max(32),
414
- coordinatorSession: z.string().min(1).max(256),
415
- assigneeSession: z.string().min(1).max(256),
416
- harness: z.enum(['pi', 'codex', 'claude']).optional(),
417
- subtaskId: z.string().min(1).max(128).optional(),
418
- attempt: z.number().int().min(1).max(1000).optional(),
419
- phase: z
420
- .enum(['discovery', 'implementation', 'review', 'handoff', 'fix'])
421
- .optional(),
422
- prompt: z.string().min(1).max(20000).optional(),
423
- },
424
- annotations: { readOnlyHint: false },
385
+ goal: collaborationGoalSchema,
386
+ }),
387
+ annotations: { readOnlyHint: !allowWorkspaceWrites },
425
388
  }, async (args) => errorResult(async () => {
426
- const result = await prepareFromObjective({
389
+ if (!allowWorkspaceWrites)
390
+ return cliRequired('pappra collab prepare');
391
+ const workspace = canonicalizeTarget(path.resolve(root)).path;
392
+ const privateDomain = path.join(workspace, '.pappra', 'local', 'collaboration');
393
+ const domain = canonicalizeTarget(path.resolve(args.domainRoot)).path;
394
+ if (!isPathInside(privateDomain, domain) ||
395
+ !isPathInside(workspace, canonicalizeTarget(args.goal.assignee.cwd).path) ||
396
+ args.goal.resources.some((resource) => !isPathInside(workspace, canonicalizeTarget(resource.path).path)))
397
+ return {
398
+ ok: false,
399
+ status: 'scope_refused',
400
+ message: 'MCP preparation is limited to a private workspace collaboration domain and workspace-local resources; use the authorized CLI for other scopes.',
401
+ };
402
+ const result = await prepareCollaboration(args.goal, {
427
403
  domainRoot: args.domainRoot,
428
- objective: args.objective,
429
- taskId: args.task,
430
- acceptance: args.acceptance,
431
- resources: args.resources,
432
- coordinatorSession: args.coordinatorSession,
433
- assigneeSession: args.assigneeSession,
434
- ...(args.harness === undefined ? {} : { harness: args.harness }),
435
- ...(args.subtaskId === undefined
436
- ? {}
437
- : { subtaskId: args.subtaskId }),
438
- ...(args.attempt === undefined ? {} : { attempt: args.attempt }),
439
- ...(args.phase === undefined ? {} : { phase: args.phase }),
440
- ...(args.prompt === undefined ? {} : { prompt: args.prompt }),
441
404
  });
442
- return result;
405
+ if (!result.ok) {
406
+ return {
407
+ ok: false,
408
+ status: result.status,
409
+ code: result.code,
410
+ message: result.message,
411
+ nextAction: result.nextAction,
412
+ diagnostics: result.diagnostics,
413
+ };
414
+ }
415
+ return {
416
+ ok: true,
417
+ prepared: result.value.prepared,
418
+ goal: result.value.goal,
419
+ notes: [
420
+ 'No capability card is generated and no observation timestamp is manufactured. Supply actual capability evidence: derive a runtime card with pappra collab capabilities derive from the receiving session, check it with pappra collab preflight, then ask the user to launch with pappra collab run in the CLI.',
421
+ 'The removed cardPath/card outputs were declared-only evidence and never authorized a launch.',
422
+ ],
423
+ };
443
424
  }));
444
425
  server.registerTool('collab_start', {
445
426
  title: 'Start one admitted collaboration launch',
446
- description: 'Performs one admitted launch with an explicit controller and returns the report. Requires confirm: true and a runtime capability card; a declared card is refused by admission.',
427
+ description: 'Returns CLI guidance without launching. The user must launch through the CLI; an agent-supplied confirm flag is not user approval.',
447
428
  inputSchema: {
448
429
  prepared: z.string().min(1).max(4096),
449
430
  capabilities: z.string().min(1).max(4096),
450
431
  controller: z.enum(['fixture', 'pi-rpc']),
451
432
  confirm: z.boolean(),
452
433
  },
453
- annotations: { readOnlyHint: false, destructiveHint: true },
454
- }, async (args) => errorResult(async () => {
455
- if (args.confirm !== true) {
456
- return {
457
- ok: false,
458
- status: 'confirmation_required',
459
- message: 'collab_start launches a process; the user must confirm before calling it with confirm: true.',
460
- };
461
- }
462
- const controller = args.controller === 'fixture'
463
- ? new FixtureController()
464
- : new PiRpcController();
465
- const started = await startPrepared(args.prepared, {
466
- capabilitiesFile: args.capabilities,
467
- controller,
468
- controllerId: controller.id,
469
- });
470
- if (!started.ok)
471
- return started;
472
- try {
473
- const finished = await finishStarted(started.value);
474
- if (!finished.ok) {
475
- return finished;
476
- }
477
- const report = submitResultReport(started.value, finished.value);
478
- return {
479
- ok: report.ok,
480
- status: finished.value.status,
481
- report,
482
- finish: finished.value,
483
- };
484
- }
485
- finally {
486
- await started.value.session.dispose?.().catch(() => undefined);
487
- }
488
- }));
434
+ annotations: { readOnlyHint: true, destructiveHint: false },
435
+ }, async () => errorResult(async () => ({
436
+ ok: false,
437
+ status: 'cli_required',
438
+ message: 'MCP cannot authorize process launches. Ask the user to run pappra collab run --prepared <file> --capabilities <file> --controller <controller> --confirm in the CLI.',
439
+ })));
489
440
  server.registerTool('runtime_status', {
490
441
  title: 'Runtime status',
491
442
  description: 'Reports the workspace runtime binding and passive runtime state.',
@@ -511,8 +462,8 @@ export function createPappraMcpServer(options) {
511
462
  }));
512
463
  return server;
513
464
  }
514
- export async function runMcpServer(root) {
515
- const server = createPappraMcpServer({ root });
465
+ export async function runMcpServer(root, allowWorkspaceWrites = false) {
466
+ const server = createPappraMcpServer({ root, allowWorkspaceWrites });
516
467
  const transport = new StdioServerTransport();
517
468
  await server.connect(transport);
518
469
  }
@@ -0,0 +1,6 @@
1
+ import type { TaskRecord, LockHolder, Message, Notification } from './collaboration-state.js';
2
+ export { object, text, errorCode, parseJson } from '../infra/validation.js';
3
+ export declare function isTaskRecord(value: unknown): value is TaskRecord;
4
+ export declare function isLockHolder(value: unknown): value is LockHolder;
5
+ export declare function isMessage(value: unknown): value is Message;
6
+ export declare function isNotification(value: unknown): value is Notification;