@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,367 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { z } from 'zod';
3
+ import { containsSensitiveContentSignal, containsSensitiveContentSignalInValue, } from './credential-safety.js';
4
+ import { requireCurrentOutboundSafety, } from './outbound-projection-safety.js';
5
+ import { RemoteAccountContextSchema, WHOLE_FIELD_SUPPRESSION_MARKER, } from './schema.js';
6
+ const MAX_ACTION_BYTES = 65_536;
7
+ const MAX_OBSERVATION_BYTES = 65_536;
8
+ const MAX_VALUE_DEPTH = 6;
9
+ const SemanticFieldNameSchema = z
10
+ .string()
11
+ .min(1)
12
+ .max(64)
13
+ .regex(/^[A-Za-z][A-Za-z0-9_-]*$/);
14
+ const SuppressedFieldReferenceSchema = z.discriminatedUnion('kind', [
15
+ z
16
+ .object({
17
+ kind: z.literal('core'),
18
+ name: z.enum(['title', 'description', 'priority', 'status']),
19
+ })
20
+ .strict(),
21
+ z
22
+ .object({ kind: z.literal('extension'), key: SemanticFieldNameSchema })
23
+ .strict(),
24
+ ]);
25
+ const DurableActionIdSchema = z
26
+ .string()
27
+ .min(1)
28
+ .max(128)
29
+ .regex(/^[A-Za-z0-9][A-Za-z0-9._-]*$/);
30
+ const ProviderSchema = z.enum(['github', 'linear', 'jira']);
31
+ const SemanticOperationSchema = z.enum([
32
+ 'read',
33
+ 'read-discussion',
34
+ 'search-duplicates',
35
+ 'create',
36
+ 'update',
37
+ 'transition',
38
+ 'annotate',
39
+ ]);
40
+ export const ExternalObservationEnvelopeSchema = z
41
+ .object({
42
+ schemaVersion: z.literal(1),
43
+ operationId: DurableActionIdSchema,
44
+ stepId: DurableActionIdSchema,
45
+ actionDigest: z.string().min(1).max(512),
46
+ observedAt: z.string().datetime({ offset: true }),
47
+ surfaceKind: z.enum(['connector', 'configured-cli']),
48
+ capabilityEvidenceDigest: z.string().min(1).max(512),
49
+ provider: ProviderSchema,
50
+ context: RemoteAccountContextSchema,
51
+ outcome: z
52
+ .object({
53
+ classification: z.enum([
54
+ 'observed',
55
+ 'not-committed',
56
+ 'unknown',
57
+ 'rejected',
58
+ ]),
59
+ identity: z
60
+ .object({
61
+ stableId: z.string().min(1).max(512),
62
+ aliases: z.array(z.string().max(2_048)).max(64),
63
+ })
64
+ .strict()
65
+ .nullable(),
66
+ fields: z.record(z.union([z.string(), z.number(), z.boolean(), z.null()])),
67
+ extensions: z
68
+ .record(z.union([z.string(), z.number(), z.boolean(), z.null()]))
69
+ .optional(),
70
+ revisionDigest: z.string().min(1).max(512).nullable(),
71
+ diagnosticCode: z.string().min(1).max(128).nullable(),
72
+ })
73
+ .strict(),
74
+ })
75
+ .strict();
76
+ const WritablePlanningFieldsSchema = z
77
+ .object({
78
+ title: z.string().max(8_192).optional(),
79
+ description: z.string().max(1_048_576).nullable().optional(),
80
+ priority: z.string().max(255).nullable().optional(),
81
+ })
82
+ .strict();
83
+ const IdentityIntentSchema = z
84
+ .object({
85
+ stableId: z.string().min(1).max(512),
86
+ localTarget: z
87
+ .object({
88
+ kind: z.literal('backlog'),
89
+ scope: z.literal('shared'),
90
+ id: z.string().min(1).max(255),
91
+ path: z.string().min(1).max(4_096),
92
+ })
93
+ .strict()
94
+ .optional(),
95
+ })
96
+ .strict();
97
+ const ActionIntentSchemas = {
98
+ read: IdentityIntentSchema,
99
+ 'read-discussion': z
100
+ .object({
101
+ stableId: z.string().min(1).max(512),
102
+ limit: z.number().int().min(1).max(100),
103
+ cursor: z.string().max(512).optional(),
104
+ })
105
+ .strict(),
106
+ 'search-duplicates': z
107
+ .object({ query: z.string().min(1).max(8_192) })
108
+ .strict(),
109
+ create: z
110
+ .object({
111
+ target: z
112
+ .object({
113
+ kind: z.enum(['backlog', 'project']),
114
+ id: z.string().min(1).max(255),
115
+ scope: z.enum(['shared', 'synced', 'local']),
116
+ })
117
+ .strict(),
118
+ fields: WritablePlanningFieldsSchema,
119
+ provenanceToken: z.string().min(1).max(512),
120
+ })
121
+ .strict(),
122
+ update: z
123
+ .object({
124
+ stableId: z.string().min(1).max(512).nullable().optional(),
125
+ fields: WritablePlanningFieldsSchema,
126
+ })
127
+ .strict(),
128
+ transition: z
129
+ .object({
130
+ stableId: z.string().min(1).max(512),
131
+ transition: z.string().min(1).max(255),
132
+ })
133
+ .strict(),
134
+ annotate: z
135
+ .object({
136
+ stableId: z.string().min(1).max(512),
137
+ body: z.string().max(1_048_576),
138
+ })
139
+ .strict(),
140
+ };
141
+ const ExternalActionBaseSchema = z
142
+ .object({
143
+ schemaVersion: z.literal(1),
144
+ operationId: DurableActionIdSchema,
145
+ stepId: DurableActionIdSchema,
146
+ actionDigest: z.string().min(1).max(512),
147
+ provider: ProviderSchema,
148
+ semanticOperation: SemanticOperationSchema,
149
+ context: RemoteAccountContextSchema,
150
+ intent: z.record(z.unknown()),
151
+ expectedObservation: z
152
+ .object({
153
+ fields: z.array(SemanticFieldNameSchema).max(64),
154
+ extensionFields: z.array(SemanticFieldNameSchema).max(32).optional(),
155
+ requireIdentity: z.boolean(),
156
+ stableId: z.string().min(1).max(512).nullable().optional(),
157
+ capabilityEvidenceDigest: z.string().min(1).max(512).optional(),
158
+ })
159
+ .strict(),
160
+ outboundSafety: z
161
+ .object({
162
+ projectionDigest: z.string().min(1).max(512),
163
+ resultDigest: z.string().min(1).max(512),
164
+ })
165
+ .strict()
166
+ .nullable(),
167
+ })
168
+ .strict();
169
+ export function parseExternalAction(value) {
170
+ if (Buffer.byteLength(JSON.stringify(value), 'utf8') > MAX_ACTION_BYTES) {
171
+ throw new Error('External action exceeds the size limit.');
172
+ }
173
+ const action = ExternalActionBaseSchema.parse(value);
174
+ assertDepth(action.intent, 0);
175
+ ActionIntentSchemas[action.semanticOperation].parse(action.intent);
176
+ const { actionDigest, ...body } = action;
177
+ if (digest(body) !== actionDigest) {
178
+ throw new Error('External action digest is stale or mismatched.');
179
+ }
180
+ return action;
181
+ }
182
+ export function buildExternalAction(input) {
183
+ const mutation = ['create', 'update', 'transition', 'annotate'].includes(input.semanticOperation);
184
+ assertDepth(input.intent, 0);
185
+ const intent = ActionIntentSchemas[input.semanticOperation].parse(input.intent);
186
+ let outboundSafety = null;
187
+ if (mutation) {
188
+ if (!input.projection)
189
+ throw new Error('Mutation action requires an explicit outbound projection.');
190
+ if (canonicalJson(writableProjection(input.semanticOperation, intent)) !==
191
+ canonicalJson(input.projection)) {
192
+ throw new Error('Mutation action writable fields must exactly match its gated projection.');
193
+ }
194
+ requireCurrentOutboundSafety(input.projection, input.outboundSafety);
195
+ if (input.persistedPreview.projectionDigest !==
196
+ input.outboundSafety.projectionDigest ||
197
+ input.persistedPreview.safetyResultDigest !==
198
+ input.outboundSafety.resultDigest) {
199
+ throw new Error('Mutation action safety evidence does not match the persisted preview.');
200
+ }
201
+ outboundSafety = {
202
+ projectionDigest: input.outboundSafety.projectionDigest,
203
+ resultDigest: input.outboundSafety.resultDigest,
204
+ };
205
+ }
206
+ const expectedFields = input.expectedObservation.fields.map((field) => SemanticFieldNameSchema.parse(field));
207
+ const expectedExtensionFields = (input.expectedObservation.extensionFields ?? []).map((field) => SemanticFieldNameSchema.parse(field));
208
+ if (new Set(expectedExtensionFields).size !== expectedExtensionFields.length) {
209
+ throw new Error('External action extension fields must be unique and bounded.');
210
+ }
211
+ if (new Set(expectedFields).size !== expectedFields.length ||
212
+ expectedFields.length > 64) {
213
+ throw new Error('External action expected fields must be unique and bounded.');
214
+ }
215
+ if (mutation &&
216
+ expectedFields.some((field) => !Object.hasOwn(input.projection, field))) {
217
+ throw new Error('Mutation action expected fields must match its projection.');
218
+ }
219
+ const actionWithoutDigest = {
220
+ schemaVersion: 1,
221
+ operationId: input.operationId,
222
+ stepId: input.stepId,
223
+ provider: input.provider,
224
+ semanticOperation: SemanticOperationSchema.parse(input.semanticOperation),
225
+ context: RemoteAccountContextSchema.parse(input.context),
226
+ intent,
227
+ expectedObservation: {
228
+ ...input.expectedObservation,
229
+ fields: expectedFields,
230
+ ...(expectedExtensionFields.length > 0
231
+ ? { extensionFields: expectedExtensionFields }
232
+ : {}),
233
+ stableId: input.expectedObservation.stableId,
234
+ capabilityEvidenceDigest: input.expectedObservation.capabilityEvidenceDigest,
235
+ },
236
+ outboundSafety,
237
+ };
238
+ if (Buffer.byteLength(canonicalJson(actionWithoutDigest), 'utf8') >
239
+ MAX_ACTION_BYTES) {
240
+ throw new Error('External action exceeds the size limit.');
241
+ }
242
+ return { ...actionWithoutDigest, actionDigest: digest(actionWithoutDigest) };
243
+ }
244
+ export function acceptExternalObservation(input) {
245
+ const bytes = Buffer.byteLength(JSON.stringify(input.observation), 'utf8');
246
+ if (bytes > MAX_OBSERVATION_BYTES)
247
+ throw new Error('External observation exceeds the size limit.');
248
+ const observation = ExternalObservationEnvelopeSchema.parse(input.observation);
249
+ if (input.acceptedStepDigests?.has(observation.actionDigest)) {
250
+ throw new Error('External observation duplicates an accepted action.');
251
+ }
252
+ if (observation.operationId !== input.action.operationId ||
253
+ observation.stepId !== input.action.stepId ||
254
+ observation.actionDigest !== input.action.actionDigest) {
255
+ throw new Error('External observation is stale or mismatched.');
256
+ }
257
+ if (observation.provider !== input.action.provider ||
258
+ canonicalJson(observation.context) !== canonicalJson(input.action.context)) {
259
+ throw new Error('External observation provider context is mismatched.');
260
+ }
261
+ if (observation.capabilityEvidenceDigest !==
262
+ input.action.expectedObservation.capabilityEvidenceDigest) {
263
+ throw new Error('External observation capability evidence is mismatched.');
264
+ }
265
+ const expected = new Set(input.action.expectedObservation.fields);
266
+ const actual = Object.keys(observation.outcome.fields);
267
+ if (actual.some((field) => !expected.has(field))) {
268
+ throw new Error('External observation contains an unexpected field.');
269
+ }
270
+ const expectedExtensions = new Set(input.action.expectedObservation.extensionFields ?? []);
271
+ const actualExtensions = Object.keys(observation.outcome.extensions ?? {});
272
+ if (actualExtensions.some((field) => !expectedExtensions.has(field))) {
273
+ throw new Error('External observation contains an unexpected adapter extension.');
274
+ }
275
+ if (observation.outcome.classification === 'observed' &&
276
+ input.action.expectedObservation.requireIdentity &&
277
+ !observation.outcome.identity) {
278
+ throw new Error('External observation is missing required identity.');
279
+ }
280
+ if (input.action.expectedObservation.stableId !== null &&
281
+ observation.outcome.identity?.stableId !==
282
+ input.action.expectedObservation.stableId) {
283
+ throw new Error('External observation stable identity is mismatched.');
284
+ }
285
+ if (observation.outcome.identity &&
286
+ [
287
+ observation.outcome.identity.stableId,
288
+ ...observation.outcome.identity.aliases,
289
+ ].some((value) => containsSensitiveContentSignal(value))) {
290
+ throw new Error('External observation identity evidence is unsafe.');
291
+ }
292
+ if (Object.values(observation.context).some((value) => containsSensitiveContentSignal(value))) {
293
+ throw new Error('External observation context evidence is unsafe.');
294
+ }
295
+ if (observation.outcome.diagnosticCode &&
296
+ containsSensitiveContentSignal(observation.outcome.diagnosticCode)) {
297
+ throw new Error('External observation diagnostic evidence is unsafe.');
298
+ }
299
+ const suppressedFields = [];
300
+ const fields = Object.fromEntries(actual.map((field) => {
301
+ const value = observation.outcome.fields[field] ?? null;
302
+ const suppressed = typeof value === 'string' &&
303
+ containsSensitiveContentSignalInValue(value);
304
+ if (suppressed) {
305
+ if (!isCoreObservationField(field)) {
306
+ throw new Error(`Sensitive observation field '${field}' requires a declared adapter extension.`);
307
+ }
308
+ suppressedFields.push({ kind: 'core', name: field });
309
+ }
310
+ return [field, suppressed ? WHOLE_FIELD_SUPPRESSION_MARKER : value];
311
+ }));
312
+ const extensions = Object.fromEntries(actualExtensions.map((key) => {
313
+ const value = observation.outcome.extensions?.[key] ?? null;
314
+ const suppressed = containsSensitiveContentSignalInValue(value);
315
+ if (suppressed)
316
+ suppressedFields.push({ kind: 'extension', key });
317
+ return [key, suppressed ? WHOLE_FIELD_SUPPRESSION_MARKER : value];
318
+ }));
319
+ return {
320
+ ...observation,
321
+ outcome: {
322
+ ...observation.outcome,
323
+ fields,
324
+ ...(actualExtensions.length > 0 ? { extensions } : {}),
325
+ suppressedFields,
326
+ },
327
+ };
328
+ }
329
+ function isCoreObservationField(field) {
330
+ return ['title', 'description', 'priority', 'status'].includes(field);
331
+ }
332
+ function writableProjection(semanticOperation, intent) {
333
+ switch (semanticOperation) {
334
+ case 'create':
335
+ case 'update':
336
+ return intent.fields;
337
+ case 'transition':
338
+ return { status: intent.transition };
339
+ case 'annotate':
340
+ return { annotation: intent.body };
341
+ default:
342
+ return null;
343
+ }
344
+ }
345
+ function assertDepth(value, depth) {
346
+ if (depth > MAX_VALUE_DEPTH)
347
+ throw new Error('External action exceeds the depth limit.');
348
+ if (!value || typeof value !== 'object')
349
+ return;
350
+ for (const item of Object.values(value))
351
+ assertDepth(item, depth + 1);
352
+ }
353
+ function digest(value) {
354
+ return `sha256:${createHash('sha256').update(canonicalJson(value)).digest('hex')}`;
355
+ }
356
+ function canonicalJson(value) {
357
+ return JSON.stringify(value && typeof value === 'object' && !Array.isArray(value)
358
+ ? Object.fromEntries(Object.entries(value)
359
+ .sort(([left], [right]) => left.localeCompare(right))
360
+ .map(([key, item]) => [
361
+ key,
362
+ item && typeof item === 'object'
363
+ ? JSON.parse(canonicalJson(item))
364
+ : item,
365
+ ]))
366
+ : value);
367
+ }
@@ -0,0 +1,28 @@
1
+ import { type ProviderContext, type RemoteProvider, type SemanticOperation } from './provider.js';
2
+ export type HostSurfaceKind = 'connector' | 'configured-cli';
3
+ export interface HostCapabilityEvidence {
4
+ provider: RemoteProvider;
5
+ context: ProviderContext;
6
+ surfaceKind: HostSurfaceKind;
7
+ availability: 'available' | 'authorization-required' | 'unsupported-or-unresolved' | 'disabled';
8
+ semanticCapabilities: SemanticOperation[];
9
+ evidenceDigest: string;
10
+ observedAt: string;
11
+ }
12
+ export declare function parseHostCapabilityEvidence(value: unknown): HostCapabilityEvidence;
13
+ export type HostExecutionSelection = {
14
+ selected: true;
15
+ evidence: HostCapabilityEvidence;
16
+ fallbackUsed: boolean;
17
+ } | {
18
+ selected: false;
19
+ reason: 'unavailable' | 'authorization-required' | 'context-mismatch' | 'capability-missing' | 'disabled' | 'attempt-started';
20
+ };
21
+ export declare function selectHostExecution(input: {
22
+ provider: RemoteProvider;
23
+ context: ProviderContext;
24
+ operation: SemanticOperation;
25
+ candidates: readonly HostCapabilityEvidence[];
26
+ attemptStarted: boolean;
27
+ }): HostExecutionSelection;
28
+ //# sourceMappingURL=host-execution.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host-execution.d.ts","sourceRoot":"","sources":["../../../../src/commands/pjm/remote/host-execution.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACvB,MAAM,YAAY,CAAC;AAGpB,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG,gBAAgB,CAAC;AAE7D,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,cAAc,CAAC;IACzB,OAAO,EAAE,eAAe,CAAC;IACzB,WAAW,EAAE,eAAe,CAAC;IAC7B,YAAY,EACR,WAAW,GACX,wBAAwB,GACxB,2BAA2B,GAC3B,UAAU,CAAC;IACf,oBAAoB,EAAE,iBAAiB,EAAE,CAAC;IAC1C,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;CACpB;AA+BD,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,OAAO,GACb,sBAAsB,CAExB;AAED,MAAM,MAAM,sBAAsB,GAC9B;IAAE,QAAQ,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,sBAAsB,CAAC;IAAC,YAAY,EAAE,OAAO,CAAA;CAAE,GAC3E;IACE,QAAQ,EAAE,KAAK,CAAC;IAChB,MAAM,EACF,aAAa,GACb,wBAAwB,GACxB,kBAAkB,GAClB,oBAAoB,GACpB,UAAU,GACV,iBAAiB,CAAC;CACvB,CAAC;AAEN,wBAAgB,mBAAmB,CAAC,KAAK,EAAE;IACzC,QAAQ,EAAE,cAAc,CAAC;IACzB,OAAO,EAAE,eAAe,CAAC;IACzB,SAAS,EAAE,iBAAiB,CAAC;IAC7B,UAAU,EAAE,SAAS,sBAAsB,EAAE,CAAC;IAC9C,cAAc,EAAE,OAAO,CAAC;CACzB,GAAG,sBAAsB,CA6CzB"}
@@ -0,0 +1,63 @@
1
+ import { z } from 'zod';
2
+ import { contextsEqual, } from './provider.js';
3
+ import { RemoteAccountContextSchema } from './schema.js';
4
+ const HostCapabilityEvidenceSchema = z
5
+ .object({
6
+ provider: z.enum(['github', 'linear', 'jira']),
7
+ context: RemoteAccountContextSchema,
8
+ surfaceKind: z.enum(['connector', 'configured-cli']),
9
+ availability: z.enum([
10
+ 'available',
11
+ 'authorization-required',
12
+ 'unsupported-or-unresolved',
13
+ 'disabled',
14
+ ]),
15
+ semanticCapabilities: z
16
+ .array(z.enum([
17
+ 'read',
18
+ 'read-discussion',
19
+ 'search-duplicates',
20
+ 'create',
21
+ 'update',
22
+ 'transition',
23
+ 'annotate',
24
+ ]))
25
+ .max(32),
26
+ evidenceDigest: z.string().min(1).max(512),
27
+ observedAt: z.string().datetime({ offset: true }),
28
+ })
29
+ .strict();
30
+ export function parseHostCapabilityEvidence(value) {
31
+ return HostCapabilityEvidenceSchema.parse(value);
32
+ }
33
+ export function selectHostExecution(input) {
34
+ const relevant = input.candidates.filter((candidate) => candidate.provider === input.provider);
35
+ if (relevant.some((candidate) => candidate.availability === 'disabled')) {
36
+ return { selected: false, reason: 'disabled' };
37
+ }
38
+ if (input.attemptStarted)
39
+ return { selected: false, reason: 'attempt-started' };
40
+ const contextual = relevant.filter((candidate) => contextsEqual(candidate.context, input.context));
41
+ if (relevant.length > 0 && contextual.length === 0) {
42
+ return { selected: false, reason: 'context-mismatch' };
43
+ }
44
+ const capable = contextual.filter((candidate) => candidate.semanticCapabilities.includes(input.operation));
45
+ if (contextual.length > 0 && capable.length === 0) {
46
+ return { selected: false, reason: 'capability-missing' };
47
+ }
48
+ const available = capable.filter((candidate) => candidate.availability === 'available');
49
+ const connector = available.find((candidate) => candidate.surfaceKind === 'connector');
50
+ const selected = connector ??
51
+ available.find((candidate) => candidate.surfaceKind === 'configured-cli');
52
+ if (selected) {
53
+ return {
54
+ selected: true,
55
+ evidence: selected,
56
+ fallbackUsed: selected.surfaceKind === 'configured-cli',
57
+ };
58
+ }
59
+ if (capable.some((candidate) => candidate.availability === 'authorization-required')) {
60
+ return { selected: false, reason: 'authorization-required' };
61
+ }
62
+ return { selected: false, reason: 'unavailable' };
63
+ }
@@ -0,0 +1,41 @@
1
+ import { Command } from 'commander';
2
+ import { type RemoteCommandEnvelope } from './output.js';
3
+ export type RemoteLifecycleOperation = 'intake' | 'publish' | 'refresh' | 'reconcile' | 'closeout' | 'discussion' | 'resolve' | 'doctor' | 'migrate' | 'storage-transition' | 'operation-continue';
4
+ export interface RemoteCommandRequest {
5
+ operation: RemoteLifecycleOperation;
6
+ projectRoot: string;
7
+ bindingId?: string;
8
+ operationId?: string;
9
+ previewOperationId?: string;
10
+ providerRef?: string;
11
+ backlogId?: string;
12
+ projectPath?: string;
13
+ discussionLimit?: number;
14
+ resolutionKind?: 'relink' | 'detach' | 'recreate';
15
+ migrationMode?: 'check' | 'apply';
16
+ migrationApprovalDigest?: string;
17
+ createTarget?: {
18
+ provider: string;
19
+ localKind: 'backlog' | 'project';
20
+ localId: string;
21
+ publicationFile?: string;
22
+ };
23
+ observationStdin?: boolean;
24
+ capabilityEvidenceStdin?: boolean;
25
+ authorityEvidenceFile?: string;
26
+ storage?: {
27
+ repositoryFingerprint: string;
28
+ configTarget: string;
29
+ currentMode: 'local' | 'shared';
30
+ proposedPaths: string[];
31
+ apply: boolean;
32
+ };
33
+ storageApprovalDigest?: string;
34
+ }
35
+ export interface PjmRemoteCommandDependencies {
36
+ resolveProjectRoot(cwd: string): Promise<string>;
37
+ checkAdoption(projectRoot: string): Promise<'complete' | 'partial' | 'absent'>;
38
+ run(request: RemoteCommandRequest): Promise<RemoteCommandEnvelope>;
39
+ }
40
+ export declare function createPjmRemoteCommand(overrides?: Partial<PjmRemoteCommandDependencies>): Command;
41
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/pjm/remote/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,OAAO,EAAuB,KAAK,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAG3E,MAAM,MAAM,wBAAwB,GAChC,QAAQ,GACR,SAAS,GACT,SAAS,GACT,WAAW,GACX,UAAU,GACV,YAAY,GACZ,SAAS,GACT,QAAQ,GACR,SAAS,GACT,oBAAoB,GACpB,oBAAoB,CAAC;AAEzB,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,wBAAwB,CAAC;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,UAAU,CAAC;IAClD,aAAa,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IAClC,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,YAAY,CAAC,EAAE;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,SAAS,GAAG,SAAS,CAAC;QACjC,OAAO,EAAE,MAAM,CAAC;QAChB,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;IACF,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,OAAO,CAAC,EAAE;QACR,qBAAqB,EAAE,MAAM,CAAC;QAC9B,YAAY,EAAE,MAAM,CAAC;QACrB,WAAW,EAAE,OAAO,GAAG,QAAQ,CAAC;QAChC,aAAa,EAAE,MAAM,EAAE,CAAC;QACxB,KAAK,EAAE,OAAO,CAAC;KAChB,CAAC;IACF,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,4BAA4B;IAC3C,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACjD,aAAa,CACX,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC,CAAC;IAC9C,GAAG,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACpE;AAkBD,wBAAgB,sBAAsB,CACpC,SAAS,GAAE,OAAO,CAAC,4BAA4B,CAAM,GACpD,OAAO,CA+WT"}