@open-agent-toolkit/cli 0.2.65 → 0.2.67

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 (238) hide show
  1. package/assets/bundle-metadata.json +1 -1
  2. package/assets/docs/cli-utilities/configuration.md +33 -2
  3. package/assets/docs/cli-utilities/index.md +3 -0
  4. package/assets/docs/cli-utilities/project-log.md +63 -4
  5. package/assets/docs/cli-utilities/remote-project-management.md +191 -0
  6. package/assets/docs/contributing/code.md +8 -4
  7. package/assets/docs/contributing/skills.md +29 -17
  8. package/assets/docs/docs-tooling/commands.md +3 -1
  9. package/assets/docs/provider-sync/manifest-and-drift.md +2 -18
  10. package/assets/docs/reference/cli-reference.md +12 -1
  11. package/assets/docs/reference/file-locations.md +22 -0
  12. package/assets/docs/reference/oat-directory-structure.md +30 -17
  13. package/assets/docs/reference/troubleshooting.md +44 -0
  14. package/assets/docs/workflows/projects/lifecycle.md +17 -0
  15. package/assets/docs/workflows/projects/picking-up-projects.md +18 -0
  16. package/assets/docs/workflows/skills/index.md +33 -0
  17. package/assets/docs/workflows/skills/repo-improve.md +7 -3
  18. package/assets/public-package-versions.json +4 -4
  19. package/assets/skills/create-agnostic-skill/SKILL.md +19 -37
  20. package/assets/skills/create-agnostic-skill/references/docs/skills-guide.md +58 -15
  21. package/assets/skills/create-agnostic-skill/references/skill-template.md +17 -15
  22. package/assets/skills/oat-agent-instructions-apply/SKILL.md +1 -1
  23. package/assets/skills/oat-agent-instructions-apply/references/instruction-file-templates/glob-scoped-rule.md +1 -4
  24. package/assets/skills/oat-doctor/SKILL.md +3 -6
  25. package/assets/skills/oat-pjm-remote/SKILL.md +101 -0
  26. package/assets/skills/oat-pjm-remote/references/external-action-protocol.md +43 -0
  27. package/assets/skills/oat-project-autonomous/references/gate-inventory.md +1 -1
  28. package/assets/skills/oat-project-complete/SKILL.md +158 -30
  29. package/assets/skills/oat-project-complete/scripts/finalize-synced-archive.mjs +26 -7
  30. package/assets/skills/oat-project-complete/scripts/validate-durable-archive-receipt.mjs +183 -0
  31. package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +1 -1
  32. package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +1 -1
  33. package/assets/skills/oat-project-lite/references/docs/autonomy-contract.md +1 -1
  34. package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +1 -1
  35. package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +1 -1
  36. package/assets/skills/oat-project-retro/SKILL.md +1 -1
  37. package/assets/skills/oat-project-retro/references/apply-procedure.md +11 -0
  38. package/assets/skills/oat-project-review-provide/SKILL.md +4 -4
  39. package/assets/skills/oat-project-summary/SKILL.md +24 -2
  40. package/assets/skills/oat-repo-improve/SKILL.md +9 -2
  41. package/assets/skills/oat-repo-improve/references/plan-template.md +4 -6
  42. package/assets/skills/oat-repo-knowledge-index/SKILL.md +11 -9
  43. package/assets/skills/oat-wave-execute/SKILL.md +20 -6
  44. package/assets/skills/oat-wave-program/SKILL.md +9 -4
  45. package/dist/commands/backlog/new.d.ts +1 -0
  46. package/dist/commands/backlog/new.d.ts.map +1 -1
  47. package/dist/commands/backlog/new.js +3 -1
  48. package/dist/commands/config/index.d.ts +3 -1
  49. package/dist/commands/config/index.d.ts.map +1 -1
  50. package/dist/commands/config/index.js +362 -36
  51. package/dist/commands/docs/index-generate/index.d.ts.map +1 -1
  52. package/dist/commands/docs/index-generate/index.js +68 -12
  53. package/dist/commands/docs/init/index.d.ts +11 -0
  54. package/dist/commands/docs/init/index.d.ts.map +1 -1
  55. package/dist/commands/docs/init/index.js +19 -1
  56. package/dist/commands/gate/index.d.ts.map +1 -1
  57. package/dist/commands/gate/index.js +10 -2
  58. package/dist/commands/instructions/instructions.utils.d.ts.map +1 -1
  59. package/dist/commands/instructions/instructions.utils.js +42 -9
  60. package/dist/commands/internal/validate-skill-version-bumps.d.ts.map +1 -1
  61. package/dist/commands/internal/validate-skill-version-bumps.js +5 -5
  62. package/dist/commands/pjm/doctor.d.ts +2 -0
  63. package/dist/commands/pjm/doctor.d.ts.map +1 -1
  64. package/dist/commands/pjm/doctor.js +71 -1
  65. package/dist/commands/pjm/index.d.ts +2 -0
  66. package/dist/commands/pjm/index.d.ts.map +1 -1
  67. package/dist/commands/pjm/index.js +3 -0
  68. package/dist/commands/pjm/remote/__integration__/lifecycle-harness.d.ts +60 -0
  69. package/dist/commands/pjm/remote/__integration__/lifecycle-harness.d.ts.map +1 -0
  70. package/dist/commands/pjm/remote/__integration__/lifecycle-harness.js +151 -0
  71. package/dist/commands/pjm/remote/association.d.ts +27 -0
  72. package/dist/commands/pjm/remote/association.d.ts.map +1 -0
  73. package/dist/commands/pjm/remote/association.js +68 -0
  74. package/dist/commands/pjm/remote/authority.d.ts +210 -0
  75. package/dist/commands/pjm/remote/authority.d.ts.map +1 -0
  76. package/dist/commands/pjm/remote/authority.js +341 -0
  77. package/dist/commands/pjm/remote/batch.d.ts +15 -0
  78. package/dist/commands/pjm/remote/batch.d.ts.map +1 -0
  79. package/dist/commands/pjm/remote/batch.js +126 -0
  80. package/dist/commands/pjm/remote/closeout.d.ts +69 -0
  81. package/dist/commands/pjm/remote/closeout.d.ts.map +1 -0
  82. package/dist/commands/pjm/remote/closeout.js +208 -0
  83. package/dist/commands/pjm/remote/create-binding.d.ts +62 -0
  84. package/dist/commands/pjm/remote/create-binding.d.ts.map +1 -0
  85. package/dist/commands/pjm/remote/create-binding.js +126 -0
  86. package/dist/commands/pjm/remote/credential-safety.d.ts +7 -0
  87. package/dist/commands/pjm/remote/credential-safety.d.ts.map +1 -0
  88. package/dist/commands/pjm/remote/credential-safety.js +21 -0
  89. package/dist/commands/pjm/remote/discussion.d.ts +49 -0
  90. package/dist/commands/pjm/remote/discussion.d.ts.map +1 -0
  91. package/dist/commands/pjm/remote/discussion.js +124 -0
  92. package/dist/commands/pjm/remote/doctor.d.ts +22 -0
  93. package/dist/commands/pjm/remote/doctor.d.ts.map +1 -0
  94. package/dist/commands/pjm/remote/doctor.js +380 -0
  95. package/dist/commands/pjm/remote/external-action.d.ts +208 -0
  96. package/dist/commands/pjm/remote/external-action.d.ts.map +1 -0
  97. package/dist/commands/pjm/remote/external-action.js +367 -0
  98. package/dist/commands/pjm/remote/host-execution.d.ts +28 -0
  99. package/dist/commands/pjm/remote/host-execution.d.ts.map +1 -0
  100. package/dist/commands/pjm/remote/host-execution.js +63 -0
  101. package/dist/commands/pjm/remote/index.d.ts +41 -0
  102. package/dist/commands/pjm/remote/index.d.ts.map +1 -0
  103. package/dist/commands/pjm/remote/index.js +280 -0
  104. package/dist/commands/pjm/remote/jira-adf.d.ts +35 -0
  105. package/dist/commands/pjm/remote/jira-adf.d.ts.map +1 -0
  106. package/dist/commands/pjm/remote/jira-adf.js +169 -0
  107. package/dist/commands/pjm/remote/lifecycle.d.ts +163 -0
  108. package/dist/commands/pjm/remote/lifecycle.d.ts.map +1 -0
  109. package/dist/commands/pjm/remote/lifecycle.js +224 -0
  110. package/dist/commands/pjm/remote/local-projection.d.ts +30 -0
  111. package/dist/commands/pjm/remote/local-projection.d.ts.map +1 -0
  112. package/dist/commands/pjm/remote/local-projection.js +95 -0
  113. package/dist/commands/pjm/remote/managed-markdown.d.ts +30 -0
  114. package/dist/commands/pjm/remote/managed-markdown.d.ts.map +1 -0
  115. package/dist/commands/pjm/remote/managed-markdown.js +128 -0
  116. package/dist/commands/pjm/remote/migrate.d.ts +14 -0
  117. package/dist/commands/pjm/remote/migrate.d.ts.map +1 -0
  118. package/dist/commands/pjm/remote/migrate.js +32 -0
  119. package/dist/commands/pjm/remote/operation-state.d.ts +15 -0
  120. package/dist/commands/pjm/remote/operation-state.d.ts.map +1 -0
  121. package/dist/commands/pjm/remote/operation-state.js +143 -0
  122. package/dist/commands/pjm/remote/outbound-projection-safety.d.ts +25 -0
  123. package/dist/commands/pjm/remote/outbound-projection-safety.d.ts.map +1 -0
  124. package/dist/commands/pjm/remote/outbound-projection-safety.js +99 -0
  125. package/dist/commands/pjm/remote/output.d.ts +60 -0
  126. package/dist/commands/pjm/remote/output.d.ts.map +1 -0
  127. package/dist/commands/pjm/remote/output.js +48 -0
  128. package/dist/commands/pjm/remote/preview.d.ts +88 -0
  129. package/dist/commands/pjm/remote/preview.d.ts.map +1 -0
  130. package/dist/commands/pjm/remote/preview.js +154 -0
  131. package/dist/commands/pjm/remote/provider-conformance.d.ts +13 -0
  132. package/dist/commands/pjm/remote/provider-conformance.d.ts.map +1 -0
  133. package/dist/commands/pjm/remote/provider-conformance.js +37 -0
  134. package/dist/commands/pjm/remote/provider.d.ts +57 -0
  135. package/dist/commands/pjm/remote/provider.d.ts.map +1 -0
  136. package/dist/commands/pjm/remote/provider.js +28 -0
  137. package/dist/commands/pjm/remote/providers/github-publication-safety.d.ts +46 -0
  138. package/dist/commands/pjm/remote/providers/github-publication-safety.d.ts.map +1 -0
  139. package/dist/commands/pjm/remote/providers/github-publication-safety.js +126 -0
  140. package/dist/commands/pjm/remote/providers/github.d.ts +207 -0
  141. package/dist/commands/pjm/remote/providers/github.d.ts.map +1 -0
  142. package/dist/commands/pjm/remote/providers/github.js +1456 -0
  143. package/dist/commands/pjm/remote/providers/jira.d.ts +245 -0
  144. package/dist/commands/pjm/remote/providers/jira.d.ts.map +1 -0
  145. package/dist/commands/pjm/remote/providers/jira.js +1650 -0
  146. package/dist/commands/pjm/remote/providers/linear.d.ts +182 -0
  147. package/dist/commands/pjm/remote/providers/linear.d.ts.map +1 -0
  148. package/dist/commands/pjm/remote/providers/linear.js +1289 -0
  149. package/dist/commands/pjm/remote/purpose-policy.d.ts +29 -0
  150. package/dist/commands/pjm/remote/purpose-policy.d.ts.map +1 -0
  151. package/dist/commands/pjm/remote/purpose-policy.js +118 -0
  152. package/dist/commands/pjm/remote/reconcile.d.ts +42 -0
  153. package/dist/commands/pjm/remote/reconcile.d.ts.map +1 -0
  154. package/dist/commands/pjm/remote/reconcile.js +101 -0
  155. package/dist/commands/pjm/remote/resolution.d.ts +122 -0
  156. package/dist/commands/pjm/remote/resolution.d.ts.map +1 -0
  157. package/dist/commands/pjm/remote/resolution.js +243 -0
  158. package/dist/commands/pjm/remote/schema.d.ts +9309 -0
  159. package/dist/commands/pjm/remote/schema.d.ts.map +1 -0
  160. package/dist/commands/pjm/remote/schema.js +1503 -0
  161. package/dist/commands/pjm/remote/service.d.ts +20 -0
  162. package/dist/commands/pjm/remote/service.d.ts.map +1 -0
  163. package/dist/commands/pjm/remote/service.js +5121 -0
  164. package/dist/commands/pjm/remote/shared-storage.d.ts +36 -0
  165. package/dist/commands/pjm/remote/shared-storage.d.ts.map +1 -0
  166. package/dist/commands/pjm/remote/shared-storage.js +110 -0
  167. package/dist/commands/pjm/remote/snapshot.d.ts +32 -0
  168. package/dist/commands/pjm/remote/snapshot.d.ts.map +1 -0
  169. package/dist/commands/pjm/remote/snapshot.js +140 -0
  170. package/dist/commands/pjm/remote/storage-locator.d.ts +29 -0
  171. package/dist/commands/pjm/remote/storage-locator.d.ts.map +1 -0
  172. package/dist/commands/pjm/remote/storage-locator.js +62 -0
  173. package/dist/commands/pjm/remote/store.d.ts +85 -0
  174. package/dist/commands/pjm/remote/store.d.ts.map +1 -0
  175. package/dist/commands/pjm/remote/store.js +553 -0
  176. package/dist/commands/pjm/remote/verification.d.ts +40 -0
  177. package/dist/commands/pjm/remote/verification.d.ts.map +1 -0
  178. package/dist/commands/pjm/remote/verification.js +100 -0
  179. package/dist/commands/project/dispatch-ceiling/index.d.ts.map +1 -1
  180. package/dist/commands/project/dispatch-ceiling/index.js +32 -18
  181. package/dist/commands/project/log/append.d.ts +48 -0
  182. package/dist/commands/project/log/append.d.ts.map +1 -1
  183. package/dist/commands/project/log/append.js +207 -30
  184. package/dist/commands/project/log/check.d.ts +87 -1
  185. package/dist/commands/project/log/check.d.ts.map +1 -1
  186. package/dist/commands/project/log/check.js +139 -5
  187. package/dist/commands/project/log/grammar.d.ts +165 -0
  188. package/dist/commands/project/log/grammar.d.ts.map +1 -1
  189. package/dist/commands/project/log/grammar.js +219 -1
  190. package/dist/commands/project/log/rollup.d.ts +16 -1
  191. package/dist/commands/project/log/rollup.d.ts.map +1 -1
  192. package/dist/commands/project/log/rollup.js +22 -2
  193. package/dist/commands/project/log/synthesize.d.ts +16 -0
  194. package/dist/commands/project/log/synthesize.d.ts.map +1 -1
  195. package/dist/commands/project/log/synthesize.js +85 -9
  196. package/dist/commands/status/index.d.ts.map +1 -1
  197. package/dist/commands/status/index.js +24 -2
  198. package/dist/commands/sync/apply.d.ts.map +1 -1
  199. package/dist/commands/sync/apply.js +6 -4
  200. package/dist/commands/tools/shared/pack-manifest.d.ts.map +1 -1
  201. package/dist/commands/tools/shared/pack-manifest.js +1 -0
  202. package/dist/config/dispatch-matrix.d.ts.map +1 -1
  203. package/dist/config/dispatch-matrix.js +13 -5
  204. package/dist/config/oat-config.d.ts +41 -0
  205. package/dist/config/oat-config.d.ts.map +1 -1
  206. package/dist/config/oat-config.js +247 -9
  207. package/dist/config/own-keys.d.ts +22 -0
  208. package/dist/config/own-keys.d.ts.map +1 -0
  209. package/dist/config/own-keys.js +32 -0
  210. package/dist/config/resolve.d.ts +11 -0
  211. package/dist/config/resolve.d.ts.map +1 -1
  212. package/dist/config/resolve.js +35 -11
  213. package/dist/config/sync-config.d.ts.map +1 -1
  214. package/dist/config/sync-config.js +16 -0
  215. package/dist/drift/detector.d.ts.map +1 -1
  216. package/dist/drift/detector.js +52 -1
  217. package/dist/drift/skill-view-diagnostic.d.ts.map +1 -1
  218. package/dist/drift/skill-view-diagnostic.js +2 -23
  219. package/dist/engine/compute-plan.d.ts.map +1 -1
  220. package/dist/engine/compute-plan.js +22 -72
  221. package/dist/engine/managed-copy-hash.d.ts +69 -0
  222. package/dist/engine/managed-copy-hash.d.ts.map +1 -0
  223. package/dist/engine/managed-copy-hash.js +175 -0
  224. package/dist/fs/assets.d.ts +11 -0
  225. package/dist/fs/assets.d.ts.map +1 -1
  226. package/dist/fs/assets.js +1 -1
  227. package/dist/manifest/hash.d.ts +110 -0
  228. package/dist/manifest/hash.d.ts.map +1 -1
  229. package/dist/manifest/hash.js +111 -13
  230. package/dist/providers/ceiling/registry.d.ts.map +1 -1
  231. package/dist/providers/ceiling/registry.js +6 -1
  232. package/dist/providers/identity/dispatch-report.d.ts.map +1 -1
  233. package/dist/providers/identity/dispatch-report.js +4 -1
  234. package/dist/release/public-package-contract.d.ts.map +1 -1
  235. package/dist/release/public-package-contract.js +21 -0
  236. package/dist/validation/skills.d.ts.map +1 -1
  237. package/dist/validation/skills.js +305 -40
  238. package/package.json +2 -2
@@ -0,0 +1,208 @@
1
+ import { buildReviewedBatch, reduceReviewedBatchOutcomes } from './batch.js';
2
+ import { semanticDigest } from './provider.js';
3
+ import { composePurposePolicies } from './purpose-policy.js';
4
+ export async function closeoutBindings(input, store) {
5
+ assertUniqueBindings(input.plans);
6
+ const operations = [];
7
+ for (const plan of input.plans) {
8
+ const operation = buildCloseoutJournal(plan, input.projectPath, input.now);
9
+ await store.writeOperation(operation);
10
+ operations.push(operation);
11
+ }
12
+ let batch = buildReviewedBatch({
13
+ batchId: input.batchId,
14
+ lifecycleOperation: 'closeout',
15
+ members: operations.map((operation) => ({
16
+ bindingId: operation.bindingId,
17
+ operationId: operation.operationId,
18
+ bindingPreviewDigest: operation.previewDigest,
19
+ })),
20
+ authority: {
21
+ effective: strictestAuthority(operations.flatMap((operation) => operation.substeps.map((step) => step.authority))),
22
+ sourceDigest: semanticDigest(operations.flatMap((operation) => operation.substeps.map((step) => step.authoritySourceDigest))),
23
+ },
24
+ approval: input.approval,
25
+ createdAt: input.now,
26
+ });
27
+ batch = reduceReviewedBatchOutcomes(batch, Object.fromEntries(operations.map((operation) => [operation.operationId, operation.state])), input.now);
28
+ await store.writeBatch(batch);
29
+ return { batch, operations };
30
+ }
31
+ export async function resumeCloseoutOperation(journal, store, executeStep, crash, now = () => new Date().toISOString(), authorization) {
32
+ let current = cloneJournal(journal);
33
+ for (let index = 0; index < current.substeps.length; index += 1) {
34
+ const step = current.substeps[index];
35
+ if (step.state === 'verified')
36
+ continue;
37
+ if ([
38
+ 'attempt-started',
39
+ 'verification-pending',
40
+ 'partial',
41
+ 'uncertain',
42
+ 'rejected',
43
+ ].includes(step.state)) {
44
+ continue;
45
+ }
46
+ if (step.state === 'blocked' || step.state === 'failed')
47
+ continue;
48
+ const dependenciesVerified = step.dependsOn.every((dependencyId) => current.substeps.some((candidate) => candidate.stepId === dependencyId && candidate.state === 'verified'));
49
+ if (!dependenciesVerified)
50
+ continue;
51
+ assertStepAuthorized(step, authorization, now());
52
+ crash?.(`before-${step.kind}`);
53
+ current.substeps[index] = { ...step, state: 'attempt-started' };
54
+ current = withReducedState(current, now());
55
+ await store.writeOperation(current);
56
+ const outcome = await executeStep(current.substeps[index]);
57
+ current.substeps[index] = {
58
+ ...current.substeps[index],
59
+ state: outcome,
60
+ };
61
+ current = withReducedState(current, now());
62
+ await store.writeOperation(current);
63
+ crash?.(`after-${step.kind}`);
64
+ }
65
+ current = withReducedState(current, now());
66
+ await store.writeOperation(current);
67
+ return current;
68
+ }
69
+ function assertStepAuthorized(step, authorization, currentTime) {
70
+ if (step.approvalRequirement === 'none')
71
+ return;
72
+ const age = authorization
73
+ ? Date.parse(currentTime) - Date.parse(authorization.authorizedAt)
74
+ : Number.POSITIVE_INFINITY;
75
+ const expectedKind = step.approvalRequirement === 'fresh-approval' ? 'approval' : 'instruction';
76
+ if (!authorization ||
77
+ authorization.kind !== expectedKind ||
78
+ authorization.previewDigest !== step.previewDigest ||
79
+ !authorization.source ||
80
+ !Number.isFinite(age) ||
81
+ age < 0 ||
82
+ age > 5 * 60 * 1_000) {
83
+ throw new Error(`Closeout ${step.approvalRequirement} must authorize the exact current composite preview.`);
84
+ }
85
+ }
86
+ function withReducedState(journal, updatedAt) {
87
+ return {
88
+ ...journal,
89
+ state: reduceCloseoutState(journal.substeps),
90
+ updatedAt,
91
+ };
92
+ }
93
+ function cloneJournal(journal) {
94
+ return {
95
+ ...journal,
96
+ substeps: journal.substeps.map((step) => ({
97
+ ...step,
98
+ dependsOn: [...step.dependsOn],
99
+ })),
100
+ };
101
+ }
102
+ function buildCloseoutJournal(plan, projectPath, now) {
103
+ if (plan.providerAutomation && plan.transition) {
104
+ throw new Error(`Binding '${plan.bindingId}' cannot combine provider automation with an OAT transition.`);
105
+ }
106
+ const purposes = new Set(plan.purposes);
107
+ const composed = composePurposePolicies([...purposes]);
108
+ const substeps = [];
109
+ if (plan.annotation &&
110
+ composed.closeout.annotation === 'propose' &&
111
+ composed.lifecycle.includes('annotate')) {
112
+ substeps.push(buildSubstep(plan, 'annotation', plan.annotation, []));
113
+ }
114
+ if (plan.transition &&
115
+ composed.closeout.transition === 'propose' &&
116
+ composed.lifecycle.includes('transition')) {
117
+ substeps.push(buildSubstep(plan, 'transition', plan.transition, substeps.map((step) => step.stepId)));
118
+ }
119
+ const state = plan.providerAutomation &&
120
+ composed.closeout.transition === 'provider-automation'
121
+ ? 'verified'
122
+ : substeps.length === 0
123
+ ? 'blocked'
124
+ : reduceCloseoutState(substeps);
125
+ const previewDigest = semanticDigest({
126
+ bindingId: plan.bindingId,
127
+ operationId: plan.operationId,
128
+ provider: plan.provider,
129
+ projectPath,
130
+ purposes: [...purposes].sort(),
131
+ providerAutomation: plan.providerAutomation ?? false,
132
+ substeps,
133
+ });
134
+ return {
135
+ schemaVersion: 1,
136
+ operationId: plan.operationId,
137
+ bindingId: plan.bindingId,
138
+ provider: plan.provider,
139
+ projectPath,
140
+ previewDigest,
141
+ state,
142
+ substeps,
143
+ createdAt: now,
144
+ updatedAt: now,
145
+ };
146
+ }
147
+ function buildSubstep(plan, kind, step, dependsOn) {
148
+ return {
149
+ stepId: `${plan.operationId}_${kind}`,
150
+ kind,
151
+ state: step.authority === 'read-only' ? 'blocked' : 'pending',
152
+ previewDigest: step.previewDigest,
153
+ authority: step.authority,
154
+ authoritySourceDigest: step.sourceDigest,
155
+ approvalRequirement: step.authority === 'user-approved'
156
+ ? 'fresh-approval'
157
+ : step.authority === 'user-authorized'
158
+ ? 'explicit-instruction'
159
+ : 'none',
160
+ dependsOn,
161
+ };
162
+ }
163
+ export function reduceCloseoutState(substeps) {
164
+ const states = substeps.map((step) => step.state);
165
+ if (states.every((state) => state === 'verified'))
166
+ return 'verified';
167
+ if (states.includes('partial') ||
168
+ (states.includes('verified') &&
169
+ states.some((state) => state !== 'verified'))) {
170
+ return 'partial';
171
+ }
172
+ if (states.includes('uncertain'))
173
+ return 'uncertain';
174
+ if (states.some((state) => state === 'attempt-started'))
175
+ return 'attempt-started';
176
+ if (states.some((state) => state === 'verification-pending'))
177
+ return 'verification-pending';
178
+ if (states.some((state) => state === 'pending'))
179
+ return 'pending';
180
+ if (states.some((state) => state === 'authorized'))
181
+ return 'authorized';
182
+ if (states.every((state) => state === 'blocked'))
183
+ return 'blocked';
184
+ if (states.some((state) => state === 'rejected'))
185
+ return 'rejected';
186
+ return 'failed';
187
+ }
188
+ function strictestAuthority(authorities) {
189
+ const rank = {
190
+ 'read-only': 0,
191
+ 'user-approved': 1,
192
+ 'user-authorized': 2,
193
+ autonomous: 3,
194
+ };
195
+ return authorities.reduce((strictest, authority) => rank[authority] < rank[strictest] ? authority : strictest, 'autonomous');
196
+ }
197
+ function assertUniqueBindings(plans) {
198
+ const bindingIds = new Set();
199
+ const operationIds = new Set();
200
+ for (const plan of plans) {
201
+ if (bindingIds.has(plan.bindingId))
202
+ throw new Error(`Duplicate closeout binding '${plan.bindingId}'.`);
203
+ if (operationIds.has(plan.operationId))
204
+ throw new Error(`Duplicate closeout operation '${plan.operationId}'.`);
205
+ bindingIds.add(plan.bindingId);
206
+ operationIds.add(plan.operationId);
207
+ }
208
+ }
@@ -0,0 +1,62 @@
1
+ import { type ExternalActionEnvelope } from './external-action.js';
2
+ import { type OutboundProjection, type OutboundProjectionSafetyResult } from './outbound-projection-safety.js';
3
+ export interface BindingCreateIntent {
4
+ bindingId: string;
5
+ operationId: string;
6
+ provider: 'github' | 'linear' | 'jira';
7
+ context: Record<string, string>;
8
+ target: {
9
+ kind: 'backlog' | 'project';
10
+ id: string;
11
+ scope: 'shared' | 'synced' | 'local';
12
+ };
13
+ projection: OutboundProjection;
14
+ previewDigest: string;
15
+ projectionDigest: string;
16
+ safetyResultDigest: string;
17
+ capabilityEvidenceDigest: string;
18
+ provenanceToken: string;
19
+ }
20
+ export interface CreateBindingDependencies {
21
+ reserveIntent(intent: BindingCreateIntent): Promise<void>;
22
+ readIntent(operationId: string): Promise<BindingCreateIntent | null>;
23
+ readAction(operationId: string): Promise<ExternalActionEnvelope | null>;
24
+ recordAction(operationId: string, action: ExternalActionEnvelope): Promise<void>;
25
+ recordVerificationPending(operationId: string, action: ExternalActionEnvelope): Promise<void>;
26
+ recordTerminal(operationId: string, state: 'rejected' | 'uncertain'): Promise<void>;
27
+ materialize(input: {
28
+ intent: BindingCreateIntent;
29
+ stableId: string;
30
+ aliases: string[];
31
+ observedFields: Record<string, string | number | boolean | null>;
32
+ revisionDigest: string;
33
+ }): Promise<void>;
34
+ writeAssociation(input: {
35
+ target: BindingCreateIntent['target'];
36
+ provider: string;
37
+ ref: string;
38
+ bindingId: string;
39
+ }): Promise<void>;
40
+ readMaterializationProgress?(operationId: string): Promise<Array<'materialized' | 'associated' | 'terminal'>>;
41
+ recordMaterializationProgress?(operationId: string, step: 'materialized' | 'associated' | 'terminal'): Promise<void>;
42
+ recordVerified?(operationId: string): Promise<void>;
43
+ crash?(point: 'after-intent' | 'after-observation' | 'after-materialize' | 'after-association' | 'after-terminal'): void;
44
+ }
45
+ export type CreateBindingResult = {
46
+ status: 'pending';
47
+ action: ExternalActionEnvelope;
48
+ } | {
49
+ status: 'verified';
50
+ bindingId: string;
51
+ } | {
52
+ status: 'rejected' | 'uncertain';
53
+ bindingId: null;
54
+ };
55
+ export declare function createAndBindRemoteIssue(input: {
56
+ intent: BindingCreateIntent;
57
+ safety: OutboundProjectionSafetyResult | null;
58
+ continuation?: {
59
+ observation: unknown;
60
+ };
61
+ }, dependencies: CreateBindingDependencies): Promise<CreateBindingResult>;
62
+ //# sourceMappingURL=create-binding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-binding.d.ts","sourceRoot":"","sources":["../../../../src/commands/pjm/remote/create-binding.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,sBAAsB,EAC5B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,8BAA8B,EACpC,MAAM,8BAA8B,CAAC;AAEtC,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;IACvC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,MAAM,EAAE;QACN,IAAI,EAAE,SAAS,GAAG,SAAS,CAAC;QAC5B,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;KACtC,CAAC;IACF,UAAU,EAAE,kBAAkB,CAAC;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,wBAAwB,EAAE,MAAM,CAAC;IACjC,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,yBAAyB;IACxC,aAAa,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAAC;IACrE,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAAC;IACxE,YAAY,CACV,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,sBAAsB,GAC7B,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,yBAAyB,CACvB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,sBAAsB,GAC7B,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,cAAc,CACZ,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,UAAU,GAAG,WAAW,GAC9B,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,WAAW,CAAC,KAAK,EAAE;QACjB,MAAM,EAAE,mBAAmB,CAAC;QAC5B,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,EAAE,CAAC;QAClB,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,CAAC;QACjE,cAAc,EAAE,MAAM,CAAC;KACxB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClB,gBAAgB,CAAC,KAAK,EAAE;QACtB,MAAM,EAAE,mBAAmB,CAAC,QAAQ,CAAC,CAAC;QACtC,QAAQ,EAAE,MAAM,CAAC;QACjB,GAAG,EAAE,MAAM,CAAC;QACZ,SAAS,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClB,2BAA2B,CAAC,CAC1B,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,KAAK,CAAC,cAAc,GAAG,YAAY,GAAG,UAAU,CAAC,CAAC,CAAC;IAC9D,6BAA6B,CAAC,CAC5B,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,cAAc,GAAG,YAAY,GAAG,UAAU,GAC/C,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,cAAc,CAAC,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,KAAK,CAAC,CACJ,KAAK,EACD,cAAc,GACd,mBAAmB,GACnB,mBAAmB,GACnB,mBAAmB,GACnB,gBAAgB,GACnB,IAAI,CAAC;CACT;AAED,MAAM,MAAM,mBAAmB,GAC3B;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,sBAAsB,CAAA;CAAE,GACrD;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,MAAM,EAAE,UAAU,GAAG,WAAW,CAAC;IAAC,SAAS,EAAE,IAAI,CAAA;CAAE,CAAC;AAE1D,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE;IACL,MAAM,EAAE,mBAAmB,CAAC;IAC5B,MAAM,EAAE,8BAA8B,GAAG,IAAI,CAAC;IAC9C,YAAY,CAAC,EAAE;QAAE,WAAW,EAAE,OAAO,CAAA;KAAE,CAAC;CACzC,EACD,YAAY,EAAE,yBAAyB,GACtC,OAAO,CAAC,mBAAmB,CAAC,CAwJ9B"}
@@ -0,0 +1,126 @@
1
+ import { acceptExternalObservation, buildExternalAction, } from './external-action.js';
2
+ import { requireCurrentOutboundSafety, } from './outbound-projection-safety.js';
3
+ export async function createAndBindRemoteIssue(input, dependencies) {
4
+ if (!input.continuation) {
5
+ await dependencies.reserveIntent(input.intent);
6
+ dependencies.crash?.('after-intent');
7
+ requireCurrentOutboundSafety(input.intent.projection, input.safety);
8
+ if (input.intent.projectionDigest !== input.safety.projectionDigest ||
9
+ input.intent.safetyResultDigest !== input.safety.resultDigest) {
10
+ throw new Error('Create intent safety evidence is stale or mismatched.');
11
+ }
12
+ const action = buildExternalAction({
13
+ operationId: input.intent.operationId,
14
+ stepId: `step_${input.intent.operationId}`,
15
+ provider: input.intent.provider,
16
+ semanticOperation: 'create',
17
+ context: input.intent.context,
18
+ intent: {
19
+ target: input.intent.target,
20
+ fields: input.intent.projection,
21
+ provenanceToken: input.intent.provenanceToken,
22
+ },
23
+ expectedObservation: {
24
+ fields: Object.keys(input.intent.projection),
25
+ requireIdentity: true,
26
+ stableId: null,
27
+ capabilityEvidenceDigest: input.intent.capabilityEvidenceDigest,
28
+ },
29
+ persistedPreview: input.intent,
30
+ projection: input.intent.projection,
31
+ outboundSafety: input.safety,
32
+ });
33
+ await dependencies.recordAction(input.intent.operationId, action);
34
+ return { status: 'pending', action };
35
+ }
36
+ const progress = new Set((await dependencies.readMaterializationProgress?.(input.intent.operationId)) ?? []);
37
+ if (progress.has('terminal')) {
38
+ throw new Error('Create operation is terminal; observation replay rejected.');
39
+ }
40
+ const persisted = await dependencies.readIntent(input.intent.operationId);
41
+ if (!persisted ||
42
+ JSON.stringify(persisted) !== JSON.stringify(input.intent)) {
43
+ throw new Error('Create continuation does not match the persisted intent.');
44
+ }
45
+ const durableAction = await dependencies.readAction(input.intent.operationId);
46
+ if (!durableAction) {
47
+ throw new Error('Create continuation has no durable current action.');
48
+ }
49
+ const observation = acceptExternalObservation({
50
+ action: durableAction,
51
+ observation: input.continuation.observation,
52
+ });
53
+ if (observation.outcome.classification === 'rejected') {
54
+ await dependencies.recordTerminal(input.intent.operationId, 'rejected');
55
+ return { status: 'rejected', bindingId: null };
56
+ }
57
+ if (observation.outcome.classification !== 'observed' ||
58
+ !observation.outcome.identity) {
59
+ await dependencies.recordTerminal(input.intent.operationId, 'uncertain');
60
+ return { status: 'uncertain', bindingId: null };
61
+ }
62
+ dependencies.crash?.('after-observation');
63
+ if (durableAction.semanticOperation === 'create') {
64
+ if (observation.outcome.classification !== 'observed' ||
65
+ !observation.outcome.identity) {
66
+ await dependencies.recordTerminal(input.intent.operationId, 'uncertain');
67
+ return { status: 'uncertain', bindingId: null };
68
+ }
69
+ const readAction = buildExternalAction({
70
+ operationId: input.intent.operationId,
71
+ stepId: `verify_${input.intent.operationId}`,
72
+ provider: input.intent.provider,
73
+ semanticOperation: 'read',
74
+ context: input.intent.context,
75
+ intent: { stableId: observation.outcome.identity.stableId },
76
+ expectedObservation: {
77
+ fields: Object.keys(input.intent.projection),
78
+ requireIdentity: true,
79
+ stableId: observation.outcome.identity.stableId,
80
+ capabilityEvidenceDigest: input.intent.capabilityEvidenceDigest,
81
+ },
82
+ persistedPreview: {},
83
+ });
84
+ await dependencies.recordVerificationPending(input.intent.operationId, readAction);
85
+ return { status: 'pending', action: readAction };
86
+ }
87
+ if (durableAction.semanticOperation !== 'read') {
88
+ throw new Error('Create continuation durable action is not current.');
89
+ }
90
+ for (const [field, expected] of Object.entries(input.intent.projection)) {
91
+ if (observation.outcome.fields[field] !== expected) {
92
+ await dependencies.recordTerminal(input.intent.operationId, 'uncertain');
93
+ return { status: 'uncertain', bindingId: null };
94
+ }
95
+ }
96
+ if (!observation.outcome.revisionDigest) {
97
+ await dependencies.recordTerminal(input.intent.operationId, 'uncertain');
98
+ return { status: 'uncertain', bindingId: null };
99
+ }
100
+ if (!progress.has('materialized')) {
101
+ await dependencies.materialize({
102
+ intent: input.intent,
103
+ stableId: observation.outcome.identity.stableId,
104
+ aliases: observation.outcome.identity.aliases,
105
+ observedFields: observation.outcome.fields,
106
+ revisionDigest: observation.outcome.revisionDigest,
107
+ });
108
+ await dependencies.recordMaterializationProgress?.(input.intent.operationId, 'materialized');
109
+ dependencies.crash?.('after-materialize');
110
+ }
111
+ if (!progress.has('associated')) {
112
+ await dependencies.writeAssociation({
113
+ target: input.intent.target,
114
+ provider: input.intent.provider,
115
+ ref: observation.outcome.identity.aliases[0] ??
116
+ observation.outcome.identity.stableId,
117
+ bindingId: input.intent.bindingId,
118
+ });
119
+ await dependencies.recordMaterializationProgress?.(input.intent.operationId, 'associated');
120
+ dependencies.crash?.('after-association');
121
+ }
122
+ await dependencies.recordVerified?.(input.intent.operationId);
123
+ await dependencies.recordMaterializationProgress?.(input.intent.operationId, 'terminal');
124
+ dependencies.crash?.('after-terminal');
125
+ return { status: 'verified', bindingId: input.intent.bindingId };
126
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Detects a deliberately small, conservative signal in one caller-approved
3
+ * text field. This is not credential-value parsing or a general DLP check.
4
+ */
5
+ export declare function containsSensitiveContentSignal(value: string): boolean;
6
+ export declare function containsSensitiveContentSignalInValue(value: unknown): boolean;
7
+ //# sourceMappingURL=credential-safety.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential-safety.d.ts","sourceRoot":"","sources":["../../../../src/commands/pjm/remote/credential-safety.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAErE;AAED,wBAAgB,qCAAqC,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAe7E"}
@@ -0,0 +1,21 @@
1
+ const SENSITIVE_CONTENT_SIGNAL = /(?<![A-Za-z0-9_-])(?:password|passwd|api(?:[ _-]+)key|access(?:[ _-]+)token|authorization|secret|token)(?![A-Za-z0-9_-])/i;
2
+ /**
3
+ * Detects a deliberately small, conservative signal in one caller-approved
4
+ * text field. This is not credential-value parsing or a general DLP check.
5
+ */
6
+ export function containsSensitiveContentSignal(value) {
7
+ return SENSITIVE_CONTENT_SIGNAL.test(value);
8
+ }
9
+ export function containsSensitiveContentSignalInValue(value) {
10
+ if (typeof value === 'string') {
11
+ return containsSensitiveContentSignal(value);
12
+ }
13
+ if (Array.isArray(value)) {
14
+ return value.some((entry) => containsSensitiveContentSignalInValue(entry));
15
+ }
16
+ if (value && typeof value === 'object') {
17
+ return Object.entries(value).some(([key, entry]) => containsSensitiveContentSignal(key) ||
18
+ containsSensitiveContentSignalInValue(entry));
19
+ }
20
+ return false;
21
+ }
@@ -0,0 +1,49 @@
1
+ import type { ExternalActionEnvelope } from './external-action.js';
2
+ export interface RemoteDiscussionItem {
3
+ id: string;
4
+ body: string;
5
+ createdAt: string;
6
+ }
7
+ export interface SanitizedDiscussionItem extends RemoteDiscussionItem {
8
+ incomplete: boolean;
9
+ }
10
+ export interface DiscussionPage {
11
+ items: RemoteDiscussionItem[];
12
+ nextCursor: string | null;
13
+ }
14
+ export interface DiscussionPageSource {
15
+ readPage(input: {
16
+ bindingId: string;
17
+ cursor: string | null;
18
+ limit: number;
19
+ }): Promise<DiscussionPage>;
20
+ }
21
+ export interface DiscussionEvidence {
22
+ status: 'available' | 'unavailable';
23
+ bindingId: string;
24
+ observedAt: string;
25
+ items: SanitizedDiscussionItem[];
26
+ pagesRead: number;
27
+ truncated: boolean;
28
+ persisted: false;
29
+ }
30
+ export declare function acceptRemoteDiscussionObservation(input: {
31
+ action: ExternalActionEnvelope;
32
+ observation: unknown;
33
+ bindingId: string;
34
+ limit: number;
35
+ maxPages: number;
36
+ }): Promise<DiscussionEvidence>;
37
+ export declare function readRemoteDiscussion(input: {
38
+ bindingId: string;
39
+ limit: number;
40
+ maxPages: number;
41
+ observedAt: string;
42
+ }, source: DiscussionPageSource | null): Promise<DiscussionEvidence>;
43
+ export declare function distillDiscussionLocally(input: {
44
+ bindingId: string;
45
+ observedAt: string;
46
+ selectedItemIds: readonly string[];
47
+ items: readonly SanitizedDiscussionItem[];
48
+ }): string;
49
+ //# sourceMappingURL=discussion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discussion.d.ts","sourceRoot":"","sources":["../../../../src/commands/pjm/remote/discussion.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAIhE,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,uBAAwB,SAAQ,oBAAoB;IACnE,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,oBAAoB,EAAE,CAAC;IAC9B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,KAAK,EAAE;QACd,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,KAAK,EAAE,MAAM,CAAC;KACf,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CAC7B;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,WAAW,GAAG,aAAa,CAAC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,uBAAuB,EAAE,CAAC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,KAAK,CAAC;CAClB;AA4BD,wBAAsB,iCAAiC,CAAC,KAAK,EAAE;IAC7D,MAAM,EAAE,sBAAsB,CAAC;IAC/B,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAoC9B;AAED,wBAAsB,oBAAoB,CACxC,KAAK,EAAE;IACL,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB,EACD,MAAM,EAAE,oBAAoB,GAAG,IAAI,GAClC,OAAO,CAAC,kBAAkB,CAAC,CAoD7B;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,KAAK,EAAE,SAAS,uBAAuB,EAAE,CAAC;CAC3C,GAAG,MAAM,CAWT"}
@@ -0,0 +1,124 @@
1
+ import { z } from 'zod';
2
+ import { containsSensitiveContentSignal } from './credential-safety.js';
3
+ import { semanticDigest } from './provider.js';
4
+ import { WHOLE_FIELD_SUPPRESSION_MARKER } from './schema.js';
5
+ const DiscussionObservationSchema = z
6
+ .object({
7
+ schemaVersion: z.literal(1),
8
+ operationId: z.string().min(1).max(128),
9
+ stepId: z.string().min(1).max(128),
10
+ actionDigest: z.string().min(1).max(512),
11
+ observedAt: z.string().datetime({ offset: true }),
12
+ provider: z.enum(['github', 'linear', 'jira']),
13
+ context: z.record(z.string(), z.string().optional()),
14
+ capabilityEvidenceDigest: z.string().min(1).max(512),
15
+ availability: z.enum(['available', 'unavailable']),
16
+ items: z
17
+ .array(z
18
+ .object({
19
+ id: z.string().min(1).max(512),
20
+ body: z.string().max(1_048_576),
21
+ createdAt: z.string().datetime({ offset: true }),
22
+ })
23
+ .strict())
24
+ .max(100),
25
+ nextCursor: z.string().max(512).nullable(),
26
+ })
27
+ .strict();
28
+ export async function acceptRemoteDiscussionObservation(input) {
29
+ if (input.action.semanticOperation !== 'read-discussion') {
30
+ throw new Error('Discussion continuation requires a discussion action.');
31
+ }
32
+ const observation = DiscussionObservationSchema.parse(input.observation);
33
+ if (observation.operationId !== input.action.operationId ||
34
+ observation.stepId !== input.action.stepId ||
35
+ observation.actionDigest !== input.action.actionDigest ||
36
+ observation.provider !== input.action.provider ||
37
+ observation.capabilityEvidenceDigest !==
38
+ input.action.expectedObservation.capabilityEvidenceDigest ||
39
+ semanticDigest(observation.context) !== semanticDigest(input.action.context)) {
40
+ throw new Error('Discussion observation does not match its durable action.');
41
+ }
42
+ return readRemoteDiscussion({
43
+ bindingId: input.bindingId,
44
+ limit: input.limit,
45
+ maxPages: input.maxPages,
46
+ observedAt: observation.observedAt,
47
+ }, observation.availability === 'available'
48
+ ? {
49
+ async readPage() {
50
+ return {
51
+ items: observation.items,
52
+ nextCursor: observation.nextCursor,
53
+ };
54
+ },
55
+ }
56
+ : null);
57
+ }
58
+ export async function readRemoteDiscussion(input, source) {
59
+ assertBounds(input.limit, input.maxPages);
60
+ if (!source) {
61
+ return {
62
+ status: 'unavailable',
63
+ bindingId: input.bindingId,
64
+ observedAt: input.observedAt,
65
+ items: [],
66
+ pagesRead: 0,
67
+ truncated: false,
68
+ persisted: false,
69
+ };
70
+ }
71
+ const items = [];
72
+ let cursor = null;
73
+ let pagesRead = 0;
74
+ let hasMore = false;
75
+ let droppedItems = false;
76
+ do {
77
+ const page = await source.readPage({
78
+ bindingId: input.bindingId,
79
+ cursor,
80
+ limit: input.limit - items.length,
81
+ });
82
+ pagesRead += 1;
83
+ const remaining = input.limit - items.length;
84
+ droppedItems ||= page.items.length > remaining;
85
+ for (const item of page.items.slice(0, remaining)) {
86
+ const suppressed = containsSensitiveContentSignal(item.body);
87
+ items.push({
88
+ ...item,
89
+ body: suppressed ? WHOLE_FIELD_SUPPRESSION_MARKER : item.body,
90
+ incomplete: suppressed,
91
+ });
92
+ }
93
+ cursor = page.nextCursor;
94
+ hasMore = cursor !== null;
95
+ } while (cursor !== null &&
96
+ pagesRead < input.maxPages &&
97
+ items.length < input.limit);
98
+ return {
99
+ status: 'available',
100
+ bindingId: input.bindingId,
101
+ observedAt: input.observedAt,
102
+ items,
103
+ pagesRead,
104
+ truncated: hasMore || droppedItems,
105
+ persisted: false,
106
+ };
107
+ }
108
+ export function distillDiscussionLocally(input) {
109
+ const selected = new Set(input.selectedItemIds);
110
+ const evidence = input.items.filter((item) => selected.has(item.id));
111
+ return [
112
+ `locally authored discussion distillation for ${input.bindingId}`,
113
+ `Observed: ${input.observedAt}`,
114
+ ...evidence.map((item) => `- ${item.body}${item.incomplete ? ' (incomplete evidence)' : ''}`),
115
+ ].join('\n');
116
+ }
117
+ function assertBounds(limit, maxPages) {
118
+ if (!Number.isSafeInteger(limit) || limit < 1 || limit > 100) {
119
+ throw new Error('Discussion limit must be an integer from 1 to 100.');
120
+ }
121
+ if (!Number.isSafeInteger(maxPages) || maxPages < 1 || maxPages > 10) {
122
+ throw new Error('Discussion maxPages must be an integer from 1 to 10.');
123
+ }
124
+ }
@@ -0,0 +1,22 @@
1
+ import type { DoctorCheck } from '../../../ui/output.js';
2
+ export interface RemoteDoctorInput {
3
+ portableBindingsDir: string;
4
+ operationalBindingsDir: string;
5
+ operationsDir: string;
6
+ associatedBindingIds?: readonly string[];
7
+ policy?: unknown;
8
+ now?: string;
9
+ staleAfterMs?: number;
10
+ retentionBreaches?: readonly string[];
11
+ evidenceAvailability?: {
12
+ associations: boolean;
13
+ retention: boolean;
14
+ hostCapabilities: boolean;
15
+ };
16
+ hostCapabilityAvailability?: ReadonlyArray<{
17
+ bindingId: string;
18
+ available: boolean;
19
+ }>;
20
+ }
21
+ export declare function runRemoteDoctorChecks(input: RemoteDoctorInput): Promise<DoctorCheck[]>;
22
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../../src/commands/pjm/remote/doctor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAY9C,MAAM,WAAW,iBAAiB;IAChC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,oBAAoB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,oBAAoB,CAAC,EAAE;QACrB,YAAY,EAAE,OAAO,CAAC;QACtB,SAAS,EAAE,OAAO,CAAC;QACnB,gBAAgB,EAAE,OAAO,CAAC;KAC3B,CAAC;IACF,0BAA0B,CAAC,EAAE,aAAa,CAAC;QACzC,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,OAAO,CAAC;KACpB,CAAC,CAAC;CACJ;AAoBD,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,iBAAiB,GACvB,OAAO,CAAC,WAAW,EAAE,CAAC,CAiHxB"}