@open-agent-toolkit/cli 0.2.65 → 0.2.66

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 (142) hide show
  1. package/assets/bundle-metadata.json +1 -1
  2. package/assets/docs/cli-utilities/configuration.md +19 -1
  3. package/assets/docs/cli-utilities/index.md +3 -0
  4. package/assets/docs/cli-utilities/remote-project-management.md +191 -0
  5. package/assets/docs/reference/cli-reference.md +12 -1
  6. package/assets/docs/reference/file-locations.md +22 -0
  7. package/assets/docs/reference/oat-directory-structure.md +30 -17
  8. package/assets/docs/reference/troubleshooting.md +44 -0
  9. package/assets/docs/workflows/skills/index.md +33 -0
  10. package/assets/public-package-versions.json +4 -4
  11. package/assets/skills/oat-doctor/SKILL.md +4 -4
  12. package/assets/skills/oat-pjm-remote/SKILL.md +101 -0
  13. package/assets/skills/oat-pjm-remote/references/external-action-protocol.md +43 -0
  14. package/dist/commands/backlog/new.d.ts +1 -0
  15. package/dist/commands/backlog/new.d.ts.map +1 -1
  16. package/dist/commands/backlog/new.js +3 -1
  17. package/dist/commands/config/index.d.ts +1 -0
  18. package/dist/commands/config/index.d.ts.map +1 -1
  19. package/dist/commands/config/index.js +232 -1
  20. package/dist/commands/pjm/doctor.d.ts +2 -0
  21. package/dist/commands/pjm/doctor.d.ts.map +1 -1
  22. package/dist/commands/pjm/doctor.js +71 -1
  23. package/dist/commands/pjm/index.d.ts +2 -0
  24. package/dist/commands/pjm/index.d.ts.map +1 -1
  25. package/dist/commands/pjm/index.js +3 -0
  26. package/dist/commands/pjm/remote/__integration__/lifecycle-harness.d.ts +60 -0
  27. package/dist/commands/pjm/remote/__integration__/lifecycle-harness.d.ts.map +1 -0
  28. package/dist/commands/pjm/remote/__integration__/lifecycle-harness.js +151 -0
  29. package/dist/commands/pjm/remote/association.d.ts +27 -0
  30. package/dist/commands/pjm/remote/association.d.ts.map +1 -0
  31. package/dist/commands/pjm/remote/association.js +68 -0
  32. package/dist/commands/pjm/remote/authority.d.ts +210 -0
  33. package/dist/commands/pjm/remote/authority.d.ts.map +1 -0
  34. package/dist/commands/pjm/remote/authority.js +341 -0
  35. package/dist/commands/pjm/remote/batch.d.ts +15 -0
  36. package/dist/commands/pjm/remote/batch.d.ts.map +1 -0
  37. package/dist/commands/pjm/remote/batch.js +126 -0
  38. package/dist/commands/pjm/remote/closeout.d.ts +69 -0
  39. package/dist/commands/pjm/remote/closeout.d.ts.map +1 -0
  40. package/dist/commands/pjm/remote/closeout.js +208 -0
  41. package/dist/commands/pjm/remote/create-binding.d.ts +62 -0
  42. package/dist/commands/pjm/remote/create-binding.d.ts.map +1 -0
  43. package/dist/commands/pjm/remote/create-binding.js +126 -0
  44. package/dist/commands/pjm/remote/credential-safety.d.ts +7 -0
  45. package/dist/commands/pjm/remote/credential-safety.d.ts.map +1 -0
  46. package/dist/commands/pjm/remote/credential-safety.js +21 -0
  47. package/dist/commands/pjm/remote/discussion.d.ts +49 -0
  48. package/dist/commands/pjm/remote/discussion.d.ts.map +1 -0
  49. package/dist/commands/pjm/remote/discussion.js +124 -0
  50. package/dist/commands/pjm/remote/doctor.d.ts +22 -0
  51. package/dist/commands/pjm/remote/doctor.d.ts.map +1 -0
  52. package/dist/commands/pjm/remote/doctor.js +380 -0
  53. package/dist/commands/pjm/remote/external-action.d.ts +208 -0
  54. package/dist/commands/pjm/remote/external-action.d.ts.map +1 -0
  55. package/dist/commands/pjm/remote/external-action.js +367 -0
  56. package/dist/commands/pjm/remote/host-execution.d.ts +28 -0
  57. package/dist/commands/pjm/remote/host-execution.d.ts.map +1 -0
  58. package/dist/commands/pjm/remote/host-execution.js +63 -0
  59. package/dist/commands/pjm/remote/index.d.ts +41 -0
  60. package/dist/commands/pjm/remote/index.d.ts.map +1 -0
  61. package/dist/commands/pjm/remote/index.js +280 -0
  62. package/dist/commands/pjm/remote/jira-adf.d.ts +35 -0
  63. package/dist/commands/pjm/remote/jira-adf.d.ts.map +1 -0
  64. package/dist/commands/pjm/remote/jira-adf.js +169 -0
  65. package/dist/commands/pjm/remote/lifecycle.d.ts +163 -0
  66. package/dist/commands/pjm/remote/lifecycle.d.ts.map +1 -0
  67. package/dist/commands/pjm/remote/lifecycle.js +224 -0
  68. package/dist/commands/pjm/remote/local-projection.d.ts +30 -0
  69. package/dist/commands/pjm/remote/local-projection.d.ts.map +1 -0
  70. package/dist/commands/pjm/remote/local-projection.js +95 -0
  71. package/dist/commands/pjm/remote/managed-markdown.d.ts +30 -0
  72. package/dist/commands/pjm/remote/managed-markdown.d.ts.map +1 -0
  73. package/dist/commands/pjm/remote/managed-markdown.js +128 -0
  74. package/dist/commands/pjm/remote/migrate.d.ts +14 -0
  75. package/dist/commands/pjm/remote/migrate.d.ts.map +1 -0
  76. package/dist/commands/pjm/remote/migrate.js +32 -0
  77. package/dist/commands/pjm/remote/operation-state.d.ts +15 -0
  78. package/dist/commands/pjm/remote/operation-state.d.ts.map +1 -0
  79. package/dist/commands/pjm/remote/operation-state.js +143 -0
  80. package/dist/commands/pjm/remote/outbound-projection-safety.d.ts +25 -0
  81. package/dist/commands/pjm/remote/outbound-projection-safety.d.ts.map +1 -0
  82. package/dist/commands/pjm/remote/outbound-projection-safety.js +99 -0
  83. package/dist/commands/pjm/remote/output.d.ts +60 -0
  84. package/dist/commands/pjm/remote/output.d.ts.map +1 -0
  85. package/dist/commands/pjm/remote/output.js +48 -0
  86. package/dist/commands/pjm/remote/preview.d.ts +88 -0
  87. package/dist/commands/pjm/remote/preview.d.ts.map +1 -0
  88. package/dist/commands/pjm/remote/preview.js +154 -0
  89. package/dist/commands/pjm/remote/provider-conformance.d.ts +13 -0
  90. package/dist/commands/pjm/remote/provider-conformance.d.ts.map +1 -0
  91. package/dist/commands/pjm/remote/provider-conformance.js +37 -0
  92. package/dist/commands/pjm/remote/provider.d.ts +57 -0
  93. package/dist/commands/pjm/remote/provider.d.ts.map +1 -0
  94. package/dist/commands/pjm/remote/provider.js +28 -0
  95. package/dist/commands/pjm/remote/providers/github-publication-safety.d.ts +46 -0
  96. package/dist/commands/pjm/remote/providers/github-publication-safety.d.ts.map +1 -0
  97. package/dist/commands/pjm/remote/providers/github-publication-safety.js +126 -0
  98. package/dist/commands/pjm/remote/providers/github.d.ts +207 -0
  99. package/dist/commands/pjm/remote/providers/github.d.ts.map +1 -0
  100. package/dist/commands/pjm/remote/providers/github.js +1456 -0
  101. package/dist/commands/pjm/remote/providers/jira.d.ts +245 -0
  102. package/dist/commands/pjm/remote/providers/jira.d.ts.map +1 -0
  103. package/dist/commands/pjm/remote/providers/jira.js +1650 -0
  104. package/dist/commands/pjm/remote/providers/linear.d.ts +182 -0
  105. package/dist/commands/pjm/remote/providers/linear.d.ts.map +1 -0
  106. package/dist/commands/pjm/remote/providers/linear.js +1289 -0
  107. package/dist/commands/pjm/remote/purpose-policy.d.ts +29 -0
  108. package/dist/commands/pjm/remote/purpose-policy.d.ts.map +1 -0
  109. package/dist/commands/pjm/remote/purpose-policy.js +118 -0
  110. package/dist/commands/pjm/remote/reconcile.d.ts +42 -0
  111. package/dist/commands/pjm/remote/reconcile.d.ts.map +1 -0
  112. package/dist/commands/pjm/remote/reconcile.js +101 -0
  113. package/dist/commands/pjm/remote/resolution.d.ts +122 -0
  114. package/dist/commands/pjm/remote/resolution.d.ts.map +1 -0
  115. package/dist/commands/pjm/remote/resolution.js +243 -0
  116. package/dist/commands/pjm/remote/schema.d.ts +9309 -0
  117. package/dist/commands/pjm/remote/schema.d.ts.map +1 -0
  118. package/dist/commands/pjm/remote/schema.js +1503 -0
  119. package/dist/commands/pjm/remote/service.d.ts +20 -0
  120. package/dist/commands/pjm/remote/service.d.ts.map +1 -0
  121. package/dist/commands/pjm/remote/service.js +5121 -0
  122. package/dist/commands/pjm/remote/shared-storage.d.ts +36 -0
  123. package/dist/commands/pjm/remote/shared-storage.d.ts.map +1 -0
  124. package/dist/commands/pjm/remote/shared-storage.js +110 -0
  125. package/dist/commands/pjm/remote/snapshot.d.ts +32 -0
  126. package/dist/commands/pjm/remote/snapshot.d.ts.map +1 -0
  127. package/dist/commands/pjm/remote/snapshot.js +140 -0
  128. package/dist/commands/pjm/remote/storage-locator.d.ts +29 -0
  129. package/dist/commands/pjm/remote/storage-locator.d.ts.map +1 -0
  130. package/dist/commands/pjm/remote/storage-locator.js +62 -0
  131. package/dist/commands/pjm/remote/store.d.ts +85 -0
  132. package/dist/commands/pjm/remote/store.d.ts.map +1 -0
  133. package/dist/commands/pjm/remote/store.js +553 -0
  134. package/dist/commands/pjm/remote/verification.d.ts +40 -0
  135. package/dist/commands/pjm/remote/verification.d.ts.map +1 -0
  136. package/dist/commands/pjm/remote/verification.js +100 -0
  137. package/dist/commands/tools/shared/pack-manifest.d.ts.map +1 -1
  138. package/dist/commands/tools/shared/pack-manifest.js +1 -0
  139. package/dist/config/oat-config.d.ts +26 -0
  140. package/dist/config/oat-config.d.ts.map +1 -1
  141. package/dist/config/oat-config.js +186 -2
  142. package/package.json +2 -2
@@ -0,0 +1,380 @@
1
+ import { readFile, readdir } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { RemoteBindingMetadataSchema, RemoteBindingStateSchema, RemoteOperationRecordSchema, assertRecordIdMatchesFilename, } from './schema.js';
4
+ const REMOTE_CONTEXT_FIELDS = [
5
+ 'host',
6
+ 'owner',
7
+ 'repositoryId',
8
+ 'workspaceId',
9
+ 'teamId',
10
+ 'cloudId',
11
+ 'siteId',
12
+ 'projectId',
13
+ ];
14
+ export async function runRemoteDoctorChecks(input) {
15
+ const [metadataFiles, stateFiles, operationFiles] = await Promise.all([
16
+ loadRecords(input.portableBindingsDir, RemoteBindingMetadataSchema),
17
+ loadRecords(input.operationalBindingsDir, RemoteBindingStateSchema),
18
+ loadRecords(input.operationsDir, RemoteOperationRecordSchema),
19
+ ]);
20
+ const adopted = metadataFiles.length > 0 ||
21
+ stateFiles.length > 0 ||
22
+ operationFiles.length > 0 ||
23
+ (input.associatedBindingIds?.length ?? 0) > 0 ||
24
+ input.policy !== undefined ||
25
+ (input.retentionBreaches?.length ?? 0) > 0 ||
26
+ (input.hostCapabilityAvailability?.length ?? 0) > 0;
27
+ if (!adopted)
28
+ return [];
29
+ const schemaFindings = collectSchemaFindings(metadataFiles, stateFiles, operationFiles);
30
+ const metadata = metadataFiles.flatMap((file) => file.parsed ? [file.parsed] : []);
31
+ const states = stateFiles.flatMap((file) => file.parsed ? [file.parsed] : []);
32
+ const operations = operationFiles.flatMap((file) => file.parsed ? [file.parsed] : []);
33
+ const identityFindings = collectIdentityFindings(metadata, states, input.associatedBindingIds ?? []);
34
+ const metadataStateFindings = collectMetadataStateFindings(metadata, states);
35
+ const forbiddenContent = metadataFiles
36
+ .filter((file) => containsForbiddenPortableKey(file.raw))
37
+ .map((file) => file.filename);
38
+ const policyFindings = collectRemotePolicyFindings(input.policy);
39
+ const concurrentBindings = collectConcurrentBindings(operations);
40
+ const operationalFindings = collectOperationalFindings(operations, input);
41
+ const retentionFindings = [...(input.retentionBreaches ?? [])].sort();
42
+ const unavailableCapabilities = (input.hostCapabilityAvailability ?? [])
43
+ .filter((entry) => !entry.available)
44
+ .map((entry) => entry.bindingId)
45
+ .sort();
46
+ if (input.evidenceAvailability?.associations === false) {
47
+ identityFindings.push('association-evidence-unavailable');
48
+ }
49
+ if (input.evidenceAvailability?.retention === false) {
50
+ retentionFindings.push('retention-evidence-unavailable');
51
+ }
52
+ if (input.evidenceAvailability?.hostCapabilities === false) {
53
+ unavailableCapabilities.push('host-capability-evidence-unavailable');
54
+ }
55
+ return [
56
+ findingCheck('pjm:remote_schema', 'Remote record schema and filename identity', schemaFindings),
57
+ findingCheck('pjm:remote_binding_ids', 'Remote binding references and stable identities', identityFindings),
58
+ findingCheck('pjm:remote_metadata_state', 'Portable metadata and operational state agreement', metadataStateFindings),
59
+ findingCheck('pjm:remote_storage_content', 'Portable metadata excludes operational or sensitive content', forbiddenContent),
60
+ {
61
+ name: 'pjm:remote_policy',
62
+ description: 'Remote repository policy is valid and fail-closed',
63
+ status: policyFindings.length === 0 ? 'pass' : 'fail',
64
+ message: policyFindings.length === 0
65
+ ? 'Remote policy is valid or not configured.'
66
+ : `Remote policy contains invalid or unknown fields: ${policyFindings.join(', ')}.`,
67
+ fix: policyFindings.length === 0
68
+ ? undefined
69
+ : 'Repair pjm.remote policy in shared .oat/config.json before any remote mutation.',
70
+ },
71
+ findingCheck('pjm:remote_concurrent_intents', 'Concurrent active remote operation intents', concurrentBindings),
72
+ findingCheck('pjm:remote_operations', 'Remote operation freshness, terminal state, and verification evidence', operationalFindings),
73
+ findingCheck('pjm:remote_retention', 'Remote operational-state retention boundary', retentionFindings),
74
+ findingCheck('pjm:remote_host_capability', 'Current host semantic capability availability', unavailableCapabilities),
75
+ ];
76
+ }
77
+ function collectOperationalFindings(operations, input) {
78
+ const findings = [];
79
+ const visibleStates = new Set([
80
+ 'pending',
81
+ 'partial',
82
+ 'uncertain',
83
+ 'attempt-started',
84
+ 'verification-pending',
85
+ ]);
86
+ const now = input.now ? Date.parse(input.now) : Number.NaN;
87
+ const staleAfterMs = input.staleAfterMs ?? Number.POSITIVE_INFINITY;
88
+ for (const operation of operations) {
89
+ if (visibleStates.has(operation.state)) {
90
+ findings.push(`${operation.operationId}:${operation.state}`);
91
+ }
92
+ const age = now - Date.parse(operation.updatedAt);
93
+ if (Number.isFinite(age) && age > staleAfterMs) {
94
+ findings.push(`${operation.operationId}:stale`);
95
+ }
96
+ if (operation.state === 'verified' && operation.verification.length === 0) {
97
+ findings.push(`${operation.operationId}:missing-verification`);
98
+ }
99
+ }
100
+ return [...new Set(findings)].sort();
101
+ }
102
+ async function loadRecords(directory, schema) {
103
+ let filenames;
104
+ try {
105
+ filenames = (await readdir(directory)).filter((name) => name.endsWith('.json'));
106
+ }
107
+ catch (error) {
108
+ if (isFilesystemError(error, 'ENOENT'))
109
+ return [];
110
+ throw error;
111
+ }
112
+ const records = [];
113
+ for (const filename of filenames.sort()) {
114
+ let raw = null;
115
+ try {
116
+ raw = JSON.parse(await readFile(join(directory, filename), 'utf8'));
117
+ }
118
+ catch {
119
+ records.push({ filename, raw: null, parsed: null });
120
+ continue;
121
+ }
122
+ const result = schema.safeParse(raw);
123
+ records.push({
124
+ filename,
125
+ raw,
126
+ parsed: result.success ? result.data : null,
127
+ });
128
+ }
129
+ return records;
130
+ }
131
+ function collectSchemaFindings(metadata, states, operations) {
132
+ const findings = [];
133
+ for (const [files, idFor] of [
134
+ [metadata, (record) => record.bindingId],
135
+ [states, (record) => record.bindingId],
136
+ [operations, (record) => record.operationId],
137
+ ]) {
138
+ for (const file of files) {
139
+ if (!file.parsed) {
140
+ findings.push(file.filename);
141
+ continue;
142
+ }
143
+ try {
144
+ assertRecordIdMatchesFilename(file.filename, idFor(file.parsed));
145
+ }
146
+ catch {
147
+ findings.push(file.filename);
148
+ }
149
+ }
150
+ }
151
+ return findings;
152
+ }
153
+ function collectIdentityFindings(metadata, states, associatedBindingIds) {
154
+ const findings = [];
155
+ const known = new Set(metadata.map((record) => record.bindingId));
156
+ for (const bindingId of associatedBindingIds) {
157
+ if (!known.has(bindingId))
158
+ findings.push(`dangling:${bindingId}`);
159
+ }
160
+ for (const state of states) {
161
+ if (!known.has(state.bindingId))
162
+ findings.push(`dangling-state:${state.bindingId}`);
163
+ }
164
+ const byIdentity = new Map();
165
+ for (const record of metadata) {
166
+ const key = `${record.provider}:${record.remoteIdentity.stableId}`;
167
+ const ids = byIdentity.get(key) ?? [];
168
+ ids.push(record.bindingId);
169
+ byIdentity.set(key, ids);
170
+ }
171
+ for (const ids of byIdentity.values()) {
172
+ if (ids.length > 1)
173
+ findings.push(`duplicate:${ids.join(',')}`);
174
+ }
175
+ return findings;
176
+ }
177
+ function collectMetadataStateFindings(metadata, states) {
178
+ const metadataById = new Map(metadata.map((record) => [record.bindingId, record]));
179
+ const statesById = new Map(states.map((record) => [record.bindingId, record]));
180
+ const findings = [];
181
+ for (const record of metadata) {
182
+ const state = statesById.get(record.bindingId);
183
+ if (!state)
184
+ continue;
185
+ if (state.metadataUpdatedAt !== record.updatedAt) {
186
+ findings.push(`${record.bindingId}:metadata-timestamp`);
187
+ }
188
+ if (state.provider !== record.provider) {
189
+ findings.push(`${record.bindingId}:provider`);
190
+ }
191
+ if (state.snapshot) {
192
+ if (state.snapshot.identity.stableId !== record.remoteIdentity.stableId) {
193
+ findings.push(`${record.bindingId}:identity`);
194
+ }
195
+ if (!remoteContextsMatch(state.snapshot.identity.context, record.remoteIdentity.context)) {
196
+ findings.push(`${record.bindingId}:identity-context`);
197
+ }
198
+ }
199
+ if (state.capability &&
200
+ !remoteContextsMatch(state.capability.context, record.remoteIdentity.context)) {
201
+ findings.push(`${record.bindingId}:capability-context`);
202
+ }
203
+ }
204
+ for (const state of states) {
205
+ if (!metadataById.has(state.bindingId))
206
+ findings.push(state.bindingId);
207
+ }
208
+ return [...new Set(findings)];
209
+ }
210
+ function remoteContextsMatch(left, right) {
211
+ return REMOTE_CONTEXT_FIELDS.every((field) => left[field] === right[field]);
212
+ }
213
+ function containsForbiddenPortableKey(value, path = []) {
214
+ if (Array.isArray(value)) {
215
+ return value.some((entry) => containsForbiddenPortableKey(entry, path));
216
+ }
217
+ if (!isRecord(value))
218
+ return false;
219
+ const forbidden = new Set([
220
+ 'snapshot',
221
+ 'baseline',
222
+ 'attempts',
223
+ 'receipt',
224
+ 'rawPayload',
225
+ 'credential',
226
+ 'authorization',
227
+ ]);
228
+ return Object.entries(value).some(([key, child]) => forbidden.has(key) ||
229
+ (key === 'description' && path.length === 0) ||
230
+ containsForbiddenPortableKey(child, [...path, key]));
231
+ }
232
+ function collectRemotePolicyFindings(value) {
233
+ if (value === undefined)
234
+ return [];
235
+ const findings = [];
236
+ if (!isRecord(value))
237
+ return ['pjm.remote'];
238
+ collectUnknownKeys(value, ['schemaVersion', 'storage', 'policy'], 'pjm.remote', findings);
239
+ if (value.schemaVersion !== 1)
240
+ findings.push('pjm.remote.schemaVersion');
241
+ if ('storage' in value) {
242
+ if (!isRecord(value.storage)) {
243
+ findings.push('pjm.remote.storage');
244
+ }
245
+ else {
246
+ collectUnknownKeys(value.storage, ['state'], 'pjm.remote.storage', findings);
247
+ if (!['local', 'shared'].includes(String(value.storage.state))) {
248
+ findings.push('pjm.remote.storage.state');
249
+ }
250
+ }
251
+ }
252
+ if (!isRecord(value.policy)) {
253
+ findings.push('pjm.remote.policy');
254
+ return [...new Set(findings)];
255
+ }
256
+ collectUnknownKeys(value.policy, ['description', 'authority', 'providers'], 'pjm.remote.policy', findings);
257
+ if (!isDescriptionMode(value.policy.description)) {
258
+ findings.push('pjm.remote.policy.description');
259
+ }
260
+ collectAuthorityFindings(value.policy.authority, 'pjm.remote.policy.authority', findings, true);
261
+ if ('providers' in value.policy) {
262
+ if (!isRecord(value.policy.providers)) {
263
+ findings.push('pjm.remote.policy.providers');
264
+ }
265
+ else {
266
+ const providers = new Set(['github', 'linear', 'jira']);
267
+ for (const [provider, providerPolicy] of Object.entries(value.policy.providers)) {
268
+ const path = `pjm.remote.policy.providers.${provider}`;
269
+ if (!providers.has(provider) || !isRecord(providerPolicy)) {
270
+ findings.push(path);
271
+ continue;
272
+ }
273
+ collectUnknownKeys(providerPolicy, ['description', 'authority'], path, findings);
274
+ if ('description' in providerPolicy &&
275
+ !isDescriptionMode(providerPolicy.description)) {
276
+ findings.push(`${path}.description`);
277
+ }
278
+ if ('authority' in providerPolicy) {
279
+ collectAuthorityFindings(providerPolicy.authority, `${path}.authority`, findings, false);
280
+ }
281
+ }
282
+ }
283
+ }
284
+ return [...new Set(findings)].sort();
285
+ }
286
+ function collectAuthorityFindings(value, path, findings, requireDefault) {
287
+ if (!isRecord(value)) {
288
+ findings.push(path);
289
+ return;
290
+ }
291
+ collectUnknownKeys(value, ['default', 'operations'], path, findings);
292
+ if (requireDefault && !('default' in value))
293
+ findings.push(`${path}.default`);
294
+ if ('default' in value && !isAuthority(value.default)) {
295
+ findings.push(`${path}.default`);
296
+ }
297
+ if ('operations' in value) {
298
+ if (!isRecord(value.operations)) {
299
+ findings.push(`${path}.operations`);
300
+ return;
301
+ }
302
+ const operations = new Set([
303
+ 'create',
304
+ 'update-fields',
305
+ 'transition',
306
+ 'annotate',
307
+ 'delete',
308
+ 'relink',
309
+ 'detach',
310
+ 'recreate',
311
+ ]);
312
+ for (const [operation, authority] of Object.entries(value.operations)) {
313
+ const operationPath = `${path}.operations.${operation}`;
314
+ if (!operations.has(operation) || !isAuthority(authority)) {
315
+ findings.push(operationPath);
316
+ }
317
+ }
318
+ }
319
+ }
320
+ function collectUnknownKeys(value, allowed, path, findings) {
321
+ const keys = new Set(allowed);
322
+ for (const key of Object.keys(value)) {
323
+ if (!keys.has(key))
324
+ findings.push(`${path}.${key}`);
325
+ }
326
+ }
327
+ function isDescriptionMode(value) {
328
+ return ['none', 'managed-section', 'replace'].includes(String(value));
329
+ }
330
+ function isAuthority(value) {
331
+ return [
332
+ 'read-only',
333
+ 'user-approved',
334
+ 'user-authorized',
335
+ 'autonomous',
336
+ ].includes(String(value));
337
+ }
338
+ function collectConcurrentBindings(operations) {
339
+ const counts = new Map();
340
+ const active = new Set([
341
+ 'planned',
342
+ 'pending',
343
+ 'authorized',
344
+ 'attempt-started',
345
+ 'verification-pending',
346
+ 'partial',
347
+ 'uncertain',
348
+ ]);
349
+ for (const operation of operations) {
350
+ if (active.has(operation.state)) {
351
+ counts.set(operation.bindingId, (counts.get(operation.bindingId) ?? 0) + 1);
352
+ }
353
+ }
354
+ return [...counts.entries()]
355
+ .filter(([, count]) => count > 1)
356
+ .map(([bindingId]) => bindingId)
357
+ .sort();
358
+ }
359
+ function findingCheck(name, description, findings) {
360
+ return {
361
+ name,
362
+ description,
363
+ status: findings.length === 0 ? 'pass' : 'fail',
364
+ message: findings.length === 0
365
+ ? `${description} passed.`
366
+ : `${description} findings: ${findings.join(', ')}`,
367
+ fix: findings.length === 0
368
+ ? undefined
369
+ : 'Inspect the named local record identifiers and reconcile them before remote mutation.',
370
+ };
371
+ }
372
+ function isRecord(value) {
373
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
374
+ }
375
+ function isFilesystemError(error, code) {
376
+ return (typeof error === 'object' &&
377
+ error !== null &&
378
+ 'code' in error &&
379
+ error.code === code);
380
+ }
@@ -0,0 +1,208 @@
1
+ import { z } from 'zod';
2
+ import { type OutboundProjection, type OutboundProjectionSafetyResult } from './outbound-projection-safety.js';
3
+ import { RemoteAccountContextSchema } from './schema.js';
4
+ declare const SuppressedFieldReferenceSchema: z.ZodDiscriminatedUnion<"kind", [z.ZodObject<{
5
+ kind: z.ZodLiteral<"core">;
6
+ name: z.ZodEnum<["title", "description", "priority", "status"]>;
7
+ }, "strict", z.ZodTypeAny, {
8
+ kind: "core";
9
+ name: "description" | "priority" | "status" | "title";
10
+ }, {
11
+ kind: "core";
12
+ name: "description" | "priority" | "status" | "title";
13
+ }>, z.ZodObject<{
14
+ kind: z.ZodLiteral<"extension">;
15
+ key: z.ZodString;
16
+ }, "strict", z.ZodTypeAny, {
17
+ kind: "extension";
18
+ key: string;
19
+ }, {
20
+ kind: "extension";
21
+ key: string;
22
+ }>]>;
23
+ declare const SemanticOperationSchema: z.ZodEnum<["read", "read-discussion", "search-duplicates", "create", "update", "transition", "annotate"]>;
24
+ export declare const ExternalObservationEnvelopeSchema: z.ZodObject<{
25
+ schemaVersion: z.ZodLiteral<1>;
26
+ operationId: z.ZodString;
27
+ stepId: z.ZodString;
28
+ actionDigest: z.ZodString;
29
+ observedAt: z.ZodString;
30
+ surfaceKind: z.ZodEnum<["connector", "configured-cli"]>;
31
+ capabilityEvidenceDigest: z.ZodString;
32
+ provider: z.ZodEnum<["github", "linear", "jira"]>;
33
+ context: z.ZodObject<{
34
+ host: z.ZodOptional<z.ZodString>;
35
+ owner: z.ZodOptional<z.ZodString>;
36
+ repositoryId: z.ZodOptional<z.ZodString>;
37
+ workspaceId: z.ZodOptional<z.ZodString>;
38
+ teamId: z.ZodOptional<z.ZodString>;
39
+ cloudId: z.ZodOptional<z.ZodString>;
40
+ siteId: z.ZodOptional<z.ZodString>;
41
+ projectId: z.ZodOptional<z.ZodString>;
42
+ }, "strict", z.ZodTypeAny, {
43
+ host?: string | undefined;
44
+ owner?: string | undefined;
45
+ repositoryId?: string | undefined;
46
+ workspaceId?: string | undefined;
47
+ teamId?: string | undefined;
48
+ cloudId?: string | undefined;
49
+ siteId?: string | undefined;
50
+ projectId?: string | undefined;
51
+ }, {
52
+ host?: string | undefined;
53
+ owner?: string | undefined;
54
+ repositoryId?: string | undefined;
55
+ workspaceId?: string | undefined;
56
+ teamId?: string | undefined;
57
+ cloudId?: string | undefined;
58
+ siteId?: string | undefined;
59
+ projectId?: string | undefined;
60
+ }>;
61
+ outcome: z.ZodObject<{
62
+ classification: z.ZodEnum<["observed", "not-committed", "unknown", "rejected"]>;
63
+ identity: z.ZodNullable<z.ZodObject<{
64
+ stableId: z.ZodString;
65
+ aliases: z.ZodArray<z.ZodString, "many">;
66
+ }, "strict", z.ZodTypeAny, {
67
+ stableId: string;
68
+ aliases: string[];
69
+ }, {
70
+ stableId: string;
71
+ aliases: string[];
72
+ }>>;
73
+ fields: z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>>;
74
+ extensions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>>>;
75
+ revisionDigest: z.ZodNullable<z.ZodString>;
76
+ diagnosticCode: z.ZodNullable<z.ZodString>;
77
+ }, "strict", z.ZodTypeAny, {
78
+ classification: "not-committed" | "observed" | "rejected" | "unknown";
79
+ identity: {
80
+ stableId: string;
81
+ aliases: string[];
82
+ } | null;
83
+ fields: Record<string, string | number | boolean | null>;
84
+ extensions?: Record<string, string | number | boolean | null> | undefined;
85
+ revisionDigest: string | null;
86
+ diagnosticCode: string | null;
87
+ }, {
88
+ classification: "not-committed" | "observed" | "rejected" | "unknown";
89
+ identity: {
90
+ stableId: string;
91
+ aliases: string[];
92
+ } | null;
93
+ fields: Record<string, string | number | boolean | null>;
94
+ extensions?: Record<string, string | number | boolean | null> | undefined;
95
+ revisionDigest: string | null;
96
+ diagnosticCode: string | null;
97
+ }>;
98
+ }, "strict", z.ZodTypeAny, {
99
+ schemaVersion: 1;
100
+ operationId: string;
101
+ stepId: string;
102
+ actionDigest: string;
103
+ observedAt: string;
104
+ surfaceKind: "configured-cli" | "connector";
105
+ capabilityEvidenceDigest: string;
106
+ provider: "github" | "jira" | "linear";
107
+ context: {
108
+ host?: string | undefined;
109
+ owner?: string | undefined;
110
+ repositoryId?: string | undefined;
111
+ workspaceId?: string | undefined;
112
+ teamId?: string | undefined;
113
+ cloudId?: string | undefined;
114
+ siteId?: string | undefined;
115
+ projectId?: string | undefined;
116
+ };
117
+ outcome: {
118
+ classification: "not-committed" | "observed" | "rejected" | "unknown";
119
+ identity: {
120
+ stableId: string;
121
+ aliases: string[];
122
+ } | null;
123
+ fields: Record<string, string | number | boolean | null>;
124
+ extensions?: Record<string, string | number | boolean | null> | undefined;
125
+ revisionDigest: string | null;
126
+ diagnosticCode: string | null;
127
+ };
128
+ }, {
129
+ schemaVersion: 1;
130
+ operationId: string;
131
+ stepId: string;
132
+ actionDigest: string;
133
+ observedAt: string;
134
+ surfaceKind: "configured-cli" | "connector";
135
+ capabilityEvidenceDigest: string;
136
+ provider: "github" | "jira" | "linear";
137
+ context: {
138
+ host?: string | undefined;
139
+ owner?: string | undefined;
140
+ repositoryId?: string | undefined;
141
+ workspaceId?: string | undefined;
142
+ teamId?: string | undefined;
143
+ cloudId?: string | undefined;
144
+ siteId?: string | undefined;
145
+ projectId?: string | undefined;
146
+ };
147
+ outcome: {
148
+ classification: "not-committed" | "observed" | "rejected" | "unknown";
149
+ identity: {
150
+ stableId: string;
151
+ aliases: string[];
152
+ } | null;
153
+ fields: Record<string, string | number | boolean | null>;
154
+ extensions?: Record<string, string | number | boolean | null> | undefined;
155
+ revisionDigest: string | null;
156
+ diagnosticCode: string | null;
157
+ };
158
+ }>;
159
+ export interface ExternalActionEnvelope {
160
+ schemaVersion: 1;
161
+ operationId: string;
162
+ stepId: string;
163
+ actionDigest: string;
164
+ provider: 'github' | 'linear' | 'jira';
165
+ semanticOperation: z.infer<typeof SemanticOperationSchema>;
166
+ context: z.infer<typeof RemoteAccountContextSchema>;
167
+ intent: Record<string, unknown>;
168
+ expectedObservation: {
169
+ fields: string[];
170
+ extensionFields?: string[];
171
+ requireIdentity: boolean;
172
+ stableId: string | null;
173
+ capabilityEvidenceDigest: string;
174
+ };
175
+ outboundSafety: {
176
+ projectionDigest: string;
177
+ resultDigest: string;
178
+ } | null;
179
+ }
180
+ export type ExternalObservationEnvelope = z.infer<typeof ExternalObservationEnvelopeSchema>;
181
+ export declare function parseExternalAction(value: unknown): ExternalActionEnvelope;
182
+ export declare function buildExternalAction(input: {
183
+ operationId: string;
184
+ stepId: string;
185
+ provider: ExternalActionEnvelope['provider'];
186
+ semanticOperation: ExternalActionEnvelope['semanticOperation'];
187
+ context: ExternalActionEnvelope['context'];
188
+ intent: Record<string, unknown>;
189
+ expectedObservation: ExternalActionEnvelope['expectedObservation'];
190
+ persistedPreview: {
191
+ projectionDigest?: string | null;
192
+ safetyResultDigest?: string | null;
193
+ };
194
+ projection?: OutboundProjection;
195
+ outboundSafety?: OutboundProjectionSafetyResult | null;
196
+ }): ExternalActionEnvelope;
197
+ export declare function acceptExternalObservation(input: {
198
+ action: ExternalActionEnvelope;
199
+ observation: unknown;
200
+ acceptedStepDigests?: ReadonlySet<string>;
201
+ }): AcceptedExternalObservationEnvelope;
202
+ export interface AcceptedExternalObservationEnvelope extends ExternalObservationEnvelope {
203
+ outcome: ExternalObservationEnvelope['outcome'] & {
204
+ suppressedFields: Array<z.infer<typeof SuppressedFieldReferenceSchema>>;
205
+ };
206
+ }
207
+ export {};
208
+ //# sourceMappingURL=external-action.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"external-action.d.ts","sourceRoot":"","sources":["../../../../src/commands/pjm/remote/external-action.ts"],"names":[],"mappings":"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"}