dsh-agy-cli 0.0.0-stage → 0.12.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 +30 -0
- package/README.en.md +27 -0
- package/README.md +94 -2
- package/agents/dsh-agy-image-view.md +17 -0
- package/agents/dsh-agy-mcp-executor.md +32 -0
- package/agents/dsh-agy-read-only.md +20 -0
- package/agents/dsh-agy-tool-free.md +16 -0
- package/agents/dsh-agy-workspace-write.md +23 -0
- package/bin/dsh-agy-cli.js +9 -0
- package/bin/win32-x64/agy-launcher.exe +0 -0
- package/cordis.patch.yml +16 -0
- package/dist/client.js +4259 -0
- package/lib/agent-installer.d.ts +66 -0
- package/lib/agent-installer.js +147 -0
- package/lib/agent-presets.d.ts +42 -0
- package/lib/agent-presets.js +130 -0
- package/lib/agents-cli.d.ts +3 -0
- package/lib/agents-cli.js +110 -0
- package/lib/agy/diagnostics.d.ts +29 -0
- package/lib/agy/diagnostics.js +109 -0
- package/lib/agy/errors.d.ts +20 -0
- package/lib/agy/errors.js +77 -0
- package/lib/agy/experimental-transport.d.ts +79 -0
- package/lib/agy/experimental-transport.js +612 -0
- package/lib/agy/keepalive.d.ts +140 -0
- package/lib/agy/keepalive.js +424 -0
- package/lib/agy/limiter.d.ts +32 -0
- package/lib/agy/limiter.js +111 -0
- package/lib/agy/log.d.ts +214 -0
- package/lib/agy/log.js +503 -0
- package/lib/agy/models.d.ts +49 -0
- package/lib/agy/models.js +203 -0
- package/lib/agy/overrides.d.ts +17 -0
- package/lib/agy/overrides.js +73 -0
- package/lib/agy/parser.d.ts +102 -0
- package/lib/agy/parser.js +492 -0
- package/lib/agy/persistent-transport.d.ts +101 -0
- package/lib/agy/persistent-transport.js +753 -0
- package/lib/agy/process.d.ts +144 -0
- package/lib/agy/process.js +452 -0
- package/lib/agy/redact.d.ts +3 -0
- package/lib/agy/redact.js +24 -0
- package/lib/agy/stream-protocol.d.ts +50 -0
- package/lib/agy/stream-protocol.js +156 -0
- package/lib/agy/windows-launcher.d.ts +21 -0
- package/lib/agy/windows-launcher.js +76 -0
- package/lib/diagnostics.d.ts +78 -0
- package/lib/diagnostics.js +162 -0
- package/lib/doctor.d.ts +138 -0
- package/lib/doctor.js +923 -0
- package/lib/dsh/context.d.ts +133 -0
- package/lib/dsh/context.js +352 -0
- package/lib/dsh-home.d.ts +6 -0
- package/lib/dsh-home.js +11 -0
- package/lib/index.d.ts +43 -0
- package/lib/index.js +256 -0
- package/lib/mcp/agy-registration.d.ts +70 -0
- package/lib/mcp/agy-registration.js +245 -0
- package/lib/mcp/bridge.d.ts +73 -0
- package/lib/mcp/bridge.js +295 -0
- package/lib/mcp/endpoint.d.ts +41 -0
- package/lib/mcp/endpoint.js +142 -0
- package/lib/mcp/protocol.d.ts +107 -0
- package/lib/mcp/protocol.js +197 -0
- package/lib/mcp/tool-projection.d.ts +64 -0
- package/lib/mcp/tool-projection.js +168 -0
- package/lib/provider/agy.d.ts +153 -0
- package/lib/provider/agy.js +2159 -0
- package/lib/provider/config.d.ts +226 -0
- package/lib/provider/config.js +294 -0
- package/lib/provider/error-codes.d.ts +22 -0
- package/lib/provider/error-codes.js +29 -0
- package/lib/provider/image-bridge.d.ts +60 -0
- package/lib/provider/image-bridge.js +290 -0
- package/lib/provider/mock.d.ts +15 -0
- package/lib/provider/mock.js +78 -0
- package/lib/provider/prompt-budget.d.ts +45 -0
- package/lib/provider/prompt-budget.js +596 -0
- package/lib/provider/serialize.d.ts +15 -0
- package/lib/provider/serialize.js +82 -0
- package/lib/provider/tool-protocol.d.ts +80 -0
- package/lib/provider/tool-protocol.js +848 -0
- package/lib/provider/tool-schema-file.d.ts +11 -0
- package/lib/provider/tool-schema-file.js +27 -0
- package/lib/session/file-store.d.ts +56 -0
- package/lib/session/file-store.js +186 -0
- package/lib/session/store.d.ts +49 -0
- package/lib/session/store.js +62 -0
- package/lib/web/router.d.ts +19 -0
- package/lib/web/router.js +906 -0
- package/package.json +112 -4
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { DSH_APPROVAL_UNAVAILABLE_CODE, DSH_CONTEXT_UNAVAILABLE_CODE, DSH_PERMISSION_UNAVAILABLE_CODE, DSH_SANDBOX_UNAVAILABLE_CODE, DSH_SESSION_INVALID_CODE, DSH_SESSION_REQUIRED_CODE, DSH_SESSION_UNAVAILABLE_CODE, DSH_SESSION_UNKNOWN_CODE, DSH_WORKSPACE_MISMATCH_CODE, DSH_WORKSPACE_UNAVAILABLE_CODE } from '../provider/error-codes.js';
|
|
2
|
+
/** Minimal Cordis reflection seam; no DSH runtime package is required at compile time. */
|
|
3
|
+
export interface DshContextLookup {
|
|
4
|
+
get(name: string): unknown;
|
|
5
|
+
}
|
|
6
|
+
/** Read-only shape of the DSH Session surface used by the Provider boundary. */
|
|
7
|
+
export interface DshSessionLike {
|
|
8
|
+
readonly id?: string;
|
|
9
|
+
readonly header?: {
|
|
10
|
+
readonly id?: string;
|
|
11
|
+
readonly cwd?: string;
|
|
12
|
+
};
|
|
13
|
+
readonly events?: readonly unknown[];
|
|
14
|
+
}
|
|
15
|
+
export interface DshSessionStoreLike {
|
|
16
|
+
get(id: string): DshSessionLike | undefined;
|
|
17
|
+
}
|
|
18
|
+
export interface DshWorkspaceLike {
|
|
19
|
+
readonly path?: string;
|
|
20
|
+
readonly sessionIds?: readonly string[];
|
|
21
|
+
status?(): Promise<'ok' | 'missing-dir' | string>;
|
|
22
|
+
}
|
|
23
|
+
export interface DshWorkspaceRegistryLike {
|
|
24
|
+
resolveByPath(path: string): Promise<DshWorkspaceLike | undefined>;
|
|
25
|
+
}
|
|
26
|
+
export interface DshSandboxPolicyLike {
|
|
27
|
+
resolve(request: {
|
|
28
|
+
session: DshSessionLike;
|
|
29
|
+
}): {
|
|
30
|
+
readonly mode?: string;
|
|
31
|
+
readonly workspaceRoot?: string;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export interface DshPermissionPresetServiceLike {
|
|
35
|
+
/**
|
|
36
|
+
* The host resolves a preset from a session's `permissions` projection
|
|
37
|
+
* (`ctx.sessionProjections.stateOf(session, 'permissions')`); passing the
|
|
38
|
+
* session object is the contract the host itself calls with.
|
|
39
|
+
*/
|
|
40
|
+
current(session: DshSessionLike): unknown;
|
|
41
|
+
}
|
|
42
|
+
export interface DshApprovalServiceLike {
|
|
43
|
+
readonly config?: {
|
|
44
|
+
readonly policy?: unknown;
|
|
45
|
+
};
|
|
46
|
+
overrideOf(session: DshSessionLike): unknown;
|
|
47
|
+
}
|
|
48
|
+
export interface DshContextServices {
|
|
49
|
+
readonly sessions?: DshSessionStoreLike;
|
|
50
|
+
readonly workspaceRegistry?: DshWorkspaceRegistryLike;
|
|
51
|
+
readonly sandboxPolicy?: DshSandboxPolicyLike;
|
|
52
|
+
readonly permissionPresets?: DshPermissionPresetServiceLike;
|
|
53
|
+
readonly approval?: DshApprovalServiceLike;
|
|
54
|
+
}
|
|
55
|
+
export type DshContextState = 'text-only' | 'ready';
|
|
56
|
+
export type DshSessionState = 'not-required' | 'trusted';
|
|
57
|
+
export type DshWorkspaceState = 'not-required' | 'trusted';
|
|
58
|
+
export type DshSandboxMode = 'read-only' | 'workspace-write' | 'danger-full-access';
|
|
59
|
+
export type DshApprovalPolicy = 'ask' | 'never';
|
|
60
|
+
export type DshPermissionPreset = DshSandboxMode | 'unknown';
|
|
61
|
+
export type DshServiceAvailability = 'available' | 'missing';
|
|
62
|
+
export interface DshContextDiagnostic {
|
|
63
|
+
readonly schemaVersion: 1;
|
|
64
|
+
readonly requested: boolean;
|
|
65
|
+
readonly toolSchemaCount: number;
|
|
66
|
+
readonly services: {
|
|
67
|
+
readonly sessions: DshServiceAvailability;
|
|
68
|
+
readonly workspaceRegistry: DshServiceAvailability;
|
|
69
|
+
readonly sandboxPolicy: DshServiceAvailability;
|
|
70
|
+
readonly permissionPresets: DshServiceAvailability;
|
|
71
|
+
readonly approval: DshServiceAvailability;
|
|
72
|
+
};
|
|
73
|
+
readonly session: {
|
|
74
|
+
readonly state: 'not-required' | 'required' | 'available' | 'unknown' | 'invalid' | 'unavailable';
|
|
75
|
+
readonly idPresent: boolean;
|
|
76
|
+
};
|
|
77
|
+
readonly workspace: {
|
|
78
|
+
readonly state: 'not-required' | 'trusted' | 'mismatch' | 'unavailable' | 'invalid';
|
|
79
|
+
};
|
|
80
|
+
readonly sandbox: {
|
|
81
|
+
readonly state: 'not-required' | 'available' | 'unavailable';
|
|
82
|
+
readonly mode: DshSandboxMode | null;
|
|
83
|
+
};
|
|
84
|
+
readonly permission: {
|
|
85
|
+
readonly state: 'not-required' | 'available' | 'unavailable';
|
|
86
|
+
readonly preset: DshPermissionPreset | null;
|
|
87
|
+
};
|
|
88
|
+
readonly approval: {
|
|
89
|
+
readonly state: 'not-required' | 'available' | 'unavailable';
|
|
90
|
+
readonly policy: DshApprovalPolicy | null;
|
|
91
|
+
};
|
|
92
|
+
readonly issueCodes: readonly string[];
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Request-scoped, immutable capability metadata. Deliberately contains no cwd,
|
|
96
|
+
* workspace path, prompt, tool arguments, or message content.
|
|
97
|
+
*/
|
|
98
|
+
export interface DshContextSnapshot {
|
|
99
|
+
readonly state: DshContextState;
|
|
100
|
+
readonly sessionState: DshSessionState;
|
|
101
|
+
readonly workspaceState: DshWorkspaceState;
|
|
102
|
+
readonly sandboxMode?: DshSandboxMode;
|
|
103
|
+
readonly permissionPreset?: string;
|
|
104
|
+
readonly approvalPolicy?: DshApprovalPolicy;
|
|
105
|
+
readonly toolSchemaCount: number;
|
|
106
|
+
}
|
|
107
|
+
export type DshContextErrorCode = typeof DSH_APPROVAL_UNAVAILABLE_CODE | typeof DSH_CONTEXT_UNAVAILABLE_CODE | typeof DSH_PERMISSION_UNAVAILABLE_CODE | typeof DSH_SANDBOX_UNAVAILABLE_CODE | typeof DSH_SESSION_INVALID_CODE | typeof DSH_SESSION_REQUIRED_CODE | typeof DSH_SESSION_UNAVAILABLE_CODE | typeof DSH_SESSION_UNKNOWN_CODE | typeof DSH_WORKSPACE_MISMATCH_CODE | typeof DSH_WORKSPACE_UNAVAILABLE_CODE;
|
|
108
|
+
/** Stable, path-redacted error at the DSH capability boundary. */
|
|
109
|
+
export declare class DshContextError extends Error {
|
|
110
|
+
readonly code: DshContextErrorCode;
|
|
111
|
+
constructor(code: DshContextErrorCode);
|
|
112
|
+
}
|
|
113
|
+
/** Read optional DSH services through Cordis reflection, never direct properties. */
|
|
114
|
+
export declare function readDshContextServices(context: DshContextLookup | undefined): DshContextServices;
|
|
115
|
+
/**
|
|
116
|
+
* Probe only the DSH capability services needed by a tool request. The report
|
|
117
|
+
* contains labels and allowlisted modes only; it never includes session IDs,
|
|
118
|
+
* cwd/workspace paths, events, prompts, arguments, or service error text.
|
|
119
|
+
*/
|
|
120
|
+
export declare function diagnoseDshContext(context: DshContextLookup | undefined, options: {
|
|
121
|
+
readonly sessionId?: string;
|
|
122
|
+
readonly toolSchemaCount?: number;
|
|
123
|
+
}): Promise<DshContextDiagnostic>;
|
|
124
|
+
/**
|
|
125
|
+
* Resolve the DSH-owned capability context without changing any DSH state.
|
|
126
|
+
* Text-only calls intentionally remain usable without the optional services;
|
|
127
|
+
* calls carrying tool schemas require every trust boundary and fail closed.
|
|
128
|
+
*/
|
|
129
|
+
export declare function resolveDshContext(context: DshContextLookup | undefined, options: {
|
|
130
|
+
readonly sessionId?: string;
|
|
131
|
+
readonly toolSchemaCount?: number;
|
|
132
|
+
}): Promise<DshContextSnapshot>;
|
|
133
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
import { realpath, stat } from 'node:fs/promises';
|
|
2
|
+
import { isAbsolute, parse } from 'node:path';
|
|
3
|
+
import { DSH_APPROVAL_UNAVAILABLE_CODE, DSH_CONTEXT_UNAVAILABLE_CODE, DSH_PERMISSION_UNAVAILABLE_CODE, DSH_SANDBOX_UNAVAILABLE_CODE, DSH_SESSION_INVALID_CODE, DSH_SESSION_REQUIRED_CODE, DSH_SESSION_UNAVAILABLE_CODE, DSH_SESSION_UNKNOWN_CODE, DSH_WORKSPACE_MISMATCH_CODE, DSH_WORKSPACE_UNAVAILABLE_CODE, } from '../provider/error-codes.js';
|
|
4
|
+
const ERROR_MESSAGES = {
|
|
5
|
+
[DSH_APPROVAL_UNAVAILABLE_CODE]: 'DSH approval service is unavailable',
|
|
6
|
+
[DSH_CONTEXT_UNAVAILABLE_CODE]: 'DSH capability context is unavailable',
|
|
7
|
+
[DSH_PERMISSION_UNAVAILABLE_CODE]: 'DSH permission preset service is unavailable',
|
|
8
|
+
[DSH_SANDBOX_UNAVAILABLE_CODE]: 'DSH sandbox policy is unavailable',
|
|
9
|
+
[DSH_SESSION_INVALID_CODE]: 'DSH session metadata is invalid',
|
|
10
|
+
[DSH_SESSION_REQUIRED_CODE]: 'DSH sessionId is required when DSH tools are enabled',
|
|
11
|
+
[DSH_SESSION_UNAVAILABLE_CODE]: 'DSH session service is unavailable',
|
|
12
|
+
[DSH_SESSION_UNKNOWN_CODE]: 'DSH session was not found',
|
|
13
|
+
[DSH_WORKSPACE_MISMATCH_CODE]: 'DSH session workspace is not trusted',
|
|
14
|
+
[DSH_WORKSPACE_UNAVAILABLE_CODE]: 'DSH workspace service is unavailable',
|
|
15
|
+
};
|
|
16
|
+
/** Stable, path-redacted error at the DSH capability boundary. */
|
|
17
|
+
export class DshContextError extends Error {
|
|
18
|
+
code;
|
|
19
|
+
constructor(code) {
|
|
20
|
+
super(ERROR_MESSAGES[code]);
|
|
21
|
+
this.name = 'DshContextError';
|
|
22
|
+
this.code = code;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function service(context, name) {
|
|
26
|
+
if (context === undefined)
|
|
27
|
+
return undefined;
|
|
28
|
+
try {
|
|
29
|
+
const direct = context.get(name);
|
|
30
|
+
if (direct !== undefined)
|
|
31
|
+
return direct;
|
|
32
|
+
// Desktop 0.2.0 mounts harness services on the root context while a plugin
|
|
33
|
+
// sees its own loader scope; fall through to the root before giving up.
|
|
34
|
+
const root = context.root;
|
|
35
|
+
const viaRoot = root?.get?.(name);
|
|
36
|
+
if (viaRoot !== undefined)
|
|
37
|
+
return viaRoot;
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
// A host that throws on an unknown service is reported as "absent" so the
|
|
42
|
+
// fail-closed checks downstream decide; never leak service names upward.
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/** Read optional DSH services through Cordis reflection, never direct properties. */
|
|
47
|
+
export function readDshContextServices(context) {
|
|
48
|
+
const sessions = service(context, 'sessions');
|
|
49
|
+
const workspaceRegistry = service(context, 'workspaceRegistry');
|
|
50
|
+
const sandboxPolicy = service(context, 'sandboxPolicy');
|
|
51
|
+
const permissionPresets = service(context, 'permissionPresets');
|
|
52
|
+
const approval = service(context, 'approval');
|
|
53
|
+
return {
|
|
54
|
+
...(sessions === undefined ? {} : { sessions }),
|
|
55
|
+
...(workspaceRegistry === undefined ? {} : { workspaceRegistry }),
|
|
56
|
+
...(sandboxPolicy === undefined ? {} : { sandboxPolicy }),
|
|
57
|
+
...(permissionPresets === undefined ? {} : { permissionPresets }),
|
|
58
|
+
...(approval === undefined ? {} : { approval }),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function snapshot(values) {
|
|
62
|
+
return Object.freeze({
|
|
63
|
+
state: values.state,
|
|
64
|
+
sessionState: values.sessionState,
|
|
65
|
+
workspaceState: values.workspaceState,
|
|
66
|
+
...(values.sandboxMode === undefined ? {} : { sandboxMode: values.sandboxMode }),
|
|
67
|
+
...(values.permissionPreset === undefined ? {} : { permissionPreset: values.permissionPreset }),
|
|
68
|
+
...(values.approvalPolicy === undefined ? {} : { approvalPolicy: values.approvalPolicy }),
|
|
69
|
+
toolSchemaCount: values.toolSchemaCount,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
async function canonicalDirectory(value) {
|
|
73
|
+
if (!isAbsolute(value))
|
|
74
|
+
throw new Error('not absolute');
|
|
75
|
+
const canonical = await realpath(value);
|
|
76
|
+
const info = await stat(canonical);
|
|
77
|
+
if (!info.isDirectory() || canonical === parse(canonical).root)
|
|
78
|
+
throw new Error('not a usable directory');
|
|
79
|
+
return canonical;
|
|
80
|
+
}
|
|
81
|
+
function toolCount(value) {
|
|
82
|
+
if (value === undefined || !Number.isFinite(value) || value <= 0)
|
|
83
|
+
return 0;
|
|
84
|
+
return Math.trunc(value);
|
|
85
|
+
}
|
|
86
|
+
function validSandboxMode(value) {
|
|
87
|
+
return value === 'read-only' || value === 'workspace-write' || value === 'danger-full-access';
|
|
88
|
+
}
|
|
89
|
+
function validApprovalPolicy(value) {
|
|
90
|
+
return value === 'ask' || value === 'never';
|
|
91
|
+
}
|
|
92
|
+
function safePermissionPreset(value) {
|
|
93
|
+
if (value === undefined)
|
|
94
|
+
return null;
|
|
95
|
+
if (validSandboxMode(value))
|
|
96
|
+
return value;
|
|
97
|
+
return 'unknown';
|
|
98
|
+
}
|
|
99
|
+
function serviceAvailability(value) {
|
|
100
|
+
return value === undefined ? 'missing' : 'available';
|
|
101
|
+
}
|
|
102
|
+
function emptyContextDiagnostic(services, count) {
|
|
103
|
+
const requested = count > 0;
|
|
104
|
+
return {
|
|
105
|
+
schemaVersion: 1,
|
|
106
|
+
requested,
|
|
107
|
+
toolSchemaCount: count,
|
|
108
|
+
services: {
|
|
109
|
+
sessions: serviceAvailability(services.sessions),
|
|
110
|
+
workspaceRegistry: serviceAvailability(services.workspaceRegistry),
|
|
111
|
+
sandboxPolicy: serviceAvailability(services.sandboxPolicy),
|
|
112
|
+
permissionPresets: serviceAvailability(services.permissionPresets),
|
|
113
|
+
approval: serviceAvailability(services.approval),
|
|
114
|
+
},
|
|
115
|
+
session: { state: requested ? 'unavailable' : 'not-required', idPresent: false },
|
|
116
|
+
workspace: { state: requested ? 'unavailable' : 'not-required' },
|
|
117
|
+
sandbox: { state: requested ? 'unavailable' : 'not-required', mode: null },
|
|
118
|
+
permission: { state: requested ? 'unavailable' : 'not-required', preset: null },
|
|
119
|
+
approval: { state: requested ? 'unavailable' : 'not-required', policy: null },
|
|
120
|
+
issueCodes: [],
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
function diagnosticForContextError(base, code, idPresent) {
|
|
124
|
+
const next = {
|
|
125
|
+
...base,
|
|
126
|
+
session: { ...base.session, idPresent },
|
|
127
|
+
issueCodes: [code],
|
|
128
|
+
};
|
|
129
|
+
switch (code) {
|
|
130
|
+
case DSH_SESSION_REQUIRED_CODE:
|
|
131
|
+
return { ...next, session: { state: 'required', idPresent: false } };
|
|
132
|
+
case DSH_SESSION_UNKNOWN_CODE:
|
|
133
|
+
return { ...next, session: { state: 'unknown', idPresent } };
|
|
134
|
+
case DSH_SESSION_INVALID_CODE:
|
|
135
|
+
return { ...next, session: { state: 'invalid', idPresent } };
|
|
136
|
+
case DSH_SESSION_UNAVAILABLE_CODE:
|
|
137
|
+
return { ...next, session: { state: 'unavailable', idPresent } };
|
|
138
|
+
case DSH_WORKSPACE_MISMATCH_CODE:
|
|
139
|
+
return { ...next, session: { state: 'available', idPresent }, workspace: { state: 'mismatch' } };
|
|
140
|
+
case DSH_WORKSPACE_UNAVAILABLE_CODE:
|
|
141
|
+
return { ...next, session: { state: 'available', idPresent }, workspace: { state: 'unavailable' } };
|
|
142
|
+
case DSH_SANDBOX_UNAVAILABLE_CODE:
|
|
143
|
+
return {
|
|
144
|
+
...next,
|
|
145
|
+
session: { state: 'available', idPresent },
|
|
146
|
+
workspace: { state: 'trusted' },
|
|
147
|
+
sandbox: { state: 'unavailable', mode: null },
|
|
148
|
+
};
|
|
149
|
+
case DSH_PERMISSION_UNAVAILABLE_CODE:
|
|
150
|
+
return {
|
|
151
|
+
...next,
|
|
152
|
+
session: { state: 'available', idPresent },
|
|
153
|
+
workspace: { state: 'trusted' },
|
|
154
|
+
sandbox: { state: 'available', mode: null },
|
|
155
|
+
permission: { state: 'unavailable', preset: null },
|
|
156
|
+
};
|
|
157
|
+
case DSH_APPROVAL_UNAVAILABLE_CODE:
|
|
158
|
+
return {
|
|
159
|
+
...next,
|
|
160
|
+
session: { state: 'available', idPresent },
|
|
161
|
+
workspace: { state: 'trusted' },
|
|
162
|
+
sandbox: { state: 'available', mode: null },
|
|
163
|
+
permission: { state: 'available', preset: null },
|
|
164
|
+
approval: { state: 'unavailable', policy: null },
|
|
165
|
+
};
|
|
166
|
+
default:
|
|
167
|
+
return next;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Probe only the DSH capability services needed by a tool request. The report
|
|
172
|
+
* contains labels and allowlisted modes only; it never includes session IDs,
|
|
173
|
+
* cwd/workspace paths, events, prompts, arguments, or service error text.
|
|
174
|
+
*/
|
|
175
|
+
export async function diagnoseDshContext(context, options) {
|
|
176
|
+
const count = toolCount(options.toolSchemaCount);
|
|
177
|
+
const services = readDshContextServices(context);
|
|
178
|
+
const base = emptyContextDiagnostic(services, count);
|
|
179
|
+
if (count === 0)
|
|
180
|
+
return base;
|
|
181
|
+
const sessionId = options.sessionId?.trim();
|
|
182
|
+
if (sessionId === undefined || sessionId.length === 0) {
|
|
183
|
+
return diagnosticForContextError(base, DSH_SESSION_REQUIRED_CODE, false);
|
|
184
|
+
}
|
|
185
|
+
try {
|
|
186
|
+
const snapshotValue = await resolveDshContext(context, {
|
|
187
|
+
sessionId,
|
|
188
|
+
toolSchemaCount: count,
|
|
189
|
+
});
|
|
190
|
+
return {
|
|
191
|
+
...base,
|
|
192
|
+
session: { state: 'available', idPresent: true },
|
|
193
|
+
workspace: { state: 'trusted' },
|
|
194
|
+
sandbox: { state: 'available', mode: snapshotValue.sandboxMode ?? null },
|
|
195
|
+
permission: {
|
|
196
|
+
state: 'available',
|
|
197
|
+
preset: safePermissionPreset(snapshotValue.permissionPreset),
|
|
198
|
+
},
|
|
199
|
+
approval: { state: 'available', policy: snapshotValue.approvalPolicy ?? null },
|
|
200
|
+
issueCodes: [],
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
const code = error instanceof DshContextError ? error.code : DSH_CONTEXT_UNAVAILABLE_CODE;
|
|
205
|
+
return diagnosticForContextError(base, code, true);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
function sessionIdOf(session, requested) {
|
|
209
|
+
const sessionId = session.id ?? session.header?.id;
|
|
210
|
+
return sessionId === undefined || sessionId === requested ? requested : undefined;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Resolve the DSH-owned capability context without changing any DSH state.
|
|
214
|
+
* Text-only calls intentionally remain usable without the optional services;
|
|
215
|
+
* calls carrying tool schemas require every trust boundary and fail closed.
|
|
216
|
+
*/
|
|
217
|
+
export async function resolveDshContext(context, options) {
|
|
218
|
+
const count = toolCount(options.toolSchemaCount);
|
|
219
|
+
if (count === 0) {
|
|
220
|
+
return snapshot({
|
|
221
|
+
state: 'text-only',
|
|
222
|
+
sessionState: 'not-required',
|
|
223
|
+
workspaceState: 'not-required',
|
|
224
|
+
toolSchemaCount: 0,
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
const requestedSessionId = options.sessionId?.trim();
|
|
228
|
+
if (requestedSessionId === undefined || requestedSessionId.length === 0) {
|
|
229
|
+
throw new DshContextError(DSH_SESSION_REQUIRED_CODE);
|
|
230
|
+
}
|
|
231
|
+
const services = readDshContextServices(context);
|
|
232
|
+
if (services.sessions === undefined)
|
|
233
|
+
throw new DshContextError(DSH_SESSION_UNAVAILABLE_CODE);
|
|
234
|
+
let session;
|
|
235
|
+
try {
|
|
236
|
+
session = services.sessions.get(requestedSessionId);
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
throw new DshContextError(DSH_SESSION_UNAVAILABLE_CODE);
|
|
240
|
+
}
|
|
241
|
+
if (session === undefined)
|
|
242
|
+
throw new DshContextError(DSH_SESSION_UNKNOWN_CODE);
|
|
243
|
+
if (sessionIdOf(session, requestedSessionId) === undefined) {
|
|
244
|
+
throw new DshContextError(DSH_SESSION_INVALID_CODE);
|
|
245
|
+
}
|
|
246
|
+
const cwd = session.header?.cwd;
|
|
247
|
+
if (typeof cwd !== 'string' || cwd.trim().length === 0) {
|
|
248
|
+
throw new DshContextError(DSH_SESSION_INVALID_CODE);
|
|
249
|
+
}
|
|
250
|
+
let canonicalCwd;
|
|
251
|
+
try {
|
|
252
|
+
canonicalCwd = await canonicalDirectory(cwd);
|
|
253
|
+
}
|
|
254
|
+
catch {
|
|
255
|
+
throw new DshContextError(DSH_SESSION_INVALID_CODE);
|
|
256
|
+
}
|
|
257
|
+
const workspaceRegistry = services.workspaceRegistry;
|
|
258
|
+
if (workspaceRegistry === undefined)
|
|
259
|
+
throw new DshContextError(DSH_WORKSPACE_UNAVAILABLE_CODE);
|
|
260
|
+
let workspace;
|
|
261
|
+
try {
|
|
262
|
+
workspace = await workspaceRegistry.resolveByPath(canonicalCwd);
|
|
263
|
+
}
|
|
264
|
+
catch {
|
|
265
|
+
throw new DshContextError(DSH_WORKSPACE_UNAVAILABLE_CODE);
|
|
266
|
+
}
|
|
267
|
+
if (workspace === undefined || typeof workspace.path !== 'string') {
|
|
268
|
+
throw new DshContextError(DSH_WORKSPACE_MISMATCH_CODE);
|
|
269
|
+
}
|
|
270
|
+
let canonicalWorkspacePath;
|
|
271
|
+
try {
|
|
272
|
+
canonicalWorkspacePath = await canonicalDirectory(workspace.path);
|
|
273
|
+
}
|
|
274
|
+
catch {
|
|
275
|
+
throw new DshContextError(DSH_WORKSPACE_MISMATCH_CODE);
|
|
276
|
+
}
|
|
277
|
+
if (canonicalWorkspacePath !== canonicalCwd) {
|
|
278
|
+
throw new DshContextError(DSH_WORKSPACE_MISMATCH_CODE);
|
|
279
|
+
}
|
|
280
|
+
// The canonical session cwd is the trust binding. workspace.sessionIds is
|
|
281
|
+
// eventually consistent for a newly-created session and must not turn an
|
|
282
|
+
// otherwise matching workspace into a transient mismatch.
|
|
283
|
+
if (workspace.status !== undefined) {
|
|
284
|
+
let status;
|
|
285
|
+
try {
|
|
286
|
+
status = await workspace.status();
|
|
287
|
+
}
|
|
288
|
+
catch {
|
|
289
|
+
throw new DshContextError(DSH_WORKSPACE_MISMATCH_CODE);
|
|
290
|
+
}
|
|
291
|
+
if (status !== 'ok')
|
|
292
|
+
throw new DshContextError(DSH_WORKSPACE_MISMATCH_CODE);
|
|
293
|
+
}
|
|
294
|
+
const sandboxPolicy = services.sandboxPolicy;
|
|
295
|
+
if (sandboxPolicy === undefined)
|
|
296
|
+
throw new DshContextError(DSH_SANDBOX_UNAVAILABLE_CODE);
|
|
297
|
+
let policy;
|
|
298
|
+
try {
|
|
299
|
+
policy = sandboxPolicy.resolve({ session });
|
|
300
|
+
}
|
|
301
|
+
catch {
|
|
302
|
+
throw new DshContextError(DSH_SANDBOX_UNAVAILABLE_CODE);
|
|
303
|
+
}
|
|
304
|
+
if (!validSandboxMode(policy.mode) || typeof policy.workspaceRoot !== 'string') {
|
|
305
|
+
throw new DshContextError(DSH_SANDBOX_UNAVAILABLE_CODE);
|
|
306
|
+
}
|
|
307
|
+
let canonicalPolicyRoot;
|
|
308
|
+
try {
|
|
309
|
+
canonicalPolicyRoot = await canonicalDirectory(policy.workspaceRoot);
|
|
310
|
+
}
|
|
311
|
+
catch {
|
|
312
|
+
throw new DshContextError(DSH_SANDBOX_UNAVAILABLE_CODE);
|
|
313
|
+
}
|
|
314
|
+
if (canonicalPolicyRoot !== canonicalCwd)
|
|
315
|
+
throw new DshContextError(DSH_WORKSPACE_MISMATCH_CODE);
|
|
316
|
+
const permissionPresets = services.permissionPresets;
|
|
317
|
+
if (permissionPresets === undefined)
|
|
318
|
+
throw new DshContextError(DSH_PERMISSION_UNAVAILABLE_CODE);
|
|
319
|
+
let permissionPreset;
|
|
320
|
+
try {
|
|
321
|
+
permissionPreset = permissionPresets.current(session);
|
|
322
|
+
}
|
|
323
|
+
catch {
|
|
324
|
+
throw new DshContextError(DSH_PERMISSION_UNAVAILABLE_CODE);
|
|
325
|
+
}
|
|
326
|
+
if (typeof permissionPreset !== 'string' || permissionPreset.trim().length === 0) {
|
|
327
|
+
throw new DshContextError(DSH_PERMISSION_UNAVAILABLE_CODE);
|
|
328
|
+
}
|
|
329
|
+
const approval = services.approval;
|
|
330
|
+
if (approval === undefined)
|
|
331
|
+
throw new DshContextError(DSH_APPROVAL_UNAVAILABLE_CODE);
|
|
332
|
+
let approvalPolicy;
|
|
333
|
+
try {
|
|
334
|
+
const override = approval.overrideOf(session);
|
|
335
|
+
approvalPolicy = override ?? approval.config?.policy ?? 'ask';
|
|
336
|
+
}
|
|
337
|
+
catch {
|
|
338
|
+
throw new DshContextError(DSH_APPROVAL_UNAVAILABLE_CODE);
|
|
339
|
+
}
|
|
340
|
+
if (!validApprovalPolicy(approvalPolicy))
|
|
341
|
+
throw new DshContextError(DSH_APPROVAL_UNAVAILABLE_CODE);
|
|
342
|
+
return snapshot({
|
|
343
|
+
state: 'ready',
|
|
344
|
+
sessionState: 'trusted',
|
|
345
|
+
workspaceState: 'trusted',
|
|
346
|
+
sandboxMode: policy.mode,
|
|
347
|
+
permissionPreset,
|
|
348
|
+
approvalPolicy,
|
|
349
|
+
toolSchemaCount: count,
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
//# sourceMappingURL=context.js.map
|
package/lib/dsh-home.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { homedir } from 'node:os';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* DSH data root. `$DSH_HOME` wins so the home follows the desktop shell's
|
|
5
|
+
* relocation; plugins must not hardcode `~/.dsh` below this helper.
|
|
6
|
+
*/
|
|
7
|
+
export function dshHome() {
|
|
8
|
+
const fromEnv = process.env.DSH_HOME?.trim();
|
|
9
|
+
return fromEnv !== undefined && fromEnv.length > 0 ? fromEnv : join(homedir(), '.dsh');
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=dsh-home.js.map
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DSH bundle entry point.
|
|
3
|
+
*
|
|
4
|
+
* The bundle patch carries explicit ready defaults for DSH profile installs.
|
|
5
|
+
* Keep the public programmatic Config schema safe for direct library callers;
|
|
6
|
+
* BundleConfig is available when a caller explicitly wants bundle defaults.
|
|
7
|
+
*/
|
|
8
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
9
|
+
import { AgyAdapter } from './provider/agy.js';
|
|
10
|
+
import { BundleConfig, Config as ConfigSchema, createConfigSchema, type Config as ConfigType } from './provider/config.js';
|
|
11
|
+
import type { ModelConfig, ToolPolicy } from './provider/config.js';
|
|
12
|
+
import { MockAdapter } from './provider/mock.js';
|
|
13
|
+
export declare const name = "dsh-agy-cli";
|
|
14
|
+
export declare const inject: string[];
|
|
15
|
+
/** Programmatic library default: enabled=false, toolPolicy=reject. */
|
|
16
|
+
export declare const Config: import("@deepseek-ai/schemastery").default<ConfigSchema>;
|
|
17
|
+
export { AgyAdapter, MockAdapter };
|
|
18
|
+
export { AgyModelDiscovery, mergeModelCatalog, parseAgyModels } from './agy/models.js';
|
|
19
|
+
export { diagnoseAgy } from './agy/diagnostics.js';
|
|
20
|
+
export { diagnoseProvider } from './diagnostics.js';
|
|
21
|
+
export { DshContextError, diagnoseDshContext, readDshContextServices, resolveDshContext } from './dsh/context.js';
|
|
22
|
+
export { appendToolProtocolPrompt, createStructuredToolProtocol, parseStructuredEnvelope, renderToolProtocolPrompt, StructuredResponseAccumulator, ToolProtocolError, TOOL_PROTOCOL_LIMITS, } from './provider/tool-protocol.js';
|
|
23
|
+
export { stageToolSchema } from './provider/tool-schema-file.js';
|
|
24
|
+
export type { DshApprovalPolicy, DshApprovalServiceLike, DshContextLookup, DshContextServices, DshContextSnapshot, DshContextState, DshContextErrorCode, DshContextDiagnostic, DshPermissionPreset, DshPermissionPresetServiceLike, DshSandboxMode, DshSandboxPolicyLike, DshServiceAvailability, DshSessionLike, DshSessionState, DshSessionStoreLike, DshWorkspaceLike, DshWorkspaceRegistryLike, DshWorkspaceState, } from './dsh/context.js';
|
|
25
|
+
export type { StructuredEnvelope, StructuredToolProtocol, ToolProtocolErrorCode, } from './provider/tool-protocol.js';
|
|
26
|
+
export type { StagedToolSchema } from './provider/tool-schema-file.js';
|
|
27
|
+
export { diagnoseProfile, runDoctor } from './doctor.js';
|
|
28
|
+
export { AgyImageBridgeError, DEFAULT_IMAGE_MAX_BYTES, DEFAULT_IMAGE_MAX_COUNT, IMAGE_MEDIA_TYPES, prepareAgyPrompts, } from './provider/image-bridge.js';
|
|
29
|
+
import { agentTemplatesForRequest } from './agent-presets.js';
|
|
30
|
+
import { AGENT_PRESET_IDS, getAgentPreset, listAgentPresets, readAgentPresetTemplate, requireAgentPreset } from './agent-presets.js';
|
|
31
|
+
export { AGENT_PRESET_IDS, agentTemplatesForRequest, getAgentPreset, listAgentPresets, readAgentPresetTemplate, requireAgentPreset, };
|
|
32
|
+
export { DEFAULT_AGENT_DIRECTORY, AgentInstallError, describeAgentPresets, findMissingAgentTemplates, installAgentPreset, isAgentPreset, } from './agent-installer.js';
|
|
33
|
+
export { formatAgentsHelp, runAgentsCli } from './agents-cli.js';
|
|
34
|
+
export { BundleConfig, ConfigSchema, createConfigSchema };
|
|
35
|
+
export type { DoctorOptions, DoctorResult, EffectiveBridgeCapability, EffectiveDshContext, ProfileDiagnosticOptions, ProfileDiagnosticResult, } from './doctor.js';
|
|
36
|
+
export type { AgentExecutionMode, AgentPreset, AgentPresetId, } from './agent-presets.js';
|
|
37
|
+
export type { AgentDirectoryEntry, AgentInstallAction, AgentInstallResult, AgentInstallOptions, MissingAgentTemplate, } from './agent-installer.js';
|
|
38
|
+
export type { AgyImageAttachmentStore, AgyImageBridgeErrorCode, AgyImageMediaType, ImageBridgeOptions, PreparedAgyPrompts, } from './provider/image-bridge.js';
|
|
39
|
+
export type { ConfigType, ModelConfig, ToolPolicy };
|
|
40
|
+
export interface Config extends ConfigType {
|
|
41
|
+
}
|
|
42
|
+
export declare function apply(ctx: Context, config: ConfigType): void;
|
|
43
|
+
//# sourceMappingURL=index.d.ts.map
|