@skrr-ai/cli 0.1.127 → 0.1.129
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/base-command.d.ts +35 -0
- package/dist/base-command.js +107 -0
- package/dist/commands/agenda/trigger/list.d.ts +2 -1
- package/dist/commands/agenda/trigger/list.js +55 -6
- package/dist/commands/agents/chat.js +7 -0
- package/dist/commands/agents/create.js +3 -1
- package/dist/commands/browser/persistent-profile.d.ts +22 -0
- package/dist/commands/browser/persistent-profile.js +46 -0
- package/dist/commands/commitments/action-history.js +1 -1
- package/dist/commands/commitments/cases.js +3 -3
- package/dist/commands/commitments/check-now.d.ts +10 -2
- package/dist/commands/commitments/check-now.js +53 -3
- package/dist/commands/commitments/create.d.ts +6 -14
- package/dist/commands/commitments/create.js +64 -7
- package/dist/commands/commitments/doctor.js +3 -1
- package/dist/commands/commitments/effective-policy.d.ts +11 -1
- package/dist/commands/commitments/effective-policy.js +90 -4
- package/dist/commands/commitments/explain.js +10 -1
- package/dist/commands/commitments/hypotheses.js +12 -12
- package/dist/commands/commitments/next-tick.js +5 -0
- package/dist/commands/commitments/observations.js +18 -17
- package/dist/commands/commitments/pack/list.js +2 -1
- package/dist/commands/commitments/pack/plan.d.ts +6 -0
- package/dist/commands/commitments/pack/plan.js +19 -0
- package/dist/commands/commitments/plan.d.ts +14 -0
- package/dist/commands/commitments/plan.js +32 -0
- package/dist/commands/commitments/preflight.d.ts +20 -1
- package/dist/commands/commitments/preflight.js +118 -12
- package/dist/commands/commitments/show.d.ts +9 -0
- package/dist/commands/commitments/show.js +14 -1
- package/dist/commands/commitments/trigger-status.js +8 -0
- package/dist/commands/commitments/update.d.ts +1 -0
- package/dist/commands/commitments/update.js +45 -4
- package/dist/commands/commitments/wake-capabilities.js +13 -0
- package/dist/commands/compass/archive.js +4 -0
- package/dist/commands/compass/commitments.js +15 -1
- package/dist/commands/compass/create.js +11 -3
- package/dist/commands/compass/effective-policy.d.ts +1 -0
- package/dist/commands/compass/effective-policy.js +8 -7
- package/dist/commands/compass/revert.d.ts +8 -0
- package/dist/commands/compass/revert.js +25 -1
- package/dist/commands/compass/revisions.d.ts +6 -0
- package/dist/commands/compass/revisions.js +26 -2
- package/dist/commands/compass/tactic.d.ts +10 -3
- package/dist/commands/compass/tactic.js +22 -7
- package/dist/commands/compass/update.js +19 -3
- package/dist/commands/followups/act.js +1 -1
- package/dist/commands/followups/cancel.js +13 -0
- package/dist/commands/followups/observability.js +20 -1
- package/dist/commands/followups/plans/create.js +12 -1
- package/dist/commands/followups/show.js +13 -0
- package/dist/commands/followups/watch.js +1 -1
- package/dist/commands/goals/planner-config.d.ts +11 -0
- package/dist/commands/goals/planner-config.js +16 -0
- package/dist/commands/harnesses/list.js +1 -1
- package/dist/commands/machines/update.d.ts +5 -3
- package/dist/commands/machines/update.js +70 -9
- package/dist/commands/northstars/create.js +3 -1
- package/dist/commands/northstars/governance/configure.d.ts +4 -0
- package/dist/commands/northstars/governance/configure.js +76 -10
- package/dist/commands/northstars/intents/decide.d.ts +6 -0
- package/dist/commands/northstars/intents/decide.js +68 -15
- package/dist/commands/northstars/intents/list.d.ts +2 -1
- package/dist/commands/northstars/intents/list.js +15 -5
- package/dist/commands/northstars/intents.d.ts +26 -0
- package/dist/commands/northstars/intents.js +49 -0
- package/dist/commands/northstars/list.d.ts +1 -0
- package/dist/commands/northstars/list.js +24 -3
- package/dist/commands/northstars/recommendations/list.d.ts +1 -1
- package/dist/commands/northstars/recommendations/list.js +3 -3
- package/dist/commands/northstars/recommendations.d.ts +19 -0
- package/dist/commands/northstars/recommendations.js +42 -0
- package/dist/commands/northstars/review-now.d.ts +1 -0
- package/dist/commands/northstars/review-now.js +15 -4
- package/dist/commands/northstars/reviews.d.ts +1 -0
- package/dist/commands/northstars/reviews.js +34 -6
- package/dist/commands/northstars/update.js +8 -1
- package/dist/commands/proposals/list.js +11 -2
- package/dist/commands/proposals/show.js +9 -1
- package/dist/commands/spaces/auto-executor/preview.d.ts +14 -1
- package/dist/commands/spaces/auto-executor/preview.js +35 -1
- package/dist/commands/spaces/auto-executor/run.d.ts +17 -0
- package/dist/commands/spaces/auto-executor/run.js +60 -2
- package/dist/commands/spaces/auto-executor/runs.d.ts +9 -1
- package/dist/commands/spaces/auto-executor/runs.js +18 -1
- package/dist/commands/spaces/files/upload.js +1 -2
- package/dist/commands/spaces/heartbeats/create.js +7 -5
- package/dist/commands/spaces/heartbeats/update.js +5 -3
- package/dist/commands/spaces/index.js +23 -0
- package/dist/commands/store/artifacts/releases.d.ts +20 -0
- package/dist/commands/store/artifacts/releases.js +85 -0
- package/dist/commands/store/library.d.ts +14 -0
- package/dist/commands/store/library.js +71 -0
- package/dist/commands/tasks/list.d.ts +48 -0
- package/dist/commands/tasks/list.js +141 -9
- package/dist/commands/tasks/remind.js +23 -11
- package/dist/commands/tasks/retry-schedule.js +6 -3
- package/dist/commands/tasks/schedule.js +29 -7
- package/dist/commands/tasks/show.js +4 -0
- package/dist/generated/agent-guides.json +69 -69
- package/dist/lib/agent-trigger-listing.d.ts +26 -0
- package/dist/lib/agent-trigger-listing.js +63 -0
- package/dist/lib/agentic-stream.d.ts +9 -0
- package/dist/lib/agentic-stream.js +152 -41
- package/dist/lib/command-miss.js +11 -2
- package/dist/lib/commitment-attention-copy.d.ts +96 -0
- package/dist/lib/commitment-attention-copy.js +209 -0
- package/dist/lib/commitment-ledgers.js +3 -1
- package/dist/lib/commitment-loop-status.d.ts +6 -0
- package/dist/lib/commitment-loop-status.js +16 -6
- package/dist/lib/commitments.d.ts +112 -0
- package/dist/lib/commitments.js +250 -2
- package/dist/lib/compass-body-help.d.ts +20 -0
- package/dist/lib/compass-body-help.js +61 -0
- package/dist/lib/compass-refusals.d.ts +35 -0
- package/dist/lib/compass-refusals.js +50 -0
- package/dist/lib/compasses.d.ts +82 -4
- package/dist/lib/compasses.js +232 -12
- package/dist/lib/followups.d.ts +22 -1
- package/dist/lib/followups.js +21 -1
- package/dist/lib/format.d.ts +11 -0
- package/dist/lib/format.js +29 -0
- package/dist/lib/initiatives.d.ts +9 -2
- package/dist/lib/initiatives.js +13 -2
- package/dist/lib/iso-instant.d.ts +52 -0
- package/dist/lib/iso-instant.js +162 -0
- package/dist/lib/machines.d.ts +14 -1
- package/dist/lib/machines.js +24 -0
- package/dist/lib/northstars.d.ts +201 -24
- package/dist/lib/northstars.js +655 -27
- package/dist/lib/proposal-decision-command.js +21 -1
- package/dist/lib/proposals.d.ts +26 -1
- package/dist/lib/proposals.js +167 -0
- package/dist/lib/rate-limit-retry.d.ts +5 -0
- package/dist/lib/rate-limit-retry.js +19 -0
- package/dist/lib/roles.d.ts +1 -1
- package/dist/lib/space-charter.js +9 -0
- package/dist/lib/store-artifact-releases.d.ts +39 -0
- package/dist/lib/store-artifact-releases.js +12 -0
- package/dist/lib/store-library.d.ts +37 -0
- package/dist/lib/store-library.js +12 -0
- package/dist/lib/task-asset-upload.js +1 -2
- package/dist/lib/task-calendar.d.ts +19 -0
- package/dist/lib/task-calendar.js +72 -0
- package/dist/lib/task-recurrence-outcome.js +3 -1
- package/dist/lib/task-recurrence-summary.d.ts +15 -0
- package/dist/lib/task-recurrence-summary.js +228 -0
- package/dist/lib/task-reminder.d.ts +28 -0
- package/dist/lib/task-reminder.js +50 -0
- package/dist/lib/triggers.d.ts +13 -2
- package/dist/lib/triggers.js +31 -13
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonWire.js +11 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/executorStopReceipt.d.ts +123 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/executorStopReceipt.js +160 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +1 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +17 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonWire.js +11 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/executorStopReceipt.d.ts +123 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/executorStopReceipt.js +173 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +1 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +2 -0
- package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +6922 -6828
- package/oclif.manifest.json +612 -62
- package/package.json +4 -4
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* `skrr agenda trigger list <agent>` and the triggers it did not show (OSK-21454).
|
|
4
|
+
*
|
|
5
|
+
* `/api/agents/:id/triggers` is the legacy per-agent facade and lists `scope: 'agent'` rows only. A
|
|
6
|
+
* passive agent (`agents create --initial-always-on off`) still owns system-managed Commitment
|
|
7
|
+
* triggers - the daily self-reflection check is `commitment-check:obj_agent_reflection_*`, scope
|
|
8
|
+
* `commitment_watcher` - so the one command whose name says "list this agent's triggers" answered
|
|
9
|
+
* "No triggers." while `triggers list --ref-entity agent:<id>` and the web Upcoming page listed it.
|
|
10
|
+
*
|
|
11
|
+
* The universal list, filtered by the agent ref, is the truth; this reads it and returns the rows the
|
|
12
|
+
* facade left out, marked so a person can tell the platform's from their own.
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.isSystemManaged = isSystemManaged;
|
|
16
|
+
exports.triggersMissingFromAgentList = triggersMissingFromAgentList;
|
|
17
|
+
exports.isSuspended = isSuspended;
|
|
18
|
+
exports.sourceLabel = sourceLabel;
|
|
19
|
+
exports.systemManagedLegend = systemManagedLegend;
|
|
20
|
+
function idOf(row) {
|
|
21
|
+
return typeof row.id === 'string' ? row.id : '';
|
|
22
|
+
}
|
|
23
|
+
function scopeKindOf(row) {
|
|
24
|
+
const scope = row.scope;
|
|
25
|
+
return typeof scope?.kind === 'string' ? scope.kind : '';
|
|
26
|
+
}
|
|
27
|
+
/** Created and run by the platform for a Commitment, not authored by the person. */
|
|
28
|
+
function isSystemManaged(row) {
|
|
29
|
+
return row.producerOwned === true || /^commitment-(check|reflect):/.test(idOf(row));
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The universal-list rows the per-agent facade did not return, each tagged `systemManaged`.
|
|
33
|
+
* Rows already listed are not repeated; a row with no id cannot be matched and is kept.
|
|
34
|
+
*/
|
|
35
|
+
function triggersMissingFromAgentList(listed, universal) {
|
|
36
|
+
const known = new Set(listed.map(idOf).filter(Boolean));
|
|
37
|
+
return universal
|
|
38
|
+
.filter((row) => !idOf(row) || !known.has(idOf(row)))
|
|
39
|
+
.map((row) => ({ ...row, systemManaged: isSystemManaged(row) }));
|
|
40
|
+
}
|
|
41
|
+
/** The platform marked this managed trigger suspended (Always-On is off for the agent). */
|
|
42
|
+
function isSuspended(row) {
|
|
43
|
+
const management = row.management;
|
|
44
|
+
return management?.suspended === true;
|
|
45
|
+
}
|
|
46
|
+
/** What the SOURCE column says: the platform, the scope it belongs to, a turn capture, or nothing. */
|
|
47
|
+
function sourceLabel(row, unconfirmedTurnCapture) {
|
|
48
|
+
if (row.systemManaged === true)
|
|
49
|
+
return isSuspended(row) ? 'system, suspended' : 'system';
|
|
50
|
+
if (unconfirmedTurnCapture)
|
|
51
|
+
return 'turn*';
|
|
52
|
+
if (row.systemManaged === false)
|
|
53
|
+
return scopeKindOf(row) || '-';
|
|
54
|
+
return '-';
|
|
55
|
+
}
|
|
56
|
+
/** The legend printed under a table that includes platform-managed rows. */
|
|
57
|
+
function systemManagedLegend(agentId, bin = 'skrr') {
|
|
58
|
+
return [
|
|
59
|
+
'system = created and run by the platform for a Commitment, not by you (for example the daily self-reflection check every agent is seeded with, passive or not).',
|
|
60
|
+
' "suspended" = the platform is holding it because Always-On is off for this agent.',
|
|
61
|
+
` Find the Commitment behind one with: ${bin} commitments list --agent ${agentId} --include-system`,
|
|
62
|
+
];
|
|
63
|
+
}
|
|
@@ -47,6 +47,14 @@ export type AgenticStreamResult = {
|
|
|
47
47
|
* (OSK-13543). Absent on every ordinary run.
|
|
48
48
|
*/
|
|
49
49
|
repaired?: true;
|
|
50
|
+
/**
|
|
51
|
+
* Tool calls refused because nobody could be asked and the run was not started with
|
|
52
|
+
* `--approve-tools`, as the same one-line description the streamed `[permission]` line uses.
|
|
53
|
+
* A quiet run discards the rendering, so without this a `--no-stream --json` turn read as a
|
|
54
|
+
* completed turn that did nothing, beside an agent telling the person to resend from another
|
|
55
|
+
* surface (which a CLI cannot offer). Absent when nothing was refused.
|
|
56
|
+
*/
|
|
57
|
+
permissionDenials?: string[];
|
|
50
58
|
lastEvent?: AgenticStreamEvent;
|
|
51
59
|
};
|
|
52
60
|
/**
|
|
@@ -605,6 +613,7 @@ export declare class AgenticStreamClient {
|
|
|
605
613
|
private readonly openQuestionPrompts;
|
|
606
614
|
/** Text already written to the terminal, for suffix-only rendering. */
|
|
607
615
|
private renderedText;
|
|
616
|
+
private permissionDenials;
|
|
608
617
|
/** The "still waiting" line for a terminal run with no output yet (OSK-20427). */
|
|
609
618
|
private waitingTimer;
|
|
610
619
|
private waitingStartedAt;
|
|
@@ -206,7 +206,10 @@ async function discardTypeAhead(input, windowMs = exports.TYPE_AHEAD_DISCARD_MS)
|
|
|
206
206
|
process.kill(process.pid, 'SIGINT');
|
|
207
207
|
}
|
|
208
208
|
const permissionGeneration = (event) => JSON.stringify([
|
|
209
|
-
event.sessionId,
|
|
209
|
+
event.sessionId,
|
|
210
|
+
event.toolUseId,
|
|
211
|
+
event.permissionBinding?.epoch,
|
|
212
|
+
event.permissionBinding?.requestId,
|
|
210
213
|
]);
|
|
211
214
|
const PERMISSION_DETAIL_MAX = 400;
|
|
212
215
|
/**
|
|
@@ -855,6 +858,7 @@ class AgenticStreamClient {
|
|
|
855
858
|
openQuestionPrompts = new Map();
|
|
856
859
|
/** Text already written to the terminal, for suffix-only rendering. */
|
|
857
860
|
renderedText = '';
|
|
861
|
+
permissionDenials = [];
|
|
858
862
|
/** The "still waiting" line for a terminal run with no output yet (OSK-20427). */
|
|
859
863
|
waitingTimer = null;
|
|
860
864
|
waitingStartedAt = 0;
|
|
@@ -1522,7 +1526,8 @@ class AgenticStreamClient {
|
|
|
1522
1526
|
return; // a pure re-delivery — drop it whole
|
|
1523
1527
|
const scoped = { ...event, envelopes: fresh };
|
|
1524
1528
|
if (fresh.some((env) => env?.ev?.t === 'text' &&
|
|
1525
|
-
env.ev?.publicProjection ===
|
|
1529
|
+
env.ev?.publicProjection ===
|
|
1530
|
+
'lookback_answer_v1'))
|
|
1526
1531
|
this.publicProjection = 'lookback_answer_v1';
|
|
1527
1532
|
// Note what never arrived before folding this batch in (OSK-7631,
|
|
1528
1533
|
// OSK-13518). Checked against the FRESH set: a re-delivery carries old
|
|
@@ -1686,7 +1691,8 @@ class AgenticStreamClient {
|
|
|
1686
1691
|
socket.on('execution:aborted', (event) => {
|
|
1687
1692
|
if (!match(event))
|
|
1688
1693
|
return;
|
|
1689
|
-
if (typeof event.permissionEpoch === 'string' &&
|
|
1694
|
+
if (typeof event.permissionEpoch === 'string' &&
|
|
1695
|
+
this.permissionEpochs.has(this.options.sessionId) &&
|
|
1690
1696
|
this.permissionEpochs.get(this.options.sessionId) !== event.permissionEpoch)
|
|
1691
1697
|
return;
|
|
1692
1698
|
if (this.handover)
|
|
@@ -1697,7 +1703,8 @@ class AgenticStreamClient {
|
|
|
1697
1703
|
socket.on('execution:cancelled', (event) => {
|
|
1698
1704
|
if (!match(event))
|
|
1699
1705
|
return;
|
|
1700
|
-
if (typeof event.permissionEpoch === 'string' &&
|
|
1706
|
+
if (typeof event.permissionEpoch === 'string' &&
|
|
1707
|
+
this.permissionEpochs.has(this.options.sessionId) &&
|
|
1701
1708
|
this.permissionEpochs.get(this.options.sessionId) !== event.permissionEpoch)
|
|
1702
1709
|
return;
|
|
1703
1710
|
if (this.handover)
|
|
@@ -1730,7 +1737,10 @@ class AgenticStreamClient {
|
|
|
1730
1737
|
return;
|
|
1731
1738
|
if (event.toolUseId) {
|
|
1732
1739
|
this.openPermissionPrompts.get(event.toolUseId)?.abort();
|
|
1733
|
-
this.permissionGenerations.set(event.toolUseId, {
|
|
1740
|
+
this.permissionGenerations.set(event.toolUseId, {
|
|
1741
|
+
key: permissionGeneration(event),
|
|
1742
|
+
bound: !!event.permissionBinding,
|
|
1743
|
+
});
|
|
1734
1744
|
if (event.permissionBinding)
|
|
1735
1745
|
this.permissionEpochs.set(this.options.sessionId, event.permissionBinding.epoch);
|
|
1736
1746
|
}
|
|
@@ -1764,21 +1774,27 @@ class AgenticStreamClient {
|
|
|
1764
1774
|
// Runtime-authored application consent is exclusively an interactive app
|
|
1765
1775
|
// decision. A TTY or --approve-tools is not that authenticated human lane.
|
|
1766
1776
|
// Recognize malformed runtime asks too, so they never fall into generic grants.
|
|
1767
|
-
if (event.purpose === 'runtime-elicitation' ||
|
|
1777
|
+
if (event.purpose === 'runtime-elicitation' ||
|
|
1778
|
+
event.runtimeElicitation !== undefined ||
|
|
1779
|
+
event.toolName === 'ComputerUse') {
|
|
1768
1780
|
let message = 'This Computer Use request cannot be verified. Wait for a new request in the app.';
|
|
1769
1781
|
let requestValid = false;
|
|
1770
1782
|
try {
|
|
1771
1783
|
const runtime = event.runtimeElicitation;
|
|
1772
1784
|
(0, computer_use_1.assertComputerUseElicitationRequest)(runtime);
|
|
1773
|
-
if (event.purpose !== 'runtime-elicitation' ||
|
|
1774
|
-
event.
|
|
1785
|
+
if (event.purpose !== 'runtime-elicitation' ||
|
|
1786
|
+
event.toolName !== 'ComputerUse' ||
|
|
1787
|
+
event.toolUseId !== runtime.requestId ||
|
|
1788
|
+
runtime.context.sessionId !== this.options.sessionId ||
|
|
1775
1789
|
runtime.expiresAt <= Date.now())
|
|
1776
1790
|
throw new Error('Mismatched runtime permission');
|
|
1777
1791
|
const display = (text) => describePermissionTarget({ command: text }) ?? '';
|
|
1778
|
-
message = [
|
|
1792
|
+
message = [
|
|
1793
|
+
display(runtime.message),
|
|
1779
1794
|
`Choices in the app: ${runtime.options.map((option) => display(option.label)).join(' | ')}`,
|
|
1780
1795
|
`Expires: ${new Date(runtime.expiresAt).toISOString()}`,
|
|
1781
|
-
'Answer in the signed-in app. This CLI cannot grant or decline application access.'
|
|
1796
|
+
'Answer in the signed-in app. This CLI cannot grant or decline application access.',
|
|
1797
|
+
].join('\n');
|
|
1782
1798
|
requestValid = true;
|
|
1783
1799
|
}
|
|
1784
1800
|
catch {
|
|
@@ -1790,10 +1806,17 @@ class AgenticStreamClient {
|
|
|
1790
1806
|
if (approvalUrl)
|
|
1791
1807
|
message += `\nOpen ${approvalUrl} and choose Review pending decisions.`;
|
|
1792
1808
|
else
|
|
1793
|
-
message +=
|
|
1809
|
+
message +=
|
|
1810
|
+
'\nOpen this conversation in the signed-in app and choose Review pending decisions.';
|
|
1794
1811
|
if (event.toolUseId)
|
|
1795
1812
|
this.browserPermissionRequests.add(event.toolUseId);
|
|
1796
|
-
this.emit({
|
|
1813
|
+
this.emit({
|
|
1814
|
+
...event,
|
|
1815
|
+
type: 'permission.browser_required',
|
|
1816
|
+
requestValid,
|
|
1817
|
+
approvalUrl,
|
|
1818
|
+
message,
|
|
1819
|
+
});
|
|
1797
1820
|
return;
|
|
1798
1821
|
}
|
|
1799
1822
|
if (!this.options.approveTools || !this.socket) {
|
|
@@ -1802,7 +1825,10 @@ class AgenticStreamClient {
|
|
|
1802
1825
|
// response was admitted. Tool execution is not confirmed.", which read like an approval.
|
|
1803
1826
|
this.emit({ ...event, type: 'permission.denied', reason: 'noninteractive_or_not_enabled' });
|
|
1804
1827
|
if (event.toolUseId) {
|
|
1805
|
-
if (await this.sendBoundPermissionDecision(event, false, {
|
|
1828
|
+
if (await this.sendBoundPermissionDecision(event, false, {
|
|
1829
|
+
reason: 'CLI was not started with --approve-tools',
|
|
1830
|
+
automatic: true,
|
|
1831
|
+
}))
|
|
1806
1832
|
return;
|
|
1807
1833
|
this.socket?.emit('permission:deny', {
|
|
1808
1834
|
sessionId: this.options.sessionId,
|
|
@@ -1876,14 +1902,22 @@ class AgenticStreamClient {
|
|
|
1876
1902
|
this.emit({ ...event, type: approved ? 'permission.approved' : 'permission.denied' });
|
|
1877
1903
|
}
|
|
1878
1904
|
replayPermissionDecision(event) {
|
|
1879
|
-
if (!event.permissionBinding ||
|
|
1880
|
-
event.
|
|
1905
|
+
if (!event.permissionBinding ||
|
|
1906
|
+
event.decisionStatus === undefined ||
|
|
1907
|
+
event.purpose === 'task-command-once' ||
|
|
1908
|
+
event.purpose === 'runtime-elicitation' ||
|
|
1909
|
+
event.runtimeElicitation !== undefined ||
|
|
1910
|
+
event.toolName === 'ComputerUse')
|
|
1881
1911
|
return false;
|
|
1882
1912
|
const generation = permissionGeneration(event);
|
|
1883
1913
|
if (event.toolUseId) {
|
|
1884
1914
|
this.openPermissionPrompts.get(event.toolUseId)?.abort();
|
|
1885
1915
|
this.openPermissionPrompts.delete(event.toolUseId);
|
|
1886
|
-
this.permissionGenerations.set(event.toolUseId, {
|
|
1916
|
+
this.permissionGenerations.set(event.toolUseId, {
|
|
1917
|
+
key: generation,
|
|
1918
|
+
bound: true,
|
|
1919
|
+
readonly: true,
|
|
1920
|
+
});
|
|
1887
1921
|
this.permissionEpochs.set(this.options.sessionId, event.permissionBinding.epoch);
|
|
1888
1922
|
}
|
|
1889
1923
|
this.firstTimeSeen('permission', generation);
|
|
@@ -1891,11 +1925,18 @@ class AgenticStreamClient {
|
|
|
1891
1925
|
const status = event.decisionStatus === 'recorded' ? 'recorded' : 'delivery_unconfirmed';
|
|
1892
1926
|
if (this.firstTimeSeen('permission-receipt', `${generation}:${valid ? status : 'unknown'}`))
|
|
1893
1927
|
this.emit({
|
|
1894
|
-
...event,
|
|
1895
|
-
|
|
1928
|
+
...event,
|
|
1929
|
+
type: status === 'recorded'
|
|
1930
|
+
? 'permission.response_recorded'
|
|
1931
|
+
: 'permission.delivery_unconfirmed',
|
|
1932
|
+
status,
|
|
1933
|
+
previouslyRecorded: valid,
|
|
1934
|
+
executionConfirmed: false,
|
|
1935
|
+
readonly: true,
|
|
1896
1936
|
message: status === 'recorded'
|
|
1897
1937
|
? 'Response recorded. Waiting for execution to admit this response; no tool execution or continuing permission grant is confirmed.'
|
|
1898
|
-
: valid
|
|
1938
|
+
: valid
|
|
1939
|
+
? 'Response recorded; delivery unconfirmed. Check execution or Stop before starting a new turn.'
|
|
1899
1940
|
: 'Your response could not be confirmed. Check execution or Stop before starting a new turn.',
|
|
1900
1941
|
});
|
|
1901
1942
|
return true;
|
|
@@ -1905,7 +1946,9 @@ class AgenticStreamClient {
|
|
|
1905
1946
|
if (!event.permissionBinding)
|
|
1906
1947
|
return false;
|
|
1907
1948
|
const generation = permissionGeneration(event);
|
|
1908
|
-
const current = () => !this.closed &&
|
|
1949
|
+
const current = () => !this.closed &&
|
|
1950
|
+
!!event.toolUseId &&
|
|
1951
|
+
this.permissionGenerations.get(event.toolUseId)?.key === generation &&
|
|
1909
1952
|
!this.permissionGenerations.get(event.toolUseId)?.readonly;
|
|
1910
1953
|
if (!current())
|
|
1911
1954
|
return true;
|
|
@@ -1922,27 +1965,54 @@ class AgenticStreamClient {
|
|
|
1922
1965
|
const timer = setTimeout(() => finish({ type: 'permission.delivery_unconfirmed', message: unknown }), 10_000);
|
|
1923
1966
|
try {
|
|
1924
1967
|
if (!this.socket?.connected) {
|
|
1925
|
-
finish({
|
|
1968
|
+
finish({
|
|
1969
|
+
type: 'permission.response_refused',
|
|
1970
|
+
message: 'The connection is offline. No response was sent.',
|
|
1971
|
+
});
|
|
1926
1972
|
return;
|
|
1927
1973
|
}
|
|
1928
1974
|
this.socket.emit(approved ? 'permission:approve' : 'permission:deny', {
|
|
1929
|
-
sessionId: this.options.sessionId,
|
|
1930
|
-
|
|
1975
|
+
sessionId: this.options.sessionId,
|
|
1976
|
+
toolUseId: event.toolUseId,
|
|
1977
|
+
toolName: event.toolName,
|
|
1978
|
+
permissionBinding: event.permissionBinding,
|
|
1979
|
+
...extra,
|
|
1931
1980
|
}, (receipt) => {
|
|
1932
1981
|
const result = receipt?.result;
|
|
1933
|
-
if (receipt?.ok === false &&
|
|
1934
|
-
|
|
1982
|
+
if (receipt?.ok === false &&
|
|
1983
|
+
['invalid', 'unauthorized'].includes(receipt.error?.code || ''))
|
|
1984
|
+
finish({
|
|
1985
|
+
type: 'permission.response_refused',
|
|
1986
|
+
message: receipt.error?.message ||
|
|
1987
|
+
'The response was refused. No new permission was granted.',
|
|
1988
|
+
});
|
|
1935
1989
|
else if (receipt?.ok === false)
|
|
1936
1990
|
finish({ type: 'permission.delivery_unconfirmed', message: unknown });
|
|
1937
1991
|
else if (!result || result.toolUseId !== event.toolUseId)
|
|
1938
1992
|
finish({ type: 'permission.delivery_unconfirmed', message: unknown });
|
|
1939
1993
|
else if (result.status === 'closed')
|
|
1940
|
-
finish({
|
|
1994
|
+
finish({
|
|
1995
|
+
type: 'permission.response_refused',
|
|
1996
|
+
status: 'closed',
|
|
1997
|
+
message: 'This approval request is closed. No new permission was granted.',
|
|
1998
|
+
});
|
|
1941
1999
|
else if (result.status === 'delivery_unconfirmed')
|
|
1942
|
-
finish({
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
2000
|
+
finish({
|
|
2001
|
+
type: 'permission.delivery_unconfirmed',
|
|
2002
|
+
status: result.status,
|
|
2003
|
+
previouslyRecorded: result.previouslyRecorded === true,
|
|
2004
|
+
message: result.previouslyRecorded === true
|
|
2005
|
+
? 'Response recorded; delivery unconfirmed. Check execution or Stop before starting a new turn.'
|
|
2006
|
+
: unknown,
|
|
2007
|
+
});
|
|
2008
|
+
else if (receipt.ok === true &&
|
|
2009
|
+
result.accepted === true &&
|
|
2010
|
+
['recorded', 'admitted'].includes(result.status || ''))
|
|
2011
|
+
finish({
|
|
2012
|
+
type: 'permission.response_recorded',
|
|
2013
|
+
status: result.status,
|
|
2014
|
+
message: 'Response recorded. This does not confirm tool execution or a continuing permission grant.',
|
|
2015
|
+
});
|
|
1946
2016
|
else
|
|
1947
2017
|
finish({ type: 'permission.delivery_unconfirmed', message: unknown });
|
|
1948
2018
|
});
|
|
@@ -1952,7 +2022,12 @@ class AgenticStreamClient {
|
|
|
1952
2022
|
}
|
|
1953
2023
|
});
|
|
1954
2024
|
if (current())
|
|
1955
|
-
this.emit({
|
|
2025
|
+
this.emit({
|
|
2026
|
+
...event,
|
|
2027
|
+
...result,
|
|
2028
|
+
decision: approved ? 'allow' : 'deny',
|
|
2029
|
+
executionConfirmed: false,
|
|
2030
|
+
});
|
|
1956
2031
|
return true;
|
|
1957
2032
|
}
|
|
1958
2033
|
async handleQuestion(event) {
|
|
@@ -2020,7 +2095,8 @@ class AgenticStreamClient {
|
|
|
2020
2095
|
handlePermissionCancel(event) {
|
|
2021
2096
|
const toolUseId = typeof event.toolUseId === 'string' ? event.toolUseId : undefined;
|
|
2022
2097
|
const generation = toolUseId ? this.permissionGenerations.get(toolUseId) : undefined;
|
|
2023
|
-
if (generation &&
|
|
2098
|
+
if (generation &&
|
|
2099
|
+
(generation.bound || event.permissionBinding) &&
|
|
2024
2100
|
(!event.permissionBinding || generation.key !== permissionGeneration(event)))
|
|
2025
2101
|
return;
|
|
2026
2102
|
const open = toolUseId ? this.openPermissionPrompts.get(toolUseId) : undefined;
|
|
@@ -2058,8 +2134,17 @@ class AgenticStreamClient {
|
|
|
2058
2134
|
if (questionId)
|
|
2059
2135
|
this.openQuestionPrompts.delete(questionId);
|
|
2060
2136
|
open?.abort();
|
|
2137
|
+
// `answered` is the server telling every surface that SOMEONE answered. When
|
|
2138
|
+
// this client's own answer comes back as one there is nothing to report (it
|
|
2139
|
+
// already printed `question.answered`); when another surface answered while
|
|
2140
|
+
// this prompt was open, the prompt was just closed and that is worth saying.
|
|
2141
|
+
if (event.reason === 'answered' && !open)
|
|
2142
|
+
return;
|
|
2061
2143
|
this.emit({
|
|
2062
2144
|
...event,
|
|
2145
|
+
...(event.reason === 'answered' && !event.message
|
|
2146
|
+
? { message: 'This question was answered in another window.' }
|
|
2147
|
+
: {}),
|
|
2063
2148
|
type: 'question.cancelled',
|
|
2064
2149
|
promptClosed: Boolean(open),
|
|
2065
2150
|
});
|
|
@@ -2206,13 +2291,26 @@ class AgenticStreamClient {
|
|
|
2206
2291
|
// result, so there the line goes to stderr (OSK-13543).
|
|
2207
2292
|
if (!this.options.jsonl && this.renderHandoverStatus(event))
|
|
2208
2293
|
return;
|
|
2209
|
-
if (event.type === 'permission.browser_required' &&
|
|
2294
|
+
if (event.type === 'permission.browser_required' &&
|
|
2295
|
+
(this.options.quiet || !this.options.jsonl)) {
|
|
2210
2296
|
const output = this.options.quiet
|
|
2211
|
-
? this.options.statusOutput ?? process.stderr
|
|
2212
|
-
: this.options.output ?? process.stdout;
|
|
2297
|
+
? (this.options.statusOutput ?? process.stderr)
|
|
2298
|
+
: (this.options.output ?? process.stdout);
|
|
2213
2299
|
output.write(`\n[application permission] ${String(event.message)}\n`);
|
|
2214
2300
|
return;
|
|
2215
2301
|
}
|
|
2302
|
+
if (event.type === 'permission.denied' && event.reason === 'noninteractive_or_not_enabled') {
|
|
2303
|
+
const described = describePermission(event);
|
|
2304
|
+
// The stream asks and is refused twice for one call (observed: both appear, identical), and
|
|
2305
|
+
// the result should name a refused call once.
|
|
2306
|
+
if (!this.permissionDenials.includes(described))
|
|
2307
|
+
this.permissionDenials.push(described);
|
|
2308
|
+
// A quiet run withholds the answer's rendering, not a refusal: say it on stderr, as the
|
|
2309
|
+
// handover and browser-permission lines above do, so stdout stays the final result.
|
|
2310
|
+
if (this.options.quiet && !this.options.jsonl) {
|
|
2311
|
+
(this.options.statusOutput ?? process.stderr).write(`\n[permission] ${described} denied: nobody could be asked, and this run was not started with --approve-tools\n`);
|
|
2312
|
+
}
|
|
2313
|
+
}
|
|
2216
2314
|
// Accumulation and `onEvent` still run — only the incremental rendering is
|
|
2217
2315
|
// suppressed, so a quiet run is the same turn with a different display.
|
|
2218
2316
|
if (this.options.quiet)
|
|
@@ -2279,7 +2377,11 @@ class AgenticStreamClient {
|
|
|
2279
2377
|
output.write(`\n[${event.type}] ${describePermission(event)}\n`);
|
|
2280
2378
|
this.renderedText = this.answerText();
|
|
2281
2379
|
}
|
|
2282
|
-
else if ([
|
|
2380
|
+
else if ([
|
|
2381
|
+
'permission.response_recorded',
|
|
2382
|
+
'permission.delivery_unconfirmed',
|
|
2383
|
+
'permission.response_refused',
|
|
2384
|
+
].includes(event.type)) {
|
|
2283
2385
|
output.write(`\n[permission] ${String(event.message ?? '')}\n`);
|
|
2284
2386
|
this.renderedText = this.answerText();
|
|
2285
2387
|
}
|
|
@@ -2304,7 +2406,8 @@ class AgenticStreamClient {
|
|
|
2304
2406
|
output.write(`\n[question] ${why}\n`);
|
|
2305
2407
|
this.renderedText = this.answerText();
|
|
2306
2408
|
}
|
|
2307
|
-
else if (event.type === 'permission.denied' &&
|
|
2409
|
+
else if (event.type === 'permission.denied' &&
|
|
2410
|
+
event.reason === 'noninteractive_or_not_enabled') {
|
|
2308
2411
|
// Said out loud, because nobody was asked and the agent will not say it plainly: this run
|
|
2309
2412
|
// had no terminal to ask at and was not given --approve-tools, so the call was refused.
|
|
2310
2413
|
output.write(`\n[permission] ${describePermission(event)} denied: nobody could be asked, and this run was not started with --approve-tools\n`);
|
|
@@ -2420,10 +2523,16 @@ class AgenticStreamClient {
|
|
|
2420
2523
|
try {
|
|
2421
2524
|
const terminal = await reconcile();
|
|
2422
2525
|
if (terminal && typeof terminal.text === 'string' && terminal.text) {
|
|
2423
|
-
return {
|
|
2526
|
+
return {
|
|
2527
|
+
text: terminal.text,
|
|
2528
|
+
...(terminal.publicProjection ? { publicProjection: terminal.publicProjection } : {}),
|
|
2529
|
+
};
|
|
2424
2530
|
}
|
|
2425
2531
|
if (terminal)
|
|
2426
|
-
empty = {
|
|
2532
|
+
empty = {
|
|
2533
|
+
text: '',
|
|
2534
|
+
...(terminal.publicProjection ? { publicProjection: terminal.publicProjection } : {}),
|
|
2535
|
+
};
|
|
2427
2536
|
}
|
|
2428
2537
|
catch {
|
|
2429
2538
|
// No evidence either way; try again, then settle on the stream.
|
|
@@ -2485,8 +2594,9 @@ class AgenticStreamClient {
|
|
|
2485
2594
|
// other way round).
|
|
2486
2595
|
// (Compared as the reader sees it: the record holds a widget as its fallback sentence,
|
|
2487
2596
|
// which is shorter than the block the stream carried, and the raw length would never lose.)
|
|
2488
|
-
if (recorded &&
|
|
2489
|
-
recorded.
|
|
2597
|
+
if (recorded &&
|
|
2598
|
+
(recorded.publicProjection === 'lookback_answer_v1' ||
|
|
2599
|
+
recorded.text.length > (0, widgetTerminalText_1.widgetsAsText)(this.accumulated, { final: true }).length)) {
|
|
2490
2600
|
this.accumulated = recorded.text;
|
|
2491
2601
|
this.publicProjection = recorded.publicProjection;
|
|
2492
2602
|
}
|
|
@@ -2522,6 +2632,7 @@ class AgenticStreamClient {
|
|
|
2522
2632
|
text: this.accumulated,
|
|
2523
2633
|
status,
|
|
2524
2634
|
...(status === 'completed' && event.repaired === true ? { repaired: true } : {}),
|
|
2635
|
+
...(this.permissionDenials.length ? { permissionDenials: [...this.permissionDenials] } : {}),
|
|
2525
2636
|
lastEvent: event,
|
|
2526
2637
|
};
|
|
2527
2638
|
this.resolve(this.terminalResult);
|
package/dist/lib/command-miss.js
CHANGED
|
@@ -359,8 +359,17 @@ function nearestCommands(id, all, limit = 3) {
|
|
|
359
359
|
// A third of the length keeps this to genuine near-misses; without a bound
|
|
360
360
|
// every miss suggests three unrelated commands, which is noise wearing the
|
|
361
361
|
// shape of help.
|
|
362
|
-
|
|
363
|
-
|
|
362
|
+
// A command NESTED under what was typed (`northstars:intents` -> `northstars:intents:list`)
|
|
363
|
+
// is the correction the reader was reaching for, whatever its edit distance, so it is
|
|
364
|
+
// neither bound-filtered nor ranked by distance. Distance alone kept `intents:decide` out
|
|
365
|
+
// and put shorter siblings ahead of `intents:list`, so `northstars intents <id>` was
|
|
366
|
+
// answered with "Did you mean: northstars create, northstars delete, northstars intents
|
|
367
|
+
// list?" and the first guess a reader acts on was a destructive one.
|
|
368
|
+
.filter(({ d, candidate }) => candidate.startsWith(`${id}:`) || d <= Math.max(2, Math.floor(id.length / 3)))
|
|
369
|
+
.sort((x, y) => {
|
|
370
|
+
const nested = (c) => (c.startsWith(`${id}:`) ? 0 : 1);
|
|
371
|
+
return nested(x.candidate) - nested(y.candidate) || x.d - y.d;
|
|
372
|
+
})
|
|
364
373
|
.slice(0, limit)
|
|
365
374
|
.map(({ candidate }) => candidate));
|
|
366
375
|
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The attention settings of a Commitment, said in words.
|
|
3
|
+
*
|
|
4
|
+
* `show`, `effective-policy` and `preflight` all print these, from this one
|
|
5
|
+
* file, so the three cannot phrase a setting three ways. A value is described
|
|
6
|
+
* from the RAW stored setting and never through a coercion: `null` is "no
|
|
7
|
+
* limit" and `0` is "muted", and `Number(null)` is `0`, which is exactly how a
|
|
8
|
+
* cap that was never set would read as a mute (the server documents the same
|
|
9
|
+
* trap at `policySchema.maxUserNudgesPerDay` in api/server/routes/commitments.js).
|
|
10
|
+
*/
|
|
11
|
+
/** What the owner can type for `--max-nudges`, as `--help` prints it. */
|
|
12
|
+
export declare const MAX_NUDGES_FLAG_HELP: string;
|
|
13
|
+
/**
|
|
14
|
+
* Parse `--max-nudges`: a whole number, or the word `unlimited` (stored as `null`).
|
|
15
|
+
* The server accepts 0 up to MAX_SAFE_INTEGER, so there is no 0..20 ceiling here.
|
|
16
|
+
*/
|
|
17
|
+
export declare function parseMaxNudgesFlag(raw: string | undefined): number | null | undefined;
|
|
18
|
+
/** `null` and an unset cap are "no daily limit"; `0` is a mute; N is "at most N a day". */
|
|
19
|
+
export declare function describeNudgeCap(value: unknown): string;
|
|
20
|
+
/** The least time the platform leaves between two nudges to you. */
|
|
21
|
+
export declare function describeNudgeGap(ms: unknown): string;
|
|
22
|
+
/** The back-off for a person who is not answering. The server's default count is 2. */
|
|
23
|
+
export declare function describeNoReplyRule(noReply: {
|
|
24
|
+
enabled?: boolean;
|
|
25
|
+
afterNudges?: number;
|
|
26
|
+
} | null | undefined): string;
|
|
27
|
+
export type NudgeSettings = {
|
|
28
|
+
/** `null` = unlimited, `0` = muted. `undefined` = never set, which is unlimited. */
|
|
29
|
+
maxUserNudgesPerDay?: number | null;
|
|
30
|
+
minUserNudgeIntervalMs?: number | null;
|
|
31
|
+
noReply?: {
|
|
32
|
+
enabled?: boolean;
|
|
33
|
+
afterNudges?: number;
|
|
34
|
+
} | null;
|
|
35
|
+
};
|
|
36
|
+
/** Read the three settings out of a stored `policy`. */
|
|
37
|
+
export declare function nudgeSettingsFromPolicy(policy: Record<string, any>): NudgeSettings;
|
|
38
|
+
/**
|
|
39
|
+
* The lines that say how much a Commitment may interrupt its owner. A muted one
|
|
40
|
+
* prints the mute alone: a gap and a back-off on a Commitment that never speaks
|
|
41
|
+
* would only suggest it does. `withNoReply: false` leaves the back-off out when the
|
|
42
|
+
* stored rule could not be read, rather than claim it is off.
|
|
43
|
+
*/
|
|
44
|
+
export declare function nudgeSettingLines(settings: NudgeSettings, { withNoReply }?: {
|
|
45
|
+
withNoReply?: boolean;
|
|
46
|
+
}): string[];
|
|
47
|
+
/** What a time of day is, in the words a person can type. */
|
|
48
|
+
export declare const CLOCK_TIME_HINT = "use HH:MM, 00:00-23:59, for example 22:00";
|
|
49
|
+
/**
|
|
50
|
+
* How to set quiet hours, for the `--from-json` help of `create` and `update`. There is no flag for
|
|
51
|
+
* them, so without this sentence a user had to know the `policy.quietHours` key from outside the CLI
|
|
52
|
+
* (OSK-21123).
|
|
53
|
+
*/
|
|
54
|
+
export declare const QUIET_HOURS_HELP: string;
|
|
55
|
+
/**
|
|
56
|
+
* What `policy.executionBudget.allowedEventSources` means, for the same help. An empty list is the
|
|
57
|
+
* unrestricted case, which is the opposite of what `[]` suggests (OSK-21113).
|
|
58
|
+
*/
|
|
59
|
+
export declare const EVENT_SOURCES_HELP: string;
|
|
60
|
+
/**
|
|
61
|
+
* The allowlist in words. An empty or missing list means every source is allowed
|
|
62
|
+
* (`sourceAllowed` in api/server/services/EventBus/commitmentWakeCapabilities.js and the check in
|
|
63
|
+
* WakeIntentResolver.js both treat it so); the stored form of "never set" is the same `[]`.
|
|
64
|
+
*/
|
|
65
|
+
export declare function describeEventSources(allowed: unknown): string;
|
|
66
|
+
/**
|
|
67
|
+
* The problem with the quiet-hours times in a `policy` about to be sent, or null. The server
|
|
68
|
+
* answered a bad time with its raw pattern (`must match pattern /^\d{1,2}:\d{2}$/`), which says
|
|
69
|
+
* nothing a person can type, and accepted `25:00` (a window that then never applies). Checked
|
|
70
|
+
* here, so the request never leaves with either.
|
|
71
|
+
*/
|
|
72
|
+
export declare function quietHoursInputProblem(policy: unknown): string | null;
|
|
73
|
+
type QuietHoursPolicy = {
|
|
74
|
+
enabled?: boolean;
|
|
75
|
+
start?: string;
|
|
76
|
+
end?: string;
|
|
77
|
+
timezone?: string;
|
|
78
|
+
} | null;
|
|
79
|
+
/**
|
|
80
|
+
* The Commitment's own quiet-hours window in words. Without one of its own a Commitment uses its
|
|
81
|
+
* Agent's Compass window (`scheduleIssues.js` documents the same rule), so "none set" says where
|
|
82
|
+
* else a window may come from rather than claiming there is no quiet time at all.
|
|
83
|
+
*/
|
|
84
|
+
export declare function describeQuietHours(quietHours: QuietHoursPolicy | undefined): string;
|
|
85
|
+
/**
|
|
86
|
+
* When a held message is released, for the preflight line "Held until your quiet hours end".
|
|
87
|
+
* The report's `quietHours` carries the end as typed, the zone, and the exact instant (`endsAt`,
|
|
88
|
+
* daylight saving included); null when it carries no instant, so the caller keeps its generic
|
|
89
|
+
* sentence rather than inventing a time.
|
|
90
|
+
*/
|
|
91
|
+
export declare function describeQuietHoursEnd(quietHours: {
|
|
92
|
+
end?: string;
|
|
93
|
+
endsAt?: string | null;
|
|
94
|
+
timezone?: string;
|
|
95
|
+
} | null | undefined): string | null;
|
|
96
|
+
export {};
|