@namzu/cli 10.0.0 → 12.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +390 -46
- package/dist/cli.d.ts +15 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +133 -4
- package/dist/cli.js.map +1 -1
- package/dist/commands/acp.d.ts +29 -0
- package/dist/commands/acp.d.ts.map +1 -0
- package/dist/commands/acp.js +156 -0
- package/dist/commands/acp.js.map +1 -0
- package/dist/commands/doctor.d.ts +12 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +18 -2
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/drain.d.ts +2 -2
- package/dist/commands/drain.d.ts.map +1 -1
- package/dist/commands/drain.js +31 -8
- package/dist/commands/drain.js.map +1 -1
- package/dist/commands/run-flags.d.ts.map +1 -1
- package/dist/commands/run-flags.js +33 -0
- package/dist/commands/run-flags.js.map +1 -1
- package/dist/commands/run-stream.d.ts +3 -3
- package/dist/commands/run-stream.d.ts.map +1 -1
- package/dist/commands/run-stream.js +27 -10
- package/dist/commands/run-stream.js.map +1 -1
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +50 -4
- package/dist/commands/run.js.map +1 -1
- package/dist/commands/types.d.ts +10 -0
- package/dist/commands/types.d.ts.map +1 -1
- package/dist/config/load.d.ts +64 -0
- package/dist/config/load.d.ts.map +1 -1
- package/dist/config/load.js +156 -20
- package/dist/config/load.js.map +1 -1
- package/dist/config/schema.d.ts +88 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js.map +1 -1
- package/dist/context/capabilities.d.ts +88 -0
- package/dist/context/capabilities.d.ts.map +1 -0
- package/dist/context/capabilities.js +160 -0
- package/dist/context/capabilities.js.map +1 -0
- package/dist/context/sandbox.d.ts +54 -0
- package/dist/context/sandbox.d.ts.map +1 -0
- package/dist/context/sandbox.js +61 -0
- package/dist/context/sandbox.js.map +1 -0
- package/dist/doctor/checks/index.d.ts +6 -1
- package/dist/doctor/checks/index.d.ts.map +1 -1
- package/dist/doctor/checks/index.js +45 -2
- package/dist/doctor/checks/index.js.map +1 -1
- package/dist/doctor/checks/invariants.d.ts +23 -0
- package/dist/doctor/checks/invariants.d.ts.map +1 -0
- package/dist/doctor/checks/invariants.js +79 -0
- package/dist/doctor/checks/invariants.js.map +1 -0
- package/dist/doctor/checks/logging.d.ts +10 -0
- package/dist/doctor/checks/logging.d.ts.map +1 -0
- package/dist/doctor/checks/logging.js +69 -0
- package/dist/doctor/checks/logging.js.map +1 -0
- package/dist/doctor/checks/session-export.d.ts +21 -0
- package/dist/doctor/checks/session-export.d.ts.map +1 -0
- package/dist/doctor/checks/session-export.js +62 -0
- package/dist/doctor/checks/session-export.js.map +1 -0
- package/dist/doctor/checks/telemetry.d.ts +15 -28
- package/dist/doctor/checks/telemetry.d.ts.map +1 -1
- package/dist/doctor/checks/telemetry.js +34 -54
- package/dist/doctor/checks/telemetry.js.map +1 -1
- package/dist/doctor/checks/vault.d.ts +4 -20
- package/dist/doctor/checks/vault.d.ts.map +1 -1
- package/dist/doctor/checks/vault.js +58 -19
- package/dist/doctor/checks/vault.js.map +1 -1
- package/dist/doctor/registry.d.ts.map +1 -1
- package/dist/doctor/registry.js +13 -6
- package/dist/doctor/registry.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/integrations/files/attachment-store.d.ts +44 -0
- package/dist/integrations/files/attachment-store.d.ts.map +1 -0
- package/dist/integrations/files/attachment-store.js +86 -0
- package/dist/integrations/files/attachment-store.js.map +1 -0
- package/dist/integrations/providers/credential-provider.d.ts +39 -0
- package/dist/integrations/providers/credential-provider.d.ts.map +1 -0
- package/dist/integrations/providers/credential-provider.js +74 -0
- package/dist/integrations/providers/credential-provider.js.map +1 -0
- package/dist/integrations/providers/discover.d.ts.map +1 -1
- package/dist/integrations/providers/discover.js +15 -3
- package/dist/integrations/providers/discover.js.map +1 -1
- package/dist/integrations/providers/oauth.d.ts.map +1 -1
- package/dist/integrations/providers/oauth.js +24 -1
- package/dist/integrations/providers/oauth.js.map +1 -1
- package/dist/integrations/sessions/store.d.ts +2 -2
- package/dist/integrations/sessions/store.d.ts.map +1 -1
- package/dist/integrations/sessions/store.js +21 -9
- package/dist/integrations/sessions/store.js.map +1 -1
- package/dist/integrations/subagents/runtime.d.ts +3 -3
- package/dist/integrations/subagents/runtime.d.ts.map +1 -1
- package/dist/integrations/subagents/runtime.js +11 -11
- package/dist/integrations/subagents/runtime.js.map +1 -1
- package/dist/integrations/telemetry/session-export.d.ts +99 -0
- package/dist/integrations/telemetry/session-export.d.ts.map +1 -0
- package/dist/integrations/telemetry/session-export.js +119 -0
- package/dist/integrations/telemetry/session-export.js.map +1 -0
- package/dist/logging.d.ts +79 -0
- package/dist/logging.d.ts.map +1 -0
- package/dist/logging.js +67 -0
- package/dist/logging.js.map +1 -0
- package/dist/permissions/rules.d.ts +3 -3
- package/dist/permissions/rules.d.ts.map +1 -1
- package/dist/permissions/rules.js +1 -1
- package/dist/permissions/rules.js.map +1 -1
- package/dist/skills/store.d.ts +1 -1
- package/dist/skills/store.js +1 -1
- package/dist/tui/App.d.ts.map +1 -1
- package/dist/tui/App.js +93 -6
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/StatusBar.d.ts +1 -1
- package/dist/tui/StatusBar.d.ts.map +1 -1
- package/dist/tui/agent.d.ts +65 -24
- package/dist/tui/agent.d.ts.map +1 -1
- package/dist/tui/agent.js +337 -122
- package/dist/tui/agent.js.map +1 -1
- package/dist/tui/index.d.ts.map +1 -1
- package/dist/tui/index.js +17 -6
- package/dist/tui/index.js.map +1 -1
- package/dist/tui/log-pane.d.ts +48 -0
- package/dist/tui/log-pane.d.ts.map +1 -0
- package/dist/tui/log-pane.js +106 -0
- package/dist/tui/log-pane.js.map +1 -0
- package/dist/tui/slashCommands.d.ts +134 -11
- package/dist/tui/slashCommands.d.ts.map +1 -1
- package/dist/tui/slashCommands.js +169 -15
- package/dist/tui/slashCommands.js.map +1 -1
- package/dist/tui/types.d.ts +18 -2
- package/dist/tui/types.d.ts.map +1 -1
- package/package.json +8 -6
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { appendFileSync, mkdirSync } from 'node:fs';
|
|
2
|
+
import { dirname, resolve } from 'node:path';
|
|
3
|
+
import { probeOptionalPackage } from '../../context/capabilities.js';
|
|
4
|
+
/** Why a configured export could not be started. */
|
|
5
|
+
export class SessionExportUnavailableError extends Error {
|
|
6
|
+
reason;
|
|
7
|
+
constructor(reason, cause) {
|
|
8
|
+
super(reason === 'absent'
|
|
9
|
+
? 'telemetry.sessionExport is configured but "@namzu/telemetry" is not installed, so nothing would be recorded. Install it (npm i @namzu/telemetry), or remove telemetry.sessionExport from your config. Refusing rather than running a session whose export silently does not exist.'
|
|
10
|
+
: `telemetry.sessionExport is configured but "@namzu/telemetry" failed to load (${cause ?? 'no detail'}). Reinstall it, or remove telemetry.sessionExport from your config.`);
|
|
11
|
+
this.reason = reason;
|
|
12
|
+
this.name = 'SessionExportUnavailableError';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
const TELEMETRY_SPECIFIER = '@namzu/telemetry';
|
|
16
|
+
/**
|
|
17
|
+
* Load the optional package, separating "not installed" from "installed and
|
|
18
|
+
* unusable" the same way `context/capabilities.ts` does — and for the same
|
|
19
|
+
* reason: the two send a reader to different places.
|
|
20
|
+
*
|
|
21
|
+
* Takes the specifier so a test can drive the REAL resolution path with a
|
|
22
|
+
* name that cannot resolve. Everything else in this file is tested through
|
|
23
|
+
* an injected loader, which proves what `attachSessionExport` does with a
|
|
24
|
+
* refusal and proves nothing about where the refusal comes from — a
|
|
25
|
+
* mutation replacing this `throw` with a stub module survived until this was
|
|
26
|
+
* separated out.
|
|
27
|
+
*/
|
|
28
|
+
export async function loadTelemetryFrom(specifier) {
|
|
29
|
+
// Through the SAME probe the doctor and the boot narrative use, rather
|
|
30
|
+
// than a second resolution here. Two answers to "is @namzu/telemetry
|
|
31
|
+
// installed" is two chances to disagree, and the one that drifted would be
|
|
32
|
+
// the one deciding whether a session gets recorded.
|
|
33
|
+
//
|
|
34
|
+
// It also inherits the fix: `require.resolve` reports an installed
|
|
35
|
+
// ESM-only package as absent, which would have produced this refusal
|
|
36
|
+
// against a machine that was configured correctly.
|
|
37
|
+
const probe = await probeOptionalPackage(specifier);
|
|
38
|
+
if (probe.state === 'absent')
|
|
39
|
+
throw new SessionExportUnavailableError('absent');
|
|
40
|
+
if (probe.state === 'broken')
|
|
41
|
+
throw new SessionExportUnavailableError('broken', probe.error.message);
|
|
42
|
+
return (await import(specifier));
|
|
43
|
+
}
|
|
44
|
+
async function loadTelemetry(loader) {
|
|
45
|
+
if (loader)
|
|
46
|
+
return await loader();
|
|
47
|
+
return await loadTelemetryFrom(TELEMETRY_SPECIFIER);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* A JSONL file, one record per line.
|
|
51
|
+
*
|
|
52
|
+
* `appendFileSync` rather than a stream, and that is a deliberate trade: a
|
|
53
|
+
* stream would not block, but a stream's buffered tail is lost when the
|
|
54
|
+
* process exits on a signal, and the whole value of an exported session is
|
|
55
|
+
* that it survives the run that produced it. The listener already never
|
|
56
|
+
* waits on `emit` — the synchronous write happens inside a call the run does
|
|
57
|
+
* not await, so the cost lands on the exporting call and not on the model
|
|
58
|
+
* loop.
|
|
59
|
+
*/
|
|
60
|
+
export function fileSink(destinationPath) {
|
|
61
|
+
const path = resolve(destinationPath);
|
|
62
|
+
let ensured = false;
|
|
63
|
+
return {
|
|
64
|
+
emit(record) {
|
|
65
|
+
if (!ensured) {
|
|
66
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
67
|
+
ensured = true;
|
|
68
|
+
}
|
|
69
|
+
appendFileSync(path, `${JSON.stringify(record)}\n`, 'utf-8');
|
|
70
|
+
},
|
|
71
|
+
// Nothing is buffered, so there is nothing to drain — and saying so is
|
|
72
|
+
// better than an empty function that reads as an unfinished one.
|
|
73
|
+
shutdown: async () => { },
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
export async function attachSessionExport(options) {
|
|
77
|
+
const telemetry = await loadTelemetry(options.loader);
|
|
78
|
+
const sink = options.sink ?? fileSink(options.config.destination);
|
|
79
|
+
// Omitted means the shipped redactor; `[]` means none. A config reaches
|
|
80
|
+
// "no redaction" only by saying so.
|
|
81
|
+
const redactors = (options.config.redactors ?? ['secrets']).map((name) => {
|
|
82
|
+
switch (name) {
|
|
83
|
+
case 'secrets':
|
|
84
|
+
return telemetry.secretRedactor();
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
const exportConfig = {
|
|
88
|
+
sink,
|
|
89
|
+
destination: options.config.destination,
|
|
90
|
+
...(options.config.eventTypes !== undefined ? { eventTypes: options.config.eventTypes } : {}),
|
|
91
|
+
redactors,
|
|
92
|
+
};
|
|
93
|
+
return {
|
|
94
|
+
listener: telemetry.createSessionExportListener(exportConfig),
|
|
95
|
+
shutdown: () => sink.shutdown(),
|
|
96
|
+
disclosure: telemetry.describeSessionExport(exportConfig),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* The disclosure when export is NOT configured.
|
|
101
|
+
*
|
|
102
|
+
* Goes through the same function as the configured case so the two cannot
|
|
103
|
+
* drift into reading alike — which is the property
|
|
104
|
+
* `describeSessionExport`'s own test pins, and which is worth nothing if
|
|
105
|
+
* this branch hand-writes its own sentence instead.
|
|
106
|
+
*/
|
|
107
|
+
export async function describeSessionExportOff(loader) {
|
|
108
|
+
try {
|
|
109
|
+
const telemetry = await loadTelemetry(loader);
|
|
110
|
+
return telemetry.describeSessionExport();
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
// `@namzu/telemetry` absent AND export unconfigured is the ordinary
|
|
114
|
+
// case, not a problem: there is nothing to disclose because there is
|
|
115
|
+
// nothing installed that could export.
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=session-export.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-export.js","sourceRoot":"","sources":["../../../src/integrations/telemetry/session-export.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log level + format resolution for the CLI's five entry points that used
|
|
3
|
+
* to force the SDK logger's level to `silent` via `configureLogger` and
|
|
4
|
+
* never turn it back on: `tui/index.tsx`, `commands/run.ts`,
|
|
5
|
+
* `commands/drain.ts` and `commands/run-stream.ts` (twice — `run-stream`
|
|
6
|
+
* itself and `providers-json`). LOG-05.
|
|
7
|
+
*
|
|
8
|
+
* Kept out of `config/load.ts`'s cascade on purpose. That system merges
|
|
9
|
+
* four sources for `format`/`quiet`/`permissions`/`sandbox`, all of them
|
|
10
|
+
* either boolean or a closed enum with a config-file counterpart.
|
|
11
|
+
* `NAMZU_LOG_LEVEL` has no config-file counterpart in this increment and is
|
|
12
|
+
* not boolean-shaped — it names a level directly, string-valued, the same
|
|
13
|
+
* way `--verbose`/`--quiet` do. Precedence here is exactly what the design
|
|
14
|
+
* specifies and nothing more: an explicit flag beats the environment beats
|
|
15
|
+
* the default that used to be silence.
|
|
16
|
+
*/
|
|
17
|
+
import type { LevelFilter, LogSink } from '@namzu/sdk';
|
|
18
|
+
export type LogFormat = 'pretty' | 'json';
|
|
19
|
+
/** What every entry point installs as its process sink, resolved once per
|
|
20
|
+
* invocation in `cli.ts#getContext()` and threaded through
|
|
21
|
+
* `CommandContext`/`TuiContext`. */
|
|
22
|
+
export interface ResolvedLogging {
|
|
23
|
+
readonly level: LevelFilter;
|
|
24
|
+
readonly format: LogFormat;
|
|
25
|
+
}
|
|
26
|
+
export interface LogLevelFlags {
|
|
27
|
+
/** `-v, --verbose` as Commander parsed it — `undefined` unless given. */
|
|
28
|
+
readonly verbose?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* `-q, --quiet` as Commander parsed it — `undefined` unless given.
|
|
31
|
+
* Reuses the CLI's existing global flag rather than minting a second
|
|
32
|
+
* "quiet" that means something different depending which one you typed.
|
|
33
|
+
*/
|
|
34
|
+
readonly quiet?: boolean;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* `--verbose` -> `debug`, `--quiet` -> `warn`, otherwise `NAMZU_LOG_LEVEL`
|
|
38
|
+
* if it names a real level, otherwise `info` — the floor that used to be
|
|
39
|
+
* silence.
|
|
40
|
+
*
|
|
41
|
+
* `cli.ts` declares `--verbose` and `--quiet` as a `.conflicts()`-paired
|
|
42
|
+
* pair of Commander options, so through the CLI itself at most one of
|
|
43
|
+
* `flags.verbose` / `flags.quiet` is ever true at once. The `verbose`-first
|
|
44
|
+
* check below is what a caller that builds `LogLevelFlags` by hand — every
|
|
45
|
+
* test in `logging.test.ts` — gets instead of relying on that invariant.
|
|
46
|
+
*/
|
|
47
|
+
export declare function resolveLogLevel(flags: LogLevelFlags, env?: NodeJS.ProcessEnv): LevelFilter;
|
|
48
|
+
export interface LogFormatFlags {
|
|
49
|
+
/**
|
|
50
|
+
* `--log-format <pretty|json>`. Commander's `.choices(['pretty','json'])`
|
|
51
|
+
* already rejects anything else at parse time, so `undefined` is the
|
|
52
|
+
* only other value `cli.ts` can hand this. Re-checked below anyway
|
|
53
|
+
* because a caller building this by hand (every test in
|
|
54
|
+
* `logging.test.ts`) is not bound by what Commander would have refused.
|
|
55
|
+
*/
|
|
56
|
+
readonly logFormat?: string;
|
|
57
|
+
}
|
|
58
|
+
export declare function resolveLogFormat(flags: LogFormatFlags, env?: NodeJS.ProcessEnv): LogFormat;
|
|
59
|
+
/**
|
|
60
|
+
* The sink `run`/`drain` install, chosen by `--log-format`/
|
|
61
|
+
* `NAMZU_LOG_FORMAT`. `run-stream` does NOT use this — its stderr is a
|
|
62
|
+
* machine-read NDJSON channel regardless of the format flag, the same way
|
|
63
|
+
* its stdout protocol is unaffected by anything the operator passes. See
|
|
64
|
+
* `commands/run-stream.ts`.
|
|
65
|
+
*/
|
|
66
|
+
export declare function createStderrSink(format: LogFormat): LogSink;
|
|
67
|
+
/**
|
|
68
|
+
* Falls back to the same resolution `cli.ts#getContext()` would have
|
|
69
|
+
* produced with no flags and the live environment, for a `ctx`/`TuiContext`
|
|
70
|
+
* a test built by hand without a `logging` field — a fixture omitting a
|
|
71
|
+
* field it does not care about must not crash the handler it exercises.
|
|
72
|
+
* Every production `ctx` carries `logging`; only a test double hits the
|
|
73
|
+
* fallback, and `test-setup.ts` defaults `NAMZU_LOG_LEVEL` to `silent` so
|
|
74
|
+
* that fallback stays quiet unless a test deliberately overrides it.
|
|
75
|
+
*/
|
|
76
|
+
export declare function contextLogging(ctx: {
|
|
77
|
+
readonly logging?: ResolvedLogging;
|
|
78
|
+
}): ResolvedLogging;
|
|
79
|
+
//# sourceMappingURL=logging.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logging.d.ts","sourceRoot":"","sources":["../src/logging.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAGtD,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAA;AAEzC;;qCAEqC;AACrC,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAA;IAC3B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAA;CAC1B;AAQD,MAAM,WAAW,aAAa;IAC7B,yEAAyE;IACzE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CACxB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAC9B,KAAK,EAAE,aAAa,EACpB,GAAG,GAAE,MAAM,CAAC,UAAwB,GAClC,WAAW,CAIb;AAED,MAAM,WAAW,cAAc;IAC9B;;;;;;OAMG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAC3B;AAED,wBAAgB,gBAAgB,CAC/B,KAAK,EAAE,cAAc,EACrB,GAAG,GAAE,MAAM,CAAC,UAAwB,GAClC,SAAS,CAGX;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAE3D;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE;IAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,eAAe,CAAA;CAAE,GAAG,eAAe,CAE3F"}
|
package/dist/logging.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log level + format resolution for the CLI's five entry points that used
|
|
3
|
+
* to force the SDK logger's level to `silent` via `configureLogger` and
|
|
4
|
+
* never turn it back on: `tui/index.tsx`, `commands/run.ts`,
|
|
5
|
+
* `commands/drain.ts` and `commands/run-stream.ts` (twice — `run-stream`
|
|
6
|
+
* itself and `providers-json`). LOG-05.
|
|
7
|
+
*
|
|
8
|
+
* Kept out of `config/load.ts`'s cascade on purpose. That system merges
|
|
9
|
+
* four sources for `format`/`quiet`/`permissions`/`sandbox`, all of them
|
|
10
|
+
* either boolean or a closed enum with a config-file counterpart.
|
|
11
|
+
* `NAMZU_LOG_LEVEL` has no config-file counterpart in this increment and is
|
|
12
|
+
* not boolean-shaped — it names a level directly, string-valued, the same
|
|
13
|
+
* way `--verbose`/`--quiet` do. Precedence here is exactly what the design
|
|
14
|
+
* specifies and nothing more: an explicit flag beats the environment beats
|
|
15
|
+
* the default that used to be silence.
|
|
16
|
+
*/
|
|
17
|
+
import { jsonLinesSink, prettySink } from '@namzu/sdk';
|
|
18
|
+
const LEVEL_FILTERS = new Set(['debug', 'info', 'warn', 'error', 'silent']);
|
|
19
|
+
function isLevelFilter(value) {
|
|
20
|
+
return value !== undefined && LEVEL_FILTERS.has(value);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* `--verbose` -> `debug`, `--quiet` -> `warn`, otherwise `NAMZU_LOG_LEVEL`
|
|
24
|
+
* if it names a real level, otherwise `info` — the floor that used to be
|
|
25
|
+
* silence.
|
|
26
|
+
*
|
|
27
|
+
* `cli.ts` declares `--verbose` and `--quiet` as a `.conflicts()`-paired
|
|
28
|
+
* pair of Commander options, so through the CLI itself at most one of
|
|
29
|
+
* `flags.verbose` / `flags.quiet` is ever true at once. The `verbose`-first
|
|
30
|
+
* check below is what a caller that builds `LogLevelFlags` by hand — every
|
|
31
|
+
* test in `logging.test.ts` — gets instead of relying on that invariant.
|
|
32
|
+
*/
|
|
33
|
+
export function resolveLogLevel(flags, env = process.env) {
|
|
34
|
+
if (flags.verbose)
|
|
35
|
+
return 'debug';
|
|
36
|
+
if (flags.quiet)
|
|
37
|
+
return 'warn';
|
|
38
|
+
return isLevelFilter(env.NAMZU_LOG_LEVEL) ? env.NAMZU_LOG_LEVEL : 'info';
|
|
39
|
+
}
|
|
40
|
+
export function resolveLogFormat(flags, env = process.env) {
|
|
41
|
+
if (flags.logFormat === 'pretty' || flags.logFormat === 'json')
|
|
42
|
+
return flags.logFormat;
|
|
43
|
+
return env.NAMZU_LOG_FORMAT === 'json' ? 'json' : 'pretty';
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The sink `run`/`drain` install, chosen by `--log-format`/
|
|
47
|
+
* `NAMZU_LOG_FORMAT`. `run-stream` does NOT use this — its stderr is a
|
|
48
|
+
* machine-read NDJSON channel regardless of the format flag, the same way
|
|
49
|
+
* its stdout protocol is unaffected by anything the operator passes. See
|
|
50
|
+
* `commands/run-stream.ts`.
|
|
51
|
+
*/
|
|
52
|
+
export function createStderrSink(format) {
|
|
53
|
+
return format === 'json' ? jsonLinesSink(process.stderr) : prettySink(process.stderr);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Falls back to the same resolution `cli.ts#getContext()` would have
|
|
57
|
+
* produced with no flags and the live environment, for a `ctx`/`TuiContext`
|
|
58
|
+
* a test built by hand without a `logging` field — a fixture omitting a
|
|
59
|
+
* field it does not care about must not crash the handler it exercises.
|
|
60
|
+
* Every production `ctx` carries `logging`; only a test double hits the
|
|
61
|
+
* fallback, and `test-setup.ts` defaults `NAMZU_LOG_LEVEL` to `silent` so
|
|
62
|
+
* that fallback stays quiet unless a test deliberately overrides it.
|
|
63
|
+
*/
|
|
64
|
+
export function contextLogging(ctx) {
|
|
65
|
+
return ctx.logging ?? { level: resolveLogLevel({}), format: resolveLogFormat({}) };
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=logging.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logging.js","sourceRoot":"","sources":["../src/logging.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAYtD,MAAM,aAAa,GAAG,IAAI,GAAG,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAA;AAEnF,SAAS,aAAa,CAAC,KAAyB;IAC/C,OAAO,KAAK,KAAK,SAAS,IAAI,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;AACvD,CAAC;AAaD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,eAAe,CAC9B,KAAoB,EACpB,MAAyB,OAAO,CAAC,GAAG;IAEpC,IAAI,KAAK,CAAC,OAAO;QAAE,OAAO,OAAO,CAAA;IACjC,IAAI,KAAK,CAAC,KAAK;QAAE,OAAO,MAAM,CAAA;IAC9B,OAAO,aAAa,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,MAAM,CAAA;AACzE,CAAC;AAaD,MAAM,UAAU,gBAAgB,CAC/B,KAAqB,EACrB,MAAyB,OAAO,CAAC,GAAG;IAEpC,IAAI,KAAK,CAAC,SAAS,KAAK,QAAQ,IAAI,KAAK,CAAC,SAAS,KAAK,MAAM;QAAE,OAAO,KAAK,CAAC,SAAS,CAAA;IACtF,OAAO,GAAG,CAAC,gBAAgB,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAA;AAC3D,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAiB;IACjD,OAAO,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;AACtF,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAAC,GAA2C;IACzE,OAAO,GAAG,CAAC,OAAO,IAAI,EAAE,KAAK,EAAE,eAAe,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,gBAAgB,CAAC,EAAE,CAAC,EAAE,CAAA;AACnF,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Operator-authored tool permissions, compiled to the kernel's rule vocabulary.
|
|
3
3
|
*
|
|
4
|
-
* The kernel already has the engine — `
|
|
4
|
+
* The kernel already has the engine — `AuthorizationRule[]` with an
|
|
5
5
|
* allow/deny/review decision, evaluated first-match-wins. What was missing was
|
|
6
6
|
* any way for a person to author those rules: the CLI passed `rules: []`, so a
|
|
7
7
|
* gate with seven rule types ran with none of them and every decision fell back
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* The whole surface is pure: config in, rules out. The gate stays the only
|
|
11
11
|
* thing that decides anything, which is what keeps this testable without a run.
|
|
12
12
|
*/
|
|
13
|
-
import type {
|
|
13
|
+
import type { AuthorizationRule } from '@namzu/sdk';
|
|
14
14
|
/** What the operator wants to happen when a rule matches. */
|
|
15
15
|
export type PermissionEffect = 'allow' | 'ask' | 'deny';
|
|
16
16
|
export declare function isPermissionEffect(value: unknown): value is PermissionEffect;
|
|
@@ -30,7 +30,7 @@ export interface CompileDiagnostic {
|
|
|
30
30
|
readonly message: string;
|
|
31
31
|
}
|
|
32
32
|
export interface CompiledPermissions {
|
|
33
|
-
readonly rules: readonly
|
|
33
|
+
readonly rules: readonly AuthorizationRule[];
|
|
34
34
|
/**
|
|
35
35
|
* What was wrong with the config, for the caller to print.
|
|
36
36
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../src/permissions/rules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../src/permissions/rules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAEnD,6DAA6D;AAC7D,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,CAAA;AAIvD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,gBAAgB,CAE5E;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG,gBAAgB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAA;AAE1F,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAA;AAExE,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,mBAAmB;IACnC,QAAQ,CAAC,KAAK,EAAE,SAAS,iBAAiB,EAAE,CAAA;IAC5C;;;;;;;OAOG;IACH,QAAQ,CAAC,WAAW,EAAE,SAAS,iBAAiB,EAAE,CAAA;CAClD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAQ7D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,wBAAgB,iBAAiB,CAChC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,QAAQ,GAAE,OAAO,GAAG,MAAe,GACjC,MAAM,CASR;AAMD,oEAAoE;AACpE,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAKtE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAU1D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,iBAAiB,GAAG,SAAS,GAAG,mBAAmB,CAgD7F"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Operator-authored tool permissions, compiled to the kernel's rule vocabulary.
|
|
3
3
|
*
|
|
4
|
-
* The kernel already has the engine — `
|
|
4
|
+
* The kernel already has the engine — `AuthorizationRule[]` with an
|
|
5
5
|
* allow/deny/review decision, evaluated first-match-wins. What was missing was
|
|
6
6
|
* any way for a person to author those rules: the CLI passed `rules: []`, so a
|
|
7
7
|
* gate with seven rule types ran with none of them and every decision fell back
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules.js","sourceRoot":"","sources":["../../src/permissions/rules.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"rules.js","sourceRoot":"","sources":["../../src/permissions/rules.ts"],"names":[],"mappings":"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"}
|
package/dist/skills/store.d.ts
CHANGED
|
@@ -48,7 +48,7 @@ interface ParsedSkill {
|
|
|
48
48
|
* ## Absent frontmatter is fine; broken frontmatter is not
|
|
49
49
|
*
|
|
50
50
|
* These were the same case here and are not the same thing. A file with no
|
|
51
|
-
* frontmatter is a documented, supported shape
|
|
51
|
+
* frontmatter is a documented, supported shape: the body
|
|
52
52
|
* is the skill. A file that opens a fence and then fails to parse is an author
|
|
53
53
|
* who tried to write metadata and got it wrong, and answering that with "no
|
|
54
54
|
* metadata, carry on" put the broken YAML into the body — and from there
|
package/dist/skills/store.js
CHANGED
|
@@ -34,7 +34,7 @@ export function projectSkillsDir(cwd = process.cwd()) {
|
|
|
34
34
|
* ## Absent frontmatter is fine; broken frontmatter is not
|
|
35
35
|
*
|
|
36
36
|
* These were the same case here and are not the same thing. A file with no
|
|
37
|
-
* frontmatter is a documented, supported shape
|
|
37
|
+
* frontmatter is a documented, supported shape: the body
|
|
38
38
|
* is the skill. A file that opens a fence and then fails to parse is an author
|
|
39
39
|
* who tried to write metadata and got it wrong, and answering that with "no
|
|
40
40
|
* metadata, carry on" put the broken YAML into the body — and from there
|
package/dist/tui/App.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/tui/App.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;
|
|
1
|
+
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/tui/App.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAmFH,OAAO,KAAK,EAAqB,UAAU,EAAE,MAAM,YAAY,CAAA;AAE/D,MAAM,WAAW,QAAQ;IACxB,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAA;CACxB;AAqCD,wBAAgB,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,QAAQ,2CAqsDpC"}
|
package/dist/tui/App.js
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* TUI root. Composes the banner, transcript, composer, status bar, and
|
|
4
|
+
* the first-run provider picker overlay.
|
|
5
|
+
*
|
|
6
|
+
* Session lifecycle:
|
|
7
|
+
* 1. Mount → probeAgentSession() (readPreferences + discoverProviders).
|
|
8
|
+
* 2. If a v2 preferences file exists → createAgentSession(prefs, detected) → ready.
|
|
9
|
+
* 3. If preferences missing OR v1 (legacy) → show <Picker/>.
|
|
10
|
+
* After picker submit, writePreferences + hydrate session.
|
|
11
|
+
* 4. If discovery returned zero providers → show <Picker/> in
|
|
12
|
+
* empty-state mode (explains where to put credentials).
|
|
13
|
+
*/
|
|
14
|
+
import { DiskMessageFeedbackStore, HostCommandRegistry, kernelHostCommands, } from '@namzu/sdk';
|
|
2
15
|
import { Box, Text, useApp, useInput } from 'ink';
|
|
3
|
-
import { relative } from 'node:path';
|
|
16
|
+
import { join, relative } from 'node:path';
|
|
4
17
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
5
18
|
import { beginSubscriptionLogin, clearStoredSubscriptionCredential, credentialsPath, primaryProvider, readStoredSubscriptionCredential, writePreferences, } from '../integrations/providers/index.js';
|
|
6
19
|
import { describeLoginOutcome, describeLoginStart, describeLogout } from './login-prompt.js';
|
|
@@ -26,7 +39,7 @@ import { appendMessages, listRecent, loadConversation, openSessions, startConver
|
|
|
26
39
|
import { createAgentSession, probeAgentSession, } from './agent.js';
|
|
27
40
|
import { ResumePicker } from './ResumePicker.js';
|
|
28
41
|
import { discoverUserCommands } from '../user-commands/store.js';
|
|
29
|
-
import {
|
|
42
|
+
import { hostCommandNames, kernelCommandDescriptors, mergeHostCommands, renderOutcome, runSlash, } from './slashCommands.js';
|
|
30
43
|
import { splitCompleteBlocks } from './stream-blocks.js';
|
|
31
44
|
import { theme } from './theme.js';
|
|
32
45
|
/**
|
|
@@ -41,6 +54,14 @@ import { theme } from './theme.js';
|
|
|
41
54
|
const LIVE_FURNITURE_ROWS = 10;
|
|
42
55
|
export function App({ ctx }) {
|
|
43
56
|
const { exit } = useApp();
|
|
57
|
+
/**
|
|
58
|
+
* The last assistant message id the run reported, for `/feedback`.
|
|
59
|
+
*
|
|
60
|
+
* A ref rather than state: nothing renders it, and making it state would
|
|
61
|
+
* re-render the transcript on every delta — the exact cost the `pending`
|
|
62
|
+
* buffering two hundred lines down exists to avoid.
|
|
63
|
+
*/
|
|
64
|
+
const lastAssistantMessage = useRef(null);
|
|
44
65
|
const [messages, setMessages] = useState([]);
|
|
45
66
|
const [history, setHistory] = useState([]);
|
|
46
67
|
const [state, setState] = useState('idle');
|
|
@@ -253,7 +274,7 @@ export function App({ ctx }) {
|
|
|
253
274
|
sessionsRef.current = sessions;
|
|
254
275
|
scopeRef.current = {
|
|
255
276
|
sessionId,
|
|
256
|
-
|
|
277
|
+
topicId: sessions.topicId,
|
|
257
278
|
projectId: sessions.projectId,
|
|
258
279
|
tenantId: sessions.tenantId,
|
|
259
280
|
};
|
|
@@ -270,6 +291,7 @@ export function App({ ctx }) {
|
|
|
270
291
|
cwd: ctx.cwd,
|
|
271
292
|
rules: ctx.rules,
|
|
272
293
|
...(ctx.mcpServers ? { mcpServers: ctx.mcpServers } : {}),
|
|
294
|
+
...(ctx.sandbox ? { sandbox: ctx.sandbox } : {}),
|
|
273
295
|
});
|
|
274
296
|
// Re-hydration (a provider switch via /model) builds a second session;
|
|
275
297
|
// without this the first one's tool-server child processes stay alive
|
|
@@ -282,7 +304,7 @@ export function App({ ctx }) {
|
|
|
282
304
|
// Builtins are reserved: a `help.md` must not take over `/help`.
|
|
283
305
|
// Passing the names here is what lets the loader tell its author
|
|
284
306
|
// the file is shadowed instead of leaving it silently unused.
|
|
285
|
-
reserved:
|
|
307
|
+
reserved: hostCommandNames(),
|
|
286
308
|
}));
|
|
287
309
|
setCurrentProvider(primaryProvider(prefs).id);
|
|
288
310
|
if (s.hasProvider) {
|
|
@@ -546,7 +568,15 @@ export function App({ ctx }) {
|
|
|
546
568
|
liveRows: LIVE_FURNITURE_ROWS + window.rows,
|
|
547
569
|
})
|
|
548
570
|
: 0;
|
|
571
|
+
// One merged vocabulary for the session: this host's own commands plus
|
|
572
|
+
// whatever the kernel's registry reports. Built here so `/help`, the
|
|
573
|
+
// autocomplete and the dispatcher all answer from the same list — three
|
|
574
|
+
// places that used to read one hardcoded array and would otherwise
|
|
575
|
+
// disagree the moment a capability added a command.
|
|
576
|
+
const hostCommands = mergeHostCommands(kernelCommandDescriptors());
|
|
549
577
|
const slashCtx = {
|
|
578
|
+
builtins: hostCommands,
|
|
579
|
+
lastAssistantMessageId: () => lastAssistantMessage.current?.messageId ?? null,
|
|
550
580
|
// Called when `/tools` renders, not read here — the same shape, and the
|
|
551
581
|
// same reason, as `neverPrompted` below.
|
|
552
582
|
availableTools: () => session?.toolNames() ?? [],
|
|
@@ -572,7 +602,6 @@ export function App({ ctx }) {
|
|
|
572
602
|
approvalLatched: () => session?.approvalLatched() ?? false,
|
|
573
603
|
neverPrompted: () => session?.promptExemptTools() ?? [],
|
|
574
604
|
},
|
|
575
|
-
agentIds: session?.agentIds ?? [],
|
|
576
605
|
instructionFiles: session?.instructionFiles ?? [],
|
|
577
606
|
userCommands,
|
|
578
607
|
};
|
|
@@ -757,6 +786,9 @@ export function App({ ctx }) {
|
|
|
757
786
|
switch (event.kind) {
|
|
758
787
|
case 'delta': {
|
|
759
788
|
setState('thinking');
|
|
789
|
+
if (event.messageId && event.runId) {
|
|
790
|
+
lastAssistantMessage.current = { runId: event.runId, messageId: event.messageId };
|
|
791
|
+
}
|
|
760
792
|
st.text += event.text;
|
|
761
793
|
// Held, not appended. Appending each delta is what produced text
|
|
762
794
|
// that types itself out — nothing animates it, but a few
|
|
@@ -988,7 +1020,7 @@ export function App({ ctx }) {
|
|
|
988
1020
|
// including the queue — so a command-driven turn is not a second way
|
|
989
1021
|
// to run one.
|
|
990
1022
|
let outgoing = value;
|
|
991
|
-
const slash = runSlash(value, slashCtx);
|
|
1023
|
+
const slash = runSlash(value, slashCtx, hostCommands);
|
|
992
1024
|
if (slash) {
|
|
993
1025
|
switch (slash.kind) {
|
|
994
1026
|
case 'message':
|
|
@@ -1166,6 +1198,61 @@ export function App({ ctx }) {
|
|
|
1166
1198
|
break;
|
|
1167
1199
|
case 'none':
|
|
1168
1200
|
return;
|
|
1201
|
+
case 'host-command': {
|
|
1202
|
+
// Dispatched through the kernel's registry, built with what
|
|
1203
|
+
// THIS session can answer from. The descriptors used for
|
|
1204
|
+
// the merge above carry no store — they are names — so the
|
|
1205
|
+
// registry is rebuilt here with the live one.
|
|
1206
|
+
const registry = new HostCommandRegistry();
|
|
1207
|
+
registry.register(kernelHostCommands({ allowedAgentIds: session?.agentIds ?? [] }));
|
|
1208
|
+
void (async () => {
|
|
1209
|
+
const outcome = await registry.dispatch(`/${slash.name} ${slash.args.join(' ')}`.trim());
|
|
1210
|
+
pushMessage('system', outcome
|
|
1211
|
+
? renderOutcome(outcome)
|
|
1212
|
+
: `/${slash.name} is registered but this session cannot run it.`);
|
|
1213
|
+
})();
|
|
1214
|
+
return;
|
|
1215
|
+
}
|
|
1216
|
+
case 'feedback': {
|
|
1217
|
+
const target = lastAssistantMessage.current;
|
|
1218
|
+
// Written under the same `<cwd>/.namzu` root the runs live
|
|
1219
|
+
// in, so a rating and the transcript it judges are one
|
|
1220
|
+
// directory apart and travel together.
|
|
1221
|
+
if (!target) {
|
|
1222
|
+
pushMessage('system', 'Nothing to rate yet.');
|
|
1223
|
+
return;
|
|
1224
|
+
}
|
|
1225
|
+
const store = new DiskMessageFeedbackStore({
|
|
1226
|
+
rootDir: join(ctx.cwd, '.namzu', 'feedback'),
|
|
1227
|
+
runsDir: join(ctx.cwd, '.namzu', 'runs'),
|
|
1228
|
+
});
|
|
1229
|
+
const runId = target.runId;
|
|
1230
|
+
const messageId = slash.messageId;
|
|
1231
|
+
// Fire-and-forget: this switch is synchronous, and the
|
|
1232
|
+
// transcript reports the outcome either way rather than
|
|
1233
|
+
// blocking a keystroke on a disk write.
|
|
1234
|
+
void (async () => {
|
|
1235
|
+
try {
|
|
1236
|
+
// A first rating expects nothing; a second replaces the
|
|
1237
|
+
// first, which is what a rater changing their mind does.
|
|
1238
|
+
// Read-then-write rather than blind overwrite, so two
|
|
1239
|
+
// raters on one message still collide loudly.
|
|
1240
|
+
const current = (await store.listMessageFeedback({ runId })).find((r) => r.messageId === messageId);
|
|
1241
|
+
const record = await store.putMessageFeedback({
|
|
1242
|
+
runId,
|
|
1243
|
+
messageId,
|
|
1244
|
+
rating: slash.rating,
|
|
1245
|
+
...(slash.note ? { note: slash.note } : {}),
|
|
1246
|
+
expectedVersion: current?.ownerVersion ?? 0,
|
|
1247
|
+
});
|
|
1248
|
+
pushMessage('system', `Recorded ${record.rating} for ${record.messageId}.`);
|
|
1249
|
+
}
|
|
1250
|
+
catch (err) {
|
|
1251
|
+
pushMessage('system', `Could not record feedback: ${err instanceof Error ? err.message : String(err)}`);
|
|
1252
|
+
}
|
|
1253
|
+
})();
|
|
1254
|
+
return;
|
|
1255
|
+
}
|
|
1169
1256
|
default: {
|
|
1170
1257
|
// Exhaustive on purpose. Without it a `SlashAction` kind added
|
|
1171
1258
|
// and not handled here falls out of the switch into the send
|