@skrr-ai/cli 0.1.21 → 0.1.23
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 +83 -73
- package/bin/dev-fallback.js +221 -0
- package/bin/run.js +43 -0
- package/dist/base-command.d.ts +15 -0
- package/dist/base-command.js +71 -10
- package/dist/commands/agents/attach-harness.d.ts +37 -0
- package/dist/commands/agents/attach-harness.js +102 -3
- package/dist/commands/agents/chat.d.ts +69 -1
- package/dist/commands/agents/chat.js +202 -22
- package/dist/commands/agents/create.d.ts +38 -0
- package/dist/commands/agents/create.js +95 -2
- package/dist/commands/agents/schedule-trace.js +11 -0
- package/dist/commands/agents/show.js +29 -1
- package/dist/commands/api-keys/create.d.ts +24 -0
- package/dist/commands/api-keys/create.js +80 -0
- package/dist/commands/api-keys/list.d.ts +11 -0
- package/dist/commands/api-keys/list.js +42 -0
- package/dist/commands/api-keys/revoke.d.ts +14 -0
- package/dist/commands/api-keys/revoke.js +33 -0
- package/dist/commands/api-keys/rotate.d.ts +19 -0
- package/dist/commands/api-keys/rotate.js +42 -0
- package/dist/commands/balance/index.d.ts +18 -0
- package/dist/commands/balance/index.js +29 -0
- package/dist/commands/balance/show.d.ts +25 -0
- package/dist/commands/balance/show.js +60 -0
- package/dist/commands/balance/statement.d.ts +19 -0
- package/dist/commands/balance/statement.js +52 -0
- package/dist/commands/browser/doctor.d.ts +11 -0
- package/dist/commands/browser/doctor.js +11 -0
- package/dist/commands/code/jobs/approve.d.ts +25 -0
- package/dist/commands/code/jobs/approve.js +52 -0
- package/dist/commands/code/jobs/cancel.d.ts +12 -0
- package/dist/commands/code/jobs/cancel.js +39 -0
- package/dist/commands/code/jobs/index.d.ts +19 -0
- package/dist/commands/code/jobs/index.js +38 -0
- package/dist/commands/code/jobs/list.d.ts +12 -0
- package/dist/commands/code/jobs/list.js +87 -0
- package/dist/commands/code/jobs/run.d.ts +32 -0
- package/dist/commands/code/jobs/run.js +151 -0
- package/dist/commands/code/jobs/show.d.ts +12 -0
- package/dist/commands/code/jobs/show.js +86 -0
- package/dist/commands/commitments/create.d.ts +1 -0
- package/dist/commands/commitments/create.js +19 -5
- package/dist/commands/commitments/preflight.js +18 -4
- package/dist/commands/commitments/receipt-metrics.d.ts +39 -0
- package/dist/commands/commitments/receipt-metrics.js +78 -0
- package/dist/commands/convos/search.js +5 -5
- package/dist/commands/harnesses/leases/list.d.ts +3 -0
- package/dist/commands/harnesses/leases/list.js +59 -12
- package/dist/commands/harnesses/leases/show.js +36 -0
- package/dist/commands/harnesses/list.d.ts +18 -0
- package/dist/commands/harnesses/list.js +30 -0
- package/dist/commands/harnesses/products.js +48 -3
- package/dist/commands/harnesses/quota.d.ts +16 -0
- package/dist/commands/harnesses/quota.js +26 -1
- package/dist/commands/harnesses/usage.js +17 -0
- package/dist/commands/inbox/index.d.ts +2 -1
- package/dist/commands/inbox/index.js +27 -4
- package/dist/commands/login.js +4 -1
- package/dist/commands/machines/list.d.ts +1 -0
- package/dist/commands/machines/list.js +33 -5
- package/dist/commands/memory/approvals/issue.d.ts +18 -0
- package/dist/commands/memory/approvals/issue.js +63 -0
- package/dist/commands/memory/commit.js +5 -2
- package/dist/commands/memory/context.d.ts +3 -2
- package/dist/commands/memory/context.js +9 -11
- package/dist/commands/memory/delete.d.ts +1 -1
- package/dist/commands/memory/list.d.ts +1 -1
- package/dist/commands/memory/list.js +1 -1
- package/dist/commands/memory/mounts/resolve.d.ts +10 -0
- package/dist/commands/memory/mounts/resolve.js +27 -0
- package/dist/commands/memory/proposals/commit.d.ts +18 -0
- package/dist/commands/memory/proposals/commit.js +32 -0
- package/dist/commands/memory/proposals/create.d.ts +18 -0
- package/dist/commands/memory/proposals/create.js +56 -0
- package/dist/commands/memory/proposals/list.d.ts +13 -0
- package/dist/commands/memory/proposals/list.js +31 -0
- package/dist/commands/memory/proposals/promote.d.ts +22 -0
- package/dist/commands/memory/proposals/promote.js +33 -0
- package/dist/commands/memory/proposals/reject.d.ts +16 -0
- package/dist/commands/memory/proposals/reject.js +28 -0
- package/dist/commands/memory/rebuild-index.d.ts +20 -0
- package/dist/commands/memory/rebuild-index.js +25 -0
- package/dist/commands/memory/save.d.ts +1 -1
- package/dist/commands/memory/save.js +1 -1
- package/dist/commands/memory/search.d.ts +6 -3
- package/dist/commands/memory/search.js +27 -3
- package/dist/commands/memory/show.d.ts +1 -1
- package/dist/commands/memory/stores/archive.d.ts +14 -0
- package/dist/commands/memory/stores/archive.js +31 -0
- package/dist/commands/memory/stores/create.d.ts +12 -0
- package/dist/commands/memory/stores/create.js +30 -0
- package/dist/commands/memory/stores/delete.d.ts +15 -0
- package/dist/commands/memory/stores/delete.js +38 -0
- package/dist/commands/memory/stores/list.d.ts +10 -0
- package/dist/commands/memory/stores/list.js +29 -0
- package/dist/commands/memory/stores/show.d.ts +12 -0
- package/dist/commands/memory/stores/show.js +14 -0
- package/dist/commands/memory/stores/update.d.ts +15 -0
- package/dist/commands/memory/stores/update.js +39 -0
- package/dist/commands/memory/sync/delete.d.ts +13 -0
- package/dist/commands/memory/sync/delete.js +35 -0
- package/dist/commands/memory/sync/pull.d.ts +19 -0
- package/dist/commands/memory/sync/pull.js +52 -0
- package/dist/commands/memory/sync/push.d.ts +18 -0
- package/dist/commands/memory/sync/push.js +115 -0
- package/dist/commands/memory/sync/resolve.d.ts +23 -0
- package/dist/commands/memory/sync/resolve.js +27 -0
- package/dist/commands/memory/sync/status.d.ts +9 -0
- package/dist/commands/memory/sync/status.js +22 -0
- package/dist/commands/memory/topics/archive.d.ts +20 -0
- package/dist/commands/memory/topics/archive.js +29 -0
- package/dist/commands/memory/topics/create.d.ts +23 -0
- package/dist/commands/memory/topics/create.js +46 -0
- package/dist/commands/memory/topics/delete.d.ts +22 -0
- package/dist/commands/memory/topics/delete.js +30 -0
- package/dist/commands/memory/topics/forget.d.ts +22 -0
- package/dist/commands/memory/topics/forget.js +29 -0
- package/dist/commands/memory/topics/list.d.ts +13 -0
- package/dist/commands/memory/topics/list.js +22 -0
- package/dist/commands/memory/topics/move.d.ts +22 -0
- package/dist/commands/memory/topics/move.js +26 -0
- package/dist/commands/memory/topics/show.d.ts +17 -0
- package/dist/commands/memory/topics/show.js +21 -0
- package/dist/commands/memory/topics/update.d.ts +23 -0
- package/dist/commands/memory/topics/update.js +27 -0
- package/dist/commands/memory/tree.d.ts +5 -2
- package/dist/commands/memory/tree.js +20 -2
- package/dist/commands/memory/update.d.ts +1 -1
- package/dist/commands/memory/versions/list.d.ts +16 -0
- package/dist/commands/memory/versions/list.js +22 -0
- package/dist/commands/memory/versions/redact.d.ts +21 -0
- package/dist/commands/memory/versions/redact.js +22 -0
- package/dist/commands/memory/versions/restore.d.ts +20 -0
- package/dist/commands/memory/versions/restore.js +16 -0
- package/dist/commands/memory/versions/show.d.ts +15 -0
- package/dist/commands/memory/versions/show.js +17 -0
- package/dist/commands/messages/list.js +25 -8
- package/dist/commands/messages/show.js +10 -0
- package/dist/commands/store/install.js +5 -1
- package/dist/commands/store/releases.js +1 -1
- package/dist/commands/store/update.js +5 -1
- package/dist/commands/subscriptions/cancel.js +5 -1
- package/dist/commands/subscriptions/health.js +5 -1
- package/dist/commands/subscriptions/status.js +5 -1
- package/dist/commands/subscriptions/subscribe.js +5 -1
- package/dist/commands/tasks/activity.d.ts +2 -3
- package/dist/commands/tasks/activity.js +15 -5
- package/dist/commands/tasks/complete.d.ts +18 -150
- package/dist/commands/tasks/complete.js +161 -600
- package/dist/commands/tasks/create.d.ts +5 -0
- package/dist/commands/tasks/create.js +107 -4
- package/dist/commands/tasks/deliverable/add.d.ts +8 -0
- package/dist/commands/tasks/deliverable/add.js +41 -8
- package/dist/commands/tasks/deliverable/confirm.d.ts +5 -5
- package/dist/commands/tasks/deliverable/confirm.js +9 -18
- package/dist/commands/tasks/deliverable/list.d.ts +12 -0
- package/dist/commands/tasks/deliverable/list.js +37 -0
- package/dist/commands/tasks/events/append.d.ts +2 -0
- package/dist/commands/tasks/events/append.js +11 -4
- package/dist/commands/tasks/events/list.d.ts +1 -0
- package/dist/commands/tasks/events/list.js +1 -0
- package/dist/commands/tasks/events/tail.d.ts +1 -0
- package/dist/commands/tasks/events/tail.js +1 -0
- package/dist/commands/tasks/expectations/assess.d.ts +21 -0
- package/dist/commands/tasks/expectations/assess.js +77 -0
- package/dist/commands/tasks/expectations.js +14 -18
- package/dist/commands/tasks/judge.d.ts +1 -0
- package/dist/commands/tasks/judge.js +2 -1
- package/dist/commands/tasks/output.d.ts +2 -11
- package/dist/commands/tasks/output.js +64 -145
- package/dist/commands/tasks/report.d.ts +3 -3
- package/dist/commands/tasks/report.js +64 -41
- package/dist/commands/tasks/resource/add.d.ts +23 -0
- package/dist/commands/tasks/resource/add.js +76 -0
- package/dist/commands/tasks/resource/list.d.ts +13 -0
- package/dist/commands/tasks/resource/list.js +41 -0
- package/dist/commands/tasks/result/show.d.ts +13 -0
- package/dist/commands/tasks/result/show.js +46 -0
- package/dist/commands/tasks/result/submit.d.ts +26 -0
- package/dist/commands/tasks/result/submit.js +134 -0
- package/dist/commands/tasks/resume/save.d.ts +16 -0
- package/dist/commands/tasks/resume/save.js +59 -0
- package/dist/commands/tasks/resume/show.d.ts +13 -0
- package/dist/commands/tasks/resume/show.js +35 -0
- package/dist/commands/tasks/review.d.ts +17 -0
- package/dist/commands/tasks/review.js +54 -0
- package/dist/commands/tasks/runs.js +5 -0
- package/dist/commands/tasks/timeline.d.ts +2 -2
- package/dist/commands/tasks/timeline.js +10 -23
- package/dist/commands/tasks/updates/add.d.ts +22 -0
- package/dist/commands/tasks/updates/add.js +101 -0
- package/dist/commands/tasks/updates/list.d.ts +15 -0
- package/dist/commands/tasks/updates/list.js +57 -0
- package/dist/commands/tasks/waive.d.ts +1 -0
- package/dist/commands/tasks/waive.js +2 -1
- package/dist/lib/agentic-stream.d.ts +257 -0
- package/dist/lib/agentic-stream.js +490 -33
- package/dist/lib/balance.d.ts +8 -0
- package/dist/lib/commitment-product.d.ts +10 -1
- package/dist/lib/commitment-product.js +66 -2
- package/dist/lib/commitments.d.ts +4 -1
- package/dist/lib/commitments.js +32 -1
- package/dist/lib/conversation-search.d.ts +3 -0
- package/dist/lib/conversation-search.js +75 -0
- package/dist/lib/execution-target.d.ts +21 -0
- package/dist/lib/execution-target.js +22 -6
- package/dist/lib/harnesses.d.ts +82 -6
- package/dist/lib/harnesses.js +30 -2
- package/dist/lib/hosted-machines.js +9 -0
- package/dist/lib/inbox.d.ts +2 -1
- package/dist/lib/machines.d.ts +17 -0
- package/dist/lib/machines.js +29 -0
- package/dist/lib/managed-agent-keys.d.ts +104 -0
- package/dist/lib/managed-agent-keys.js +50 -0
- package/dist/lib/memory-scope.d.ts +4 -3
- package/dist/lib/memory-scope.js +9 -9
- package/dist/lib/memory-sync.d.ts +114 -0
- package/dist/lib/memory-sync.js +730 -0
- package/dist/lib/message-provenance.d.ts +42 -0
- package/dist/lib/message-provenance.js +89 -0
- package/dist/lib/scoped-memory-command.d.ts +68 -0
- package/dist/lib/scoped-memory-command.js +183 -0
- package/dist/lib/session-task-endpoints.d.ts +1 -1
- package/dist/lib/session-task-endpoints.js +7 -0
- package/dist/lib/sky-code-broker.d.ts +47 -0
- package/dist/lib/sky-code-broker.js +50 -0
- package/dist/lib/sky-code-doctor.js +10 -1
- package/dist/lib/task-artifact-flags.d.ts +2 -0
- package/dist/lib/task-artifact-flags.js +7 -0
- package/dist/lib/task-execution.d.ts +4 -5
- package/dist/lib/task-execution.js +4 -5
- package/dist/lib/task-extras.d.ts +1 -5
- package/dist/lib/task-extras.js +1 -5
- package/dist/lib/task-transcript.d.ts +5 -7
- package/dist/lib/task-transcript.js +8 -16
- package/dist/lib/tasks.d.ts +7 -21
- package/dist/lib/tasks.js +17 -20
- package/dist/lib/triggers.d.ts +39 -1
- package/dist/lib/triggers.js +70 -2
- package/dist/lib/usage-discovery.d.ts +17 -1
- package/dist/lib/usage-discovery.js +17 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +3733 -3618
- package/oclif.manifest.json +25726 -19886
- package/package.json +26 -5
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.previousClosedQuarter = previousClosedQuarter;
|
|
4
|
+
const core_1 = require("@oclif/core");
|
|
5
|
+
const base_command_1 = require("../../base-command");
|
|
6
|
+
const commitments_1 = require("../../lib/commitments");
|
|
7
|
+
const commitment_product_1 = require("../../lib/commitment-product");
|
|
8
|
+
/**
|
|
9
|
+
* The quarter to report when the caller names none.
|
|
10
|
+
*
|
|
11
|
+
* Computed in **UTC**, deliberately. The server buckets a quarter on UTC
|
|
12
|
+
* boundaries, so a local-time computation would disagree with it for a few
|
|
13
|
+
* hours either side of a quarter change — `skrr` would ask for Q3 and the
|
|
14
|
+
* server would answer about the Q4 it thinks we are in. Same clock, no seam.
|
|
15
|
+
*
|
|
16
|
+
* The previous calendar quarter is always closed, which is the cohort this
|
|
17
|
+
* endpoint reports on (`scope: 'closed_quarter'`); the current one is not, so
|
|
18
|
+
* it is never a safe default.
|
|
19
|
+
*/
|
|
20
|
+
function previousClosedQuarter(now = new Date()) {
|
|
21
|
+
const quarter = Math.floor(now.getUTCMonth() / 3) + 1;
|
|
22
|
+
if (quarter === 1)
|
|
23
|
+
return { year: now.getUTCFullYear() - 1, quarter: 4 };
|
|
24
|
+
return { year: now.getUTCFullYear(), quarter: quarter - 1 };
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* `skrr commitments receipt-metrics <id>` — the closed-quarter rollup behind
|
|
28
|
+
* `commitments receipt`.
|
|
29
|
+
*
|
|
30
|
+
* `receipt` explains ONE wake. This aggregates a whole closed quarter, which is
|
|
31
|
+
* the window you need to answer "is this commitment actually delivering" rather
|
|
32
|
+
* than "what happened last night".
|
|
33
|
+
*/
|
|
34
|
+
class CommitmentsReceiptMetrics extends base_command_1.BaseCommand {
|
|
35
|
+
static description = "Show a closed quarter's execution receipt metrics for a commitment";
|
|
36
|
+
static examples = [
|
|
37
|
+
'<%= config.bin %> commitments receipt-metrics obj_abc123',
|
|
38
|
+
'<%= config.bin %> commitments receipt-metrics obj_abc123 --year 2026 --quarter 2',
|
|
39
|
+
'<%= config.bin %> commitments receipt-metrics obj_abc123 --verbose',
|
|
40
|
+
'<%= config.bin %> commitments receipt-metrics obj_abc123 --json',
|
|
41
|
+
];
|
|
42
|
+
static args = {
|
|
43
|
+
id: core_1.Args.string({ description: 'Commitment ID', required: true, ignoreStdin: true }),
|
|
44
|
+
};
|
|
45
|
+
static flags = {
|
|
46
|
+
year: core_1.Flags.integer({ description: 'Calendar year (defaults to the last closed quarter)' }),
|
|
47
|
+
quarter: core_1.Flags.integer({
|
|
48
|
+
description: 'Quarter 1-4 (defaults to the last closed quarter)',
|
|
49
|
+
min: 1,
|
|
50
|
+
max: 4,
|
|
51
|
+
}),
|
|
52
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
53
|
+
verbose: core_1.Flags.boolean({ description: 'Include the measurement basis behind the rates' }),
|
|
54
|
+
};
|
|
55
|
+
async run() {
|
|
56
|
+
this.requireAuth();
|
|
57
|
+
const { args, flags } = await this.parse(CommitmentsReceiptMetrics);
|
|
58
|
+
// Both or neither. Filling in half of a caller's intent would silently
|
|
59
|
+
// report on a quarter they did not ask for — and the numbers would look
|
|
60
|
+
// perfectly plausible, which is the kind of wrong that gets acted on.
|
|
61
|
+
if ((flags.year === undefined) !== (flags.quarter === undefined)) {
|
|
62
|
+
this.error('Pass --year and --quarter together, or neither to use the last closed quarter.');
|
|
63
|
+
}
|
|
64
|
+
const fallback = previousClosedQuarter();
|
|
65
|
+
const year = flags.year ?? fallback.year;
|
|
66
|
+
const quarter = flags.quarter ?? fallback.quarter;
|
|
67
|
+
try {
|
|
68
|
+
const response = await commitments_1.commitmentApi.receiptQuarterlyMetrics(args.id, year, quarter);
|
|
69
|
+
if (flags.json)
|
|
70
|
+
return this.log(JSON.stringify(response, null, 2));
|
|
71
|
+
(0, commitment_product_1.renderExecutionReceiptQuarterlyMetrics)(response, (line) => this.log(line), flags.verbose);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
this.handleApiError(error);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
exports.default = CommitmentsReceiptMetrics;
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const core_1 = require("@oclif/core");
|
|
4
4
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
5
5
|
const base_command_1 = require("../../base-command");
|
|
6
|
+
const conversation_search_1 = require("../../lib/conversation-search");
|
|
6
7
|
const format_1 = require("../../lib/format");
|
|
7
8
|
/**
|
|
8
9
|
* Message-level search across the caller's own conversations.
|
|
@@ -51,13 +52,14 @@ class ConvosSearch extends base_command_1.BaseCommand {
|
|
|
51
52
|
}
|
|
52
53
|
const hits = Array.isArray(response?.messages) ? response.messages : [];
|
|
53
54
|
const shown = hits.slice(0, flags.limit);
|
|
55
|
+
const compactHits = shown.map((message) => (0, conversation_search_1.compactMessageSearchHit)(message, flags.snippet, query));
|
|
54
56
|
if (flags.json) {
|
|
55
57
|
this.log(JSON.stringify({
|
|
56
58
|
query,
|
|
57
59
|
total: hits.length,
|
|
58
60
|
shown: shown.length,
|
|
59
61
|
truncated: hits.length > shown.length,
|
|
60
|
-
hits:
|
|
62
|
+
hits: compactHits,
|
|
61
63
|
}, null, 2));
|
|
62
64
|
return;
|
|
63
65
|
}
|
|
@@ -65,13 +67,11 @@ class ConvosSearch extends base_command_1.BaseCommand {
|
|
|
65
67
|
this.log(`No messages matched "${query}".`);
|
|
66
68
|
return;
|
|
67
69
|
}
|
|
68
|
-
(0, format_1.renderTable)(
|
|
70
|
+
(0, format_1.renderTable)(compactHits.map((m) => ({
|
|
69
71
|
when: m.createdAt ? String(m.createdAt).slice(0, 10) : '-',
|
|
70
72
|
who: m.isCreatedByUser === true ? 'you' : (0, format_1.formatCell)(m.sender, 'agent'),
|
|
71
73
|
thread: (0, format_1.formatCell)(m.title, 'Untitled'),
|
|
72
|
-
snippet: String(m.text ?? '')
|
|
73
|
-
.replace(/\s+/g, ' ')
|
|
74
|
-
.slice(0, flags.snippet),
|
|
74
|
+
snippet: String(m.text ?? ''),
|
|
75
75
|
})), [
|
|
76
76
|
{ key: 'when', header: 'WHEN' },
|
|
77
77
|
{ key: 'who', header: 'WHO', maxWidth: 14 },
|
|
@@ -4,6 +4,9 @@ export default class HarnessesLeasesList extends BaseCommand {
|
|
|
4
4
|
static examples: string[];
|
|
5
5
|
static flags: {
|
|
6
6
|
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
7
|
+
limit: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
8
|
+
state: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
9
|
+
product: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
7
10
|
};
|
|
8
11
|
run(): Promise<void>;
|
|
9
12
|
}
|
|
@@ -14,18 +14,38 @@ const base_command_1 = require("../../../base-command");
|
|
|
14
14
|
const format_1 = require("../../../lib/format");
|
|
15
15
|
const harnesses_1 = require("../../../lib/harnesses");
|
|
16
16
|
class HarnessesLeasesList extends base_command_1.BaseCommand {
|
|
17
|
-
static description = 'List your
|
|
17
|
+
static description = 'List your harness leases, newest first';
|
|
18
18
|
static examples = [
|
|
19
19
|
'<%= config.bin %> harnesses leases list',
|
|
20
|
+
'<%= config.bin %> harnesses leases list --state lost',
|
|
21
|
+
'<%= config.bin %> harnesses leases list --limit 100 --product hosted-machine',
|
|
20
22
|
'<%= config.bin %> harnesses leases list --json',
|
|
21
23
|
];
|
|
22
|
-
static flags = {
|
|
24
|
+
static flags = {
|
|
25
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
26
|
+
limit: core_1.Flags.integer({
|
|
27
|
+
description: 'How many to return, newest first (1-100; the server defaults to 50)',
|
|
28
|
+
min: 1,
|
|
29
|
+
max: 100,
|
|
30
|
+
}),
|
|
31
|
+
state: core_1.Flags.string({
|
|
32
|
+
description: 'Only this lease state — e.g. active, paused, terminated, failed, lost. `lost` is the one worth asking for: it means the platform stopped tracking the machine, and it is billed for the whole gap.',
|
|
33
|
+
}),
|
|
34
|
+
product: core_1.Flags.string({
|
|
35
|
+
description: 'Only this machine product',
|
|
36
|
+
options: ['hosted-machine', 'hosted-job-machine'],
|
|
37
|
+
}),
|
|
38
|
+
};
|
|
23
39
|
async run() {
|
|
24
40
|
this.requireAuth();
|
|
25
41
|
const { flags } = await this.parse(HarnessesLeasesList);
|
|
26
42
|
let response;
|
|
27
43
|
try {
|
|
28
|
-
response = await (0, harnesses_1.listHarnessLeases)(
|
|
44
|
+
response = await (0, harnesses_1.listHarnessLeases)({
|
|
45
|
+
limit: flags.limit,
|
|
46
|
+
state: flags.state,
|
|
47
|
+
machineProduct: flags.product,
|
|
48
|
+
});
|
|
29
49
|
}
|
|
30
50
|
catch (err) {
|
|
31
51
|
this.handleApiError(err);
|
|
@@ -39,21 +59,48 @@ class HarnessesLeasesList extends base_command_1.BaseCommand {
|
|
|
39
59
|
if (leases.length === 0) {
|
|
40
60
|
// Say what empty MEANS. "No leases" reads as a failed query; the honest
|
|
41
61
|
// reading is that nothing hosted is running, and nothing is being billed.
|
|
42
|
-
|
|
62
|
+
// With a filter on, that reading would be a lie — the absence is about
|
|
63
|
+
// the filter, not the account.
|
|
64
|
+
const filters = [
|
|
65
|
+
flags.state ? `state ${flags.state}` : '',
|
|
66
|
+
flags.product ? `product ${flags.product}` : '',
|
|
67
|
+
].filter(Boolean);
|
|
68
|
+
this.log(filters.length
|
|
69
|
+
? `No leases matching ${filters.join(' and ')}. Without a filter this lists every lease, newest first.`
|
|
70
|
+
: 'No leases — nothing hosted is running, and nothing is accruing.');
|
|
43
71
|
return;
|
|
44
72
|
}
|
|
73
|
+
// The server caps at 100 and defaults to 50, so a full page is ambiguous:
|
|
74
|
+
// it may be all there is, or the newest of more. Say which rather than
|
|
75
|
+
// letting the reader assume.
|
|
76
|
+
if (!flags.json && leases.length === (flags.limit ?? 50)) {
|
|
77
|
+
this.log(`Showing the newest ${leases.length}. There may be more — raise \`--limit\` (max 100) or narrow with \`--state\`.`);
|
|
78
|
+
}
|
|
79
|
+
// Columns follow the payload, not a guess at it. PRODUCT is the one that
|
|
80
|
+
// tells a Hosted Machine lease from a Hosted Job Machine lease, and BILLING
|
|
81
|
+
// answers the question a lease list exists to answer: is this still
|
|
82
|
+
// charging me. There is no ENGINE or EXPIRES on a lease -- it carries no
|
|
83
|
+
// top-level runtime id and does not expire -- so those columns are gone
|
|
84
|
+
// rather than printed empty.
|
|
45
85
|
(0, format_1.renderTable)(leases.map((lease) => ({
|
|
46
|
-
id:
|
|
47
|
-
product:
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
86
|
+
id: (0, format_1.formatCell)(lease.id),
|
|
87
|
+
product: (0, format_1.formatCell)(lease.machineProduct),
|
|
88
|
+
name: (0, format_1.formatCell)(lease.displayName),
|
|
89
|
+
state: (0, format_1.formatCell)(lease.stateReason && lease.stateReason !== lease.state
|
|
90
|
+
? `${lease.state} (${lease.stateReason})`
|
|
91
|
+
: lease.state),
|
|
92
|
+
billing: (0, format_1.formatCell)(lease.billing?.billableState),
|
|
93
|
+
updated: (0, format_1.localStamp)(lease.updatedAt ?? lease.leaseTimestamps?.lastStateChangeAt),
|
|
51
94
|
})), [
|
|
52
95
|
{ key: 'id', header: 'LEASE' },
|
|
53
96
|
{ key: 'product', header: 'PRODUCT' },
|
|
54
|
-
{ key: '
|
|
55
|
-
|
|
56
|
-
|
|
97
|
+
{ key: 'name', header: 'NAME', maxWidth: 24 },
|
|
98
|
+
// The reason is the actionable half of a state, so it stays in the
|
|
99
|
+
// column rather than moving to `show` -- capped only so a long one
|
|
100
|
+
// cannot wrap the whole table on an 80-column terminal.
|
|
101
|
+
{ key: 'state', header: 'STATE', maxWidth: 30 },
|
|
102
|
+
{ key: 'billing', header: 'BILLING' },
|
|
103
|
+
{ key: 'updated', header: 'UPDATED' },
|
|
57
104
|
], (line) => this.log(line));
|
|
58
105
|
}
|
|
59
106
|
}
|
|
@@ -12,6 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
const core_1 = require("@oclif/core");
|
|
13
13
|
const base_command_1 = require("../../../base-command");
|
|
14
14
|
const harnesses_1 = require("../../../lib/harnesses");
|
|
15
|
+
const balance_1 = require("../../../lib/balance");
|
|
15
16
|
class HarnessesLeasesShow extends base_command_1.BaseCommand {
|
|
16
17
|
static description = 'Show one harness lease';
|
|
17
18
|
static examples = ['<%= config.bin %> harnesses leases show <lease-id>'];
|
|
@@ -46,6 +47,8 @@ class HarnessesLeasesShow extends base_command_1.BaseCommand {
|
|
|
46
47
|
const line = (label, value) => {
|
|
47
48
|
if (value === undefined || value === null || value === '')
|
|
48
49
|
return;
|
|
50
|
+
// 14 columns. A longer label does not wrap, it collides with its own
|
|
51
|
+
// value — keep new labels inside it.
|
|
49
52
|
this.log(`${label.padEnd(14)}${String(value)}`);
|
|
50
53
|
};
|
|
51
54
|
// Only ever a PRIMITIVE reaches `line`. Falling back to the parent object
|
|
@@ -77,6 +80,39 @@ class HarnessesLeasesShow extends base_command_1.BaseCommand {
|
|
|
77
80
|
// Money last, and only when the server sent it — an absent billing block
|
|
78
81
|
// and a zero are different states.
|
|
79
82
|
line('Billing:', nested(lease.billing, 'billableState'));
|
|
83
|
+
// The monthly cap, which is what actually refuses a Hosted Machine.
|
|
84
|
+
//
|
|
85
|
+
// The server has computed and sent these on every lease read all along and
|
|
86
|
+
// the web renders them; the CLI printed only `billableState`. So a refusal
|
|
87
|
+
// said "spending limit exceeded" and the only number a CLI user could find
|
|
88
|
+
// was `skrr balance show`'s DAILY cap, sitting at full headroom — which
|
|
89
|
+
// made the refusal look like it was about something else (OSK-7920).
|
|
90
|
+
//
|
|
91
|
+
// Read through `nested` like every other sub-object here: these arrive on a
|
|
92
|
+
// permissive payload type, and the helper is what keeps a non-primitive
|
|
93
|
+
// from rendering as `[object Object]`.
|
|
94
|
+
const cents = (key) => {
|
|
95
|
+
const value = nested(lease.billing, key);
|
|
96
|
+
// `formatMicros` takes micro-dollars; these are cents.
|
|
97
|
+
return typeof value === 'number' ? (0, balance_1.formatMicros)(value * 10_000) : undefined;
|
|
98
|
+
};
|
|
99
|
+
if (nested(lease.billing, 'spendStatusUnavailable') === true) {
|
|
100
|
+
// Distinguish "we could not read it" from "you have headroom". Admission
|
|
101
|
+
// fails CLOSED on an unreadable status, so silence would be the most
|
|
102
|
+
// misleading thing to print.
|
|
103
|
+
line('Monthly cap:', 'unavailable — the spend status could not be read');
|
|
104
|
+
}
|
|
105
|
+
else if (cents('monthlySpendLimitCents')) {
|
|
106
|
+
line('Monthly cap:', cents('monthlySpendLimitCents'));
|
|
107
|
+
line('Spent:', cents('currentMonthSpendCents'));
|
|
108
|
+
line('Open leases:', cents('openUsageEstimateCents'));
|
|
109
|
+
// Projected is what admission compares against the cap, so it is the
|
|
110
|
+
// number that decides whether the next turn is refused.
|
|
111
|
+
const over = nested(lease.billing, 'spendingLimitExceeded') === true;
|
|
112
|
+
const projected = cents('projectedCurrentMonthSpendCents');
|
|
113
|
+
line('Projected:', projected ? `${projected}${over ? ' — over the cap' : ''}` : undefined);
|
|
114
|
+
line('Month began:', nested(lease.billing, 'monthStartedAt'));
|
|
115
|
+
}
|
|
80
116
|
this.log('');
|
|
81
117
|
this.log('Full record: --json');
|
|
82
118
|
}
|
|
@@ -14,6 +14,10 @@ export type HarnessRow = {
|
|
|
14
14
|
status?: string;
|
|
15
15
|
harnessLocation?: string;
|
|
16
16
|
lastSeenAt?: string;
|
|
17
|
+
metadata?: {
|
|
18
|
+
machineProduct?: string;
|
|
19
|
+
source?: string;
|
|
20
|
+
};
|
|
17
21
|
};
|
|
18
22
|
export type HarnessSelection = {
|
|
19
23
|
/** Rows to print, after every filter and the `--limit` slice. */
|
|
@@ -33,6 +37,20 @@ export type HarnessSelection = {
|
|
|
33
37
|
* cloud products never register through a daemon. Treating the missing field
|
|
34
38
|
* as cloud made a healthy, connected local harness disappear from the one CLI
|
|
35
39
|
* command intended to discover it.
|
|
40
|
+
*
|
|
41
|
+
* "Cloud products never register through a daemon" is no longer true, and that
|
|
42
|
+
* is why the product identity is checked FIRST. The Hosted Machine boots a
|
|
43
|
+
* daemon inside itself and registers through the ordinary local path, so its
|
|
44
|
+
* row carries `harnessLocation: 'local'` on a machine whose `compute.ownership`
|
|
45
|
+
* is `oversky-managed` — and it therefore appeared in the DEFAULT, local-only
|
|
46
|
+
* listing. `--local`'s documented meaning ("Only show local (daemon-backed)
|
|
47
|
+
* harnesses … pass --no-local to include cloud/hosted rows") did not hold: a
|
|
48
|
+
* user filtering to their own machines was silently shown a cloud one, and the
|
|
49
|
+
* flag that separates them separated nothing (OSK-7636).
|
|
50
|
+
*
|
|
51
|
+
* Read-side rather than a stored-value migration on purpose: existing rows
|
|
52
|
+
* already carry the wrong `harnessLocation`, and rewriting it would have to
|
|
53
|
+
* move the registration identity filter with it.
|
|
36
54
|
*/
|
|
37
55
|
export declare function isLocalHarnessRow(row: HarnessRow): boolean;
|
|
38
56
|
/**
|
|
@@ -7,14 +7,44 @@ const core_1 = require("@oclif/core");
|
|
|
7
7
|
const base_command_1 = require("../../base-command");
|
|
8
8
|
const api_fetch_1 = require("../../lib/api-fetch");
|
|
9
9
|
const format_1 = require("../../lib/format");
|
|
10
|
+
/**
|
|
11
|
+
* Products skrr provisions and owns. A row that says it is one of these is
|
|
12
|
+
* cloud, whatever `harnessLocation` reads.
|
|
13
|
+
*/
|
|
14
|
+
const MANAGED_MACHINE_PRODUCTS = new Set(['hosted-machine', 'hosted-job-machine']);
|
|
15
|
+
const MANAGED_REGISTRATION_SOURCES = new Set([
|
|
16
|
+
'hosted-machine',
|
|
17
|
+
'hosted-job-machine',
|
|
18
|
+
'cloud-coding',
|
|
19
|
+
]);
|
|
10
20
|
/**
|
|
11
21
|
* Harness rows created before `harnessLocation` was introduced do not carry that
|
|
12
22
|
* field. A daemon id is the durable discriminator for those legacy rows:
|
|
13
23
|
* cloud products never register through a daemon. Treating the missing field
|
|
14
24
|
* as cloud made a healthy, connected local harness disappear from the one CLI
|
|
15
25
|
* command intended to discover it.
|
|
26
|
+
*
|
|
27
|
+
* "Cloud products never register through a daemon" is no longer true, and that
|
|
28
|
+
* is why the product identity is checked FIRST. The Hosted Machine boots a
|
|
29
|
+
* daemon inside itself and registers through the ordinary local path, so its
|
|
30
|
+
* row carries `harnessLocation: 'local'` on a machine whose `compute.ownership`
|
|
31
|
+
* is `oversky-managed` — and it therefore appeared in the DEFAULT, local-only
|
|
32
|
+
* listing. `--local`'s documented meaning ("Only show local (daemon-backed)
|
|
33
|
+
* harnesses … pass --no-local to include cloud/hosted rows") did not hold: a
|
|
34
|
+
* user filtering to their own machines was silently shown a cloud one, and the
|
|
35
|
+
* flag that separates them separated nothing (OSK-7636).
|
|
36
|
+
*
|
|
37
|
+
* Read-side rather than a stored-value migration on purpose: existing rows
|
|
38
|
+
* already carry the wrong `harnessLocation`, and rewriting it would have to
|
|
39
|
+
* move the registration identity filter with it.
|
|
16
40
|
*/
|
|
17
41
|
function isLocalHarnessRow(row) {
|
|
42
|
+
const product = row.metadata?.machineProduct?.trim() ?? '';
|
|
43
|
+
if (MANAGED_MACHINE_PRODUCTS.has(product))
|
|
44
|
+
return false;
|
|
45
|
+
const source = row.metadata?.source?.trim() ?? '';
|
|
46
|
+
if (MANAGED_REGISTRATION_SOURCES.has(source))
|
|
47
|
+
return false;
|
|
18
48
|
return row.harnessLocation === 'local' || (row.harnessLocation == null && Boolean(row.daemonId));
|
|
19
49
|
}
|
|
20
50
|
/**
|
|
@@ -4,6 +4,34 @@ const core_1 = require("@oclif/core");
|
|
|
4
4
|
const base_command_1 = require("../../base-command");
|
|
5
5
|
const format_1 = require("../../lib/format");
|
|
6
6
|
const harnesses_1 = require("../../lib/harnesses");
|
|
7
|
+
/**
|
|
8
|
+
* How you actually start each product FROM HERE.
|
|
9
|
+
*
|
|
10
|
+
* The server sends a `userAction` (`start-hosted-machine`, …) and the table
|
|
11
|
+
* used to print it. That token is a launch-context assertion the API validates
|
|
12
|
+
* against `launchSurfaces` — it is not a command, and printing it in a column
|
|
13
|
+
* headed ACTION told a reader to run something that does not exist (OSK-7779).
|
|
14
|
+
*
|
|
15
|
+
* So the column names a real command instead. The map lives here rather than on
|
|
16
|
+
* the server because only the CLI knows its own command names; a product with
|
|
17
|
+
* no entry prints `-` and is called out below the table, which is the honest
|
|
18
|
+
* rendering of "you cannot start this from a terminal".
|
|
19
|
+
*/
|
|
20
|
+
const START_COMMAND = {
|
|
21
|
+
'byo-machine': 'harnesses install-token',
|
|
22
|
+
'hosted-machine': 'machines hosted start',
|
|
23
|
+
// Not `machines …`: a Hosted Job Machine is one-shot compute that exists for
|
|
24
|
+
// the duration of one job, so the job is what you create.
|
|
25
|
+
//
|
|
26
|
+
// `code jobs run`, not `code handover`. Both start this product, and the
|
|
27
|
+
// difference is the one the finding was actually about: `handover` clones a
|
|
28
|
+
// repository, works it and opens a pull request, so it cannot start the bare
|
|
29
|
+
// one-shot the product describes — `"continuity": {"semantics": "one-shot"}`
|
|
30
|
+
// with `stateRetention: false` on filesystem, memory and processes. Pointing
|
|
31
|
+
// a reader who wants compute at the repository flow is a smaller version of
|
|
32
|
+
// pointing them at a verb nobody implements.
|
|
33
|
+
'hosted-job-machine': 'code jobs run',
|
|
34
|
+
};
|
|
7
35
|
/**
|
|
8
36
|
* `availability` is a string on some rows and an object on others. The table
|
|
9
37
|
* has to render both, and a `[object Object]` cell in a catalogue listing is
|
|
@@ -43,17 +71,34 @@ class HarnessesProducts extends base_command_1.BaseCommand {
|
|
|
43
71
|
this.log('No harness products available.');
|
|
44
72
|
return;
|
|
45
73
|
}
|
|
74
|
+
const bin = this.config.bin;
|
|
46
75
|
(0, format_1.renderTable)(products.map((p) => ({
|
|
47
76
|
id: (0, format_1.formatCell)(p.id),
|
|
48
77
|
label: (0, format_1.formatCell)(p.label),
|
|
49
|
-
|
|
78
|
+
// What you are buying: `one-shot` and `true-resume` are the difference
|
|
79
|
+
// between compute that forgets everything and a workspace that resumes.
|
|
80
|
+
lifecycle: (0, format_1.formatCell)(p.lifecycleSemantics),
|
|
81
|
+
start: p.id && START_COMMAND[p.id] ? `${bin} ${START_COMMAND[p.id]}` : '-',
|
|
50
82
|
availability: availabilityLabel(p),
|
|
51
83
|
})), [
|
|
52
84
|
{ key: 'id', header: 'ID' },
|
|
53
|
-
{ key: 'label', header: 'LABEL', maxWidth:
|
|
54
|
-
{ key: '
|
|
85
|
+
{ key: 'label', header: 'LABEL', maxWidth: 26 },
|
|
86
|
+
{ key: 'lifecycle', header: 'LIFECYCLE' },
|
|
87
|
+
{ key: 'start', header: 'START' },
|
|
55
88
|
{ key: 'availability', header: 'AVAILABILITY' },
|
|
56
89
|
], (line) => this.log(line));
|
|
90
|
+
// A product the CLI cannot start is worth one line. Silence here is what
|
|
91
|
+
// made the old ACTION column misleading: `available` beside a verb nobody
|
|
92
|
+
// implements reads as "run this", and the reader learns otherwise by
|
|
93
|
+
// failing.
|
|
94
|
+
const unreachable = products.filter((p) => p.id && !START_COMMAND[p.id]);
|
|
95
|
+
if (unreachable.length > 0) {
|
|
96
|
+
this.log('');
|
|
97
|
+
for (const p of unreachable) {
|
|
98
|
+
const where = p.catalog?.launchSurfaces?.join(', ') || 'unknown';
|
|
99
|
+
this.log(`${p.id}: not startable from the CLI — launch surfaces: ${where}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
57
102
|
// The full record carries contract, billing, compute and lifecycle blocks.
|
|
58
103
|
// Pointing at --json is cheaper than a second table nobody asked for.
|
|
59
104
|
this.log('');
|
|
@@ -21,6 +21,22 @@ import { BaseCommand } from '../../base-command';
|
|
|
21
21
|
* cannot: is this window going to run out before it resets, which days were
|
|
22
22
|
* expensive, was last week's cap actually hit.
|
|
23
23
|
*/
|
|
24
|
+
/**
|
|
25
|
+
* WHY this window is empty — without asserting a cause we cannot know.
|
|
26
|
+
*
|
|
27
|
+
* OSK-7616 — this used to read "Runs started outside skrr still move the
|
|
28
|
+
* provider meter above, but cannot be priced here", which names one
|
|
29
|
+
* explanation as though it were the only one. In the reported case it was the
|
|
30
|
+
* wrong one: three Codex turns were started THROUGH skrr, completed, and were
|
|
31
|
+
* recorded at zero tokens because the harness reported an empty usage envelope.
|
|
32
|
+
* The reader was told, by the one screen whose job is answering "what is my
|
|
33
|
+
* agent costing me", that the cause was something they had not done.
|
|
34
|
+
*
|
|
35
|
+
* The second sentence is the one that was missing, and it is the actionable
|
|
36
|
+
* half: a run skrr saw and could not price is a reportable defect, not a
|
|
37
|
+
* property of the user's habits.
|
|
38
|
+
*/
|
|
39
|
+
export declare function unpricedWindowLines(): string[];
|
|
24
40
|
export default class HarnessesQuota extends BaseCommand {
|
|
25
41
|
static description: string;
|
|
26
42
|
static examples: string[];
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.unpricedWindowLines = unpricedWindowLines;
|
|
3
4
|
const core_1 = require("@oclif/core");
|
|
4
5
|
const base_command_1 = require("../../base-command");
|
|
5
6
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
@@ -28,6 +29,28 @@ const quota_render_1 = require("../../lib/quota-render");
|
|
|
28
29
|
* cannot: is this window going to run out before it resets, which days were
|
|
29
30
|
* expensive, was last week's cap actually hit.
|
|
30
31
|
*/
|
|
32
|
+
/**
|
|
33
|
+
* WHY this window is empty — without asserting a cause we cannot know.
|
|
34
|
+
*
|
|
35
|
+
* OSK-7616 — this used to read "Runs started outside skrr still move the
|
|
36
|
+
* provider meter above, but cannot be priced here", which names one
|
|
37
|
+
* explanation as though it were the only one. In the reported case it was the
|
|
38
|
+
* wrong one: three Codex turns were started THROUGH skrr, completed, and were
|
|
39
|
+
* recorded at zero tokens because the harness reported an empty usage envelope.
|
|
40
|
+
* The reader was told, by the one screen whose job is answering "what is my
|
|
41
|
+
* agent costing me", that the cause was something they had not done.
|
|
42
|
+
*
|
|
43
|
+
* The second sentence is the one that was missing, and it is the actionable
|
|
44
|
+
* half: a run skrr saw and could not price is a reportable defect, not a
|
|
45
|
+
* property of the user's habits.
|
|
46
|
+
*/
|
|
47
|
+
function unpricedWindowLines() {
|
|
48
|
+
return [
|
|
49
|
+
'The provider meter above counts every run on this harness; this table counts only the runs skrr priced.',
|
|
50
|
+
'A run started outside skrr is never priced here. A run started THROUGH skrr should be — if one is missing, its harness reported no token usage, which is a bug worth reporting.',
|
|
51
|
+
' skrr harnesses usage # the runs skrr did see',
|
|
52
|
+
];
|
|
53
|
+
}
|
|
31
54
|
class HarnessesQuota extends base_command_1.BaseCommand {
|
|
32
55
|
static description = 'Claude Code / Codex subscription quota over time — windows, pace, and daily spend';
|
|
33
56
|
static examples = [
|
|
@@ -180,7 +203,9 @@ class HarnessesQuota extends base_command_1.BaseCommand {
|
|
|
180
203
|
// is a real and common state that must not read as "you spent nothing".
|
|
181
204
|
this.log('');
|
|
182
205
|
this.log('No skrr-recorded token spend in this window.');
|
|
183
|
-
|
|
206
|
+
for (const line of unpricedWindowLines()) {
|
|
207
|
+
this.log(line);
|
|
208
|
+
}
|
|
184
209
|
return;
|
|
185
210
|
}
|
|
186
211
|
this.log('');
|
|
@@ -122,6 +122,23 @@ class HarnessesUsage extends base_command_1.BaseCommand {
|
|
|
122
122
|
this.log(`Total: ${count(totals.sessions)} sessions · ${usd(totals.totalCostUsd)} · ` +
|
|
123
123
|
`${count(totals.inputTokens)} in / ${count(totals.outputTokens)} out / ` +
|
|
124
124
|
`${count(totals.cachedInputTokens)} cached`);
|
|
125
|
+
// SAY WHICH PROVIDERS THAT TOTAL COVERS.
|
|
126
|
+
//
|
|
127
|
+
// It was presented as the account total and is not: the ingestion path is
|
|
128
|
+
// fed by the Claude account-telemetry reader, so five completed Codex
|
|
129
|
+
// runs on the SAME daemon as a reported Claude harness produced no row at
|
|
130
|
+
// all, and `grandTotals.sessions: 150` was the Claude-only figure with no
|
|
131
|
+
// qualifier. A user reading it to answer "what has my automation cost me"
|
|
132
|
+
// gets a confidently wrong answer, and nothing hints that entire
|
|
133
|
+
// providers are missing (OSK-7672). Naming the providers present is not
|
|
134
|
+
// the whole fix — the missing producers are — but it is the difference
|
|
135
|
+
// between an incomplete number and a wrong one.
|
|
136
|
+
const providers = [...new Set(rows.map((r) => r.provider).filter(Boolean))].sort();
|
|
137
|
+
if (!args.harness && providers.length > 0) {
|
|
138
|
+
this.log(`Covers ${providers.join(', ')} only — usage is recorded per provider, and a harness ` +
|
|
139
|
+
'whose provider has no usage producer contributes nothing to this total. ' +
|
|
140
|
+
'This is NOT necessarily your whole account.');
|
|
141
|
+
}
|
|
125
142
|
}
|
|
126
143
|
}
|
|
127
144
|
}
|
|
@@ -4,7 +4,8 @@ import { BaseCommand } from '../../base-command';
|
|
|
4
4
|
*
|
|
5
5
|
* Gap analysis §3.3 (b). The CLI's 50 command groups were entirely pull-shaped,
|
|
6
6
|
* with nothing that surfaced an agent-initiated message. The reply direction
|
|
7
|
-
* already closed the loop (`skrr agents chat --conversation <id
|
|
7
|
+
* already closed the loop (`skrr agents chat <agent-id> --conversation <id>
|
|
8
|
+
* --prompt "…"` stamps
|
|
8
9
|
* `Message.intentId` and wakes the originating run) — so the missing half was
|
|
9
10
|
* literally "tell me it happened", and its absence is what made use case 3's
|
|
10
11
|
* "the agent messages me a couple of times like a person" a terminal dead end.
|
|
@@ -6,12 +6,14 @@ const data_provider_1 = require("@skrr-ai/data-provider");
|
|
|
6
6
|
const base_command_1 = require("../../base-command");
|
|
7
7
|
const inbox_1 = require("../../lib/inbox");
|
|
8
8
|
const format_1 = require("../../lib/format");
|
|
9
|
+
const agentic_stream_1 = require("../../lib/agentic-stream");
|
|
9
10
|
/**
|
|
10
11
|
* `skrr inbox` / `skrr inbox --follow` — what have my agents said to me?
|
|
11
12
|
*
|
|
12
13
|
* Gap analysis §3.3 (b). The CLI's 50 command groups were entirely pull-shaped,
|
|
13
14
|
* with nothing that surfaced an agent-initiated message. The reply direction
|
|
14
|
-
* already closed the loop (`skrr agents chat --conversation <id
|
|
15
|
+
* already closed the loop (`skrr agents chat <agent-id> --conversation <id>
|
|
16
|
+
* --prompt "…"` stamps
|
|
15
17
|
* `Message.intentId` and wakes the originating run) — so the missing half was
|
|
16
18
|
* literally "tell me it happened", and its absence is what made use case 3's
|
|
17
19
|
* "the agent messages me a couple of times like a person" a terminal dead end.
|
|
@@ -77,19 +79,33 @@ class Inbox extends base_command_1.BaseCommand {
|
|
|
77
79
|
}
|
|
78
80
|
(0, format_1.renderTable)(selected.map((dm) => ({
|
|
79
81
|
agent: dm.agentId,
|
|
82
|
+
// The reply command below needs this, and the row has carried it all
|
|
83
|
+
// along — it was simply never rendered, so the command printed under
|
|
84
|
+
// the table could not be completed from the table. `verbatim` because a
|
|
85
|
+
// clipped id is not an id (OSK-7621).
|
|
86
|
+
conversation: dm.conversationId,
|
|
80
87
|
unread: String(dm.unreadCount),
|
|
81
88
|
when: dm.lastMessageAt ? dm.lastMessageAt.slice(0, 19) : '-',
|
|
82
89
|
preview: (dm.lastMessagePreview || '').replace(/\s+/g, ' ').trim(),
|
|
83
90
|
})), [
|
|
84
91
|
{ key: 'agent', header: 'AGENT', verbatim: true },
|
|
92
|
+
{ key: 'conversation', header: 'CONVERSATION', verbatim: true },
|
|
85
93
|
{ key: 'unread', header: 'UNREAD', maxWidth: 6 },
|
|
86
94
|
{ key: 'when', header: 'LAST', maxWidth: 20 },
|
|
87
|
-
{ key: 'preview', header: 'PREVIEW', maxWidth:
|
|
95
|
+
{ key: 'preview', header: 'PREVIEW', maxWidth: 48 },
|
|
88
96
|
], (line) => this.log(line));
|
|
89
97
|
const totalUnread = selected.reduce((sum, dm) => sum + dm.unreadCount, 0);
|
|
90
98
|
if (totalUnread > 0) {
|
|
99
|
+
// The reply command must be RUNNABLE (OSK-7585/7594/7597). `agents chat`
|
|
100
|
+
// takes the agent as a required positional and `--prompt` as a required
|
|
101
|
+
// flag, so the argument-less form this used to print here (and, at the
|
|
102
|
+
// time those findings were filed, on every detach) exits with
|
|
103
|
+
// "Missing 1 required arg". A command a reader copies and cannot run is
|
|
104
|
+
// worse than no command: it costs them a round trip to learn the surface
|
|
105
|
+
// does not work the way it was just told them it does.
|
|
91
106
|
this.log(`\n${totalUnread} unread. \`skrr inbox --follow\` to watch, ` +
|
|
92
|
-
'`skrr agents chat --conversation <id
|
|
107
|
+
'`skrr agents chat <agent-id> --conversation <id> --prompt "<your reply>"` to reply ' +
|
|
108
|
+
'(the AGENT and CONVERSATION columns above carry both ids).');
|
|
93
109
|
}
|
|
94
110
|
}
|
|
95
111
|
/** The terminal projection reads the same Notification rows as the web task inbox. */
|
|
@@ -192,7 +208,14 @@ class Inbox extends base_command_1.BaseCommand {
|
|
|
192
208
|
cursors.set(dm.conversationId, newest);
|
|
193
209
|
}
|
|
194
210
|
};
|
|
195
|
-
|
|
211
|
+
// Hoist a web apex to its `api.` realtime host, exactly as the run-stream
|
|
212
|
+
// sibling does. Using `baseURL` raw sends the upgrade to the apex, which is
|
|
213
|
+
// CloudFront-fronted: it cannot carry a WebSocket, and its WAF refuses a
|
|
214
|
+
// handshake that sends no `User-Agent` — which `ws` never does. Measured:
|
|
215
|
+
// an upgrade to `skrr.ai` answers `403 Request blocked`, the same request
|
|
216
|
+
// to `api.skrr.ai` answers `101`. Nothing errors at the call site; the
|
|
217
|
+
// socket simply never connects, which reads as a network problem.
|
|
218
|
+
const wsURL = (0, agentic_stream_1.toWebSocketOrigin)(this.cliConfig.baseURL);
|
|
196
219
|
const socket = (0, socket_io_client_1.io)(wsURL, {
|
|
197
220
|
path: '/ws/agentic',
|
|
198
221
|
auth: {
|
package/dist/commands/login.js
CHANGED
|
@@ -134,9 +134,12 @@ class Login extends base_command_1.BaseCommand {
|
|
|
134
134
|
// terminal through the daemon broker, which is the case that matters
|
|
135
135
|
// most on a headless box, and a confirmation would break it.
|
|
136
136
|
const profile = (0, keychain_1.getActiveProfile)();
|
|
137
|
+
const isolationGuidance = profile === 'default'
|
|
138
|
+
? 'Sign in with `--profile <name>` instead to keep both.'
|
|
139
|
+
: `Only the named "${profile}" profile changes; the default and all other profiles remain untouched.`;
|
|
137
140
|
this.warn(`Pointing profile "${profile}" at ${(0, config_1.describeDeployment)(nextBaseURL)}. ` +
|
|
138
141
|
`Its ${(0, config_1.describeDeployment)(previousBaseURL)} session will be replaced — ` +
|
|
139
|
-
|
|
142
|
+
isolationGuidance);
|
|
140
143
|
undoBaseURL = () => {
|
|
141
144
|
// Re-read rather than reusing `existing`: the flow may have persisted
|
|
142
145
|
// other fields (cliId, migration markers) before failing, and this
|
|
@@ -8,6 +8,7 @@ export default class MachinesList extends BaseCommand {
|
|
|
8
8
|
static examples: string[];
|
|
9
9
|
static flags: {
|
|
10
10
|
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
11
|
+
all: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
11
12
|
};
|
|
12
13
|
run(): Promise<void>;
|
|
13
14
|
}
|