@hongmaple0820/dsh-scale 0.0.0-stage → 0.1.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/README.md +59 -2
- package/cordis.patch.yml +6 -0
- package/lib/cliExecutor.d.ts +19 -0
- package/lib/cliExecutor.js +88 -0
- package/lib/cliExecutor.js.map +1 -0
- package/lib/client.d.ts +11 -0
- package/lib/client.js +114 -0
- package/lib/client.js.map +1 -0
- package/lib/commandsBridge.d.ts +26 -0
- package/lib/commandsBridge.js +52 -0
- package/lib/commandsBridge.js.map +1 -0
- package/lib/cortexBridge.d.ts +17 -0
- package/lib/cortexBridge.js +34 -0
- package/lib/cortexBridge.js.map +1 -0
- package/lib/dshTypes.d.ts +99 -0
- package/lib/dshTypes.js +9 -0
- package/lib/dshTypes.js.map +1 -0
- package/lib/evidenceBridge.d.ts +19 -0
- package/lib/evidenceBridge.js +92 -0
- package/lib/evidenceBridge.js.map +1 -0
- package/lib/index.d.ts +33 -0
- package/lib/index.js +195 -0
- package/lib/index.js.map +1 -0
- package/lib/shieldBridge.d.ts +28 -0
- package/lib/shieldBridge.js +74 -0
- package/lib/shieldBridge.js.map +1 -0
- package/lib/skillsBridge.d.ts +18 -0
- package/lib/skillsBridge.js +123 -0
- package/lib/skillsBridge.js.map +1 -0
- package/package.json +57 -4
package/README.md
CHANGED
|
@@ -1,3 +1,60 @@
|
|
|
1
|
-
#
|
|
1
|
+
# dsh-scale
|
|
2
|
+
|
|
3
|
+
SCALE Engine 治理插件 for DeepSeek Harness(DSH)。一个 `apply()` 挂五座桥:
|
|
4
|
+
|
|
5
|
+
| 桥 | DSH 扩展点 | 作用 |
|
|
6
|
+
| --- | --- | --- |
|
|
7
|
+
| Shield | `tools/pre-execute`(waterfall) | 危险命令拦截(block→deny)、受保护路径、warn 级命令转 `ask` 用户确认 |
|
|
8
|
+
| Cortex | `systemPrompt.context` | 注入 SCALE 证据纪律契约 + 高置信本能(`InstinctStore`/`SessionInjector`) |
|
|
9
|
+
| Evidence | `tools/post-execute` | 工具调用落 `.scale/evidence/runtime/`(异步、默认 failures-only) |
|
|
10
|
+
| Commands(T2) | `ctx.commands.register` | 6 个治理斜杠命令:`/scale-preflight`、`/scale-gate-quality`、`/scale-verify`、`/scale-shield-status`、`/scale-cortex-metrics`、`/scale-doctor-env`——真实拉起 `scale` CLI(allowlist 固定参数、120–300s 超时、输出截断) |
|
|
11
|
+
| Skills(T2) | `ctx.skills.registerProvider` | `.scale/skills/<PHASE>/<name>.md` 阶段工作流技能进 DSH 注册表(名字 kebab-case、正文 get() 懒加载;`skills.json` 的域路由元数据不注册——那些指向全局根的外部技能,DSH 自己的文件发现负责) |
|
|
12
|
+
|
|
13
|
+
客户端半(T3):`exports["./client"]`(`dsh.client.platform: "web"`)为 25 个 `mcp__scale__*` 工具注册 `tool.call.toolview` 卡片——纯展示(会话内参数 + 结果),轻量 React(`React.createElement` 全局 + `styles.insert`,无 JSX、无 Vue 混挂——计划 R6 允许的回退路线,U4 就此关闭),不触文件系统。
|
|
14
|
+
|
|
15
|
+
工具名映射(DSH → SCALE Shield):`pwsh→Bash`、`write→Write`、`edit→Edit`、`read→Read`;`mcp__scale__*` 前缀自动解包(`shell_run` 按 Bash 语义判定)。
|
|
16
|
+
|
|
17
|
+
## 配置(cordis.patch.yml config)
|
|
18
|
+
|
|
19
|
+
| 键 | 默认 | 说明 |
|
|
20
|
+
| --- | --- | --- |
|
|
21
|
+
| `projectDir` | `''`(用 DSH 会话 cwd) | `.scale/` 所在项目根 |
|
|
22
|
+
| `enableShield` / `enableCortex` / `enableEvidence` / `enableCommands` / `enableSkills` | `true` | 五座桥单独开关 |
|
|
23
|
+
| `evidenceMode` | `'failures-only'` | `'all'` 记录全部工具调用(写盘量未压测,plan U8) |
|
|
24
|
+
|
|
25
|
+
## 本地开发
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# 1. 构建主包(插件类型与运行时都依赖 dist/)
|
|
29
|
+
npm run build # repo root
|
|
30
|
+
|
|
31
|
+
# 2. 插件依赖 + 构建(file: 链接主包)
|
|
32
|
+
cd packages/dsh-scale
|
|
33
|
+
npm install
|
|
34
|
+
npm run build
|
|
35
|
+
|
|
36
|
+
# 3. 独立 profile 验证(desktop 被 Electron 独占,不能用)
|
|
37
|
+
dsh --profile scale-dev --from-default-profile web # 建一次
|
|
38
|
+
dsh --profile scale-dev --patch packages/dsh-scale/dev.patch.yml --dump-config
|
|
39
|
+
SCALE_DSH_SELFTEST=1 dsh --profile scale-dev --patch packages/dsh-scale/dev.patch.yml --help
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`SCALE_DSH_SELFTEST=1` 触发 §5.6 式零 API 自测(BLOCK/PROTECT/ALLOW 三用例)。
|
|
43
|
+
|
|
44
|
+
## 安装(正式)
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
dsh plugin --profile <profile> add @hongmaple0820/dsh-scale
|
|
48
|
+
dsh --profile <profile> --dump-config # 确认 scale-governance 层未被跳过
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
发布须知:`files` 只含 `lib/`(预构建,含 client.js)+ `cordis.patch.yml`,避免 git 安装的 build 授权陷阱(plan §2.11)。
|
|
52
|
+
|
|
53
|
+
## 边界
|
|
54
|
+
|
|
55
|
+
- 不构造 `SQLiteArtifactStore`/`MemoryBrain` —— DSH 的 Electron ABI(MODULE_VERSION 149)与主包原生模块(137)不兼容;本插件只走 `InMemoryArtifactStore`/纯函数路径(plan R1)。
|
|
56
|
+
- 多项目:`projectDir` 固定值在多工作区场景会保护错项目;Shield 逐次按 `exec.agent.session.header.cwd` 解析。Skills/Commands 按进程 cwd(`projectDir` 配置优先)。
|
|
57
|
+
- `SessionInjector` 的 `.scale/specs` 按 `process.cwd()` 解析(主包既有行为),会话 cwd ≠ projectDir 时 specs 段缺省。
|
|
58
|
+
- 斜杠命令的 CLI 参数是 allowlist 固定的,`rawInput` 不透传(v1 安全取舍);需要带参命令时先扩 allowlist。
|
|
59
|
+
- 客户端卡片对 props 做防御式消费(第三方卡片的载荷形状不是稳定公开契约),缺字段时降级为仅显示工具名。
|
|
2
60
|
|
|
3
|
-
This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
|
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface CliRunResult {
|
|
2
|
+
ok: boolean;
|
|
3
|
+
exitCode: number | null;
|
|
4
|
+
output: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Locate <main package>/dist/api/cli.js by walking up from this module
|
|
8
|
+
* looking for the installed package. Filesystem probing (not require.resolve):
|
|
9
|
+
* the main package is ESM-only — its `exports` map has just an `import`
|
|
10
|
+
* condition, so a CJS resolve of the bare name always throws
|
|
11
|
+
* ERR_PACKAGE_PATH_NOT_EXPORTED. Symlinks (npm file:, pnpm) are realpath'd
|
|
12
|
+
* to the physical package root.
|
|
13
|
+
*/
|
|
14
|
+
export declare function resolveScaleCli(): string | null;
|
|
15
|
+
/**
|
|
16
|
+
* Run `scale <args...>` in projectDir. Output (stdout+stderr) is capped;
|
|
17
|
+
* timeout kills the child and reports failure. Never rejects.
|
|
18
|
+
*/
|
|
19
|
+
export declare function runScaleCli(args: string[], projectDir: string, timeoutMs?: number): Promise<CliRunResult>;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// dsh-scale: SCALE CLI executor — spawns the real `scale` CLI from the
|
|
2
|
+
// resolved main package (dist/api/cli.js, the `bin` entry) with a hard
|
|
3
|
+
// timeout and bounded output. Never throws: every failure is a return value
|
|
4
|
+
// (a throwing command handler settles as an error result, but staying inside
|
|
5
|
+
// the contract is cheaper than relying on that).
|
|
6
|
+
import { spawn } from 'node:child_process';
|
|
7
|
+
import { existsSync, realpathSync } from 'node:fs';
|
|
8
|
+
import { dirname, join } from 'node:path';
|
|
9
|
+
import { fileURLToPath } from 'node:url';
|
|
10
|
+
const OUTPUT_CAP = 20_000;
|
|
11
|
+
const DEFAULT_TIMEOUT_MS = 120_000;
|
|
12
|
+
const PKG_DIR = join('node_modules', '@hongmaple0820', 'scale-engine');
|
|
13
|
+
/**
|
|
14
|
+
* Locate <main package>/dist/api/cli.js by walking up from this module
|
|
15
|
+
* looking for the installed package. Filesystem probing (not require.resolve):
|
|
16
|
+
* the main package is ESM-only — its `exports` map has just an `import`
|
|
17
|
+
* condition, so a CJS resolve of the bare name always throws
|
|
18
|
+
* ERR_PACKAGE_PATH_NOT_EXPORTED. Symlinks (npm file:, pnpm) are realpath'd
|
|
19
|
+
* to the physical package root.
|
|
20
|
+
*/
|
|
21
|
+
export function resolveScaleCli() {
|
|
22
|
+
let dir = dirname(fileURLToPath(import.meta.url));
|
|
23
|
+
for (let depth = 0; depth < 8; depth += 1) {
|
|
24
|
+
const candidate = join(dir, PKG_DIR);
|
|
25
|
+
if (existsSync(candidate)) {
|
|
26
|
+
const root = realpathSync(candidate);
|
|
27
|
+
const cli = join(root, 'dist', 'api', 'cli.js');
|
|
28
|
+
return existsSync(cli) ? cli : null;
|
|
29
|
+
}
|
|
30
|
+
const parent = dirname(dir);
|
|
31
|
+
if (parent === dir)
|
|
32
|
+
break;
|
|
33
|
+
dir = parent;
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Run `scale <args...>` in projectDir. Output (stdout+stderr) is capped;
|
|
39
|
+
* timeout kills the child and reports failure. Never rejects.
|
|
40
|
+
*/
|
|
41
|
+
export function runScaleCli(args, projectDir, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
42
|
+
const cli = resolveScaleCli();
|
|
43
|
+
if (!cli) {
|
|
44
|
+
return Promise.resolve({
|
|
45
|
+
ok: false,
|
|
46
|
+
exitCode: null,
|
|
47
|
+
output: 'scale CLI not found: @hongmaple0820/scale-engine is not installed (or dist/ not built) next to dsh-scale',
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
return new Promise((resolve) => {
|
|
51
|
+
let output = '';
|
|
52
|
+
let settled = false;
|
|
53
|
+
const child = spawn(process.execPath, [cli, ...args], {
|
|
54
|
+
cwd: projectDir,
|
|
55
|
+
env: { ...process.env, SCALE_DIR: '.scale' },
|
|
56
|
+
windowsHide: true,
|
|
57
|
+
});
|
|
58
|
+
const cap = (chunk) => {
|
|
59
|
+
if (output.length >= OUTPUT_CAP)
|
|
60
|
+
return;
|
|
61
|
+
output = (output + chunk).slice(0, OUTPUT_CAP);
|
|
62
|
+
};
|
|
63
|
+
child.stdout.on('data', (d) => cap(String(d)));
|
|
64
|
+
child.stderr.on('data', (d) => cap(String(d)));
|
|
65
|
+
const timer = setTimeout(() => {
|
|
66
|
+
if (settled)
|
|
67
|
+
return;
|
|
68
|
+
settled = true;
|
|
69
|
+
child.kill();
|
|
70
|
+
resolve({ ok: false, exitCode: null, output: `${output}\n[scale] timed out after ${timeoutMs}ms` });
|
|
71
|
+
}, timeoutMs);
|
|
72
|
+
child.on('error', (err) => {
|
|
73
|
+
if (settled)
|
|
74
|
+
return;
|
|
75
|
+
settled = true;
|
|
76
|
+
clearTimeout(timer);
|
|
77
|
+
resolve({ ok: false, exitCode: null, output: `spawn failed: ${err.message}` });
|
|
78
|
+
});
|
|
79
|
+
child.on('close', (code) => {
|
|
80
|
+
if (settled)
|
|
81
|
+
return;
|
|
82
|
+
settled = true;
|
|
83
|
+
clearTimeout(timer);
|
|
84
|
+
resolve({ ok: code === 0, exitCode: code, output });
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=cliExecutor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cliExecutor.js","sourceRoot":"","sources":["../src/cliExecutor.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,uEAAuE;AACvE,4EAA4E;AAC5E,6EAA6E;AAC7E,iDAAiD;AAEjD,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AAC1C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAQxC,MAAM,UAAU,GAAG,MAAM,CAAA;AACzB,MAAM,kBAAkB,GAAG,OAAO,CAAA;AAClC,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,EAAE,gBAAgB,EAAE,cAAc,CAAC,CAAA;AAEtE;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe;IAC7B,IAAI,GAAG,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;IACjD,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QAC1C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;QACpC,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,GAAG,YAAY,CAAC,SAAS,CAAC,CAAA;YACpC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAA;YAC/C,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAA;QACrC,CAAC;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAA;QAC3B,IAAI,MAAM,KAAK,GAAG;YAAE,MAAK;QACzB,GAAG,GAAG,MAAM,CAAA;IACd,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CACzB,IAAc,EACd,UAAkB,EAClB,SAAS,GAAG,kBAAkB;IAE9B,MAAM,GAAG,GAAG,eAAe,EAAE,CAAA;IAC7B,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,OAAO,OAAO,CAAC,OAAO,CAAC;YACrB,EAAE,EAAE,KAAK;YACT,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE,0GAA0G;SACnH,CAAC,CAAA;IACJ,CAAC;IAED,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,IAAI,MAAM,GAAG,EAAE,CAAA;QACf,IAAI,OAAO,GAAG,KAAK,CAAA;QACnB,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,EAAE;YACpD,GAAG,EAAE,UAAU;YACf,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE;YAC5C,WAAW,EAAE,IAAI;SAClB,CAAC,CAAA;QAEF,MAAM,GAAG,GAAG,CAAC,KAAa,EAAE,EAAE;YAC5B,IAAI,MAAM,CAAC,MAAM,IAAI,UAAU;gBAAE,OAAM;YACvC,MAAM,GAAG,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAA;QAChD,CAAC,CAAA;QACD,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QAC9C,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QAE9C,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,IAAI,OAAO;gBAAE,OAAM;YACnB,OAAO,GAAG,IAAI,CAAA;YACd,KAAK,CAAC,IAAI,EAAE,CAAA;YACZ,OAAO,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,6BAA6B,SAAS,IAAI,EAAE,CAAC,CAAA;QACrG,CAAC,EAAE,SAAS,CAAC,CAAA;QAEb,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACxB,IAAI,OAAO;gBAAE,OAAM;YACnB,OAAO,GAAG,IAAI,CAAA;YACd,YAAY,CAAC,KAAK,CAAC,CAAA;YACnB,OAAO,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAA;QAChF,CAAC,CAAC,CAAA;QAEF,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACzB,IAAI,OAAO;gBAAE,OAAM;YACnB,OAAO,GAAG,IAAI,CAAA;YACd,YAAY,CAAC,KAAK,CAAC,CAAA;YACnB,OAAO,CAAC,EAAE,EAAE,EAAE,IAAI,KAAK,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAA;QACrD,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC"}
|
package/lib/client.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const inject: string[];
|
|
2
|
+
export declare function apply(ctx: {
|
|
3
|
+
slots?: {
|
|
4
|
+
inject?: (slot: string, fn: () => unknown) => void;
|
|
5
|
+
register?: (meta: {
|
|
6
|
+
name: string;
|
|
7
|
+
key: string;
|
|
8
|
+
}, component: unknown) => unknown;
|
|
9
|
+
};
|
|
10
|
+
effect?: (fn: () => (() => void) | void) => void;
|
|
11
|
+
}): void;
|
package/lib/client.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// dsh-scale client half (T3) — Web (React) client plugin.
|
|
2
|
+
//
|
|
3
|
+
// Route decision (plan R6/U4, resolved): lightweight React components via the
|
|
4
|
+
// client `React` global and `styles.insert` — no JSX transform, no Vue
|
|
5
|
+
// mounting bridge, no DSH-internal module imports. Everything renders from
|
|
6
|
+
// data already in the conversation (tool call args + results); the client
|
|
7
|
+
// never touches the filesystem (plan §6 T3 acceptance).
|
|
8
|
+
//
|
|
9
|
+
// This module must stay free of node-only imports: it loads in the browser.
|
|
10
|
+
/** The 25 MCP tools dsh-scale exposes under mcp__scale__ (27 minus the narrowed shell pair). */
|
|
11
|
+
const SCALE_MCP_TOOLS = [
|
|
12
|
+
'scale_create', 'scale_transition', 'scale_list', 'scale_show', 'scale_available_actions',
|
|
13
|
+
'scale_context', 'scale_stats', 'scale_detect_changes', 'scale_review_context',
|
|
14
|
+
'scale_code_intelligence_status', 'task_create', 'task_start', 'task_status',
|
|
15
|
+
'task_checkpoint', 'task_resume', 'complete_task', 'capability_list', 'capability_map',
|
|
16
|
+
'bridge_register', 'bridge_heartbeat', 'delegation_delegate', 'delegation_review',
|
|
17
|
+
'cortex_promotion_propose', 'cortex_promotion_hit', 'cortex_promotion_approve',
|
|
18
|
+
];
|
|
19
|
+
const CSS = `
|
|
20
|
+
.dsh-scale-card{border:1px solid var(--dsh-border,#e2e2e2);border-radius:8px;padding:8px 10px;margin:4px 0;font-size:12px;font-family:var(--dsh-mono,ui-monospace,monospace)}
|
|
21
|
+
.dsh-scale-card-head{display:flex;gap:6px;align-items:baseline;margin-bottom:4px}
|
|
22
|
+
.dsh-scale-card-badge{background:#1f6feb;color:#fff;border-radius:4px;padding:1px 5px;font-size:10px;font-weight:600;letter-spacing:.03em}
|
|
23
|
+
.dsh-scale-card-name{font-weight:600}
|
|
24
|
+
.dsh-scale-card-args{color:var(--dsh-muted,#666);white-space:pre-wrap;word-break:break-all;max-height:6.5em;overflow:hidden}
|
|
25
|
+
.dsh-scale-card-result{margin-top:4px;color:var(--dsh-text,#222);white-space:pre-wrap;word-break:break-all;max-height:10em;overflow:hidden;border-top:1px dashed var(--dsh-border,#ddd);padding-top:4px}
|
|
26
|
+
`;
|
|
27
|
+
/** Defensive React access — the client exposes React (createElement) as a global (plan §2.8). */
|
|
28
|
+
function react() {
|
|
29
|
+
return globalThis.React;
|
|
30
|
+
}
|
|
31
|
+
function preview(value, cap = 600) {
|
|
32
|
+
if (value === null || value === undefined)
|
|
33
|
+
return '';
|
|
34
|
+
if (typeof value === 'string')
|
|
35
|
+
return value.slice(0, cap);
|
|
36
|
+
try {
|
|
37
|
+
return JSON.stringify(value, null, 1).slice(0, cap);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return '[unserializable]';
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/** Extract the raw tool name from mcp__scale__<name>. */
|
|
44
|
+
function shortName(wireName) {
|
|
45
|
+
return wireName.startsWith('mcp__scale__') ? wireName.slice('mcp__scale__'.length) : wireName;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Toolview card for mcp__scale__* calls. Props are consumed defensively:
|
|
49
|
+
* the exact third-party card payload shape is not part of a stable public
|
|
50
|
+
* contract, so every field is optional and rendering degrades to the name.
|
|
51
|
+
*/
|
|
52
|
+
function ScaleToolCard(props) {
|
|
53
|
+
const R = react();
|
|
54
|
+
if (!R)
|
|
55
|
+
return null;
|
|
56
|
+
const wireName = typeof props.tool === 'string' ? props.tool
|
|
57
|
+
: typeof props.name === 'string' ? props.name
|
|
58
|
+
: 'mcp__scale__?';
|
|
59
|
+
const argsText = preview(props.arguments ?? props.args ?? props.input);
|
|
60
|
+
const resultText = preview(props.result ?? props.content ?? props.output);
|
|
61
|
+
const children = [
|
|
62
|
+
R.createElement('span', { className: 'dsh-scale-card-badge' }, 'SCALE'),
|
|
63
|
+
R.createElement('span', { className: 'dsh-scale-card-name' }, shortName(wireName)),
|
|
64
|
+
];
|
|
65
|
+
if (props.phase === 'preparing' || props.isRunning === true) {
|
|
66
|
+
children.push(R.createElement('span', { className: 'dsh-scale-card-name' }, '· running'));
|
|
67
|
+
}
|
|
68
|
+
const body = [R.createElement('div', { className: 'dsh-scale-card-head' }, ...children)];
|
|
69
|
+
if (argsText)
|
|
70
|
+
body.push(R.createElement('div', { className: 'dsh-scale-card-args' }, argsText));
|
|
71
|
+
if (resultText)
|
|
72
|
+
body.push(R.createElement('div', { className: 'dsh-scale-card-result' }, resultText));
|
|
73
|
+
return R.createElement('div', { className: 'dsh-scale-card', 'data-tool': wireName }, ...body);
|
|
74
|
+
}
|
|
75
|
+
export const inject = ['slots'];
|
|
76
|
+
export function apply(ctx) {
|
|
77
|
+
// Client-scoped CSS, inserted once (styles.insert is a client global).
|
|
78
|
+
const styles = globalThis.styles;
|
|
79
|
+
try {
|
|
80
|
+
styles?.insert(CSS);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
// styling is best-effort; the card still renders unstyled
|
|
84
|
+
}
|
|
85
|
+
const slots = ctx.slots;
|
|
86
|
+
if (!slots?.register)
|
|
87
|
+
return;
|
|
88
|
+
const disposers = [];
|
|
89
|
+
for (const tool of SCALE_MCP_TOOLS) {
|
|
90
|
+
const wireName = `mcp__scale__${tool}`;
|
|
91
|
+
try {
|
|
92
|
+
const registered = slots.register({ name: 'tool.call.toolview', key: wireName }, ScaleToolCard);
|
|
93
|
+
if (typeof registered === 'function')
|
|
94
|
+
disposers.push(registered);
|
|
95
|
+
else if (registered && typeof registered.dispose === 'function') {
|
|
96
|
+
disposers.push(() => registered.dispose());
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// duplicate key (reload) — skip, keep the rest
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
ctx.effect?.(() => () => {
|
|
104
|
+
for (const dispose of disposers) {
|
|
105
|
+
try {
|
|
106
|
+
dispose();
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// best-effort teardown
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { CommandsService } from './dshTypes.js';
|
|
2
|
+
export interface ScaleCommandSpec {
|
|
3
|
+
/** DSH slash command name: /^[a-z][a-z0-9_-]*$/ */
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
/** CLI argv after the `scale` binary (allowlisted — raw user input is never appended) */
|
|
7
|
+
args: string[];
|
|
8
|
+
/** timeout override for slow gates */
|
|
9
|
+
timeoutMs?: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The T2.1 allowlist (plan §6: candidates from ~90 top-level commands).
|
|
13
|
+
* Deliberately excludes daemons (open, dashboard, orch start) and anything
|
|
14
|
+
* that mutates agent installs from inside a UI command.
|
|
15
|
+
*/
|
|
16
|
+
export declare const SCALE_COMMANDS: ScaleCommandSpec[];
|
|
17
|
+
/**
|
|
18
|
+
* Register the allowlisted SCALE commands. The handler stays inside the
|
|
19
|
+
* CommandResult contract on every path — a throw would settle as an error
|
|
20
|
+
* result, but not throwing is cheaper and keeps our own message.
|
|
21
|
+
*/
|
|
22
|
+
export declare function registerScaleCommands(ctx: {
|
|
23
|
+
commands?: CommandsService;
|
|
24
|
+
}, config: {
|
|
25
|
+
projectDir?: string;
|
|
26
|
+
}): number;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// dsh-scale: Commands Bridge (T2.1) — exposes SCALE governance gates as DSH
|
|
2
|
+
// slash commands. Commands are user-invoked UI actions; they never enter the
|
|
3
|
+
// model (plan §2.7). Only non-daemon commands are allowlisted — long-running
|
|
4
|
+
// surfaces (open/dashboard/orch start) stay out because DSH has its own
|
|
5
|
+
// scheduling (plan §6 T2.1).
|
|
6
|
+
import { runScaleCli } from './cliExecutor.js';
|
|
7
|
+
/**
|
|
8
|
+
* The T2.1 allowlist (plan §6: candidates from ~90 top-level commands).
|
|
9
|
+
* Deliberately excludes daemons (open, dashboard, orch start) and anything
|
|
10
|
+
* that mutates agent installs from inside a UI command.
|
|
11
|
+
*/
|
|
12
|
+
export const SCALE_COMMANDS = [
|
|
13
|
+
{ name: 'scale-preflight', description: 'Run SCALE preflight checks for this project', args: ['preflight'] },
|
|
14
|
+
{ name: 'scale-gate-quality', description: 'Run the SCALE quality gate chain', args: ['gate', 'quality'], timeoutMs: 300_000 },
|
|
15
|
+
{ name: 'scale-verify', description: 'Run SCALE verify with the default profile', args: ['verify', '--profile', 'default'], timeoutMs: 300_000 },
|
|
16
|
+
{ name: 'scale-shield-status', description: 'Show Scale Shield hook registration and .scale integrity', args: ['shield', 'status'] },
|
|
17
|
+
{ name: 'scale-cortex-metrics', description: 'Show SCALE Cortex governance ROI metrics (30 days)', args: ['cortex', 'metrics', '--days', '30'] },
|
|
18
|
+
{ name: 'scale-doctor-env', description: 'Diagnose the SCALE environment', args: ['doctor', 'env'] },
|
|
19
|
+
];
|
|
20
|
+
/**
|
|
21
|
+
* Register the allowlisted SCALE commands. The handler stays inside the
|
|
22
|
+
* CommandResult contract on every path — a throw would settle as an error
|
|
23
|
+
* result, but not throwing is cheaper and keeps our own message.
|
|
24
|
+
*/
|
|
25
|
+
export function registerScaleCommands(ctx, config) {
|
|
26
|
+
const commands = ctx.commands;
|
|
27
|
+
if (!commands?.register)
|
|
28
|
+
return 0;
|
|
29
|
+
let registered = 0;
|
|
30
|
+
for (const spec of SCALE_COMMANDS) {
|
|
31
|
+
try {
|
|
32
|
+
commands.register({
|
|
33
|
+
name: spec.name,
|
|
34
|
+
description: spec.description,
|
|
35
|
+
handler: async () => {
|
|
36
|
+
const projectDir = config.projectDir || process.cwd();
|
|
37
|
+
const result = await runScaleCli(spec.args, projectDir, spec.timeoutMs);
|
|
38
|
+
const text = `$ scale ${spec.args.join(' ')}\n${result.output.trim()}`.trim();
|
|
39
|
+
return result.ok
|
|
40
|
+
? { kind: 'success', text }
|
|
41
|
+
: { kind: 'error', text: `${text}\n(exit ${result.exitCode ?? 'killed'})` };
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
registered += 1;
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// duplicate name (reload) or registry closed — skip this command, keep the rest
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return registered;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=commandsBridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commandsBridge.js","sourceRoot":"","sources":["../src/commandsBridge.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,6EAA6E;AAC7E,6EAA6E;AAC7E,wEAAwE;AACxE,6BAA6B;AAG7B,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAY9C;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAuB;IAChD,EAAE,IAAI,EAAE,iBAAiB,EAAE,WAAW,EAAE,6CAA6C,EAAE,IAAI,EAAE,CAAC,WAAW,CAAC,EAAE;IAC5G,EAAE,IAAI,EAAE,oBAAoB,EAAE,WAAW,EAAE,kCAAkC,EAAE,IAAI,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE;IAC9H,EAAE,IAAI,EAAE,cAAc,EAAE,WAAW,EAAE,2CAA2C,EAAE,IAAI,EAAE,CAAC,QAAQ,EAAE,WAAW,EAAE,SAAS,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE;IAChJ,EAAE,IAAI,EAAE,qBAAqB,EAAE,WAAW,EAAE,0DAA0D,EAAE,IAAI,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE;IACpI,EAAE,IAAI,EAAE,sBAAsB,EAAE,WAAW,EAAE,oDAAoD,EAAE,IAAI,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE;IAChJ,EAAE,IAAI,EAAE,kBAAkB,EAAE,WAAW,EAAE,gCAAgC,EAAE,IAAI,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,EAAE;CACrG,CAAA;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CACnC,GAAmC,EACnC,MAA+B;IAE/B,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAA;IAC7B,IAAI,CAAC,QAAQ,EAAE,QAAQ;QAAE,OAAO,CAAC,CAAA;IAEjC,IAAI,UAAU,GAAG,CAAC,CAAA;IAClB,KAAK,MAAM,IAAI,IAAI,cAAc,EAAE,CAAC;QAClC,IAAI,CAAC;YACH,QAAQ,CAAC,QAAQ,CAAC;gBAChB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,WAAW,EAAE,IAAI,CAAC,WAAW;gBAC7B,OAAO,EAAE,KAAK,IAA4B,EAAE;oBAC1C,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,IAAI,OAAO,CAAC,GAAG,EAAE,CAAA;oBACrD,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,CAAA;oBACvE,MAAM,IAAI,GAAG,WAAW,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAA;oBAC7E,OAAO,MAAM,CAAC,EAAE;wBACd,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE;wBAC3B,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,IAAI,WAAW,MAAM,CAAC,QAAQ,IAAI,QAAQ,GAAG,EAAE,CAAA;gBAC/E,CAAC;aACF,CAAC,CAAA;YACF,UAAU,IAAI,CAAC,CAAA;QACjB,CAAC;QAAC,MAAM,CAAC;YACP,gFAAgF;QAClF,CAAC;IACH,CAAC;IACD,OAAO,UAAU,CAAA;AACnB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface CortexContextEntry {
|
|
2
|
+
id: string;
|
|
3
|
+
content: string;
|
|
4
|
+
order: number;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Build the single systemPrompt.context entry for a project.
|
|
8
|
+
*
|
|
9
|
+
* buildMinimal() always returns at least the evidence-discipline contract;
|
|
10
|
+
* high-confidence instincts (≥0.7, plan §3.3) are appended when present.
|
|
11
|
+
* Returns null only if the injection cannot be built at all (graceful degrade).
|
|
12
|
+
*
|
|
13
|
+
* Note: SessionInjector.loadScopedSpecs resolves .scale/specs against
|
|
14
|
+
* process.cwd(), not projectDir — single-project deployments where the DSH
|
|
15
|
+
* session cwd === projectDir get the full injection (plan §6 T1.2 caveat).
|
|
16
|
+
*/
|
|
17
|
+
export declare function buildCortexContext(projectDir: string): CortexContextEntry | null;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// dsh-scale: Cortex Bridge — system prompt instinct injection
|
|
2
|
+
// Uses SCALE's own InstinctStore + SessionInjector so the on-disk format is
|
|
3
|
+
// read by the code that writes it (<domain>/<id>.yaml, .audit.jsonl — plan §3.3).
|
|
4
|
+
// The earlier hand-rolled reader expected manifest.json + flat .md files,
|
|
5
|
+
// which InstinctStore never writes: it silently matched zero instincts.
|
|
6
|
+
import { join } from 'node:path';
|
|
7
|
+
import { InstinctStore, SessionInjector } from '@hongmaple0820/scale-engine';
|
|
8
|
+
/**
|
|
9
|
+
* Build the single systemPrompt.context entry for a project.
|
|
10
|
+
*
|
|
11
|
+
* buildMinimal() always returns at least the evidence-discipline contract;
|
|
12
|
+
* high-confidence instincts (≥0.7, plan §3.3) are appended when present.
|
|
13
|
+
* Returns null only if the injection cannot be built at all (graceful degrade).
|
|
14
|
+
*
|
|
15
|
+
* Note: SessionInjector.loadScopedSpecs resolves .scale/specs against
|
|
16
|
+
* process.cwd(), not projectDir — single-project deployments where the DSH
|
|
17
|
+
* session cwd === projectDir get the full injection (plan §6 T1.2 caveat).
|
|
18
|
+
*/
|
|
19
|
+
export function buildCortexContext(projectDir) {
|
|
20
|
+
try {
|
|
21
|
+
// createDirs: false — reading must never mint a .scale/instincts directory
|
|
22
|
+
const store = new InstinctStore(join(projectDir, '.scale', 'instincts'), { createDirs: false });
|
|
23
|
+
const injector = new SessionInjector(store);
|
|
24
|
+
const injection = injector.buildMinimal();
|
|
25
|
+
if (!injection?.content?.trim())
|
|
26
|
+
return null;
|
|
27
|
+
return { id: 'scale-cortex', content: injection.content, order: 900 };
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// Instinct store unreadable → no injection; Shield and Evidence stay up
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=cortexBridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cortexBridge.js","sourceRoot":"","sources":["../src/cortexBridge.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,4EAA4E;AAC5E,kFAAkF;AAClF,0EAA0E;AAC1E,wEAAwE;AAExE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAQ5E;;;;;;;;;;GAUG;AACH,MAAM,UAAU,kBAAkB,CAAC,UAAkB;IACnD,IAAI,CAAC;QACH,2EAA2E;QAC3E,MAAM,KAAK,GAAG,IAAI,aAAa,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,EAAE,WAAW,CAAC,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAA;QAC/F,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC,KAAK,CAAC,CAAA;QAC3C,MAAM,SAAS,GAAG,QAAQ,CAAC,YAAY,EAAE,CAAA;QACzC,IAAI,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE;YAAE,OAAO,IAAI,CAAA;QAC5C,OAAO,EAAE,EAAE,EAAE,cAAc,EAAE,OAAO,EAAE,SAAS,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,CAAA;IACvE,CAAC;IAAC,MAAM,CAAC;QACP,wEAAwE;QACxE,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/** Event names this plugin subscribes to (plan §2.5 tool pipeline). */
|
|
2
|
+
export type ToolEventListener = (...args: unknown[]) => unknown;
|
|
3
|
+
export interface SystemPromptService {
|
|
4
|
+
/** Register a context block; signature per plan §6 T1.2 (U5: exact arity re-checked at live acceptance). */
|
|
5
|
+
context?: (id: string, content: string, opts?: {
|
|
6
|
+
order?: number;
|
|
7
|
+
}) => void;
|
|
8
|
+
}
|
|
9
|
+
/** Materialized final result of a tools.execute() call (verified against dsh-tools 0.2.1-rc.2). */
|
|
10
|
+
export interface ToolExecutionOutcome {
|
|
11
|
+
isError: boolean;
|
|
12
|
+
content?: Array<{
|
|
13
|
+
type: string;
|
|
14
|
+
text?: string;
|
|
15
|
+
}>;
|
|
16
|
+
message?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface ToolsService {
|
|
19
|
+
/** execute(exec) takes a typed call input object — NOT (name, args). Call it as tools.execute({...}) so `this` stays bound. */
|
|
20
|
+
execute?: (exec: {
|
|
21
|
+
name: string;
|
|
22
|
+
arguments?: Record<string, unknown>;
|
|
23
|
+
callId?: string;
|
|
24
|
+
/** callerCancelled() reads signal.aborted — required in 0.2.1-rc.2. */
|
|
25
|
+
signal?: AbortSignal;
|
|
26
|
+
}) => Promise<ToolExecutionOutcome>;
|
|
27
|
+
}
|
|
28
|
+
/** dsh-commands CommandResult: success may omit text; error text must be non-empty. */
|
|
29
|
+
export type CommandResult = {
|
|
30
|
+
kind: 'success';
|
|
31
|
+
text?: string;
|
|
32
|
+
} | {
|
|
33
|
+
kind: 'error';
|
|
34
|
+
text: string;
|
|
35
|
+
};
|
|
36
|
+
export interface CommandInvocation {
|
|
37
|
+
commandId: string;
|
|
38
|
+
rawInput: string;
|
|
39
|
+
signal: AbortSignal;
|
|
40
|
+
agent?: unknown;
|
|
41
|
+
}
|
|
42
|
+
export interface CommandsService {
|
|
43
|
+
/** name must match /^[a-z][a-z0-9_-]*$/; description non-empty; handler returns CommandResult. */
|
|
44
|
+
register?: (definition: {
|
|
45
|
+
name: string;
|
|
46
|
+
description: string;
|
|
47
|
+
input?: {
|
|
48
|
+
hint: string;
|
|
49
|
+
attachments?: boolean;
|
|
50
|
+
};
|
|
51
|
+
handler: (invocation: CommandInvocation) => Promise<CommandResult> | CommandResult;
|
|
52
|
+
}) => unknown;
|
|
53
|
+
}
|
|
54
|
+
/** /^[a-z0-9]+(?:-[a-z0-9]+)*$/ — kebab-case, no uppercase. */
|
|
55
|
+
export type SkillInvocation = {
|
|
56
|
+
modelInvocable: boolean;
|
|
57
|
+
userInvocable: boolean;
|
|
58
|
+
};
|
|
59
|
+
export interface SkillCandidate {
|
|
60
|
+
name: string;
|
|
61
|
+
description: string;
|
|
62
|
+
invocation: SkillInvocation;
|
|
63
|
+
/** where this skill came from (display) */
|
|
64
|
+
source: string;
|
|
65
|
+
/** must equal the provider's own name */
|
|
66
|
+
provider: string;
|
|
67
|
+
rank: number;
|
|
68
|
+
whenToUse?: string;
|
|
69
|
+
path?: string;
|
|
70
|
+
/** opaque value passed back to provider.get() */
|
|
71
|
+
locator?: unknown;
|
|
72
|
+
}
|
|
73
|
+
export interface SkillDefinition extends SkillCandidate {
|
|
74
|
+
/** full skill body (markdown) */
|
|
75
|
+
content: string;
|
|
76
|
+
}
|
|
77
|
+
export interface SkillProvider {
|
|
78
|
+
name: string;
|
|
79
|
+
list: () => Promise<SkillCandidate[] | {
|
|
80
|
+
candidates: SkillCandidate[];
|
|
81
|
+
complete: boolean;
|
|
82
|
+
}>;
|
|
83
|
+
get: (candidate: SkillCandidate) => Promise<SkillDefinition | undefined>;
|
|
84
|
+
}
|
|
85
|
+
export interface SkillsService {
|
|
86
|
+
/** create() runs synchronously during apply; disk/remote work belongs in list()/get(). */
|
|
87
|
+
registerProvider?: (create: (control: {
|
|
88
|
+
signal: AbortSignal;
|
|
89
|
+
invalidate: () => void;
|
|
90
|
+
}) => SkillProvider) => unknown;
|
|
91
|
+
}
|
|
92
|
+
export interface CordisContext {
|
|
93
|
+
on: (event: string, listener: ToolEventListener) => void;
|
|
94
|
+
effect: (setup: () => (() => void) | void) => void;
|
|
95
|
+
systemPrompt?: SystemPromptService;
|
|
96
|
+
tools?: ToolsService;
|
|
97
|
+
commands?: CommandsService;
|
|
98
|
+
skills?: SkillsService;
|
|
99
|
+
}
|
package/lib/dshTypes.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Minimal structural types for the Cordis Context DSH hands to apply().
|
|
2
|
+
//
|
|
3
|
+
// The real types live in DSH's own cordis package (not published under the
|
|
4
|
+
// bare name `cordis` this plugin could resolve); we only consume three
|
|
5
|
+
// services, so structural types keep the plugin dependency-free while staying
|
|
6
|
+
// honest about what we touch. Swap for `@deepseek-ai/cordis` types once that
|
|
7
|
+
// package is consumable outside the DSH tree (plan R7: rc drift).
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=dshTypes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dshTypes.js","sourceRoot":"","sources":["../src/dshTypes.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,EAAE;AACF,2EAA2E;AAC3E,uEAAuE;AACvE,8EAA8E;AAC9E,6EAA6E;AAC7E,kEAAkE"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type EvidenceMode = 'failures-only' | 'all';
|
|
2
|
+
export interface ToolEvidenceParams {
|
|
3
|
+
toolName: string;
|
|
4
|
+
args: Record<string, unknown>;
|
|
5
|
+
result: unknown;
|
|
6
|
+
error: boolean;
|
|
7
|
+
projectDir: string;
|
|
8
|
+
sessionId?: string;
|
|
9
|
+
mode?: EvidenceMode;
|
|
10
|
+
}
|
|
11
|
+
/** Await all in-flight evidence writes (tests, graceful shutdown). */
|
|
12
|
+
export declare function pendingEvidenceWrites(): Promise<void>;
|
|
13
|
+
/** Reset module state — plugin unload (ctx.effect disposer) and tests. */
|
|
14
|
+
export declare function resetEvidenceBridge(): void;
|
|
15
|
+
/**
|
|
16
|
+
* Record a tool execution. Fire-and-forget: enqueues an async write and
|
|
17
|
+
* returns immediately — evidence must never block or fail the tool result.
|
|
18
|
+
*/
|
|
19
|
+
export declare function recordToolEvidence(params: ToolEvidenceParams): void;
|