@skrr-ai/cli 0.1.116 → 0.1.118

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 (94) hide show
  1. package/dist/base-command.d.ts +21 -0
  2. package/dist/base-command.js +95 -8
  3. package/dist/commands/actions/browse.js +2 -1
  4. package/dist/commands/actions/install.d.ts +2 -0
  5. package/dist/commands/actions/install.js +67 -2
  6. package/dist/commands/actions/list.js +2 -1
  7. package/dist/commands/actions/show.js +2 -1
  8. package/dist/commands/commitments/create.d.ts +21 -2
  9. package/dist/commands/commitments/create.js +74 -4
  10. package/dist/commands/convos/recovery.js +12 -4
  11. package/dist/commands/followups/plans/list.js +1 -1
  12. package/dist/commands/guide.d.ts +21 -0
  13. package/dist/commands/guide.js +46 -0
  14. package/dist/commands/instructions/guide.js +34 -52
  15. package/dist/commands/memory/maintain.js +1 -1
  16. package/dist/commands/skills/browse.js +2 -1
  17. package/dist/commands/skills/details.js +4 -2
  18. package/dist/commands/skills/featured.js +2 -1
  19. package/dist/commands/skills/install.d.ts +2 -0
  20. package/dist/commands/skills/install.js +62 -3
  21. package/dist/commands/skills/search.js +2 -1
  22. package/dist/commands/slack/send-as-agent.js +3 -3
  23. package/dist/commands/spaces/create.js +8 -2
  24. package/dist/commands/spaces/guide.d.ts +21 -0
  25. package/dist/commands/spaces/guide.js +40 -0
  26. package/dist/commands/spaces/index.d.ts +0 -1
  27. package/dist/commands/spaces/index.js +1 -6
  28. package/dist/commands/store/acquisitions/list.js +2 -1
  29. package/dist/commands/store/acquisitions/show.js +2 -1
  30. package/dist/commands/store/browse.js +4 -2
  31. package/dist/commands/store/install.d.ts +1 -0
  32. package/dist/commands/store/install.js +26 -2
  33. package/dist/commands/store/releases.js +4 -2
  34. package/dist/commands/store/show.js +3 -2
  35. package/dist/commands/store/tip.js +2 -2
  36. package/dist/commands/tasks/checkout.js +2 -3
  37. package/dist/commands/tasks/comments/add.js +3 -5
  38. package/dist/commands/tasks/complete.js +2 -3
  39. package/dist/commands/tasks/deliverable/add.d.ts +1 -1
  40. package/dist/commands/tasks/deliverable/add.js +4 -7
  41. package/dist/commands/tasks/expectations/assess.js +2 -2
  42. package/dist/commands/tasks/guide.d.ts +8 -0
  43. package/dist/commands/tasks/guide.js +23 -10
  44. package/dist/commands/tasks/report.js +9 -5
  45. package/dist/commands/tasks/resource/add.js +2 -3
  46. package/dist/commands/tasks/result/submit.js +2 -3
  47. package/dist/commands/tasks/resume/save.js +2 -3
  48. package/dist/commands/tasks/review.js +2 -3
  49. package/dist/commands/tasks/triage.js +2 -1
  50. package/dist/commands/tasks/updates/add.js +2 -3
  51. package/dist/generated/agent-guides.json +8312 -0
  52. package/dist/generated/managed-instruction-guides.json +1 -1
  53. package/dist/help.js +4 -3
  54. package/dist/hooks/command-not-found.js +1 -1
  55. package/dist/lib/action-listings.js +2 -1
  56. package/dist/lib/agent-guide-reference-gate.d.ts +28 -0
  57. package/dist/lib/agent-guide-reference-gate.js +186 -0
  58. package/dist/lib/agent-guides.d.ts +51 -0
  59. package/dist/lib/agent-guides.js +170 -0
  60. package/dist/lib/api-fetch.js +3 -1
  61. package/dist/lib/command-miss.d.ts +13 -2
  62. package/dist/lib/command-miss.js +134 -8
  63. package/dist/lib/guide-pointer.d.ts +15 -0
  64. package/dist/lib/guide-pointer.js +51 -0
  65. package/dist/lib/lookbackPlans.d.ts +3 -1
  66. package/dist/lib/lookbackPlans.js +9 -0
  67. package/dist/lib/node-adapter.js +4 -3
  68. package/dist/lib/outbox.d.ts +0 -14
  69. package/dist/lib/outbox.js +0 -21
  70. package/dist/lib/roles.d.ts +1 -1
  71. package/dist/lib/store-listing.d.ts +6 -1
  72. package/dist/lib/store-listing.js +6 -1
  73. package/dist/lib/task-admission.js +27 -5
  74. package/dist/lib/task-batch.d.ts +10 -7
  75. package/dist/lib/task-batch.js +5 -20
  76. package/dist/lib/task-operations.d.ts +8 -20
  77. package/dist/lib/task-operations.js +9 -94
  78. package/dist/lib/task-preflight.js +70 -33
  79. package/dist/lib/task-runtime-headers.d.ts +11 -0
  80. package/dist/lib/task-runtime-headers.js +73 -0
  81. package/dist/lib/task-write-attribution.js +1 -1
  82. package/dist/lib/usage-discovery.d.ts +4 -0
  83. package/dist/lib/usage-discovery.js +5 -0
  84. package/dist/lib/usd-micros.d.ts +27 -0
  85. package/dist/lib/usd-micros.js +67 -2
  86. package/dist/lib/voice-call-intent.js +3 -1
  87. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessPermissionControls.d.ts +17 -0
  88. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessPermissionControls.js +35 -2
  89. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessPermissionControls.d.ts +17 -0
  90. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessPermissionControls.js +44 -0
  91. package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
  92. package/dist/node_modules/@skrr-ai/data-provider/index.js +11927 -11678
  93. package/oclif.manifest.json +251 -14
  94. package/package.json +4 -2
@@ -1,10 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.taskActionCommand = taskActionCommand;
4
- exports.taskOperationsGuide = taskOperationsGuide;
5
- exports.taskOperationsGuideLines = taskOperationsGuideLines;
6
4
  const shell_quote_1 = require("./shell-quote");
7
- /** Documentation and display paths only. The server still owns allowedActions. */
5
+ /**
6
+ * Documentation and display paths only. The server still owns allowedActions.
7
+ *
8
+ * `skrr tasks guide`'s command map retired into the tasks guide's `commands`
9
+ * section (`skrr guide tasks commands`), the one copy every surface reads;
10
+ * what remains here is the action→command remedies preflight and
11
+ * actionability render into server-declared allowedActions.
12
+ */
8
13
  function taskActionCommand(action, taskId, targetId, bin = 'skrr', context = {}) {
9
14
  const task = (0, shell_quote_1.shellQuoteArg)(taskId);
10
15
  const target = targetId ? (0, shell_quote_1.shellQuoteArg)(targetId) : '<id>';
@@ -13,7 +18,7 @@ function taskActionCommand(action, taskId, targetId, bin = 'skrr', context = {})
13
18
  assign_task: `tasks assign ${task} --help`,
14
19
  // Managed work already has a current Result. Its server-declared
15
20
  // continuation surface distinguishes closing from submitting a new Result.
16
- complete_task: context.allowedActions?.some(item => item.action === 'continue_task')
21
+ complete_task: context.allowedActions?.some((item) => item.action === 'continue_task')
17
22
  ? `tasks move ${task} --status done`
18
23
  : `tasks complete ${task}`,
19
24
  continue_task: `tasks continue ${task} --text "<instruction>" --command-key <key>`,
@@ -31,93 +36,3 @@ function taskActionCommand(action, taskId, targetId, bin = 'skrr', context = {})
31
36
  };
32
37
  return commands[action] ? `${bin} ${commands[action]}` : undefined;
33
38
  }
34
- function taskOperationsGuide(bin = 'skrr') {
35
- const command = (usage, purpose) => ({ command: `${bin} ${usage}`, purpose });
36
- return {
37
- title: 'Task operations',
38
- sections: [
39
- {
40
- title: 'Inspect and plan',
41
- commands: [
42
- command('tasks show <task> --json', 'Read the Task, assignment, and dependency IDs.'),
43
- command('tasks actionability <task>', 'Read the canonical next actor, blocker, and allowed actions.'),
44
- command('tasks preflight <task>', 'Read workflow actionability and execution prerequisites together; creates no Run.'),
45
- command('tasks ready --for agent --agent <agent-id>', 'Find workflow-actionable work for an Agent; this does not verify its runtime.'),
46
- command('tasks create-tree --help', 'Create a related Task tree; blockedByTempIds declares dependencies within that tree.'),
47
- ],
48
- },
49
- {
50
- title: 'Choose assignment',
51
- note: 'Executor intent, assignment, and starting a Run are separate choices. --unassigned clears both assignee kinds and suppresses automatic defaults; it does not start work.',
52
- commands: [
53
- command('tasks create --title "Task title" --execution-mode agent --unassigned --dry-run --json', 'Preview Agent-intended work without selecting an Agent or writing a Task.'),
54
- command('tasks assign <task> --unassigned', 'Clear current assignees while retaining executor intent; creates no Run.'),
55
- command('tasks assign <task> --help', 'Choose an eligible Human or Agent explicitly using the native assignment options.'),
56
- ],
57
- },
58
- {
59
- title: 'Apply and recover a batch',
60
- note: 'Keep the same JSON, scope, and external-key options after an incomplete result. Explicit node externalKey values are preserved; otherwise keys derive from the file and defaults. Changing that input can name new Tasks.',
61
- commands: [
62
- command('tasks create-tree --from-json tasks.json --unassigned --readback --json', 'Apply the batch and reread its declared structured fields. This does not start Tasks.'),
63
- command('tasks create-tree --from-json tasks.json --unassigned --resume --readback --json', 'Continue the unchanged file: confirm existing IDs without patching them, create only missing nodes, then read back.'),
64
- command('tasks create-tree --from-json tasks.json --unassigned --verify-spec --json', 'Read-only structured-field comparison. Rich text and unsupported fields are explicitly unchecked; no Expectation assessment or drift repair is performed.'),
65
- command('tasks create-tree --from-json tasks.json --verify --json', 'Read-only existence check by external key. This makes no specification-equality claim.'),
66
- ],
67
- },
68
- {
69
- title: 'Name a Project or Goal',
70
- note: 'Use exact scoped Project/Goal titles, native refs, or canonical IDs. Duplicate names refuse instead of choosing one. A qualified Project supplies containment; a qualified Goal changes the Goal relationship without moving the Task. Project external keys remain exact and case-sensitive, including keys containing slashes.',
71
- commands: [
72
- command('tasks create --title "Task title" --space <space-id> --project "Exact project title" --goal "Exact Goal title" --unassigned --dry-run --json', 'Preview exact names inside the selected Space.'),
73
- command('tasks create --title "Task title" --project "<space-ref>/<project-ref-or-exact-title>" --goal "<space-ref>/<Goal-exact-title>" --unassigned --dry-run --json', 'Preview qualified references; native relationship permissions still apply.'),
74
- command('tasks create --title "Task title" --space <space-id> --project "<project-external-key>" --unassigned --dry-run --json', 'Reuse an existing Project’s native external key without rewriting it.'),
75
- ],
76
- },
77
- {
78
- title: 'Edit dependencies',
79
- note: 'A waits for B: update A with --add-blocked-by B. These commands change dependencies; inspecting a blocker does not remove it.',
80
- commands: [
81
- command('tasks update <task-A> --add-blocked-by <task-B>', 'Make A wait for B.'),
82
- command('tasks update <task-A> --remove-blocked-by <task-B>', 'Remove that dependency when the relationship is no longer intended.'),
83
- command('tasks update <task-B> --add-blocks <task-A>', 'The same relationship, edited from B.'),
84
- ],
85
- },
86
- {
87
- title: 'Check execution before starting',
88
- note: 'Preflight reads server projections at separate times. It runs no shell command and cannot prove machine directory access, tool availability, or future approval. Starting rechecks current authority.',
89
- commands: [
90
- command('tasks start <task> --dry-run --json', 'Read only the server-owned execution preview through the dedicated preview endpoint.'),
91
- command('agents show <agent-id>', 'Inspect the assigned Agent and its configured runtime.'),
92
- command('harnesses show <harness-id> --json', 'Inspect the actual Harness record and reported provider credential readiness, where available.'),
93
- command('harnesses installers --daemon <daemon-id>', 'Ask that daemon about installed coding CLIs and sign-in where it can tell; this is not a shell execution test.'),
94
- command('harnesses ping <harness-id>', 'Explicitly probe a local daemon for reachability; an answer does not prove a provider can run a task.'),
95
- command('tasks start <task>', 'Start a new Run after reviewing the checks. This command executes work.'),
96
- ],
97
- },
98
- {
99
- title: 'Follow and finish',
100
- commands: [
101
- command('tasks show <task>', 'Inspect current execution and follow the Task link.'),
102
- command('tasks expectations <task>', 'Read what is owed and how it will be checked.'),
103
- command('tasks result submit <task> --help', 'Submit the concrete result and evidence.'),
104
- command('tasks review <task> --help', 'Review another actor’s exact Result.'),
105
- command('tasks complete <task> --help', 'Submit a Result and close out when appropriate.'),
106
- command('instructions guide task-management', 'Read the detailed canonical workflow guide; --offline uses the bundled release copy.'),
107
- ],
108
- },
109
- ],
110
- };
111
- }
112
- function taskOperationsGuideLines(bin = 'skrr') {
113
- const guide = taskOperationsGuide(bin);
114
- const lines = [guide.title];
115
- for (const section of guide.sections) {
116
- lines.push('', section.title);
117
- if (section.note)
118
- lines.push(section.note);
119
- for (const entry of section.commands)
120
- lines.push(` ${entry.command}\n ${entry.purpose}`);
121
- }
122
- return lines;
123
- }
@@ -22,7 +22,9 @@ function unavailable(error, label) {
22
22
  if (typeof body?.code === 'string' && /^[A-Z][A-Z0-9_]{0,100}$/.test(body.code))
23
23
  code = body.code;
24
24
  }
25
- catch { /* non-JSON server refusal */ }
25
+ catch {
26
+ /* non-JSON server refusal */
27
+ }
26
28
  }
27
29
  const remedy = status === 401
28
30
  ? 'Restore the current CLI sign-in or delegated runtime credential, then repeat this read-only check.'
@@ -32,9 +34,12 @@ function unavailable(error, label) {
32
34
  ? 'Check the Task reference and server support for this diagnostic. No start fallback was attempted.'
33
35
  : 'Read tasks actionability and tasks start --dry-run separately for the native refusal, then repeat preflight after resolving it.';
34
36
  return {
35
- status: 'unavailable', certainty: 'unknown', code: code || 'TASK_PREFLIGHT_UNAVAILABLE',
37
+ status: 'unavailable',
38
+ certainty: 'unknown',
39
+ code: code || 'TASK_PREFLIGHT_UNAVAILABLE',
36
40
  ...(status ? { httpStatus: status } : {}),
37
- message: `${label} could not be confirmed${status ? ` (HTTP ${status})` : ''}.`, remedy,
41
+ message: `${label} could not be confirmed${status ? ` (HTTP ${status})` : ''}.`,
42
+ remedy,
38
43
  };
39
44
  }
40
45
  function isWorkflow(value, taskId) {
@@ -42,60 +47,92 @@ function isWorkflow(value, taskId) {
42
47
  return false;
43
48
  const row = value;
44
49
  const a = row.actionability;
45
- return row.taskId === taskId && Boolean(a &&
46
- ['ready', 'running', 'waiting', 'terminal'].includes(a.state) &&
47
- ['agent', 'human', 'system', 'external', 'none'].includes(a.nextActor) &&
48
- typeof a.reasonCode === 'string' && typeof a.reason === 'string' &&
49
- (a.actorRefs === undefined || Array.isArray(a.actorRefs) && a.actorRefs.every(ref => ref && ['user', 'agent'].includes(ref.kind) && typeof ref.id === 'string')) &&
50
- Array.isArray(a.allowedActions) && a.allowedActions.every(action => action &&
51
- typeof action.action === 'string' && (action.targetId === undefined || typeof action.targetId === 'string')));
50
+ return (row.taskId === taskId &&
51
+ Boolean(a &&
52
+ ['ready', 'running', 'waiting', 'terminal'].includes(a.state) &&
53
+ ['agent', 'human', 'system', 'external', 'none'].includes(a.nextActor) &&
54
+ typeof a.reasonCode === 'string' &&
55
+ typeof a.reason === 'string' &&
56
+ (a.actorRefs === undefined ||
57
+ (Array.isArray(a.actorRefs) &&
58
+ a.actorRefs.every((ref) => ref && ['user', 'agent'].includes(ref.kind) && typeof ref.id === 'string'))) &&
59
+ Array.isArray(a.allowedActions) &&
60
+ a.allowedActions.every((action) => action &&
61
+ typeof action.action === 'string' &&
62
+ (action.targetId === undefined || typeof action.targetId === 'string'))));
52
63
  }
53
64
  function isPreview(value, taskId) {
54
65
  if (!(0, task_admission_1.isAdmissionPreview)(value) || value.taskId !== taskId)
55
66
  return false;
56
67
  const a = value.executionAdmission;
57
- return Boolean(typeof a.unattended === 'boolean' && typeof a.approverAvailable === 'boolean' &&
58
- (a.constraints === undefined || Array.isArray(a.constraints) && a.constraints.every(c => c &&
59
- (c.message === undefined || typeof c.message === 'string') &&
60
- (c.requiredAction === undefined || typeof c.requiredAction === 'string'))) &&
61
- (a.permission === undefined || a.permission && typeof a.permission === 'object' &&
62
- (a.permission.mode == null || typeof a.permission.mode === 'string') &&
63
- (a.permission.source === undefined || typeof a.permission.source === 'string')) &&
64
- (a.shell === undefined || a.shell && typeof a.shell === 'object' &&
65
- (a.shell.state === undefined || typeof a.shell.state === 'string')) &&
66
- (a.workingDirectory === undefined || a.workingDirectory &&
67
- (a.workingDirectory.path === null || typeof a.workingDirectory.path === 'string') &&
68
- typeof a.workingDirectory.source === 'string'));
68
+ return Boolean(typeof a.unattended === 'boolean' &&
69
+ typeof a.approverAvailable === 'boolean' &&
70
+ (a.constraints === undefined ||
71
+ (Array.isArray(a.constraints) &&
72
+ a.constraints.every((c) => c &&
73
+ (c.message === undefined || typeof c.message === 'string') &&
74
+ (c.requiredAction === undefined || typeof c.requiredAction === 'string')))) &&
75
+ (a.permission === undefined ||
76
+ (a.permission &&
77
+ typeof a.permission === 'object' &&
78
+ (a.permission.mode == null || typeof a.permission.mode === 'string') &&
79
+ (a.permission.source === undefined || typeof a.permission.source === 'string'))) &&
80
+ (a.shell === undefined ||
81
+ (a.shell &&
82
+ typeof a.shell === 'object' &&
83
+ (a.shell.state === undefined || typeof a.shell.state === 'string'))) &&
84
+ (a.workingDirectory === undefined ||
85
+ (a.workingDirectory &&
86
+ (a.workingDirectory.path === null || typeof a.workingDirectory.path === 'string') &&
87
+ typeof a.workingDirectory.source === 'string')));
69
88
  }
70
89
  /** Compose native reads. This module cannot dispatch execution or infer grants. */
71
90
  async function readTaskPreflight(taskId, reads) {
72
91
  const [workflowResult, executionResult] = await Promise.allSettled([
73
- Promise.resolve().then(reads.workflow), Promise.resolve().then(reads.execution),
92
+ Promise.resolve().then(reads.workflow),
93
+ Promise.resolve().then(reads.execution),
74
94
  ]);
75
95
  const workflow = workflowResult.status === 'fulfilled' && isWorkflow(workflowResult.value, taskId)
76
96
  ? { status: 'observed', certainty: 'server_projection', value: workflowResult.value }
77
- : unavailable(workflowResult.status === 'rejected' ? workflowResult.reason : { code: 'TASK_ACTIONABILITY_UNSUPPORTED' }, 'Workflow actionability');
97
+ : unavailable(workflowResult.status === 'rejected'
98
+ ? workflowResult.reason
99
+ : { code: 'TASK_ACTIONABILITY_UNSUPPORTED' }, 'Workflow actionability');
78
100
  const execution = executionResult.status === 'fulfilled' && isPreview(executionResult.value, taskId)
79
101
  ? { status: 'observed', certainty: 'server_projection', value: executionResult.value }
80
- : unavailable(executionResult.status === 'rejected' ? executionResult.reason : { code: 'TASK_START_PREVIEW_UNSUPPORTED' }, 'Execution preview');
102
+ : unavailable(executionResult.status === 'rejected'
103
+ ? executionResult.reason
104
+ : { code: 'TASK_START_PREVIEW_UNSUPPORTED' }, 'Execution preview');
81
105
  // actionability.revision is the attention revision, not Task.version from
82
106
  // start-preview. Equal numbers would not prove the reads shared a snapshot.
83
107
  const workflowBlocked = workflow.status === 'observed' &&
84
- !workflow.value.actionability.allowedActions.some(action => action.action === 'start_task');
108
+ !workflow.value.actionability.allowedActions.some((action) => action.action === 'start_task');
85
109
  const executionBlocked = execution.status === 'observed' && execution.value.executionAdmission.state === 'blocked';
86
- const summary = workflowBlocked || executionBlocked ? 'blocked'
87
- : workflow.status === 'unavailable' || execution.status === 'unavailable' ||
88
- execution.value.executionAdmission.state !== 'ready' ? 'unknown'
110
+ const summary = workflowBlocked || executionBlocked
111
+ ? 'blocked'
112
+ : workflow.status === 'unavailable' ||
113
+ execution.status === 'unavailable' ||
114
+ execution.value.executionAdmission.state !== 'ready'
115
+ ? 'unknown'
89
116
  : 'eligible_to_attempt';
90
- return { taskId, summary, workflow, execution, consistency: 'independent_observations', limits: [...LIMITS] };
117
+ return {
118
+ taskId,
119
+ summary,
120
+ workflow,
121
+ execution,
122
+ consistency: 'independent_observations',
123
+ limits: [...LIMITS],
124
+ };
91
125
  }
92
126
  function taskPreflightLines(report, bin = 'skrr') {
93
- const lines = [`Task preflight: ${report.taskId}`, `Start eligibility: ${report.summary.replaceAll('_', ' ')} (current server projections)`];
127
+ const lines = [
128
+ `Task preflight: ${report.taskId}`,
129
+ `Start eligibility: ${report.summary.replaceAll('_', ' ')} (current server projections)`,
130
+ ];
94
131
  if (report.workflow.status === 'observed') {
95
132
  const a = report.workflow.value.actionability;
96
133
  lines.push('', `Workflow: ${a.state} (server projection)`, `Next actor: ${a.nextActor}`, `Why: ${a.reason} [${a.reasonCode}]`);
97
134
  if (a.actorRefs?.length)
98
- lines.push(`Eligible actors: ${a.actorRefs.map(ref => `${ref.kind}:${ref.id}`).join(', ')}`);
135
+ lines.push(`Eligible actors: ${a.actorRefs.map((ref) => `${ref.kind}:${ref.id}`).join(', ')}`);
99
136
  for (const action of a.allowedActions) {
100
137
  const command = (0, task_operations_1.taskActionCommand)(action.action, report.taskId, action.targetId, bin, {
101
138
  allowedActions: a.allowedActions,
@@ -116,6 +153,6 @@ function taskPreflightLines(report, bin = 'skrr') {
116
153
  }
117
154
  else
118
155
  lines.push('', `Execution: unknown. ${report.execution.message} [${report.execution.code}]`, `Next step: ${report.execution.remedy}`);
119
- lines.push('', ...report.limits, `More operations: ${bin} tasks guide`);
156
+ lines.push('', ...report.limits, `More operations: ${bin} guide tasks commands`);
120
157
  return lines;
121
158
  }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Account Authorization decides access; a separate server-issued session
3
+ * credential proves Agent authorship. Environment ids are selectors only.
4
+ * Share this across both CLI transports so Task authorship cannot depend on
5
+ * which command happens to use dataService rather than apiFetch.
6
+ */
7
+ export declare function withTaskRuntimeHeaders(headers: Record<string, string>, requestUrl: string, method: string, env?: Record<string, string | undefined>): Record<string, string>;
8
+ /** Custom credentials never follow HTTP redirects, including 302 POST-to-GET. */
9
+ export declare function taskRuntimeRedirectOptions(headers: Record<string, string>): {
10
+ redirect?: 'error';
11
+ };
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.withTaskRuntimeHeaders = withTaskRuntimeHeaders;
4
+ exports.taskRuntimeRedirectOptions = taskRuntimeRedirectOptions;
5
+ /**
6
+ * Account Authorization decides access; a separate server-issued session
7
+ * credential proves Agent authorship. Environment ids are selectors only.
8
+ * Share this across both CLI transports so Task authorship cannot depend on
9
+ * which command happens to use dataService rather than apiFetch.
10
+ */
11
+ function withTaskRuntimeHeaders(headers, requestUrl, method, env = process.env) {
12
+ const sent = { ...headers };
13
+ // A companion credential never travels on a read, another API surface,
14
+ // or a caller-selected header. Preserve existing nonsecret correlation
15
+ // hints outside generic Task mutations for other APIs' provenance checks.
16
+ for (const key of Object.keys(sent)) {
17
+ if (key.toLowerCase() === 'x-oversky-session-authorization')
18
+ delete sent[key];
19
+ }
20
+ if (!['POST', 'PUT', 'PATCH', 'DELETE'].includes(method.toUpperCase()))
21
+ return sent;
22
+ const refuseOrigin = () => Object.assign(new Error('Managed Task requests require their bound server origin; refusing account-attributed fallback.'), {
23
+ code: 'SESSION_TASK_ORIGIN_MISMATCH',
24
+ });
25
+ let target;
26
+ try {
27
+ target = new URL(requestUrl);
28
+ }
29
+ catch {
30
+ if (env.OVERSKY_AUTONOMOUS_SESSION === '1')
31
+ throw refuseOrigin();
32
+ return sent;
33
+ }
34
+ if (!/^\/api\/tasks(?:\/|$)/.test(target.pathname))
35
+ return sent;
36
+ const names = new Set(['x-oversky-agent-id', 'x-oversky-session-id', 'x-oversky-autonomous-run-id']);
37
+ for (const key of Object.keys(sent))
38
+ if (names.has(key.toLowerCase()))
39
+ delete sent[key];
40
+ if (env.OVERSKY_AUTONOMOUS_SESSION !== '1')
41
+ return sent;
42
+ const runId = env.OVERSKY_AUTONOMOUS_RUN_ID?.trim();
43
+ const sessionId = env.OVERSKY_SESSION_ID?.trim();
44
+ const token = env.OVERSKY_SESSION_TOKEN?.trim();
45
+ let trusted;
46
+ try {
47
+ trusted = new URL(env.OVERSKY_SERVER_URL || '');
48
+ }
49
+ catch {
50
+ throw refuseOrigin();
51
+ }
52
+ // The companion credential only travels to the managed runtime's server
53
+ // and only to generic Task mutations. Bound routes use it as Authorization.
54
+ if (target.origin !== trusted.origin)
55
+ throw refuseOrigin();
56
+ if (!sessionId || !token) {
57
+ throw Object.assign(new Error('Managed Task requests require their bound session credential; refusing account-attributed fallback.'), {
58
+ code: 'SESSION_TASK_CREDENTIAL_MISSING',
59
+ });
60
+ }
61
+ if (runId)
62
+ sent['X-Oversky-Autonomous-Run-Id'] = runId;
63
+ sent['X-Oversky-Session-Id'] = sessionId;
64
+ sent['X-Oversky-Session-Authorization'] = `Bearer ${token}`;
65
+ const agentId = env.OVERSKY_SESSION_AGENT_ID?.trim();
66
+ if (agentId)
67
+ sent['X-Oversky-Agent-Id'] = agentId;
68
+ return sent;
69
+ }
70
+ /** Custom credentials never follow HTTP redirects, including 302 POST-to-GET. */
71
+ function taskRuntimeRedirectOptions(headers) {
72
+ return headers['X-Oversky-Session-Authorization'] ? { redirect: 'error' } : {};
73
+ }
@@ -4,7 +4,7 @@ exports.ACCOUNT_ATTRIBUTION_NOTICE = exports.AGENT_BINDING_GUIDANCE = void 0;
4
4
  exports.taskWriteAttribution = taskWriteAttribution;
5
5
  exports.attributionLines = attributionLines;
6
6
  exports.runtimeWriteAttribution = runtimeWriteAttribution;
7
- exports.AGENT_BINDING_GUIDANCE = 'Assign this runtime in skrr → Engines, then run in its authenticated Agent session. ' +
7
+ exports.AGENT_BINDING_GUIDANCE = 'Run `skrr tasks start <task>` to execute in the assigned Agent’s authenticated runtime. ' +
8
8
  'An --agent flag or an environment Agent id cannot establish authenticated authorship.';
9
9
  exports.ACCOUNT_ATTRIBUTION_NOTICE = 'Without authenticated Agent provenance, Task writes are attributed to the signed-in account. ' +
10
10
  'An account-attributed assessment is not proof of an independent human check.';
@@ -33,6 +33,10 @@ export declare const USAGE_OVERVIEW_TOKEN_BUDGET = 240;
33
33
  * `skrr widgets check`, and the app runs in the same frame. Its own overview line took the first read from 240 to 241
34
34
  * tokens, and this file's rule for that is to fold into a domain that already has the concept, not to raise the bound.
35
35
  * `skrr usage apps` still resolves, to the `widgets` pages, which name it in `Includes:`.
36
+ * `instruction-blocks` (version-pinned instruction blocks for cloud Agents) is the same concept as
37
+ * `instructions` (version-pinned blocks for local CLAUDE.md / AGENTS.md), aimed at another target. The overview
38
+ * read 245 once `skrr guide` joined it, and `guide` stays a line of its own because it is where every operation
39
+ * guide is read.
36
40
  */
37
41
  export declare const USAGE_DOMAIN_FOLDS: Readonly<Record<string, string>>;
38
42
  export declare const USAGE_DOMAIN_TOKEN_BUDGET = 500;
@@ -44,10 +44,15 @@ exports.USAGE_OVERVIEW_TOKEN_BUDGET = 240;
44
44
  * `skrr widgets check`, and the app runs in the same frame. Its own overview line took the first read from 240 to 241
45
45
  * tokens, and this file's rule for that is to fold into a domain that already has the concept, not to raise the bound.
46
46
  * `skrr usage apps` still resolves, to the `widgets` pages, which name it in `Includes:`.
47
+ * `instruction-blocks` (version-pinned instruction blocks for cloud Agents) is the same concept as
48
+ * `instructions` (version-pinned blocks for local CLAUDE.md / AGENTS.md), aimed at another target. The overview
49
+ * read 245 once `skrr guide` joined it, and `guide` stays a line of its own because it is where every operation
50
+ * guide is read.
47
51
  */
48
52
  exports.USAGE_DOMAIN_FOLDS = {
49
53
  proposals: 'inbox',
50
54
  apps: 'widgets',
55
+ 'instruction-blocks': 'instructions',
51
56
  };
52
57
  exports.USAGE_DOMAIN_TOKEN_BUDGET = 500;
53
58
  const GENERIC_FLAGS = new Set(['bare', 'help', 'json', 'token', 'workspace']);
@@ -7,3 +7,30 @@
7
7
  * Returns null for anything that is not a positive amount with ≤ 2 decimals.
8
8
  */
9
9
  export declare function usdToMicros(amount: string): number | null;
10
+ /**
11
+ * The same parse, but "0" is a price too: `--expected-price 0` pins free.
12
+ * Returns null for anything that is not an amount with ≤ 2 decimals.
13
+ */
14
+ export declare function usdToMicrosOrZero(amount: string): number | null;
15
+ /**
16
+ * `--expected-price` as micros: `undefined` when the flag was not passed,
17
+ * `null` when the value is not a USD amount.
18
+ */
19
+ export declare function expectedPriceFlagMicros(value: string | undefined): number | null | undefined;
20
+ /**
21
+ * The refusal text when `--expected-price` does not match what a paid
22
+ * install would now charge — one wording for every install command so the
23
+ * pin reads the same whichever listing it guarded (OSK-18256).
24
+ */
25
+ export declare function expectedPriceMismatchMessage(expectedMicros: number, chargeMicros: number): string;
26
+ /**
27
+ * A `--json` payload with every unstated-unit store price restated in
28
+ * dollars: a numeric `price`, `listPrice` or `charge` (integer micro-USD,
29
+ * the one unit store prices travel the wire in — see `storePricing.ts` in
30
+ * `@skrr-ai/data-provider`) gains a sibling `<name>Usd` in dollars, so a
31
+ * reader never has to know the conversion (OSK-18256). Fields that already
32
+ * name their unit (`amountMicros`, `*Micros`) and anything that is not a
33
+ * finite number pass through untouched; the wire fields themselves keep
34
+ * their values.
35
+ */
36
+ export declare function withUsdPrices<T>(payload: T): T;
@@ -1,6 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.usdToMicros = usdToMicros;
4
+ exports.usdToMicrosOrZero = usdToMicrosOrZero;
5
+ exports.expectedPriceFlagMicros = expectedPriceFlagMicros;
6
+ exports.expectedPriceMismatchMessage = expectedPriceMismatchMessage;
7
+ exports.withUsdPrices = withUsdPrices;
8
+ const data_provider_1 = require("@skrr-ai/data-provider");
4
9
  /**
5
10
  * Parse a user-typed USD amount ("5", "2.50") into integer micros.
6
11
  *
@@ -10,12 +15,72 @@ exports.usdToMicros = usdToMicros;
10
15
  * Returns null for anything that is not a positive amount with ≤ 2 decimals.
11
16
  */
12
17
  function usdToMicros(amount) {
18
+ const cents = parseUsdCents(amount);
19
+ if (cents === null || cents <= 0)
20
+ return null;
21
+ return cents * 10_000;
22
+ }
23
+ /**
24
+ * The same parse, but "0" is a price too: `--expected-price 0` pins free.
25
+ * Returns null for anything that is not an amount with ≤ 2 decimals.
26
+ */
27
+ function usdToMicrosOrZero(amount) {
28
+ const cents = parseUsdCents(amount);
29
+ return cents === null ? null : cents * 10_000;
30
+ }
31
+ function parseUsdCents(amount) {
13
32
  const trimmed = amount.trim();
14
33
  if (!/^\d+(\.\d{1,2})?$/.test(trimmed))
15
34
  return null;
16
35
  const [whole, frac = ''] = trimmed.split('.');
17
36
  const cents = Number(whole) * 100 + Number(frac.padEnd(2, '0'));
18
- if (!Number.isSafeInteger(cents) || cents <= 0)
37
+ // cents * 10_000 must stay an exact integer micros value.
38
+ if (!Number.isSafeInteger(cents) || cents > Number.MAX_SAFE_INTEGER / 10_000)
19
39
  return null;
20
- return cents * 10_000;
40
+ return cents;
41
+ }
42
+ /**
43
+ * `--expected-price` as micros: `undefined` when the flag was not passed,
44
+ * `null` when the value is not a USD amount.
45
+ */
46
+ function expectedPriceFlagMicros(value) {
47
+ return value === undefined ? undefined : usdToMicrosOrZero(value);
48
+ }
49
+ /**
50
+ * The refusal text when `--expected-price` does not match what a paid
51
+ * install would now charge — one wording for every install command so the
52
+ * pin reads the same whichever listing it guarded (OSK-18256).
53
+ */
54
+ function expectedPriceMismatchMessage(expectedMicros, chargeMicros) {
55
+ return (`--expected-price ${(0, data_provider_1.formatStoreAcquisitionPrice)(expectedMicros)} does not match the price ` +
56
+ `the listing now charges (${(0, data_provider_1.formatStoreAcquisitionPrice)(chargeMicros)}). ` +
57
+ 'Nothing was installed — read the price again and ask the person before buying.');
58
+ }
59
+ /** Fields that carry a store price in integer micro-USD without saying so. */
60
+ const MICROS_PRICE_FIELDS = new Set(['price', 'listPrice', 'charge']);
61
+ /**
62
+ * A `--json` payload with every unstated-unit store price restated in
63
+ * dollars: a numeric `price`, `listPrice` or `charge` (integer micro-USD,
64
+ * the one unit store prices travel the wire in — see `storePricing.ts` in
65
+ * `@skrr-ai/data-provider`) gains a sibling `<name>Usd` in dollars, so a
66
+ * reader never has to know the conversion (OSK-18256). Fields that already
67
+ * name their unit (`amountMicros`, `*Micros`) and anything that is not a
68
+ * finite number pass through untouched; the wire fields themselves keep
69
+ * their values.
70
+ */
71
+ function withUsdPrices(payload) {
72
+ if (Array.isArray(payload)) {
73
+ return payload.map((item) => withUsdPrices(item));
74
+ }
75
+ if (payload === null || typeof payload !== 'object') {
76
+ return payload;
77
+ }
78
+ const out = {};
79
+ for (const [key, value] of Object.entries(payload)) {
80
+ out[key] = withUsdPrices(value);
81
+ if (MICROS_PRICE_FIELDS.has(key) && typeof value === 'number' && Number.isFinite(value)) {
82
+ out[`${key}Usd`] = (0, data_provider_1.listingPriceMicrosToUsd)(value);
83
+ }
84
+ }
85
+ return out;
21
86
  }
@@ -74,9 +74,11 @@ function readVoiceCallSessionContext(env = process.env) {
74
74
  };
75
75
  }
76
76
  function generatedVoiceCallIdempotencyKey({ context, reason, conversationId, expiresInSeconds, }) {
77
+ if (!context.requestId)
78
+ return `voice-call:${crypto.randomUUID()}`;
77
79
  const input = [
78
80
  context.sessionId,
79
- context.requestId || 'no-request-id',
81
+ context.requestId,
80
82
  context.agentId,
81
83
  reason,
82
84
  conversationId || '',
@@ -30,3 +30,20 @@ export interface HarnessPermissionControlReport {
30
30
  * rather than a green badge. Additive fields are stripped for compatibility.
31
31
  */
32
32
  export declare function parseHarnessPermissionControls(value: unknown): HarnessPermissionControls | null;
33
+ /** Last-reported local configuration and adapter protocol, never authority. */
34
+ export interface HarnessSessionPolicyReport {
35
+ version: 1;
36
+ configuredDefault: {
37
+ provider: 'claude';
38
+ engine: 'sdk' | 'cli';
39
+ permissionMode: 'default' | 'acceptEdits' | 'plan' | 'bypassPermissions';
40
+ } | null;
41
+ taskCommandApproval: {
42
+ protocol: 'task_command_once_v1';
43
+ adapters: readonly {
44
+ provider: 'claude';
45
+ engine: 'sdk';
46
+ }[];
47
+ } | null;
48
+ }
49
+ export declare function parseHarnessSessionPolicyReport(value: unknown): HarnessSessionPolicyReport | null;
@@ -18,7 +18,8 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var harnessPermissionControls_exports = {};
20
20
  __export(harnessPermissionControls_exports, {
21
- parseHarnessPermissionControls: () => parseHarnessPermissionControls
21
+ parseHarnessPermissionControls: () => parseHarnessPermissionControls,
22
+ parseHarnessSessionPolicyReport: () => parseHarnessSessionPolicyReport
22
23
  });
23
24
  module.exports = __toCommonJS(harnessPermissionControls_exports);
24
25
  const PLAN = ["harness", "reported-actions", "unsupported", "unknown"];
@@ -63,7 +64,39 @@ function parseHarnessPermissionControls(value) {
63
64
  return null;
64
65
  }
65
66
  }
67
+ function parseHarnessSessionPolicyReport(value) {
68
+ try {
69
+ if (!value || typeof value !== "object" || Array.isArray(value))
70
+ return null;
71
+ const row = value;
72
+ if (row.version !== 1)
73
+ return null;
74
+ let configuredDefault = null;
75
+ let taskCommandApproval = null;
76
+ const config = row.configuredDefault;
77
+ if (config && typeof config === "object" && !Array.isArray(config) && config.provider === "claude" && ["sdk", "cli"].includes(config.engine) && ["default", "acceptEdits", "plan", "bypassPermissions"].includes(config.permissionMode)) {
78
+ configuredDefault = Object.freeze({
79
+ provider: "claude",
80
+ engine: config.engine,
81
+ permissionMode: config.permissionMode
82
+ });
83
+ }
84
+ const approval = row.taskCommandApproval;
85
+ if (approval && typeof approval === "object" && !Array.isArray(approval) && approval.protocol === "task_command_once_v1" && Array.isArray(approval.adapters) && approval.adapters.length === 1 && approval.adapters[0]?.provider === "claude" && approval.adapters[0]?.engine === "sdk") {
86
+ taskCommandApproval = Object.freeze({
87
+ protocol: "task_command_once_v1",
88
+ adapters: Object.freeze([
89
+ Object.freeze({ provider: "claude", engine: "sdk" })
90
+ ])
91
+ });
92
+ }
93
+ return Object.freeze({ version: 1, configuredDefault, taskCommandApproval });
94
+ } catch {
95
+ return null;
96
+ }
97
+ }
66
98
  // Annotate the CommonJS export names for ESM import in node:
67
99
  0 && (module.exports = {
68
- parseHarnessPermissionControls
100
+ parseHarnessPermissionControls,
101
+ parseHarnessSessionPolicyReport
69
102
  });
@@ -30,3 +30,20 @@ export interface HarnessPermissionControlReport {
30
30
  * rather than a green badge. Additive fields are stripped for compatibility.
31
31
  */
32
32
  export declare function parseHarnessPermissionControls(value: unknown): HarnessPermissionControls | null;
33
+ /** Last-reported local configuration and adapter protocol, never authority. */
34
+ export interface HarnessSessionPolicyReport {
35
+ version: 1;
36
+ configuredDefault: {
37
+ provider: 'claude';
38
+ engine: 'sdk' | 'cli';
39
+ permissionMode: 'default' | 'acceptEdits' | 'plan' | 'bypassPermissions';
40
+ } | null;
41
+ taskCommandApproval: {
42
+ protocol: 'task_command_once_v1';
43
+ adapters: readonly {
44
+ provider: 'claude';
45
+ engine: 'sdk';
46
+ }[];
47
+ } | null;
48
+ }
49
+ export declare function parseHarnessSessionPolicyReport(value: unknown): HarnessSessionPolicyReport | null;