@skrr-ai/cli 0.1.17 → 0.1.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +7 -4
  2. package/dist/commands/commitments/action-proposals/decide.d.ts +13 -0
  3. package/dist/commands/commitments/action-proposals/decide.js +41 -0
  4. package/dist/commands/commitments/action-proposals/execute.d.ts +12 -0
  5. package/dist/commands/commitments/action-proposals/execute.js +29 -0
  6. package/dist/commands/commitments/action-proposals.d.ts +13 -0
  7. package/dist/commands/commitments/action-proposals.js +56 -0
  8. package/dist/commands/commitments/autonomy.d.ts +7 -11
  9. package/dist/commands/commitments/autonomy.js +16 -25
  10. package/dist/commands/commitments/bundle.d.ts +14 -0
  11. package/dist/commands/commitments/bundle.js +49 -0
  12. package/dist/commands/commitments/create.d.ts +25 -0
  13. package/dist/commands/commitments/create.js +200 -23
  14. package/dist/commands/commitments/delivery.d.ts +16 -0
  15. package/dist/commands/commitments/delivery.js +71 -0
  16. package/dist/commands/commitments/doctor.d.ts +1 -0
  17. package/dist/commands/commitments/doctor.js +33 -17
  18. package/dist/commands/commitments/effective-policy.d.ts +2 -0
  19. package/dist/commands/commitments/effective-policy.js +50 -5
  20. package/dist/commands/commitments/endpoints/connect.d.ts +3 -10
  21. package/dist/commands/commitments/endpoints/connect.js +6 -37
  22. package/dist/commands/commitments/endpoints/create.d.ts +2 -9
  23. package/dist/commands/commitments/endpoints/create.js +10 -23
  24. package/dist/commands/commitments/mode.d.ts +15 -0
  25. package/dist/commands/commitments/mode.js +57 -0
  26. package/dist/commands/commitments/pack/promote.d.ts +1 -1
  27. package/dist/commands/commitments/pack/promote.js +7 -3
  28. package/dist/commands/commitments/pack/shadow.d.ts +3 -2
  29. package/dist/commands/commitments/pack/shadow.js +6 -4
  30. package/dist/commands/commitments/patch.d.ts +14 -0
  31. package/dist/commands/commitments/patch.js +51 -0
  32. package/dist/commands/commitments/preflight.d.ts +2 -1
  33. package/dist/commands/commitments/preflight.js +23 -4
  34. package/dist/commands/commitments/receipt.d.ts +15 -0
  35. package/dist/commands/commitments/receipt.js +34 -0
  36. package/dist/commands/commitments/remediate.d.ts +0 -1
  37. package/dist/commands/commitments/remediate.js +5 -3
  38. package/dist/commands/commitments/reports.js +12 -3
  39. package/dist/commands/commitments/show.d.ts +1 -0
  40. package/dist/commands/commitments/show.js +22 -1
  41. package/dist/commands/commitments/update.js +4 -2
  42. package/dist/commands/commitments/wake-capabilities.d.ts +5 -0
  43. package/dist/commands/commitments/wake-capabilities.js +23 -7
  44. package/dist/commands/spaces/bootstrap.js +1 -1
  45. package/dist/lib/commitment-endpoints.d.ts +3 -2
  46. package/dist/lib/commitment-endpoints.js +12 -9
  47. package/dist/lib/commitment-product.d.ts +14 -0
  48. package/dist/lib/commitment-product.js +78 -0
  49. package/dist/lib/commitments.d.ts +39 -17
  50. package/dist/lib/commitments.js +70 -29
  51. package/dist/node_modules/@skrr-ai/data-provider/index.js +3551 -3461
  52. package/oclif.manifest.json +19993 -19322
  53. package/package.json +1 -1
@@ -1,12 +1,136 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.hasEventCapableWatchedSource = hasEventCapableWatchedSource;
4
+ exports.assertEventDrivenWatchedSource = assertEventDrivenWatchedSource;
5
+ exports.createCadenceFromFlags = createCadenceFromFlags;
3
6
  exports.autonomyStagingNotice = autonomyStagingNotice;
4
7
  const core_1 = require("@oclif/core");
5
8
  const base_command_1 = require("../../base-command");
6
9
  const web_url_1 = require("../../lib/web-url");
7
10
  const prompt_1 = require("../../lib/prompt");
8
11
  const triggers_1 = require("../../lib/triggers");
12
+ const commitment_product_1 = require("../../lib/commitment-product");
9
13
  const commitments_1 = require("../../lib/commitments");
14
+ const DEFAULT_EVENT_DRIVEN_BACKSTOP_MS = 24 * 60 * 60 * 1000;
15
+ const DEFAULT_EVENT_SOURCES = new Set(['github', 'slack', 'email', 'calendar']);
16
+ function record(value) {
17
+ return value && typeof value === 'object' && !Array.isArray(value)
18
+ ? value
19
+ : undefined;
20
+ }
21
+ function configuredId(config, ...keys) {
22
+ return keys.some((key) => {
23
+ const value = config?.[key];
24
+ return typeof value === 'string' && value.trim().length > 0;
25
+ });
26
+ }
27
+ function hasStructurallyValidExplicitEvent(config) {
28
+ const events = config?.events;
29
+ if (!Array.isArray(events))
30
+ return false;
31
+ return events.some((value) => {
32
+ const event = record(value);
33
+ if (!event)
34
+ return false;
35
+ if (typeof event.entityType !== 'string' || !event.entityType.trim())
36
+ return false;
37
+ if (typeof event.eventType !== 'string' || !event.eventType.trim())
38
+ return false;
39
+ if (event.filterField === undefined)
40
+ return true;
41
+ if (typeof event.filterField !== 'string')
42
+ return false;
43
+ return !event.filterField
44
+ .split('.')
45
+ .some((part) => ['__proto__', 'constructor', 'prototype'].includes(part));
46
+ });
47
+ }
48
+ /**
49
+ * True only when the authored create body can materialize at least one event
50
+ * binding. A polling-only source must not make `--event-driven` look successful
51
+ * while the resulting Commitment still wakes exclusively on its backstop.
52
+ */
53
+ function hasEventCapableWatchedSource(payload) {
54
+ const goalId = typeof payload.goalId === 'string' && payload.goalId.trim().length > 0;
55
+ const watchedSources = Array.isArray(payload.watchedSources) ? payload.watchedSources : [];
56
+ return watchedSources.some((value) => {
57
+ const sourceEntry = record(value);
58
+ if (!sourceEntry || sourceEntry.enabled === false || typeof sourceEntry.source !== 'string') {
59
+ return false;
60
+ }
61
+ const source = sourceEntry.source;
62
+ const config = record(sourceEntry.config);
63
+ // For these four sources, TriggerSync owns a default event family. An
64
+ // explicit empty or malformed event list intentionally suppresses it.
65
+ if (DEFAULT_EVENT_SOURCES.has(source)) {
66
+ return Array.isArray(config?.events) ? hasStructurallyValidExplicitEvent(config) : true;
67
+ }
68
+ if (source === 'tasks') {
69
+ return (goalId || configuredId(config, 'taskId', 'goalId', 'keyResultId'));
70
+ }
71
+ if (source === 'goal') {
72
+ return goalId || configuredId(config, 'goalId', 'keyResultId');
73
+ }
74
+ if (source === 'space')
75
+ return configuredId(config, 'spaceId');
76
+ if (source === 'conversations')
77
+ return configuredId(config, 'conversationId');
78
+ if (source === 'messages')
79
+ return configuredId(config, 'groupChatId');
80
+ if (source === 'agent_initiatives') {
81
+ return configuredId(config, 'initiativeId', 'cloudCodingTaskId');
82
+ }
83
+ if (source === 'documents')
84
+ return configuredId(config, 'artifactIdentifier');
85
+ if (source === 'monitor')
86
+ return configuredId(config, 'monitorId');
87
+ // Custom bindings are still server-validated against the source-specific
88
+ // wake allowlist. At this boundary, require at least a structurally valid
89
+ // event row instead of treating any non-empty array as event capability.
90
+ return hasStructurallyValidExplicitEvent(config);
91
+ });
92
+ }
93
+ function assertEventDrivenWatchedSource(payload) {
94
+ if (record(payload.cadence)?.mode !== 'event_plus_interval' ||
95
+ hasEventCapableWatchedSource(payload)) {
96
+ return;
97
+ }
98
+ throw new Error('Event-driven cadence (--event-driven or --cadence-mode event_plus_interval) requires at least one event-capable watched source. ' +
99
+ 'Add --watch github (or another event-capable source), or choose an interval-only cadence.');
100
+ }
101
+ /**
102
+ * Resolve the create-time cadence flags into the API payload.
103
+ *
104
+ * `--event-driven` is deliberately a complete shortcut rather than an alias
105
+ * for the mode string: event delivery is an accelerator, so the contract must
106
+ * always retain a timed safety net even when the author omits `--cadence`.
107
+ */
108
+ function createCadenceFromFlags({ eventDriven, cadence: cadenceInput, cadenceMode, timezone, }) {
109
+ if (eventDriven) {
110
+ if (cadenceMode && cadenceMode !== 'event_plus_interval') {
111
+ throw new Error(`--event-driven cannot be combined with --cadence-mode ${cadenceMode}. ` +
112
+ 'Use --event-driven alone or --cadence-mode event_plus_interval.');
113
+ }
114
+ return {
115
+ mode: 'event_plus_interval',
116
+ intervalMs: cadenceInput
117
+ ? (0, commitments_1.parseIntervalToMs)(cadenceInput)
118
+ : DEFAULT_EVENT_DRIVEN_BACKSTOP_MS,
119
+ ...(timezone ? { timezone } : {}),
120
+ };
121
+ }
122
+ const cadence = {};
123
+ if (cadenceInput) {
124
+ cadence.intervalMs = (0, commitments_1.parseIntervalToMs)(cadenceInput);
125
+ cadence.mode = cadenceMode || 'interval';
126
+ }
127
+ else if (cadenceMode) {
128
+ cadence.mode = cadenceMode;
129
+ }
130
+ if (timezone)
131
+ cadence.timezone = timezone;
132
+ return Object.keys(cadence).length ? cadence : undefined;
133
+ }
10
134
  /**
11
135
  * Creation preserves the policy its author wrote, so the mode that comes back
12
136
  * is normally the mode that was asked for. When it is not — normalization
@@ -21,14 +145,21 @@ function autonomyStagingNotice({ payload, commitment, bin, }) {
21
145
  const returnedPolicy = commitment.policy && typeof commitment.policy === 'object' && !Array.isArray(commitment.policy)
22
146
  ? commitment.policy
23
147
  : {};
24
- const requested = typeof requestedPolicy.autonomyMode === 'string' ? requestedPolicy.autonomyMode : '';
148
+ const requested = typeof payload.mode === 'string'
149
+ ? payload.mode
150
+ : typeof requestedPolicy.autonomyMode === 'string'
151
+ ? requestedPolicy.autonomyMode
152
+ : '';
25
153
  const admitted = typeof returnedPolicy.autonomyMode === 'string' ? returnedPolicy.autonomyMode : '';
26
- if (!requested || requested === admitted || requested === 'off')
154
+ if (!requested ||
155
+ (0, commitment_product_1.productMode)(requested) === (0, commitment_product_1.productMode)(admitted || 'suggestions_only') ||
156
+ requested === 'off') {
27
157
  return undefined;
158
+ }
28
159
  const id = typeof commitment.id === 'string' ? commitment.id : '<commitment-id>';
29
160
  return [
30
- `Requested autonomy ${requested} was not applied; this commitment is running as ${admitted || 'suggestions_only'}.`,
31
- `To set it explicitly: ${bin} commitments autonomy ${id} --mode ${requested} --reason "<why this scope is safe>"`,
161
+ `Requested mode ${(0, commitment_product_1.productModeLabel)(requested)} was not applied; this commitment is running as ${(0, commitment_product_1.productModeLabel)(admitted || 'suggestions_only')}.`,
162
+ `To set it explicitly: ${bin} commitments mode ${id} ${(0, commitment_product_1.productMode)(requested)}`,
32
163
  ].join('\n');
33
164
  }
34
165
  /**
@@ -45,10 +176,11 @@ class CommitmentsCreate extends base_command_1.BaseCommand {
45
176
  static description = 'Create a commitment (a durable agent contract)';
46
177
  static examples = [
47
178
  '<%= config.bin %> commitments create --agent <agent-id> --title "Ship v2" --outcome "v2 is live for all users" --cadence 6h',
48
- '<%= config.bin %> commitments create --agent <agent-id> --title "Hiring loop" --outcome "Every candidate hears back in 48h" --watch tasks --watch email --cadence 12h --status active',
179
+ '<%= config.bin %> commitments create --agent <agent-id> --title "Hiring loop" --outcome "Every candidate hears back in 48h" --watch tasks --watch email --cadence 12h',
49
180
  '<%= config.bin %> commitments create --agent <agent-id> --title "SLA" --outcome "p95 under 200ms" --criterion "p95 latency confirmed" --evaluator metric --measure <measure-id>',
50
181
  '<%= config.bin %> commitments create --agent <agent-id> --title "AWS cost watch" --outcome "Cost regressions are investigated" --agent-directive-file ./aws-cost-policy.md',
51
182
  '<%= config.bin %> commitments create --from-json commitment.json --json',
183
+ '<%= config.bin %> commitments create --agent <agent-id> --title "Keep CI healthy" --outcome "Failed checks are repaired" --watch github --event-driven --mode execute --delivery draft-pr --repo owner/repo --base main --status draft',
52
184
  ];
53
185
  static flags = {
54
186
  json: core_1.Flags.boolean({ description: 'Output the created commitment as JSON' }),
@@ -73,8 +205,8 @@ class CommitmentsCreate extends base_command_1.BaseCommand {
73
205
  }),
74
206
  goal: core_1.Flags.string({ description: 'Link to a goal ID' }),
75
207
  status: core_1.Flags.string({
76
- description: 'Create as draft (default) or active',
77
- options: ['draft', 'active'],
208
+ description: 'Create as a draft (default); activate later with commitments resume',
209
+ options: ['draft'],
78
210
  }),
79
211
  deadline: core_1.Flags.string({ description: 'ISO-8601 deadline for an `achieve` commitment' }),
80
212
  criterion: core_1.Flags.string({
@@ -115,21 +247,34 @@ class CommitmentsCreate extends base_command_1.BaseCommand {
115
247
  multiple: true,
116
248
  }),
117
249
  cadence: core_1.Flags.string({
118
- description: 'Check interval, e.g. "15m", "6h", "1d" (1m..30d). Implies --cadence-mode interval.',
250
+ description: 'Check interval, e.g. "15m", "6h", "30d" (1m..365d). Defaults to interval mode; with --event-driven, this is the timed backstop.',
251
+ }),
252
+ 'event-driven': core_1.Flags.boolean({
253
+ description: 'Wake on matching watched-source events, with a timed backstop from --cadence (default 24h). Requires an event-capable watched source and cannot be combined with a different --cadence-mode.',
119
254
  }),
120
255
  'cadence-mode': core_1.Flags.string({
121
- description: 'Cadence mode (default: interval when --cadence is set, else manual)',
122
- options: [...commitments_1.COMMITMENT_CADENCE_MODES],
256
+ description: 'Advanced cadence mode (default: interval when --cadence is set, else manual). Prefer --event-driven for event_plus_interval with a 24h default backstop.',
257
+ options: [...commitments_1.COMMITMENT_AUTHORABLE_CADENCE_MODES],
123
258
  }),
124
259
  timezone: core_1.Flags.string({ description: 'IANA timezone for the cadence' }),
260
+ mode: core_1.Flags.string({
261
+ description: 'How the commitment progresses (default Monitor)',
262
+ options: [...commitment_product_1.COMMITMENT_PRODUCT_MODES],
263
+ }),
264
+ delivery: core_1.Flags.string({
265
+ description: 'Where Prepare or Execute coding work is delivered; Monitor is report-only',
266
+ options: [...commitment_product_1.COMMITMENT_DELIVERY_CHOICES],
267
+ }),
268
+ repo: core_1.Flags.string({ description: 'Delivery repository, owner/repo' }),
269
+ base: core_1.Flags.string({ description: 'Delivery target branch' }),
125
270
  autonomy: core_1.Flags.string({
126
271
  // `--help` is where someone decides what to type, so the ceiling that can
127
272
  // still bind has to be stated HERE and not only in the notice that
128
273
  // corrects them afterwards. `commitments autonomy --mode` learned the
129
274
  // same lesson: what it must not keep is the silence.
130
- description: 'Autonomy to set at creation (default suggestions_only). Explicit values are preserved; ' +
131
- 'Agent, Compass, and workspace governance can still impose a visible effective ceiling.',
275
+ description: 'Compatibility flag. Prefer --mode monitor|prepare|execute. Workspace administrator rules remain binding.',
132
276
  options: [...commitments_1.COMMITMENT_AUTONOMY_MODES],
277
+ hidden: true,
133
278
  }),
134
279
  isolation: core_1.Flags.string({
135
280
  // Omitting this is not the same as passing `shared`: an omitted value
@@ -140,6 +285,7 @@ class CommitmentsCreate extends base_command_1.BaseCommand {
140
285
  'and destroys it after; "shared" lands them on the daemon working tree, in place. ' +
141
286
  'Omit to leave the runtime default. Cannot be combined with a remediation capability.',
142
287
  options: [...commitments_1.COMMITMENT_EXECUTION_ISOLATION_MODES],
288
+ hidden: true,
143
289
  }),
144
290
  'max-nudges': core_1.Flags.integer({ description: 'Max user nudges per day (0..20)' }),
145
291
  };
@@ -147,6 +293,7 @@ class CommitmentsCreate extends base_command_1.BaseCommand {
147
293
  this.requireAuth();
148
294
  const { flags } = await this.parse(CommitmentsCreate);
149
295
  let payload;
296
+ let deliveryNormalizedForMonitor = false;
150
297
  try {
151
298
  // `createBodySchema` is a z.strictObject, so unwrap a `plan --json`
152
299
  // envelope and drop any key it does not declare (a contract dumped from
@@ -210,27 +357,47 @@ class CommitmentsCreate extends base_command_1.BaseCommand {
210
357
  });
211
358
  if (built)
212
359
  payload.watchedSources = built;
213
- const cadence = {};
214
- if (flags.cadence) {
215
- cadence.intervalMs = (0, commitments_1.parseIntervalToMs)(flags.cadence);
216
- cadence.mode = flags['cadence-mode'] || 'interval';
217
- }
218
- else if (flags['cadence-mode']) {
219
- cadence.mode = flags['cadence-mode'];
220
- }
221
- if (flags.timezone)
222
- cadence.timezone = flags.timezone;
223
- if (Object.keys(cadence).length)
360
+ const cadence = createCadenceFromFlags({
361
+ eventDriven: flags['event-driven'],
362
+ cadence: flags.cadence,
363
+ cadenceMode: flags['cadence-mode'],
364
+ timezone: flags.timezone,
365
+ });
366
+ if (cadence)
224
367
  payload.cadence = cadence;
368
+ assertEventDrivenWatchedSource(payload);
225
369
  const policy = {};
226
370
  if (flags.autonomy)
227
371
  policy.autonomyMode = flags.autonomy;
372
+ if (flags.mode && flags.autonomy)
373
+ throw new Error('Use --mode or the compatibility --autonomy flag, not both.');
374
+ if (flags.mode)
375
+ payload.mode = (0, commitment_product_1.productMode)(flags.mode);
376
+ if (flags.delivery)
377
+ payload.delivery = (0, commitment_product_1.deliveryInput)(flags.delivery, flags);
378
+ else if (flags.repo || flags.base)
379
+ throw new Error('--repo and --base require --delivery.');
228
380
  if (flags.isolation)
229
381
  policy.executionIsolation = flags.isolation;
230
382
  if (flags['max-nudges'] !== undefined)
231
383
  policy.maxUserNudgesPerDay = flags['max-nudges'];
232
384
  if (Object.keys(policy).length)
233
385
  payload.policy = policy;
386
+ const payloadPolicy = payload.policy && typeof payload.policy === 'object' && !Array.isArray(payload.policy)
387
+ ? payload.policy
388
+ : {};
389
+ const selectedMode = typeof payload.mode === 'string'
390
+ ? payload.mode
391
+ : typeof payloadPolicy.autonomyMode === 'string'
392
+ ? payloadPolicy.autonomyMode
393
+ : 'monitor';
394
+ if (payload.delivery && typeof payload.delivery === 'object' && !Array.isArray(payload.delivery)) {
395
+ const declared = payload.delivery;
396
+ const coherent = (0, commitment_product_1.deliveryForProductMode)(selectedMode, declared);
397
+ deliveryNormalizedForMonitor =
398
+ (0, commitment_product_1.productMode)(selectedMode) === 'monitor' && declared.mode !== 'report_only';
399
+ payload.delivery = coherent;
400
+ }
234
401
  }
235
402
  catch (err) {
236
403
  this.error(err.message, { exit: 1 });
@@ -245,6 +412,9 @@ class CommitmentsCreate extends base_command_1.BaseCommand {
245
412
  exit: 1,
246
413
  });
247
414
  }
415
+ // Creation is authoring only. Activation is a separate resume boundary
416
+ // that runs the current preflight; JSON imports cannot bypass it.
417
+ payload.status = 'draft';
248
418
  let commitment;
249
419
  try {
250
420
  commitment = await commitments_1.commitmentApi.create(payload);
@@ -261,6 +431,9 @@ class CommitmentsCreate extends base_command_1.BaseCommand {
261
431
  });
262
432
  if (notice)
263
433
  this.warn(notice);
434
+ if (deliveryNormalizedForMonitor) {
435
+ this.warn('Monitor is report-only, so the requested code-delivery destination was not stored. Use --mode prepare or --mode execute to deliver code.');
436
+ }
264
437
  return;
265
438
  }
266
439
  this.log('Created commitment:');
@@ -274,6 +447,10 @@ class CommitmentsCreate extends base_command_1.BaseCommand {
274
447
  this.log('');
275
448
  this.log(notice);
276
449
  }
450
+ if (deliveryNormalizedForMonitor) {
451
+ this.log('');
452
+ this.log('Monitor is report-only, so delivery was set to Report only. Choose Prepare or Execute to deliver code.');
453
+ }
277
454
  if (commitment.status === 'draft') {
278
455
  this.log('');
279
456
  this.log(`Activate it with: ${this.config.bin} commitments resume ${commitment.id}`);
@@ -0,0 +1,16 @@
1
+ import { BaseCommand } from '../../base-command';
2
+ export default class CommitmentsDelivery extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
7
+ mode: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
8
+ };
9
+ static flags: {
10
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
11
+ repo: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
12
+ base: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
13
+ reason: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
14
+ };
15
+ run(): Promise<void>;
16
+ }
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const base_command_1 = require("../../base-command");
5
+ const commitments_1 = require("../../lib/commitments");
6
+ const commitment_product_1 = require("../../lib/commitment-product");
7
+ const web_url_1 = require("../../lib/web-url");
8
+ class CommitmentsDelivery extends base_command_1.BaseCommand {
9
+ static description = 'Declare where Prepare or Execute delivers work; Monitor is always report-only';
10
+ static examples = [
11
+ '<%= config.bin %> commitments delivery <id> draft-pr --repo owner/repo --base main',
12
+ ];
13
+ static args = {
14
+ id: core_1.Args.string({ required: true, ignoreStdin: true }),
15
+ mode: core_1.Args.string({
16
+ required: true,
17
+ description: 'Delivery destination. Code destinations require Prepare or Execute (or a Pack Shadow promotion target).',
18
+ options: [
19
+ ...commitment_product_1.COMMITMENT_DELIVERY_CHOICES,
20
+ ...commitment_product_1.COMMITMENT_DELIVERY_CHOICES.map((mode) => mode.replace(/-/g, '_')),
21
+ ],
22
+ }),
23
+ };
24
+ static flags = {
25
+ json: core_1.Flags.boolean({ description: 'Output the complete contract as JSON' }),
26
+ repo: core_1.Flags.string({ description: 'GitHub repository, owner/repo' }),
27
+ base: core_1.Flags.string({ description: 'Delivery target branch, such as main' }),
28
+ reason: core_1.Flags.string({ description: 'Reason recorded with this contract change' }),
29
+ };
30
+ async run() {
31
+ this.requireAuth();
32
+ const { args, flags } = await this.parse(CommitmentsDelivery);
33
+ try {
34
+ const current = (await commitments_1.commitmentApi.get(args.id)).commitment;
35
+ const requested = (0, commitment_product_1.deliveryInput)(args.mode, flags);
36
+ const stagingForPromotion = current.pack?.phase === 'shadow';
37
+ const targetPolicy = stagingForPromotion
38
+ ? current.pack?.policyBeforeShadow || current.policy
39
+ : current.policy;
40
+ const productContract = targetPolicy?.workPromotionModel === 'monitor_prepare_execute_v1';
41
+ if (productContract &&
42
+ (0, commitment_product_1.productMode)(targetPolicy?.autonomyMode) === 'monitor' &&
43
+ requested.mode !== 'report_only') {
44
+ throw new Error(stagingForPromotion
45
+ ? 'This Pack promotion target is Monitor, so its delivery must be report-only. Set the commitment mode to Prepare or Execute before staging code delivery.'
46
+ : 'Monitor is report-only. Set the commitment mode to Prepare or Execute before selecting code delivery.');
47
+ }
48
+ const delivery = { ...current.delivery, ...requested };
49
+ const result = await commitments_1.commitmentApi.delivery(args.id, {
50
+ delivery,
51
+ expectedVersion: current.version,
52
+ ...(flags.reason ? { reason: flags.reason } : {}),
53
+ });
54
+ const linked = (0, web_url_1.withCommitmentUrl)(this.cliConfig.baseURL, result);
55
+ if (flags.json)
56
+ return this.log(JSON.stringify(linked, null, 2));
57
+ const renderedDelivery = stagingForPromotion
58
+ ? result.pack?.deliveryBeforeShadow || delivery
59
+ : result.delivery;
60
+ this.log(`${stagingForPromotion ? 'Promotion delivery staged' : 'Delivery'}: ${(0, commitment_product_1.deliveryLabel)(renderedDelivery?.mode)}${renderedDelivery?.repo ? ` · ${renderedDelivery.repo}` : ''}${renderedDelivery?.baseBranch ? ` → ${renderedDelivery.baseBranch}` : ''}`);
61
+ if (stagingForPromotion) {
62
+ this.log('Live Shadow delivery remains Report only until explicit promotion.');
63
+ }
64
+ this.log(`URL: ${linked.url}`);
65
+ }
66
+ catch (error) {
67
+ this.handleApiError(error);
68
+ }
69
+ }
70
+ }
71
+ exports.default = CommitmentsDelivery;
@@ -2,6 +2,7 @@ import { BaseCommand } from '../../base-command';
2
2
  export declare function doctorVerdict(input: {
3
3
  commitment?: Record<string, unknown>;
4
4
  preflight?: Record<string, unknown>;
5
+ operatingState?: Record<string, unknown>;
5
6
  }): {
6
7
  verdict: string;
7
8
  next: string;
@@ -7,6 +7,24 @@ const commitments_1 = require("../../lib/commitments");
7
7
  function doctorVerdict(input) {
8
8
  const commitment = input.commitment || {};
9
9
  const preflight = input.preflight || {};
10
+ const operatingState = input.operatingState || {};
11
+ const blocker = operatingState.firstActionableBlocker;
12
+ if (blocker?.code) {
13
+ return { verdict: 'blocked', next: String(blocker.remediation || 'Inspect the Commitment') };
14
+ }
15
+ if (operatingState.status === 'waiting_approval') {
16
+ return { verdict: 'waiting_approval', next: 'Open the pending prepared action for review' };
17
+ }
18
+ if (operatingState.coverage && operatingState.coverage.complete === false) {
19
+ return { verdict: 'degraded', next: 'Retry doctor; one or more operating-state projections are unavailable' };
20
+ }
21
+ if (operatingState.status && commitment.status === 'active') {
22
+ const status = String(operatingState.status);
23
+ return {
24
+ verdict: ['on_track', 'healthy'].includes(status) ? 'active_healthy' : status,
25
+ next: 'skrr commitments trace <id> --limit 50',
26
+ };
27
+ }
10
28
  if (commitment.status !== 'active')
11
29
  return { verdict: 'blocked', next: 'skrr commitments resume <id>' };
12
30
  if (preflight.verdict === 'blocked')
@@ -31,32 +49,22 @@ class CommitmentsDoctor extends base_command_1.BaseCommand {
31
49
  this.requireAuth();
32
50
  const { args, flags } = await this.parse(CommitmentsDoctor);
33
51
  let commitment;
34
- let preflight;
35
- let triggerStatus;
36
- let ledger;
52
+ let shown;
37
53
  try {
38
- const [shown, pf, triggers, runs] = await Promise.all([
39
- commitments_1.commitmentApi.get(args.id),
40
- commitments_1.commitmentApi.preflight(args.id),
41
- commitments_1.commitmentApi.triggerStatus(args.id, 5),
42
- commitments_1.commitmentApi.ledger(args.id, { limit: 5 }),
43
- ]);
54
+ shown = (await commitments_1.commitmentApi.get(args.id));
44
55
  commitment = (shown.commitment || {});
45
- preflight = pf;
46
- triggerStatus = triggers;
47
- ledger = runs;
48
56
  }
49
57
  catch (error) {
50
58
  this.handleApiError(error);
51
59
  return;
52
60
  }
53
- const diagnosis = doctorVerdict({ commitment, preflight });
61
+ const operatingState = (shown.operatingState || {});
62
+ const diagnosis = doctorVerdict({ commitment, operatingState });
54
63
  const report = {
55
64
  ...diagnosis,
56
65
  commitment,
57
- preflight,
58
- triggerStatus,
59
- ledger,
66
+ abilities: shown.abilities,
67
+ operatingState,
60
68
  observedAt: new Date().toISOString(),
61
69
  };
62
70
  if (flags.json)
@@ -64,9 +72,17 @@ class CommitmentsDoctor extends base_command_1.BaseCommand {
64
72
  else {
65
73
  this.log(`Verdict: ${diagnosis.verdict}`);
66
74
  this.log(`Next: ${diagnosis.next.replace('<id>', args.id)}`);
75
+ const autonomy = operatingState.autonomy;
76
+ if (autonomy) {
77
+ this.log(`Mode: ${(0, commitments_1.commitmentAutonomyLabel)(String(autonomy.declaredMode || ''))} → ${(0, commitments_1.commitmentAutonomyLabel)(String(autonomy.effectiveMode || ''))}`);
78
+ }
79
+ const approvals = operatingState.approvals;
80
+ if (approvals?.pendingCount)
81
+ this.log(`Waiting approval: ${String(approvals.pendingCount)}`);
67
82
  }
68
- if (flags.strict && diagnosis.verdict !== 'active_healthy')
83
+ if (flags.strict && !['healthy', 'active_healthy'].includes(diagnosis.verdict)) {
69
84
  process.exitCode = 1;
85
+ }
70
86
  }
71
87
  }
72
88
  exports.default = CommitmentsDoctor;
@@ -1,4 +1,5 @@
1
1
  import { BaseCommand } from '../../base-command';
2
+ export declare function effectivePolicyLines(policy: Record<string, any>): string[];
2
3
  /** Show the policy actually governing a Commitment without changing it. */
3
4
  export default class CommitmentsEffectivePolicy extends BaseCommand {
4
5
  static description: string;
@@ -8,6 +9,7 @@ export default class CommitmentsEffectivePolicy extends BaseCommand {
8
9
  };
9
10
  static flags: {
10
11
  json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
12
+ verbose: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
11
13
  };
12
14
  run(): Promise<void>;
13
15
  }
@@ -1,8 +1,46 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.effectivePolicyLines = effectivePolicyLines;
3
4
  const core_1 = require("@oclif/core");
4
5
  const base_command_1 = require("../../base-command");
5
6
  const commitments_1 = require("../../lib/commitments");
7
+ const commitment_product_1 = require("../../lib/commitment-product");
8
+ function effectivePolicyLines(policy) {
9
+ const governance = policy.governance || {};
10
+ const owner = policy.owner || {};
11
+ const lines = [`Mode in force: ${(0, commitment_product_1.productModeLabel)(governance.effectiveAutonomyMode)}`];
12
+ if (governance.blocked) {
13
+ lines.push(`Workspace status: blocked${governance.blockedReason ? ` — ${governance.blockedReason}` : ''}`);
14
+ }
15
+ else {
16
+ lines.push('Workspace status: allowed');
17
+ }
18
+ if (governance.workspaceMaxMode) {
19
+ lines.push(`Workspace Mode ceiling: ${(0, commitment_product_1.productModeLabel)(governance.workspaceMaxMode)}`);
20
+ }
21
+ if (Array.isArray(governance.workspaceModeOverrides)) {
22
+ for (const override of governance.workspaceModeOverrides) {
23
+ if (override?.effectiveMode) {
24
+ lines.push(`Workspace override: ${(0, commitment_product_1.productModeLabel)(override.effectiveMode)} — ${override.policy || 'configured administrator rule'}${override.configuredValue ? ` (${override.configuredValue})` : ''}`);
25
+ }
26
+ }
27
+ }
28
+ if (Array.isArray(governance.allowedCommitmentDeliveryModes)) {
29
+ lines.push(`Workspace delivery allowlist: ${governance.allowedCommitmentDeliveryModes.length ? governance.allowedCommitmentDeliveryModes.map(commitment_product_1.deliveryLabel).join(', ') : 'none'}`);
30
+ }
31
+ if (Array.isArray(governance.requireAttestedAccessForDeliveryModes) && governance.requireAttestedAccessForDeliveryModes.length) {
32
+ lines.push(`Runtime attestation required for: ${governance.requireAttestedAccessForDeliveryModes.map(commitment_product_1.deliveryLabel).join(', ')}`);
33
+ }
34
+ const runLimit = owner.actionRunsPerDay;
35
+ if (runLimit) {
36
+ lines.push(`Owner action-run limit: ${runLimit.mode === 'unbounded' ? 'Unlimited' : `${runLimit.value}/day`}`);
37
+ }
38
+ const cost = policy.billing;
39
+ if (cost?.effectiveCostLimitUsd != null) {
40
+ lines.push(`Effective daily cost limit: $${Number(cost.effectiveCostLimitUsd).toFixed(2)}`);
41
+ }
42
+ return lines;
43
+ }
6
44
  /** Show the policy actually governing a Commitment without changing it. */
7
45
  class CommitmentsEffectivePolicy extends base_command_1.BaseCommand {
8
46
  static description = 'Show the owner, workspace, and infrastructure policy currently governing a commitment';
@@ -15,6 +53,7 @@ class CommitmentsEffectivePolicy extends base_command_1.BaseCommand {
15
53
  };
16
54
  static flags = {
17
55
  json: core_1.Flags.boolean({ description: 'Output the complete effective policy as JSON' }),
56
+ verbose: core_1.Flags.boolean({ description: 'Append raw compatibility and diagnostic policy JSON' }),
18
57
  };
19
58
  async run() {
20
59
  this.requireAuth();
@@ -27,11 +66,17 @@ class CommitmentsEffectivePolicy extends base_command_1.BaseCommand {
27
66
  this.handleApiError(err);
28
67
  return;
29
68
  }
30
- // The response is deliberately provenance-rich and evolves with each policy
31
- // layer. Preserve that shape rather than flattening it into a lossy table.
32
- if (!flags.json)
33
- this.log('Effective policy:');
34
- this.log(JSON.stringify(policy, null, 2));
69
+ if (flags.json) {
70
+ this.log(JSON.stringify(policy, null, 2));
71
+ return;
72
+ }
73
+ this.log('Effective policy:');
74
+ for (const line of effectivePolicyLines(policy))
75
+ this.log(` ${line}`);
76
+ if (flags.verbose) {
77
+ this.log('\nRaw compatibility diagnostics:');
78
+ this.log(JSON.stringify(policy, null, 2));
79
+ }
35
80
  }
36
81
  }
37
82
  exports.default = CommitmentsEffectivePolicy;
@@ -1,13 +1,8 @@
1
1
  import { BaseCommand } from '../../../base-command';
2
2
  /**
3
- * `skrr commitments endpoints connect <id>` start (or finish) the handshake.
4
- *
5
- * For a provider-backed endpoint this returns an AUTHORIZATION URL rather than a
6
- * connected endpoint: open it, approve, then run the same command with
7
- * `--finalize`. That two-step is the reason this needed a CLI — without it a
8
- * headless operator could not connect a delivery target at all.
9
- *
10
- * `--reconnect` runs the same handshake for an endpoint that has gone stale.
3
+ * `skrr commitments endpoints connect <id>` probes the Agent's native App or
4
+ * Slack transport and records its live health. `--reconnect` reruns the same
5
+ * probe for a stale/revoked endpoint.
11
6
  */
12
7
  export default class CommitmentsEndpointsConnect extends BaseCommand {
13
8
  static description: string;
@@ -17,9 +12,7 @@ export default class CommitmentsEndpointsConnect extends BaseCommand {
17
12
  };
18
13
  static flags: {
19
14
  json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
20
- finalize: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
21
15
  reconnect: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
22
- request: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
23
16
  };
24
17
  run(): Promise<void>;
25
18
  }