@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.
Files changed (134) hide show
  1. package/README.md +390 -46
  2. package/dist/cli.d.ts +15 -0
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +133 -4
  5. package/dist/cli.js.map +1 -1
  6. package/dist/commands/acp.d.ts +29 -0
  7. package/dist/commands/acp.d.ts.map +1 -0
  8. package/dist/commands/acp.js +156 -0
  9. package/dist/commands/acp.js.map +1 -0
  10. package/dist/commands/doctor.d.ts +12 -1
  11. package/dist/commands/doctor.d.ts.map +1 -1
  12. package/dist/commands/doctor.js +18 -2
  13. package/dist/commands/doctor.js.map +1 -1
  14. package/dist/commands/drain.d.ts +2 -2
  15. package/dist/commands/drain.d.ts.map +1 -1
  16. package/dist/commands/drain.js +31 -8
  17. package/dist/commands/drain.js.map +1 -1
  18. package/dist/commands/run-flags.d.ts.map +1 -1
  19. package/dist/commands/run-flags.js +33 -0
  20. package/dist/commands/run-flags.js.map +1 -1
  21. package/dist/commands/run-stream.d.ts +3 -3
  22. package/dist/commands/run-stream.d.ts.map +1 -1
  23. package/dist/commands/run-stream.js +27 -10
  24. package/dist/commands/run-stream.js.map +1 -1
  25. package/dist/commands/run.d.ts.map +1 -1
  26. package/dist/commands/run.js +50 -4
  27. package/dist/commands/run.js.map +1 -1
  28. package/dist/commands/types.d.ts +10 -0
  29. package/dist/commands/types.d.ts.map +1 -1
  30. package/dist/config/load.d.ts +64 -0
  31. package/dist/config/load.d.ts.map +1 -1
  32. package/dist/config/load.js +156 -20
  33. package/dist/config/load.js.map +1 -1
  34. package/dist/config/schema.d.ts +88 -0
  35. package/dist/config/schema.d.ts.map +1 -1
  36. package/dist/config/schema.js.map +1 -1
  37. package/dist/context/capabilities.d.ts +88 -0
  38. package/dist/context/capabilities.d.ts.map +1 -0
  39. package/dist/context/capabilities.js +160 -0
  40. package/dist/context/capabilities.js.map +1 -0
  41. package/dist/context/sandbox.d.ts +54 -0
  42. package/dist/context/sandbox.d.ts.map +1 -0
  43. package/dist/context/sandbox.js +61 -0
  44. package/dist/context/sandbox.js.map +1 -0
  45. package/dist/doctor/checks/index.d.ts +6 -1
  46. package/dist/doctor/checks/index.d.ts.map +1 -1
  47. package/dist/doctor/checks/index.js +45 -2
  48. package/dist/doctor/checks/index.js.map +1 -1
  49. package/dist/doctor/checks/invariants.d.ts +23 -0
  50. package/dist/doctor/checks/invariants.d.ts.map +1 -0
  51. package/dist/doctor/checks/invariants.js +79 -0
  52. package/dist/doctor/checks/invariants.js.map +1 -0
  53. package/dist/doctor/checks/logging.d.ts +10 -0
  54. package/dist/doctor/checks/logging.d.ts.map +1 -0
  55. package/dist/doctor/checks/logging.js +69 -0
  56. package/dist/doctor/checks/logging.js.map +1 -0
  57. package/dist/doctor/checks/session-export.d.ts +21 -0
  58. package/dist/doctor/checks/session-export.d.ts.map +1 -0
  59. package/dist/doctor/checks/session-export.js +62 -0
  60. package/dist/doctor/checks/session-export.js.map +1 -0
  61. package/dist/doctor/checks/telemetry.d.ts +15 -28
  62. package/dist/doctor/checks/telemetry.d.ts.map +1 -1
  63. package/dist/doctor/checks/telemetry.js +34 -54
  64. package/dist/doctor/checks/telemetry.js.map +1 -1
  65. package/dist/doctor/checks/vault.d.ts +4 -20
  66. package/dist/doctor/checks/vault.d.ts.map +1 -1
  67. package/dist/doctor/checks/vault.js +58 -19
  68. package/dist/doctor/checks/vault.js.map +1 -1
  69. package/dist/doctor/registry.d.ts.map +1 -1
  70. package/dist/doctor/registry.js +13 -6
  71. package/dist/doctor/registry.js.map +1 -1
  72. package/dist/index.d.ts +3 -2
  73. package/dist/index.d.ts.map +1 -1
  74. package/dist/index.js +3 -2
  75. package/dist/index.js.map +1 -1
  76. package/dist/integrations/files/attachment-store.d.ts +44 -0
  77. package/dist/integrations/files/attachment-store.d.ts.map +1 -0
  78. package/dist/integrations/files/attachment-store.js +86 -0
  79. package/dist/integrations/files/attachment-store.js.map +1 -0
  80. package/dist/integrations/providers/credential-provider.d.ts +39 -0
  81. package/dist/integrations/providers/credential-provider.d.ts.map +1 -0
  82. package/dist/integrations/providers/credential-provider.js +74 -0
  83. package/dist/integrations/providers/credential-provider.js.map +1 -0
  84. package/dist/integrations/providers/discover.d.ts.map +1 -1
  85. package/dist/integrations/providers/discover.js +15 -3
  86. package/dist/integrations/providers/discover.js.map +1 -1
  87. package/dist/integrations/providers/oauth.d.ts.map +1 -1
  88. package/dist/integrations/providers/oauth.js +24 -1
  89. package/dist/integrations/providers/oauth.js.map +1 -1
  90. package/dist/integrations/sessions/store.d.ts +2 -2
  91. package/dist/integrations/sessions/store.d.ts.map +1 -1
  92. package/dist/integrations/sessions/store.js +21 -9
  93. package/dist/integrations/sessions/store.js.map +1 -1
  94. package/dist/integrations/subagents/runtime.d.ts +3 -3
  95. package/dist/integrations/subagents/runtime.d.ts.map +1 -1
  96. package/dist/integrations/subagents/runtime.js +11 -11
  97. package/dist/integrations/subagents/runtime.js.map +1 -1
  98. package/dist/integrations/telemetry/session-export.d.ts +99 -0
  99. package/dist/integrations/telemetry/session-export.d.ts.map +1 -0
  100. package/dist/integrations/telemetry/session-export.js +119 -0
  101. package/dist/integrations/telemetry/session-export.js.map +1 -0
  102. package/dist/logging.d.ts +79 -0
  103. package/dist/logging.d.ts.map +1 -0
  104. package/dist/logging.js +67 -0
  105. package/dist/logging.js.map +1 -0
  106. package/dist/permissions/rules.d.ts +3 -3
  107. package/dist/permissions/rules.d.ts.map +1 -1
  108. package/dist/permissions/rules.js +1 -1
  109. package/dist/permissions/rules.js.map +1 -1
  110. package/dist/skills/store.d.ts +1 -1
  111. package/dist/skills/store.js +1 -1
  112. package/dist/tui/App.d.ts.map +1 -1
  113. package/dist/tui/App.js +93 -6
  114. package/dist/tui/App.js.map +1 -1
  115. package/dist/tui/StatusBar.d.ts +1 -1
  116. package/dist/tui/StatusBar.d.ts.map +1 -1
  117. package/dist/tui/agent.d.ts +65 -24
  118. package/dist/tui/agent.d.ts.map +1 -1
  119. package/dist/tui/agent.js +337 -122
  120. package/dist/tui/agent.js.map +1 -1
  121. package/dist/tui/index.d.ts.map +1 -1
  122. package/dist/tui/index.js +17 -6
  123. package/dist/tui/index.js.map +1 -1
  124. package/dist/tui/log-pane.d.ts +48 -0
  125. package/dist/tui/log-pane.d.ts.map +1 -0
  126. package/dist/tui/log-pane.js +106 -0
  127. package/dist/tui/log-pane.js.map +1 -0
  128. package/dist/tui/slashCommands.d.ts +134 -11
  129. package/dist/tui/slashCommands.d.ts.map +1 -1
  130. package/dist/tui/slashCommands.js +169 -15
  131. package/dist/tui/slashCommands.js.map +1 -1
  132. package/dist/tui/types.d.ts +18 -2
  133. package/dist/tui/types.d.ts.map +1 -1
  134. 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"}
@@ -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 — `VerificationRule[]` with an
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 { VerificationRule } from '@namzu/sdk';
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 VerificationRule[];
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,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAElD,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,gBAAgB,EAAE,CAAA;IAC3C;;;;;;;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
+ {"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 — `VerificationRule[]` with an
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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"}
@@ -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 (`docs/cli/skills.md`): the body
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
@@ -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 (`docs/cli/skills.md`): the body
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
@@ -1 +1 @@
1
- {"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/tui/App.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAmEH,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,2CAinDpC"}
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 { SLASH_COMMANDS, runSlash } from './slashCommands.js';
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
- threadId: sessions.threadId,
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: SLASH_COMMANDS.map((c) => c.name),
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