@phyzess/pappra 0.0.0-stage → 0.1.0-beta.2

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 (221) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +80 -2
  3. package/THIRD_PARTY_NOTICES.md +16 -0
  4. package/assets/integrations/skills/pappra/SKILL.md +68 -0
  5. package/assets/integrations/skills/pappra/references/hosts.md +30 -0
  6. package/assets/integrations/skills/pappra/references/lifecycle.md +37 -0
  7. package/assets/integrations/skills/pappra/references/operations.md +14 -0
  8. package/assets/manifest.json +4 -0
  9. package/dist/app/collaboration.d.ts +170 -0
  10. package/dist/app/collaboration.js +1650 -0
  11. package/dist/app/doctor.d.ts +9 -0
  12. package/dist/app/doctor.js +1030 -0
  13. package/dist/app/init.d.ts +143 -0
  14. package/dist/app/init.js +1111 -0
  15. package/dist/cli/commands/code.d.ts +16 -0
  16. package/dist/cli/commands/code.js +127 -0
  17. package/dist/cli/commands/collaboration.d.ts +13 -0
  18. package/dist/cli/commands/collaboration.js +186 -0
  19. package/dist/cli/commands/continuity.d.ts +29 -0
  20. package/dist/cli/commands/continuity.js +133 -0
  21. package/dist/cli/commands/docs.d.ts +11 -0
  22. package/dist/cli/commands/docs.js +133 -0
  23. package/dist/cli/commands/doctor.d.ts +14 -0
  24. package/dist/cli/commands/doctor.js +57 -0
  25. package/dist/cli/commands/host.d.ts +13 -0
  26. package/dist/cli/commands/host.js +125 -0
  27. package/dist/cli/commands/init.d.ts +51 -0
  28. package/dist/cli/commands/init.js +668 -0
  29. package/dist/cli/main.d.ts +2 -0
  30. package/dist/cli/main.js +10 -0
  31. package/dist/cli/output.d.ts +4 -0
  32. package/dist/cli/output.js +1 -0
  33. package/dist/cli/run.d.ts +2 -0
  34. package/dist/cli/run.js +597 -0
  35. package/dist/code/budget.d.ts +14 -0
  36. package/dist/code/budget.js +39 -0
  37. package/dist/code/exec.d.ts +23 -0
  38. package/dist/code/exec.js +133 -0
  39. package/dist/code/identity.d.ts +13 -0
  40. package/dist/code/identity.js +214 -0
  41. package/dist/code/index.d.ts +6 -0
  42. package/dist/code/index.js +3 -0
  43. package/dist/code/providers/codegraph.d.ts +59 -0
  44. package/dist/code/providers/codegraph.js +567 -0
  45. package/dist/code/registration.d.ts +9 -0
  46. package/dist/code/registration.js +293 -0
  47. package/dist/code/service.d.ts +53 -0
  48. package/dist/code/service.js +633 -0
  49. package/dist/code/text.d.ts +3 -0
  50. package/dist/code/text.js +202 -0
  51. package/dist/collab/admission.d.ts +450 -0
  52. package/dist/collab/admission.js +797 -0
  53. package/dist/collab/canonical.d.ts +26 -0
  54. package/dist/collab/canonical.js +136 -0
  55. package/dist/collab/contracts.d.ts +73 -0
  56. package/dist/collab/contracts.js +76 -0
  57. package/dist/collab/envelope.d.ts +52 -0
  58. package/dist/collab/envelope.js +241 -0
  59. package/dist/collab/fingerprint.d.ts +7 -0
  60. package/dist/collab/fingerprint.js +58 -0
  61. package/dist/collab/handoff.d.ts +350 -0
  62. package/dist/collab/handoff.js +513 -0
  63. package/dist/collab/index.d.ts +9 -0
  64. package/dist/collab/index.js +8 -0
  65. package/dist/collab/lifecycle.d.ts +449 -0
  66. package/dist/collab/lifecycle.js +534 -0
  67. package/dist/collab/messages.d.ts +148 -0
  68. package/dist/collab/messages.js +583 -0
  69. package/dist/collab/notify.d.ts +47 -0
  70. package/dist/collab/notify.js +140 -0
  71. package/dist/collab/preflight.d.ts +31 -0
  72. package/dist/collab/preflight.js +271 -0
  73. package/dist/collab/resources.d.ts +119 -0
  74. package/dist/collab/resources.js +451 -0
  75. package/dist/collab/store.d.ts +143 -0
  76. package/dist/collab/store.js +606 -0
  77. package/dist/collab/types.d.ts +354 -0
  78. package/dist/collab/types.js +1 -0
  79. package/dist/collab/validation.d.ts +10 -0
  80. package/dist/collab/validation.js +303 -0
  81. package/dist/continuity/context.d.ts +24 -0
  82. package/dist/continuity/context.js +179 -0
  83. package/dist/continuity/index.d.ts +3 -0
  84. package/dist/continuity/index.js +1 -0
  85. package/dist/continuity/paths.d.ts +37 -0
  86. package/dist/continuity/paths.js +258 -0
  87. package/dist/continuity/service.d.ts +59 -0
  88. package/dist/continuity/service.js +1258 -0
  89. package/dist/hosts/claude/native.d.ts +79 -0
  90. package/dist/hosts/claude/native.js +853 -0
  91. package/dist/hosts/codex/native.d.ts +345 -0
  92. package/dist/hosts/codex/native.js +1528 -0
  93. package/dist/hosts/codex/protocol.d.ts +51 -0
  94. package/dist/hosts/codex/protocol.js +42 -0
  95. package/dist/hosts/detect.d.ts +28 -0
  96. package/dist/hosts/detect.js +73 -0
  97. package/dist/hosts/index.d.ts +10 -0
  98. package/dist/hosts/index.js +10 -0
  99. package/dist/hosts/integration/bundle.d.ts +16 -0
  100. package/dist/hosts/integration/bundle.js +81 -0
  101. package/dist/hosts/integration/hook-entry.d.ts +1 -0
  102. package/dist/hosts/integration/hook-entry.js +68 -0
  103. package/dist/hosts/integration/hook.d.ts +32 -0
  104. package/dist/hosts/integration/hook.js +781 -0
  105. package/dist/hosts/integration/pi-extension-runtime.d.ts +18 -0
  106. package/dist/hosts/integration/pi-extension-runtime.js +89 -0
  107. package/dist/hosts/integration/pi-template.d.ts +3 -0
  108. package/dist/hosts/integration/pi-template.js +5 -0
  109. package/dist/hosts/integration/service.d.ts +41 -0
  110. package/dist/hosts/integration/service.js +1381 -0
  111. package/dist/hosts/integration/support.d.ts +36 -0
  112. package/dist/hosts/integration/support.js +41 -0
  113. package/dist/hosts/integration/templates.d.ts +22 -0
  114. package/dist/hosts/integration/templates.js +70 -0
  115. package/dist/hosts/pi/protocol.d.ts +22 -0
  116. package/dist/hosts/pi/protocol.js +28 -0
  117. package/dist/hosts/pi/query-result.d.ts +22 -0
  118. package/dist/hosts/pi/query-result.js +710 -0
  119. package/dist/hosts/pi/rpc.d.ts +937 -0
  120. package/dist/hosts/pi/rpc.js +1621 -0
  121. package/dist/hosts/pilot.d.ts +485 -0
  122. package/dist/hosts/pilot.js +593 -0
  123. package/dist/index.d.ts +5 -0
  124. package/dist/index.js +4 -0
  125. package/dist/infra/fs.d.ts +27 -0
  126. package/dist/infra/fs.js +130 -0
  127. package/dist/infra/git.d.ts +60 -0
  128. package/dist/infra/git.js +358 -0
  129. package/dist/infra/owned-process-group.d.ts +173 -0
  130. package/dist/infra/owned-process-group.js +571 -0
  131. package/dist/install/apply.d.ts +65 -0
  132. package/dist/install/apply.js +663 -0
  133. package/dist/install/index.d.ts +5 -0
  134. package/dist/install/index.js +5 -0
  135. package/dist/install/ownership.d.ts +85 -0
  136. package/dist/install/ownership.js +430 -0
  137. package/dist/install/plan.d.ts +39 -0
  138. package/dist/install/plan.js +97 -0
  139. package/dist/install/rollback.d.ts +18 -0
  140. package/dist/install/rollback.js +544 -0
  141. package/dist/install/runtime.d.ts +76 -0
  142. package/dist/install/runtime.js +1145 -0
  143. package/dist/knowledge/catalog.d.ts +47 -0
  144. package/dist/knowledge/catalog.js +308 -0
  145. package/dist/knowledge/context.d.ts +28 -0
  146. package/dist/knowledge/context.js +61 -0
  147. package/dist/knowledge/index.d.ts +3 -0
  148. package/dist/knowledge/index.js +1 -0
  149. package/dist/knowledge/journal.d.ts +16 -0
  150. package/dist/knowledge/journal.js +109 -0
  151. package/dist/knowledge/lifecycle.d.ts +8 -0
  152. package/dist/knowledge/lifecycle.js +1001 -0
  153. package/dist/knowledge/paths.d.ts +37 -0
  154. package/dist/knowledge/paths.js +236 -0
  155. package/dist/knowledge/refs.d.ts +36 -0
  156. package/dist/knowledge/refs.js +267 -0
  157. package/dist/knowledge/service.d.ts +21 -0
  158. package/dist/knowledge/service.js +393 -0
  159. package/dist/knowledge/types.d.ts +171 -0
  160. package/dist/knowledge/types.js +1 -0
  161. package/dist/knowledge/write.d.ts +8 -0
  162. package/dist/knowledge/write.js +1223 -0
  163. package/dist/package-info.d.ts +6 -0
  164. package/dist/package-info.js +19 -0
  165. package/dist/schemas/code.d.ts +377 -0
  166. package/dist/schemas/code.js +145 -0
  167. package/dist/schemas/collaboration.d.ts +115 -0
  168. package/dist/schemas/collaboration.js +106 -0
  169. package/dist/schemas/continuity.d.ts +315 -0
  170. package/dist/schemas/continuity.js +199 -0
  171. package/dist/schemas/diagnostics.d.ts +28 -0
  172. package/dist/schemas/diagnostics.js +27 -0
  173. package/dist/schemas/doctor.d.ts +157 -0
  174. package/dist/schemas/doctor.js +75 -0
  175. package/dist/schemas/document.d.ts +644 -0
  176. package/dist/schemas/document.js +296 -0
  177. package/dist/schemas/errors.d.ts +177 -0
  178. package/dist/schemas/errors.js +176 -0
  179. package/dist/schemas/evidence.d.ts +24 -0
  180. package/dist/schemas/evidence.js +16 -0
  181. package/dist/schemas/host.d.ts +436 -0
  182. package/dist/schemas/host.js +201 -0
  183. package/dist/schemas/index.d.ts +15 -0
  184. package/dist/schemas/index.js +15 -0
  185. package/dist/schemas/init.d.ts +121 -0
  186. package/dist/schemas/init.js +94 -0
  187. package/dist/schemas/install.d.ts +213 -0
  188. package/dist/schemas/install.js +139 -0
  189. package/dist/schemas/machine.d.ts +43 -0
  190. package/dist/schemas/machine.js +96 -0
  191. package/dist/schemas/outcome.d.ts +23 -0
  192. package/dist/schemas/outcome.js +17 -0
  193. package/dist/schemas/paths.d.ts +19 -0
  194. package/dist/schemas/paths.js +63 -0
  195. package/dist/schemas/workspace.d.ts +120 -0
  196. package/dist/schemas/workspace.js +201 -0
  197. package/dist/workspace/config-file.d.ts +36 -0
  198. package/dist/workspace/config-file.js +237 -0
  199. package/dist/workspace/config.d.ts +28 -0
  200. package/dist/workspace/config.js +79 -0
  201. package/dist/workspace/discover.d.ts +34 -0
  202. package/dist/workspace/discover.js +195 -0
  203. package/dist/workspace/documents.d.ts +21 -0
  204. package/dist/workspace/documents.js +395 -0
  205. package/dist/workspace/ignore.d.ts +10 -0
  206. package/dist/workspace/ignore.js +48 -0
  207. package/dist/workspace/index.d.ts +7 -0
  208. package/dist/workspace/index.js +3 -0
  209. package/dist/workspace/repositories.d.ts +24 -0
  210. package/dist/workspace/repositories.js +411 -0
  211. package/dist/workspace/resolve.d.ts +24 -0
  212. package/dist/workspace/resolve.js +268 -0
  213. package/dist/workspace/types.d.ts +71 -0
  214. package/dist/workspace/types.js +1 -0
  215. package/dist/workspace/validation.d.ts +18 -0
  216. package/dist/workspace/validation.js +197 -0
  217. package/package.json +105 -4
  218. package/skills/pappra/SKILL.md +68 -0
  219. package/skills/pappra/references/hosts.md +30 -0
  220. package/skills/pappra/references/lifecycle.md +37 -0
  221. package/skills/pappra/references/operations.md +14 -0
@@ -0,0 +1,633 @@
1
+ import { sha256Digest } from '../infra/fs.js';
2
+ import { createDiagnostic } from '../schemas/diagnostics.js';
3
+ import { diagnosticCodes } from '../schemas/errors.js';
4
+ import { succeeded } from '../schemas/outcome.js';
5
+ import { inspectMachineConfig, inspectWorkspaceConfig, } from '../workspace/config.js';
6
+ import { discoverRepositories } from '../workspace/repositories.js';
7
+ import { codeIndexHealthSchema, codePreparePlanSchema, codeQueryLimitsSchema, codeQueryRequestSchema, } from '../schemas/code.js';
8
+ import { CodeGraphProvider, observeCodeGraphConfig, codeGraphVersion, codeGraphPlanCommand, } from './providers/codegraph.js';
9
+ import { computeCodeIdentity, codeIdentityDigest } from './identity.js';
10
+ import { codeRegistrationPath, readCodeRegistration, registrationMatches, acquireCodePrepareLock, releaseCodePrepareLock, ensureCodeMutationBoundary, writeCodeRegistration, } from './registration.js';
11
+ import { runTextQuery } from './text.js';
12
+ const discoveryOptions = {
13
+ scanDepth: 0,
14
+ maxDirectories: 1,
15
+ maxDocuments: 1,
16
+ maxEntriesPerDirectory: 1,
17
+ gitTimeoutMs: 10_000,
18
+ };
19
+ function outcomeDiagnostic(failure, source) {
20
+ return createDiagnostic({
21
+ code: failure.code,
22
+ severity: 'error',
23
+ message: failure.message,
24
+ source,
25
+ pointer: null,
26
+ hint: failure.nextAction,
27
+ });
28
+ }
29
+ function fallbackHealth(state, reason, engineVersion = 'unknown') {
30
+ return codeIndexHealthSchema.parse({
31
+ schema: 'pappra/code-index-health/1',
32
+ state,
33
+ reasons: [reason],
34
+ evidence: [],
35
+ coverage: {
36
+ scope: 'selected-repository',
37
+ languages: [],
38
+ semantic: false,
39
+ callGraph: false,
40
+ note: 'No ready code index was established.',
41
+ },
42
+ engineVersion,
43
+ observedAt: new Date().toISOString(),
44
+ });
45
+ }
46
+ async function loadWorkspace(root) {
47
+ const config = await inspectWorkspaceConfig(root);
48
+ const diagnostics = [...config.diagnostics];
49
+ if (config.value === null) {
50
+ return { root: config.root, repositories: [], diagnostics };
51
+ }
52
+ const machine = await inspectMachineConfig(config.root);
53
+ diagnostics.push(...machine.diagnostics);
54
+ const repositories = await discoverRepositories({
55
+ root: config.root,
56
+ config: config.value,
57
+ machine: machine.value,
58
+ configPath: config.path,
59
+ options: discoveryOptions,
60
+ });
61
+ diagnostics.push(...repositories.diagnostics);
62
+ return {
63
+ root: config.root,
64
+ repositories: repositories.repositories,
65
+ diagnostics,
66
+ };
67
+ }
68
+ function selectRepository(view, repositoryId) {
69
+ return (view.repositories.find((repository) => repository.id === repositoryId && !repository.external) ??
70
+ view.repositories.find((repository) => repository.id === repositoryId) ??
71
+ null);
72
+ }
73
+ function overlayRegistration(raw, registration, registrationFailure, identity) {
74
+ const reasons = [...raw.reasons];
75
+ if (registrationFailure !== null) {
76
+ reasons.push(registrationFailure.code);
77
+ return {
78
+ ...raw,
79
+ state: raw.state === 'ready' ? 'partial' : raw.state,
80
+ reasons: [...new Set(reasons)].slice(0, 32),
81
+ };
82
+ }
83
+ if (raw.state !== 'ready')
84
+ return raw;
85
+ if (registration === null) {
86
+ return {
87
+ ...raw,
88
+ state: 'partial',
89
+ reasons: [...reasons, 'registration_missing'].slice(0, 32),
90
+ };
91
+ }
92
+ if (!registrationMatches(registration, identity)) {
93
+ return {
94
+ ...raw,
95
+ state: 'stale',
96
+ reasons: [...reasons, 'registration_identity_changed'].slice(0, 32),
97
+ };
98
+ }
99
+ return raw;
100
+ }
101
+ async function observeCode(input) {
102
+ const view = await loadWorkspace(input.root);
103
+ const diagnostics = [...view.diagnostics];
104
+ const repository = selectRepository(view, input.repositoryId);
105
+ if (repository === null) {
106
+ return {
107
+ identity: null,
108
+ rawHealth: fallbackHealth('unsupported', 'repository_not_found'),
109
+ health: fallbackHealth('unsupported', 'repository_not_found'),
110
+ registration: null,
111
+ registrationPath: null,
112
+ excludedRoots: [],
113
+ access: 'read',
114
+ diagnostics: [
115
+ ...diagnostics,
116
+ createDiagnostic({
117
+ code: diagnosticCodes.code_repository_unknown,
118
+ severity: 'error',
119
+ message: `Selected repository is not declared: ${input.repositoryId}`,
120
+ source: view.root,
121
+ pointer: null,
122
+ hint: 'Select an explicit repository id from workspace.json.',
123
+ }),
124
+ ],
125
+ };
126
+ }
127
+ const version = await codeGraphVersion(input.signal);
128
+ const versionValue = version.ok ? version.value : 'unknown';
129
+ if (!version.ok)
130
+ diagnostics.push(outcomeDiagnostic(version, repository.root));
131
+ const configObserved = await observeCodeGraphConfig(repository.root);
132
+ const configDigest = configObserved.ok
133
+ ? configObserved.value.digest
134
+ : sha256Digest('codegraph:unknown');
135
+ const configStatus = configObserved.ok
136
+ ? configObserved.value.status
137
+ : 'unknown';
138
+ if (configStatus === 'unknown') {
139
+ diagnostics.push(createDiagnostic({
140
+ code: diagnosticCodes.code_index_partial,
141
+ severity: 'warning',
142
+ message: 'CodeGraph configuration could not be observed as a regular bounded file; ready is not permitted.',
143
+ source: repository.root,
144
+ pointer: '.codegraph/config.json',
145
+ hint: 'Inspect the engine configuration; the default configuration is not assumed.',
146
+ }));
147
+ }
148
+ const excludedRoots = view.repositories
149
+ .filter((entry) => entry.root !== repository.root)
150
+ .map((entry) => entry.root);
151
+ const identity = await computeCodeIdentity({
152
+ repositoryId: input.repositoryId,
153
+ root: repository.root,
154
+ engineVersion: versionValue,
155
+ configDigest,
156
+ configStatus,
157
+ excludedRoots,
158
+ ...(input.signal === undefined ? {} : { signal: input.signal }),
159
+ });
160
+ if (!identity.ok) {
161
+ diagnostics.push(outcomeDiagnostic(identity, repository.root));
162
+ return {
163
+ identity: null,
164
+ rawHealth: fallbackHealth('partial', identity.code, versionValue),
165
+ health: fallbackHealth('partial', identity.code, versionValue),
166
+ registration: null,
167
+ registrationPath: null,
168
+ excludedRoots,
169
+ access: repository.access,
170
+ diagnostics,
171
+ };
172
+ }
173
+ const provider = new CodeGraphProvider();
174
+ const raw = await provider.status(identity.value, input.signal);
175
+ const rawHealth = raw.ok
176
+ ? raw.value
177
+ : fallbackHealth('unsupported', raw.code, versionValue);
178
+ if (!raw.ok)
179
+ diagnostics.push(outcomeDiagnostic(raw, repository.root));
180
+ const registrationRead = await readCodeRegistration(repository.root, input.repositoryId);
181
+ let registration = null;
182
+ let registrationFailure = null;
183
+ if (registrationRead.ok) {
184
+ registration = registrationRead.value;
185
+ }
186
+ else {
187
+ registrationFailure = registrationRead;
188
+ diagnostics.push(outcomeDiagnostic(registrationRead, repository.root));
189
+ }
190
+ const health = overlayRegistration(rawHealth, registration, registrationFailure, identity.value);
191
+ return {
192
+ identity: identity.value,
193
+ rawHealth,
194
+ health,
195
+ registration,
196
+ registrationPath: codeRegistrationPath(repository.root, input.repositoryId),
197
+ excludedRoots,
198
+ access: repository.access,
199
+ diagnostics,
200
+ };
201
+ }
202
+ export class CodeIntelligenceService {
203
+ root;
204
+ constructor(root) {
205
+ this.root = root;
206
+ }
207
+ async status(input) {
208
+ const repositoryId = input?.repositoryId;
209
+ if (repositoryId === undefined) {
210
+ const health = fallbackHealth('unsupported', 'repository_required');
211
+ return {
212
+ ok: false,
213
+ identity: null,
214
+ health,
215
+ registrationPath: null,
216
+ registrationPresent: false,
217
+ diagnostics: [
218
+ createDiagnostic({
219
+ code: diagnosticCodes.code_repository_required,
220
+ severity: 'error',
221
+ message: 'code status requires an explicit repository id.',
222
+ source: this.root,
223
+ pointer: null,
224
+ hint: 'Pass --repo <id> from workspace.json.',
225
+ }),
226
+ ],
227
+ };
228
+ }
229
+ const observed = await observeCode({
230
+ root: this.root,
231
+ repositoryId,
232
+ ...(input?.signal === undefined ? {} : { signal: input.signal }),
233
+ });
234
+ return {
235
+ ok: observed.identity !== null && observed.health.state === 'ready',
236
+ identity: observed.identity,
237
+ health: observed.health,
238
+ registrationPath: observed.registrationPath,
239
+ registrationPresent: observed.registration !== null,
240
+ diagnostics: observed.diagnostics,
241
+ };
242
+ }
243
+ async planPrepare(input) {
244
+ const observed = await observeCode(input);
245
+ if (observed.identity === null) {
246
+ return {
247
+ observed,
248
+ plan: codePreparePlanSchema.parse({
249
+ schema: 'pappra/code-prepare-plan/1',
250
+ repositoryId: input.repositoryId,
251
+ identityDigest: `sha256:${'0'.repeat(64)}`,
252
+ action: 'none',
253
+ indexPath: this.root,
254
+ command: ['codegraph', 'status', '--json', this.root],
255
+ mutates: false,
256
+ reasons: ['identity_unavailable'],
257
+ }),
258
+ };
259
+ }
260
+ const provider = new CodeGraphProvider();
261
+ let plan = provider.plan(observed.identity, observed.rawHealth, input.rebuild);
262
+ if (observed.registration !== null &&
263
+ !registrationMatches(observed.registration, observed.identity) &&
264
+ plan.action === 'none' &&
265
+ !input.rebuild) {
266
+ const sameEngineAndCheckout = observed.registration.checkoutId === observed.identity.checkoutId &&
267
+ observed.registration.engineVersion ===
268
+ observed.identity.engine.version &&
269
+ observed.registration.configDigest ===
270
+ observed.identity.engine.configDigest;
271
+ plan = sameEngineAndCheckout
272
+ ? {
273
+ ...plan,
274
+ action: 'sync',
275
+ command: codeGraphPlanCommand('codegraph', 'sync', observed.identity.root),
276
+ mutates: true,
277
+ reasons: [
278
+ ...plan.reasons,
279
+ 'registration_working_tree_changed',
280
+ ].slice(0, 16),
281
+ }
282
+ : {
283
+ ...plan,
284
+ action: 'none',
285
+ command: codeGraphPlanCommand('codegraph', 'none', observed.identity.root),
286
+ mutates: false,
287
+ reasons: [
288
+ ...plan.reasons,
289
+ 'registration_identity_changed',
290
+ 'explicit_rebuild_required',
291
+ ].slice(0, 16),
292
+ };
293
+ }
294
+ return { observed, plan };
295
+ }
296
+ async prepare(input) {
297
+ const { observed, plan } = await this.planPrepare(input);
298
+ if (!input.apply) {
299
+ return {
300
+ schema: 'pappra/code-prepare-result/1',
301
+ ok: observed.identity !== null,
302
+ status: 'planned',
303
+ plan,
304
+ health: observed.health,
305
+ registrationPath: null,
306
+ diagnostics: [...observed.diagnostics],
307
+ };
308
+ }
309
+ if (observed.identity === null) {
310
+ return {
311
+ schema: 'pappra/code-prepare-result/1',
312
+ ok: false,
313
+ status: 'failed',
314
+ plan,
315
+ health: observed.health,
316
+ registrationPath: null,
317
+ diagnostics: [...observed.diagnostics],
318
+ };
319
+ }
320
+ if (plan.reasons.includes('explicit_rebuild_required')) {
321
+ return {
322
+ schema: 'pappra/code-prepare-result/1',
323
+ ok: false,
324
+ status: 'conflict',
325
+ plan,
326
+ health: observed.health,
327
+ registrationPath: null,
328
+ diagnostics: [...observed.diagnostics],
329
+ };
330
+ }
331
+ if (observed.access !== 'write') {
332
+ return {
333
+ schema: 'pappra/code-prepare-result/1',
334
+ ok: false,
335
+ status: 'conflict',
336
+ plan: {
337
+ ...plan,
338
+ action: 'none',
339
+ command: codeGraphPlanCommand('codegraph', 'none', observed.identity.root),
340
+ mutates: false,
341
+ reasons: [...plan.reasons, 'repository_read_only'].slice(0, 16),
342
+ },
343
+ health: observed.health,
344
+ registrationPath: null,
345
+ diagnostics: [...observed.diagnostics],
346
+ };
347
+ }
348
+ const registrationTarget = codeRegistrationPath(observed.identity.root, observed.identity.repositoryId);
349
+ for (const target of [plan.indexPath, registrationTarget]) {
350
+ const boundary = await ensureCodeMutationBoundary(observed.identity.root, target, observed.excludedRoots);
351
+ if (!boundary.ok) {
352
+ return {
353
+ schema: 'pappra/code-prepare-result/1',
354
+ ok: false,
355
+ status: 'conflict',
356
+ plan: {
357
+ ...plan,
358
+ action: 'none',
359
+ command: codeGraphPlanCommand('codegraph', 'none', observed.identity.root),
360
+ mutates: false,
361
+ reasons: [...plan.reasons, boundary.code].slice(0, 16),
362
+ },
363
+ health: observed.health,
364
+ registrationPath: null,
365
+ diagnostics: [
366
+ ...observed.diagnostics,
367
+ outcomeDiagnostic(boundary, target),
368
+ ],
369
+ };
370
+ }
371
+ }
372
+ const lock = await acquireCodePrepareLock(observed.identity.root, observed.excludedRoots);
373
+ if (!lock.ok) {
374
+ return {
375
+ schema: 'pappra/code-prepare-result/1',
376
+ ok: false,
377
+ status: 'conflict',
378
+ plan: {
379
+ ...plan,
380
+ action: 'none',
381
+ mutates: false,
382
+ command: codeGraphPlanCommand('codegraph', 'none', observed.identity.root),
383
+ },
384
+ health: observed.health,
385
+ registrationPath: null,
386
+ diagnostics: [
387
+ ...observed.diagnostics,
388
+ outcomeDiagnostic(lock, observed.identity.root),
389
+ ],
390
+ };
391
+ }
392
+ const perform = async () => {
393
+ const identity = observed.identity;
394
+ if (identity === null) {
395
+ throw new Error('Code identity disappeared before prepare');
396
+ }
397
+ const provider = new CodeGraphProvider();
398
+ const prepared = await provider.prepare(identity, plan, input.signal);
399
+ if (!prepared.ok) {
400
+ return {
401
+ schema: 'pappra/code-prepare-result/1',
402
+ ok: false,
403
+ status: 'failed',
404
+ plan,
405
+ health: fallbackHealth('failed', prepared.code),
406
+ registrationPath: null,
407
+ diagnostics: [
408
+ ...observed.diagnostics,
409
+ outcomeDiagnostic(prepared, identity.root),
410
+ ],
411
+ };
412
+ }
413
+ const afterVersion = await codeGraphVersion(input.signal);
414
+ const afterConfig = await observeCodeGraphConfig(identity.root);
415
+ if (!afterVersion.ok ||
416
+ !afterConfig.ok ||
417
+ afterConfig.value.status === 'unknown' ||
418
+ afterVersion.value !== identity.engine.version ||
419
+ afterConfig.value.digest !== identity.engine.configDigest) {
420
+ const reasons = [
421
+ ...prepared.value.reasons,
422
+ ...(afterConfig.ok && afterConfig.value.status === 'unknown'
423
+ ? ['engine_config_unknown']
424
+ : []),
425
+ 'engine_identity_changed_after_prepare',
426
+ ].slice(0, 32);
427
+ return {
428
+ schema: 'pappra/code-prepare-result/1',
429
+ ok: false,
430
+ status: 'partial',
431
+ plan,
432
+ health: { ...prepared.value, state: 'partial', reasons },
433
+ registrationPath: null,
434
+ diagnostics: [...observed.diagnostics],
435
+ };
436
+ }
437
+ const afterIdentity = await computeCodeIdentity({
438
+ repositoryId: identity.repositoryId,
439
+ root: identity.root,
440
+ engineVersion: afterVersion.value,
441
+ configDigest: afterConfig.value.digest,
442
+ configStatus: afterConfig.value.status,
443
+ excludedRoots: observed.excludedRoots,
444
+ ...(input.signal === undefined ? {} : { signal: input.signal }),
445
+ });
446
+ if (!afterIdentity.ok) {
447
+ return {
448
+ schema: 'pappra/code-prepare-result/1',
449
+ ok: false,
450
+ status: 'partial',
451
+ plan,
452
+ health: fallbackHealth('partial', afterIdentity.code),
453
+ registrationPath: null,
454
+ diagnostics: [
455
+ ...observed.diagnostics,
456
+ outcomeDiagnostic(afterIdentity, identity.root),
457
+ ],
458
+ };
459
+ }
460
+ if (codeIdentityDigest(afterIdentity.value) !== codeIdentityDigest(identity)) {
461
+ return {
462
+ schema: 'pappra/code-prepare-result/1',
463
+ ok: false,
464
+ status: 'partial',
465
+ plan,
466
+ health: {
467
+ ...prepared.value,
468
+ state: 'partial',
469
+ reasons: [
470
+ ...prepared.value.reasons,
471
+ 'source_changed_during_prepare',
472
+ ].slice(0, 32),
473
+ },
474
+ registrationPath: null,
475
+ diagnostics: [
476
+ ...observed.diagnostics,
477
+ createDiagnostic({
478
+ code: diagnosticCodes.code_identity_changed,
479
+ severity: 'warning',
480
+ message: 'Source identity changed while preparing the index; ready registration was not published.',
481
+ source: identity.root,
482
+ pointer: null,
483
+ hint: 'Repeat prepare after the working tree is stable.',
484
+ }),
485
+ ],
486
+ };
487
+ }
488
+ if (prepared.value.state !== 'ready') {
489
+ return {
490
+ schema: 'pappra/code-prepare-result/1',
491
+ ok: false,
492
+ status: prepared.value.state === 'failed' ? 'failed' : 'partial',
493
+ plan,
494
+ health: prepared.value,
495
+ registrationPath: null,
496
+ diagnostics: [...observed.diagnostics],
497
+ };
498
+ }
499
+ const registration = {
500
+ schema: 'pappra/code-index-registration/1',
501
+ repositoryId: afterIdentity.value.repositoryId,
502
+ identityDigest: codeIdentityDigest(afterIdentity.value),
503
+ checkoutId: afterIdentity.value.checkoutId,
504
+ root: afterIdentity.value.root,
505
+ engineVersion: afterIdentity.value.engine.version,
506
+ configDigest: afterIdentity.value.engine.configDigest,
507
+ preparedAt: new Date().toISOString(),
508
+ coverage: prepared.value.coverage,
509
+ };
510
+ const written = await writeCodeRegistration(afterIdentity.value.root, registration, observed.excludedRoots);
511
+ if (!written.ok) {
512
+ return {
513
+ schema: 'pappra/code-prepare-result/1',
514
+ ok: false,
515
+ status: 'partial',
516
+ plan,
517
+ health: {
518
+ ...prepared.value,
519
+ state: 'partial',
520
+ reasons: [
521
+ ...prepared.value.reasons,
522
+ 'registration_write_failed',
523
+ ].slice(0, 32),
524
+ },
525
+ registrationPath: null,
526
+ diagnostics: [
527
+ ...observed.diagnostics,
528
+ outcomeDiagnostic(written, identity.root),
529
+ ],
530
+ };
531
+ }
532
+ return {
533
+ schema: 'pappra/code-prepare-result/1',
534
+ ok: true,
535
+ status: 'ready',
536
+ plan,
537
+ health: prepared.value,
538
+ registrationPath: written.value,
539
+ diagnostics: [...observed.diagnostics],
540
+ };
541
+ };
542
+ let result;
543
+ try {
544
+ result = await perform();
545
+ }
546
+ catch (error) {
547
+ await releaseCodePrepareLock(lock.value);
548
+ throw error;
549
+ }
550
+ const released = await releaseCodePrepareLock(lock.value);
551
+ if (released.ok)
552
+ return result;
553
+ return {
554
+ ...result,
555
+ ok: false,
556
+ status: result.ok ? 'partial' : result.status,
557
+ diagnostics: [
558
+ ...result.diagnostics,
559
+ outcomeDiagnostic(released, lock.value),
560
+ ],
561
+ };
562
+ }
563
+ async query(input) {
564
+ const limits = codeQueryLimitsSchema.parse({
565
+ maxResults: input.limits?.maxResults ?? 20,
566
+ maxBytes: input.limits?.maxBytes ?? 1024 * 1024,
567
+ maxFiles: input.limits?.maxFiles ?? 1000,
568
+ });
569
+ const observed = await observeCode(input);
570
+ if (observed.identity === null) {
571
+ return {
572
+ ok: false,
573
+ result: null,
574
+ health: observed.health,
575
+ diagnostics: [...observed.diagnostics],
576
+ };
577
+ }
578
+ const request = codeQueryRequestSchema.parse({
579
+ schema: 'pappra/code-query/1',
580
+ kind: input.kind,
581
+ query: input.query,
582
+ identity: observed.identity,
583
+ limits,
584
+ excludedRoots: observed.excludedRoots,
585
+ });
586
+ const provider = new CodeGraphProvider();
587
+ let result;
588
+ if (input.kind === 'text') {
589
+ result = await runTextQuery(request, 'text', input.signal);
590
+ }
591
+ else if (observed.health.state === 'ready') {
592
+ result = await provider.query(request, input.signal);
593
+ }
594
+ else if (input.kind === 'symbol') {
595
+ result = await runTextQuery(request, 'structure', input.signal);
596
+ }
597
+ else {
598
+ result = succeeded({
599
+ schema: 'pappra/code-query-result/1',
600
+ provider: 'text',
601
+ kind: input.kind,
602
+ query: input.query,
603
+ identityDigest: codeIdentityDigest(observed.identity),
604
+ observedIdentity: observed.identity,
605
+ coverage: 'unsupported',
606
+ items: [],
607
+ bytes: 0,
608
+ truncated: false,
609
+ reasons: [...observed.health.reasons, 'index_not_ready'],
610
+ evidence: observed.health.evidence,
611
+ unsupportedReason: 'The selected code index is not ready; only text or structure fallback is available.',
612
+ });
613
+ }
614
+ if (!result.ok) {
615
+ return {
616
+ ok: false,
617
+ result: null,
618
+ health: observed.health,
619
+ diagnostics: [
620
+ ...observed.diagnostics,
621
+ outcomeDiagnostic(result, observed.identity.root),
622
+ ],
623
+ };
624
+ }
625
+ return {
626
+ ok: result.value.coverage !== 'unsupported',
627
+ result: result.value,
628
+ health: observed.health,
629
+ diagnostics: [...observed.diagnostics],
630
+ };
631
+ }
632
+ }
633
+ export { codeIdentityDigest };
@@ -0,0 +1,3 @@
1
+ import { type Outcome } from '../schemas/outcome.js';
2
+ import type { CodeQueryRequest, CodeQueryResult } from '../schemas/code.js';
3
+ export declare function runTextQuery(request: CodeQueryRequest, mode: 'text' | 'structure', signal?: AbortSignal): Promise<Outcome<CodeQueryResult>>;