@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
@@ -0,0 +1,669 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { fingerprintSkill } from '../../collab/fingerprint.js';
4
+ import { nowIso } from '../../collab/store.js';
5
+ import { argumentStrings, assertTemplateIdentity, deriveOutcome, evidenceRecords, fail, fingerprintTemplateSkill, isTimestamp, MAX_EVENTS, parseExecution, piTimestamp, readNativeEvidence, record, samePath, } from './shared.js';
6
+ /**
7
+ * The observation time is the native session's own last usable timestamp. A
8
+ * message-level value that is missing or unusable falls back to that record's
9
+ * own timestamp; the adapter never substitutes its own clock, so replaying old
10
+ * evidence cannot make it look fresh.
11
+ */
12
+ function nativeObservationTime(records) {
13
+ const stamps = [];
14
+ for (const row of records) {
15
+ const message = record(row.message) ? row.message : null;
16
+ const candidates = row.type === 'message'
17
+ ? [message?.timestamp, row.timestamp]
18
+ : [row.timestamp];
19
+ let millis = null;
20
+ for (const candidate of candidates) {
21
+ millis = piTimestamp(candidate);
22
+ if (millis !== null)
23
+ break;
24
+ }
25
+ if (millis !== null)
26
+ stamps.push(millis);
27
+ }
28
+ if (!stamps.length)
29
+ fail('no_native_observation_time');
30
+ return nowIso(stamps[stamps.length - 1]);
31
+ }
32
+ export function readPiExecution(options) {
33
+ const sessionBytes = readNativeEvidence(options.sessionFile);
34
+ if (options.live && options.executionFile)
35
+ fail('live_execution_conflict');
36
+ if (!options.live && !options.executionFile)
37
+ fail('execution_required');
38
+ const executionBytes = options.executionFile
39
+ ? readNativeEvidence(options.executionFile)
40
+ : null;
41
+ let records;
42
+ let execution;
43
+ try {
44
+ const lines = sessionBytes.text
45
+ .split('\n')
46
+ .filter((line) => line.trim().length);
47
+ if (lines.length > MAX_EVENTS)
48
+ fail('event_limit');
49
+ records = lines.map((line) => {
50
+ const value = JSON.parse(line);
51
+ if (!record(value))
52
+ fail('unsupported_event_shape');
53
+ return value;
54
+ });
55
+ execution =
56
+ executionBytes === null
57
+ ? { status: 'observed', mode: 'live-session-snapshot' }
58
+ : parseExecution(executionBytes.text);
59
+ }
60
+ catch {
61
+ fail('invalid_native_json');
62
+ }
63
+ if (!options.live &&
64
+ (execution.status !== 'exited' || execution.exit_code !== 0))
65
+ fail('native_process_not_successfully_exited');
66
+ if (!options.live &&
67
+ (!isTimestamp(execution.started_at) ||
68
+ !isTimestamp(execution.finished_at) ||
69
+ Date.parse(execution.finished_at) <
70
+ Date.parse(execution.started_at)))
71
+ fail('invalid_execution_clock');
72
+ if (execution.native_evidence &&
73
+ !samePath(execution.native_evidence, options.sessionFile))
74
+ fail('execution_evidence_mismatch');
75
+ if (records.some((row) => !record(row) || typeof row.type !== 'string'))
76
+ fail('unsupported_event_shape');
77
+ const sessions = records.filter((row) => row.type === 'session');
78
+ if (sessions.length !== 1 || records[0] !== sessions[0])
79
+ fail('ambiguous_native_lifecycle');
80
+ const session = sessions[0];
81
+ if (session.id !== options.sessionId)
82
+ fail('native_identity_mismatch');
83
+ if (typeof session.cwd !== 'string' || !samePath(session.cwd, options.cwd))
84
+ fail('native_cwd_mismatch');
85
+ const calls = new Map();
86
+ const results = new Map();
87
+ const assistantTurns = [];
88
+ for (const row of records) {
89
+ if (row.type !== 'message')
90
+ continue;
91
+ const message = record(row.message)
92
+ ? row.message
93
+ : fail('unsupported_message_shape');
94
+ if (typeof message.role !== 'string')
95
+ fail('unsupported_message_shape');
96
+ const content = message.content;
97
+ if (!Array.isArray(content)) {
98
+ // Only the system prompt record carries plain text in the observed shape.
99
+ if (message.role !== 'system' || typeof content !== 'string')
100
+ fail('unsupported_message_shape');
101
+ continue;
102
+ }
103
+ if (message.role === 'assistant') {
104
+ assistantTurns.push({
105
+ model: message.model ?? null,
106
+ provider: message.provider ?? null,
107
+ stop_reason: message.stopReason ?? null,
108
+ usage: message.usage ?? null,
109
+ timestamp: message.timestamp ?? row.timestamp ?? null,
110
+ });
111
+ }
112
+ for (const part of content) {
113
+ if (!record(part))
114
+ continue;
115
+ if (part.type === 'toolCall') {
116
+ if (message.role !== 'assistant' ||
117
+ typeof part.id !== 'string' ||
118
+ typeof part.name !== 'string' ||
119
+ calls.has(part.id))
120
+ fail('unsupported_tool_call');
121
+ calls.set(part.id, {
122
+ id: part.id,
123
+ name: part.name,
124
+ arguments: part.arguments ?? {},
125
+ at: row.timestamp,
126
+ });
127
+ }
128
+ }
129
+ if (message.role === 'toolResult') {
130
+ if (typeof message.toolCallId !== 'string' ||
131
+ !calls.has(message.toolCallId) ||
132
+ results.has(message.toolCallId) ||
133
+ message.toolName !== calls.get(message.toolCallId)?.name ||
134
+ typeof message.isError !== 'boolean')
135
+ fail('unsupported_tool_result');
136
+ results.set(message.toolCallId, {
137
+ isError: message.isError,
138
+ at: message.timestamp ?? row.timestamp,
139
+ toolName: message.toolName,
140
+ });
141
+ }
142
+ }
143
+ if ([...calls.keys()].some((id) => !results.has(id)))
144
+ fail('incomplete_tool_results');
145
+ if (!assistantTurns.length)
146
+ fail('no_assistant_turn');
147
+ const lastTurn = assistantTurns[assistantTurns.length - 1];
148
+ // A turn that ended while a tool call was still outstanding is an
149
+ // indeterminate lifecycle, not a completed observation.
150
+ if (lastTurn.stop_reason === 'toolUse')
151
+ fail('indeterminate_turn_end');
152
+ if (options.live) {
153
+ if (typeof lastTurn.model !== 'string' ||
154
+ !lastTurn.model ||
155
+ typeof lastTurn.provider !== 'string' ||
156
+ !lastTurn.provider)
157
+ fail('live_model_observation_missing');
158
+ const lastMessage = records.filter((row) => row.type === 'message').at(-1);
159
+ if (!record(lastMessage?.message) ||
160
+ lastMessage.message.role !== 'assistant' ||
161
+ lastTurn.stop_reason !== 'stop')
162
+ fail('live_session_not_settled');
163
+ // A later model change invalidates the old runtime observation; do not
164
+ // present capabilities observed on the previous model as the new runtime.
165
+ const lastIndex = records.lastIndexOf(lastMessage);
166
+ if (records.slice(lastIndex + 1).some((row) => row.type === 'model_change'))
167
+ fail('live_model_changed_since_observation');
168
+ }
169
+ return {
170
+ records,
171
+ execution,
172
+ session,
173
+ calls,
174
+ results,
175
+ assistantTurns,
176
+ lastTurn,
177
+ evidenceRecords: executionBytes === null
178
+ ? [{ ref: options.sessionFile, digest: sessionBytes.digest }]
179
+ : evidenceRecords(sessionBytes, options.sessionFile, executionBytes, options.executionFile),
180
+ };
181
+ }
182
+ export function derivePiCard(options) {
183
+ return deriveOutcome(options.assignment, options.template, () => {
184
+ assertTemplateIdentity(options.assignment, options.template, 'pi');
185
+ const native = readPiExecution({
186
+ sessionFile: options.sessionFile,
187
+ executionFile: options.executionFile ?? null,
188
+ live: options.live ?? false,
189
+ sessionId: options.template.session_id,
190
+ cwd: options.template.cwd,
191
+ });
192
+ const successful = (name) => [...native.calls.values()].some((call) => call.name === name && native.results.get(call.id)?.isError === false);
193
+ // Pi loads a skill by reading its SKILL.md. Only an actual successful `read`
194
+ // of that entry counts: a path in a write argument or shell string does not.
195
+ const loadedSkillEntry = (file, cwd) => [...native.calls.values()].some((call) => {
196
+ if (call.name !== 'read')
197
+ return false;
198
+ if (native.results.get(call.id)?.isError !== false)
199
+ return false;
200
+ return argumentStrings(call.arguments).some((candidate) => {
201
+ if (candidate === file)
202
+ return true;
203
+ const resolved = path.isAbsolute(candidate)
204
+ ? candidate
205
+ : path.resolve(cwd, candidate);
206
+ return samePath(resolved, file);
207
+ });
208
+ });
209
+ const card = structuredClone(options.template);
210
+ card.evidence_level = 'runtime';
211
+ card.observed_at = nativeObservationTime(options.live
212
+ ? native.records.filter((row) => row.type === 'message')
213
+ : native.records);
214
+ card.evidence_records = native.evidenceRecords;
215
+ card.native_observation = {
216
+ source: 'pi-session-jsonl',
217
+ observation_mode: options.live
218
+ ? 'live-session-snapshot'
219
+ : 'exited-process',
220
+ launcher_clock: options.live
221
+ ? null
222
+ : {
223
+ started_at: native.execution.started_at,
224
+ finished_at: native.execution.finished_at,
225
+ },
226
+ session_id: native.session.id,
227
+ cwd: native.session.cwd,
228
+ pi_version: native.session.version ?? null,
229
+ phase: native.execution.phase ?? null,
230
+ tool_allowlist: native.execution.tool_allowlist ?? null,
231
+ tools_observed: [
232
+ ...new Set([...native.calls.values()].map((call) => call.name)),
233
+ ].sort(),
234
+ project_trust: native.execution.project_trust ?? null,
235
+ model: native.lastTurn.model,
236
+ provider: native.lastTurn.provider,
237
+ stop_reason: native.lastTurn.stop_reason,
238
+ usage: native.lastTurn.usage,
239
+ assistant_turns: native.assistantTurns.length,
240
+ // Cost is not reported by the Pi session record; it is accounted for separately.
241
+ cost: { reported_usd: null, source: 'not_reported_by_pi_session_record' },
242
+ };
243
+ card.tools = card.tools.map((tool) => {
244
+ const verified = successful(tool.id);
245
+ const next = { ...tool, state: verified ? 'verified' : 'unknown' };
246
+ if (verified)
247
+ next.evidence_ref = options.sessionFile;
248
+ return next;
249
+ });
250
+ card.skills = card.skills.map((skill) => {
251
+ const snapshot = fingerprintTemplateSkill(skill);
252
+ const loaded = loadedSkillEntry(snapshot.entry, options.template.cwd);
253
+ const next = {
254
+ ...skill,
255
+ state: loaded ? 'verified' : 'unknown',
256
+ };
257
+ if (loaded)
258
+ next.evidence_ref = options.sessionFile;
259
+ return next;
260
+ });
261
+ return {
262
+ card,
263
+ ...(options.live
264
+ ? {
265
+ limitations: [
266
+ 'live_snapshot_does_not_prove_process_state_or_queue_approval_inventory',
267
+ 'capabilities_observed_in_saved_session_not_current_tool_registration',
268
+ ],
269
+ }
270
+ : {}),
271
+ };
272
+ });
273
+ }
274
+ const PI_MANAGED_SESSION_SCHEMA = 'harness-collab/pi-managed-session/1';
275
+ const PI_SDK_PACKAGE = '@earendil-works/pi-coding-agent';
276
+ const PI_SDK_VERSION = '1.4.0';
277
+ function startupRecords(text) {
278
+ const lines = text.split('\n').filter((line) => line.trim().length > 0);
279
+ if (lines.length > MAX_EVENTS)
280
+ fail('event_limit');
281
+ try {
282
+ return lines.map((line) => {
283
+ const value = JSON.parse(line);
284
+ if (!record(value))
285
+ fail('unsupported_event_shape');
286
+ return value;
287
+ });
288
+ }
289
+ catch {
290
+ return fail('invalid_native_json');
291
+ }
292
+ }
293
+ function startupNames(value) {
294
+ if (!Array.isArray(value) ||
295
+ !value.every((item) => typeof item === 'string' && item.length > 0))
296
+ fail('startup_tool_inventory_invalid');
297
+ const names = value;
298
+ if (new Set(names).size !== names.length)
299
+ fail('startup_tool_inventory_duplicate');
300
+ return [...names];
301
+ }
302
+ function startupCount(value) {
303
+ return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0;
304
+ }
305
+ function sameObservedPath(left, right) {
306
+ return path.resolve(left) === path.resolve(right) || samePath(left, right);
307
+ }
308
+ function assertNativeHeader(header, sessionId, cwd) {
309
+ if ((header.type !== undefined && header.type !== 'session') ||
310
+ header.id !== sessionId ||
311
+ typeof header.cwd !== 'string' ||
312
+ !samePath(header.cwd, cwd))
313
+ fail('native_header_identity_mismatch');
314
+ }
315
+ /** Derive startup availability from the native SDK observation, never from model settlement. */
316
+ export function derivePiStartupCard(options) {
317
+ return deriveOutcome(options.assignment, options.template, () => {
318
+ assertTemplateIdentity(options.assignment, options.template, 'pi');
319
+ if (options.template.session_id !== options.sessionId ||
320
+ !samePath(options.template.cwd, options.cwd))
321
+ fail('startup_native_identity_mismatch');
322
+ const metadata = readNativeEvidence(options.metadataFile);
323
+ const sidecar = startupRecords(metadata.text);
324
+ const starts = sidecar.filter((row) => row.type === 'session_start');
325
+ if (starts.length !== 1)
326
+ fail('startup_session_start_missing_or_ambiguous');
327
+ const started = starts[0];
328
+ if (started.schema !== PI_MANAGED_SESSION_SCHEMA ||
329
+ started.session_id !== options.sessionId ||
330
+ typeof started.cwd !== 'string' ||
331
+ !samePath(started.cwd, options.cwd) ||
332
+ !isTimestamp(started.at) ||
333
+ !(started.session_file === null ||
334
+ typeof started.session_file === 'string'))
335
+ fail('startup_session_start_identity_mismatch');
336
+ // Resource reloads/tool-selection updates append new sidecar observations. The
337
+ // latest one is authoritative; a stale or foreign latest row never falls back.
338
+ const ready = sidecar
339
+ .filter((row) => row.type === 'resources_ready')
340
+ .at(-1);
341
+ if (!ready)
342
+ fail('native_resources_ready_missing');
343
+ const payload = ready;
344
+ if (payload.schema !== PI_MANAGED_SESSION_SCHEMA ||
345
+ payload.type !== 'resources_ready' ||
346
+ payload.phase !== 'interactive_mode_init_complete' ||
347
+ !isTimestamp(payload.at) ||
348
+ Date.parse(payload.at) < Date.parse(started.at) ||
349
+ payload.session_id !== options.sessionId ||
350
+ typeof payload.cwd !== 'string' ||
351
+ !samePath(payload.cwd, options.cwd))
352
+ fail('native_resources_ready_identity_mismatch');
353
+ const nativeHeader = payload.native_header;
354
+ if (!record(nativeHeader))
355
+ fail('startup_native_header_missing');
356
+ assertNativeHeader(nativeHeader, options.sessionId, options.cwd);
357
+ const reportedFile = payload.native_session_file;
358
+ if (!(reportedFile === null || typeof reportedFile === 'string'))
359
+ fail('startup_native_session_file_invalid');
360
+ const startedFile = typeof started.session_file === 'string' ? started.session_file : null;
361
+ if ((reportedFile !== null && !path.isAbsolute(reportedFile)) ||
362
+ (startedFile !== null && !path.isAbsolute(startedFile)))
363
+ fail('startup_native_session_file_invalid');
364
+ if (reportedFile !== null &&
365
+ startedFile !== null &&
366
+ !sameObservedPath(reportedFile, startedFile))
367
+ fail('startup_native_session_file_mismatch');
368
+ const sessionFile = reportedFile ?? startedFile;
369
+ let sessionEvidence = null;
370
+ if (sessionFile !== null) {
371
+ let stat;
372
+ try {
373
+ stat = fs.lstatSync(sessionFile);
374
+ }
375
+ catch (error) {
376
+ const code = typeof error === 'object' && error !== null && 'code' in error
377
+ ? String(error.code)
378
+ : null;
379
+ if (code !== 'ENOENT')
380
+ fail('native_evidence_unavailable');
381
+ }
382
+ if (stat) {
383
+ if (!stat.isFile() || stat.isSymbolicLink())
384
+ fail('unsupported_evidence_file');
385
+ sessionEvidence = readNativeEvidence(sessionFile);
386
+ const nativeRows = startupRecords(sessionEvidence.text);
387
+ const headers = nativeRows.filter((row) => row.type === 'session');
388
+ if (headers.length !== 1 || nativeRows[0] !== headers[0])
389
+ fail('ambiguous_native_lifecycle');
390
+ assertNativeHeader(headers[0], options.sessionId, options.cwd);
391
+ for (const key of ['timestamp', 'version']) {
392
+ if (nativeHeader[key] !== undefined &&
393
+ headers[0][key] !== undefined &&
394
+ nativeHeader[key] !== headers[0][key])
395
+ fail('native_header_mismatch');
396
+ }
397
+ }
398
+ }
399
+ const sdk = payload.sdk;
400
+ if (!record(sdk) ||
401
+ sdk.package !== PI_SDK_PACKAGE ||
402
+ sdk.version !== PI_SDK_VERSION)
403
+ fail('unsupported_native_sdk');
404
+ const nativeIdentity = payload.native_identity;
405
+ if (!record(nativeIdentity))
406
+ fail('startup_native_identity_missing');
407
+ for (const key of [
408
+ 'agent_id',
409
+ 'harness',
410
+ 'surface',
411
+ 'configuration_id',
412
+ ]) {
413
+ if (typeof nativeIdentity[key] !== 'string' ||
414
+ nativeIdentity[key] !== options.template[key])
415
+ fail('startup_native_identity_mismatch');
416
+ }
417
+ if (nativeIdentity.harness !== 'pi')
418
+ fail('unsupported_harness');
419
+ const model = payload.model;
420
+ if (!record(model) ||
421
+ typeof model.provider !== 'string' ||
422
+ model.provider.length === 0 ||
423
+ typeof model.id !== 'string' ||
424
+ model.id.length === 0 ||
425
+ !(model.thinking_level === null ||
426
+ typeof model.thinking_level === 'string'))
427
+ fail('startup_model_observation_missing');
428
+ if ((options.expectedProvider !== undefined &&
429
+ model.provider !== options.expectedProvider) ||
430
+ (options.expectedModel !== undefined &&
431
+ model.id !== options.expectedModel))
432
+ fail('startup_model_identity_mismatch');
433
+ const configuration = payload.configuration;
434
+ if (!record(configuration) ||
435
+ configuration.configuration_id !== nativeIdentity.configuration_id)
436
+ fail('startup_configuration_identity_mismatch');
437
+ if (configuration.project_trusted !== true)
438
+ fail('startup_project_trust_unresolved');
439
+ const inventory = payload.resource_inventory;
440
+ if (!record(inventory) ||
441
+ inventory.completeness !== 'complete' ||
442
+ inventory.source !== 'pi_1_4_runtime_apis')
443
+ fail('startup_resource_inventory_incomplete');
444
+ const tools = inventory.tools;
445
+ if (!record(tools))
446
+ fail('startup_tool_inventory_invalid');
447
+ const allToolNames = startupNames(tools.all_names);
448
+ const activeToolNames = startupNames(tools.active_names);
449
+ const allToolSet = new Set(allToolNames);
450
+ if (activeToolNames.some((name) => !allToolSet.has(name)))
451
+ fail('startup_active_tool_not_registered');
452
+ if (!Array.isArray(inventory.skills) ||
453
+ inventory.skills.length > MAX_EVENTS)
454
+ fail('startup_skill_inventory_invalid');
455
+ const observedSkills = [];
456
+ const skillNames = new Set();
457
+ const skillEntries = new Set();
458
+ for (const item of inventory.skills) {
459
+ if (!record(item) ||
460
+ typeof item.name !== 'string' ||
461
+ item.name.length === 0 ||
462
+ typeof item.entry !== 'string' ||
463
+ !path.isAbsolute(item.entry) ||
464
+ path.basename(item.entry) !== 'SKILL.md' ||
465
+ item.availability !== 'available' ||
466
+ item.body_loaded !== 'not_observed')
467
+ fail('startup_skill_inventory_unresolved');
468
+ if (skillNames.has(item.name))
469
+ fail('startup_skill_inventory_duplicate');
470
+ let fingerprint;
471
+ try {
472
+ fingerprint = fingerprintSkill(item.entry);
473
+ }
474
+ catch {
475
+ fail('startup_skill_files_unavailable');
476
+ }
477
+ if (!samePath(fingerprint.path, item.entry))
478
+ fail('startup_skill_entry_mismatch');
479
+ const canonicalEntry = path.resolve(fingerprint.path);
480
+ if (skillEntries.has(canonicalEntry))
481
+ fail('startup_skill_inventory_duplicate');
482
+ skillNames.add(item.name);
483
+ skillEntries.add(canonicalEntry);
484
+ observedSkills.push({
485
+ name: item.name,
486
+ entry: fingerprint.path,
487
+ bundleDigest: fingerprint.bundle_digest,
488
+ });
489
+ }
490
+ const runtime = payload.owned_runtime;
491
+ if (!record(runtime) ||
492
+ runtime.scope !== 'pinned_pi_1_4_owned_runtime' ||
493
+ runtime.queues_completeness !== 'complete' ||
494
+ !startupCount(runtime.pending_message_count) ||
495
+ runtime.work_observation !== 'complete' ||
496
+ typeof runtime.is_idle !== 'boolean' ||
497
+ typeof runtime.is_streaming !== 'boolean' ||
498
+ typeof runtime.is_compacting !== 'boolean' ||
499
+ typeof runtime.is_bash_running !== 'boolean' ||
500
+ typeof runtime.has_pending_bash_messages !== 'boolean' ||
501
+ !startupCount(runtime.pending_tool_calls) ||
502
+ runtime.extension_dialogs_completeness !== 'complete' ||
503
+ !startupCount(runtime.pending_extension_dialogs) ||
504
+ runtime.built_in_ui_approvals_observation !== 'complete' ||
505
+ !Array.isArray(runtime.uncovered_approval_paths) ||
506
+ !runtime.uncovered_approval_paths.every((item) => typeof item === 'string'))
507
+ fail('startup_owned_runtime_inventory_incomplete');
508
+ if (runtime.pending_message_count !== 0 ||
509
+ runtime.is_idle !== true ||
510
+ runtime.is_streaming !== false ||
511
+ runtime.is_compacting !== false ||
512
+ runtime.is_bash_running !== false ||
513
+ runtime.has_pending_bash_messages !== false ||
514
+ runtime.pending_tool_calls !== 0)
515
+ fail('startup_owned_runtime_work_pending');
516
+ if (runtime.pending_extension_dialogs !== 0 ||
517
+ runtime.uncovered_approval_paths.length !== 0)
518
+ fail('startup_approval_unresolved');
519
+ const activeToolSet = new Set(activeToolNames);
520
+ const toolsById = new Map();
521
+ for (const capability of options.template.tools) {
522
+ const { evidence_ref: _evidenceRef, ...declared } = capability;
523
+ const state = activeToolSet.has(capability.id)
524
+ ? 'callable'
525
+ : allToolSet.has(capability.id)
526
+ ? 'disabled'
527
+ : 'unknown';
528
+ toolsById.set(capability.id, {
529
+ ...declared,
530
+ state,
531
+ ...(state === 'callable' ? { evidence_ref: options.metadataFile } : {}),
532
+ });
533
+ }
534
+ for (const name of allToolNames) {
535
+ if (toolsById.has(name))
536
+ continue;
537
+ const state = activeToolSet.has(name) ? 'callable' : 'disabled';
538
+ toolsById.set(name, {
539
+ id: name,
540
+ state,
541
+ ...(state === 'callable' ? { evidence_ref: options.metadataFile } : {}),
542
+ });
543
+ }
544
+ const skillsById = new Map();
545
+ const consumedSkills = new Set();
546
+ for (const capability of options.template.skills) {
547
+ const snapshot = fingerprintTemplateSkill(capability);
548
+ const nativeNameValue = capability.native_name;
549
+ const nativeName = typeof nativeNameValue === 'string' ? nativeNameValue : capability.id;
550
+ const observed = observedSkills.find((skill) => skill.name === nativeName);
551
+ if (observed) {
552
+ if (!samePath(snapshot.entry, observed.entry) ||
553
+ snapshot.bundleDigest !== observed.bundleDigest)
554
+ fail('startup_skill_identity_mismatch');
555
+ consumedSkills.add(observed.name);
556
+ }
557
+ const { evidence_ref: _evidenceRef, ...declared } = capability;
558
+ skillsById.set(capability.id, {
559
+ ...declared,
560
+ state: observed ? 'callable' : 'unknown',
561
+ ...(observed ? { evidence_ref: options.metadataFile } : {}),
562
+ });
563
+ }
564
+ for (const skill of observedSkills) {
565
+ if (consumedSkills.has(skill.name))
566
+ continue;
567
+ if (skillsById.has(skill.name))
568
+ fail('startup_skill_identity_mismatch');
569
+ skillsById.set(skill.name, {
570
+ id: skill.name,
571
+ state: 'callable',
572
+ path: skill.entry,
573
+ bundle_digest: skill.bundleDigest,
574
+ evidence_ref: options.metadataFile,
575
+ });
576
+ }
577
+ const card = structuredClone(options.template);
578
+ card.evidence_level = 'runtime';
579
+ card.observed_at = payload.at;
580
+ card.evidence_records = [
581
+ { ref: options.metadataFile, digest: metadata.digest },
582
+ ...(sessionEvidence && sessionFile
583
+ ? [{ ref: sessionFile, digest: sessionEvidence.digest }]
584
+ : []),
585
+ ];
586
+ card.native_observation = {
587
+ source: 'pi-managed-resources-ready-sidecar',
588
+ observation_mode: 'startup-resource-inventory',
589
+ session_id: options.sessionId,
590
+ cwd: options.cwd,
591
+ session_file: sessionFile,
592
+ native_header: {
593
+ id: nativeHeader.id,
594
+ cwd: nativeHeader.cwd,
595
+ ...(nativeHeader.timestamp === undefined
596
+ ? {}
597
+ : { timestamp: nativeHeader.timestamp }),
598
+ ...(nativeHeader.version === undefined
599
+ ? {}
600
+ : { version: nativeHeader.version }),
601
+ },
602
+ sdk: { package: PI_SDK_PACKAGE, version: PI_SDK_VERSION },
603
+ model: {
604
+ provider: model.provider,
605
+ id: model.id,
606
+ thinking_level: model.thinking_level,
607
+ },
608
+ native_identity: {
609
+ agent_id: nativeIdentity.agent_id,
610
+ harness: nativeIdentity.harness,
611
+ surface: nativeIdentity.surface,
612
+ configuration_id: nativeIdentity.configuration_id,
613
+ },
614
+ configuration: {
615
+ configuration_id: configuration.configuration_id,
616
+ project_trusted: configuration.project_trusted,
617
+ },
618
+ resource_inventory: {
619
+ completeness: 'complete',
620
+ source: 'pi_1_4_runtime_apis',
621
+ tools: {
622
+ all_names: [...allToolNames].sort(),
623
+ active_names: [...activeToolNames].sort(),
624
+ },
625
+ skills: [...observedSkills]
626
+ .sort((left, right) => left.name.localeCompare(right.name))
627
+ .map((skill) => ({
628
+ name: skill.name,
629
+ entry: skill.entry,
630
+ bundle_digest: skill.bundleDigest,
631
+ availability: 'available',
632
+ body_loaded: 'not_observed',
633
+ })),
634
+ },
635
+ owned_runtime: {
636
+ scope: runtime.scope,
637
+ queues_completeness: runtime.queues_completeness,
638
+ pending_message_count: runtime.pending_message_count,
639
+ work_observation: runtime.work_observation,
640
+ is_idle: runtime.is_idle,
641
+ is_streaming: runtime.is_streaming,
642
+ is_compacting: runtime.is_compacting,
643
+ is_bash_running: runtime.is_bash_running,
644
+ has_pending_bash_messages: runtime.has_pending_bash_messages,
645
+ pending_tool_calls: runtime.pending_tool_calls,
646
+ extension_dialogs_completeness: runtime.extension_dialogs_completeness,
647
+ pending_extension_dialogs: runtime.pending_extension_dialogs,
648
+ built_in_ui_approvals_observation: runtime.built_in_ui_approvals_observation,
649
+ uncovered_approval_paths: runtime.uncovered_approval_paths,
650
+ },
651
+ limitations: [
652
+ 'tool_execution_not_observed',
653
+ 'skill_body_loading_not_observed',
654
+ 'startup_resource_metadata_not_cryptographically_authenticated',
655
+ ...(sessionEvidence ? [] : ['native_transcript_not_yet_persisted']),
656
+ ],
657
+ };
658
+ card.tools = [...toolsById.values()];
659
+ card.skills = [...skillsById.values()];
660
+ return {
661
+ card,
662
+ limitations: [
663
+ 'tool_execution_not_observed',
664
+ 'skill_body_loading_not_observed',
665
+ ...(sessionEvidence ? [] : ['native_transcript_not_yet_persisted']),
666
+ ],
667
+ };
668
+ });
669
+ }