@skrr-ai/cli 0.1.108 → 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/README.md +10 -0
- package/dist/base-command.d.ts +74 -0
- package/dist/base-command.js +182 -24
- 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 +25 -0
- package/dist/commands/agents/update.js +98 -3
- package/dist/commands/commitments/accounting.js +7 -2
- package/dist/commands/commitments/cost.d.ts +11 -0
- package/dist/commands/commitments/cost.js +26 -3
- package/dist/commands/commitments/create.js +2 -1
- package/dist/commands/commitments/operating-review.d.ts +15 -0
- package/dist/commands/commitments/operating-review.js +103 -50
- package/dist/commands/commitments/update.js +12 -5
- package/dist/commands/daemon/install.js +17 -1
- package/dist/commands/daemon/login.js +14 -0
- package/dist/commands/doctor.js +9 -0
- package/dist/commands/goals/list.js +6 -1
- package/dist/commands/grants/rotate.js +4 -0
- package/dist/commands/harnesses/prune.d.ts +26 -0
- package/dist/commands/harnesses/prune.js +172 -0
- package/dist/commands/login.js +53 -14
- package/dist/commands/machines/list.js +28 -6
- package/dist/commands/projects/show.js +1 -1
- package/dist/commands/revoke-daemon.js +2 -1
- package/dist/commands/spaces/workflows/archive.d.ts +1 -0
- package/dist/commands/spaces/workflows/archive.js +1 -0
- package/dist/commands/spaces/workflows/artifact.d.ts +1 -0
- package/dist/commands/spaces/workflows/artifact.js +1 -0
- package/dist/commands/spaces/workflows/cancel-node.d.ts +1 -0
- package/dist/commands/spaces/workflows/cancel-node.js +1 -0
- package/dist/commands/spaces/workflows/cancel.d.ts +1 -0
- package/dist/commands/spaces/workflows/cancel.js +6 -2
- package/dist/commands/spaces/workflows/create.d.ts +1 -0
- package/dist/commands/spaces/workflows/create.js +7 -1
- package/dist/commands/spaces/workflows/events.d.ts +1 -0
- package/dist/commands/spaces/workflows/events.js +1 -0
- package/dist/commands/spaces/workflows/fixtures/create.d.ts +1 -0
- package/dist/commands/spaces/workflows/fixtures/create.js +1 -0
- package/dist/commands/spaces/workflows/fixtures/list.d.ts +1 -0
- package/dist/commands/spaces/workflows/fixtures/list.js +1 -0
- package/dist/commands/spaces/workflows/lifecycle-diagnostics.d.ts +1 -0
- package/dist/commands/spaces/workflows/lifecycle-diagnostics.js +1 -0
- package/dist/commands/spaces/workflows/list.d.ts +1 -0
- package/dist/commands/spaces/workflows/list.js +1 -0
- package/dist/commands/spaces/workflows/node-types.d.ts +2 -0
- package/dist/commands/spaces/workflows/node-types.js +24 -6
- package/dist/commands/spaces/workflows/pause.d.ts +1 -0
- package/dist/commands/spaces/workflows/pause.js +1 -0
- package/dist/commands/spaces/workflows/plan/show.d.ts +1 -0
- package/dist/commands/spaces/workflows/plan/show.js +1 -0
- package/dist/commands/spaces/workflows/plan/update.d.ts +1 -0
- package/dist/commands/spaces/workflows/plan/update.js +1 -0
- package/dist/commands/spaces/workflows/proposals/apply.d.ts +1 -0
- package/dist/commands/spaces/workflows/proposals/apply.js +1 -0
- package/dist/commands/spaces/workflows/proposals/confirm.d.ts +1 -0
- package/dist/commands/spaces/workflows/proposals/confirm.js +1 -0
- package/dist/commands/spaces/workflows/proposals/create.d.ts +1 -0
- package/dist/commands/spaces/workflows/proposals/create.js +1 -0
- package/dist/commands/spaces/workflows/proposals/dismiss.d.ts +1 -0
- package/dist/commands/spaces/workflows/proposals/dismiss.js +1 -0
- package/dist/commands/spaces/workflows/proposals/list.d.ts +1 -0
- package/dist/commands/spaces/workflows/proposals/list.js +1 -0
- package/dist/commands/spaces/workflows/publish.d.ts +1 -0
- package/dist/commands/spaces/workflows/publish.js +9 -0
- package/dist/commands/spaces/workflows/reconcile.d.ts +1 -0
- package/dist/commands/spaces/workflows/reconcile.js +1 -0
- package/dist/commands/spaces/workflows/resume.d.ts +1 -0
- package/dist/commands/spaces/workflows/resume.js +1 -0
- package/dist/commands/spaces/workflows/retry.d.ts +1 -0
- package/dist/commands/spaces/workflows/retry.js +1 -0
- package/dist/commands/spaces/workflows/run.d.ts +1 -0
- package/dist/commands/spaces/workflows/run.js +14 -7
- package/dist/commands/spaces/workflows/runs.d.ts +1 -0
- package/dist/commands/spaces/workflows/runs.js +1 -0
- package/dist/commands/spaces/workflows/show.d.ts +25 -0
- package/dist/commands/spaces/workflows/show.js +42 -4
- package/dist/commands/spaces/workflows/signal.d.ts +12 -0
- package/dist/commands/spaces/workflows/signal.js +40 -2
- package/dist/commands/spaces/workflows/start.d.ts +1 -0
- package/dist/commands/spaces/workflows/start.js +4 -1
- package/dist/commands/spaces/workflows/task-execution/create.d.ts +1 -0
- package/dist/commands/spaces/workflows/task-execution/create.js +1 -0
- package/dist/commands/spaces/workflows/test.d.ts +1 -0
- package/dist/commands/spaces/workflows/test.js +1 -0
- package/dist/commands/spaces/workflows/triggers/create.d.ts +1 -0
- package/dist/commands/spaces/workflows/triggers/create.js +1 -0
- package/dist/commands/spaces/workflows/triggers/fire.d.ts +1 -0
- package/dist/commands/spaces/workflows/triggers/fire.js +1 -0
- package/dist/commands/spaces/workflows/triggers/list.d.ts +1 -0
- package/dist/commands/spaces/workflows/triggers/list.js +1 -0
- package/dist/commands/spaces/workflows/triggers/update.d.ts +1 -0
- package/dist/commands/spaces/workflows/triggers/update.js +1 -0
- package/dist/commands/spaces/workflows/update.d.ts +1 -0
- package/dist/commands/spaces/workflows/update.js +4 -0
- package/dist/commands/spaces/workflows/validate.d.ts +1 -0
- package/dist/commands/spaces/workflows/validate.js +27 -2
- package/dist/commands/tasks/activity.js +17 -3
- package/dist/commands/tasks/bulk-update.d.ts +1 -0
- package/dist/commands/tasks/bulk-update.js +7 -0
- package/dist/commands/tasks/complete.js +2 -1
- package/dist/commands/tasks/create-tree.d.ts +69 -0
- package/dist/commands/tasks/create-tree.js +413 -47
- package/dist/commands/tasks/list.d.ts +2 -0
- package/dist/commands/tasks/list.js +25 -3
- package/dist/commands/tasks/rearm-recurrence.d.ts +22 -0
- package/dist/commands/tasks/rearm-recurrence.js +87 -0
- package/dist/commands/tasks/show.d.ts +9 -0
- package/dist/commands/tasks/show.js +79 -33
- package/dist/commands/tasks/timeline.js +4 -0
- package/dist/commands/tasks/unschedule.js +5 -1
- package/dist/commands/tasks/update.d.ts +1 -0
- package/dist/commands/tasks/update.js +17 -2
- package/dist/commands/triggers/audit.js +12 -3
- package/dist/commands/triggers/create.js +9 -3
- 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.d.ts +7 -0
- package/dist/commands/triggers/parse-intent.js +31 -9
- package/dist/commands/triggers/update.js +1 -1
- package/dist/commands/workspaces/grants.js +20 -3
- package/dist/commands/workspaces/members.d.ts +20 -0
- package/dist/commands/workspaces/members.js +64 -0
- package/dist/commands/workspaces/stewardship.js +14 -2
- package/dist/help.js +12 -0
- package/dist/hooks/command-not-found.js +27 -1
- package/dist/lib/command-miss.d.ts +52 -2
- package/dist/lib/command-miss.js +187 -18
- package/dist/lib/commitment-loop-status.d.ts +8 -0
- package/dist/lib/commitment-loop-status.js +45 -0
- package/dist/lib/commitment-product.js +5 -2
- package/dist/lib/commitments.d.ts +18 -3
- package/dist/lib/commitments.js +85 -45
- package/dist/lib/daemon-command-hint.d.ts +15 -0
- package/dist/lib/daemon-command-hint.js +21 -0
- 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/daemon-setup.js +10 -1
- package/dist/lib/daemonBrokerRefusal.js +3 -2
- package/dist/lib/daemonHandoff.d.ts +19 -1
- package/dist/lib/daemonHandoff.js +61 -1
- package/dist/lib/deployed-build.d.ts +43 -0
- package/dist/lib/deployed-build.js +66 -0
- package/dist/lib/grants.d.ts +27 -1
- package/dist/lib/grants.js +39 -21
- package/dist/lib/harnesses.d.ts +71 -0
- package/dist/lib/harnesses.js +70 -0
- package/dist/lib/json-mode.d.ts +11 -0
- package/dist/lib/json-mode.js +19 -0
- package/dist/lib/json-output.d.ts +25 -0
- package/dist/lib/json-output.js +30 -0
- package/dist/lib/list-output.d.ts +10 -1
- package/dist/lib/list-output.js +22 -1
- package/dist/lib/local-daemon-readiness.d.ts +90 -0
- package/dist/lib/local-daemon-readiness.js +143 -0
- package/dist/lib/machines.d.ts +117 -0
- package/dist/lib/machines.js +139 -0
- package/dist/lib/managed-instruction-local.d.ts +2 -0
- package/dist/lib/managed-instruction-local.js +2 -0
- package/dist/lib/profile-machine-identity-guard.d.ts +18 -0
- package/dist/lib/profile-machine-identity-guard.js +39 -0
- package/dist/lib/request-field-flags.d.ts +20 -0
- package/dist/lib/request-field-flags.js +34 -0
- package/dist/lib/stewardship-output.d.ts +1 -1
- package/dist/lib/stewardship-output.js +26 -30
- package/dist/lib/task-batch.d.ts +61 -4
- package/dist/lib/task-batch.js +316 -80
- package/dist/lib/task-economics.d.ts +15 -0
- package/dist/lib/task-economics.js +39 -2
- package/dist/lib/task-recurrence-outcome.d.ts +6 -6
- package/dist/lib/task-recurrence-outcome.js +27 -3
- package/dist/lib/tasks.d.ts +39 -0
- package/dist/lib/tasks.js +132 -0
- package/dist/lib/triggers.d.ts +42 -1
- package/dist/lib/triggers.js +98 -2
- package/dist/lib/workflow-issues.d.ts +14 -0
- package/dist/lib/workflow-issues.js +32 -0
- package/dist/lib/workflow-run-view.d.ts +59 -0
- package/dist/lib/workflow-run-view.js +110 -0
- package/dist/lib/workspaces.d.ts +48 -4
- package/dist/lib/workspaces.js +55 -0
- package/dist/lib/write-target.d.ts +29 -0
- package/dist/lib/write-target.js +72 -0
- 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/cjs/workspaceIsolationProbeWire.d.ts +51 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/workspaceIsolationProbeWire.js +50 -0
- 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/dist/esm/workspaceIsolationProbeWire.d.ts +51 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/workspaceIsolationProbeWire.js +46 -0
- package/dist/node_modules/@skrr-ai/auth-core/package.json +11 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +7523 -7140
- package/oclif.manifest.json +473 -59
- package/package.json +28 -1
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.AGENT_FENCE_RETRY_CODES = void 0;
|
|
4
4
|
exports.agentUpdateWarnings = agentUpdateWarnings;
|
|
5
|
+
exports.agentRowFromUpdate = agentRowFromUpdate;
|
|
6
|
+
exports.alwaysOnReceiptLine = alwaysOnReceiptLine;
|
|
7
|
+
exports.writeReceiptWarnings = writeReceiptWarnings;
|
|
5
8
|
exports.retryOnceOnAgentFence = retryOnceOnAgentFence;
|
|
6
9
|
exports.defaultPermissionModePatch = defaultPermissionModePatch;
|
|
7
10
|
exports.defaultPermissionModeNote = defaultPermissionModeNote;
|
|
@@ -184,7 +187,9 @@ class AgentsUpdate extends base_command_1.BaseCommand {
|
|
|
184
187
|
this.error(err.message, { exit: 1 });
|
|
185
188
|
}
|
|
186
189
|
if (Object.keys(payload).length === 0) {
|
|
187
|
-
this.error('Nothing to update. Pass at least one flag (e.g. --name) or --from-json.', {
|
|
190
|
+
this.error('Nothing to update. Pass at least one flag (e.g. --name) or --from-json.', {
|
|
191
|
+
exit: 1,
|
|
192
|
+
});
|
|
188
193
|
}
|
|
189
194
|
let updated;
|
|
190
195
|
try {
|
|
@@ -209,8 +214,26 @@ class AgentsUpdate extends base_command_1.BaseCommand {
|
|
|
209
214
|
this.log(JSON.stringify((0, web_url_1.withAgentUrl)(this.cliConfig.baseURL, updated), null, 2));
|
|
210
215
|
return;
|
|
211
216
|
}
|
|
212
|
-
|
|
213
|
-
|
|
217
|
+
// The Always-On control replies with its own envelope, which names no agent.
|
|
218
|
+
// Name it from the Agent's own row, not "(no name)" (OSK-16477).
|
|
219
|
+
const a = agentRowFromUpdate(updated) ?? { id: args.id };
|
|
220
|
+
if (typeof a.name !== 'string') {
|
|
221
|
+
try {
|
|
222
|
+
const row = (await data_provider_1.dataService.getAgentById({ agent_id: args.id }));
|
|
223
|
+
if (row &&
|
|
224
|
+
typeof row === 'object' &&
|
|
225
|
+
typeof row.name === 'string') {
|
|
226
|
+
a.name = row.name;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
// The update already happened; a failed name read only costs the label.
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
this.log(`Updated agent ${a.id ?? a._id ?? args.id} — ${typeof a.name === 'string' ? a.name || '(no name)' : '(name unavailable)'}`);
|
|
234
|
+
const alwaysOnLine = alwaysOnReceiptLine(payload, updated);
|
|
235
|
+
if (alwaysOnLine)
|
|
236
|
+
this.log(alwaysOnLine);
|
|
214
237
|
this.log(`URL: ${(0, web_url_1.withAgentUrl)(this.cliConfig.baseURL, { ...a, id: a.id ?? a._id ?? args.id }).url ?? '-'}`);
|
|
215
238
|
const modeNote = defaultPermissionModeNote(flags['default-permission-mode'], a);
|
|
216
239
|
if (modeNote)
|
|
@@ -240,9 +263,18 @@ exports.default = AgentsUpdate;
|
|
|
240
263
|
* through `--from-json` was reported as "not an agent field" after the server
|
|
241
264
|
* had cleared it on purpose (OSK-12167).
|
|
242
265
|
*
|
|
266
|
+
* All of that is the fallback for a server that predates `writeReceipt`. When
|
|
267
|
+
* the response carries a receipt, the server's own account of each key is used
|
|
268
|
+
* instead and nothing is inferred from the response's shape (OSK-15070).
|
|
269
|
+
*
|
|
243
270
|
* Exported for tests.
|
|
244
271
|
*/
|
|
245
272
|
function agentUpdateWarnings(payload, updated) {
|
|
273
|
+
// A server that reports what it did with each key is the authority; the
|
|
274
|
+
// shape comparison below is only for a server older than the receipt.
|
|
275
|
+
const receipt = (0, data_provider_1.readAgentWriteReceipt)(updated);
|
|
276
|
+
if (receipt)
|
|
277
|
+
return writeReceiptWarnings(payload, receipt);
|
|
246
278
|
const isRecord = (value) => value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
247
279
|
const controlReply = isRecord(updated) &&
|
|
248
280
|
typeof updated.agentId === 'string' &&
|
|
@@ -273,6 +305,69 @@ function agentUpdateWarnings(payload, updated) {
|
|
|
273
305
|
...(unapplied.length > 0 ? [(0, create_1.unappliedPayloadKeysWarning)(unapplied)] : []),
|
|
274
306
|
];
|
|
275
307
|
}
|
|
308
|
+
/**
|
|
309
|
+
* The Agent row inside an update reply: the reply itself for an ordinary
|
|
310
|
+
* PATCH, `agent` inside the Always-On control envelope, or null when the
|
|
311
|
+
* control reply carries none (a PATCH of `isAlwaysOn` alone). Exported for tests.
|
|
312
|
+
*/
|
|
313
|
+
function agentRowFromUpdate(updated) {
|
|
314
|
+
if (!updated || typeof updated !== 'object' || Array.isArray(updated))
|
|
315
|
+
return null;
|
|
316
|
+
const reply = updated;
|
|
317
|
+
const isControlReply = typeof reply.agentId === 'string' && reply.state !== null && typeof reply.state === 'object';
|
|
318
|
+
if (!isControlReply)
|
|
319
|
+
return { ...reply };
|
|
320
|
+
const agent = reply.agent;
|
|
321
|
+
return agent && typeof agent === 'object' && !Array.isArray(agent)
|
|
322
|
+
? { ...agent, id: agent.id ?? reply.agentId }
|
|
323
|
+
: { id: reply.agentId };
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* One line for an `isAlwaysOn` write, from the receipt: applied, or already in
|
|
327
|
+
* that state so nothing changed (OSK-16477). Exported for tests.
|
|
328
|
+
*/
|
|
329
|
+
function alwaysOnReceiptLine(payload, updated) {
|
|
330
|
+
if (typeof payload.isAlwaysOn !== 'boolean')
|
|
331
|
+
return null;
|
|
332
|
+
const receipt = (0, data_provider_1.readAgentWriteReceipt)(updated);
|
|
333
|
+
if (!receipt)
|
|
334
|
+
return null;
|
|
335
|
+
const state = payload.isAlwaysOn ? 'on' : 'off';
|
|
336
|
+
if (receipt.unchanged.some((entry) => entry.field === 'isAlwaysOn')) {
|
|
337
|
+
return `Always-On: already ${state}; nothing changed.`;
|
|
338
|
+
}
|
|
339
|
+
if (receipt.applied.some((entry) => entry.field === 'isAlwaysOn')) {
|
|
340
|
+
return `Always-On: turned ${state}.`;
|
|
341
|
+
}
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Warnings from the server's `writeReceipt` (OSK-15070). The receipt names
|
|
346
|
+
* every key the write saw as applied (and through which control: the legacy
|
|
347
|
+
* `isAlwaysOn` goes to the Always-On control and is applied, not "not kept") or
|
|
348
|
+
* ignored with a reason. A sent key it does not mention never reached the write.
|
|
349
|
+
*
|
|
350
|
+
* Exported for tests.
|
|
351
|
+
*/
|
|
352
|
+
function writeReceiptWarnings(payload, receipt) {
|
|
353
|
+
const explained = receipt.ignored
|
|
354
|
+
.filter((entry) => entry.reason !== 'not_an_agent_field')
|
|
355
|
+
.map((entry) => `${entry.field}: ${entry.detail || 'ignored by the server'}`);
|
|
356
|
+
const notFields = receipt.ignored
|
|
357
|
+
.filter((entry) => entry.reason === 'not_an_agent_field')
|
|
358
|
+
.map((entry) => entry.field);
|
|
359
|
+
const unreported = (0, data_provider_1.unreportedAgentWriteFields)(payload, receipt);
|
|
360
|
+
const warnings = [...explained];
|
|
361
|
+
if (notFields.length > 0)
|
|
362
|
+
warnings.push((0, create_1.unappliedPayloadKeysWarning)(notFields));
|
|
363
|
+
if (unreported.length > 0) {
|
|
364
|
+
const one = unreported.length === 1;
|
|
365
|
+
warnings.push(`The server did not receive ${unreported.join(', ')}: a request filter removed ` +
|
|
366
|
+
`${one ? 'it' : 'them'} before the write, so nothing was changed for ${one ? 'it' : 'them'}. ` +
|
|
367
|
+
'`skrr agents show <id> --json` shows what the agent stores.');
|
|
368
|
+
}
|
|
369
|
+
return warnings;
|
|
370
|
+
}
|
|
276
371
|
/**
|
|
277
372
|
* The per-Agent mutation fence's "another request holds this right now"
|
|
278
373
|
* refusals. `updateAgent` takes a short lease on the Agent before it writes, so
|
|
@@ -4,6 +4,7 @@ exports.formatAccountingReadout = formatAccountingReadout;
|
|
|
4
4
|
const core_1 = require("@oclif/core");
|
|
5
5
|
const base_command_1 = require("../../base-command");
|
|
6
6
|
const commitments_1 = require("../../lib/commitments");
|
|
7
|
+
const cost_1 = require("./cost");
|
|
7
8
|
/**
|
|
8
9
|
* `skrr commitments accounting <id>` — the allowance-accounting SHADOW readout.
|
|
9
10
|
*
|
|
@@ -92,14 +93,18 @@ function formatAccountingReadout(readout) {
|
|
|
92
93
|
// a priced window and an unpriced one read alike (OSK-10940).
|
|
93
94
|
const costStatus = readout.costStatus ?? 'not_applicable';
|
|
94
95
|
const costCaveat = {
|
|
95
|
-
reported:
|
|
96
|
+
reported: "every run's cost is known",
|
|
96
97
|
partial: 'some runs reported no cost — the total is a FLOOR',
|
|
97
98
|
unavailable: 'no run reported a cost — the total is meaningless',
|
|
98
99
|
not_applicable: 'no closed runs in the window',
|
|
99
100
|
};
|
|
100
101
|
lines.push(`Window cost: $${(Number(readout.costUsdMicros || 0) / 1_000_000).toFixed(4)}` +
|
|
101
102
|
` — ${costStatus}: ${costCaveat[costStatus] ?? 'unrecognized cost status'}` +
|
|
102
|
-
` (${Number(readout.costReportedRunCount || 0)} of ${Number(readout.costRunCount || 0)} runs priced
|
|
103
|
+
` (${Number(readout.costReportedRunCount || 0)} of ${Number(readout.costRunCount || 0)} runs priced` +
|
|
104
|
+
`, ${Number(readout.costNoSpendRunCount || 0)} refused before starting)`);
|
|
105
|
+
const noSpendNote = (0, cost_1.noSpendInferenceNote)(Number(readout.costNoSpendRunCount || 0), Number(readout.costNoSpendInferredRunCount || 0));
|
|
106
|
+
if (noSpendNote)
|
|
107
|
+
lines.push(noSpendNote);
|
|
103
108
|
const multiplier = readout.recommendedAttemptMultiplier;
|
|
104
109
|
lines.push('');
|
|
105
110
|
lines.push(`Attempt multiplier: ${multiplier == null ? 'not derivable yet' : multiplier}` +
|
|
@@ -60,3 +60,14 @@ export default class CommitmentsCost extends BaseCommand {
|
|
|
60
60
|
* formed a belief by the time they reach the caveat.
|
|
61
61
|
*/
|
|
62
62
|
export declare function formatCostWindow(data: CommitmentCostWindow): string[];
|
|
63
|
+
/**
|
|
64
|
+
* The line that says when "cost nothing" rests on inference (OSK-15500).
|
|
65
|
+
*
|
|
66
|
+
* A Run refused before any model turn records that fact when it is refused.
|
|
67
|
+
* Runs written before the fact was recorded are judged by the platform's legacy
|
|
68
|
+
* inference (admission-denied status, a pre-start refusal code, cancelled before
|
|
69
|
+
* any claim). Both are counted as $0 by the live budget, the spend ledger and
|
|
70
|
+
* this read alike — but a reader must be able to tell a recorded fact from an
|
|
71
|
+
* inferred one, so an inferred share is always printed, never folded in.
|
|
72
|
+
*/
|
|
73
|
+
export declare function noSpendInferenceNote(noSpend: number, inferred: number): string | null;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.resolveCostWindow = resolveCostWindow;
|
|
4
4
|
exports.formatCostWindow = formatCostWindow;
|
|
5
|
+
exports.noSpendInferenceNote = noSpendInferenceNote;
|
|
5
6
|
const core_1 = require("@oclif/core");
|
|
6
7
|
const base_command_1 = require("../../base-command");
|
|
7
8
|
const commitments_1 = require("../../lib/commitments");
|
|
@@ -113,18 +114,40 @@ function formatCostWindow(data) {
|
|
|
113
114
|
const micros = Number(data.costUsdMicros || 0);
|
|
114
115
|
const runs = Number(data.runCount || 0);
|
|
115
116
|
const unattributed = Number(data.unavailableRunCount || 0);
|
|
117
|
+
const noSpend = Number(data.noSpendRunCount || 0);
|
|
116
118
|
const status = data.costStatus ?? 'not_applicable';
|
|
117
119
|
const caveat = {
|
|
118
|
-
reported:
|
|
120
|
+
reported: "every run's cost in the window is known",
|
|
119
121
|
partial: 'some runs reported no cost — the total below is a FLOOR',
|
|
120
122
|
unavailable: 'no run in the window reported a cost — the total below is meaningless',
|
|
121
123
|
not_applicable: 'no closed runs in the window',
|
|
122
124
|
};
|
|
123
|
-
|
|
125
|
+
const lines = [
|
|
124
126
|
`Cost for ${data.commitmentId ?? '-'}`,
|
|
125
127
|
`Window: ${data.from ?? '-'} → ${data.to ?? '-'} (${Number(data.dayCount || 0)} closed day(s))`,
|
|
126
128
|
`Attribution: ${status} — ${caveat[status] ?? 'unrecognized cost status'}`,
|
|
127
129
|
`Cost: $${(micros / 1_000_000).toFixed(4)}`,
|
|
128
|
-
`Runs: ${runs} (${Number(data.reportedRunCount || 0)} with cost,
|
|
130
|
+
`Runs: ${runs} (${Number(data.reportedRunCount || 0)} with cost, ` +
|
|
131
|
+
`${noSpend} refused before starting, ${unattributed} without)`,
|
|
129
132
|
];
|
|
133
|
+
const note = noSpendInferenceNote(noSpend, Number(data.noSpendInferredRunCount || 0));
|
|
134
|
+
if (note)
|
|
135
|
+
lines.push(note);
|
|
136
|
+
return lines;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* The line that says when "cost nothing" rests on inference (OSK-15500).
|
|
140
|
+
*
|
|
141
|
+
* A Run refused before any model turn records that fact when it is refused.
|
|
142
|
+
* Runs written before the fact was recorded are judged by the platform's legacy
|
|
143
|
+
* inference (admission-denied status, a pre-start refusal code, cancelled before
|
|
144
|
+
* any claim). Both are counted as $0 by the live budget, the spend ledger and
|
|
145
|
+
* this read alike — but a reader must be able to tell a recorded fact from an
|
|
146
|
+
* inferred one, so an inferred share is always printed, never folded in.
|
|
147
|
+
*/
|
|
148
|
+
function noSpendInferenceNote(noSpend, inferred) {
|
|
149
|
+
if (!(inferred > 0))
|
|
150
|
+
return null;
|
|
151
|
+
return (`Note: ${inferred} of the ${noSpend} run(s) refused before starting are counted ` +
|
|
152
|
+
'as $0 by inference (recorded before refusals were stored), not from a recorded refusal');
|
|
130
153
|
}
|
|
@@ -156,7 +156,8 @@ function createCadenceFromFlags({ eventDriven, cadence: cadenceInput, cadenceMod
|
|
|
156
156
|
* For a natural-language draft instead of flags, use `skrr commitments plan`.
|
|
157
157
|
*/
|
|
158
158
|
class CommitmentsCreate extends base_command_1.BaseCommand {
|
|
159
|
-
static description = 'Create a commitment (a durable agent contract)'
|
|
159
|
+
static description = 'Create a commitment (a durable agent contract). Its cadence is manual, an interval or daily clock times; ' +
|
|
160
|
+
'it has no weekday, holiday, business-day or trading-calendar fields';
|
|
160
161
|
static examples = [
|
|
161
162
|
'<%= config.bin %> commitments create --agent <agent-id> --title "Ship v2" --outcome "v2 is live for all users" --cadence 6h',
|
|
162
163
|
'<%= config.bin %> commitments create --agent <agent-id> --title "Hiring loop" --outcome "Every candidate hears back in 48h" --watch tasks --watch email --cadence 12h',
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import type { CommitmentLoopStatus } from '@skrr-ai/data-provider';
|
|
1
2
|
import { BaseCommand } from '../../base-command';
|
|
2
3
|
type SystemCommitmentRow = {
|
|
4
|
+
id?: string;
|
|
3
5
|
systemRole?: string;
|
|
4
6
|
status?: string;
|
|
5
7
|
lastCheckedAt?: string;
|
|
@@ -13,6 +15,19 @@ type SystemCommitmentRow = {
|
|
|
13
15
|
* (OSK-15438): an Agent that cannot run cannot have asked.
|
|
14
16
|
*/
|
|
15
17
|
export declare function noQuestionsSentence(alwaysOn: boolean, roles: SystemCommitmentRow[]): string;
|
|
18
|
+
/**
|
|
19
|
+
* What the roster said about this Agent's loops, or why it could not be read. The review's own rows
|
|
20
|
+
* carry only the stored lifecycle status; whether a loop is armed, when it next wakes, why it last
|
|
21
|
+
* stopped and whether it can read its sources come from the roster (OSK-15438, OSK-15412).
|
|
22
|
+
*/
|
|
23
|
+
export type OperatingReviewLoops = {
|
|
24
|
+
rows: Map<string, CommitmentLoopStatus>;
|
|
25
|
+
truncated: boolean;
|
|
26
|
+
} | {
|
|
27
|
+
error: string;
|
|
28
|
+
};
|
|
29
|
+
/** The review as text. Pure, so the whole output can be pinned. */
|
|
30
|
+
export declare function formatOperatingReview(review: Record<string, unknown>, loops: OperatingReviewLoops): string[];
|
|
16
31
|
export default class CommitmentsOperatingReview extends BaseCommand {
|
|
17
32
|
static description: string;
|
|
18
33
|
static args: {
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.noQuestionsSentence = noQuestionsSentence;
|
|
4
|
+
exports.formatOperatingReview = formatOperatingReview;
|
|
4
5
|
const core_1 = require("@oclif/core");
|
|
5
6
|
const base_command_1 = require("../../base-command");
|
|
7
|
+
const commitment_loop_status_1 = require("../../lib/commitment-loop-status");
|
|
6
8
|
const commitments_1 = require("../../lib/commitments");
|
|
7
9
|
/** What each silent loop is for, in the owner's terms rather than the role key. */
|
|
8
10
|
const ROLE_PURPOSE = {
|
|
@@ -39,6 +41,79 @@ function noQuestionsSentence(alwaysOn, roles) {
|
|
|
39
41
|
? 'None. It has not told you anything is missing.'
|
|
40
42
|
: 'None recorded yet. None of its loops has checked, so this says nothing about whether anything is missing.';
|
|
41
43
|
}
|
|
44
|
+
/** The review as text. Pure, so the whole output can be pinned. */
|
|
45
|
+
function formatOperatingReview(review, loops) {
|
|
46
|
+
const lines = [];
|
|
47
|
+
const roles = review.systemCommitments || [];
|
|
48
|
+
const alwaysOn = review.alwaysOn === true;
|
|
49
|
+
const questions = review.openQuestions || [];
|
|
50
|
+
const portfolio = review.portfolio || {};
|
|
51
|
+
const metrics = review.metrics || {};
|
|
52
|
+
lines.push(`Agent ${review.agentId}`);
|
|
53
|
+
lines.push('');
|
|
54
|
+
// A loop's own status says `active`, but a system-managed loop is only
|
|
55
|
+
// given a scheduling trigger while the Agent is Always-On. Printing
|
|
56
|
+
// `active` beside "last checked never" without saying that read as
|
|
57
|
+
// "nothing has happened yet" rather than "this cannot happen", and nothing
|
|
58
|
+
// led the owner to the switch that decides it.
|
|
59
|
+
if (!alwaysOn) {
|
|
60
|
+
lines.push('Always-On is OFF — these loops are provisioned but will not run.');
|
|
61
|
+
lines.push(` skrr agents always-on enable ${review.agentId}`);
|
|
62
|
+
lines.push('');
|
|
63
|
+
}
|
|
64
|
+
lines.push('Background loops');
|
|
65
|
+
if (roles.length === 0) {
|
|
66
|
+
lines.push(' (none provisioned)');
|
|
67
|
+
}
|
|
68
|
+
if ('error' in loops) {
|
|
69
|
+
// "Cannot see" must not read as "nothing to report": say what is missing and what it hides.
|
|
70
|
+
lines.push(` Loop detail unavailable (${loops.error}). The states below are the stored lifecycle only; ` +
|
|
71
|
+
'they do not say whether a loop is armed, what it can read, or why it last stopped.');
|
|
72
|
+
}
|
|
73
|
+
for (const role of roles) {
|
|
74
|
+
const key = role.systemRole || '?';
|
|
75
|
+
const purpose = ROLE_PURPOSE[key] ? ` — ${ROLE_PURPOSE[key]}` : '';
|
|
76
|
+
const contact = role.maxUserNudgesPerDay && role.maxUserNudgesPerDay > 0
|
|
77
|
+
? `may contact you ${role.maxUserNudgesPerDay}/day`
|
|
78
|
+
: 'never contacts you';
|
|
79
|
+
// `idle` replaces `active` only. A paused loop is paused for its own
|
|
80
|
+
// reason — Relationship Pulse ships paused as a separate consent
|
|
81
|
+
// decision — and collapsing that into `idle` would hide a distinction
|
|
82
|
+
// the owner needs when they do turn Always-On on.
|
|
83
|
+
const state = !alwaysOn && role.status === 'active' ? 'idle' : role.status || '?';
|
|
84
|
+
lines.push(` ${state.padEnd(7)} ${key}${purpose}`);
|
|
85
|
+
lines.push(` last checked ${ago(role.lastCheckedAt)} · ${contact}`);
|
|
86
|
+
if ('rows' in loops) {
|
|
87
|
+
const row = role.id ? loops.rows.get(role.id) : undefined;
|
|
88
|
+
if (row) {
|
|
89
|
+
for (const line of (0, commitment_loop_status_1.formatLoopSummary)(row))
|
|
90
|
+
lines.push(` ${line}`);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
lines.push(` loop detail: not in the roster read${loops.truncated ? ' (the roster is bounded and this Agent holds more)' : ''}; run \`skrr commitments status ${role.id ?? '<id>'}\``);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
lines.push('');
|
|
98
|
+
lines.push(`Open questions from this agent (${questions.length})`);
|
|
99
|
+
if (questions.length === 0) {
|
|
100
|
+
lines.push(` ${noQuestionsSentence(alwaysOn, roles)}`);
|
|
101
|
+
}
|
|
102
|
+
for (const q of questions) {
|
|
103
|
+
lines.push(` • ${q.question}`);
|
|
104
|
+
if (q.whyItMatters)
|
|
105
|
+
lines.push(` why: ${q.whyItMatters}`);
|
|
106
|
+
lines.push(` asked ${ago(q.askedAt)}`);
|
|
107
|
+
}
|
|
108
|
+
lines.push('');
|
|
109
|
+
const drafts = portfolio.draftCommitmentCount ?? 0;
|
|
110
|
+
lines.push(`Business commitments: ${portfolio.activeCommitmentCount ?? 0} active, ${portfolio.pausedCommitmentCount ?? 0} paused${drafts > 0 ? `, ${drafts} draft` : ''}`);
|
|
111
|
+
if (typeof metrics.awaitingApproval === 'number') {
|
|
112
|
+
lines.push(`Proposals awaiting your approval: ${metrics.awaitingApproval}`);
|
|
113
|
+
}
|
|
114
|
+
lines.push(`Every commitment it holds, loop by loop: skrr commitments roster --agent ${review.agentId}`);
|
|
115
|
+
return lines;
|
|
116
|
+
}
|
|
42
117
|
class CommitmentsOperatingReview extends base_command_1.BaseCommand {
|
|
43
118
|
static description = 'Read an agent’s system-managed commitment operating review';
|
|
44
119
|
static args = {
|
|
@@ -60,61 +135,39 @@ class CommitmentsOperatingReview extends base_command_1.BaseCommand {
|
|
|
60
135
|
catch (error) {
|
|
61
136
|
this.handleApiError(error);
|
|
62
137
|
}
|
|
138
|
+
// The roster is a second read; its failure must not take the review down with it, and must not
|
|
139
|
+
// pass for "nothing to report" either.
|
|
140
|
+
let loops;
|
|
141
|
+
try {
|
|
142
|
+
const roster = await commitments_1.commitmentApi.roster(args.agentId);
|
|
143
|
+
loops = {
|
|
144
|
+
rows: new Map((Array.isArray(roster.commitments) ? roster.commitments : []).map((row) => [
|
|
145
|
+
row.commitmentId,
|
|
146
|
+
row,
|
|
147
|
+
])),
|
|
148
|
+
truncated: roster.truncated === true,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
loops = { error: error instanceof Error ? error.message : String(error) };
|
|
153
|
+
}
|
|
63
154
|
if (flags.json) {
|
|
64
|
-
|
|
155
|
+
const review = result;
|
|
156
|
+
const roles = review.systemCommitments || [];
|
|
157
|
+
this.log(JSON.stringify('error' in loops
|
|
158
|
+
? { ...review, loopStatusError: loops.error }
|
|
159
|
+
: {
|
|
160
|
+
...review,
|
|
161
|
+
loopStatus: roles
|
|
162
|
+
.map((role) => (role.id ? loops.rows.get(role.id) : undefined))
|
|
163
|
+
.filter((row) => row !== undefined),
|
|
164
|
+
}, null, 2));
|
|
65
165
|
return;
|
|
66
166
|
}
|
|
67
167
|
// Without this the command printed raw JSON in both modes, which is why the
|
|
68
168
|
// meta loops read as machinery rather than as something an owner supervises.
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
const alwaysOn = review.alwaysOn === true;
|
|
72
|
-
const questions = review.openQuestions || [];
|
|
73
|
-
const portfolio = review.portfolio || {};
|
|
74
|
-
this.log(`Agent ${review.agentId}`);
|
|
75
|
-
this.log('');
|
|
76
|
-
// A loop's own status says `active`, but a system-managed loop is only
|
|
77
|
-
// given a scheduling trigger while the Agent is Always-On. Printing
|
|
78
|
-
// `active` beside "last checked never" without saying that read as
|
|
79
|
-
// "nothing has happened yet" rather than "this cannot happen", and nothing
|
|
80
|
-
// led the owner to the switch that decides it.
|
|
81
|
-
if (!alwaysOn) {
|
|
82
|
-
this.log('Always-On is OFF — these loops are provisioned but will not run.');
|
|
83
|
-
this.log(` skrr agents always-on enable ${review.agentId}`);
|
|
84
|
-
this.log('');
|
|
85
|
-
}
|
|
86
|
-
this.log('Background loops');
|
|
87
|
-
if (roles.length === 0) {
|
|
88
|
-
this.log(' (none provisioned)');
|
|
89
|
-
}
|
|
90
|
-
for (const role of roles) {
|
|
91
|
-
const key = role.systemRole || '?';
|
|
92
|
-
const purpose = ROLE_PURPOSE[key] ? ` — ${ROLE_PURPOSE[key]}` : '';
|
|
93
|
-
const contact = role.maxUserNudgesPerDay && role.maxUserNudgesPerDay > 0
|
|
94
|
-
? `may contact you ${role.maxUserNudgesPerDay}/day`
|
|
95
|
-
: 'never contacts you';
|
|
96
|
-
// `idle` replaces `active` only. A paused loop is paused for its own
|
|
97
|
-
// reason — Relationship Pulse ships paused as a separate consent
|
|
98
|
-
// decision — and collapsing that into `idle` would hide a distinction
|
|
99
|
-
// the owner needs when they do turn Always-On on.
|
|
100
|
-
const state = !alwaysOn && role.status === 'active' ? 'idle' : role.status || '?';
|
|
101
|
-
this.log(` ${state.padEnd(7)} ${key}${purpose}`);
|
|
102
|
-
this.log(` last checked ${ago(role.lastCheckedAt)} · ${contact}`);
|
|
103
|
-
}
|
|
104
|
-
this.log('');
|
|
105
|
-
this.log(`Open questions from this agent (${questions.length})`);
|
|
106
|
-
if (questions.length === 0) {
|
|
107
|
-
this.log(` ${noQuestionsSentence(alwaysOn, roles)}`);
|
|
108
|
-
}
|
|
109
|
-
for (const q of questions) {
|
|
110
|
-
this.log(` • ${q.question}`);
|
|
111
|
-
if (q.whyItMatters)
|
|
112
|
-
this.log(` why: ${q.whyItMatters}`);
|
|
113
|
-
this.log(` asked ${ago(q.askedAt)}`);
|
|
114
|
-
}
|
|
115
|
-
this.log('');
|
|
116
|
-
const drafts = portfolio.draftCommitmentCount ?? 0;
|
|
117
|
-
this.log(`Business commitments: ${portfolio.activeCommitmentCount ?? 0} active, ${portfolio.pausedCommitmentCount ?? 0} paused${drafts > 0 ? `, ${drafts} draft` : ''}`);
|
|
169
|
+
for (const line of formatOperatingReview(result, loops))
|
|
170
|
+
this.log(line);
|
|
118
171
|
}
|
|
119
172
|
}
|
|
120
173
|
exports.default = CommitmentsOperatingReview;
|
|
@@ -31,7 +31,8 @@ const commitments_1 = require("../../lib/commitments");
|
|
|
31
31
|
* the contract untouched.
|
|
32
32
|
*/
|
|
33
33
|
class CommitmentsUpdate extends base_command_1.BaseCommand {
|
|
34
|
-
static description = "Update a commitment's contract (title, target, cadence, sources)"
|
|
34
|
+
static description = "Update a commitment's contract (title, target, cadence, sources). A cadence is manual, an interval or daily clock times; " +
|
|
35
|
+
'it has no weekday, holiday, business-day or trading-calendar fields';
|
|
35
36
|
static examples = [
|
|
36
37
|
'<%= config.bin %> commitments update <commitment-id> --cadence 12h',
|
|
37
38
|
'<%= config.bin %> commitments update <commitment-id> --title "Ship v2 (Q3)" --outcome "v2 is live for all users"',
|
|
@@ -275,9 +276,13 @@ JSON
|
|
|
275
276
|
// only for a binding it still names; explicit JSON is the authored base.
|
|
276
277
|
const declarations = Array.isArray(payload.watchedSources)
|
|
277
278
|
? (0, commitments_1.normalizeWatchedSourceDeclarations)(payload.watchedSources)
|
|
278
|
-
: current?.watchedSources ?? [];
|
|
279
|
+
: (current?.watchedSources ?? []);
|
|
279
280
|
payload.watchedSources = built.map((next) => {
|
|
280
|
-
const scopeKey = next.source === 'space'
|
|
281
|
+
const scopeKey = next.source === 'space'
|
|
282
|
+
? 'spaceId'
|
|
283
|
+
: next.source === 'monitor'
|
|
284
|
+
? 'monitorId'
|
|
285
|
+
: undefined;
|
|
281
286
|
const nextConfig = next.config;
|
|
282
287
|
const prior = declarations.find((binding) => binding?.source === next.source &&
|
|
283
288
|
(!scopeKey || binding.config?.[scopeKey] === nextConfig?.[scopeKey]));
|
|
@@ -301,7 +306,9 @@ JSON
|
|
|
301
306
|
storedCadence[key] = existing[key];
|
|
302
307
|
}
|
|
303
308
|
if (payload.cadence !== undefined) {
|
|
304
|
-
if (!payload.cadence ||
|
|
309
|
+
if (!payload.cadence ||
|
|
310
|
+
typeof payload.cadence !== 'object' ||
|
|
311
|
+
Array.isArray(payload.cadence)) {
|
|
305
312
|
this.error('cadence must be a JSON object when using cadence flags.', { exit: 1 });
|
|
306
313
|
}
|
|
307
314
|
}
|
|
@@ -403,7 +410,7 @@ JSON
|
|
|
403
410
|
this.log(JSON.stringify((0, web_url_1.withCommitmentUrl)(this.cliConfig.baseURL, commitment), null, 2));
|
|
404
411
|
return;
|
|
405
412
|
}
|
|
406
|
-
this.log(
|
|
413
|
+
this.log((0, commitments_1.describeCommitmentRevision)(commitment?.revision));
|
|
407
414
|
(0, commitments_1.renderCommitmentSummary)(commitment, (line) => this.log(line));
|
|
408
415
|
}
|
|
409
416
|
}
|
|
@@ -5,6 +5,9 @@ const exec_runtime_binary_1 = require("../../lib/exec-runtime-binary");
|
|
|
5
5
|
const daemon_binding_1 = require("../../lib/daemon-binding");
|
|
6
6
|
const daemon_installer_1 = require("../../lib/daemon-installer");
|
|
7
7
|
const daemon_setup_1 = require("../../lib/daemon-setup");
|
|
8
|
+
const daemonHandoff_1 = require("../../lib/daemonHandoff");
|
|
9
|
+
const daemon_machine_identity_copy_1 = require("../../lib/daemon-machine-identity-copy");
|
|
10
|
+
const live_runtime_binary_1 = require("../../lib/live-runtime-binary");
|
|
8
11
|
/**
|
|
9
12
|
* `skrr daemon install` — install the local runtime's OS service.
|
|
10
13
|
*
|
|
@@ -83,7 +86,20 @@ class DaemonInstall extends core_1.Command {
|
|
|
83
86
|
// moment the binding is chosen, and leaving it to a separate command
|
|
84
87
|
// is how a CLI and its daemon end up on different deployments
|
|
85
88
|
// (OSK-279) without anyone doing anything wrong.
|
|
86
|
-
const
|
|
89
|
+
const installArgs = (0, daemon_binding_1.bindToCliSession)(argv);
|
|
90
|
+
// A service installed from a daemon that predates per-profile machine
|
|
91
|
+
// identities runs that daemon for good, and registers the profile on the
|
|
92
|
+
// default profile's machine row (OSK-S-440). Ask the binary about to run.
|
|
93
|
+
// `--help` and `--json` are not installs.
|
|
94
|
+
if (!installArgs.some((arg) => ['--help', '-h'].includes(arg))) {
|
|
95
|
+
const skew = await (0, daemonHandoff_1.checkLocalDaemonMachineIdentity)((0, live_runtime_binary_1.profileFromArgs)(installArgs));
|
|
96
|
+
if (skew) {
|
|
97
|
+
for (const line of (0, daemon_machine_identity_copy_1.describeDaemonMachineIdentitySkew)(skew))
|
|
98
|
+
this.logToStderr(line);
|
|
99
|
+
this.exit(78);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const code = await (0, exec_runtime_binary_1.execRuntimeBinary)(['install', ...installArgs]);
|
|
87
103
|
if (code === 0 &&
|
|
88
104
|
!argv.some((arg) => ['--json', '--help', '-h'].includes(arg))) {
|
|
89
105
|
this.log('Coding-agent instructions: sign in with `skrr login`, or review installation choices with `skrr instructions setup`.');
|
|
@@ -4,6 +4,8 @@ const core_1 = require("@oclif/core");
|
|
|
4
4
|
const daemon_binding_1 = require("../../lib/daemon-binding");
|
|
5
5
|
const exec_runtime_binary_1 = require("../../lib/exec-runtime-binary");
|
|
6
6
|
const live_runtime_binary_1 = require("../../lib/live-runtime-binary");
|
|
7
|
+
const daemonHandoff_1 = require("../../lib/daemonHandoff");
|
|
8
|
+
const daemon_machine_identity_copy_1 = require("../../lib/daemon-machine-identity-copy");
|
|
7
9
|
/**
|
|
8
10
|
* `skrr daemon login` — authenticate the local runtime.
|
|
9
11
|
*
|
|
@@ -53,6 +55,18 @@ class DaemonLogin extends core_1.Command {
|
|
|
53
55
|
if (decision?.kind === 'forward-live') {
|
|
54
56
|
this.warn(`Signing in with the live daemon binary ${decision.binary}.`);
|
|
55
57
|
}
|
|
58
|
+
// The binary about to sign this profile in must register it under the
|
|
59
|
+
// machine identity the profile has (OSK-S-440): a daemon that predates
|
|
60
|
+
// per-profile identities would bind this login to the default profile's
|
|
61
|
+
// machine row. `--help` is not a login.
|
|
62
|
+
if (!boundArgv.some((arg) => ['--help', '-h'].includes(arg))) {
|
|
63
|
+
const skew = await (0, daemonHandoff_1.checkLocalDaemonMachineIdentity)((0, live_runtime_binary_1.profileFromArgs)(boundArgv), decision?.binary ?? pathBinary);
|
|
64
|
+
if (skew) {
|
|
65
|
+
for (const line of (0, daemon_machine_identity_copy_1.describeDaemonMachineIdentitySkew)(skew))
|
|
66
|
+
this.logToStderr(line);
|
|
67
|
+
this.exit(78);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
56
70
|
// `--cwd` is deliberately NOT defaulted here. `skrrd login` resolves it
|
|
57
71
|
// from the installed service definition, which is the only authoritative
|
|
58
72
|
// answer; guessing it from the CLI's cwd is exactly the mistake that made
|
package/dist/commands/doctor.js
CHANGED
|
@@ -49,6 +49,7 @@ const cli_runtime_1 = require("../lib/cli-runtime");
|
|
|
49
49
|
const command_manifest_1 = require("../lib/command-manifest");
|
|
50
50
|
const completion_index_1 = require("../lib/completion-index");
|
|
51
51
|
const runtime_context_1 = require("../lib/runtime-context");
|
|
52
|
+
const deployed_build_1 = require("../lib/deployed-build");
|
|
52
53
|
const outbox_1 = require("../lib/outbox");
|
|
53
54
|
/**
|
|
54
55
|
* What each check actually verifies, in the words a reader thinks in.
|
|
@@ -230,6 +231,9 @@ class Doctor extends base_command_1.BaseCommand {
|
|
|
230
231
|
}
|
|
231
232
|
}
|
|
232
233
|
}
|
|
234
|
+
// OSK-15497 — which code the server is running, API and web separately.
|
|
235
|
+
// Public reads, no credential; a failure is reported, never an issue.
|
|
236
|
+
const deployed = await (0, deployed_build_1.readDeployedBuild)(this.cliConfig.baseURL);
|
|
233
237
|
const now = Date.now();
|
|
234
238
|
const jwtExp = this.resolvedCredential?.token
|
|
235
239
|
? (0, auth_core_1.decodeJwtExpiry)(this.resolvedCredential.token)
|
|
@@ -287,6 +291,9 @@ class Doctor extends base_command_1.BaseCommand {
|
|
|
287
291
|
command: process.argv.slice(1).join(' '),
|
|
288
292
|
},
|
|
289
293
|
server: this.cliConfig.baseURL,
|
|
294
|
+
// The commit the server's API image and its published web shell were
|
|
295
|
+
// each built from. They differ whenever a release changed only one.
|
|
296
|
+
deployed,
|
|
290
297
|
profile: (0, keychain_1.getActiveProfile)(),
|
|
291
298
|
config: {
|
|
292
299
|
path: (0, config_1.getConfigPath)(),
|
|
@@ -351,6 +358,8 @@ class Doctor extends base_command_1.BaseCommand {
|
|
|
351
358
|
}
|
|
352
359
|
this.log(`skrr CLI ${payload.cli.version} at ${root}`);
|
|
353
360
|
this.log(`Server: ${payload.server}`);
|
|
361
|
+
for (const line of (0, deployed_build_1.deployedBuildLines)(deployed))
|
|
362
|
+
this.log(line);
|
|
354
363
|
this.log(`Auth: ${payload.auth.signedIn
|
|
355
364
|
? `${account?.email ?? account?.id}`
|
|
356
365
|
: serverReachability === 'unavailable'
|
|
@@ -5,6 +5,7 @@ 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
|
const format_1 = require("../../lib/format");
|
|
8
|
+
const list_output_1 = require("../../lib/list-output");
|
|
8
9
|
class GoalsList extends base_command_1.BaseCommand {
|
|
9
10
|
static description = 'List goals';
|
|
10
11
|
static examples = [
|
|
@@ -72,7 +73,11 @@ class GoalsList extends base_command_1.BaseCommand {
|
|
|
72
73
|
this.handleApiError(err);
|
|
73
74
|
}
|
|
74
75
|
if (flags.json) {
|
|
75
|
-
|
|
76
|
+
// The one list envelope (`{object:'list', data, has_more, next_cursor}`), so
|
|
77
|
+
// a script reads `.data` here exactly as it does for tasks and projects. The
|
|
78
|
+
// space-scoped endpoint is not paginated and answers a bare `{data}`; filling
|
|
79
|
+
// the missing fields is additive, so nothing that read `.data` changes.
|
|
80
|
+
this.log(JSON.stringify((0, web_url_1.withDataUrls)(this.cliConfig.baseURL, (0, list_output_1.toListEnvelope)(response) ?? response, web_url_1.goalUrlFrom), null, 2));
|
|
76
81
|
return;
|
|
77
82
|
}
|
|
78
83
|
// Both listGoals and listSpaceGoals return { data: Goal[] }. The general
|
|
@@ -51,6 +51,10 @@ class GrantsRotate extends base_command_1.BaseCommand {
|
|
|
51
51
|
}
|
|
52
52
|
this.log(`Rotated grant ${grant.id}.`);
|
|
53
53
|
this.log(` variables: ${grant.credential?.envKeys.join(', ') || '—'}`);
|
|
54
|
+
// When the server recorded the new value: the proof the rotation landed,
|
|
55
|
+
// without anything derived from the value itself (OSK-15358).
|
|
56
|
+
if (grant.credential?.setAt)
|
|
57
|
+
this.log(` value set: ${grant.credential.setAt}`);
|
|
54
58
|
if (!grant.access) {
|
|
55
59
|
this.log(' access: not declared (rotation clears the declared class; use --access to re-declare)');
|
|
56
60
|
}
|