@jayyuen66/dsh-plugin-shared 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/LICENSE +21 -0
- package/README.md +230 -0
- package/config/oxlint.base.ts +1020 -0
- package/config/tsconfig.base.json +25 -0
- package/config/tsconfig.client.base.json +10 -0
- package/config/vitest.base.ts +78 -0
- package/dist/canonicalize-region-paths.js +63 -0
- package/dist/card-apply.js +20 -0
- package/dist/config/oxlint.base.js +855 -0
- package/dist/config/vitest.base.js +43 -0
- package/dist/errors.js +7 -0
- package/dist/http.js +121 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +13 -0
- package/dist/job-outcome.js +18 -0
- package/dist/jsonl.js +20 -0
- package/dist/lesson-bus.js +43 -0
- package/dist/locale.js +43 -0
- package/dist/project-key.js +23 -0
- package/dist/record.js +11 -0
- package/dist/text.js +24 -0
- package/dist/tool-events.js +165 -0
- package/dist/trust.js +122 -0
- package/dist/types/canonicalize-region-paths.d.ts +7 -0
- package/dist/types/card-apply.d.ts +25 -0
- package/dist/types/config/oxlint.base.d.ts +109 -0
- package/dist/types/config/vitest.base.d.ts +29 -0
- package/dist/types/errors.d.ts +2 -0
- package/dist/types/http.d.ts +60 -0
- package/dist/types/job-outcome.d.ts +10 -0
- package/dist/types/jsonl.d.ts +8 -0
- package/dist/types/lesson-bus.d.ts +6 -0
- package/dist/types/locale.d.ts +39 -0
- package/dist/types/project-key.d.ts +9 -0
- package/dist/types/record.d.ts +4 -0
- package/dist/types/text.d.ts +10 -0
- package/dist/types/tool-events.d.ts +77 -0
- package/dist/types/trust.d.ts +22 -0
- package/icon.svg +1 -0
- package/package.json +146 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2024",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"lib": ["ES2024"],
|
|
7
|
+
"types": ["node"],
|
|
8
|
+
"strict": true,
|
|
9
|
+
"noImplicitOverride": true,
|
|
10
|
+
"noImplicitReturns": true,
|
|
11
|
+
"noFallthroughCasesInSwitch": true,
|
|
12
|
+
"noUnusedLocals": true,
|
|
13
|
+
"noUnusedParameters": true,
|
|
14
|
+
"noUncheckedSideEffectImports": true,
|
|
15
|
+
"noPropertyAccessFromIndexSignature": true,
|
|
16
|
+
"exactOptionalPropertyTypes": true,
|
|
17
|
+
"noUncheckedIndexedAccess": true,
|
|
18
|
+
"noEmit": true,
|
|
19
|
+
"allowImportingTsExtensions": true,
|
|
20
|
+
"verbatimModuleSyntax": true,
|
|
21
|
+
"erasableSyntaxOnly": true,
|
|
22
|
+
"skipLibCheck": true,
|
|
23
|
+
"forceConsistentCasingInFileNames": true
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"//": "target 不覆盖:与官方一致(deepseek-harness/tsconfig.base.json 是 es2024,client 层只加 lib)。本仓的 client 产物由 rolldown 打,构建脚本里没有 target,也没有读 tsconfig ⇒ 这里的 target 只影响类型面,不影响产物语法。旧基线把它钉在 ES2020 是继承来的写法,实测无产物后果,只把 Promise.withResolvers 一类 ES2024 API 判成 TS2550,逼出包级 lint 例外。",
|
|
3
|
+
"extends": "./tsconfig.base.json",
|
|
4
|
+
"compilerOptions": {
|
|
5
|
+
"module": "ESNext",
|
|
6
|
+
"moduleResolution": "Bundler",
|
|
7
|
+
"lib": ["ES2024", "DOM", "DOM.Iterable", "ESNext.Disposable"],
|
|
8
|
+
"types": []
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// shared/config/vitest.base.ts —— 13 个包的 vitest 配置单源。
|
|
2
|
+
//
|
|
3
|
+
// 为什么从"每包一份零 import 的 `.mjs` 纯对象"换成"TS + 共享基模块":老 README 给出的理由是
|
|
4
|
+
// "vitest 会把配置复制到 `node_modules/.vite-temp/` 再加载,从那里解析 `vitest` 会被 node_modules
|
|
5
|
+
// 边界截断"。在 vitest 5.0.2 上实测三条,全部与该理由相反:
|
|
6
|
+
// ① `.mjs` 配置里 `import { defineConfig } from "vitest/config"` ⇒ 通过;
|
|
7
|
+
// ② 配置改名 `.ts` 并同样 import ⇒ 通过;
|
|
8
|
+
// ③ 两次运行后 `plugins/node_modules/.vite-temp/` 与 `shared/node_modules/.vite-temp/` 都是空目录
|
|
9
|
+
// (复制路径没有被触发)。
|
|
10
|
+
// 也就是说那是 rolldown-vite 早期版本的行为,在 5.0.2 + Vite 8.3.1 上已经不成立。TS 形态的净收益:
|
|
11
|
+
// 判据能写理由、能被 `defineConfig` 的类型检查、能把 13 份重复的公共面收成一份(owner 口径:
|
|
12
|
+
// 能用 TS 就不用其他格式)。各包配置从此只留**自己的差异**:覆盖率 `include` 的面。
|
|
13
|
+
//
|
|
14
|
+
// 阈值不在这里放宽:四项 100% 是每包都生效的默认,任何包要例外必须在自己的配置里写明理由。
|
|
15
|
+
|
|
16
|
+
import { defineConfig } from "vitest/config";
|
|
17
|
+
import type { ViteUserConfig } from "vitest/config";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 类型名按实测取(四轮才钉准,过程记在这里免得下次再猜):
|
|
21
|
+
* - `import type { UserConfig } from "vitest/config"` ⇒ TS2305,5.0.2 不导出这个名字;
|
|
22
|
+
* - `import type { UserConfig as ViteUserConfig }` 同样 TS2305 —— 它在 `vitest/config` 里的
|
|
23
|
+
* **导出名就已经是 `ViteUserConfig`**(源上是 `export { UserConfig as ViteUserConfig } from 'vite'`),
|
|
24
|
+
* 别名要写在被导入的那一侧,不能自己再造一遍;
|
|
25
|
+
* - `Parameters<typeof defineConfig>[0]` ⇒ 合出来是重载联合 `ViteUserConfigExport`(函数类型),
|
|
26
|
+
* 取 `.test` 直接 TS2339,并级联两条 `no-unsafe-*`;
|
|
27
|
+
* - `TestUserConfig` 是 **test 块本身**的类型,不是配置文件对象类型,
|
|
28
|
+
* 拿它当返回值会在 `exactOptionalPropertyTypes: true` 下报 TS2375。
|
|
29
|
+
* 正确的那个是 `ViteUserConfig`:vitest 用模块声明合并给它加了 `test?: VitestInlineConfig`,
|
|
30
|
+
* 也正是 `defineConfig(config: UserConfig): UserConfig` 那条重载吃的形状。
|
|
31
|
+
*/
|
|
32
|
+
type PackageConfig = ViteUserConfig;
|
|
33
|
+
|
|
34
|
+
/** 覆盖率面与 test 块里真正因包而异的那一项。 */
|
|
35
|
+
export interface PackageVitestOptions {
|
|
36
|
+
/** `coverage.include` —— 本包该被统计的源文件(各包只有这里不同)。 */
|
|
37
|
+
coverageInclude: string[];
|
|
38
|
+
/** 追加/覆盖 test 字段(少用;出现即应在包内配置里写明为什么)。 */
|
|
39
|
+
test?: PackageConfig["test"];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* 公共面:13 份配置里逐字相同的那部分,从今往后才真的只有一处。
|
|
44
|
+
* `testTimeout: 20_000` 是 12 个包的共同值(vitest 默认 5000),shared 原先没写、
|
|
45
|
+
* 现在继承这个值只会放宽不会收紧,故不会把任何已过用例变成不稳定。
|
|
46
|
+
*/
|
|
47
|
+
export function definePackageConfig(options: PackageVitestOptions): PackageConfig {
|
|
48
|
+
const { coverageInclude, test } = options;
|
|
49
|
+
return defineConfig({
|
|
50
|
+
test: {
|
|
51
|
+
include: ["test/**/*.test.ts"],
|
|
52
|
+
environment: "node",
|
|
53
|
+
testTimeout: 20_000,
|
|
54
|
+
coverage: {
|
|
55
|
+
provider: "v8",
|
|
56
|
+
include: coverageInclude,
|
|
57
|
+
exclude: [
|
|
58
|
+
"test/**",
|
|
59
|
+
"node_modules/**",
|
|
60
|
+
"build-client*",
|
|
61
|
+
"client.js",
|
|
62
|
+
"agents/**",
|
|
63
|
+
"scripts/**",
|
|
64
|
+
"**/*.d.mts",
|
|
65
|
+
],
|
|
66
|
+
reporter: ["text", "json-summary", "json"],
|
|
67
|
+
reportsDirectory: "coverage",
|
|
68
|
+
thresholds: {
|
|
69
|
+
lines: 100,
|
|
70
|
+
statements: 100,
|
|
71
|
+
functions: 100,
|
|
72
|
+
branches: 100,
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
...test,
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
//#region lib/canonicalize-region-paths.ts
|
|
2
|
+
/** rolldown 模块标记的前缀。`//#endregion` 与代码里的任何其它行都不在本函数的射程内。 */
|
|
3
|
+
const REGION_MARK = "//#region ";
|
|
4
|
+
/** 路径行首的相对段(`./` 与 `../` 的任意串),收掉后跨包依赖在两处 cwd 下才同形。 */
|
|
5
|
+
const LEADING_RELATIVE_SEGMENTS = /^(?:\.\.?\/)+/u;
|
|
6
|
+
/**
|
|
7
|
+
* 取路径的末段。分隔符两头认:产物里的模块路径由 rolldown 写成 `/`,
|
|
8
|
+
* 而 `import.meta.dirname` 在 Windows 上是 `\`。
|
|
9
|
+
* @param dir - 目录路径
|
|
10
|
+
* @returns 末段;只剩分隔符时为空串
|
|
11
|
+
*/
|
|
12
|
+
function lastSegment(dir) {
|
|
13
|
+
const trimmed = dir.replace(/[/\\]+$/u, "");
|
|
14
|
+
const index = Math.max(trimmed.lastIndexOf("/"), trimmed.lastIndexOf("\\"));
|
|
15
|
+
return index === -1 ? trimmed : trimmed.slice(index + 1);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* 行首可被收掉的两枚锚点段:包根的父目录名(DSH_HOME 当 cwd 时多出来那一段)与包名。
|
|
19
|
+
* @param pkgDir - 包根路径(调用方的 import.meta.dirname)
|
|
20
|
+
* @returns 按序待收的段名;空串(pkgDir 只剩分隔符、或压根没有父目录)已剔除
|
|
21
|
+
*/
|
|
22
|
+
function leadingAnchors(pkgDir) {
|
|
23
|
+
const pkgName = lastSegment(pkgDir);
|
|
24
|
+
return [lastSegment(pkgDir.slice(0, pkgDir.length - pkgName.length)), pkgName].filter((anchor) => anchor.length > 0);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* 依次收掉行首的锚点段(每枚最多一次,且只在整段命中时收)。
|
|
28
|
+
* @param path - 已收掉行首相对段的模块路径
|
|
29
|
+
* @param anchors - 见 {@link leadingAnchors}
|
|
30
|
+
* @returns 相对包根的形状;没有命中时段不变
|
|
31
|
+
*/
|
|
32
|
+
function stripLeadingAnchor(path, anchors) {
|
|
33
|
+
let rest = path;
|
|
34
|
+
for (const anchor of anchors) if (rest.startsWith(`${anchor}/`)) rest = rest.slice(anchor.length + 1);
|
|
35
|
+
return rest;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 折单行:命中 `//#region ` 前缀才动刀,且只动该行之后的那段路径文本。
|
|
39
|
+
* 代码中间的字符串(哪怕原样写着 `//#region foo/`)不在射程内——判据是整行行首。
|
|
40
|
+
* @param line - 产物里的一行
|
|
41
|
+
* @param anchors - 见 {@link leadingAnchors}
|
|
42
|
+
* @returns canonical 形态的那一行
|
|
43
|
+
*/
|
|
44
|
+
function canonicalizeLine(line, anchors) {
|
|
45
|
+
if (line.startsWith(REGION_MARK)) {
|
|
46
|
+
const folded = line.slice(10).replace(LEADING_RELATIVE_SEGMENTS, "");
|
|
47
|
+
return `${REGION_MARK}${stripLeadingAnchor(folded, anchors)}`;
|
|
48
|
+
}
|
|
49
|
+
return line;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* 产物文本的 canonical 形态:所有 `//#region` 行折成相对包根的形状,其余字节原样保留。
|
|
53
|
+
* @param code - builder 拿到的产物文本
|
|
54
|
+
* @param pkgDir - 包根绝对路径(builder 的 import.meta.dirname)
|
|
55
|
+
* @returns 与 process.cwd() 无关的同一份文本;对 canonical 输入幂等
|
|
56
|
+
*/
|
|
57
|
+
function canonicalizeRegionPaths(code, pkgDir) {
|
|
58
|
+
const anchors = leadingAnchors(pkgDir);
|
|
59
|
+
if (anchors.length === 0) return code;
|
|
60
|
+
return code.split("\n").map((line) => canonicalizeLine(line, anchors)).join("\n");
|
|
61
|
+
}
|
|
62
|
+
//#endregion
|
|
63
|
+
export { canonicalizeRegionPaths };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//#region lib/card-apply.ts
|
|
2
|
+
/**
|
|
3
|
+
* apply 幂等守卫:已 claim 返回 false(调用方直接 return),否则占位并
|
|
4
|
+
* 挂 ctx.effect 清理——HMR 重载时 flag 复位,再次 apply 可重新声明。
|
|
5
|
+
* @param ctx - apply 的 ctx(需要 effect)。
|
|
6
|
+
* @param flag - globalThis 上的布尔标记键名(如 "__xxxCardApplied")。
|
|
7
|
+
* @param label - effect 标签(日志/生命周期可观测)。
|
|
8
|
+
* @returns true 表示本次拿到声明权(继续执行),false 表示已被占位。
|
|
9
|
+
*/
|
|
10
|
+
function claimApply(ctx, flag, label) {
|
|
11
|
+
const marker = globalThis;
|
|
12
|
+
if (marker[flag] === true) return false;
|
|
13
|
+
marker[flag] = true;
|
|
14
|
+
ctx.effect(() => () => {
|
|
15
|
+
marker[flag] = void 0;
|
|
16
|
+
}, label);
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
export { claimApply };
|