@skrr-ai/cli 0.1.109 → 0.1.110
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.
- package/dist/base-command.d.ts +15 -0
- package/dist/base-command.js +64 -17
- package/dist/commands/agents/triggers/create.js +1 -1
- package/dist/commands/agents/triggers/update.js +1 -1
- package/dist/commands/agents/update.d.ts +11 -0
- package/dist/commands/agents/update.js +58 -2
- package/dist/commands/daemon/install.js +17 -1
- package/dist/commands/daemon/login.js +14 -0
- package/dist/commands/harnesses/prune.d.ts +26 -0
- package/dist/commands/harnesses/prune.js +172 -0
- package/dist/commands/login.js +11 -0
- package/dist/commands/spaces/workflows/start.js +3 -1
- package/dist/commands/spaces/workflows/validate.js +12 -2
- package/dist/commands/tasks/activity.js +11 -1
- package/dist/commands/tasks/list.js +6 -2
- package/dist/commands/tasks/rearm-recurrence.js +22 -3
- package/dist/commands/tasks/show.d.ts +8 -0
- package/dist/commands/tasks/show.js +64 -32
- package/dist/commands/tasks/unschedule.js +5 -1
- package/dist/commands/tasks/update.js +11 -1
- package/dist/commands/triggers/audit.js +12 -3
- package/dist/commands/triggers/create.js +1 -1
- package/dist/commands/triggers/fire-detail.d.ts +7 -0
- package/dist/commands/triggers/fire-detail.js +30 -12
- package/dist/commands/triggers/fire.js +13 -3
- package/dist/commands/triggers/parse-intent.js +1 -1
- package/dist/commands/triggers/update.js +1 -1
- package/dist/commands/workspaces/grants.js +1 -4
- package/dist/commands/workspaces/members.js +6 -6
- package/dist/lib/commitment-product.js +5 -2
- package/dist/lib/commitments.d.ts +2 -1
- package/dist/lib/commitments.js +40 -40
- package/dist/lib/daemon-machine-identity-copy.d.ts +14 -0
- package/dist/lib/daemon-machine-identity-copy.js +27 -0
- package/dist/lib/daemon-machine-identity.d.ts +27 -0
- package/dist/lib/daemon-machine-identity.js +61 -0
- package/dist/lib/daemonHandoff.d.ts +19 -1
- package/dist/lib/daemonHandoff.js +59 -0
- package/dist/lib/harnesses.d.ts +71 -0
- package/dist/lib/harnesses.js +70 -0
- package/dist/lib/list-output.d.ts +1 -1
- package/dist/lib/list-output.js +2 -0
- package/dist/lib/profile-machine-identity-guard.js +11 -1
- package/dist/lib/task-economics.d.ts +10 -0
- package/dist/lib/task-economics.js +24 -2
- package/dist/lib/triggers.d.ts +11 -0
- package/dist/lib/triggers.js +43 -1
- package/dist/lib/workflow-run-view.d.ts +4 -0
- package/dist/lib/workflow-run-view.js +5 -0
- package/dist/lib/workspaces.d.ts +24 -7
- package/dist/lib/workspaces.js +14 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +5 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/machineUuid.d.ts +60 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/machineUuid.js +130 -6
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/machineUuid.d.ts +60 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/machineUuid.js +128 -6
- package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +4003 -3968
- package/oclif.manifest.json +99 -9
- package/package.json +10 -1
|
@@ -30,12 +30,22 @@ class SpacesWorkflowsValidate extends base_command_1.BaseCommand {
|
|
|
30
30
|
this.handleApiError(error);
|
|
31
31
|
return;
|
|
32
32
|
}
|
|
33
|
+
// The one rule (OSK-16493): an error-severity issue means invalid, whatever `valid` says. A
|
|
34
|
+
// server that predates the shared gate answered `valid: true` beside such an issue, and the
|
|
35
|
+
// text view then called the draft ready to publish and hid the issue.
|
|
36
|
+
const blocking = (0, data_provider_1.blockingWorkflowIssues)(result.issues ?? []);
|
|
37
|
+
const valid = Boolean(result.valid) && blocking.length === 0;
|
|
33
38
|
if (flags.json) {
|
|
34
39
|
this.log(JSON.stringify((0, space_output_1.withSpacePerspectiveUrl)(this.cliConfig.baseURL, args.spaceId, 'workflows', result), null, 2));
|
|
40
|
+
// One answer, two renderings: an invalid draft fails the command in either mode, so a
|
|
41
|
+
// script reading --json can trust the exit status exactly as a person reading text can
|
|
42
|
+
// (OSK-16473).
|
|
43
|
+
if (!valid)
|
|
44
|
+
this.exit(1);
|
|
35
45
|
return;
|
|
36
46
|
}
|
|
37
47
|
const advisories = (result.issues ?? []).filter((issue) => issue.severity !== 'error');
|
|
38
|
-
if (
|
|
48
|
+
if (valid) {
|
|
39
49
|
this.log('Workflow draft is valid and ready to publish.');
|
|
40
50
|
if (advisories.length) {
|
|
41
51
|
this.log(`${advisories.length} warning${advisories.length === 1 ? '' : 's'} (publishing is allowed):`);
|
|
@@ -44,7 +54,7 @@ class SpacesWorkflowsValidate extends base_command_1.BaseCommand {
|
|
|
44
54
|
}
|
|
45
55
|
return;
|
|
46
56
|
}
|
|
47
|
-
this.log(`Workflow draft is invalid${result.code ? ` (${result.code})` : ''}: ${result.message ?? 'Unknown validation error'}`);
|
|
57
|
+
this.log(`Workflow draft is invalid${result.code ? ` (${result.code})` : ''}: ${result.message ?? blocking[0]?.message ?? 'Unknown validation error'}`);
|
|
48
58
|
// Every problem, not only the first one publish would stop at.
|
|
49
59
|
const all = result.issues ?? [];
|
|
50
60
|
if (all.length) {
|
|
@@ -8,6 +8,16 @@ const base_command_1 = require("../../base-command");
|
|
|
8
8
|
const format_1 = require("../../lib/format");
|
|
9
9
|
const task_economics_1 = require("../../lib/task-economics");
|
|
10
10
|
const task_legacy_1 = require("../../lib/task-legacy");
|
|
11
|
+
/**
|
|
12
|
+
* A system-written embedded entry names no person (OSK-16475): it carries
|
|
13
|
+
* `details.actorKind: 'system'` instead of a `userId`, so the actor is the service.
|
|
14
|
+
*/
|
|
15
|
+
function systemEntryActor(details) {
|
|
16
|
+
const value = details;
|
|
17
|
+
if (value?.actorKind !== 'system')
|
|
18
|
+
return undefined;
|
|
19
|
+
return `system:${value.actorService ?? '-'}`;
|
|
20
|
+
}
|
|
11
21
|
function activityRow(entry) {
|
|
12
22
|
const actor = entry.actor;
|
|
13
23
|
const actorText = actor
|
|
@@ -18,7 +28,7 @@ function activityRow(entry) {
|
|
|
18
28
|
: actor.kind === 'integration'
|
|
19
29
|
? `integration:${actor.provider}`
|
|
20
30
|
: `system:${actor.service}`
|
|
21
|
-
: (entry.userId ?? entry.actorId);
|
|
31
|
+
: (entry.userId ?? entry.actorId ?? systemEntryActor(entry.details));
|
|
22
32
|
const type = entry.action ?? entry.event ?? entry.type;
|
|
23
33
|
return {
|
|
24
34
|
time: (0, format_1.localTime)(entry.occurredAt ?? entry.timestamp ?? entry.createdAt),
|
|
@@ -588,7 +588,9 @@ class TasksList extends base_command_1.BaseCommand {
|
|
|
588
588
|
Array.isArray(response.data)) {
|
|
589
589
|
response = {
|
|
590
590
|
...response,
|
|
591
|
-
|
|
591
|
+
// Each row carries the `economicsRank` it was sorted by, so `--json` shows the same SCORE
|
|
592
|
+
// as the table, computed once in the shared ranking (OSK-16476).
|
|
593
|
+
data: (0, data_provider_1.annotateEconomicRank)(response.data),
|
|
592
594
|
rank_applied: { key: 'economics', scope: 'fetched_page' },
|
|
593
595
|
};
|
|
594
596
|
}
|
|
@@ -693,7 +695,9 @@ class TasksList extends base_command_1.BaseCommand {
|
|
|
693
695
|
: 'Unknown',
|
|
694
696
|
effort: economics?.effortHours !== undefined ? `${economics.effortHours}h` : 'Unknown',
|
|
695
697
|
risk: economics?.risk ?? 'Unknown',
|
|
696
|
-
score:
|
|
698
|
+
score: t.economicsRank
|
|
699
|
+
? (0, task_economics_1.scoreText)(t.economicsRank.score)
|
|
700
|
+
: (0, task_economics_1.economicsScoreText)(economics),
|
|
697
701
|
basis: economics?.basis && Object.prototype.hasOwnProperty.call(basis, economics.basis)
|
|
698
702
|
? basis[economics.basis]
|
|
699
703
|
: 'Unknown',
|
|
@@ -60,9 +60,28 @@ class TasksRearmRecurrence extends base_command_1.BaseCommand {
|
|
|
60
60
|
const from = finished.identifier || finished.id || taskRef;
|
|
61
61
|
const next = result.successor.identifier || result.successor.id;
|
|
62
62
|
const when = result.successor.scheduledFor ? ` for ${result.successor.scheduledFor}` : '';
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
// The server's sentence IS the answer: it is derived with the JSON fields, so the two can
|
|
64
|
+
// never disagree (round 3 of OSK-15321 found them disagreeing). The fallback below is only
|
|
65
|
+
// for an older server that sends no `message`.
|
|
66
|
+
if (typeof result.message === 'string' && result.message) {
|
|
67
|
+
this.log(result.message);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
// Never call a successor with no schedule "armed": it will not fire (#4262 verification).
|
|
71
|
+
let line;
|
|
72
|
+
if (!result.successor.scheduledFor) {
|
|
73
|
+
line = `The next occurrence ${next} of the series from ${from} exists but has no schedule, so nothing will fire it on its own; start it by hand or give it a time with \`${this.config.bin} tasks schedule ${next} --at <ISO time>\`.`;
|
|
74
|
+
}
|
|
75
|
+
else if (result.rescheduled) {
|
|
76
|
+
line = `The next occurrence ${next} existed but had no schedule; it is now scheduled${when}. The failure marker is cleared.`;
|
|
77
|
+
}
|
|
78
|
+
else if (result.alreadyArmed) {
|
|
79
|
+
line = `The series from ${from} was already armed: next occurrence ${next}${when}. The failure marker is cleared.`;
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
line = `Re-armed the series from ${from}: next occurrence ${next} is scheduled${when}.`;
|
|
83
|
+
}
|
|
84
|
+
this.log(line);
|
|
66
85
|
}
|
|
67
86
|
}
|
|
68
87
|
exports.default = TasksRearmRecurrence;
|
|
@@ -69,6 +69,14 @@ export declare function labelsLine(labelIds?: string[], nameById?: Map<string, s
|
|
|
69
69
|
* reassigning the task changes only the implied kind.
|
|
70
70
|
*/
|
|
71
71
|
export declare function taskExecutorLabel(t: Record<string, unknown>, bin?: string): string;
|
|
72
|
+
/**
|
|
73
|
+
* The `Resolution:` lines for any resolved Task: how it ended, the reason the
|
|
74
|
+
* closer recorded, who closed it, and what the close stood on. The reason used to
|
|
75
|
+
* be JSON-only, so text showed "Task workflow type is cancelled" for every
|
|
76
|
+
* cancel, and a Task its Workflow step cancelled could not be told from one a
|
|
77
|
+
* person cancelled by hand (OSK-16475). Silent for an open Task.
|
|
78
|
+
*/
|
|
79
|
+
export declare function resolutionLines(t: Record<string, unknown>, names?: Map<string, string>): string[];
|
|
72
80
|
/**
|
|
73
81
|
* The `Recurrence:` line for a series whose next occurrence was never armed.
|
|
74
82
|
* Silent otherwise: a healthy series has nothing to say here.
|
|
@@ -6,6 +6,7 @@ exports.completionLines = completionLines;
|
|
|
6
6
|
exports.reviewPolicyLine = reviewPolicyLine;
|
|
7
7
|
exports.labelsLine = labelsLine;
|
|
8
8
|
exports.taskExecutorLabel = taskExecutorLabel;
|
|
9
|
+
exports.resolutionLines = resolutionLines;
|
|
9
10
|
exports.recurrenceArmFailureLines = recurrenceArmFailureLines;
|
|
10
11
|
exports.taskFailureLines = taskFailureLines;
|
|
11
12
|
const core_1 = require("@oclif/core");
|
|
@@ -151,6 +152,43 @@ function taskExecutorLabel(t, bin = 'skrr') {
|
|
|
151
152
|
return '-';
|
|
152
153
|
}
|
|
153
154
|
}
|
|
155
|
+
function resolverLabel(by, names) {
|
|
156
|
+
if (!by || typeof by !== 'object' || !by.kind)
|
|
157
|
+
return null;
|
|
158
|
+
const kind = String(by.kind);
|
|
159
|
+
if (kind === 'human')
|
|
160
|
+
return `person ${(0, principal_display_1.displayPrincipal)(by.userId, names)}`;
|
|
161
|
+
if (kind === 'agent')
|
|
162
|
+
return `agent ${(0, principal_display_1.displayPrincipal)(by.agentId, names)}`;
|
|
163
|
+
if (kind === 'system')
|
|
164
|
+
return `system${by.service ? ` (${String(by.service)})` : ''}`;
|
|
165
|
+
if (kind === 'integration')
|
|
166
|
+
return `integration${by.provider ? ` (${String(by.provider)})` : ''}`;
|
|
167
|
+
return kind;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* The `Resolution:` lines for any resolved Task: how it ended, the reason the
|
|
171
|
+
* closer recorded, who closed it, and what the close stood on. The reason used to
|
|
172
|
+
* be JSON-only, so text showed "Task workflow type is cancelled" for every
|
|
173
|
+
* cancel, and a Task its Workflow step cancelled could not be told from one a
|
|
174
|
+
* person cancelled by hand (OSK-16475). Silent for an open Task.
|
|
175
|
+
*/
|
|
176
|
+
function resolutionLines(t, names) {
|
|
177
|
+
const resolution = t.resolution;
|
|
178
|
+
if (!resolution || typeof resolution !== 'object' || !resolution.kind)
|
|
179
|
+
return [];
|
|
180
|
+
const reason = typeof resolution.reason === 'string' ? resolution.reason.trim() : '';
|
|
181
|
+
const closure = resolution.closure
|
|
182
|
+
? (0, task_closure_1.closureSnapshotLines)(resolution.closure)
|
|
183
|
+
: [];
|
|
184
|
+
const lines = [`Resolution: ${String(resolution.kind)}${reason ? ` — ${reason}` : ''}`];
|
|
185
|
+
if (closure.length > 0)
|
|
186
|
+
lines.push(` ${closure.join(' ')}`);
|
|
187
|
+
const by = resolverLabel(resolution.resolvedBy, names);
|
|
188
|
+
if (by)
|
|
189
|
+
lines.push(`Resolved by: ${by}`);
|
|
190
|
+
return lines;
|
|
191
|
+
}
|
|
154
192
|
/**
|
|
155
193
|
* The `Recurrence:` line for a series whose next occurrence was never armed.
|
|
156
194
|
* Silent otherwise: a healthy series has nothing to say here.
|
|
@@ -163,10 +201,14 @@ function recurrenceArmFailureLines(t, bin = 'skrr') {
|
|
|
163
201
|
const ref = (typeof t.identifier === 'string' && t.identifier) ||
|
|
164
202
|
(typeof t.id === 'string' && t.id) ||
|
|
165
203
|
'<task-id>';
|
|
204
|
+
// A finished occurrence is re-armed (`tasks schedule` refuses it, OSK-15338); a LIVE series the
|
|
205
|
+
// scheduler stopped on an unrunnable pattern is rescheduled with a valid one, which clears it.
|
|
206
|
+
const finished = ['completed', 'cancelled'].includes(String(t.statusType ?? ''));
|
|
166
207
|
return [
|
|
167
208
|
`Recurrence: ${(0, data_provider_1.describeRecurrenceArmFailure)(code)} (${code})`,
|
|
168
|
-
|
|
169
|
-
|
|
209
|
+
finished || t.statusType === undefined
|
|
210
|
+
? ` ${(0, task_recurrence_outcome_1.recurrenceRearmHint)(code, ref, bin)}`
|
|
211
|
+
: ` Reschedule it with \`${bin} tasks schedule ${ref} --at <ISO time> --cron "<minute hour day month weekday>"\`.`,
|
|
170
212
|
];
|
|
171
213
|
}
|
|
172
214
|
/**
|
|
@@ -352,6 +394,21 @@ class TasksShow extends base_command_1.BaseCommand {
|
|
|
352
394
|
this.log(line);
|
|
353
395
|
const agents = Array.isArray(t.assigneeAgentIds) ? t.assigneeAgentIds : [];
|
|
354
396
|
const users = Array.isArray(t.assigneeUserIds) ? t.assigneeUserIds : [];
|
|
397
|
+
// Principals print as names, not ObjectIds — same rule as labels: a
|
|
398
|
+
// roster that cannot be read prints ids rather than failing the command.
|
|
399
|
+
const resolvedBy = t.resolution?.resolvedBy;
|
|
400
|
+
const principalIds = [
|
|
401
|
+
t.author,
|
|
402
|
+
t.dri?.resolved?.id,
|
|
403
|
+
...(Array.isArray(t.assigneeAgentIds) ? t.assigneeAgentIds : []),
|
|
404
|
+
...(Array.isArray(t.assigneeUserIds) ? t.assigneeUserIds : []),
|
|
405
|
+
t.economics?.confirmedBy,
|
|
406
|
+
resolvedBy?.userId,
|
|
407
|
+
resolvedBy?.agentId,
|
|
408
|
+
];
|
|
409
|
+
const principalNames = await (0, principal_display_1.resolvePrincipalNames)(principalIds, {
|
|
410
|
+
spaceId: t.spaceId ?? null,
|
|
411
|
+
});
|
|
355
412
|
this.log(`ID: ${t.id ?? t._id ?? '-'}`);
|
|
356
413
|
this.log(`Ref: ${t.identifier ?? (t.taskNumber ? `#${t.taskNumber}` : '-')}`);
|
|
357
414
|
this.log(`Title: ${t.title ?? '-'}`);
|
|
@@ -368,25 +425,12 @@ class TasksShow extends base_command_1.BaseCommand {
|
|
|
368
425
|
* Closing is the actor's call — a Task may be `done` with work still
|
|
369
426
|
* outstanding, and `resolution.closure` is where the server recorded what
|
|
370
427
|
* it stood on at close. Show it so a bare "done" never reads as "clean."
|
|
428
|
+
* The closure sentences share the `tasks move` receipt's renderer, so the
|
|
429
|
+
* two cannot disagree; the reason and the closer are printed for every
|
|
430
|
+
* resolved Task (OSK-16475).
|
|
371
431
|
*/
|
|
372
|
-
const
|
|
373
|
-
|
|
374
|
-
* Same renderer as the `tasks move` receipt, so the two cannot disagree
|
|
375
|
-
* about a Task they are both describing.
|
|
376
|
-
*
|
|
377
|
-
* This copy showed an owner's ordinary close as an override:
|
|
378
|
-
* `TASK_RESULT_REVIEW_REQUIRED` lands in `blockers` whenever the policy is
|
|
379
|
-
* unsatisfied — including when the owner, who is not bound by the Review
|
|
380
|
-
* they declared, closes it themselves — and this rendered it identically to
|
|
381
|
-
* a genuine forced close. So the only read surface for "was this gate
|
|
382
|
-
* overridden?" could not answer the question.
|
|
383
|
-
*/
|
|
384
|
-
if (resolution?.closure) {
|
|
385
|
-
const sentences = (0, task_closure_1.closureSnapshotLines)(resolution.closure);
|
|
386
|
-
if (sentences.length > 0) {
|
|
387
|
-
this.log(`Resolution: ${resolution.kind ?? '-'} — ${sentences.join(' ')}`);
|
|
388
|
-
}
|
|
389
|
-
}
|
|
432
|
+
for (const line of resolutionLines(t, principalNames))
|
|
433
|
+
this.log(line);
|
|
390
434
|
/*
|
|
391
435
|
* A Result orphaned by a spec edit is not the same as no Result.
|
|
392
436
|
*
|
|
@@ -519,18 +563,6 @@ class TasksShow extends base_command_1.BaseCommand {
|
|
|
519
563
|
}
|
|
520
564
|
}
|
|
521
565
|
this.log(`Labels: ${labelsLine(labelIds, labelNames)}`);
|
|
522
|
-
// Principals print as names, not ObjectIds — same rule as labels above: a
|
|
523
|
-
// roster that cannot be read prints ids rather than failing the command.
|
|
524
|
-
const principalIds = [
|
|
525
|
-
t.author,
|
|
526
|
-
t.dri?.resolved?.id,
|
|
527
|
-
...(Array.isArray(t.assigneeAgentIds) ? t.assigneeAgentIds : []),
|
|
528
|
-
...(Array.isArray(t.assigneeUserIds) ? t.assigneeUserIds : []),
|
|
529
|
-
t.economics?.confirmedBy,
|
|
530
|
-
];
|
|
531
|
-
const principalNames = await (0, principal_display_1.resolvePrincipalNames)(principalIds, {
|
|
532
|
-
spaceId: t.spaceId ?? null,
|
|
533
|
-
});
|
|
534
566
|
this.log(`Author: ${t.authorDisplayName || (0, principal_display_1.displayPrincipal)(t.author, principalNames)}`);
|
|
535
567
|
const dri = t.dri;
|
|
536
568
|
if (dri?.resolved) {
|
|
@@ -5,7 +5,11 @@ const data_provider_1 = require("@skrr-ai/data-provider");
|
|
|
5
5
|
const base_command_1 = require("../../base-command");
|
|
6
6
|
const web_url_1 = require("../../lib/web-url");
|
|
7
7
|
class TasksUnschedule extends base_command_1.BaseCommand {
|
|
8
|
-
|
|
8
|
+
// Decision (OSK-15321, round 3): unschedule ENDS the series at this occurrence; it clears the
|
|
9
|
+
// time and the recurrence. Stopping without ending is `pause-schedule` (keeps the series,
|
|
10
|
+
// `resume-schedule` continues it). A series ended here by mistake is restored, settings and
|
|
11
|
+
// all, with `rearm-recurrence <the previous occurrence>`.
|
|
12
|
+
static description = 'Clear the schedule on a task and end its series here (no future fires). To stop without ending the series use pause-schedule; to restore an ended series run rearm-recurrence on the previous occurrence';
|
|
9
13
|
static examples = [
|
|
10
14
|
'<%= config.bin %> tasks unschedule <task-id>',
|
|
11
15
|
'<%= config.bin %> tasks unschedule <task-id> --json',
|
|
@@ -543,7 +543,17 @@ class TasksUpdate extends base_command_1.BaseCommand {
|
|
|
543
543
|
}
|
|
544
544
|
const t = updated;
|
|
545
545
|
const ref = t.identifier ?? (t.taskNumber ? `#${t.taskNumber}` : '');
|
|
546
|
-
|
|
546
|
+
const label = `${t.id ?? t._id ?? taskRef}${ref ? ` (${ref})` : ''}`;
|
|
547
|
+
// The server's own answer about the estimate (OSK-16476): a no-op says so, never "Updated".
|
|
548
|
+
const unchanged = (0, task_economics_1.estimateUnchangedLine)(payload.economics, t);
|
|
549
|
+
const onlyEstimate = payloadKeys.every((key) => key === 'economics' || payload[key] === undefined);
|
|
550
|
+
if (unchanged && onlyEstimate) {
|
|
551
|
+
this.log(`Task ${label}: ${unchanged}`);
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
this.log(`Updated task ${label} — ${t.title ?? '(no title)'}`);
|
|
555
|
+
if (unchanged)
|
|
556
|
+
this.log(unchanged);
|
|
547
557
|
// `--yes` asserts the revocation; it does not erase that it happened.
|
|
548
558
|
// Report the cost after the write too, or the evidence is silently gone.
|
|
549
559
|
if (changesSpec && flags.yes && (settledSpecAssessments > 0 || acceptanceUnreadable)) {
|
|
@@ -25,17 +25,25 @@ class TriggersAudit extends base_command_1.BaseCommand {
|
|
|
25
25
|
agent: core_1.Flags.string({ description: 'Agent ID filter for owner-wide audit history' }),
|
|
26
26
|
scope: core_1.Flags.string({ description: 'Scope kind filter for owner-wide audit history' }),
|
|
27
27
|
outcome: core_1.Flags.string({
|
|
28
|
-
description: 'Outcome filter
|
|
28
|
+
description: 'Outcome filter (succeeded, failed, skipped, incomplete, capped, ...); an unknown value is refused with the full list',
|
|
29
29
|
}),
|
|
30
30
|
source: core_1.Flags.string({
|
|
31
|
-
description: 'Source filter
|
|
31
|
+
description: 'Source filter (schedule, once, event, manual, webhook, replay, ...); an unknown value is refused with the full list',
|
|
32
32
|
}),
|
|
33
33
|
};
|
|
34
34
|
async run() {
|
|
35
35
|
this.requireAuth();
|
|
36
36
|
const { args, flags } = await this.parse(TriggersAudit);
|
|
37
37
|
const triggerId = args.id ?? flags.trigger;
|
|
38
|
-
|
|
38
|
+
// The per-trigger route takes no filters. A filter passed with a trigger id used to be
|
|
39
|
+
// dropped without a word, so `--outcome failed` listed succeeded rows and exited 0 (OSK-16474).
|
|
40
|
+
// A filter now always reaches the filtered history, narrowed to that trigger; that history
|
|
41
|
+
// covers triggers you own, which is said out loud rather than discovered.
|
|
42
|
+
const filtered = [flags.outcome, flags.source, flags.scope, flags.agent].some((value) => value !== undefined);
|
|
43
|
+
if (triggerId && filtered && !flags.json) {
|
|
44
|
+
this.warn('Filters read the fire history of triggers you own: a trigger shared with you but owned by someone else lists no rows here (omit the filters to read its own audit).');
|
|
45
|
+
}
|
|
46
|
+
const path = triggerId && !filtered
|
|
39
47
|
? (0, triggers_1.withQuery)(`/api/triggers/${encodeURIComponent(triggerId)}/audit`, {
|
|
40
48
|
limit: flags.limit,
|
|
41
49
|
before: flags.before,
|
|
@@ -47,6 +55,7 @@ class TriggersAudit extends base_command_1.BaseCommand {
|
|
|
47
55
|
agentId: flags.agent,
|
|
48
56
|
outcome: flags.outcome,
|
|
49
57
|
source: flags.source,
|
|
58
|
+
...(triggerId ? { triggerId } : {}),
|
|
50
59
|
});
|
|
51
60
|
let response;
|
|
52
61
|
try {
|
|
@@ -99,7 +99,7 @@ class TriggersCreate extends base_command_1.BaseCommand {
|
|
|
99
99
|
description: 'ISO-8601 datetime after which a schedule stops firing',
|
|
100
100
|
}),
|
|
101
101
|
'stale-catchup-ms': core_1.Flags.integer({
|
|
102
|
-
description: 'How late a missed occurrence may still run, in ms (
|
|
102
|
+
description: 'How late a missed occurrence may still run, in ms, from 1000 (1 second) to 31622400000 (366 days). After downtime, an occurrence more than this overdue is skipped rather than run late, and the schedule moves to its next future slot. Unset: 3600000 (1 hour).',
|
|
103
103
|
}),
|
|
104
104
|
at: core_1.Flags.string({
|
|
105
105
|
description: 'ISO-8601 datetime for once triggers. --next-run-at is also accepted with --kind once for backwards compatibility.',
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import { BaseCommand } from '../../base-command';
|
|
2
|
+
/**
|
|
3
|
+
* The text rendering of one fire. `reason` is the typed code and `errorMessage` the sentence a
|
|
4
|
+
* person reads; the view printed whichever came first, so a fire that resolved nothing showed
|
|
5
|
+
* only `Reason: no_waiting_step` and its sentence ("No step in this Space was waiting on that
|
|
6
|
+
* event key.") was JSON-only (OSK-16474). Both are shown now when both exist.
|
|
7
|
+
*/
|
|
8
|
+
export declare function describeFireAuditDetail(detail: Record<string, unknown>, fireId: string, triggerId: string): string[];
|
|
2
9
|
export default class TriggersFireDetail extends BaseCommand {
|
|
3
10
|
static description: string;
|
|
4
11
|
static examples: string[];
|
|
@@ -1,8 +1,36 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.describeFireAuditDetail = describeFireAuditDetail;
|
|
3
4
|
const core_1 = require("@oclif/core");
|
|
4
5
|
const base_command_1 = require("../../base-command");
|
|
5
6
|
const triggers_1 = require("../../lib/triggers");
|
|
7
|
+
/**
|
|
8
|
+
* The text rendering of one fire. `reason` is the typed code and `errorMessage` the sentence a
|
|
9
|
+
* person reads; the view printed whichever came first, so a fire that resolved nothing showed
|
|
10
|
+
* only `Reason: no_waiting_step` and its sentence ("No step in this Space was waiting on that
|
|
11
|
+
* event key.") was JSON-only (OSK-16474). Both are shown now when both exist.
|
|
12
|
+
*/
|
|
13
|
+
function describeFireAuditDetail(detail, fireId, triggerId) {
|
|
14
|
+
const text = (value) => (typeof value === 'string' && value.trim() ? value.trim() : '');
|
|
15
|
+
const lines = [
|
|
16
|
+
`Fire: ${String(detail._id ?? fireId)}`,
|
|
17
|
+
`Trigger: ${String(detail.triggerId ?? triggerId)}`,
|
|
18
|
+
`Fired at: ${String(detail.firedAt ?? '-')}`,
|
|
19
|
+
`Outcome: ${String(detail.outcome ?? '-')}`,
|
|
20
|
+
`Source: ${String(detail.source ?? '-')}`,
|
|
21
|
+
];
|
|
22
|
+
const reason = text(detail.reason);
|
|
23
|
+
const message = text(detail.errorMessage);
|
|
24
|
+
if (reason)
|
|
25
|
+
lines.push(`Reason: ${reason}`);
|
|
26
|
+
if (message && message !== reason)
|
|
27
|
+
lines.push(`${reason ? 'Detail:' : 'Reason:'} ${message}`);
|
|
28
|
+
if (detail.durationMs !== undefined)
|
|
29
|
+
lines.push(`Duration: ${String(detail.durationMs)}ms`);
|
|
30
|
+
if (detail.conversationId)
|
|
31
|
+
lines.push(`Conversation: ${String(detail.conversationId)}`);
|
|
32
|
+
return lines;
|
|
33
|
+
}
|
|
6
34
|
class TriggersFireDetail extends base_command_1.BaseCommand {
|
|
7
35
|
static description = 'Show full detail for one trigger fire record';
|
|
8
36
|
static examples = [
|
|
@@ -34,18 +62,8 @@ class TriggersFireDetail extends base_command_1.BaseCommand {
|
|
|
34
62
|
this.log(JSON.stringify(detail, null, 2));
|
|
35
63
|
return;
|
|
36
64
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
this.log(`Fired at: ${detail.firedAt ?? '-'}`);
|
|
40
|
-
this.log(`Outcome: ${detail.outcome ?? '-'}`);
|
|
41
|
-
this.log(`Source: ${detail.source ?? '-'}`);
|
|
42
|
-
if (detail.reason || detail.errorMessage) {
|
|
43
|
-
this.log(`Reason: ${detail.reason ?? detail.errorMessage}`);
|
|
44
|
-
}
|
|
45
|
-
if (detail.durationMs !== undefined)
|
|
46
|
-
this.log(`Duration: ${detail.durationMs}ms`);
|
|
47
|
-
if (detail.conversationId)
|
|
48
|
-
this.log(`Conversation: ${detail.conversationId}`);
|
|
65
|
+
for (const line of describeFireAuditDetail(detail, args.fireId, args.id))
|
|
66
|
+
this.log(line);
|
|
49
67
|
}
|
|
50
68
|
}
|
|
51
69
|
exports.default = TriggersFireDetail;
|
|
@@ -46,9 +46,17 @@ class TriggersFire extends base_command_1.BaseCommand {
|
|
|
46
46
|
}
|
|
47
47
|
const accepted = (0, triggers_1.fireWasAccepted)(result);
|
|
48
48
|
if (flags.json) {
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
// `ok` and the exit status are one answer: a strict refusal prints `ok: false` and why,
|
|
50
|
+
// never the server's transport-level `ok: true` beside exit 1 (OSK-16494).
|
|
51
|
+
const refused = flags.strict && !accepted;
|
|
52
|
+
this.log(JSON.stringify(refused
|
|
53
|
+
? { ...result, ok: false, strictRefusal: (0, triggers_1.describeStrictFireRefusal)(result) }
|
|
54
|
+
: result, null, 2));
|
|
55
|
+
if (refused) {
|
|
56
|
+
// stdout stays the one JSON document; the reason goes to stderr.
|
|
57
|
+
process.stderr.write(`${(0, triggers_1.describeStrictFireRefusal)(result)}\n`);
|
|
51
58
|
this.exit(1);
|
|
59
|
+
}
|
|
52
60
|
return;
|
|
53
61
|
}
|
|
54
62
|
this.log(`Fire requested: outcome=${String(result.outcome ?? '-')} reason=${String(result.reason ?? '-')}`);
|
|
@@ -57,8 +65,10 @@ class TriggersFire extends base_command_1.BaseCommand {
|
|
|
57
65
|
const note = (0, triggers_1.describeScheduledFire)(result);
|
|
58
66
|
if (note)
|
|
59
67
|
this.log(note);
|
|
60
|
-
if (flags.strict && !accepted)
|
|
68
|
+
if (flags.strict && !accepted) {
|
|
69
|
+
process.stderr.write(`${(0, triggers_1.describeStrictFireRefusal)(result)}\n`);
|
|
61
70
|
this.exit(1);
|
|
71
|
+
}
|
|
62
72
|
}
|
|
63
73
|
}
|
|
64
74
|
exports.default = TriggersFire;
|
|
@@ -26,7 +26,7 @@ class TriggersParseIntent extends base_command_1.BaseCommand {
|
|
|
26
26
|
multiple: true,
|
|
27
27
|
}),
|
|
28
28
|
'history-json': core_1.Flags.string({
|
|
29
|
-
description: 'Parser history JSON array of {role:"user"|"assistant",content:string} objects. To answer a clarifying question, pass the `history` a previous --json run returned and add your reply with --message',
|
|
29
|
+
description: 'Parser history: an inline JSON array of {role:"user"|"assistant",content:string} objects, or @file / a path to a file holding it. To answer a clarifying question, pass the `history` a previous --json run returned and add your reply with --message',
|
|
30
30
|
}),
|
|
31
31
|
timezone: core_1.Flags.string({ description: 'IANA timezone used for relative times' }),
|
|
32
32
|
now: core_1.Flags.string({ description: 'Override current ISO timestamp used for relative times' }),
|
|
@@ -56,7 +56,7 @@ class TriggersUpdate extends base_command_1.BaseCommand {
|
|
|
56
56
|
description: 'ISO-8601 datetime after which a schedule stops firing',
|
|
57
57
|
}),
|
|
58
58
|
'stale-catchup-ms': core_1.Flags.integer({
|
|
59
|
-
description: 'How late a missed occurrence may still run, in ms (
|
|
59
|
+
description: 'How late a missed occurrence may still run, in ms, from 1000 (1 second) to 31622400000 (366 days). After downtime, an occurrence more than this overdue is skipped rather than run late, and the schedule moves to its next future slot. Unset: 3600000 (1 hour).',
|
|
60
60
|
}),
|
|
61
61
|
at: core_1.Flags.string({ description: 'ISO-8601 datetime for once triggers' }),
|
|
62
62
|
entity: core_1.Flags.string({
|
|
@@ -39,10 +39,7 @@ async function memberNames(workspaceId) {
|
|
|
39
39
|
try {
|
|
40
40
|
const members = await (0, workspaces_1.listWorkspaceMembers)(workspaceId);
|
|
41
41
|
return new Map(members
|
|
42
|
-
.map((member) => [
|
|
43
|
-
String(member.userId),
|
|
44
|
-
member.user?.name || member.user?.username || member.user?.email || '',
|
|
45
|
-
])
|
|
42
|
+
.map((member) => [member.userId, member.name ?? member.email ?? ''])
|
|
46
43
|
.filter(([, name]) => name));
|
|
47
44
|
}
|
|
48
45
|
catch {
|
|
@@ -36,7 +36,7 @@ class WorkspacesMembers extends base_command_1.BaseCommand {
|
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
38
38
|
if (flags.json) {
|
|
39
|
-
this.
|
|
39
|
+
this.printJsonResult(members);
|
|
40
40
|
return;
|
|
41
41
|
}
|
|
42
42
|
if (members.length === 0) {
|
|
@@ -44,11 +44,11 @@ class WorkspacesMembers extends base_command_1.BaseCommand {
|
|
|
44
44
|
return;
|
|
45
45
|
}
|
|
46
46
|
(0, format_1.renderTable)(members.map((member) => ({
|
|
47
|
-
userId:
|
|
48
|
-
name: member.
|
|
49
|
-
email: member.
|
|
50
|
-
role: member.role
|
|
51
|
-
joined: member.joinedAt
|
|
47
|
+
userId: member.userId,
|
|
48
|
+
name: member.name ?? '—',
|
|
49
|
+
email: member.email ?? '—',
|
|
50
|
+
role: member.role ?? '—',
|
|
51
|
+
joined: member.joinedAt ?? '—',
|
|
52
52
|
})), [
|
|
53
53
|
{ key: 'userId', header: 'USER ID', verbatim: true },
|
|
54
54
|
{ key: 'name', header: 'NAME', maxWidth: 28 },
|
|
@@ -62,9 +62,12 @@ function renderExecutionReceipt(receipt, log, verbose = false) {
|
|
|
62
62
|
// restates what happened (a typed blocker's summary, which servers before
|
|
63
63
|
// OSK-16429 sent as the reason) is narrative, not something to do: the actor
|
|
64
64
|
// is printed without it and the narrative stays with the blocker.
|
|
65
|
+
// A bare reason code (servers before OSK-16451 sent `runtime_connection_unverifiable`
|
|
66
|
+
// there) is not an action either: the actor is printed alone.
|
|
65
67
|
const narrative = [receipt.summary, receipt.blocker?.summary].filter(Boolean);
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
+
const reason = receipt.nextActor?.reason;
|
|
69
|
+
const action = reason && !narrative.includes(reason) && !/^[A-Za-z0-9_.:-]+$/.test(reason.trim())
|
|
70
|
+
? reason
|
|
68
71
|
: '';
|
|
69
72
|
if (receipt.nextActor)
|
|
70
73
|
log(`Next: ${receipt.nextActor.label || receipt.nextActor.kind}${action ? ` — ${action}` : ''}`);
|
|
@@ -832,8 +832,9 @@ export declare function describeOperation(operation: string | null | undefined,
|
|
|
832
832
|
* under "Fix:" read as a remedy nobody wrote (OSK-16230). That narrative is
|
|
833
833
|
* labelled `Blocker:` instead, and no remedy is made up for it.
|
|
834
834
|
*/
|
|
835
|
+
type OperationFixLabel = 'Fix' | 'Blocker' | 'Last run';
|
|
835
836
|
export declare function describeOperationFix(commitment: CommitmentView, operation: string | null | undefined): Array<{
|
|
836
|
-
label:
|
|
837
|
+
label: OperationFixLabel;
|
|
837
838
|
text: string;
|
|
838
839
|
}>;
|
|
839
840
|
/**
|