@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.
- package/LICENSE +201 -0
- package/README.i18n.yaml +6 -0
- package/README.md +47 -0
- package/README.zh.md +47 -0
- package/lib/checks/env.d.ts +12 -0
- package/lib/checks/env.d.ts.map +1 -0
- package/lib/checks/env.js +71 -0
- package/lib/checks/env.js.map +1 -0
- package/lib/checks/git.d.ts +26 -0
- package/lib/checks/git.d.ts.map +1 -0
- package/lib/checks/git.js +94 -0
- package/lib/checks/git.js.map +1 -0
- package/lib/checks/hooks.d.ts +33 -0
- package/lib/checks/hooks.d.ts.map +1 -0
- package/lib/checks/hooks.js +138 -0
- package/lib/checks/hooks.js.map +1 -0
- package/lib/checks/mcp.d.ts +24 -0
- package/lib/checks/mcp.d.ts.map +1 -0
- package/lib/checks/mcp.js +107 -0
- package/lib/checks/mcp.js.map +1 -0
- package/lib/checks/models.d.ts +57 -0
- package/lib/checks/models.d.ts.map +1 -0
- package/lib/checks/models.js +190 -0
- package/lib/checks/models.js.map +1 -0
- package/lib/checks/plugins.d.ts +24 -0
- package/lib/checks/plugins.d.ts.map +1 -0
- package/lib/checks/plugins.js +55 -0
- package/lib/checks/plugins.js.map +1 -0
- package/lib/checks/seams.d.ts +12 -0
- package/lib/checks/seams.d.ts.map +1 -0
- package/lib/checks/seams.js +44 -0
- package/lib/checks/seams.js.map +1 -0
- package/lib/checks/session.d.ts +10 -0
- package/lib/checks/session.d.ts.map +1 -0
- package/lib/checks/session.js +88 -0
- package/lib/checks/session.js.map +1 -0
- package/lib/checks/storage.d.ts +13 -0
- package/lib/checks/storage.d.ts.map +1 -0
- package/lib/checks/storage.js +53 -0
- package/lib/checks/storage.js.map +1 -0
- package/lib/checks/web.d.ts +12 -0
- package/lib/checks/web.d.ts.map +1 -0
- package/lib/checks/web.js +128 -0
- package/lib/checks/web.js.map +1 -0
- package/lib/collect.d.ts +28 -0
- package/lib/collect.d.ts.map +1 -0
- package/lib/collect.js +76 -0
- package/lib/collect.js.map +1 -0
- package/lib/doctor.d.ts +8 -0
- package/lib/doctor.d.ts.map +1 -0
- package/lib/doctor.js +7 -0
- package/lib/doctor.js.map +1 -0
- package/lib/flags.d.ts +23 -0
- package/lib/flags.d.ts.map +1 -0
- package/lib/flags.js +36 -0
- package/lib/flags.js.map +1 -0
- package/lib/index.d.ts +20 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +71 -0
- package/lib/index.js.map +1 -0
- package/lib/invariant.d.ts +16 -0
- package/lib/invariant.d.ts.map +1 -0
- package/lib/invariant.js +23 -0
- package/lib/invariant.js.map +1 -0
- package/lib/json.d.ts +19 -0
- package/lib/json.d.ts.map +1 -0
- package/lib/json.js +27 -0
- package/lib/json.js.map +1 -0
- package/lib/last-model.d.ts +23 -0
- package/lib/last-model.d.ts.map +1 -0
- package/lib/last-model.js +30 -0
- package/lib/last-model.js.map +1 -0
- package/lib/redact.d.ts +14 -0
- package/lib/redact.d.ts.map +1 -0
- package/lib/redact.js +53 -0
- package/lib/redact.js.map +1 -0
- package/lib/render.d.ts +17 -0
- package/lib/render.d.ts.map +1 -0
- package/lib/render.js +60 -0
- package/lib/render.js.map +1 -0
- package/lib/report.d.ts +60 -0
- package/lib/report.d.ts.map +1 -0
- package/lib/report.js +18 -0
- package/lib/report.js.map +1 -0
- package/lib/version.d.ts +29 -0
- package/lib/version.d.ts.map +1 -0
- package/lib/version.js +62 -0
- package/lib/version.js.map +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `seams` compatibility checks for `/doctor`: today's seven seam names,
|
|
3
|
+
* presence-only (absence is expected, so not-mounted is `skip`, not `fail`).
|
|
4
|
+
* @module @dsh-cc/command-doctor/checks/seams
|
|
5
|
+
*/
|
|
6
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
7
|
+
import type { Check } from '../report.ts';
|
|
8
|
+
/** The compatibility seam names kept from the pre-report `/doctor`. */
|
|
9
|
+
export declare const SEAM_NAMES: readonly string[];
|
|
10
|
+
/** Collect the seams group checks. */
|
|
11
|
+
export declare function seamChecks(ctx: Context): Check[];
|
|
12
|
+
//# sourceMappingURL=seams.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seams.d.ts","sourceRoot":"","sources":["../../src/checks/seams.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAA;AAEzC,uEAAuE;AACvE,eAAO,MAAM,UAAU,EAAE,SAAS,MAAM,EAEvC,CAAA;AAED,sCAAsC;AACtC,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,KAAK,EAAE,CAEhD"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `seams` compatibility checks for `/doctor`: today's seven seam names,
|
|
3
|
+
* presence-only (absence is expected, so not-mounted is `skip`, not `fail`).
|
|
4
|
+
* @module @dsh-cc/command-doctor/checks/seams
|
|
5
|
+
*/
|
|
6
|
+
/** The compatibility seam names kept from the pre-report `/doctor`. */
|
|
7
|
+
export const SEAM_NAMES = [
|
|
8
|
+
'shell', 'subprocess', 'fs', 'skills', 'web', 'lsp', 'llm',
|
|
9
|
+
];
|
|
10
|
+
/** Collect the seams group checks. */
|
|
11
|
+
export function seamChecks(ctx) {
|
|
12
|
+
return SEAM_NAMES.map(name => seamCheck(ctx, name));
|
|
13
|
+
}
|
|
14
|
+
/** One seam row; `llm` lists provider ids in detail when enumerable. */
|
|
15
|
+
function seamCheck(ctx, name) {
|
|
16
|
+
const mounted = ctx.get(name) !== undefined;
|
|
17
|
+
if (!mounted) {
|
|
18
|
+
return {
|
|
19
|
+
id: `seams.${name}`,
|
|
20
|
+
group: 'seams',
|
|
21
|
+
status: 'skip',
|
|
22
|
+
summary: `${name} not mounted`,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
if (name === 'llm') {
|
|
26
|
+
const providers = ctx.get('llm')
|
|
27
|
+
?.listProviders?.() ?? [];
|
|
28
|
+
return {
|
|
29
|
+
id: 'seams.llm',
|
|
30
|
+
group: 'seams',
|
|
31
|
+
status: 'ok',
|
|
32
|
+
summary: 'llm mounted',
|
|
33
|
+
detail: providers.length === 0 ? undefined : providers.map(provider => provider.id).join(', '),
|
|
34
|
+
evidence: { providers: providers.length },
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
id: `seams.${name}`,
|
|
39
|
+
group: 'seams',
|
|
40
|
+
status: 'ok',
|
|
41
|
+
summary: `${name} mounted`,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=seams.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seams.js","sourceRoot":"","sources":["../../src/checks/seams.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,uEAAuE;AACvE,MAAM,CAAC,MAAM,UAAU,GAAsB;IAC3C,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK;CAC3D,CAAA;AAED,sCAAsC;AACtC,MAAM,UAAU,UAAU,CAAC,GAAY;IACrC,OAAO,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAA;AACrD,CAAC;AAED,wEAAwE;AACxE,SAAS,SAAS,CAAC,GAAY,EAAE,IAAY;IAC3C,MAAM,OAAO,GAAG,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,SAAS,CAAA;IAC3C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO;YACL,EAAE,EAAE,SAAS,IAAI,EAAE;YACnB,KAAK,EAAE,OAAO;YACd,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,GAAG,IAAI,cAAc;SAC/B,CAAA;IACH,CAAC;IACD,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QACnB,MAAM,SAAS,GAAI,GAAG,CAAC,GAAG,CAAC,KAAK,CAAwD;YACtF,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,CAAA;QAC3B,OAAO;YACL,EAAE,EAAE,WAAW;YACf,KAAK,EAAE,OAAO;YACd,MAAM,EAAE,IAAI;YACZ,OAAO,EAAE,aAAa;YACtB,MAAM,EAAE,SAAS,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;YAC9F,QAAQ,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,MAAM,EAAE;SAC1C,CAAA;IACH,CAAC;IACD,OAAO;QACL,EAAE,EAAE,SAAS,IAAI,EAAE;QACnB,KAAK,EAAE,OAAO;QACd,MAAM,EAAE,IAAI;QACZ,OAAO,EAAE,GAAG,IAAI,UAAU;KAC3B,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `session` checks for `/doctor`: identity, cwd, presets, and the dsh profile.
|
|
3
|
+
* @module @dsh-cc/command-doctor/checks/session
|
|
4
|
+
*/
|
|
5
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
6
|
+
import type { CommandInvocation } from '@deepseek-ai/dsh-commands';
|
|
7
|
+
import type { Check } from '../report.ts';
|
|
8
|
+
/** Collect the session group checks. */
|
|
9
|
+
export declare function sessionChecks(ctx: Context, invocation: CommandInvocation): Check[];
|
|
10
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/checks/session.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAClE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAA;AAEzC,wCAAwC;AACxC,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,iBAAiB,GAAG,KAAK,EAAE,CAsBlF"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `session` checks for `/doctor`: identity, cwd, presets, and the dsh profile.
|
|
3
|
+
* @module @dsh-cc/command-doctor/checks/session
|
|
4
|
+
*/
|
|
5
|
+
/** Collect the session group checks. */
|
|
6
|
+
export function sessionChecks(ctx, invocation) {
|
|
7
|
+
const checks = [];
|
|
8
|
+
const session = invocation.agent.session;
|
|
9
|
+
checks.push({
|
|
10
|
+
id: 'session.id',
|
|
11
|
+
group: 'session',
|
|
12
|
+
status: 'ok',
|
|
13
|
+
summary: session.id,
|
|
14
|
+
evidence: { sessionId: session.id },
|
|
15
|
+
});
|
|
16
|
+
const cwd = session.header.cwd ?? process.cwd();
|
|
17
|
+
checks.push({
|
|
18
|
+
id: 'session.cwd',
|
|
19
|
+
group: 'session',
|
|
20
|
+
status: 'ok',
|
|
21
|
+
summary: cwd,
|
|
22
|
+
evidence: { cwd },
|
|
23
|
+
});
|
|
24
|
+
checks.push(permissionPresetCheck(ctx, session.events));
|
|
25
|
+
checks.push(agentPresetCheck(ctx));
|
|
26
|
+
checks.push(dshProfileCheck(ctx));
|
|
27
|
+
return checks;
|
|
28
|
+
}
|
|
29
|
+
/** Fold the effective permission preset; throw or missing → skip. */
|
|
30
|
+
function permissionPresetCheck(ctx, events) {
|
|
31
|
+
const presets = ctx.get('permissionPresets');
|
|
32
|
+
if (presets === undefined) {
|
|
33
|
+
return { id: 'session.permission-preset', group: 'session', status: 'skip', summary: 'permissionPresets seam not mounted' };
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
const preset = presets.current(events);
|
|
37
|
+
return {
|
|
38
|
+
id: 'session.permission-preset',
|
|
39
|
+
group: 'session',
|
|
40
|
+
status: 'ok',
|
|
41
|
+
summary: preset,
|
|
42
|
+
evidence: { preset },
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
return {
|
|
47
|
+
id: 'session.permission-preset',
|
|
48
|
+
group: 'session',
|
|
49
|
+
status: 'skip',
|
|
50
|
+
summary: `preset unavailable: ${String(error)}`,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/** Fold the default agent preset id; missing → skip. */
|
|
55
|
+
function agentPresetCheck(ctx) {
|
|
56
|
+
const presets = ctx.get('agentPresets');
|
|
57
|
+
const defaultId = typeof presets?.defaultId === 'string' ? presets.defaultId : undefined;
|
|
58
|
+
if (defaultId === undefined) {
|
|
59
|
+
return { id: 'session.agent-preset', group: 'session', status: 'skip', summary: 'agentPresets seam not mounted' };
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
id: 'session.agent-preset',
|
|
63
|
+
group: 'session',
|
|
64
|
+
status: 'ok',
|
|
65
|
+
summary: defaultId,
|
|
66
|
+
evidence: { defaultId },
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/** Fold the dsh profile (`'tui'`); missing → skip. */
|
|
70
|
+
function dshProfileCheck(ctx) {
|
|
71
|
+
const profile = ctx.get('dshProfile');
|
|
72
|
+
if (typeof profile !== 'string' || profile.length === 0) {
|
|
73
|
+
return {
|
|
74
|
+
id: 'session.dsh-profile',
|
|
75
|
+
group: 'session',
|
|
76
|
+
status: 'skip',
|
|
77
|
+
summary: 'dshProfile seam not mounted',
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
id: 'session.dsh-profile',
|
|
82
|
+
group: 'session',
|
|
83
|
+
status: 'ok',
|
|
84
|
+
summary: profile,
|
|
85
|
+
evidence: { profile },
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/checks/session.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `storage` checks for `/doctor`: a verbose-only write probe against the
|
|
3
|
+
* session persistence store.
|
|
4
|
+
* @module @dsh-cc/command-doctor/checks/storage
|
|
5
|
+
*/
|
|
6
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
7
|
+
import type { CommandInvocation } from '@deepseek-ai/dsh-commands';
|
|
8
|
+
import type { Check } from '../report.ts';
|
|
9
|
+
/** Collect the storage group checks. */
|
|
10
|
+
export declare function storageChecks(ctx: Context, invocation: CommandInvocation, options: {
|
|
11
|
+
verbose: boolean;
|
|
12
|
+
}): Promise<Check[]>;
|
|
13
|
+
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/checks/storage.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAClE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAA;AAEzC,wCAAwC;AACxC,wBAAsB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,OAAO,EAAE;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,CA4ChI"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `storage` checks for `/doctor`: a verbose-only write probe against the
|
|
3
|
+
* session persistence store.
|
|
4
|
+
* @module @dsh-cc/command-doctor/checks/storage
|
|
5
|
+
*/
|
|
6
|
+
import { unlink, writeFile } from 'node:fs/promises';
|
|
7
|
+
/** Collect the storage group checks. */
|
|
8
|
+
export async function storageChecks(ctx, invocation, options) {
|
|
9
|
+
if (!options.verbose) {
|
|
10
|
+
return [{
|
|
11
|
+
id: 'storage.session',
|
|
12
|
+
group: 'storage',
|
|
13
|
+
status: 'skip',
|
|
14
|
+
summary: 'not probed (use --verbose)',
|
|
15
|
+
}];
|
|
16
|
+
}
|
|
17
|
+
const persistence = ctx.get('sessionPersistence');
|
|
18
|
+
const located = persistence?.locate?.(invocation.agent.session.header);
|
|
19
|
+
const path = located?.path;
|
|
20
|
+
if (path === undefined) {
|
|
21
|
+
return [{
|
|
22
|
+
id: 'storage.session',
|
|
23
|
+
group: 'storage',
|
|
24
|
+
status: 'skip',
|
|
25
|
+
summary: 'session store path unavailable',
|
|
26
|
+
}];
|
|
27
|
+
}
|
|
28
|
+
const probe = `${path}.${process.pid}.doctor-tmp`;
|
|
29
|
+
try {
|
|
30
|
+
await writeFile(probe, 'dsh-cc doctor write probe\n', 'utf8');
|
|
31
|
+
return [{
|
|
32
|
+
id: 'storage.session',
|
|
33
|
+
group: 'storage',
|
|
34
|
+
status: 'ok',
|
|
35
|
+
summary: `store directory writable: ${path}`,
|
|
36
|
+
evidence: { path },
|
|
37
|
+
}];
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
return [{
|
|
41
|
+
id: 'storage.session',
|
|
42
|
+
group: 'storage',
|
|
43
|
+
status: 'fail',
|
|
44
|
+
summary: `store directory not writable: ${String(error)}`,
|
|
45
|
+
fix: 'check filesystem permissions for the session store directory',
|
|
46
|
+
evidence: { path },
|
|
47
|
+
}];
|
|
48
|
+
}
|
|
49
|
+
finally {
|
|
50
|
+
await unlink(probe).catch(() => undefined);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/checks/storage.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAKpD,wCAAwC;AACxC,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAY,EAAE,UAA6B,EAAE,OAA6B;IAC5G,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QACrB,OAAO,CAAC;gBACN,EAAE,EAAE,iBAAiB;gBACrB,KAAK,EAAE,SAAS;gBAChB,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,4BAA4B;aACtC,CAAC,CAAA;IACJ,CAAC;IACD,MAAM,WAAW,GAAG,GAAG,CAAC,GAAG,CAAC,oBAAoB,CAEnC,CAAA;IACb,MAAM,OAAO,GAAG,WAAW,EAAE,MAAM,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;IACtE,MAAM,IAAI,GAAG,OAAO,EAAE,IAAI,CAAA;IAC1B,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,OAAO,CAAC;gBACN,EAAE,EAAE,iBAAiB;gBACrB,KAAK,EAAE,SAAS;gBAChB,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,gCAAgC;aAC1C,CAAC,CAAA;IACJ,CAAC;IACD,MAAM,KAAK,GAAG,GAAG,IAAI,IAAI,OAAO,CAAC,GAAG,aAAa,CAAA;IACjD,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,KAAK,EAAE,6BAA6B,EAAE,MAAM,CAAC,CAAA;QAC7D,OAAO,CAAC;gBACN,EAAE,EAAE,iBAAiB;gBACrB,KAAK,EAAE,SAAS;gBAChB,MAAM,EAAE,IAAI;gBACZ,OAAO,EAAE,6BAA6B,IAAI,EAAE;gBAC5C,QAAQ,EAAE,EAAE,IAAI,EAAE;aACnB,CAAC,CAAA;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC;gBACN,EAAE,EAAE,iBAAiB;gBACrB,KAAK,EAAE,SAAS;gBAChB,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,iCAAiC,MAAM,CAAC,KAAK,CAAC,EAAE;gBACzD,GAAG,EAAE,8DAA8D;gBACnE,QAAQ,EAAE,EAAE,IAAI,EAAE;aACnB,CAAC,CAAA;IACJ,CAAC;YAAS,CAAC;QACT,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAA;IAC5C,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `web` checks for `/doctor`: seam presence, an execution probe for the fetch
|
|
3
|
+
* provider (a mounted provider resolves URLs, so `WEB_PROVIDER_UNAVAILABLE`
|
|
4
|
+
* from the harness runtime means missing), the literal SSRF gate, and the
|
|
5
|
+
* haiku summarizer lane.
|
|
6
|
+
* @module @dsh-cc/command-doctor/checks/web
|
|
7
|
+
*/
|
|
8
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
9
|
+
import type { Check } from '../report.ts';
|
|
10
|
+
/** Collect the web group checks. */
|
|
11
|
+
export declare function webChecks(ctx: Context): Promise<Check[]>;
|
|
12
|
+
//# sourceMappingURL=web.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../../src/checks/web.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAElD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAA;AAuBzC,oCAAoC;AACpC,wBAAsB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,CA4C9D"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `web` checks for `/doctor`: seam presence, an execution probe for the fetch
|
|
3
|
+
* provider (a mounted provider resolves URLs, so `WEB_PROVIDER_UNAVAILABLE`
|
|
4
|
+
* from the harness runtime means missing), the literal SSRF gate, and the
|
|
5
|
+
* haiku summarizer lane.
|
|
6
|
+
* @module @dsh-cc/command-doctor/checks/web
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Execute the seam with an invalid URL and no network: a missing provider is
|
|
10
|
+
* `WEB_PROVIDER_UNAVAILABLE` (resolved before the URL is seen); a present
|
|
11
|
+
* provider yields `WEB_INVALID_URL` / `WEB_BLOCKED_URL` / `WEB_ABORTED`.
|
|
12
|
+
*/
|
|
13
|
+
async function probeFetch(web) {
|
|
14
|
+
try {
|
|
15
|
+
await web.fetch({ url: 'not-a-url' }, AbortSignal.abort());
|
|
16
|
+
return 'present'; // unexpected success
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
const code = error.code;
|
|
20
|
+
if (code === 'WEB_PROVIDER_UNAVAILABLE')
|
|
21
|
+
return 'missing';
|
|
22
|
+
return 'present';
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/** Collect the web group checks. */
|
|
26
|
+
export async function webChecks(ctx) {
|
|
27
|
+
const checks = [];
|
|
28
|
+
const web = ctx.get('web');
|
|
29
|
+
if (web === undefined) {
|
|
30
|
+
checks.push({
|
|
31
|
+
id: 'web.seam',
|
|
32
|
+
group: 'web',
|
|
33
|
+
status: 'skip',
|
|
34
|
+
summary: 'web seam not mounted',
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
checks.push({
|
|
39
|
+
id: 'web.seam',
|
|
40
|
+
group: 'web',
|
|
41
|
+
status: 'ok',
|
|
42
|
+
summary: 'web seam mounted',
|
|
43
|
+
});
|
|
44
|
+
if (typeof web.fetch !== 'function') {
|
|
45
|
+
checks.push({
|
|
46
|
+
id: 'web.fetch-provider',
|
|
47
|
+
group: 'web',
|
|
48
|
+
status: 'warn',
|
|
49
|
+
summary: 'fetch method missing on the web seam',
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
const probe = await probeFetch(web);
|
|
54
|
+
checks.push(probe === 'missing'
|
|
55
|
+
? {
|
|
56
|
+
id: 'web.fetch-provider',
|
|
57
|
+
group: 'web',
|
|
58
|
+
status: 'warn',
|
|
59
|
+
summary: 'fetch provider not mounted (WEB_PROVIDER_UNAVAILABLE at execute)',
|
|
60
|
+
}
|
|
61
|
+
: {
|
|
62
|
+
id: 'web.fetch-provider',
|
|
63
|
+
group: 'web',
|
|
64
|
+
status: 'ok',
|
|
65
|
+
summary: 'fetch provider mounted',
|
|
66
|
+
});
|
|
67
|
+
checks.push(await ssrfGateCheck(web, probe));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
checks.push(haikuSummarizerCheck(ctx));
|
|
71
|
+
return checks;
|
|
72
|
+
}
|
|
73
|
+
/** Probe the loopback literal with a short abort so `/doctor` cannot hang. */
|
|
74
|
+
async function ssrfGateCheck(web, probe) {
|
|
75
|
+
if (probe === 'missing') {
|
|
76
|
+
return { id: 'web.ssrf-gate', group: 'web', status: 'skip', summary: 'fetch provider not mounted' };
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
await web.fetch({ url: 'http://127.0.0.1/' }, AbortSignal.timeout(200));
|
|
80
|
+
return {
|
|
81
|
+
id: 'web.ssrf-gate',
|
|
82
|
+
group: 'web',
|
|
83
|
+
status: 'warn',
|
|
84
|
+
summary: 'SSRF gate off or bypassed: loopback fetch was not blocked',
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
if (error.code === 'WEB_BLOCKED_URL') {
|
|
89
|
+
return { id: 'web.ssrf-gate', group: 'web', status: 'ok', summary: 'loopback literal blocked before connect' };
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
id: 'web.ssrf-gate',
|
|
93
|
+
group: 'web',
|
|
94
|
+
status: 'warn',
|
|
95
|
+
summary: 'SSRF gate off or bypassed',
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/** The haiku cheap lane: a full route is ok, inherit is info. */
|
|
100
|
+
function haikuSummarizerCheck(ctx) {
|
|
101
|
+
const routes = ctx.get('ccModelRoutes');
|
|
102
|
+
if (routes?.inspect === undefined) {
|
|
103
|
+
return {
|
|
104
|
+
id: 'web.haiku-summarizer',
|
|
105
|
+
group: 'web',
|
|
106
|
+
status: 'skip',
|
|
107
|
+
summary: 'ccModelRoutes not mounted',
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
const inspection = routes.inspect('haiku');
|
|
111
|
+
const route = inspection.route;
|
|
112
|
+
if (inspection.kind !== 'inherit' && route?.provider !== undefined && route.model !== undefined) {
|
|
113
|
+
return {
|
|
114
|
+
id: 'web.haiku-summarizer',
|
|
115
|
+
group: 'web',
|
|
116
|
+
status: 'ok',
|
|
117
|
+
summary: `haiku summarizer: ${route.provider}/${route.model}`,
|
|
118
|
+
evidence: { provider: route.provider, model: route.model },
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
id: 'web.haiku-summarizer',
|
|
123
|
+
group: 'web',
|
|
124
|
+
status: 'info',
|
|
125
|
+
summary: 'raw WebFetch OK; prompt summarization unavailable',
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=web.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/checks/web.ts"],"names":[],"mappings":"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"}
|
package/lib/collect.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `/doctor` collection orchestration: runs every check group in stable order,
|
|
3
|
+
* converting a thrown check into a `fail` row so the command always succeeds.
|
|
4
|
+
* @module @dsh-cc/command-doctor/collect
|
|
5
|
+
*/
|
|
6
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
7
|
+
import type { CommandInvocation } from '@deepseek-ai/dsh-commands';
|
|
8
|
+
import { type DoctorReport } from './report.ts';
|
|
9
|
+
/** Injected clock so reports are deterministic under test. */
|
|
10
|
+
export interface CollectClock {
|
|
11
|
+
/** The report generation timestamp. */
|
|
12
|
+
now(): Date;
|
|
13
|
+
/** A monotonic millisecond measure for `durationMs`. */
|
|
14
|
+
ms(): number;
|
|
15
|
+
}
|
|
16
|
+
/** Collection options: mode plus the injected clock. */
|
|
17
|
+
export interface CollectOptions extends CollectClock {
|
|
18
|
+
/** Verbose mode adds slow probes and evidence. */
|
|
19
|
+
verbose: boolean;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Collect the full report for the live session.
|
|
23
|
+
* @param ctx - the composed context (optional seams are duck-typed via get).
|
|
24
|
+
* @param invocation - the `/doctor` invocation (its agent session).
|
|
25
|
+
* @param options - mode flags plus the injected clock.
|
|
26
|
+
*/
|
|
27
|
+
export declare function collect(ctx: Context, invocation: CommandInvocation, options: CollectOptions): Promise<DoctorReport>;
|
|
28
|
+
//# sourceMappingURL=collect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collect.d.ts","sourceRoot":"","sources":["../src/collect.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAWlE,OAAO,EAA6C,KAAK,YAAY,EAAE,MAAM,aAAa,CAAA;AAG1F,8DAA8D;AAC9D,MAAM,WAAW,YAAY;IAC3B,uCAAuC;IACvC,GAAG,IAAI,IAAI,CAAA;IACX,wDAAwD;IACxD,EAAE,IAAI,MAAM,CAAA;CACb;AAED,wDAAwD;AACxD,MAAM,WAAW,cAAe,SAAQ,YAAY;IAClD,kDAAkD;IAClD,OAAO,EAAE,OAAO,CAAA;CACjB;AAmBD;;;;;GAKG;AACH,wBAAsB,OAAO,CAC3B,GAAG,EAAE,OAAO,EACZ,UAAU,EAAE,iBAAiB,EAC7B,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,YAAY,CAAC,CAqCvB"}
|
package/lib/collect.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `/doctor` collection orchestration: runs every check group in stable order,
|
|
3
|
+
* converting a thrown check into a `fail` row so the command always succeeds.
|
|
4
|
+
* @module @dsh-cc/command-doctor/collect
|
|
5
|
+
*/
|
|
6
|
+
import { envChecks } from "./checks/env.js";
|
|
7
|
+
import { gitChecks, gitInfo } from "./checks/git.js";
|
|
8
|
+
import { hookChecks } from "./checks/hooks.js";
|
|
9
|
+
import { mcpChecks } from "./checks/mcp.js";
|
|
10
|
+
import { modelChecks } from "./checks/models.js";
|
|
11
|
+
import { pluginChecks } from "./checks/plugins.js";
|
|
12
|
+
import { seamChecks } from "./checks/seams.js";
|
|
13
|
+
import { sessionChecks } from "./checks/session.js";
|
|
14
|
+
import { storageChecks } from "./checks/storage.js";
|
|
15
|
+
import { webChecks } from "./checks/web.js";
|
|
16
|
+
import { countSummary } from "./report.js";
|
|
17
|
+
import { readVersion } from "./version.js";
|
|
18
|
+
/** Run one group's check function, converting a throw into a fail row. */
|
|
19
|
+
async function runGroup(group, fn) {
|
|
20
|
+
try {
|
|
21
|
+
return await fn();
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
return [{
|
|
25
|
+
id: `${group}.probe`,
|
|
26
|
+
group,
|
|
27
|
+
status: 'fail',
|
|
28
|
+
summary: String(error),
|
|
29
|
+
}];
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Collect the full report for the live session.
|
|
34
|
+
* @param ctx - the composed context (optional seams are duck-typed via get).
|
|
35
|
+
* @param invocation - the `/doctor` invocation (its agent session).
|
|
36
|
+
* @param options - mode flags plus the injected clock.
|
|
37
|
+
*/
|
|
38
|
+
export async function collect(ctx, invocation, options) {
|
|
39
|
+
const started = options.ms();
|
|
40
|
+
const cwd = invocation.agent.session.header.cwd ?? process.cwd();
|
|
41
|
+
let git;
|
|
42
|
+
if (options.verbose)
|
|
43
|
+
git = gitInfo(cwd);
|
|
44
|
+
const checks = [
|
|
45
|
+
...await runGroup('env', () => envChecks(ctx)),
|
|
46
|
+
...await runGroup('session', () => sessionChecks(ctx, invocation)),
|
|
47
|
+
...await runGroup('models', () => modelChecks(ctx, invocation, options)),
|
|
48
|
+
...await runGroup('mcp', () => mcpChecks(ctx, { ...(git === undefined ? {} : { git }), verbose: options.verbose })),
|
|
49
|
+
...await runGroup('hooks', () => hookChecks(ctx, options)),
|
|
50
|
+
...await runGroup('web', () => webChecks(ctx)),
|
|
51
|
+
...await runGroup('storage', () => storageChecks(ctx, invocation, options)),
|
|
52
|
+
...await runGroup('git', () => gitChecks(ctx, { verbose: options.verbose, cwd })),
|
|
53
|
+
...await runGroup('plugins', () => pluginChecks(ctx)),
|
|
54
|
+
...await runGroup('seams', () => seamChecks(ctx)),
|
|
55
|
+
];
|
|
56
|
+
const harness = ctx.get('harnessVersion');
|
|
57
|
+
const harnessVersion = typeof harness === 'string'
|
|
58
|
+
? harness
|
|
59
|
+
: typeof harness?.version === 'string' ? harness.version : undefined;
|
|
60
|
+
return {
|
|
61
|
+
schemaVersion: 1,
|
|
62
|
+
generatedAt: options.now().toISOString(),
|
|
63
|
+
durationMs: options.ms() - started,
|
|
64
|
+
env: {
|
|
65
|
+
dshCc: readVersion(),
|
|
66
|
+
...(harnessVersion === undefined ? {} : { harness: harnessVersion }),
|
|
67
|
+
node: process.version,
|
|
68
|
+
os: process.platform,
|
|
69
|
+
arch: process.arch,
|
|
70
|
+
cwd,
|
|
71
|
+
},
|
|
72
|
+
checks,
|
|
73
|
+
summary: countSummary(checks),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=collect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collect.js","sourceRoot":"","sources":["../src/collect.ts"],"names":[],"mappings":"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"}
|
package/lib/doctor.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public `/doctor` report surface: the structured types and the text
|
|
3
|
+
* formatter, so `@dsh-cc/command-doctor/doctor` keeps resolving.
|
|
4
|
+
* @module @dsh-cc/command-doctor/doctor
|
|
5
|
+
*/
|
|
6
|
+
export { formatDoctorReport, type RenderOptions } from './render.ts';
|
|
7
|
+
export type { Check, CheckGroup, CheckStatus, DoctorReport, } from './report.ts';
|
|
8
|
+
//# sourceMappingURL=doctor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,kBAAkB,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAA;AACpE,YAAY,EACV,KAAK,EACL,UAAU,EACV,WAAW,EACX,YAAY,GACb,MAAM,aAAa,CAAA"}
|
package/lib/doctor.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public `/doctor` report surface: the structured types and the text
|
|
3
|
+
* formatter, so `@dsh-cc/command-doctor/doctor` keeps resolving.
|
|
4
|
+
* @module @dsh-cc/command-doctor/doctor
|
|
5
|
+
*/
|
|
6
|
+
export { formatDoctorReport } from "./render.js";
|
|
7
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,kBAAkB,EAAsB,MAAM,aAAa,CAAA"}
|
package/lib/flags.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `/doctor` flag parsing and usage text. Pure and cordis-free.
|
|
3
|
+
* @module @dsh-cc/command-doctor/flags
|
|
4
|
+
*/
|
|
5
|
+
export type DoctorFlags = {
|
|
6
|
+
kind: 'run';
|
|
7
|
+
verbose: boolean;
|
|
8
|
+
json: boolean;
|
|
9
|
+
} | {
|
|
10
|
+
kind: 'usage';
|
|
11
|
+
};
|
|
12
|
+
/** The usage text shown for unknown flags (never an error result). */
|
|
13
|
+
export declare const DOCTOR_USAGE: string;
|
|
14
|
+
/** The usage formatter used by the handler for unknown tokens. */
|
|
15
|
+
export declare function formatUsage(): string;
|
|
16
|
+
/**
|
|
17
|
+
* Parse the tokens after `/doctor`. `--verbose` and `--json` are
|
|
18
|
+
* order-independent; any other token yields usage. Both flags collect
|
|
19
|
+
* verbose and emit JSON.
|
|
20
|
+
* @param rawInput - `invocation.rawInput`, the text after the command name.
|
|
21
|
+
*/
|
|
22
|
+
export declare function parseDoctorFlags(rawInput: string): DoctorFlags;
|
|
23
|
+
//# sourceMappingURL=flags.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flags.d.ts","sourceRoot":"","sources":["../src/flags.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAA;AAErB,sEAAsE;AACtE,eAAO,MAAM,YAAY,QAKb,CAAA;AAEZ,kEAAkE;AAClE,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,CAU9D"}
|
package/lib/flags.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `/doctor` flag parsing and usage text. Pure and cordis-free.
|
|
3
|
+
* @module @dsh-cc/command-doctor/flags
|
|
4
|
+
*/
|
|
5
|
+
/** The usage text shown for unknown flags (never an error result). */
|
|
6
|
+
export const DOCTOR_USAGE = [
|
|
7
|
+
'Usage:',
|
|
8
|
+
' /doctor session health report',
|
|
9
|
+
' /doctor --verbose include slow probes and evidence',
|
|
10
|
+
' /doctor --json write $DSH_HOME/tui/doctor-report.json (overwrites)',
|
|
11
|
+
].join('\n');
|
|
12
|
+
/** The usage formatter used by the handler for unknown tokens. */
|
|
13
|
+
export function formatUsage() {
|
|
14
|
+
return DOCTOR_USAGE;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Parse the tokens after `/doctor`. `--verbose` and `--json` are
|
|
18
|
+
* order-independent; any other token yields usage. Both flags collect
|
|
19
|
+
* verbose and emit JSON.
|
|
20
|
+
* @param rawInput - `invocation.rawInput`, the text after the command name.
|
|
21
|
+
*/
|
|
22
|
+
export function parseDoctorFlags(rawInput) {
|
|
23
|
+
const tokens = rawInput.trim().split(/\s+/u).filter(token => token.length > 0);
|
|
24
|
+
let verbose = false;
|
|
25
|
+
let json = false;
|
|
26
|
+
for (const token of tokens) {
|
|
27
|
+
if (token === '--verbose')
|
|
28
|
+
verbose = true;
|
|
29
|
+
else if (token === '--json')
|
|
30
|
+
json = true;
|
|
31
|
+
else
|
|
32
|
+
return { kind: 'usage' };
|
|
33
|
+
}
|
|
34
|
+
return { kind: 'run', verbose, json };
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=flags.js.map
|
package/lib/flags.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flags.js","sourceRoot":"","sources":["../src/flags.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,sEAAsE;AACtE,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,QAAQ;IACR,8CAA8C;IAC9C,yDAAyD;IACzD,4EAA4E;CAC7E,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAEZ,kEAAkE;AAClE,MAAM,UAAU,WAAW;IACzB,OAAO,YAAY,CAAA;AACrB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IAC9E,IAAI,OAAO,GAAG,KAAK,CAAA;IACnB,IAAI,IAAI,GAAG,KAAK,CAAA;IAChB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,KAAK,KAAK,WAAW;YAAE,OAAO,GAAG,IAAI,CAAA;aACpC,IAAI,KAAK,KAAK,QAAQ;YAAE,IAAI,GAAG,IAAI,CAAA;;YACnC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAA;IAC/B,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;AACvC,CAAC"}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
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 { Context } from '@deepseek-ai/cordis';
|
|
8
|
+
export { readVersion } from './version.ts';
|
|
9
|
+
export { DOCTOR_USAGE, parseDoctorFlags } from './flags.ts';
|
|
10
|
+
export { redactReport } from './redact.ts';
|
|
11
|
+
export { collect } from './collect.ts';
|
|
12
|
+
export type { Check, CheckGroup, CheckStatus, DoctorReport } from './report.ts';
|
|
13
|
+
export declare const name = "command-doctor";
|
|
14
|
+
export declare const inject: string[];
|
|
15
|
+
/**
|
|
16
|
+
* Register the `/doctor` command for every composed command adapter.
|
|
17
|
+
* @param ctx - context carrying the command registry.
|
|
18
|
+
*/
|
|
19
|
+
export declare function apply(ctx: Context): void;
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAQ7C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,YAAY,EAAE,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE/E,eAAO,MAAM,IAAI,mBAAmB,CAAA;AACpC,eAAO,MAAM,MAAM,UAAe,CAAA;AA4ClC;;;GAGG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAOxC"}
|