@dsh-cc/command-doctor 0.5.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 (89) hide show
  1. package/LICENSE +201 -0
  2. package/README.i18n.yaml +6 -0
  3. package/README.md +47 -0
  4. package/README.zh.md +47 -0
  5. package/lib/checks/env.d.ts +12 -0
  6. package/lib/checks/env.d.ts.map +1 -0
  7. package/lib/checks/env.js +71 -0
  8. package/lib/checks/env.js.map +1 -0
  9. package/lib/checks/git.d.ts +26 -0
  10. package/lib/checks/git.d.ts.map +1 -0
  11. package/lib/checks/git.js +94 -0
  12. package/lib/checks/git.js.map +1 -0
  13. package/lib/checks/hooks.d.ts +33 -0
  14. package/lib/checks/hooks.d.ts.map +1 -0
  15. package/lib/checks/hooks.js +138 -0
  16. package/lib/checks/hooks.js.map +1 -0
  17. package/lib/checks/mcp.d.ts +24 -0
  18. package/lib/checks/mcp.d.ts.map +1 -0
  19. package/lib/checks/mcp.js +107 -0
  20. package/lib/checks/mcp.js.map +1 -0
  21. package/lib/checks/models.d.ts +57 -0
  22. package/lib/checks/models.d.ts.map +1 -0
  23. package/lib/checks/models.js +190 -0
  24. package/lib/checks/models.js.map +1 -0
  25. package/lib/checks/plugins.d.ts +24 -0
  26. package/lib/checks/plugins.d.ts.map +1 -0
  27. package/lib/checks/plugins.js +55 -0
  28. package/lib/checks/plugins.js.map +1 -0
  29. package/lib/checks/seams.d.ts +12 -0
  30. package/lib/checks/seams.d.ts.map +1 -0
  31. package/lib/checks/seams.js +44 -0
  32. package/lib/checks/seams.js.map +1 -0
  33. package/lib/checks/session.d.ts +10 -0
  34. package/lib/checks/session.d.ts.map +1 -0
  35. package/lib/checks/session.js +88 -0
  36. package/lib/checks/session.js.map +1 -0
  37. package/lib/checks/storage.d.ts +13 -0
  38. package/lib/checks/storage.d.ts.map +1 -0
  39. package/lib/checks/storage.js +53 -0
  40. package/lib/checks/storage.js.map +1 -0
  41. package/lib/checks/web.d.ts +12 -0
  42. package/lib/checks/web.d.ts.map +1 -0
  43. package/lib/checks/web.js +128 -0
  44. package/lib/checks/web.js.map +1 -0
  45. package/lib/collect.d.ts +28 -0
  46. package/lib/collect.d.ts.map +1 -0
  47. package/lib/collect.js +76 -0
  48. package/lib/collect.js.map +1 -0
  49. package/lib/doctor.d.ts +8 -0
  50. package/lib/doctor.d.ts.map +1 -0
  51. package/lib/doctor.js +7 -0
  52. package/lib/doctor.js.map +1 -0
  53. package/lib/flags.d.ts +23 -0
  54. package/lib/flags.d.ts.map +1 -0
  55. package/lib/flags.js +36 -0
  56. package/lib/flags.js.map +1 -0
  57. package/lib/index.d.ts +20 -0
  58. package/lib/index.d.ts.map +1 -0
  59. package/lib/index.js +71 -0
  60. package/lib/index.js.map +1 -0
  61. package/lib/invariant.d.ts +16 -0
  62. package/lib/invariant.d.ts.map +1 -0
  63. package/lib/invariant.js +23 -0
  64. package/lib/invariant.js.map +1 -0
  65. package/lib/json.d.ts +19 -0
  66. package/lib/json.d.ts.map +1 -0
  67. package/lib/json.js +27 -0
  68. package/lib/json.js.map +1 -0
  69. package/lib/last-model.d.ts +23 -0
  70. package/lib/last-model.d.ts.map +1 -0
  71. package/lib/last-model.js +30 -0
  72. package/lib/last-model.js.map +1 -0
  73. package/lib/redact.d.ts +14 -0
  74. package/lib/redact.d.ts.map +1 -0
  75. package/lib/redact.js +53 -0
  76. package/lib/redact.js.map +1 -0
  77. package/lib/render.d.ts +17 -0
  78. package/lib/render.d.ts.map +1 -0
  79. package/lib/render.js +60 -0
  80. package/lib/render.js.map +1 -0
  81. package/lib/report.d.ts +60 -0
  82. package/lib/report.d.ts.map +1 -0
  83. package/lib/report.js +18 -0
  84. package/lib/report.js.map +1 -0
  85. package/lib/version.d.ts +29 -0
  86. package/lib/version.d.ts.map +1 -0
  87. package/lib/version.js +62 -0
  88. package/lib/version.js.map +1 -0
  89. package/package.json +51 -0
package/lib/index.js ADDED
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Human-facing `/doctor` command: a product-grade session health report with
3
+ * three renderings of one data object — default text, verbose text, and a
4
+ * JSON file written under `$DSH_HOME`.
5
+ * @module @dsh-cc/command-doctor
6
+ */
7
+ import { collect } from "./collect.js";
8
+ import { formatUsage, parseDoctorFlags } from "./flags.js";
9
+ import { doctorJsonPath, writeDoctorReport } from "./json.js";
10
+ import { redactReport } from "./redact.js";
11
+ import { formatDoctorReport } from "./render.js";
12
+ export { readVersion } from "./version.js";
13
+ export { DOCTOR_USAGE, parseDoctorFlags } from "./flags.js";
14
+ export { redactReport } from "./redact.js";
15
+ export { collect } from "./collect.js";
16
+ export const name = 'command-doctor';
17
+ export const inject = ['commands'];
18
+ /** Execute `/doctor [flags]` against the composed context. */
19
+ async function executeDoctor(ctx, invocation) {
20
+ const flags = parseDoctorFlags(invocation.rawInput);
21
+ if (flags.kind === 'usage') {
22
+ return { kind: 'success', text: formatUsage() };
23
+ }
24
+ const t0 = performance.now();
25
+ const collected = await collect(ctx, invocation, {
26
+ verbose: flags.verbose || flags.json,
27
+ now: () => new Date(),
28
+ ms: () => performance.now() - t0,
29
+ });
30
+ const report = redactReport(collected);
31
+ if (flags.json) {
32
+ return { kind: 'success', text: await emitJson(report) };
33
+ }
34
+ return { kind: 'success', text: formatDoctorReport(report, { verbose: flags.verbose }) };
35
+ }
36
+ /** Write the JSON file and produce the short ack text (never the JSON body). */
37
+ async function emitJson(report) {
38
+ const path = doctorJsonPath();
39
+ const summary = `summary: ${report.summary.ok} ok, ${report.summary.warn} warn, ${report.summary.fail} fail, ${report.summary.skip} skip, ${report.summary.info} info`;
40
+ const ids = statusIds(report);
41
+ try {
42
+ await writeDoctorReport(path, report);
43
+ return [`doctor report written: ${path}`, summary, ...ids].join('\n');
44
+ }
45
+ catch (error) {
46
+ return [`failed to write ${path}: ${String(error)}`, summary, ...ids].join('\n');
47
+ }
48
+ }
49
+ /** The fail/warn ids appended under the JSON ack. */
50
+ function statusIds(report) {
51
+ const lines = [];
52
+ for (const status of ['fail', 'warn']) {
53
+ const ids = report.checks.filter(check => check.status === status).map(check => check.id);
54
+ if (ids.length > 0)
55
+ lines.push(`${status}: ${ids.join(', ')}`);
56
+ }
57
+ return lines;
58
+ }
59
+ /**
60
+ * Register the `/doctor` command for every composed command adapter.
61
+ * @param ctx - context carrying the command registry.
62
+ */
63
+ export function apply(ctx) {
64
+ ctx.commands.register({
65
+ name: 'doctor',
66
+ description: 'session health report',
67
+ input: { hint: '[--verbose|--json]' },
68
+ handler: (invocation) => executeDoctor(ctx, invocation),
69
+ });
70
+ }
71
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Package-owned invariant companion for `@dsh-cc/command-doctor`.
3
+ * @module @dsh-cc/command-doctor/invariant
4
+ */
5
+ import type { Context } from '@deepseek-ai/cordis';
6
+ /** Cordis companion plugin name. */
7
+ export declare const name = "command-doctor-invariant";
8
+ /** Service required before the companion can reserve package ownership. */
9
+ export declare const inject: string[];
10
+ /**
11
+ * Register this package's invariant companion.
12
+ * @param ctx - Cordis context carrying the invariant service.
13
+ * @returns the installed registration's disposer after setup succeeds.
14
+ */
15
+ export declare const apply: (ctx: Context) => Promise<() => void>;
16
+ //# sourceMappingURL=invariant.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invariant.d.ts","sourceRoot":"","sources":["../src/invariant.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAKlD,oCAAoC;AACpC,eAAO,MAAM,IAAI,6BAA6B,CAAA;AAC9C,2EAA2E;AAC3E,eAAO,MAAM,MAAM,UAAiB,CAAA;AASpC;;;;GAIG;AACH,eAAO,MAAM,KAAK,GAAI,KAAK,OAAO,KAAG,OAAO,CAAC,MAAM,IAAI,CACU,CAAA"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Package-owned invariant companion for `@dsh-cc/command-doctor`.
3
+ * @module @dsh-cc/command-doctor/invariant
4
+ */
5
+ const PACKAGE_NAME = '@dsh-cc/command-doctor';
6
+ /** Cordis companion plugin name. */
7
+ export const name = 'command-doctor-invariant';
8
+ /** Service required before the companion can reserve package ownership. */
9
+ export const inject = ['invariants'];
10
+ /**
11
+ * No runtime invariant: this command adapter owns no event stream or state projection; the doctor
12
+ * report is a pure read over mounted services and version metadata, and the command registry owns
13
+ * registration and dispatch lifecycle.
14
+ */
15
+ const install = () => { };
16
+ /**
17
+ * Register this package's invariant companion.
18
+ * @param ctx - Cordis context carrying the invariant service.
19
+ * @returns the installed registration's disposer after setup succeeds.
20
+ */
21
+ export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
22
+ /* jscpd:ignore-end */
23
+ //# sourceMappingURL=invariant.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invariant.js","sourceRoot":"","sources":["../src/invariant.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,MAAM,YAAY,GAAG,wBAAwB,CAAA;AAE7C,oCAAoC;AACpC,MAAM,CAAC,MAAM,IAAI,GAAG,0BAA0B,CAAA;AAC9C,2EAA2E;AAC3E,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,YAAY,CAAC,CAAA;AAEpC;;;;GAIG;AACH,MAAM,OAAO,GAAuB,GAAG,EAAE,GAAE,CAAC,CAAA;AAE5C;;;;GAIG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,GAAY,EAAuB,EAAE,CACzD,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAA;AACjE,sBAAsB"}
package/lib/json.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ /**
2
+ * JSON emission: resolve the `doctor-report.json` path under `$DSH_HOME`
3
+ * (default `~/.dsh`) and write (mkdir + overwrite) a redacted report.
4
+ * @module @dsh-cc/command-doctor/json
5
+ */
6
+ import type { DoctorReport } from './report.ts';
7
+ /**
8
+ * Resolve the report path: `$DSH_HOME/tui/doctor-report.json`, falling back
9
+ * to `~/.dsh/tui/doctor-report.json` when `DSH_HOME` is unset.
10
+ */
11
+ export declare function doctorJsonPath(env?: NodeJS.ProcessEnv): string;
12
+ /**
13
+ * Write the report, creating parent directories and overwriting any existing
14
+ * file.
15
+ * @param path - the resolved target path.
16
+ * @param report - the redacted report.
17
+ */
18
+ export declare function writeDoctorReport(path: string, report: DoctorReport): Promise<void>;
19
+ //# sourceMappingURL=json.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../src/json.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE/C;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAG3E;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAGzF"}
package/lib/json.js ADDED
@@ -0,0 +1,27 @@
1
+ /**
2
+ * JSON emission: resolve the `doctor-report.json` path under `$DSH_HOME`
3
+ * (default `~/.dsh`) and write (mkdir + overwrite) a redacted report.
4
+ * @module @dsh-cc/command-doctor/json
5
+ */
6
+ import { mkdir, writeFile } from 'node:fs/promises';
7
+ import { homedir } from 'node:os';
8
+ import { join } from 'node:path';
9
+ /**
10
+ * Resolve the report path: `$DSH_HOME/tui/doctor-report.json`, falling back
11
+ * to `~/.dsh/tui/doctor-report.json` when `DSH_HOME` is unset.
12
+ */
13
+ export function doctorJsonPath(env = process.env) {
14
+ const home = env.DSH_HOME ?? join(homedir(), '.dsh');
15
+ return join(home, 'tui', 'doctor-report.json');
16
+ }
17
+ /**
18
+ * Write the report, creating parent directories and overwriting any existing
19
+ * file.
20
+ * @param path - the resolved target path.
21
+ * @param report - the redacted report.
22
+ */
23
+ export async function writeDoctorReport(path, report) {
24
+ await mkdir(join(path, '..'), { recursive: true });
25
+ await writeFile(path, `${JSON.stringify(report, null, 2)}\n`, 'utf8');
26
+ }
27
+ //# sourceMappingURL=json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.js","sourceRoot":"","sources":["../src/json.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAGhC;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,MAAyB,OAAO,CAAC,GAAG;IACjE,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,CAAC,CAAA;IACpD,OAAO,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,oBAAoB,CAAC,CAAA;AAChD,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,IAAY,EAAE,MAAoB;IACxE,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAClD,MAAM,SAAS,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;AACvE,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Last-model fold for `/doctor`, copied from `/status` (do not import
3
+ * command-status): the most recent `request/header` provider/model, plus an
4
+ * optional duck-read `reasoningEffort`.
5
+ * @module @dsh-cc/command-doctor/last-model
6
+ */
7
+ import type { SessionEvent } from '@deepseek-ai/dsh-session';
8
+ /** A resolved provider route/model pair from a request header. */
9
+ export interface ModelRef {
10
+ readonly provider: string;
11
+ readonly model: string;
12
+ /** Duck-read effort from the header config, when present. */
13
+ readonly reasoningEffort?: string;
14
+ }
15
+ /**
16
+ * Fold the session log for the most recent model route. `request/header`
17
+ * snapshots record the conversation's call config; the last one wins. This is
18
+ * *not* necessarily "the main model" — a command can run from a child agent.
19
+ * @param events - the session's durable event log, in sequence order.
20
+ * @returns the latest provider/model pair, or undefined when no header was logged.
21
+ */
22
+ export declare function lastModel(events: readonly SessionEvent[]): ModelRef | undefined;
23
+ //# sourceMappingURL=last-model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"last-model.d.ts","sourceRoot":"","sources":["../src/last-model.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAE5D,kEAAkE;AAClE,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,6DAA6D;IAC7D,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;CAClC;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,GAAG,QAAQ,GAAG,SAAS,CAc/E"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Last-model fold for `/doctor`, copied from `/status` (do not import
3
+ * command-status): the most recent `request/header` provider/model, plus an
4
+ * optional duck-read `reasoningEffort`.
5
+ * @module @dsh-cc/command-doctor/last-model
6
+ */
7
+ /**
8
+ * Fold the session log for the most recent model route. `request/header`
9
+ * snapshots record the conversation's call config; the last one wins. This is
10
+ * *not* necessarily "the main model" — a command can run from a child agent.
11
+ * @param events - the session's durable event log, in sequence order.
12
+ * @returns the latest provider/model pair, or undefined when no header was logged.
13
+ */
14
+ export function lastModel(events) {
15
+ let result;
16
+ for (const event of events) {
17
+ if (event.type !== 'request/header')
18
+ continue;
19
+ const config = event.data.header.config;
20
+ result = {
21
+ provider: event.data.header.config.provider,
22
+ model: event.data.header.config.model,
23
+ ...(typeof config.reasoningEffort === 'string' && config.reasoningEffort.length > 0
24
+ ? { reasoningEffort: config.reasoningEffort }
25
+ : {}),
26
+ };
27
+ }
28
+ return result;
29
+ }
30
+ //# sourceMappingURL=last-model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"last-model.js","sourceRoot":"","sources":["../src/last-model.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAYH;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,MAA+B;IACvD,IAAI,MAA4B,CAAA;IAChC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,KAAK,CAAC,IAAI,KAAK,gBAAgB;YAAE,SAAQ;QAC7C,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAuC,CAAA;QACxE,MAAM,GAAG;YACP,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ;YAC3C,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK;YACrC,GAAG,CAAC,OAAO,MAAM,CAAC,eAAe,KAAK,QAAQ,IAAI,MAAM,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC;gBACjF,CAAC,CAAC,EAAE,eAAe,EAAE,MAAM,CAAC,eAAe,EAAE;gBAC7C,CAAC,CAAC,EAAE,CAAC;SACR,CAAA;IACH,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Pure report redaction: whitelist evidence primitives and scrub secret-like
3
+ * substrings from every human string in the report. No cordis imports.
4
+ * @module @dsh-cc/command-doctor/redact
5
+ */
6
+ import type { DoctorReport } from './report.ts';
7
+ /**
8
+ * Return a redacted copy of the report. Evidence values must already be
9
+ * primitives; only string evidence is scrubbed. Called once by the handler;
10
+ * both the text render and the JSON write consume the redacted report.
11
+ * @param report - the collected report.
12
+ */
13
+ export declare function redactReport(report: DoctorReport): DoctorReport;
14
+ //# sourceMappingURL=redact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redact.d.ts","sourceRoot":"","sources":["../src/redact.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAS,YAAY,EAAE,MAAM,aAAa,CAAA;AAoCtD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,YAAY,CAW/D"}
package/lib/redact.js ADDED
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Pure report redaction: whitelist evidence primitives and scrub secret-like
3
+ * substrings from every human string in the report. No cordis imports.
4
+ * @module @dsh-cc/command-doctor/redact
5
+ */
6
+ /** Secret-like substrings scrubbed from summary/detail/fix/evidence strings. */
7
+ const SECRET_PATTERNS = [
8
+ { pattern: /sk-[A-Za-z0-9_-]+/gu, replacement: 'sk-[redacted]' },
9
+ { pattern: /ghp_[A-Za-z0-9]+/gu, replacement: 'ghp_[redacted]' },
10
+ { pattern: /xoxb-[A-Za-z0-9-]+/gu, replacement: 'xoxb-[redacted]' },
11
+ { pattern: /Bearer\s+\S+/gu, replacement: 'Bearer [redacted]' },
12
+ ];
13
+ /** Scrub secret-like substrings from one string. */
14
+ function scrub(value) {
15
+ let result = value;
16
+ for (const { pattern, replacement } of SECRET_PATTERNS) {
17
+ result = result.replace(pattern, replacement);
18
+ }
19
+ return result;
20
+ }
21
+ /** Scrub one optional human field. */
22
+ function scrubOptional(value) {
23
+ return value === undefined ? undefined : scrub(value);
24
+ }
25
+ /** Scrub evidence string values; non-string primitives pass through untouched. */
26
+ function scrubEvidence(evidence) {
27
+ if (evidence === undefined)
28
+ return undefined;
29
+ const entries = Object.entries(evidence).map(([key, value]) => [
30
+ key,
31
+ typeof value === 'string' ? scrub(value) : value,
32
+ ]);
33
+ return Object.fromEntries(entries);
34
+ }
35
+ /**
36
+ * Return a redacted copy of the report. Evidence values must already be
37
+ * primitives; only string evidence is scrubbed. Called once by the handler;
38
+ * both the text render and the JSON write consume the redacted report.
39
+ * @param report - the collected report.
40
+ */
41
+ export function redactReport(report) {
42
+ return {
43
+ ...report,
44
+ checks: report.checks.map(check => ({
45
+ ...check,
46
+ summary: scrub(check.summary),
47
+ detail: scrubOptional(check.detail),
48
+ fix: scrubOptional(check.fix),
49
+ evidence: scrubEvidence(check.evidence),
50
+ })),
51
+ };
52
+ }
53
+ //# sourceMappingURL=redact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redact.js","sourceRoot":"","sources":["../src/redact.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,gFAAgF;AAChF,MAAM,eAAe,GAAwD;IAC3E,EAAE,OAAO,EAAE,qBAAqB,EAAE,WAAW,EAAE,eAAe,EAAE;IAChE,EAAE,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAE,gBAAgB,EAAE;IAChE,EAAE,OAAO,EAAE,sBAAsB,EAAE,WAAW,EAAE,iBAAiB,EAAE;IACnE,EAAE,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,mBAAmB,EAAE;CAChE,CAAA;AAED,oDAAoD;AACpD,SAAS,KAAK,CAAC,KAAa;IAC1B,IAAI,MAAM,GAAG,KAAK,CAAA;IAClB,KAAK,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,eAAe,EAAE,CAAC;QACvD,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,WAAW,CAAC,CAAA;IAC/C,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED,sCAAsC;AACtC,SAAS,aAAa,CAAC,KAAyB;IAC9C,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;AACvD,CAAC;AAED,kFAAkF;AAClF,SAAS,aAAa,CACpB,QAA2B;IAE3B,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,SAAS,CAAA;IAC5C,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC;QAC7D,GAAG;QACH,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK;KACxC,CAAC,CAAA;IACX,OAAO,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAA;AACpC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,MAAoB;IAC/C,OAAO;QACL,GAAG,MAAM;QACT,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAClC,GAAG,KAAK;YACR,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC;YAC7B,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC;YACnC,GAAG,EAAE,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC;YAC7B,QAAQ,EAAE,aAAa,CAAC,KAAK,CAAC,QAAQ,CAAC;SACxC,CAAC,CAAC;KACJ,CAAA;AACH,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * `/doctor` text rendering: default (ok collapsed) and verbose (everything
3
+ * expanded) views over one redacted report. ASCII-only, no emoji.
4
+ * @module @dsh-cc/command-doctor/render
5
+ */
6
+ import { type DoctorReport } from './report.ts';
7
+ export interface RenderOptions {
8
+ /** Expand every check and print evidence. */
9
+ readonly verbose?: boolean;
10
+ }
11
+ /**
12
+ * Render the report as human shell text.
13
+ * @param report - the redacted report.
14
+ * @param options - `{ verbose }` switches to the expanded view.
15
+ */
16
+ export declare function formatDoctorReport(report: DoctorReport, options?: RenderOptions): string;
17
+ //# sourceMappingURL=render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAA4B,KAAK,YAAY,EAAE,MAAM,aAAa,CAAA;AAEzE,MAAM,WAAW,aAAa;IAC5B,6CAA6C;IAC7C,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAC3B;AAyBD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAmB5F"}
package/lib/render.js ADDED
@@ -0,0 +1,60 @@
1
+ /**
2
+ * `/doctor` text rendering: default (ok collapsed) and verbose (everything
3
+ * expanded) views over one redacted report. ASCII-only, no emoji.
4
+ * @module @dsh-cc/command-doctor/render
5
+ */
6
+ import { CHECK_GROUPS } from "./report.js";
7
+ /** Render one status token padded to a stable column width. */
8
+ function statusToken(status) {
9
+ return status.padEnd(4, ' ');
10
+ }
11
+ /** Render one check's evidence as a compact `k=v` list. */
12
+ function evidenceText(check) {
13
+ const entries = Object.entries(check.evidence ?? {});
14
+ if (entries.length === 0)
15
+ return undefined;
16
+ return entries.map(([key, value]) => `${key}=${String(value)}`).join(', ');
17
+ }
18
+ /** Render one check, expanding per the mode. */
19
+ function renderCheck(lines, check, verbose) {
20
+ const expand = verbose || check.status !== 'ok';
21
+ lines.push(` ${statusToken(check.status)} ${check.id}: ${check.summary}`);
22
+ if (!expand)
23
+ return;
24
+ if (check.detail !== undefined)
25
+ lines.push(` ${check.detail}`);
26
+ if (check.fix !== undefined)
27
+ lines.push(` fix: ${check.fix}`);
28
+ const evidence = evidenceText(check);
29
+ if (evidence !== undefined)
30
+ lines.push(` evidence: ${evidence}`);
31
+ }
32
+ /**
33
+ * Render the report as human shell text.
34
+ * @param report - the redacted report.
35
+ * @param options - `{ verbose }` switches to the expanded view.
36
+ */
37
+ export function formatDoctorReport(report, options = {}) {
38
+ const verbose = options.verbose === true;
39
+ const lines = [];
40
+ lines.push(`dsh-cc ${report.env.dshCc}`);
41
+ if (report.env.harness !== undefined)
42
+ lines.push(`harness ${report.env.harness}`);
43
+ lines.push(`node ${report.env.node}`);
44
+ lines.push(`os ${report.env.os} ${report.env.arch}`);
45
+ lines.push(`cwd ${report.env.cwd}`);
46
+ lines.push('');
47
+ for (const group of CHECK_GROUPS) {
48
+ const groupChecks = report.checks.filter(check => check.group === group);
49
+ if (groupChecks.length === 0)
50
+ continue;
51
+ lines.push(`${group}:`);
52
+ for (const check of groupChecks)
53
+ renderCheck(lines, check, verbose);
54
+ }
55
+ const s = report.summary;
56
+ lines.push('');
57
+ lines.push(`summary: ${s.ok} ok, ${s.warn} warn, ${s.fail} fail, ${s.skip} skip, ${s.info} info`);
58
+ return lines.join('\n');
59
+ }
60
+ //# sourceMappingURL=render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Structured `/doctor` report data model: check types, report shape, and the
3
+ * summary counter fold. No cordis imports, so the types and fold are
4
+ * unit-testable in isolation.
5
+ * @module @dsh-cc/command-doctor/report
6
+ */
7
+ /** One check's outcome severity. */
8
+ export type CheckStatus = 'ok' | 'warn' | 'fail' | 'skip' | 'info';
9
+ /** The stable group ordering of the report. */
10
+ export type CheckGroup = 'env' | 'session' | 'models' | 'mcp' | 'hooks' | 'web' | 'storage' | 'git' | 'plugins' | 'seams';
11
+ /** Stable render/JSON ordering of the check groups. */
12
+ export declare const CHECK_GROUPS: readonly CheckGroup[];
13
+ /** One named health observation inside the report. */
14
+ export interface Check {
15
+ /** Kebab, dotted id (e.g. `models.alias.blueprint`). Adding an id is not breaking. */
16
+ readonly id: string;
17
+ /** The group the check belongs to. */
18
+ readonly group: CheckGroup;
19
+ /** The check's outcome. */
20
+ readonly status: CheckStatus;
21
+ /** One-line human summary. */
22
+ readonly summary: string;
23
+ /** Optional expanded human detail for non-ok (or verbose) rendering. */
24
+ readonly detail?: string | undefined;
25
+ /** Whitelisted primitive evidence; scrubbed by `redactReport` before render/JSON. */
26
+ readonly evidence?: Readonly<Record<string, string | number | boolean | null>> | undefined;
27
+ /** Optional suggested fix for warn/fail rows. */
28
+ readonly fix?: string | undefined;
29
+ }
30
+ /** The structured health report `/doctor` renders and writes as JSON. */
31
+ export interface DoctorReport {
32
+ /** Bumps only on a breaking schema change; adding check ids is not breaking. */
33
+ readonly schemaVersion: 1;
34
+ /** ISO timestamp of report generation. */
35
+ readonly generatedAt: string;
36
+ /** Wall-clock duration of the collection, in milliseconds. */
37
+ readonly durationMs: number;
38
+ /** Environment header facts. */
39
+ readonly env: {
40
+ readonly dshCc: string;
41
+ readonly harness?: string;
42
+ readonly node: string;
43
+ readonly os: string;
44
+ readonly arch: string;
45
+ readonly cwd: string;
46
+ };
47
+ /** Every collected check, in group order. */
48
+ readonly checks: readonly Check[];
49
+ /** Per-status counts. */
50
+ readonly summary: {
51
+ ok: number;
52
+ warn: number;
53
+ fail: number;
54
+ skip: number;
55
+ info: number;
56
+ };
57
+ }
58
+ /** Fold the checks into per-status counts. */
59
+ export declare function countSummary(checks: readonly Check[]): DoctorReport['summary'];
60
+ //# sourceMappingURL=report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,oCAAoC;AACpC,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAA;AAElE,+CAA+C;AAC/C,MAAM,MAAM,UAAU,GAClB,KAAK,GACL,SAAS,GACT,QAAQ,GACR,KAAK,GACL,OAAO,GACP,KAAK,GACL,SAAS,GACT,KAAK,GACL,SAAS,GACT,OAAO,CAAA;AAEX,uDAAuD;AACvD,eAAO,MAAM,YAAY,EAAE,SAAS,UAAU,EAE7C,CAAA;AAED,sDAAsD;AACtD,MAAM,WAAW,KAAK;IACpB,sFAAsF;IACtF,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,sCAAsC;IACtC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;IAC1B,2BAA2B;IAC3B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;IAC5B,8BAA8B;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,wEAAwE;IACxE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACpC,qFAAqF;IACrF,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,CAAC,GAAG,SAAS,CAAA;IAC1F,iDAAiD;IACjD,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAClC;AAED,yEAAyE;AACzE,MAAM,WAAW,YAAY;IAC3B,gFAAgF;IAChF,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAA;IACzB,0CAA0C;IAC1C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,8DAA8D;IAC9D,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,gCAAgC;IAChC,QAAQ,CAAC,GAAG,EAAE;QACZ,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;QACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;QACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;QACrB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;QACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;QACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;KACrB,CAAA;IACD,6CAA6C;IAC7C,QAAQ,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,CAAA;IACjC,yBAAyB;IACzB,QAAQ,CAAC,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CACzF;AAED,8CAA8C;AAC9C,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,GAAG,YAAY,CAAC,SAAS,CAAC,CAI9E"}
package/lib/report.js ADDED
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Structured `/doctor` report data model: check types, report shape, and the
3
+ * summary counter fold. No cordis imports, so the types and fold are
4
+ * unit-testable in isolation.
5
+ * @module @dsh-cc/command-doctor/report
6
+ */
7
+ /** Stable render/JSON ordering of the check groups. */
8
+ export const CHECK_GROUPS = [
9
+ 'env', 'session', 'models', 'mcp', 'hooks', 'web', 'storage', 'git', 'plugins', 'seams',
10
+ ];
11
+ /** Fold the checks into per-status counts. */
12
+ export function countSummary(checks) {
13
+ const summary = { ok: 0, warn: 0, fail: 0, skip: 0, info: 0 };
14
+ for (const check of checks)
15
+ summary[check.status] += 1;
16
+ return summary;
17
+ }
18
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAkBH,uDAAuD;AACvD,MAAM,CAAC,MAAM,YAAY,GAA0B;IACjD,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO;CACxF,CAAA;AA2CD,8CAA8C;AAC9C,MAAM,UAAU,YAAY,CAAC,MAAwB;IACnD,MAAM,OAAO,GAAG,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAA;IAC7D,KAAK,MAAM,KAAK,IAAI,MAAM;QAAE,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IACtD,OAAO,OAAO,CAAA;AAChB,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Version and Node engines helpers for `/doctor`. Reads this package's own
3
+ * manifest (mirroring `/version`) and implements the repo's single engines
4
+ * range without a `semver` dependency.
5
+ * @module @dsh-cc/command-doctor/version
6
+ */
7
+ /** Fallback engines range, matching this package's `package.json`. */
8
+ export declare const FALLBACK_ENGINES = "^22.19 || >=24";
9
+ /**
10
+ * Read this package's manifest version, mirroring `apps/cli`'s self-version
11
+ * read: every harness package shares `0.1.0-rc.x`, so the command package's
12
+ * own manifest carries the harness version.
13
+ * @returns the version string, or `0.0.0` when the manifest is unreadable.
14
+ */
15
+ export declare function readVersion(): string;
16
+ /**
17
+ * Read this package's `engines.node` range (same manifest walk as
18
+ * `readVersion`).
19
+ * @returns the range string, or the known fallback when unreadable.
20
+ */
21
+ export declare function readEngines(): string;
22
+ /**
23
+ * Whether a Node version satisfies this repo's only engines range,
24
+ * `"^22.19 || >=24"`. Coarse by design: `v`-prefixed versions are accepted,
25
+ * `22.x` requires `minor >= 19`, anything at or above 24 passes, and 23 fails.
26
+ * @param version - a Node version string such as `22.19.0` or `v24.1.0`.
27
+ */
28
+ export declare function nodeSatisfiesEngines(version: string): boolean;
29
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,sEAAsE;AACtE,eAAO,MAAM,gBAAgB,mBAAmB,CAAA;AAEhD;;;;;GAKG;AACH,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED;;;;GAIG;AACH,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAqBD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAO7D"}
package/lib/version.js ADDED
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Version and Node engines helpers for `/doctor`. Reads this package's own
3
+ * manifest (mirroring `/version`) and implements the repo's single engines
4
+ * range without a `semver` dependency.
5
+ * @module @dsh-cc/command-doctor/version
6
+ */
7
+ import { readFileSync } from 'node:fs';
8
+ /** Fallback version when the manifest is unreadable. */
9
+ const FALLBACK_VERSION = '0.0.0';
10
+ /** Fallback engines range, matching this package's `package.json`. */
11
+ export const FALLBACK_ENGINES = '^22.19 || >=24';
12
+ /**
13
+ * Read this package's manifest version, mirroring `apps/cli`'s self-version
14
+ * read: every harness package shares `0.1.0-rc.x`, so the command package's
15
+ * own manifest carries the harness version.
16
+ * @returns the version string, or `0.0.0` when the manifest is unreadable.
17
+ */
18
+ export function readVersion() {
19
+ return readManifest().version ?? FALLBACK_VERSION;
20
+ }
21
+ /**
22
+ * Read this package's `engines.node` range (same manifest walk as
23
+ * `readVersion`).
24
+ * @returns the range string, or the known fallback when unreadable.
25
+ */
26
+ export function readEngines() {
27
+ return readManifest().engines ?? FALLBACK_ENGINES;
28
+ }
29
+ /** Read the manifest fields this module cares about. */
30
+ function readManifest() {
31
+ try {
32
+ const manifest = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
33
+ const version = typeof manifest.version === 'string' ? manifest.version : undefined;
34
+ const engines = typeof manifest.engines === 'object' && manifest.engines !== null
35
+ ? manifest.engines
36
+ : undefined;
37
+ return {
38
+ version,
39
+ engines: typeof engines?.node === 'string' ? engines.node : undefined,
40
+ };
41
+ }
42
+ catch {
43
+ return {};
44
+ }
45
+ }
46
+ /**
47
+ * Whether a Node version satisfies this repo's only engines range,
48
+ * `"^22.19 || >=24"`. Coarse by design: `v`-prefixed versions are accepted,
49
+ * `22.x` requires `minor >= 19`, anything at or above 24 passes, and 23 fails.
50
+ * @param version - a Node version string such as `22.19.0` or `v24.1.0`.
51
+ */
52
+ export function nodeSatisfiesEngines(version) {
53
+ const parts = version.replace(/^v/u, '').split('.').map(part => Number(part));
54
+ const major = parts[0] ?? NaN;
55
+ const minor = parts[1] ?? NaN;
56
+ if (!Number.isFinite(major) || !Number.isFinite(minor))
57
+ return false;
58
+ if (major === 22)
59
+ return minor >= 19;
60
+ return major >= 24;
61
+ }
62
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAEtC,wDAAwD;AACxD,MAAM,gBAAgB,GAAG,OAAO,CAAA;AAChC,sEAAsE;AACtE,MAAM,CAAC,MAAM,gBAAgB,GAAG,gBAAgB,CAAA;AAEhD;;;;;GAKG;AACH,MAAM,UAAU,WAAW;IACzB,OAAO,YAAY,EAAE,CAAC,OAAO,IAAI,gBAAgB,CAAA;AACnD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW;IACzB,OAAO,YAAY,EAAE,CAAC,OAAO,IAAI,gBAAgB,CAAA;AACnD,CAAC;AAED,wDAAwD;AACxD,SAAS,YAAY;IACnB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CACzB,YAAY,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CACtB,CAAA;QAC7C,MAAM,OAAO,GAAG,OAAO,QAAQ,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAA;QACnF,MAAM,OAAO,GAAG,OAAO,QAAQ,CAAC,OAAO,KAAK,QAAQ,IAAI,QAAQ,CAAC,OAAO,KAAK,IAAI;YAC/E,CAAC,CAAE,QAAQ,CAAC,OAA8B;YAC1C,CAAC,CAAC,SAAS,CAAA;QACb,OAAO;YACL,OAAO;YACP,OAAO,EAAE,OAAO,OAAO,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;SACtE,CAAA;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAA;IACX,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAe;IAClD,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAA;IAC7E,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,CAAA;IAC7B,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,CAAA;IAC7B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IACpE,IAAI,KAAK,KAAK,EAAE;QAAE,OAAO,KAAK,IAAI,EAAE,CAAA;IACpC,OAAO,KAAK,IAAI,EAAE,CAAA;AACpB,CAAC"}