@namzu/cli 11.0.0 → 12.0.1
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 +132 -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 +137 -20
- package/dist/config/load.js.map +1 -1
- package/dist/config/schema.d.ts +51 -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 +13 -0
- package/dist/context/sandbox.d.ts.map +1 -1
- package/dist/context/sandbox.js +15 -0
- package/dist/context/sandbox.js.map +1 -1
- 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 +12 -12
- 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 +92 -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 +54 -24
- package/dist/tui/agent.d.ts.map +1 -1
- package/dist/tui/agent.js +330 -127
- 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 +11 -2
- package/dist/tui/types.d.ts.map +1 -1
- package/package.json +8 -6
|
@@ -1,11 +1,46 @@
|
|
|
1
|
+
import { capabilityCheckId } from '../../context/capabilities.js';
|
|
1
2
|
import { providerChainCheck } from './chain.js';
|
|
2
3
|
import { credentialSourcesCheck } from './credentials.js';
|
|
4
|
+
import { invariantsCheck } from './invariants.js';
|
|
5
|
+
import { loggingPipelineCheck } from './logging.js';
|
|
3
6
|
import { providersRegisteredCheck } from './providers.js';
|
|
4
7
|
import { cwdWritableCheck, tmpdirWritableCheck } from './runtime.js';
|
|
5
8
|
import { sandboxPlatformCheck } from './sandbox.js';
|
|
6
|
-
import { telemetryInstalledCheck } from './telemetry.js';
|
|
9
|
+
import { describeInstalledPackage, telemetryInstalledCheck } from './telemetry.js';
|
|
7
10
|
import { vaultRegisteredCheck } from './vault.js';
|
|
8
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Build an `installed` check for one optional package, over the same
|
|
13
|
+
* absent/present/broken mapping `telemetryInstalledCheck` already used.
|
|
14
|
+
*
|
|
15
|
+
* `telemetryInstalledCheck` keeps its own hand-written definition below
|
|
16
|
+
* rather than being rebuilt through this factory — it shipped first, and
|
|
17
|
+
* `doctor/checks/__tests__/telemetry.test.ts` already exercises that exact
|
|
18
|
+
* object with zero edits required by NZ-BOOT-02. A fifth optional package
|
|
19
|
+
* needs one call to this factory, not a fourth hand-written check that can
|
|
20
|
+
* drift from the other three.
|
|
21
|
+
*/
|
|
22
|
+
function installedCheck(specifier, category) {
|
|
23
|
+
return {
|
|
24
|
+
id: capabilityCheckId(specifier),
|
|
25
|
+
category,
|
|
26
|
+
run: () => describeInstalledPackage(specifier),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
// `sandboxPlatformCheck` already owns the `sandbox` category for a different
|
|
30
|
+
// question (does THIS PLATFORM enforce isolation); this check asking IS THE
|
|
31
|
+
// PACKAGE HERE fits the same category. `DoctorCategory` has no `files` or
|
|
32
|
+
// `computer-use` member, and widening that union is an SDK type change this
|
|
33
|
+
// task does not make, so those two register under `custom` — the category
|
|
34
|
+
// the registry's own tests already use for exactly this situation.
|
|
35
|
+
export const sandboxInstalledCheck = installedCheck('@namzu/sandbox', 'sandbox');
|
|
36
|
+
export const filesInstalledCheck = installedCheck('@namzu/files', 'custom');
|
|
37
|
+
export const computerUseInstalledCheck = installedCheck('@namzu/computer-use', 'custom');
|
|
38
|
+
// NOTE the fix versus the original submission: sandboxInstalledCheck /
|
|
39
|
+
// filesInstalledCheck / computerUseInstalledCheck are NOT repeated here.
|
|
40
|
+
// They already carry their own `export` keyword above; naming them again in
|
|
41
|
+
// this aggregation block is a duplicate-export declaration and fails
|
|
42
|
+
// `tsc --build` with TS2323/TS2484 (confirmed by building this exact file).
|
|
43
|
+
export { credentialSourcesCheck, providerChainCheck, providersRegisteredCheck, cwdWritableCheck, tmpdirWritableCheck, invariantsCheck, loggingPipelineCheck, sandboxPlatformCheck, telemetryInstalledCheck, vaultRegisteredCheck, };
|
|
9
44
|
export const builtInDoctorChecks = [
|
|
10
45
|
sandboxPlatformCheck,
|
|
11
46
|
cwdWritableCheck,
|
|
@@ -17,6 +52,14 @@ export const builtInDoctorChecks = [
|
|
|
17
52
|
// the operator has seen what was found.
|
|
18
53
|
providerChainCheck,
|
|
19
54
|
vaultRegisteredCheck,
|
|
55
|
+
sandboxInstalledCheck,
|
|
56
|
+
filesInstalledCheck,
|
|
57
|
+
computerUseInstalledCheck,
|
|
20
58
|
telemetryInstalledCheck,
|
|
59
|
+
// Last, deliberately: it reports what the pipeline did to the records
|
|
60
|
+
// every check above it just produced, so running it first would report a
|
|
61
|
+
// process that had barely logged anything yet.
|
|
62
|
+
loggingPipelineCheck,
|
|
63
|
+
invariantsCheck,
|
|
21
64
|
];
|
|
22
65
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/doctor/checks/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAC/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAA;AACzD,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAA;AACzD,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AACnD,OAAO,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/doctor/checks/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAA;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAC/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAA;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AACnD,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAA;AACzD,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AACnD,OAAO,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAA;AAClF,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAEjD;;;;;;;;;;GAUG;AACH,SAAS,cAAc,CAAC,SAAiB,EAAE,QAAiC;IAC3E,OAAO;QACN,EAAE,EAAE,iBAAiB,CAAC,SAAS,CAAC;QAChC,QAAQ;QACR,GAAG,EAAE,GAA+B,EAAE,CAAC,wBAAwB,CAAC,SAAS,CAAC;KAC1E,CAAA;AACF,CAAC;AAED,6EAA6E;AAC7E,4EAA4E;AAC5E,0EAA0E;AAC1E,4EAA4E;AAC5E,0EAA0E;AAC1E,mEAAmE;AACnE,MAAM,CAAC,MAAM,qBAAqB,GAAgB,cAAc,CAAC,gBAAgB,EAAE,SAAS,CAAC,CAAA;AAC7F,MAAM,CAAC,MAAM,mBAAmB,GAAgB,cAAc,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAA;AACxF,MAAM,CAAC,MAAM,yBAAyB,GAAgB,cAAc,CACnE,qBAAqB,EACrB,QAAQ,CACR,CAAA;AAED,uEAAuE;AACvE,yEAAyE;AACzE,4EAA4E;AAC5E,qEAAqE;AACrE,4EAA4E;AAC5E,OAAO,EACN,sBAAsB,EACtB,kBAAkB,EAClB,wBAAwB,EACxB,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,EACf,oBAAoB,EACpB,oBAAoB,EACpB,uBAAuB,EACvB,oBAAoB,GACpB,CAAA;AAED,MAAM,CAAC,MAAM,mBAAmB,GAA2B;IAC1D,oBAAoB;IACpB,gBAAgB;IAChB,mBAAmB;IACnB,wBAAwB;IACxB,sBAAsB;IACtB,4EAA4E;IAC5E,0EAA0E;IAC1E,wCAAwC;IACxC,kBAAkB;IAClB,oBAAoB;IACpB,qBAAqB;IACrB,mBAAmB;IACnB,yBAAyB;IACzB,uBAAuB;IACvB,sEAAsE;IACtE,yEAAyE;IACzE,+CAA+C;IAC/C,oBAAoB;IACpB,eAAe;CACf,CAAA"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { DoctorCheck, DoctorCheckResult, InvariantRegistry } from '@namzu/sdk';
|
|
2
|
+
/**
|
|
3
|
+
* Evaluate every invariant `registry` holds and fold the outcomes, plus each
|
|
4
|
+
* invariant's own violation counter, into one doctor row.
|
|
5
|
+
*
|
|
6
|
+
* Exported separately from the `DoctorCheck` — same reasoning as
|
|
7
|
+
* `describeInstalledPackage` on the telemetry check — so a test can drive a
|
|
8
|
+
* SCOPED registry directly, rather than mutating the process-wide singleton
|
|
9
|
+
* every other test also reads. The check itself is still exercised through
|
|
10
|
+
* `invariantsCheck.run`, because a helper proven in isolation says nothing
|
|
11
|
+
* about whether the check reaches it.
|
|
12
|
+
*
|
|
13
|
+
* Every invariant is evaluated with `ctx: undefined`. `namzu doctor` runs
|
|
14
|
+
* with no live run and no candidate compaction reduction — there is nothing
|
|
15
|
+
* a real invariant's check could read that is specific to one run — so
|
|
16
|
+
* `undefined` is the honest context, not a shortcut: each check registered
|
|
17
|
+
* against it is written to answer `unknown` rather than guess (see
|
|
18
|
+
* `compaction.ts` and `claim-disk.ts` in `@namzu/sdk`), and this row reports
|
|
19
|
+
* that state rather than papering over it as a pass.
|
|
20
|
+
*/
|
|
21
|
+
export declare function describeInvariants(registry: InvariantRegistry): Promise<DoctorCheckResult>;
|
|
22
|
+
export declare const invariantsCheck: DoctorCheck;
|
|
23
|
+
//# sourceMappingURL=invariants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invariants.d.ts","sourceRoot":"","sources":["../../../src/doctor/checks/invariants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAanF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAyDhG;AAED,eAAO,MAAM,eAAe,EAAE,WAI7B,CAAA"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { invariants } from '@namzu/sdk';
|
|
2
|
+
function label(row) {
|
|
3
|
+
return `${row.id} (${row.violations} violation${row.violations === 1 ? '' : 's'})`;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Evaluate every invariant `registry` holds and fold the outcomes, plus each
|
|
7
|
+
* invariant's own violation counter, into one doctor row.
|
|
8
|
+
*
|
|
9
|
+
* Exported separately from the `DoctorCheck` — same reasoning as
|
|
10
|
+
* `describeInstalledPackage` on the telemetry check — so a test can drive a
|
|
11
|
+
* SCOPED registry directly, rather than mutating the process-wide singleton
|
|
12
|
+
* every other test also reads. The check itself is still exercised through
|
|
13
|
+
* `invariantsCheck.run`, because a helper proven in isolation says nothing
|
|
14
|
+
* about whether the check reaches it.
|
|
15
|
+
*
|
|
16
|
+
* Every invariant is evaluated with `ctx: undefined`. `namzu doctor` runs
|
|
17
|
+
* with no live run and no candidate compaction reduction — there is nothing
|
|
18
|
+
* a real invariant's check could read that is specific to one run — so
|
|
19
|
+
* `undefined` is the honest context, not a shortcut: each check registered
|
|
20
|
+
* against it is written to answer `unknown` rather than guess (see
|
|
21
|
+
* `compaction.ts` and `claim-disk.ts` in `@namzu/sdk`), and this row reports
|
|
22
|
+
* that state rather than papering over it as a pass.
|
|
23
|
+
*/
|
|
24
|
+
export async function describeInvariants(registry) {
|
|
25
|
+
const ids = registry.listIds();
|
|
26
|
+
if (ids.length === 0) {
|
|
27
|
+
return { status: 'skipped', message: 'no invariants registered' };
|
|
28
|
+
}
|
|
29
|
+
const rows = await Promise.all(ids.map(async (id) => ({
|
|
30
|
+
id,
|
|
31
|
+
outcome: await registry.evaluate(id, undefined),
|
|
32
|
+
violations: registry.violationCount(id),
|
|
33
|
+
})));
|
|
34
|
+
const violated = rows.filter((r) => r.outcome.state === 'violated');
|
|
35
|
+
const unknown = rows.filter((r) => r.outcome.state === 'unknown');
|
|
36
|
+
if (violated.length > 0) {
|
|
37
|
+
const detail = violated
|
|
38
|
+
.map((r) => (r.outcome.state === 'violated' ? `${label(r)}: ${r.outcome.detail}` : label(r)))
|
|
39
|
+
.join('; ');
|
|
40
|
+
return {
|
|
41
|
+
status: 'fail',
|
|
42
|
+
message: `${violated.length}/${ids.length} invariant(s) violated — ${detail}`,
|
|
43
|
+
remediation: 'Check the warn/error logs at the module that registered the violated invariant.',
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
if (unknown.length > 0) {
|
|
47
|
+
const names = unknown.map(label).join(', ');
|
|
48
|
+
// `skipped`, not `inconclusive`, and the difference is the whole
|
|
49
|
+
// behaviour of this row. `inconclusive` maps to exit 69 in
|
|
50
|
+
// `doctor/registry.ts` and means "I asked and could not establish an
|
|
51
|
+
// answer" — a real signal that something is wrong with the check
|
|
52
|
+
// itself. A runtime invariant outside a live run is a different thing:
|
|
53
|
+
// the question has no subject yet, every registered check is written
|
|
54
|
+
// to answer `unknown` here on purpose, and so this state is reached on
|
|
55
|
+
// EVERY doctor run. Reporting it as inconclusive made `namzu doctor`
|
|
56
|
+
// exit 69 unconditionally, which retires the one code that was
|
|
57
|
+
// supposed to mean something.
|
|
58
|
+
//
|
|
59
|
+
// `skipped` is not "satisfied" either — the summary counts it
|
|
60
|
+
// separately from `pass`, and the message still names which invariants
|
|
61
|
+
// went unevaluated and how many violations each has accumulated. The
|
|
62
|
+
// violation counters above are what actually carry a live run's
|
|
63
|
+
// findings back to this row.
|
|
64
|
+
return {
|
|
65
|
+
status: 'skipped',
|
|
66
|
+
message: `${unknown.length}/${ids.length} invariant(s) have no subject outside a live run: ${names}`,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
status: 'pass',
|
|
71
|
+
message: `${ids.length} invariant(s) hold: ${rows.map(label).join(', ')}`,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
export const invariantsCheck = {
|
|
75
|
+
id: 'runtime.invariants',
|
|
76
|
+
category: 'runtime',
|
|
77
|
+
run: () => describeInvariants(invariants),
|
|
78
|
+
};
|
|
79
|
+
//# sourceMappingURL=invariants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invariants.js","sourceRoot":"","sources":["../../../src/doctor/checks/invariants.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { DoctorCheck, DoctorCheckResult, LogSinkCounters } from '@namzu/sdk';
|
|
2
|
+
/**
|
|
3
|
+
* Exported separately from the check so all three outcomes can be driven
|
|
4
|
+
* directly, the same arrangement `describeInstalledPackage` uses: a check
|
|
5
|
+
* whose only entry point is `run` can be tested for the state the machine
|
|
6
|
+
* happens to be in and nothing else.
|
|
7
|
+
*/
|
|
8
|
+
export declare function describeLogPipeline(counters: LogSinkCounters | undefined): DoctorCheckResult;
|
|
9
|
+
export declare const loggingPipelineCheck: DoctorCheck;
|
|
10
|
+
//# sourceMappingURL=logging.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logging.d.ts","sourceRoot":"","sources":["../../../src/doctor/checks/logging.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAkCjF;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,eAAe,GAAG,SAAS,GAAG,iBAAiB,CA6B5F;AAED,eAAO,MAAM,oBAAoB,EAAE,WAOlC,CAAA"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { getLogCounters } from '@namzu/sdk';
|
|
2
|
+
/**
|
|
3
|
+
* What the log pipeline actually did to this process's records.
|
|
4
|
+
*
|
|
5
|
+
* `LogSinkCounters` has counted five things on every record since the sink
|
|
6
|
+
* seam landed — dropped, redacted, attributes shed, values truncated,
|
|
7
|
+
* records shrunk — and until this check nothing read any of them. That is
|
|
8
|
+
* `declared-but-undriven` with an unusually direct tell: the comment above
|
|
9
|
+
* `createLogger` promised "a caller that wants to observe the pipeline — a
|
|
10
|
+
* test, `namzu doctor` later — reads `.counters` off the same reference",
|
|
11
|
+
* and `namzu doctor` did not. This file is that comment coming true.
|
|
12
|
+
*
|
|
13
|
+
* The counters only became readable as part of this change. They lived on
|
|
14
|
+
* whatever logger `createLogger` happened to build, and `getRootLogger`
|
|
15
|
+
* builds a new one on every call, so each count died with the expression
|
|
16
|
+
* that produced it. `installProcessSink` now owns one set for the process
|
|
17
|
+
* and every logger routed through it adds to those totals.
|
|
18
|
+
*/
|
|
19
|
+
/** Field-by-field, so a new counter cannot be silently left unreported. */
|
|
20
|
+
const FIELDS = [
|
|
21
|
+
'dropped',
|
|
22
|
+
'redacted',
|
|
23
|
+
'attributesDropped',
|
|
24
|
+
'valuesTruncated',
|
|
25
|
+
'recordsTruncated',
|
|
26
|
+
];
|
|
27
|
+
function summarise(counters) {
|
|
28
|
+
return FIELDS.map((f) => `${f}=${counters[f]}`).join(' ');
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Exported separately from the check so all three outcomes can be driven
|
|
32
|
+
* directly, the same arrangement `describeInstalledPackage` uses: a check
|
|
33
|
+
* whose only entry point is `run` can be tested for the state the machine
|
|
34
|
+
* happens to be in and nothing else.
|
|
35
|
+
*/
|
|
36
|
+
export function describeLogPipeline(counters) {
|
|
37
|
+
if (counters === undefined) {
|
|
38
|
+
// NOT `pass`, and not five zeros dressed up as one. Nothing measured
|
|
39
|
+
// these records, so "nothing was dropped" is a claim this check has no
|
|
40
|
+
// standing to make — and it is the claim a reader would take from a
|
|
41
|
+
// green row. The CLI installs a sink during boot, so reaching here at
|
|
42
|
+
// all means that boot step did not run.
|
|
43
|
+
return {
|
|
44
|
+
status: 'inconclusive',
|
|
45
|
+
message: 'no log sink installed — records reach stderr through the legacy path, where nothing is counted, redacted or size-capped',
|
|
46
|
+
remediation: 'A host owns its log destination: call installProcessSink(sink, level) during boot. The CLI does this itself, so seeing this from `namzu doctor` means that step did not run.',
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
if (counters.dropped > 0) {
|
|
50
|
+
return {
|
|
51
|
+
status: 'fail',
|
|
52
|
+
message: `${counters.dropped} log record(s) never reached the sink — ${summarise(counters)}`,
|
|
53
|
+
remediation: 'A record is counted dropped when the installed sink threw, or when the sink is NOOP_SINK. Check the sink passed to installProcessSink: a sink that throws is caught so one bad record cannot fail a run, which is exactly why the count is the only place this shows up.',
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
status: 'pass',
|
|
58
|
+
message: `log pipeline live, nothing dropped — ${summarise(counters)}`,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
export const loggingPipelineCheck = {
|
|
62
|
+
id: 'logging.pipeline',
|
|
63
|
+
// `DoctorCategory` has no `logging` member, and widening that union is an
|
|
64
|
+
// SDK type change this check does not need — the same call the optional
|
|
65
|
+
// package probes made for `files` and `computer-use`.
|
|
66
|
+
category: 'custom',
|
|
67
|
+
run: () => Promise.resolve(describeLogPipeline(getLogCounters())),
|
|
68
|
+
};
|
|
69
|
+
//# sourceMappingURL=logging.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logging.js","sourceRoot":"","sources":["../../../src/doctor/checks/logging.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAE3C;;;;;;;;;;;;;;;;GAgBG;AAEH,2EAA2E;AAC3E,MAAM,MAAM,GAAuC;IAClD,SAAS;IACT,UAAU;IACV,mBAAmB;IACnB,iBAAiB;IACjB,kBAAkB;CAClB,CAAA;AAED,SAAS,SAAS,CAAC,QAAyB;IAC3C,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAC1D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,QAAqC;IACxE,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC5B,qEAAqE;QACrE,uEAAuE;QACvE,oEAAoE;QACpE,sEAAsE;QACtE,wCAAwC;QACxC,OAAO;YACN,MAAM,EAAE,cAAc;YACtB,OAAO,EACN,yHAAyH;YAC1H,WAAW,EACV,8KAA8K;SAC/K,CAAA;IACF,CAAC;IAED,IAAI,QAAQ,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC;QAC1B,OAAO;YACN,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,GAAG,QAAQ,CAAC,OAAO,2CAA2C,SAAS,CAAC,QAAQ,CAAC,EAAE;YAC5F,WAAW,EACV,0QAA0Q;SAC3Q,CAAA;IACF,CAAC;IAED,OAAO;QACN,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,wCAAwC,SAAS,CAAC,QAAQ,CAAC,EAAE;KACtE,CAAA;AACF,CAAC;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAgB;IAChD,EAAE,EAAE,kBAAkB;IACtB,0EAA0E;IAC1E,wEAAwE;IACxE,sDAAsD;IACtD,QAAQ,EAAE,QAAQ;IAClB,GAAG,EAAE,GAA+B,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC,cAAc,EAAE,CAAC,CAAC;CAC7F,CAAA"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { DoctorCheck, DoctorCheckResult } from '@namzu/sdk';
|
|
2
|
+
import type { NamzuCliConfig } from '../../config/schema.js';
|
|
3
|
+
import { type TelemetryLoader } from '../../integrations/telemetry/session-export.js';
|
|
4
|
+
/**
|
|
5
|
+
* Is this machine sending conversation content anywhere?
|
|
6
|
+
*
|
|
7
|
+
* A doctor row rather than only a boot line, because the two answer for
|
|
8
|
+
* different people at different moments: the boot narrative tells whoever
|
|
9
|
+
* started the run, and `namzu doctor` is what somebody runs when they are
|
|
10
|
+
* asked "does this tool send our transcripts off the box" and need an answer
|
|
11
|
+
* they can paste.
|
|
12
|
+
*
|
|
13
|
+
* The row is a `pass` in both directions on purpose. Export being ON is not
|
|
14
|
+
* a fault — it is a configuration somebody chose — so reporting it as a
|
|
15
|
+
* warning would train a reader to ignore the one row that describes their
|
|
16
|
+
* data leaving. What the row owes them is the destination and the redactor
|
|
17
|
+
* count, which is exactly what `describeSessionExport` already builds.
|
|
18
|
+
*/
|
|
19
|
+
export declare function describeSessionExportStatus(config: NamzuCliConfig, loader?: TelemetryLoader): Promise<DoctorCheckResult>;
|
|
20
|
+
export declare function sessionExportCheck(config: NamzuCliConfig, loader?: TelemetryLoader): DoctorCheck;
|
|
21
|
+
//# sourceMappingURL=session-export.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-export.d.ts","sourceRoot":"","sources":["../../../src/doctor/checks/session-export.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAEhE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAC5D,OAAO,EACN,KAAK,eAAe,EAEpB,MAAM,gDAAgD,CAAA;AAEvD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,2BAA2B,CAChD,MAAM,EAAE,cAAc,EACtB,MAAM,CAAC,EAAE,eAAe,GACtB,OAAO,CAAC,iBAAiB,CAAC,CAyC5B;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,eAAe,GAAG,WAAW,CAMhG"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { describeSessionExportOff, } from '../../integrations/telemetry/session-export.js';
|
|
2
|
+
/**
|
|
3
|
+
* Is this machine sending conversation content anywhere?
|
|
4
|
+
*
|
|
5
|
+
* A doctor row rather than only a boot line, because the two answer for
|
|
6
|
+
* different people at different moments: the boot narrative tells whoever
|
|
7
|
+
* started the run, and `namzu doctor` is what somebody runs when they are
|
|
8
|
+
* asked "does this tool send our transcripts off the box" and need an answer
|
|
9
|
+
* they can paste.
|
|
10
|
+
*
|
|
11
|
+
* The row is a `pass` in both directions on purpose. Export being ON is not
|
|
12
|
+
* a fault — it is a configuration somebody chose — so reporting it as a
|
|
13
|
+
* warning would train a reader to ignore the one row that describes their
|
|
14
|
+
* data leaving. What the row owes them is the destination and the redactor
|
|
15
|
+
* count, which is exactly what `describeSessionExport` already builds.
|
|
16
|
+
*/
|
|
17
|
+
export async function describeSessionExportStatus(config, loader) {
|
|
18
|
+
const configured = config.telemetry?.sessionExport;
|
|
19
|
+
if (!configured) {
|
|
20
|
+
const off = await describeSessionExportOff(loader);
|
|
21
|
+
return {
|
|
22
|
+
status: 'pass',
|
|
23
|
+
message: off ?? 'Session export is off: telemetry.sessionExport is not configured.',
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
// The disclosure is built from the config, not from a live listener: a
|
|
27
|
+
// doctor run must be able to answer this without starting a session, and
|
|
28
|
+
// starting one to find out what it would export would be the check
|
|
29
|
+
// causing the thing it reports on.
|
|
30
|
+
const off = await describeSessionExportOff(loader);
|
|
31
|
+
if (off === null) {
|
|
32
|
+
// Configured, but the package that would do it is not installed. The
|
|
33
|
+
// run itself refuses in this state (`attachSessionExport`), and saying
|
|
34
|
+
// so here is what stops an operator discovering it at run time.
|
|
35
|
+
return {
|
|
36
|
+
status: 'fail',
|
|
37
|
+
message: `telemetry.sessionExport is configured (destination: ${configured.destination}) but "@namzu/telemetry" is not installed, so nothing would be recorded.`,
|
|
38
|
+
remediation: 'Install @namzu/telemetry, or remove telemetry.sessionExport from your config. namzu refuses to start a session in this state rather than run one whose export silently does not exist.',
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const redactorCount = configured.redactors?.length ?? 1;
|
|
42
|
+
const typePhrase = configured.eventTypes
|
|
43
|
+
? `${configured.eventTypes.length} event type(s)`
|
|
44
|
+
: 'every run event';
|
|
45
|
+
return {
|
|
46
|
+
status: 'pass',
|
|
47
|
+
message: `Session export is ON: ${typePhrase} is written to ${configured.destination}, with ${redactorCount} redactor(s) installed.`,
|
|
48
|
+
...(redactorCount === 0
|
|
49
|
+
? {
|
|
50
|
+
remediation: '`redactors: []` turns redaction off entirely — credential-shaped values in tool results will be written verbatim. Remove the key to install the shipped `secrets` redactor.',
|
|
51
|
+
}
|
|
52
|
+
: {}),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
export function sessionExportCheck(config, loader) {
|
|
56
|
+
return {
|
|
57
|
+
id: 'telemetry.session-export',
|
|
58
|
+
category: 'telemetry',
|
|
59
|
+
run: () => describeSessionExportStatus(config, loader),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=session-export.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-export.js","sourceRoot":"","sources":["../../../src/doctor/checks/session-export.ts"],"names":[],"mappings":"AAGA,OAAO,EAEN,wBAAwB,GACxB,MAAM,gDAAgD,CAAA;AAEvD;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAChD,MAAsB,EACtB,MAAwB;IAExB,MAAM,UAAU,GAAG,MAAM,CAAC,SAAS,EAAE,aAAa,CAAA;IAClD,IAAI,CAAC,UAAU,EAAE,CAAC;QACjB,MAAM,GAAG,GAAG,MAAM,wBAAwB,CAAC,MAAM,CAAC,CAAA;QAClD,OAAO;YACN,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,GAAG,IAAI,mEAAmE;SACnF,CAAA;IACF,CAAC;IAED,uEAAuE;IACvE,yEAAyE;IACzE,mEAAmE;IACnE,mCAAmC;IACnC,MAAM,GAAG,GAAG,MAAM,wBAAwB,CAAC,MAAM,CAAC,CAAA;IAClD,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QAClB,qEAAqE;QACrE,uEAAuE;QACvE,gEAAgE;QAChE,OAAO;YACN,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,uDAAuD,UAAU,CAAC,WAAW,0EAA0E;YAChK,WAAW,EACV,wLAAwL;SACzL,CAAA;IACF,CAAC;IAED,MAAM,aAAa,GAAG,UAAU,CAAC,SAAS,EAAE,MAAM,IAAI,CAAC,CAAA;IACvD,MAAM,UAAU,GAAG,UAAU,CAAC,UAAU;QACvC,CAAC,CAAC,GAAG,UAAU,CAAC,UAAU,CAAC,MAAM,gBAAgB;QACjD,CAAC,CAAC,iBAAiB,CAAA;IACpB,OAAO;QACN,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,yBAAyB,UAAU,kBAAkB,UAAU,CAAC,WAAW,UAAU,aAAa,yBAAyB;QACpI,GAAG,CAAC,aAAa,KAAK,CAAC;YACtB,CAAC,CAAC;gBACA,WAAW,EACV,6KAA6K;aAC9K;YACF,CAAC,CAAC,EAAE,CAAC;KACN,CAAA;AACF,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,MAAsB,EAAE,MAAwB;IAClF,OAAO;QACN,EAAE,EAAE,0BAA0B;QAC9B,QAAQ,EAAE,WAAW;QACrB,GAAG,EAAE,GAA+B,EAAE,CAAC,2BAA2B,CAAC,MAAM,EAAE,MAAM,CAAC;KAClF,CAAA;AACF,CAAC"}
|
|
@@ -8,38 +8,25 @@ import type { DoctorCheck, DoctorCheckResult } from '@namzu/sdk';
|
|
|
8
8
|
* deferred to a follow-up check that the consumer can register
|
|
9
9
|
* themselves once their telemetry config is known.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* Splitting the question is what makes each answer honest, and a code check on
|
|
20
|
-
* the thrown error is not enough to do it: a transitive dependency that cannot
|
|
21
|
-
* resolve raises `ERR_MODULE_NOT_FOUND` exactly as a missing `@namzu/telemetry`
|
|
22
|
-
* does, so matching on the code would report a broken installation as no
|
|
23
|
-
* installation. `resolve` asks only about THIS specifier, so it separates the
|
|
24
|
-
* two by construction rather than by reading a message that may be reworded.
|
|
25
|
-
*
|
|
26
|
-
* - cannot resolve → the package is not here → `skipped`
|
|
27
|
-
* - resolves, import throws → it is here and unusable → `fail`
|
|
11
|
+
* The three-state resolve-then-import probe this used to do inline now
|
|
12
|
+
* lives at `context/capabilities.ts` as `probeOptionalPackage` (NZ-BOOT-02),
|
|
13
|
+
* extracted so the boot path can report the SAME answer about
|
|
14
|
+
* `@namzu/sandbox`, `@namzu/files` and `@namzu/computer-use` that this file
|
|
15
|
+
* has always given about telemetry, instead of inventing its own. What
|
|
16
|
+
* stays here is the one thing the doctor still owns: turning that answer
|
|
17
|
+
* into the prose and remediation a `DoctorCheckResult` carries.
|
|
28
18
|
*/
|
|
29
19
|
/**
|
|
30
|
-
*
|
|
20
|
+
* `specifier`'s `CapabilityProbe`, read as a `DoctorCheckResult`.
|
|
31
21
|
*
|
|
32
22
|
* Exported separately from the `DoctorCheck` so all three outcomes can be
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* code path serves a package name and a file, which is what lets the
|
|
41
|
-
* present-but-broken case be reached at all. Resolution has already applied the
|
|
42
|
-
* package's export map by that point.
|
|
23
|
+
* asserted directly — there is no way to uninstall or break a real optional
|
|
24
|
+
* package from inside a test run, so `capabilities.test.ts` drives
|
|
25
|
+
* `probeOptionalPackage` with fixtures and this function's own tests only
|
|
26
|
+
* need to check the mapping. The check itself is still exercised through
|
|
27
|
+
* `telemetryInstalledCheck.run`, because a helper proven in isolation says
|
|
28
|
+
* nothing about whether the check reaches it. Same arrangement, and the
|
|
29
|
+
* same reason, as `describeProviderChain`.
|
|
43
30
|
*/
|
|
44
31
|
export declare function describeInstalledPackage(specifier: string): Promise<DoctorCheckResult>;
|
|
45
32
|
export declare const telemetryInstalledCheck: DoctorCheck;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"telemetry.d.ts","sourceRoot":"","sources":["../../../src/doctor/checks/telemetry.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"telemetry.d.ts","sourceRoot":"","sources":["../../../src/doctor/checks/telemetry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAMhE;;;;;;;;;;;;;;;;GAgBG;AACH;;;;;;;;;;;GAWG;AACH,wBAAsB,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAoB5F;AAED,eAAO,MAAM,uBAAuB,EAAE,WAIrC,CAAA"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { pathToFileURL } from 'node:url';
|
|
1
|
+
import { probeOptionalPackage } from '../../context/capabilities.js';
|
|
3
2
|
const TELEMETRY = '@namzu/telemetry';
|
|
4
3
|
/**
|
|
5
4
|
* Telemetry presence probe.
|
|
@@ -10,64 +9,45 @@ const TELEMETRY = '@namzu/telemetry';
|
|
|
10
9
|
* deferred to a follow-up check that the consumer can register
|
|
11
10
|
* themselves once their telemetry config is known.
|
|
12
11
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* Splitting the question is what makes each answer honest, and a code check on
|
|
22
|
-
* the thrown error is not enough to do it: a transitive dependency that cannot
|
|
23
|
-
* resolve raises `ERR_MODULE_NOT_FOUND` exactly as a missing `@namzu/telemetry`
|
|
24
|
-
* does, so matching on the code would report a broken installation as no
|
|
25
|
-
* installation. `resolve` asks only about THIS specifier, so it separates the
|
|
26
|
-
* two by construction rather than by reading a message that may be reworded.
|
|
27
|
-
*
|
|
28
|
-
* - cannot resolve → the package is not here → `skipped`
|
|
29
|
-
* - resolves, import throws → it is here and unusable → `fail`
|
|
12
|
+
* The three-state resolve-then-import probe this used to do inline now
|
|
13
|
+
* lives at `context/capabilities.ts` as `probeOptionalPackage` (NZ-BOOT-02),
|
|
14
|
+
* extracted so the boot path can report the SAME answer about
|
|
15
|
+
* `@namzu/sandbox`, `@namzu/files` and `@namzu/computer-use` that this file
|
|
16
|
+
* has always given about telemetry, instead of inventing its own. What
|
|
17
|
+
* stays here is the one thing the doctor still owns: turning that answer
|
|
18
|
+
* into the prose and remediation a `DoctorCheckResult` carries.
|
|
30
19
|
*/
|
|
31
20
|
/**
|
|
32
|
-
*
|
|
21
|
+
* `specifier`'s `CapabilityProbe`, read as a `DoctorCheckResult`.
|
|
33
22
|
*
|
|
34
23
|
* Exported separately from the `DoctorCheck` so all three outcomes can be
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* code path serves a package name and a file, which is what lets the
|
|
43
|
-
* present-but-broken case be reached at all. Resolution has already applied the
|
|
44
|
-
* package's export map by that point.
|
|
24
|
+
* asserted directly — there is no way to uninstall or break a real optional
|
|
25
|
+
* package from inside a test run, so `capabilities.test.ts` drives
|
|
26
|
+
* `probeOptionalPackage` with fixtures and this function's own tests only
|
|
27
|
+
* need to check the mapping. The check itself is still exercised through
|
|
28
|
+
* `telemetryInstalledCheck.run`, because a helper proven in isolation says
|
|
29
|
+
* nothing about whether the check reaches it. Same arrangement, and the
|
|
30
|
+
* same reason, as `describeProviderChain`.
|
|
45
31
|
*/
|
|
46
32
|
export async function describeInstalledPackage(specifier) {
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
message: `${specifier}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
// The reason is the whole value of separating these: "installed but
|
|
66
|
-
// will not load" sends the reader somewhere, and "not installed" would
|
|
67
|
-
// have sent them to install what is already there.
|
|
68
|
-
message: `${specifier} is installed but failed to load: ${err instanceof Error ? err.message : String(err)}`,
|
|
69
|
-
remediation: `Reinstall ${specifier}, or remove it if you are not using telemetry — it is optional and namzu runs without it.`,
|
|
70
|
-
};
|
|
33
|
+
const probe = await probeOptionalPackage(specifier);
|
|
34
|
+
switch (probe.state) {
|
|
35
|
+
case 'absent':
|
|
36
|
+
return {
|
|
37
|
+
status: 'skipped',
|
|
38
|
+
message: `${specifier} not installed (optional package)`,
|
|
39
|
+
};
|
|
40
|
+
case 'present':
|
|
41
|
+
return { status: 'pass', message: `${specifier} is installed` };
|
|
42
|
+
case 'broken':
|
|
43
|
+
return {
|
|
44
|
+
status: 'fail',
|
|
45
|
+
// The reason is the whole value of separating these: "installed but
|
|
46
|
+
// will not load" sends the reader somewhere, and "not installed" would
|
|
47
|
+
// have sent them to install what is already there.
|
|
48
|
+
message: `${specifier} is installed but failed to load: ${probe.error.message}`,
|
|
49
|
+
remediation: `Reinstall ${specifier}, or remove it if you are not using it — it is optional and namzu runs without it.`,
|
|
50
|
+
};
|
|
71
51
|
}
|
|
72
52
|
}
|
|
73
53
|
export const telemetryInstalledCheck = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"telemetry.js","sourceRoot":"","sources":["../../../src/doctor/checks/telemetry.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"telemetry.js","sourceRoot":"","sources":["../../../src/doctor/checks/telemetry.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAA;AAEpE,MAAM,SAAS,GAAG,kBAAkB,CAAA;AAEpC;;;;;;;;;;;;;;;;GAgBG;AACH;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,SAAiB;IAC/D,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,SAAS,CAAC,CAAA;IACnD,QAAQ,KAAK,CAAC,KAAK,EAAE,CAAC;QACrB,KAAK,QAAQ;YACZ,OAAO;gBACN,MAAM,EAAE,SAAS;gBACjB,OAAO,EAAE,GAAG,SAAS,mCAAmC;aACxD,CAAA;QACF,KAAK,SAAS;YACb,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,SAAS,eAAe,EAAE,CAAA;QAChE,KAAK,QAAQ;YACZ,OAAO;gBACN,MAAM,EAAE,MAAM;gBACd,oEAAoE;gBACpE,uEAAuE;gBACvE,mDAAmD;gBACnD,OAAO,EAAE,GAAG,SAAS,qCAAqC,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE;gBAC/E,WAAW,EAAE,aAAa,SAAS,oFAAoF;aACvH,CAAA;IACH,CAAC;AACF,CAAC;AAED,MAAM,CAAC,MAAM,uBAAuB,GAAgB;IACnD,EAAE,EAAE,qBAAqB;IACzB,QAAQ,EAAE,WAAW;IACrB,GAAG,EAAE,GAA+B,EAAE,CAAC,wBAAwB,CAAC,SAAS,CAAC;CAC1E,CAAA"}
|
|
@@ -1,22 +1,6 @@
|
|
|
1
|
-
import type { DoctorCheck } from '@namzu/sdk';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
* `CredentialVault` is an interface, not a globally-discoverable
|
|
6
|
-
* registry — consumers instantiate their own (`InMemoryCredentialVault`,
|
|
7
|
-
* file-backed, env-backed, KMS-backed, …). The doctor cannot enumerate
|
|
8
|
-
* vaults it doesn't know about. To get a real vault healthcheck, the
|
|
9
|
-
* consumer registers a custom check via `registerDoctorCheck` that
|
|
10
|
-
* exercises their specific vault wiring.
|
|
11
|
-
*
|
|
12
|
-
* `skipped`, not `inconclusive`, and the difference is the whole point of the
|
|
13
|
-
* split: `inconclusive` means a check tried and could not answer, which is a
|
|
14
|
-
* gap in the report and now carries a non-zero exit code. This check has no
|
|
15
|
-
* subject to answer about — there is no discovery mechanism to fail — and that
|
|
16
|
-
* is true on every machine, permanently, by design. Reporting a permanent
|
|
17
|
-
* design decision as an unanswered question would make `namzu doctor` non-zero
|
|
18
|
-
* on every healthy machine, and a diagnostic that always complains is one
|
|
19
|
-
* nobody reads.
|
|
20
|
-
*/
|
|
1
|
+
import type { CredentialProvider, DoctorCheck } from '@namzu/sdk';
|
|
2
|
+
export declare function registerCredentialProvider(provider: CredentialProvider, label: string, refs: readonly string[]): () => void;
|
|
3
|
+
/** For tests, and for a host rebuilding its wiring. */
|
|
4
|
+
export declare function clearRegisteredCredentialProviders(): void;
|
|
21
5
|
export declare const vaultRegisteredCheck: DoctorCheck;
|
|
22
6
|
//# sourceMappingURL=vault.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vault.d.ts","sourceRoot":"","sources":["../../../src/doctor/checks/vault.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAqB,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"vault.d.ts","sourceRoot":"","sources":["../../../src/doctor/checks/vault.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAqB,MAAM,YAAY,CAAA;AAmBpF,wBAAgB,0BAA0B,CACzC,QAAQ,EAAE,kBAAkB,EAC5B,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,SAAS,MAAM,EAAE,GACrB,MAAM,IAAI,CAOZ;AAED,uDAAuD;AACvD,wBAAgB,kCAAkC,IAAI,IAAI,CAEzD;AAED,eAAO,MAAM,oBAAoB,EAAE,WA0ClC,CAAA"}
|