@skrr-ai/cli 0.1.114 → 0.1.115

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dist/commands/agents/chat.js +10 -1
  2. package/dist/commands/computer-use/audio.d.ts +6 -0
  3. package/dist/commands/computer-use/audio.js +9 -0
  4. package/dist/commands/computer-use/browser.d.ts +7 -0
  5. package/dist/commands/computer-use/browser.js +16 -0
  6. package/dist/commands/computer-use/disable.d.ts +6 -0
  7. package/dist/commands/computer-use/disable.js +9 -0
  8. package/dist/commands/computer-use/enable.d.ts +6 -0
  9. package/dist/commands/computer-use/enable.js +9 -0
  10. package/dist/commands/computer-use/index.d.ts +6 -0
  11. package/dist/commands/computer-use/index.js +9 -0
  12. package/dist/commands/computer-use/install.d.ts +6 -0
  13. package/dist/commands/computer-use/install.js +9 -0
  14. package/dist/commands/computer-use/recover.d.ts +6 -0
  15. package/dist/commands/computer-use/recover.js +9 -0
  16. package/dist/commands/computer-use/status.d.ts +6 -0
  17. package/dist/commands/computer-use/status.js +9 -0
  18. package/dist/commands/computer-use/stop.d.ts +6 -0
  19. package/dist/commands/computer-use/stop.js +9 -0
  20. package/dist/commands/daemon/login.js +1 -1
  21. package/dist/commands/followups/plans/cancel.js +10 -3
  22. package/dist/commands/followups/plans/capacity.d.ts +9 -0
  23. package/dist/commands/followups/plans/capacity.js +42 -0
  24. package/dist/commands/followups/plans/create.js +3 -0
  25. package/dist/commands/followups/plans/revise.js +13 -6
  26. package/dist/lib/agentic-stream.d.ts +5 -1
  27. package/dist/lib/agentic-stream.js +25 -9
  28. package/dist/lib/computer-use.d.ts +9 -0
  29. package/dist/lib/computer-use.js +41 -0
  30. package/dist/lib/lookbackPlans.d.ts +20 -6
  31. package/dist/lib/lookbackPlans.js +19 -5
  32. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/computerUse.d.ts +228 -0
  33. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/computerUse.js +375 -0
  34. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonScopes.d.ts +4 -1
  35. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonScopes.js +6 -2
  36. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonWire.js +40 -0
  37. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/desktopWire.d.ts +140 -0
  38. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/desktopWire.js +46 -0
  39. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarness.d.ts +1 -1
  40. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +3 -1
  41. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +8 -5
  42. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/computerUse.d.ts +228 -0
  43. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/computerUse.js +358 -0
  44. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonScopes.d.ts +4 -1
  45. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonScopes.js +5 -1
  46. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonWire.js +40 -0
  47. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/desktopWire.d.ts +140 -0
  48. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/desktopWire.js +42 -0
  49. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarness.d.ts +1 -1
  50. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +3 -1
  51. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +3 -1
  52. package/dist/node_modules/@skrr-ai/auth-core/package.json +21 -1
  53. package/dist/node_modules/@skrr-ai/data-provider/index.js +23687 -23456
  54. package/oclif.manifest.json +284 -4
  55. package/package.json +2 -2
@@ -105,10 +105,14 @@ function reconcileTerminalFromMessages(messages, responseMessageId) {
105
105
  [...messages].reverse().find((m) => m && m.isCreatedByUser === false);
106
106
  if (!row)
107
107
  return null;
108
+ const projection = row.metadata && typeof row.metadata === 'object'
109
+ ? row.metadata.publicProjection : undefined;
110
+ const publicProjection = (0, data_provider_1.isDecodedPublicProjection)(projection) ? { publicProjection: projection } : {};
108
111
  const failure = (0, data_provider_1.resolveMessageFailure)(row);
109
112
  if (failure) {
110
113
  return {
111
114
  status: 'failed',
115
+ ...publicProjection,
112
116
  ...(failure.answer ? { text: failure.answer } : {}),
113
117
  // The reason exists on the row; it simply never reached the surface. Say
114
118
  // it, rather than the transport error that masked it (OSK-7595).
@@ -123,7 +127,7 @@ function reconcileTerminalFromMessages(messages, responseMessageId) {
123
127
  // it set is a turn that ended having produced nothing, which is still
124
128
  // terminal and still better reported than waited on.
125
129
  if (row.unfinished === false)
126
- return { status: 'completed', text };
130
+ return { status: 'completed', text, ...publicProjection };
127
131
  return null;
128
132
  }
129
133
  function agenticRecord(row) {
@@ -161,12 +165,16 @@ function handoverStateFromMessages(messages, responseMessageId) {
161
165
  (!responseMessageId && [...messages].reverse().find((m) => m && m.isCreatedByUser === false));
162
166
  if (!row)
163
167
  return { state: 'pending' };
168
+ const projection = row.metadata && typeof row.metadata === 'object'
169
+ ? row.metadata.publicProjection : undefined;
170
+ const publicProjection = (0, data_provider_1.isDecodedPublicProjection)(projection) ? { publicProjection: projection } : {};
164
171
  const failure = (0, data_provider_1.resolveMessageFailure)(row);
165
172
  if (failure) {
166
173
  if (agenticErrorSubtype(row) === agentic_stream_1.DAEMON_HANDOVER_REASON)
167
174
  return { state: 'pending' };
168
175
  return {
169
176
  state: 'failed',
177
+ ...publicProjection,
170
178
  error: failure.reason ?? 'The run failed. No reason was recorded on the message.',
171
179
  ...(failure.answer ? { text: failure.answer } : {}),
172
180
  };
@@ -178,6 +186,7 @@ function handoverStateFromMessages(messages, responseMessageId) {
178
186
  const repairedAt = typeof repair.repairedAt === 'string' ? repair.repairedAt : undefined;
179
187
  return {
180
188
  state: 'repaired',
189
+ ...publicProjection,
181
190
  text: typeof row.text === 'string' ? row.text : '',
182
191
  ...(repairedAt ? { repairedAt } : {}),
183
192
  };
@@ -0,0 +1,6 @@
1
+ import { ComputerUseCommand } from '../../lib/computer-use';
2
+ export default class ComputerUseAudio extends ComputerUseCommand {
3
+ static summary: string;
4
+ static description: string;
5
+ protected action: string;
6
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const computer_use_1 = require("../../lib/computer-use");
4
+ class ComputerUseAudio extends computer_use_1.ComputerUseCommand {
5
+ static summary = 'Configure optional computer audio with status, enable or disable';
6
+ static description = 'Flags are forwarded unchanged. Run `skrrd computer-use audio --help` for options; --profile selects the local daemon profile and --json emits one stable document.';
7
+ action = 'audio';
8
+ }
9
+ exports.default = ComputerUseAudio;
@@ -0,0 +1,7 @@
1
+ import { ComputerUseCommand } from '../../lib/computer-use';
2
+ export default class ComputerUseBrowser extends ComputerUseCommand {
3
+ static summary: string;
4
+ static description: string;
5
+ static examples: string[];
6
+ protected action: string;
7
+ }
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const computer_use_1 = require("../../lib/computer-use");
4
+ class ComputerUseBrowser extends computer_use_1.ComputerUseCommand {
5
+ static summary = 'Configure original Chrome, inspect its extension, and manage its native host';
6
+ static description = 'Actions: status, enable, disable, setup, update, verify. Setup uses the original LCU installer: private relay files belong to the selected skrr profile, while native-host registration is shared by the desktop account and supported Chromium browsers. Verify initializes the original MCP schema without browser actions. Flags are forwarded unchanged; run `skrrd computer-use browser --help` for all options.';
7
+ static examples = [
8
+ '<%= config.bin %> computer-use browser enable',
9
+ '<%= config.bin %> computer-use browser setup --profile work',
10
+ '<%= config.bin %> computer-use browser status --profile work --json',
11
+ '<%= config.bin %> computer-use browser update --profile work',
12
+ '<%= config.bin %> computer-use browser verify --profile work --json',
13
+ ];
14
+ action = 'browser';
15
+ }
16
+ exports.default = ComputerUseBrowser;
@@ -0,0 +1,6 @@
1
+ import { ComputerUseCommand } from '../../lib/computer-use';
2
+ export default class ComputerUseDisable extends ComputerUseCommand {
3
+ static summary: string;
4
+ static description: string;
5
+ protected action: string;
6
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const computer_use_1 = require("../../lib/computer-use");
4
+ class ComputerUseDisable extends computer_use_1.ComputerUseCommand {
5
+ static summary = 'Revoke Computer Use consent and stop the active controller';
6
+ static description = 'Flags are forwarded unchanged. Run `skrrd computer-use disable --help` for options; --profile selects the local daemon profile and --json emits one stable document.';
7
+ action = 'disable';
8
+ }
9
+ exports.default = ComputerUseDisable;
@@ -0,0 +1,6 @@
1
+ import { ComputerUseCommand } from '../../lib/computer-use';
2
+ export default class ComputerUseEnable extends ComputerUseCommand {
3
+ static summary: string;
4
+ static description: string;
5
+ protected action: string;
6
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const computer_use_1 = require("../../lib/computer-use");
4
+ class ComputerUseEnable extends computer_use_1.ComputerUseCommand {
5
+ static summary = 'Enable Computer Use locally; --cloud-agents separately grants cloud Agent access';
6
+ static description = 'Flags are forwarded unchanged. Run `skrrd computer-use enable --help` for options; --profile selects the local daemon profile and --json emits one stable document.';
7
+ action = 'enable';
8
+ }
9
+ exports.default = ComputerUseEnable;
@@ -0,0 +1,6 @@
1
+ import { ComputerUseCommand } from '../../lib/computer-use';
2
+ export default class ComputerUse extends ComputerUseCommand {
3
+ static summary: string;
4
+ static description: string;
5
+ protected action: undefined;
6
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const computer_use_1 = require("../../lib/computer-use");
4
+ class ComputerUse extends computer_use_1.ComputerUseCommand {
5
+ static summary = 'Install and control optional Computer Use on this machine';
6
+ static description = 'Computer Use uses your installed official app runtime. Run `skrr computer-use status`; use `skrrd computer-use --help` for all options, including --profile and --json.';
7
+ action = undefined;
8
+ }
9
+ exports.default = ComputerUse;
@@ -0,0 +1,6 @@
1
+ import { ComputerUseCommand } from '../../lib/computer-use';
2
+ export default class ComputerUseInstall extends ComputerUseCommand {
3
+ static summary: string;
4
+ static description: string;
5
+ protected action: string;
6
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const computer_use_1 = require("../../lib/computer-use");
4
+ class ComputerUseInstall extends computer_use_1.ComputerUseCommand {
5
+ static summary = 'Install a pinned thin release from an explicit local archive and trusted SHA-256';
6
+ static description = 'Flags are forwarded unchanged. Run `skrrd computer-use install --help` for options; --profile selects the local daemon profile and --json emits one stable document.';
7
+ action = 'install';
8
+ }
9
+ exports.default = ComputerUseInstall;
@@ -0,0 +1,6 @@
1
+ import { ComputerUseCommand } from '../../lib/computer-use';
2
+ export default class ComputerUseRecover extends ComputerUseCommand {
3
+ static summary: string;
4
+ static description: string;
5
+ protected action: string;
6
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const computer_use_1 = require("../../lib/computer-use");
4
+ class ComputerUseRecover extends computer_use_1.ComputerUseCommand {
5
+ static summary = 'Retry runtime recovery only after confirmed execution cleanup';
6
+ static description = 'Flags are forwarded unchanged. Run `skrrd computer-use recover --help` for options; --profile selects the local daemon profile and --json emits one stable document.';
7
+ action = 'recover';
8
+ }
9
+ exports.default = ComputerUseRecover;
@@ -0,0 +1,6 @@
1
+ import { ComputerUseCommand } from '../../lib/computer-use';
2
+ export default class ComputerUseStatus extends ComputerUseCommand {
3
+ static summary: string;
4
+ static description: string;
5
+ protected action: string;
6
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const computer_use_1 = require("../../lib/computer-use");
4
+ class ComputerUseStatus extends computer_use_1.ComputerUseCommand {
5
+ static summary = 'Show configuration and live Computer Use availability without desktop interaction';
6
+ static description = 'Flags are forwarded unchanged. Run `skrrd computer-use status --help` for options; --profile selects the local daemon profile and --json emits one stable document.';
7
+ action = 'status';
8
+ }
9
+ exports.default = ComputerUseStatus;
@@ -0,0 +1,6 @@
1
+ import { ComputerUseCommand } from '../../lib/computer-use';
2
+ export default class ComputerUseStop extends ComputerUseCommand {
3
+ static summary: string;
4
+ static description: string;
5
+ protected action: string;
6
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const computer_use_1 = require("../../lib/computer-use");
4
+ class ComputerUseStop extends computer_use_1.ComputerUseCommand {
5
+ static summary = 'Stop the running Computer Use controller and confirm cleanup';
6
+ static description = 'Flags are forwarded unchanged. Run `skrrd computer-use stop --help` for options; --profile selects the local daemon profile and --json emits one stable document.';
7
+ action = 'stop';
8
+ }
9
+ exports.default = ComputerUseStop;
@@ -32,7 +32,7 @@ const daemon_machine_identity_copy_1 = require("../../lib/daemon-machine-identit
32
32
  class DaemonLogin extends core_1.Command {
33
33
  static aliases = ['daemons:login'];
34
34
  static summary = 'Authenticate the skrr background service on this computer (separate from `skrr login`)';
35
- static description = (0, exec_runtime_binary_1.forwardedFlagsNote)('login', { binds: true });
35
+ static description = (0, exec_runtime_binary_1.forwardedFlagsNote)('login', { binds: true }) + '\nUse --computer-use to request explicit Computer Use permission in browser consent. This does not enable the runtime or grant machine access.';
36
36
  static strict = false; // forward all args verbatim — see run()
37
37
  async run() {
38
38
  // `this.argv`, NOT `this.parse()` — `strict = false` relaxes POSITIONAL
@@ -1,11 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ const lookbackPlans_1 = require("../../../lib/lookbackPlans");
3
4
  const core_1 = require("@oclif/core");
4
5
  const base_command_1 = require("../../../base-command");
5
- const lookbackPlans_1 = require("../../../lib/lookbackPlans");
6
+ const lookbackPlans_2 = require("../../../lib/lookbackPlans");
6
7
  class LookbackPlansCancel extends base_command_1.BaseCommand {
7
8
  static description = 'Cancel the remaining lookbacks of a plan';
8
- static args = { id: lookbackPlans_1.lookbackPlanIdArg };
9
+ static args = { id: lookbackPlans_2.lookbackPlanIdArg };
9
10
  static flags = {
10
11
  revision: core_1.Flags.integer({ description: 'Expected current revision; stale edits are refused', min: 1 }),
11
12
  reason: core_1.Flags.string({ description: 'Why the remaining lookbacks are no longer needed' }),
@@ -15,10 +16,16 @@ class LookbackPlansCancel extends base_command_1.BaseCommand {
15
16
  this.requireAuth();
16
17
  const { args, flags } = await this.parse(LookbackPlansCancel);
17
18
  try {
18
- const result = await lookbackPlans_1.lookbackPlansApi.cancel(args.id, { expectedRevision: flags.revision, reason: flags.reason });
19
+ const result = await lookbackPlans_2.lookbackPlansApi.cancel(args.id, { expectedRevision: flags.revision, reason: flags.reason });
19
20
  this.log(flags.json ? JSON.stringify(result, null, 2) : `Lookback plan ${result.plan.id}: ${result.plan.state} (r${result.plan.revision}).`);
20
21
  }
21
22
  catch (err) {
23
+ if ((0, lookbackPlans_1.isLookbackMutationOutcomeUnknown)(err)) {
24
+ const readback = await lookbackPlans_2.lookbackPlansApi.show(args.id).catch(() => null);
25
+ this.failWithCliError((0, lookbackPlans_1.lookbackUnconfirmedFailure)({ operation: 'cancel', planId: args.id,
26
+ ...(readback?.plan ? { currentPlan: readback.plan } : {}),
27
+ readback: readback?.plan ? 'observed' : 'unavailable' }));
28
+ }
22
29
  this.handleApiError(err);
23
30
  }
24
31
  }
@@ -0,0 +1,9 @@
1
+ import { BaseCommand } from '../../../base-command';
2
+ export default class LookbackPlansCapacity extends BaseCommand {
3
+ static description: string;
4
+ static flags: {
5
+ agent: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
6
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
7
+ };
8
+ run(): Promise<void>;
9
+ }
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const base_command_1 = require("../../../base-command");
5
+ const lookbackPlans_1 = require("../../../lib/lookbackPlans");
6
+ const followups_1 = require("../../../lib/followups");
7
+ class LookbackPlansCapacity extends base_command_1.BaseCommand {
8
+ static description = 'Read one agent’s actual UTC-day lookback plan allowance; reserves nothing';
9
+ static flags = {
10
+ agent: core_1.Flags.string({ description: 'Agent ID (default: bound session agent)' }),
11
+ json: core_1.Flags.boolean({ description: 'Output authoritative capacity facts as JSON' }),
12
+ };
13
+ async run() {
14
+ this.requireAuth();
15
+ const { flags } = await this.parse(LookbackPlansCapacity);
16
+ let agentId;
17
+ try {
18
+ agentId = (0, followups_1.resolveFollowUpAgent)(flags.agent).id;
19
+ }
20
+ catch (err) {
21
+ this.failWithCliError({ message: err instanceof Error ? err.message : String(err),
22
+ code: 'AGENT_CONTEXT_AMBIGUOUS', exit: 2, retryable: false });
23
+ return;
24
+ }
25
+ try {
26
+ const result = await lookbackPlans_1.lookbackPlansApi.capacity({ agentId });
27
+ if (flags.json) {
28
+ this.log(JSON.stringify(result, null, 2));
29
+ return;
30
+ }
31
+ this.log(`${result.scope.agentId}: ${result.remaining}/${result.limit} plans remaining (${result.used} admitted this UTC day).`);
32
+ this.log(result.admission === 'policy_blocked'
33
+ ? 'New plans are blocked by a zero agent allowance. The daily reset does not change that policy.'
34
+ : `UTC-day reset: ${new Date(result.period.resetAt).toLocaleString()} (${result.period.resetAt}). Recheck capacity then.`);
35
+ this.log(`Observed: ${result.observedAt}. This read reserves nothing; source, execution and delivery are checked separately.`);
36
+ }
37
+ catch (err) {
38
+ this.handleApiError(err);
39
+ }
40
+ }
41
+ }
42
+ exports.default = LookbackPlansCapacity;
@@ -30,6 +30,9 @@ class LookbackPlansCreate extends base_command_1.BaseCommand {
30
30
  this.log(flags.json ? JSON.stringify(result, null, 2) : (0, lookbackPlans_1.lookbackArmingLine)(result));
31
31
  }
32
32
  catch (err) {
33
+ if ((0, lookbackPlans_1.isLookbackMutationOutcomeUnknown)(err)) {
34
+ this.failWithCliError((0, lookbackPlans_1.lookbackUnconfirmedFailure)({ operation: 'create', source: body.plan.source, agentId: body.agentId }));
35
+ }
33
36
  this.handleApiError(err);
34
37
  }
35
38
  }
@@ -1,15 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ const lookbackPlans_1 = require("../../../lib/lookbackPlans");
3
4
  const core_1 = require("@oclif/core");
4
5
  const base_command_1 = require("../../../base-command");
5
6
  const prompt_1 = require("../../../lib/prompt");
6
- const lookbackPlans_1 = require("../../../lib/lookbackPlans");
7
+ const lookbackPlans_2 = require("../../../lib/lookbackPlans");
7
8
  const lookbackPlanHelp_1 = require("../../../lib/lookbackPlanHelp");
8
9
  class LookbackPlansRevise extends base_command_1.BaseCommand {
9
10
  static description = 'Revise pending lookbacks using the original source and step IDs\n\n' + lookbackPlanHelp_1.LOOKBACK_PLAN_INPUT_HELP +
10
11
  '\n\nRevise accepts the plan itself, not a create envelope. Use the current --revision from show; a stale revision returns LOOKBACK_CONFLICT (409).';
11
12
  static examples = ['<%= config.bin %> followups plans revise PLAN_ID --revision 1 --from-json revised-plan.json --json'];
12
- static args = { id: lookbackPlans_1.lookbackPlanIdArg };
13
+ static args = { id: lookbackPlans_2.lookbackPlanIdArg };
13
14
  static flags = {
14
15
  revision: core_1.Flags.integer({ description: 'Expected current revision; stale edits are refused', min: 1, required: true }),
15
16
  'from-json': core_1.Flags.string({ description: 'Full PlanInput JSON file; - reads stdin', required: true }),
@@ -20,17 +21,23 @@ class LookbackPlansRevise extends base_command_1.BaseCommand {
20
21
  const { args, flags } = await this.parse(LookbackPlansRevise);
21
22
  let plan;
22
23
  try {
23
- plan = (0, lookbackPlans_1.lookbackInput)(await (0, prompt_1.readJsonBody)(flags['from-json']), true);
24
+ plan = (0, lookbackPlans_2.lookbackInput)(await (0, prompt_1.readJsonBody)(flags['from-json']), true);
24
25
  }
25
26
  catch (err) {
26
- this.failWithCliError((0, lookbackPlans_1.lookbackInputFailure)(err));
27
+ this.failWithCliError((0, lookbackPlans_2.lookbackInputFailure)(err));
27
28
  return;
28
29
  }
29
30
  try {
30
- const result = await lookbackPlans_1.lookbackPlansApi.revise(args.id, { expectedRevision: flags.revision, plan });
31
- this.log(flags.json ? JSON.stringify(result, null, 2) : (0, lookbackPlans_1.lookbackArmingLine)(result));
31
+ const result = await lookbackPlans_2.lookbackPlansApi.revise(args.id, { expectedRevision: flags.revision, plan });
32
+ this.log(flags.json ? JSON.stringify(result, null, 2) : (0, lookbackPlans_2.lookbackArmingLine)(result));
32
33
  }
33
34
  catch (err) {
35
+ if ((0, lookbackPlans_1.isLookbackMutationOutcomeUnknown)(err)) {
36
+ const readback = await lookbackPlans_2.lookbackPlansApi.show(args.id).catch(() => null);
37
+ this.failWithCliError((0, lookbackPlans_1.lookbackUnconfirmedFailure)({ operation: 'revise', planId: args.id,
38
+ ...(readback?.plan ? { currentPlan: readback.plan } : {}),
39
+ readback: readback?.plan ? 'observed' : 'unavailable' }));
40
+ }
34
41
  this.handleApiError(err);
35
42
  }
36
43
  }
@@ -1,4 +1,4 @@
1
- import { type AssistantTextJoiner } from '@skrr-ai/data-provider';
1
+ import { type PublicProjection, type AssistantTextJoiner } from '@skrr-ai/data-provider';
2
2
  /**
3
3
  * Why a question was dismissed when no terminal exists to ask it on. It is the
4
4
  * REASON for a dismissal, never an answer: it travels as the value of the
@@ -48,6 +48,7 @@ export type AgenticStreamResult = {
48
48
  */
49
49
  export type ReconciledTerminal = {
50
50
  status: 'completed' | 'failed';
51
+ publicProjection?: PublicProjection;
51
52
  /** The answer as persisted, when there is one. */
52
53
  text?: string;
53
54
  /** The recorded failure reason — `metadata.agentic.error` on the message. */
@@ -100,6 +101,7 @@ export type HandoverReading =
100
101
  | {
101
102
  state: 'repaired';
102
103
  text: string;
104
+ publicProjection?: PublicProjection;
103
105
  repairedAt?: string;
104
106
  }
105
107
  /** The machine's turn ended without finishing, and the server settled it so. */
@@ -107,6 +109,7 @@ export type HandoverReading =
107
109
  state: 'failed';
108
110
  error: string;
109
111
  text?: string;
112
+ publicProjection?: PublicProjection;
110
113
  };
111
114
  export type HandoverWaitOptions = {
112
115
  /** Read the persisted response message. A throw or null is "no evidence". */
@@ -512,6 +515,7 @@ export declare class AgenticStreamClient {
512
515
  private readonly textJoiner;
513
516
  /** Highest envelope `__seq` folded into `accumulated`, for gap detection. */
514
517
  private highestSeq;
518
+ private publicProjection;
515
519
  private readonly pendingEnvelopes;
516
520
  private replayTimer;
517
521
  private replayFlight;
@@ -740,6 +740,7 @@ class AgenticStreamClient {
740
740
  textJoiner = (0, data_provider_1.createAssistantTextJoiner)();
741
741
  /** Highest envelope `__seq` folded into `accumulated`, for gap detection. */
742
742
  highestSeq = 0;
743
+ publicProjection;
743
744
  pendingEnvelopes = new Map();
744
745
  replayTimer = null;
745
746
  replayFlight = null;
@@ -972,6 +973,7 @@ class AgenticStreamClient {
972
973
  reason,
973
974
  ...(terminal.error ? { message: terminal.error, error: terminal.error } : {}),
974
975
  ...(typeof terminal.text === 'string' ? { result: terminal.text } : {}),
976
+ ...(terminal.publicProjection ? { publicProjection: terminal.publicProjection } : {}),
975
977
  });
976
978
  return true;
977
979
  }
@@ -1129,6 +1131,7 @@ class AgenticStreamClient {
1129
1131
  type: 'execution:complete',
1130
1132
  sessionId: this.options.sessionId,
1131
1133
  result: reading.text,
1134
+ ...(reading.publicProjection ? { publicProjection: reading.publicProjection } : {}),
1132
1135
  repaired: true,
1133
1136
  repairedFrom: 'durable_record',
1134
1137
  overturned: { code: exports.WORKER_REPLACED_CODE, reason: exports.DAEMON_HANDOVER_REASON },
@@ -1146,6 +1149,7 @@ class AgenticStreamClient {
1146
1149
  message: reading.error,
1147
1150
  errors: [reading.error],
1148
1151
  ...(typeof reading.text === 'string' && reading.text ? { result: reading.text } : {}),
1152
+ ...(reading.publicProjection ? { publicProjection: reading.publicProjection } : {}),
1149
1153
  handover: { outcome: 'machine_failed', waitedMs },
1150
1154
  });
1151
1155
  return true;
@@ -1454,6 +1458,9 @@ class AgenticStreamClient {
1454
1458
  if (fresh.length === 0)
1455
1459
  return; // a pure re-delivery — drop it whole
1456
1460
  const scoped = { ...event, envelopes: fresh };
1461
+ if (fresh.some((env) => env?.ev?.t === 'text' &&
1462
+ env.ev?.publicProjection === 'lookback_answer_v1'))
1463
+ this.publicProjection = 'lookback_answer_v1';
1457
1464
  // Note what never arrived before folding this batch in (OSK-7631,
1458
1465
  // OSK-13518). Checked against the FRESH set: a re-delivery carries old
1459
1466
  // seqs and would read as a gap that never happened.
@@ -1539,6 +1546,8 @@ class AgenticStreamClient {
1539
1546
  socket.on('message:stream', (event) => {
1540
1547
  if (!match(event))
1541
1548
  return;
1549
+ if (event.publicProjection === 'lookback_answer_v1')
1550
+ this.publicProjection = event.publicProjection;
1542
1551
  const text = typeof event.text === 'string' ? event.text : '';
1543
1552
  const delta = typeof event.delta === 'string' ? event.delta : '';
1544
1553
  if (text && text.length >= this.accumulated.length)
@@ -1574,6 +1583,7 @@ class AgenticStreamClient {
1574
1583
  if (!match(event))
1575
1584
  return;
1576
1585
  this.accumulated = '';
1586
+ this.publicProjection = undefined;
1577
1587
  this.textJoiner.reset();
1578
1588
  this.renderedText = '';
1579
1589
  // Seqs restart with the stream, so a fresh low seq is not a gap.
@@ -2099,7 +2109,7 @@ class AgenticStreamClient {
2099
2109
  const streamedText = (0, widgetTerminalText_1.widgetsAsText)(this.accumulated, { final: true });
2100
2110
  void this.readRecordedText().then((recorded) => {
2101
2111
  this.settleGapVerdict(streamedText, recorded);
2102
- this.settle(status, event, recorded?.text || undefined);
2112
+ this.settle(status, event, recorded);
2103
2113
  });
2104
2114
  return;
2105
2115
  }
@@ -2124,10 +2134,10 @@ class AgenticStreamClient {
2124
2134
  try {
2125
2135
  const terminal = await reconcile();
2126
2136
  if (terminal && typeof terminal.text === 'string' && terminal.text) {
2127
- return { text: terminal.text };
2137
+ return { text: terminal.text, ...(terminal.publicProjection ? { publicProjection: terminal.publicProjection } : {}) };
2128
2138
  }
2129
2139
  if (terminal)
2130
- empty = { text: '' };
2140
+ empty = { text: '', ...(terminal.publicProjection ? { publicProjection: terminal.publicProjection } : {}) };
2131
2141
  }
2132
2142
  catch {
2133
2143
  // No evidence either way; try again, then settle on the stream.
@@ -2135,7 +2145,7 @@ class AgenticStreamClient {
2135
2145
  }
2136
2146
  return empty;
2137
2147
  }
2138
- settle(status, event, recordedText) {
2148
+ settle(status, event, recorded) {
2139
2149
  // `execution:complete` carries the final answer as `result`, and it is
2140
2150
  // AUTHORITATIVE — preferred over whatever the deltas added up to, not just
2141
2151
  // used when they added up to nothing.
@@ -2146,6 +2156,8 @@ class AgenticStreamClient {
2146
2156
  // `result` whenever the server sends one makes the returned text the
2147
2157
  // agent's actual final message rather than however much of it arrived in
2148
2158
  // time.
2159
+ if (event.publicProjection === 'lookback_answer_v1')
2160
+ this.publicProjection = event.publicProjection;
2149
2161
  const finalText = typeof event.result === 'string' ? event.result : '';
2150
2162
  // …EXCEPT when it is a strict suffix of what we accumulated.
2151
2163
  //
@@ -2168,7 +2180,10 @@ class AgenticStreamClient {
2168
2180
  this.accumulated.length > finalText.length &&
2169
2181
  (this.accumulated.endsWith(finalText) ||
2170
2182
  endsWithIgnoringWhitespace(this.accumulated, finalText));
2171
- if (finalText && finalText !== this.accumulated && !accumulationIsSuperset) {
2183
+ if (event.publicProjection === 'lookback_answer_v1' && typeof event.result === 'string') {
2184
+ this.accumulated = event.result;
2185
+ }
2186
+ else if (finalText && finalText !== this.accumulated && !accumulationIsSuperset) {
2172
2187
  this.accumulated = finalText;
2173
2188
  }
2174
2189
  // The record wins over a stream known to have lost chunks, unless what
@@ -2176,9 +2191,10 @@ class AgenticStreamClient {
2176
2191
  // other way round).
2177
2192
  // (Compared as the reader sees it: the record holds a widget as its fallback sentence,
2178
2193
  // which is shorter than the block the stream carried, and the raw length would never lose.)
2179
- if (recordedText &&
2180
- recordedText.length > (0, widgetTerminalText_1.widgetsAsText)(this.accumulated, { final: true }).length) {
2181
- this.accumulated = recordedText;
2194
+ if (recorded && (recorded.publicProjection === 'lookback_answer_v1' ||
2195
+ recorded.text.length > (0, widgetTerminalText_1.widgetsAsText)(this.accumulated, { final: true }).length)) {
2196
+ this.accumulated = recorded.text;
2197
+ this.publicProjection = recorded.publicProjection;
2182
2198
  }
2183
2199
  // The finished answer, as every other surface shows it: the web applies
2184
2200
  // this same sanitizer, so a scheduling JSON block or leaked function-call
@@ -2186,7 +2202,7 @@ class AgenticStreamClient {
2186
2202
  // printed as part of the agent's answer.
2187
2203
  // A widget is its fallback sentence in a terminal, first: the sanitizer must read
2188
2204
  // prose and never a widget's script (the server projects before it sanitizes, too).
2189
- this.accumulated = (0, data_provider_1.sanitizeFinalText)((0, widgetTerminalText_1.widgetsAsText)(this.accumulated, { final: true }));
2205
+ this.accumulated = (0, data_provider_1.sanitizeFinalText)((0, widgetTerminalText_1.widgetsAsText)(this.accumulated, { final: true }), this.publicProjection);
2190
2206
  if (!this.options.quiet && !this.options.jsonl && this.accumulated) {
2191
2207
  const output = this.options.output ?? process.stdout;
2192
2208
  const { append, shown } = renderableDelta(this.renderedText, this.accumulated);
@@ -0,0 +1,9 @@
1
+ import { Command } from '@oclif/core';
2
+ export declare function buildComputerUseArgs(action: string | undefined, argv: readonly string[]): string[];
3
+ /** The runtime owns local consent, installation and lifecycle; the REST CLI only dispatches. */
4
+ export declare function forwardComputerUseCommand(command: Command, action: string | undefined, argv: readonly string[]): Promise<void>;
5
+ export declare abstract class ComputerUseCommand extends Command {
6
+ static strict: boolean;
7
+ protected abstract action: string | undefined;
8
+ run(): Promise<void>;
9
+ }
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ComputerUseCommand = void 0;
4
+ exports.buildComputerUseArgs = buildComputerUseArgs;
5
+ exports.forwardComputerUseCommand = forwardComputerUseCommand;
6
+ const core_1 = require("@oclif/core");
7
+ const exec_runtime_binary_1 = require("./exec-runtime-binary");
8
+ function buildComputerUseArgs(action, argv) {
9
+ return ['computer-use', ...(action ? [action] : []), ...argv];
10
+ }
11
+ /** The runtime owns local consent, installation and lifecycle; the REST CLI only dispatches. */
12
+ async function forwardComputerUseCommand(command, action, argv) {
13
+ const fail = (message, code, exit) => {
14
+ if (argv.includes('--json')) {
15
+ command.log(JSON.stringify({ object: 'computer_use_control', schemaVersion: 1, action: action ?? argv[0] ?? 'help', ok: false, error: { code, message } }));
16
+ return command.exit(exit);
17
+ }
18
+ command.log(message);
19
+ return command.exit(exit);
20
+ };
21
+ try {
22
+ if ((await (0, exec_runtime_binary_1.runtimeBinarySupportsSubcommand)('computer-use')) === false) {
23
+ return fail('This local daemon does not support Computer Use. Update skrrd, then retry.', 'runtime_unsupported', 2);
24
+ }
25
+ command.exit(await (0, exec_runtime_binary_1.execRuntimeBinary)(buildComputerUseArgs(action, argv)));
26
+ }
27
+ catch (error) {
28
+ if (error.message === 'runtime-binary-not-installed') {
29
+ return fail((0, exec_runtime_binary_1.notInstalledMessage)(), 'runtime_not_installed', 127);
30
+ }
31
+ throw error;
32
+ }
33
+ }
34
+ class ComputerUseCommand extends core_1.Command {
35
+ static strict = false;
36
+ async run() {
37
+ // Never call parse(): unknown runtime flags must reach the authoritative parser unchanged.
38
+ await forwardComputerUseCommand(this, this.action, this.argv);
39
+ }
40
+ }
41
+ exports.ComputerUseCommand = ComputerUseCommand;