@skrr-ai/cli 0.1.123 → 0.1.125
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/commands/agents/chat.d.ts +26 -0
- package/dist/commands/agents/chat.js +48 -10
- package/dist/commands/agents/delete.d.ts +8 -0
- package/dist/commands/agents/delete.js +16 -0
- package/dist/commands/context.js +7 -0
- package/dist/commands/search/workspace.js +1 -1
- package/dist/commands/store/gallery-admissions/approve.js +1 -1
- package/dist/commands/store/gallery-admissions/preview.js +1 -1
- package/dist/commands/store/gallery-admissions/refuse.js +1 -1
- package/dist/commands/store/gallery-admissions/show.js +1 -1
- package/dist/generated/agent-guides.json +19 -19
- package/dist/lib/agentic-stream.js +15 -1
- package/dist/lib/auth-core-init.d.ts +15 -2
- package/dist/lib/auth-core-init.js +47 -6
- package/dist/lib/command-hygiene.js +30 -1
- package/dist/lib/daemonBrokerRefusal.js +5 -1
- package/dist/lib/keychain.js +41 -4
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/cliHandoffWire.d.ts +5 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/cliHandoffWire.js +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/credentialEnvelopeBridge.js +13 -28
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceIdentityBridge.d.ts +133 -4
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceIdentityBridge.js +387 -90
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceKey.d.ts +106 -7
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceKey.js +77 -19
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceKeyHandle.d.ts +33 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceKeyHandle.js +77 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceKeyHardware.d.ts +68 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceKeyHardware.js +264 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceKeyServerSupport.d.ts +31 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceKeyServerSupport.js +90 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/dpop.js +2 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/independentMachineReservation.js +2 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +7 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +102 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/kek/index.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/kek/index.js +6 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/kek/linux.d.ts +18 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/kek/linux.js +8 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/kek/macos.d.ts +22 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/kek/macos.js +11 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/kek/masterKekService.d.ts +43 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/kek/masterKekService.js +33 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/liveState.d.ts +154 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/liveState.js +281 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/machineId.js +6 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/machineUuid.js +8 -5
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/profileStateDir.js +7 -27
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/refresh.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/refresh.js +12 -10
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/stateFiles.d.ts +31 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/stateFiles.js +89 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/cliHandoffWire.d.ts +5 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/cliHandoffWire.js +4 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/credentialEnvelopeBridge.js +15 -37
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceIdentityBridge.d.ts +133 -4
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceIdentityBridge.js +536 -101
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceKey.d.ts +106 -7
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceKey.js +131 -27
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceKeyHandle.d.ts +33 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceKeyHandle.js +81 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceKeyHardware.d.ts +68 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceKeyHardware.js +317 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceKeyServerSupport.d.ts +31 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceKeyServerSupport.js +86 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/dpop.js +4 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/independentMachineReservation.js +4 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +7 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +13 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/kek/index.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/kek/index.js +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/kek/linux.d.ts +18 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/kek/linux.js +15 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/kek/macos.d.ts +22 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/kek/macos.js +20 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/kek/masterKekService.d.ts +43 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/kek/masterKekService.js +104 -8
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/liveState.d.ts +154 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/liveState.js +386 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/machineId.js +6 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/machineUuid.js +11 -5
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/profileStateDir.js +6 -35
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/refresh.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/refresh.js +14 -10
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/stateFiles.d.ts +31 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/stateFiles.js +73 -0
- package/dist/node_modules/@skrr-ai/auth-core/package.json +11 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +1094 -1067
- package/oclif.manifest.json +16 -3
- package/package.json +4 -1
|
@@ -59,6 +59,31 @@ export declare function interruptedDetachMessage(input: {
|
|
|
59
59
|
/** The second Ctrl-C: the CLI stopped waiting rather than running out the grace period. */
|
|
60
60
|
forced?: boolean;
|
|
61
61
|
}): string;
|
|
62
|
+
/**
|
|
63
|
+
* `--jsonl` prints `text.delta` as a real delta unless `--cumulative` asks for the whole answer
|
|
64
|
+
* so far in every event. The cumulative form costs the square of the answer's length (a 57 KB
|
|
65
|
+
* answer printed 34.6 MB, OSK-20596), which is the wrong default for the mode scripts and other
|
|
66
|
+
* agents drive. `--incremental` is the old opt-in for what is now the default and changes nothing.
|
|
67
|
+
*/
|
|
68
|
+
export declare function jsonlTextForm(flags: {
|
|
69
|
+
cumulative?: boolean;
|
|
70
|
+
}): {
|
|
71
|
+
incrementalText: boolean;
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* What to say when the user pressed Ctrl-C and the server then confirmed the run ended.
|
|
75
|
+
*
|
|
76
|
+
* The warning printed at the keypress ("a tool call already running on the runtime is not
|
|
77
|
+
* guaranteed to stop") is written before the outcome is known. When the run settles as `aborted`
|
|
78
|
+
* it is no longer the whole truth, and left as the last line it reads as a cancel that failed:
|
|
79
|
+
* the CLI exited without a word, the prompt came back, and a person could not tell whether to go
|
|
80
|
+
* and kill something (OSK-20603). A script has `run.result {status: "aborted"}`; a terminal gets
|
|
81
|
+
* this line. It claims what the server said, that the run ended, and nothing about processes.
|
|
82
|
+
*/
|
|
83
|
+
export declare function cancelledRunMessage(input: {
|
|
84
|
+
sessionId: string;
|
|
85
|
+
conversationId?: string | null;
|
|
86
|
+
}): string;
|
|
62
87
|
/**
|
|
63
88
|
* What the durable record says about a turn, read from its messages.
|
|
64
89
|
*
|
|
@@ -228,6 +253,7 @@ export default class AgentsChat extends BaseCommand {
|
|
|
228
253
|
'thread-root': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
229
254
|
'no-stream': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
230
255
|
quick: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
256
|
+
cumulative: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
231
257
|
incremental: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
232
258
|
jsonl: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
233
259
|
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.MAX_HANDOVER_WAIT_SECONDS = exports.DEFAULT_HANDOVER_WAIT_SECONDS = exports.STREAM_LOST_EXIT_CODE = exports.DETACH_EXIT_CODE = void 0;
|
|
4
4
|
exports.streamedResultExitCode = streamedResultExitCode;
|
|
5
5
|
exports.interruptedDetachMessage = interruptedDetachMessage;
|
|
6
|
+
exports.jsonlTextForm = jsonlTextForm;
|
|
7
|
+
exports.cancelledRunMessage = cancelledRunMessage;
|
|
6
8
|
exports.reconcileTerminalFromMessages = reconcileTerminalFromMessages;
|
|
7
9
|
exports.handoverStateFromMessages = handoverStateFromMessages;
|
|
8
10
|
exports.handoverInterruptMessage = handoverInterruptMessage;
|
|
@@ -88,6 +90,29 @@ function interruptedDetachMessage(input) {
|
|
|
88
90
|
? ''
|
|
89
91
|
: ', and look for a surviving process with `ps -ef | grep -i claude`'));
|
|
90
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* `--jsonl` prints `text.delta` as a real delta unless `--cumulative` asks for the whole answer
|
|
95
|
+
* so far in every event. The cumulative form costs the square of the answer's length (a 57 KB
|
|
96
|
+
* answer printed 34.6 MB, OSK-20596), which is the wrong default for the mode scripts and other
|
|
97
|
+
* agents drive. `--incremental` is the old opt-in for what is now the default and changes nothing.
|
|
98
|
+
*/
|
|
99
|
+
function jsonlTextForm(flags) {
|
|
100
|
+
return { incrementalText: flags.cumulative !== true };
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* What to say when the user pressed Ctrl-C and the server then confirmed the run ended.
|
|
104
|
+
*
|
|
105
|
+
* The warning printed at the keypress ("a tool call already running on the runtime is not
|
|
106
|
+
* guaranteed to stop") is written before the outcome is known. When the run settles as `aborted`
|
|
107
|
+
* it is no longer the whole truth, and left as the last line it reads as a cancel that failed:
|
|
108
|
+
* the CLI exited without a word, the prompt came back, and a person could not tell whether to go
|
|
109
|
+
* and kill something (OSK-20603). A script has `run.result {status: "aborted"}`; a terminal gets
|
|
110
|
+
* this line. It claims what the server said, that the run ended, and nothing about processes.
|
|
111
|
+
*/
|
|
112
|
+
function cancelledRunMessage(input) {
|
|
113
|
+
return (`Run ${input.sessionId} cancelled: the server confirmed it ended.` +
|
|
114
|
+
(input.conversationId ? ` Continue the conversation with --conversation ${input.conversationId}.` : ''));
|
|
115
|
+
}
|
|
91
116
|
/**
|
|
92
117
|
* What the durable record says about a turn, read from its messages.
|
|
93
118
|
*
|
|
@@ -379,20 +404,29 @@ class AgentsChat extends base_command_1.BaseCommand {
|
|
|
379
404
|
'agent’s runtime, tools, session, or working directory and cannot perform work — ' +
|
|
380
405
|
'it is for inline text assistance. Use --no-stream for a real turn.',
|
|
381
406
|
}),
|
|
407
|
+
cumulative: core_1.Flags.boolean({
|
|
408
|
+
description: 'With --jsonl, make `text.delta` carry the whole answer so far in `text` (plus `delta`, ' +
|
|
409
|
+
'the characters it adds, when it only appends) and repeat the envelopes that ' +
|
|
410
|
+
'`session.output` already carries: the form --jsonl had before it was incremental by ' +
|
|
411
|
+
'default. A long answer written this way grows with the square of its length ' +
|
|
412
|
+
'(a 57 KB answer printed 34.6 MB), so use it only for a consumer that must read ' +
|
|
413
|
+
'the answer from any single event.',
|
|
414
|
+
dependsOn: ['jsonl'],
|
|
415
|
+
exclusive: ['incremental'],
|
|
416
|
+
}),
|
|
382
417
|
incremental: core_1.Flags.boolean({
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
'
|
|
386
|
-
'`replace`, the new full text. `run.result` still holds the whole answer. Without it ' +
|
|
387
|
-
'a long answer written as JSON lines grows with the square of its length.',
|
|
418
|
+
hidden: true,
|
|
419
|
+
description: 'No longer needed: --jsonl is incremental by default. Accepted so scripts that already ' +
|
|
420
|
+
'pass it keep working.',
|
|
388
421
|
dependsOn: ['jsonl'],
|
|
389
422
|
}),
|
|
390
423
|
jsonl: core_1.Flags.boolean({
|
|
391
424
|
description: 'Emit one JSON event per line while streaming. Every line is a complete JSON value. ' +
|
|
392
|
-
'Assistant text arrives as `text.delta
|
|
393
|
-
'
|
|
394
|
-
'
|
|
395
|
-
'
|
|
425
|
+
'Assistant text arrives as `text.delta`, a real delta: `delta` is the characters it ' +
|
|
426
|
+
'adds, and a rewrite that is not an append arrives as `replace`, the new full text. ' +
|
|
427
|
+
'Append the `delta`s, or take `run.result` at the end, which always holds the whole ' +
|
|
428
|
+
'answer. (--cumulative restores the older form, where `text` is the whole answer so ' +
|
|
429
|
+
'far; it grows with the square of the answer.) The same text is ' +
|
|
396
430
|
'mirrored inside `session.output` envelopes for consumers that want the raw stream, ' +
|
|
397
431
|
'so folding both doubles the answer: pick ONE lane. A widget the agent wrote ' +
|
|
398
432
|
'(a block of CSS, HTML and JavaScript the apps draw) is its text description in ' +
|
|
@@ -813,7 +847,7 @@ class AgentsChat extends base_command_1.BaseCommand {
|
|
|
813
847
|
sessionId: started.sessionId,
|
|
814
848
|
conversationId,
|
|
815
849
|
jsonl: flags.jsonl,
|
|
816
|
-
|
|
850
|
+
...jsonlTextForm(flags),
|
|
817
851
|
quiet,
|
|
818
852
|
approveTools: flags['approve-tools'],
|
|
819
853
|
reconcileTerminal,
|
|
@@ -1005,6 +1039,10 @@ class AgentsChat extends base_command_1.BaseCommand {
|
|
|
1005
1039
|
this.error(noOutput, { exit: 1 });
|
|
1006
1040
|
this.log(result.text);
|
|
1007
1041
|
}
|
|
1042
|
+
else if (result.status === 'aborted') {
|
|
1043
|
+
// Streaming human mode: say the cancel took, rather than leave the keypress warning last.
|
|
1044
|
+
this.log(`\n${cancelledRunMessage({ sessionId: started.sessionId, conversationId: started.conversationId })}`);
|
|
1045
|
+
}
|
|
1008
1046
|
}
|
|
1009
1047
|
finally {
|
|
1010
1048
|
if (graceTimer)
|
|
@@ -8,6 +8,14 @@ import { BaseCommand } from '../../base-command';
|
|
|
8
8
|
export declare function agentRemovalQuestion(agentId: string, kind: AgentRemovalKind | null): string;
|
|
9
9
|
/** What happened, read from the server's response rather than predicted. */
|
|
10
10
|
export declare function agentRemovalReport(agentId: string, response: DeleteAgentResponse | undefined): string;
|
|
11
|
+
/**
|
|
12
|
+
* What became of the agent's Personal Context data, read from the same response
|
|
13
|
+
* (OSK-20112). The agent row is gone as soon as the delete returns, but data
|
|
14
|
+
* derived from its connected sources is erased separately: `Deleted agent` must
|
|
15
|
+
* never stand in for "erased". Nothing is printed when the server reported
|
|
16
|
+
* nothing (an older server, or an uninstall, which erases nothing).
|
|
17
|
+
*/
|
|
18
|
+
export declare function agentErasureReport(response: DeleteAgentResponse | undefined): string[];
|
|
11
19
|
export default class AgentsDelete extends BaseCommand {
|
|
12
20
|
static description: string;
|
|
13
21
|
static examples: string[];
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.agentRemovalQuestion = agentRemovalQuestion;
|
|
4
4
|
exports.agentRemovalReport = agentRemovalReport;
|
|
5
|
+
exports.agentErasureReport = agentErasureReport;
|
|
5
6
|
const core_1 = require("@oclif/core");
|
|
6
7
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
7
8
|
const base_command_1 = require("../../base-command");
|
|
@@ -38,6 +39,19 @@ function agentRemovalReport(agentId, response) {
|
|
|
38
39
|
return `Deleted agent ${agentId}`;
|
|
39
40
|
}
|
|
40
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* What became of the agent's Personal Context data, read from the same response
|
|
44
|
+
* (OSK-20112). The agent row is gone as soon as the delete returns, but data
|
|
45
|
+
* derived from its connected sources is erased separately: `Deleted agent` must
|
|
46
|
+
* never stand in for "erased". Nothing is printed when the server reported
|
|
47
|
+
* nothing (an older server, or an uninstall, which erases nothing).
|
|
48
|
+
*/
|
|
49
|
+
function agentErasureReport(response) {
|
|
50
|
+
if ((0, data_provider_1.agentRemovalKind)(response) !== 'deleted')
|
|
51
|
+
return [];
|
|
52
|
+
const erasure = response && 'erasure' in response ? response.erasure : undefined;
|
|
53
|
+
return (0, data_provider_1.describePersonalContextErasure)(erasure)?.lines ?? [];
|
|
54
|
+
}
|
|
41
55
|
class AgentsDelete extends base_command_1.BaseCommand {
|
|
42
56
|
static description = 'Delete an agent you created (irreversible), or uninstall one installed from the store (reinstalling restores it)';
|
|
43
57
|
static examples = [
|
|
@@ -89,6 +103,8 @@ class AgentsDelete extends base_command_1.BaseCommand {
|
|
|
89
103
|
this.handleApiError(err);
|
|
90
104
|
}
|
|
91
105
|
this.log(agentRemovalReport(args.id, response));
|
|
106
|
+
for (const line of agentErasureReport(response))
|
|
107
|
+
this.log(line);
|
|
92
108
|
}
|
|
93
109
|
}
|
|
94
110
|
exports.default = AgentsDelete;
|
package/dist/commands/context.js
CHANGED
|
@@ -64,6 +64,13 @@ class Context extends base_command_1.BaseCommand {
|
|
|
64
64
|
path: (0, config_1.getConfigPath)(),
|
|
65
65
|
cliId: (0, cli_id_1.resolveCliId)(this.cliConfig) ?? null,
|
|
66
66
|
},
|
|
67
|
+
// Silent about the DAEMON's device key on purpose (OSK-20507). This is the CLI's
|
|
68
|
+
// own sign-in, and the CLI never requires a device key (OSK-12063), so an
|
|
69
|
+
// unreadable one changes nothing an agent reading this can do. The daemon's
|
|
70
|
+
// account of its key is `skrr daemon status` (`problems`, from `/health`
|
|
71
|
+
// `deviceIdentity`), and the one line a `skrr` process prints about it is the
|
|
72
|
+
// notice in `lib/auth-core-init.ts`. Adding it here would put a machine fact
|
|
73
|
+
// beside a per-process one and read as this credential's state.
|
|
67
74
|
auth: {
|
|
68
75
|
signedIn: Boolean(this.resolvedCredential?.token),
|
|
69
76
|
tokenSource: this.credentialSourceLabel(),
|
|
@@ -104,7 +104,7 @@ class SearchWorkspace extends base_command_1.BaseCommand {
|
|
|
104
104
|
url: `${(0, web_url_1.webOrigin)(this.cliConfig.baseURL)}${item.href}`,
|
|
105
105
|
}));
|
|
106
106
|
if (flags.json) {
|
|
107
|
-
this.
|
|
107
|
+
this.printJsonResult({ ...response, results });
|
|
108
108
|
return;
|
|
109
109
|
}
|
|
110
110
|
for (const diagnostic of new Set(response.diagnostics || []))
|
|
@@ -24,7 +24,7 @@ class StoreGalleryAdmissionsApprove extends base_command_1.BaseCommand {
|
|
|
24
24
|
revision: flags.revision, digest: flags.digest, imagesReviewed: true, ...(flags.note ? { note: flags.note } : {}),
|
|
25
25
|
});
|
|
26
26
|
if (flags.json)
|
|
27
|
-
this.
|
|
27
|
+
this.printJsonResult(result);
|
|
28
28
|
else
|
|
29
29
|
this.log(`Approved gallery revision ${flags.revision}.`);
|
|
30
30
|
}
|
|
@@ -36,7 +36,7 @@ class StoreGalleryAdmissionsPreview extends base_command_1.BaseCommand {
|
|
|
36
36
|
await (0, promises_1.writeFile)(flags.output, bytes, { flag: 'wx', mode: 0o600 });
|
|
37
37
|
const receipt = { requestId: args.id, kind, revision: review.revision, digest: review.digest, imageId: args.imageId, sha256: digest, path: flags.output, bytes: bytes.length };
|
|
38
38
|
if (flags.json)
|
|
39
|
-
this.
|
|
39
|
+
this.printJsonResult(receipt);
|
|
40
40
|
else
|
|
41
41
|
this.log(`Wrote ${bytes.length} bytes to ${flags.output} (sha256:${digest}). Review revision ${review.revision}, digest ${review.digest}.`);
|
|
42
42
|
}
|
|
@@ -23,7 +23,7 @@ class StoreGalleryAdmissionsRefuse extends base_command_1.BaseCommand {
|
|
|
23
23
|
revision: flags.revision, digest: flags.digest, note: flags.note.trim(),
|
|
24
24
|
});
|
|
25
25
|
if (flags.json)
|
|
26
|
-
this.
|
|
26
|
+
this.printJsonResult(result);
|
|
27
27
|
else
|
|
28
28
|
this.log(`Refused gallery revision ${flags.revision}.`);
|
|
29
29
|
}
|
|
@@ -16,7 +16,7 @@ class StoreGalleryAdmissionsShow extends base_command_1.BaseCommand {
|
|
|
16
16
|
try {
|
|
17
17
|
const result = await data_provider_1.dataService.getStoreGalleryAdmission(flags.kind, args.id);
|
|
18
18
|
if (flags.json) {
|
|
19
|
-
this.
|
|
19
|
+
this.printJsonResult(result);
|
|
20
20
|
return;
|
|
21
21
|
}
|
|
22
22
|
const r = result.review;
|
|
@@ -350,7 +350,7 @@
|
|
|
350
350
|
"id": "memory",
|
|
351
351
|
"title": "Where an Agent's knowledge lives",
|
|
352
352
|
"readWhen": "you need to read or change what an Agent knows, or tell its Memory from its configuration",
|
|
353
|
-
"tokens":
|
|
353
|
+
"tokens": 891,
|
|
354
354
|
"aliases": [],
|
|
355
355
|
"explains": [
|
|
356
356
|
"MEMORY_NOT_MOUNTED",
|
|
@@ -489,7 +489,7 @@
|
|
|
489
489
|
"version": 4,
|
|
490
490
|
"routed": true,
|
|
491
491
|
"aliases": [],
|
|
492
|
-
"tokens":
|
|
492
|
+
"tokens": 865,
|
|
493
493
|
"sections": [
|
|
494
494
|
{
|
|
495
495
|
"id": "model",
|
|
@@ -709,7 +709,7 @@
|
|
|
709
709
|
]
|
|
710
710
|
}
|
|
711
711
|
],
|
|
712
|
-
"hash": "
|
|
712
|
+
"hash": "3581ad4744d3aae5df82a9358ddb6f87e823b4928104006581e16b3a4d821b2e",
|
|
713
713
|
"tokens": 544
|
|
714
714
|
},
|
|
715
715
|
"routedIndex": {
|
|
@@ -1063,7 +1063,7 @@
|
|
|
1063
1063
|
"id": "memory",
|
|
1064
1064
|
"title": "Where an Agent's knowledge lives",
|
|
1065
1065
|
"readWhen": "you need to read or change what an Agent knows, or tell its Memory from its configuration",
|
|
1066
|
-
"tokens":
|
|
1066
|
+
"tokens": 891,
|
|
1067
1067
|
"aliases": [],
|
|
1068
1068
|
"explains": [
|
|
1069
1069
|
"MEMORY_NOT_MOUNTED",
|
|
@@ -1202,7 +1202,7 @@
|
|
|
1202
1202
|
"version": 4,
|
|
1203
1203
|
"routed": true,
|
|
1204
1204
|
"aliases": [],
|
|
1205
|
-
"tokens":
|
|
1205
|
+
"tokens": 865,
|
|
1206
1206
|
"sections": [
|
|
1207
1207
|
{
|
|
1208
1208
|
"id": "model",
|
|
@@ -1353,7 +1353,7 @@
|
|
|
1353
1353
|
]
|
|
1354
1354
|
}
|
|
1355
1355
|
],
|
|
1356
|
-
"hash": "
|
|
1356
|
+
"hash": "2f65b076744f03768c49bce61d58f4ee26354c007316777602a3567f3d71f35d",
|
|
1357
1357
|
"tokens": 493
|
|
1358
1358
|
},
|
|
1359
1359
|
"cards": {
|
|
@@ -1676,7 +1676,7 @@
|
|
|
1676
1676
|
"routed": true,
|
|
1677
1677
|
"aliases": [],
|
|
1678
1678
|
"body": "## Concept model\n\n| Noun | Question it answers |\n| --- | --- |\n| **Agent** | Who acts, and with which identity, instructions, model, tools and tone? |\n| **Harness** | Which provider runs its turns, on which machine? One machine × one provider: Claude Code and Codex on one laptop are two Harnesses. |\n| **Machine** | Which computer: a personal machine running the daemon, a Dedicated Runtime, or a Hosted Machine? |\n| **Release** | Which exact, installable snapshot of the Agent's portable specification? |\n| **Role** | Which portable responsibility (purpose, scope, parameters) can be installed on an Agent? |\n| **Memory Store** | What does the Agent know, kept for the Agent or for a Space? |\n| **Notepad** | What does one person privately want this Agent to keep in mind? |\n\n## Decide\n\n- **Who am I?** The managed identity block in your instruction file names the Agent this machine\n speaks as. `--agent <agent-id>` chooses which Agent a message speaks as. Neither sets authorship:\n the server records the author of every write from the authenticated runtime, and `skrr context`\n reports only whether this runtime carries an Agent binding.\n- How it writes (shorter, plainer, warmer) is **tone**. What it does or must never do is an\n **instruction block**. Neither belongs in a Memory Store or the Notepad.\n- A preference the person tells you to remember is a Memory proposal they review, not an edit to\n your own instructions. Work to do later, or to keep checking, belongs to a commitment.\n- Where it runs is its execution targets. A Machine is not a Harness: pin the Harness.\n\n## Workflow\n\n### Change an Agent's configuration\n\n1. Read the current value of exactly what you will change, on the Agent the owner named.\n2. Make the narrowest change asked for: add or edit one instruction block rather than replacing\n all of them.\n3. Read the resolved state back and report that. A workspace policy can override a tone you set.\n\nThe commands for each step are in the `configure` section; `--help` gives their flags.\n\n## Authority\n\n| Actor | May do | Only a person may do |\n| --- | --- | --- |\n| Agent | Read any Agent it can view; when the owner asks, change an Agent's instructions, tone, model or tools, create an Agent, or delete one the owner's own message names; propose a Memory change | Widen an Agent's permissions: permission mode, network egress, tool sign-in; publish, list, price or share an Agent; connect a channel; choose paid compute; approve a Memory promotion; set Memory governance |\n| Person | Everything in both columns | — |\n\nAn Agent never widens its own permissions or membership, even where a command would accept it.\n\n## Live state\n\n- `skrr agents show <agent-id> --expanded` — the full configuration, execution targets included.\n- `skrr agents instructions show <agent-id>` — the instruction blocks in order, with instance ids.\n- `skrr agents tone show <agent-id>` — the tone it actually writes in, and where that came from.\n- `skrr harnesses list` and `skrr machines list` — Harness ids and the Machines they run on.\n- `skrr memory mounts resolve --agent <agent-id>` — the Memory Stores it can read or write.\n\n## Related guides\n\n- `commitments` — what an Agent is responsible for over time, and making something happen later.\n- `learning` — teaching an Agent a preference or procedure that lasts.\n- `spaces` — admitting an Agent to a Space.\n- `store` — publishing an Agent release.",
|
|
1679
|
-
"hash": "
|
|
1679
|
+
"hash": "accb2eed6a5f6f0fe16c9bec8bd2233ecda3111976e36215e81ea61491ebe93b",
|
|
1680
1680
|
"tokens": 944,
|
|
1681
1681
|
"sections": [
|
|
1682
1682
|
{
|
|
@@ -1716,7 +1716,7 @@
|
|
|
1716
1716
|
"id": "memory",
|
|
1717
1717
|
"title": "Where an Agent's knowledge lives",
|
|
1718
1718
|
"readWhen": "you need to read or change what an Agent knows, or tell its Memory from its configuration",
|
|
1719
|
-
"tokens":
|
|
1719
|
+
"tokens": 891,
|
|
1720
1720
|
"aliases": [],
|
|
1721
1721
|
"explains": [
|
|
1722
1722
|
"MEMORY_NOT_MOUNTED",
|
|
@@ -1861,9 +1861,9 @@
|
|
|
1861
1861
|
"version": 4,
|
|
1862
1862
|
"routed": true,
|
|
1863
1863
|
"aliases": [],
|
|
1864
|
-
"body": "## Concept model\n\n| Noun | Question it answers |\n| --- | --- |\n| Memory | What does the agent durably know — a fact in a versioned Agent or Space Store? |\n| Lesson | What reviewed instruction applies — a Memory node typed `knowledge`, `preference`, `procedure`, `exemplar`, `rubric` or `capability`? |\n| Lesson state | May it reach runtime context — `candidate` (proposed), `active`, `needs_attention` (stopped because its evidence changed) or `archived` (history only)? |\n| Use receipt | What happened when one exact lesson version was used — `presented`, `applied`, `verified` or `failed`, at the strength the server assigned? |\n| Notepad | What did the agent note for itself — private scratch, never reviewed knowledge? |\n| Skill | What is installed and invoked — the executable artifact a reviewed lesson can compile into? |\n\n## Decide\n\n- A durable **fact** belongs in Memory. A **rule, preference or procedure** that should govern future work belongs in a lesson, and every lesson enters as a `candidate` a person must review.\n- The agent's own working notes belong in its **Notepad** — never something the person asked to stick.\n- A reviewed procedure that should become invocable or publishable becomes a **Skill**.\n- Never use a lesson to grant access: it cannot open a file, install a credential, widen a membership or authorize a tool action.\n\n## Workflow\n\n### Make a rule stick\n\n1. Restate it exactly — the trigger, the action and the exception — and choose its kind.\n2. File it for review. Never write it straight into canonical Memory or your own instructions.\n\nWhere the current Task is filed does not choose a Memory Store. The default below is deliberately\nAgent-owned; use a Space scope only after
|
|
1865
|
-
"hash": "
|
|
1866
|
-
"tokens":
|
|
1864
|
+
"body": "## Concept model\n\n| Noun | Question it answers |\n| --- | --- |\n| Memory | What does the agent durably know — a fact in a versioned Agent or Space Store? |\n| Lesson | What reviewed instruction applies — a Memory node typed `knowledge`, `preference`, `procedure`, `exemplar`, `rubric` or `capability`? |\n| Lesson state | May it reach runtime context — `candidate` (proposed), `active`, `needs_attention` (stopped because its evidence changed) or `archived` (history only)? |\n| Use receipt | What happened when one exact lesson version was used — `presented`, `applied`, `verified` or `failed`, at the strength the server assigned? |\n| Notepad | What did the agent note for itself — private scratch, never reviewed knowledge? |\n| Skill | What is installed and invoked — the executable artifact a reviewed lesson can compile into? |\n\n## Decide\n\n- A durable **fact** belongs in Memory. A **rule, preference or procedure** that should govern future work belongs in a lesson, and every lesson enters as a `candidate` a person must review.\n- The agent's own working notes belong in its **Notepad** — never something the person asked to stick.\n- A reviewed procedure that should become invocable or publishable becomes a **Skill**.\n- Never use a lesson to grant access: it cannot open a file, install a credential, widen a membership or authorize a tool action.\n\n## Workflow\n\n### Make a rule stick\n\n1. Restate it exactly — the trigger, the action and the exception — and choose its kind.\n2. File it for review. Never write it straight into canonical Memory or your own instructions.\n\nWhere the current Task is filed does not choose a Memory Store. The default below is deliberately\nAgent-owned; use a Space scope only after this session's mounts confirm that Space Store is mounted.\n\n`skrr memory mounts resolve` shows the mounts.\n\n```bash\nskrr memory proposals create --agent <agent-id> --scope agent:<agent-id> \\\n --kind <kind> --path <path> --content \"<the rule as stated>\"\n```\n\n3. Report it as awaiting the person's review — a candidate, not something learned.\n\n### Act on a lesson\n\n1. Only `active` lessons reach runtime context; check `applicability` and `exclusions` before relying on one.\n2. Act under ordinary tool and permission authority — the lesson itself grants nothing.\n3. The runtime records a use receipt against the exact version; a self-report counts as a claim, not an observation.\n\n## Authority\n\n| Actor | May do | Only a person may do |\n| --- | --- | --- |\n| Agent | Propose candidates; reinforce an active lesson whose content did not change; stop using one | Activate, change or restore active instructions |\n| Person | Review, activate and change instructions; dismiss candidates; grant evidence use; install and publish a Skill; own adaptive-learning consent | — |\n\n## Live state\n\n- `skrr memory proposals list --agent <agent-id> --scope <scope>` — proposals awaiting review (`proposed` is the default status).\n- `skrr learning status` — the person's adaptive-learning consent, learned state and serving fallback.\n- `skrr agents notepad show <agent-id>` — the agent's private notes.\n\n## Related guides\n\n- `store` — publishing a lesson as a Skill release, and installing Skills.\n- `agents` — the agent's Memory, Notepad and instructions.",
|
|
1865
|
+
"hash": "6c69c94f8070907742b4513feea16b30aa0f99cf632eb7ef74b85ea8991ed305",
|
|
1866
|
+
"tokens": 865,
|
|
1867
1867
|
"sections": [
|
|
1868
1868
|
{
|
|
1869
1869
|
"id": "model",
|
|
@@ -5437,7 +5437,7 @@
|
|
|
5437
5437
|
"id": "memory",
|
|
5438
5438
|
"title": "Where an Agent's knowledge lives",
|
|
5439
5439
|
"readWhen": "you need to read or change what an Agent knows, or tell its Memory from its configuration",
|
|
5440
|
-
"tokens":
|
|
5440
|
+
"tokens": 891,
|
|
5441
5441
|
"aliases": [],
|
|
5442
5442
|
"explains": [
|
|
5443
5443
|
"MEMORY_NOT_MOUNTED",
|
|
@@ -5513,7 +5513,7 @@
|
|
|
5513
5513
|
"id": "memory",
|
|
5514
5514
|
"title": "Where an Agent's knowledge lives",
|
|
5515
5515
|
"readWhen": "you need to read or change what an Agent knows, or tell its Memory from its configuration",
|
|
5516
|
-
"tokens":
|
|
5516
|
+
"tokens": 891,
|
|
5517
5517
|
"aliases": [],
|
|
5518
5518
|
"explains": [
|
|
5519
5519
|
"MEMORY_NOT_MOUNTED",
|
|
@@ -5590,7 +5590,7 @@
|
|
|
5590
5590
|
"id": "memory",
|
|
5591
5591
|
"title": "Where an Agent's knowledge lives",
|
|
5592
5592
|
"readWhen": "you need to read or change what an Agent knows, or tell its Memory from its configuration",
|
|
5593
|
-
"tokens":
|
|
5593
|
+
"tokens": 891,
|
|
5594
5594
|
"aliases": [],
|
|
5595
5595
|
"explains": [
|
|
5596
5596
|
"MEMORY_NOT_MOUNTED",
|
|
@@ -5625,9 +5625,9 @@
|
|
|
5625
5625
|
"MEMORY_VERSION_CONFLICT",
|
|
5626
5626
|
"NODE_REFERENCE_REQUIRED"
|
|
5627
5627
|
],
|
|
5628
|
-
"body": "Read this when you need to read or change what an Agent knows, or tell its Memory from its configuration.\n\n| Where | What it holds | Who changes it |\n| ------------------ | -------------------------------------------------------------------------- | ---------------------------------------- |\n| Agent Memory Store | What this Agent knows, as versioned topics | The Agent, through its own mounted store |\n| Space Memory Store | What a Space knows; mounted only for a member of that Space | An Agent proposes; a person approves |\n| Notepad | One person's private notes to this Agent, read on that person's chat turns | That person |\n| Persona files | Who the Agent is and who it works for (SOUL, IDENTITY, USER and others) | The owner, or the Agent about itself |\n\nInstructions and tone are configuration, not Memory: what the Agent must always do goes in an\ninstruction block, and how it writes goes in its tone.\n\nRules:\n\n- Resolve the mounts before you read or write. A store mounted read-only takes neither writes nor\n proposals from you: keep the topic in the Agent's own store, where a person can promote it.\n-
|
|
5629
|
-
"hash": "
|
|
5630
|
-
"tokens":
|
|
5628
|
+
"body": "Read this when you need to read or change what an Agent knows, or tell its Memory from its configuration.\n\n| Where | What it holds | Who changes it |\n| ------------------ | -------------------------------------------------------------------------- | ---------------------------------------- |\n| Agent Memory Store | What this Agent knows, as versioned topics | The Agent, through its own mounted store |\n| Space Memory Store | What a Space knows; mounted only for a member of that Space | An Agent proposes; a person approves |\n| Notepad | One person's private notes to this Agent, read on that person's chat turns | That person |\n| Persona files | Who the Agent is and who it works for (SOUL, IDENTITY, USER and others) | The owner, or the Agent about itself |\n\nInstructions and tone are configuration, not Memory: what the Agent must always do goes in an\ninstruction block, and how it writes goes in its tone.\n\nRules:\n\n- Resolve the mounts before you read or write. A store mounted read-only takes neither writes nor\n proposals from you: keep the topic in the Agent's own store, where a person can promote it.\n- The Space a Task or call names chooses where that work is filed and supplies request context; it\n does **not** select or mount a Space Memory Store. Resolve the mounts first, then name one of the\n mounted scopes. When the requested Space Store is absent, use the Agent Store only for\n Agent-owned knowledge; never treat that fallback as shared Space Memory.\n- An Agent's change to a Space Memory Store is always a proposal. It changes nothing until a\n person approves it, and only a person may approve promoting an Agent topic into a Space or\n admitting personal data to one.\n- A change to an existing topic names the version it read. When the topic has moved on, read the\n latest version and retry against it; never overwrite it.\n- Everyone with edit access to the Agent can read its Agent Memory Store.\n- What the Agent may remember (read and write scopes, retention, evidence) is governance, and\n governance is the owner's.\n\nUse the canonical commands: `skrr memory mounts`, `skrr memory topics`, `skrr memory proposals`,\n`skrr memory versions`. The ungrouped commands such as `skrr memory list` and `skrr memory tree`\naddress older pools: what one surface holds does not exist in the other. `--agent` selects whose\nMemory you act on; it does not change who is signed in. `--space` chooses where a command's work is\nfiled and never mounts a store: run `skrr memory mounts resolve` first, then pass one of the\nmounted scopes with `--scope`.\n\n## Example\n\nFind what the Agent already knows before adding to it, then propose the addition.\n\n```bash\nskrr memory mounts resolve --agent <agent-id> --space <space-id> --json\nskrr memory topics list --agent <agent-id> --space <space-id> --scope \"space:<space-id>\"\nskrr memory proposals create --agent <agent-id> --space <space-id> --scope \"space:<space-id>\" \\\n --path /team/release-process --content \"Releases need a green smoke test.\" --evidence task:<task-id>\n```\n\n## Refusals\n\n| Code | Cause | Fix |\n| -------------------------------- | ------------------------------------------------ | ------------------------------------------------------- |\n| `MEMORY_NOT_MOUNTED` | The target store is not mounted for this session; naming a Space alone does not mount it | Resolve the mounts; choose a writable mounted scope, or use Agent-owned Memory without claiming it is shared |\n| `MEMORY_STORE_READ_ONLY` | The target store is mounted read-only | Write to the Agent's own store; a person can promote it |\n| `MEMORY_SPACE_PROPOSAL_REQUIRED` | An Agent wrote straight to a Space Memory Store | Submit it as a proposal |\n| `MEMORY_VERSION_CONFLICT` | The topic changed since you read it | Read the latest version and retry against it |\n| `NODE_REFERENCE_REQUIRED` | The request named no topic | Pass one of `memoryId`, `nodeId` or `path` |",
|
|
5629
|
+
"hash": "8a5bafc440947aa93782c6d0b196c08f83a0656c4eafd1439990ba99f35c30ce",
|
|
5630
|
+
"tokens": 891,
|
|
5631
5631
|
"sections": [
|
|
5632
5632
|
{
|
|
5633
5633
|
"id": "model",
|
|
@@ -5666,7 +5666,7 @@
|
|
|
5666
5666
|
"id": "memory",
|
|
5667
5667
|
"title": "Where an Agent's knowledge lives",
|
|
5668
5668
|
"readWhen": "you need to read or change what an Agent knows, or tell its Memory from its configuration",
|
|
5669
|
-
"tokens":
|
|
5669
|
+
"tokens": 891,
|
|
5670
5670
|
"aliases": [],
|
|
5671
5671
|
"explains": [
|
|
5672
5672
|
"MEMORY_NOT_MOUNTED",
|
|
@@ -5741,7 +5741,7 @@
|
|
|
5741
5741
|
"id": "memory",
|
|
5742
5742
|
"title": "Where an Agent's knowledge lives",
|
|
5743
5743
|
"readWhen": "you need to read or change what an Agent knows, or tell its Memory from its configuration",
|
|
5744
|
-
"tokens":
|
|
5744
|
+
"tokens": 891,
|
|
5745
5745
|
"aliases": [],
|
|
5746
5746
|
"explains": [
|
|
5747
5747
|
"MEMORY_NOT_MOUNTED",
|
|
@@ -775,6 +775,12 @@ function endsWithIgnoringWhitespace(whole, tail) {
|
|
|
775
775
|
const wanted = solid(tail);
|
|
776
776
|
return wanted.length > 0 && solid(whole).endsWith(wanted);
|
|
777
777
|
}
|
|
778
|
+
/** `head` is the start of `whole`, whitespace aside. */
|
|
779
|
+
function startsWithIgnoringWhitespace(whole, head) {
|
|
780
|
+
const solid = (value) => value.replace(/\s+/g, '');
|
|
781
|
+
const wanted = solid(head);
|
|
782
|
+
return wanted.length > 0 && solid(whole).startsWith(wanted);
|
|
783
|
+
}
|
|
778
784
|
class AgenticStreamClient {
|
|
779
785
|
options;
|
|
780
786
|
socket = null;
|
|
@@ -2456,10 +2462,18 @@ class AgenticStreamClient {
|
|
|
2456
2462
|
// `' \n\n::::skrr-ui{'`), so the harness's last block is not a byte-for-byte suffix of the
|
|
2457
2463
|
// accumulation even though it is its tail, and taking it as the answer would drop
|
|
2458
2464
|
// everything the agent said before the tool call (OSK-16934).
|
|
2465
|
+
//
|
|
2466
|
+
// The other way round is the same defect from the other end: a result that is a strict
|
|
2467
|
+
// PREFIX of the accumulation was cut to a length cap, not written as the answer. The daemon
|
|
2468
|
+
// keeps the first 4000 characters of a turn's text for the result it reports, so every local
|
|
2469
|
+
// answer longer than that came back as its first 4000 characters, cut mid-word, with
|
|
2470
|
+
// `status: completed` (OSK-20616). What streamed is the longer record of the same words.
|
|
2459
2471
|
const accumulationIsSuperset = finalText.length > 0 &&
|
|
2460
2472
|
this.accumulated.length > finalText.length &&
|
|
2461
2473
|
(this.accumulated.endsWith(finalText) ||
|
|
2462
|
-
endsWithIgnoringWhitespace(this.accumulated, finalText)
|
|
2474
|
+
endsWithIgnoringWhitespace(this.accumulated, finalText) ||
|
|
2475
|
+
this.accumulated.startsWith(finalText) ||
|
|
2476
|
+
startsWithIgnoringWhitespace(this.accumulated, finalText));
|
|
2463
2477
|
if (event.publicProjection === 'lookback_answer_v1' && typeof event.result === 'string') {
|
|
2464
2478
|
this.accumulated = event.result;
|
|
2465
2479
|
}
|
|
@@ -38,9 +38,22 @@ export declare function plainCredentialEnvelopeWarning(args: readonly unknown[])
|
|
|
38
38
|
export declare const CREDENTIAL_KEY_CHANGED_NOTICE: string;
|
|
39
39
|
/**
|
|
40
40
|
* The one line an unreadable device key prints when no credential-key change
|
|
41
|
-
* explains it
|
|
42
|
-
*
|
|
41
|
+
* explains it (OSK-20506).
|
|
42
|
+
*
|
|
43
|
+
* The CLI never enrolls or requires a device key (OSK-12063), so this degrades a
|
|
44
|
+
* proof, not a sign-in: say exactly that. What it must not do is point at
|
|
45
|
+
* `skrr login`. That signs this CLI in on its own and never creates or replaces a
|
|
46
|
+
* device key, so a person who followed it would be told the same thing on the next
|
|
47
|
+
* command. Only an interactive daemon sign-in mints a key and re-pins it, and which
|
|
48
|
+
* one depends on who runs the daemon, so this uses the sentence the hand-off
|
|
49
|
+
* refusals use for the same repair (`daemonSignInRemedy`) rather than a second
|
|
50
|
+
* spelling.
|
|
51
|
+
*
|
|
52
|
+
* `profile` names the command for a non-default profile: a bare `skrr daemon login`
|
|
53
|
+
* signs the default daemon in and leaves this one as it was (OSK-16435).
|
|
43
54
|
*/
|
|
55
|
+
export declare function deviceKeyRecoveryRequiredNotice(profile?: string): string;
|
|
56
|
+
/** The notice for the default profile. */
|
|
44
57
|
export declare const DEVICE_KEY_RECOVERY_REQUIRED_NOTICE: string;
|
|
45
58
|
export declare function createCredentialEnvelopeWarningPresenter(): (args: readonly unknown[]) => string | null;
|
|
46
59
|
type DedicatedGenerationPreparationOptions = {
|
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.CliCredentialInitializationError = exports.DEVICE_KEY_RECOVERY_REQUIRED_NOTICE = exports.CREDENTIAL_KEY_CHANGED_NOTICE = void 0;
|
|
7
7
|
exports.plainCredentialEnvelopeWarning = plainCredentialEnvelopeWarning;
|
|
8
|
+
exports.deviceKeyRecoveryRequiredNotice = deviceKeyRecoveryRequiredNotice;
|
|
8
9
|
exports.createCredentialEnvelopeWarningPresenter = createCredentialEnvelopeWarningPresenter;
|
|
9
10
|
exports.prepareDedicatedRuntimeAuthGeneration = prepareDedicatedRuntimeAuthGeneration;
|
|
10
11
|
exports.ensureAuthCoreConfigured = ensureAuthCoreConfigured;
|
|
@@ -38,10 +39,12 @@ const node_fs_1 = __importDefault(require("node:fs"));
|
|
|
38
39
|
const node_path_1 = __importDefault(require("node:path"));
|
|
39
40
|
const proper_lockfile_1 = __importDefault(require("proper-lockfile"));
|
|
40
41
|
const auth_core_1 = require("@skrr-ai/auth-core");
|
|
42
|
+
const cli_handoff_wire_1 = require("@skrr-ai/auth-core/cli-handoff-wire");
|
|
41
43
|
const cred_envelope_1 = require("./cred-envelope");
|
|
42
44
|
const device_identity_1 = require("./device-identity");
|
|
43
45
|
const auth_storage_1 = require("./auth-storage");
|
|
44
46
|
const keychain_1 = require("./keychain");
|
|
47
|
+
const daemon_command_hint_1 = require("./daemon-command-hint");
|
|
45
48
|
function envFlag(name) {
|
|
46
49
|
const v = process.env[name];
|
|
47
50
|
return v === '1' || v === 'true' || v === 'TRUE';
|
|
@@ -117,13 +120,33 @@ const DEVICE_KEY_DECRYPT_FAILED = '[deviceIdentity] private_key_decrypt_failed';
|
|
|
117
120
|
const DEVICE_KEY_RECOVERY_REQUIRED = '[deviceIdentity] recovery_required';
|
|
118
121
|
/**
|
|
119
122
|
* The one line an unreadable device key prints when no credential-key change
|
|
120
|
-
* explains it
|
|
121
|
-
*
|
|
123
|
+
* explains it (OSK-20506).
|
|
124
|
+
*
|
|
125
|
+
* The CLI never enrolls or requires a device key (OSK-12063), so this degrades a
|
|
126
|
+
* proof, not a sign-in: say exactly that. What it must not do is point at
|
|
127
|
+
* `skrr login`. That signs this CLI in on its own and never creates or replaces a
|
|
128
|
+
* device key, so a person who followed it would be told the same thing on the next
|
|
129
|
+
* command. Only an interactive daemon sign-in mints a key and re-pins it, and which
|
|
130
|
+
* one depends on who runs the daemon, so this uses the sentence the hand-off
|
|
131
|
+
* refusals use for the same repair (`daemonSignInRemedy`) rather than a second
|
|
132
|
+
* spelling.
|
|
133
|
+
*
|
|
134
|
+
* `profile` names the command for a non-default profile: a bare `skrr daemon login`
|
|
135
|
+
* signs the default daemon in and leaves this one as it was (OSK-16435).
|
|
122
136
|
*/
|
|
123
|
-
|
|
124
|
-
|
|
137
|
+
function deviceKeyRecoveryRequiredNotice(profile = keychain_1.DEFAULT_PROFILE) {
|
|
138
|
+
const loginCommand = (0, daemon_command_hint_1.daemonCommandHint)('login', { profile });
|
|
139
|
+
return ("warning: this machine's stored device key could not be read, so skrr sends requests " +
|
|
140
|
+
`without a device proof. To replace it, ${(0, cli_handoff_wire_1.daemonSignInRemedy)({ repinsDeviceKey: true, loginCommand })}. ` +
|
|
141
|
+
'(DEBUG=1 shows the underlying error.)');
|
|
142
|
+
}
|
|
143
|
+
/** The notice for the default profile. */
|
|
144
|
+
exports.DEVICE_KEY_RECOVERY_REQUIRED_NOTICE = deviceKeyRecoveryRequiredNotice(keychain_1.DEFAULT_PROFILE);
|
|
125
145
|
function createCredentialEnvelopeWarningPresenter() {
|
|
126
146
|
let keyChanged = false;
|
|
147
|
+
// auth-core named a failure as the DEVICE key's (see below): the person has one
|
|
148
|
+
// line to read for it, and it is not the credential line.
|
|
149
|
+
let deviceKeyUnreadable = false;
|
|
127
150
|
return (args) => {
|
|
128
151
|
const [message, metadata] = args;
|
|
129
152
|
const event = typeof message === 'string' && message.startsWith('[credEnvelope] ')
|
|
@@ -157,10 +180,28 @@ function createCredentialEnvelopeWarningPresenter() {
|
|
|
157
180
|
(message === DEVICE_KEY_DECRYPT_FAILED || message === DEVICE_KEY_RECOVERY_REQUIRED)) {
|
|
158
181
|
return '';
|
|
159
182
|
}
|
|
183
|
+
// No key change in THIS process, yet the device key will not open (the
|
|
184
|
+
// credential key changed in an earlier one, or the file is damaged).
|
|
185
|
+
// auth-core's device identity labels that read with its own hint, so the
|
|
186
|
+
// producer says WHAT failed and this decides what a person reads. The
|
|
187
|
+
// generic line would say "signing in again rebuilds it", and `skrr login`
|
|
188
|
+
// does not rebuild a device key. Print nothing for it, and nothing for the
|
|
189
|
+
// device identity's own echo of the same failure: `recovery_required`
|
|
190
|
+
// follows and carries the one line (OSK-20506). The flag is set by that
|
|
191
|
+
// hint alone, so another credential that will not open still gets its own
|
|
192
|
+
// line below.
|
|
193
|
+
if (event === 'cred_envelope.read.decrypt_failed' &&
|
|
194
|
+
meta.hint === auth_core_1.DEVICE_KEY_UNREADABLE_CREDENTIAL_HINT) {
|
|
195
|
+
deviceKeyUnreadable = true;
|
|
196
|
+
return '';
|
|
197
|
+
}
|
|
198
|
+
if (deviceKeyUnreadable && message === DEVICE_KEY_DECRYPT_FAILED)
|
|
199
|
+
return '';
|
|
160
200
|
// Without a key change an unreadable device key is a real fault: one
|
|
161
201
|
// plain line instead of an object dump.
|
|
162
|
-
if (message === DEVICE_KEY_RECOVERY_REQUIRED)
|
|
163
|
-
return
|
|
202
|
+
if (message === DEVICE_KEY_RECOVERY_REQUIRED) {
|
|
203
|
+
return deviceKeyRecoveryRequiredNotice((0, keychain_1.getActiveProfile)());
|
|
204
|
+
}
|
|
164
205
|
return plainCredentialEnvelopeWarning(args);
|
|
165
206
|
};
|
|
166
207
|
}
|
|
@@ -453,6 +453,35 @@ const AGENT_CRITICAL_COMMANDS = [
|
|
|
453
453
|
'agent:message:send',
|
|
454
454
|
'tasks:complete',
|
|
455
455
|
];
|
|
456
|
+
/**
|
|
457
|
+
* The text of a command file, with a pure re-export alias read as its target.
|
|
458
|
+
*
|
|
459
|
+
* `export { default } from '../search/tasks';` is a second spelling of another
|
|
460
|
+
* command: oclif loads the same class, so the alias has the target's flags,
|
|
461
|
+
* description and args. Reading the alias's own few lines reports a missing
|
|
462
|
+
* `--json` and a missing description that the command in fact has, and the only
|
|
463
|
+
* way to silence that would be to copy the description into the alias, where
|
|
464
|
+
* the two spellings could drift apart.
|
|
465
|
+
*
|
|
466
|
+
* One hop, and only when the re-export is the whole module (comments aside), so
|
|
467
|
+
* a file that adds its own code is still audited as itself.
|
|
468
|
+
*/
|
|
469
|
+
function readCommandSource(file) {
|
|
470
|
+
const source = fs.readFileSync(file, 'utf8');
|
|
471
|
+
const code = source
|
|
472
|
+
.replace(/\/\*[\s\S]*?\*\//g, '')
|
|
473
|
+
.replace(/\/\/.*$/gm, '')
|
|
474
|
+
.trim();
|
|
475
|
+
const alias = code.match(/^export\s*\{\s*default\s*\}\s*from\s*['"](\.{1,2}\/[^'"]+)['"]\s*;?$/);
|
|
476
|
+
if (!alias)
|
|
477
|
+
return source;
|
|
478
|
+
const target = path.resolve(path.dirname(file), alias[1]);
|
|
479
|
+
for (const candidate of [`${target}.ts`, path.join(target, 'index.ts')]) {
|
|
480
|
+
if (fs.existsSync(candidate))
|
|
481
|
+
return fs.readFileSync(candidate, 'utf8');
|
|
482
|
+
}
|
|
483
|
+
return source;
|
|
484
|
+
}
|
|
456
485
|
function auditCommands({ rootDir, manifest, }) {
|
|
457
486
|
const issues = [];
|
|
458
487
|
const commands = manifest?.commands ?? {};
|
|
@@ -512,7 +541,7 @@ function auditCommands({ rootDir, manifest, }) {
|
|
|
512
541
|
sourceCommandFiles = files.length;
|
|
513
542
|
for (const file of files) {
|
|
514
543
|
const rel = path.relative(sourceRoot, file);
|
|
515
|
-
const source =
|
|
544
|
+
const source = readCommandSource(file);
|
|
516
545
|
const command = commandIdFromRelativePath(rel);
|
|
517
546
|
sourceCommandIds.add(command);
|
|
518
547
|
const hasFromJson = /['"]from-json['"]/.test(source);
|