dsh-advisor 0.1.0 → 0.1.1
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.i18n.yaml +2 -2
- package/README.md +11 -14
- package/README.zh.md +6 -6
- package/lib/client.js +2 -2
- package/lib/config.d.ts +1 -1
- package/lib/config.js +1 -1
- package/lib/config.js.map +1 -1
- package/package.json +6 -3
- package/scripts/prepare-release.mjs +190 -0
package/README.i18n.yaml
CHANGED
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
# editing either side, bring the other along and re-record with:
|
|
4
4
|
# git hash-object README.md
|
|
5
5
|
# git hash-object README.zh.md
|
|
6
|
-
README.md:
|
|
7
|
-
README.zh.md:
|
|
6
|
+
README.md: c0096d75da8f4c6e528b24a5bf3cdce6722f0358
|
|
7
|
+
README.zh.md: 6b7c4425bb81764d4bc47a6dc417b7e352fc3769
|
package/README.md
CHANGED
|
@@ -13,10 +13,10 @@ model are required), and injects severity-ranked advice (nit / concern /
|
|
|
13
13
|
blocker) back into the session — without polluting or recursively reviewing
|
|
14
14
|
itself.
|
|
15
15
|
|
|
16
|
-
Install with a single command
|
|
16
|
+
Install with a single command:
|
|
17
17
|
|
|
18
18
|
```sh
|
|
19
|
-
dsh plugin --profile web add
|
|
19
|
+
dsh plugin --profile web add dsh-advisor # <name> = your profile name
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
**Advisory only.** The advisor never approves or rejects the primary agent's
|
|
@@ -27,21 +27,18 @@ policy) so it can never stall or pollute the primary loop.
|
|
|
27
27
|
|
|
28
28
|
## Install
|
|
29
29
|
|
|
30
|
-
### One-line
|
|
30
|
+
### One-line registry install
|
|
31
31
|
|
|
32
32
|
```sh
|
|
33
|
-
dsh plugin --profile web add
|
|
33
|
+
dsh plugin --profile web add dsh-advisor # <name> = your profile name
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
A
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
(`
|
|
42
|
-
approve-builds`), then re-run the `add`. Treat that allowance as permission to
|
|
43
|
-
execute the package's code on your machine at install time, and pin a commit
|
|
44
|
-
(`#<sha>`) so a later push cannot silently change what runs.
|
|
36
|
+
A registry install fetches the published tarball, which ships the built
|
|
37
|
+
artifacts (`lib/` + `cordis.patch.yml`), so no `prepare` build or build
|
|
38
|
+
permission is needed. Runtime dependencies (`@deepseek-ai/cordis`, `@deepseek-ai/schemastery`,
|
|
39
|
+
and the `@deepseek-ai/dsh-*` peers) are declared as peerDependencies and resolve
|
|
40
|
+
through the dsh installation's flat profile module fallback — no extra install
|
|
41
|
+
step. Pin an exact version (`dsh-advisor@0.1.0`) for reproducible installs.
|
|
45
42
|
|
|
46
43
|
### Local directory install (recommended for development / verification)
|
|
47
44
|
|
|
@@ -280,7 +277,7 @@ bin-less cordis shim at `node_modules/@deepseek-ai/cordis` answers the scoped
|
|
|
280
277
|
name and resolves to the vendored files, because the real packages type and
|
|
281
278
|
run against the vendored build and module identity requires dev-time
|
|
282
279
|
`import '@deepseek-ai/cordis'` to resolve to the same files. The public
|
|
283
|
-
devDependencies (
|
|
280
|
+
devDependencies (`@deepseek-ai/schemastery`, `react`, …) resolve from the npm registry as
|
|
284
281
|
usual.
|
|
285
282
|
|
|
286
283
|
`prepack` runs `pnpm build`; `prepare` runs the link farm and the build, so
|
package/README.zh.md
CHANGED
|
@@ -8,23 +8,23 @@
|
|
|
8
8
|
|
|
9
9
|
一个移植 omp「advisor」子系统的独立 dsh 插件组合包:一个按会话运行的评审模型,观察主会话 transcript,用显式配置的模型(provider 与 model 均为必填)评审每个已完成的 stepped turn,并把按严重度排序的建议(nit / concern / blocker)注入回会话 —— 不污染主循环,也不递归地评审自己。
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
一条命令即可安装:
|
|
12
12
|
|
|
13
13
|
```sh
|
|
14
|
-
dsh plugin --profile web add
|
|
14
|
+
dsh plugin --profile web add dsh-advisor # <name> = 你的 profile 名
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
**仅作建议。** advisor 从不批准或否决主 agent 的动作,也绝不会像主 agent 那样发出命令。每条送达的消息都是自我描述的 advisory 内容;一个行为异常的评审者会被端到端约束(emission guard、immuneTurns 冷却、failure policy),因此它永远不会卡住或污染主循环。
|
|
18
18
|
|
|
19
19
|
## 安装
|
|
20
20
|
|
|
21
|
-
### 一条命令的
|
|
21
|
+
### 一条命令的 registry 安装
|
|
22
22
|
|
|
23
23
|
```sh
|
|
24
|
-
dsh plugin --profile web add
|
|
24
|
+
dsh plugin --profile web add dsh-advisor # <name> = 你的 profile 名
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
registry 安装拉取的是已发布的 tarball,其中自带构建产物(`lib/` + `cordis.patch.yml`),因此不会运行 `prepare` 构建,也无需构建放行。运行时依赖(`@deepseek-ai/cordis`、`@deepseek-ai/schemastery` 与 `@deepseek-ai/dsh-*` peers)声明为 peerDependencies,由 dsh 安装的扁平 profile module fallback 解析——无需额外安装步骤。需要可复现安装时用 `dsh-advisor@0.1.0` 钉住精确版本。
|
|
28
28
|
|
|
29
29
|
### 本地目录安装(推荐用于开发 / 验证)
|
|
30
30
|
|
|
@@ -149,7 +149,7 @@ pnpm pack # build + produce dsh-advisor-0.0.1.tgz
|
|
|
149
149
|
|
|
150
150
|
Windows 上链接农场的目录条目以 junction 创建(无需特权),但 cordis shim 的文件条目使用文件符号链接,需要开启[开发者模式](https://learn.microsoft.com/windows/apps/get-started/enable-your-device-for-development)(或以管理员 shell 运行)——请先开启再执行 `pnpm install`。Windows 没有 `HOME`,脚本回退到 `USERPROFILE` 解析 dsh 源码树。
|
|
151
151
|
|
|
152
|
-
内置 `cordis` 框架声明为 scoped peer `@deepseek-ai/cordis: ^4.0.1-rc.1`(范围必须带精确的发布 tag —— 带 prerelease 的 comparator 只匹配同 `[major, minor, patch]` tuple,`^4.0.0-rc.7` 永远不匹配 vendored 的 `4.0.1-rc.1`);安装后链接农场的无 bin cordis shim 位于 `node_modules/@deepseek-ai/cordis`,以 scoped 名应答并解析到 vendored 文件,因为真实包是对着 vendored 构建类型化/运行的,模块身份要求开发期的 `import '@deepseek-ai/cordis'` 解析到同一份文件。其余公开 devDependencies
|
|
152
|
+
内置 `cordis` 框架声明为 scoped peer `@deepseek-ai/cordis: ^4.0.1-rc.1`(范围必须带精确的发布 tag —— 带 prerelease 的 comparator 只匹配同 `[major, minor, patch]` tuple,`^4.0.0-rc.7` 永远不匹配 vendored 的 `4.0.1-rc.1`);安装后链接农场的无 bin cordis shim 位于 `node_modules/@deepseek-ai/cordis`,以 scoped 名应答并解析到 vendored 文件,因为真实包是对着 vendored 构建类型化/运行的,模块身份要求开发期的 `import '@deepseek-ai/cordis'` 解析到同一份文件。其余公开 devDependencies(`@deepseek-ai/schemastery`、`react` 等)照常从 npm registry 解析。
|
|
153
153
|
|
|
154
154
|
`prepack` 运行 `pnpm build`;`prepare` 运行链接农场与构建,因此 `pnpm pack` 会构建两次(每个生命周期一次)——这是为保持 git 安装可构建而接受的取舍。没有 `postinstall` 步骤:tarball 安装已带构建产物,完全跳过构建。
|
|
155
155
|
|
package/lib/client.js
CHANGED
|
@@ -35,7 +35,7 @@ var import_dsh_client_web_react = require("@deepseek-ai/dsh-client-web-react");
|
|
|
35
35
|
var import_react = require("react");
|
|
36
36
|
var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
37
37
|
|
|
38
|
-
var css = `.
|
|
38
|
+
var css = `.kPHV8a_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}.kPHV8a_card:hover{border-color:var(--dsw-alias-label-dimmed)}.kPHV8a_cardOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}.kPHV8a_header{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.kPHV8a_header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.kPHV8a_headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.kPHV8a_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.kPHV8a_description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.kPHV8a_chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.kPHV8a_chevronOpen{transform:rotate(180deg)}.kPHV8a_body{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}.kPHV8a_readOnly{color:var(--dsw-alias-label-tertiary);margin:12px 0 0;font-size:12px;line-height:1.5}.kPHV8a_pending{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.kPHV8a_footer{border-top:1px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}.kPHV8a_failed{min-width:0;color:var(--dsw-alias-label-error);flex:1;margin:0;font-size:12px;line-height:1.5}.kPHV8a_discard,.kPHV8a_save{appearance:none;font:inherit;cursor:pointer;border:1px solid #0000;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.kPHV8a_discard{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0}.kPHV8a_discard:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.kPHV8a_save{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}.kPHV8a_discard:disabled,.kPHV8a_save:disabled{opacity:.4;cursor:default}.kPHV8a_discard:focus-visible,.kPHV8a_save:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.kPHV8a_notice{color:var(--dsw-alias-state-warn-label);margin:12px 0 0;font-size:12px;line-height:18px}.kPHV8a_savedNotice{color:var(--dsw-alias-state-success-primary);margin:12px 0 0;font-size:12px;line-height:18px}.kPHV8a_error{color:var(--dsw-alias-state-error-primary);margin:12px 0 0;font-size:12px;line-height:18px}.kPHV8a_form{flex-direction:column;gap:12px;padding:12px 0 0;display:flex}.kPHV8a_checkboxRow{align-items:center;gap:8px;display:flex}.kPHV8a_checkLabel{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px}.kPHV8a_checkbox{width:16px;height:16px;accent-color:var(--dsw-alias-brand-primary);cursor:pointer;margin:0}.kPHV8a_checkbox:disabled{opacity:.4;cursor:default}.kPHV8a_checkbox:focus-visible{outline:2px solid var(--dsw-alias-border-l3);outline-offset:2px}.kPHV8a_fieldset{border:none;flex-direction:column;gap:12px;margin:0;padding:0;display:flex}.kPHV8a_field{flex-direction:column;gap:6px;display:flex}.kPHV8a_fieldLabel{color:var(--dsw-alias-label-secondary);align-items:center;gap:10px;font-size:12px;font-weight:500;line-height:18px;display:inline-flex}.kPHV8a_input{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);width:100%;height:32px;font:inherit;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 10px;font-size:14px;line-height:22px}select.kPHV8a_input{cursor:pointer;max-width:240px}.kPHV8a_input:focus{border-color:var(--dsw-alias-brand-primary);outline:none}.kPHV8a_input::placeholder{color:var(--dsw-alias-label-dimmed)}.kPHV8a_input:disabled{opacity:.6;cursor:default}.kPHV8a_selectInput{appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M3 4.5L6 7.5L9 4.5' stroke='%2381858C' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");background-position:right 12px center;background-repeat:no-repeat;background-size:12px 12px;padding-right:32px}.kPHV8a_textarea{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);width:100%;min-height:96px;font:inherit;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);resize:vertical;border-radius:8px;padding:8px 10px;font-size:14px;line-height:22px}.kPHV8a_textarea:focus{border-color:var(--dsw-alias-brand-primary);outline:none}.kPHV8a_textarea:disabled{opacity:.6;cursor:default}.kPHV8a_numberFields{grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:12px;display:grid}.kPHV8a_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.kPHV8a_warnHint{color:var(--dsw-alias-state-warn-label);margin:0;font-size:12px;line-height:18px}`;
|
|
39
39
|
var tagId = "dsh-advisor/advisor-card.module.css";
|
|
40
40
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
41
41
|
const tag = document.createElement("style");
|
|
@@ -44,7 +44,7 @@ if (typeof document !== "undefined" && document.querySelector("style[data-plugin
|
|
|
44
44
|
tag.textContent = css;
|
|
45
45
|
document.head.appendChild(tag);
|
|
46
46
|
}
|
|
47
|
-
var advisor_card_module_css_default = { "body": "
|
|
47
|
+
var advisor_card_module_css_default = { "body": "kPHV8a_body", "card": "kPHV8a_card", "cardOpen": "kPHV8a_cardOpen", "checkLabel": "kPHV8a_checkLabel", "checkbox": "kPHV8a_checkbox", "checkboxRow": "kPHV8a_checkboxRow", "chevron": "kPHV8a_chevron", "chevronOpen": "kPHV8a_chevronOpen", "description": "kPHV8a_description", "discard": "kPHV8a_discard", "error": "kPHV8a_error", "failed": "kPHV8a_failed", "field": "kPHV8a_field", "fieldLabel": "kPHV8a_fieldLabel", "fieldset": "kPHV8a_fieldset", "footer": "kPHV8a_footer", "form": "kPHV8a_form", "headText": "kPHV8a_headText", "header": "kPHV8a_header", "hint": "kPHV8a_hint", "input": "kPHV8a_input", "name": "kPHV8a_name", "notice": "kPHV8a_notice", "numberFields": "kPHV8a_numberFields", "pending": "kPHV8a_pending", "readOnly": "kPHV8a_readOnly", "save": "kPHV8a_save", "savedNotice": "kPHV8a_savedNotice", "selectInput": "kPHV8a_selectInput", "textarea": "kPHV8a_textarea", "warnHint": "kPHV8a_warnHint" };
|
|
48
48
|
|
|
49
49
|
// src/client/advisor-card.tsx
|
|
50
50
|
var import_jsx_runtime = require("react/jsx-runtime");
|
package/lib/config.d.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*
|
|
12
12
|
* @module dsh-advisor/config
|
|
13
13
|
*/
|
|
14
|
-
import z from 'schemastery';
|
|
14
|
+
import z from '@deepseek-ai/schemastery';
|
|
15
15
|
/** Raw plugin row config after Loader defaults — spec §5.1. */
|
|
16
16
|
export interface AdvisorConfig {
|
|
17
17
|
/** Master switch; default false. */
|
package/lib/config.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*
|
|
12
12
|
* @module dsh-advisor/config
|
|
13
13
|
*/
|
|
14
|
-
import z from 'schemastery';
|
|
14
|
+
import z from '@deepseek-ai/schemastery';
|
|
15
15
|
/**
|
|
16
16
|
* Complete configuration key set for strict unknown-key rejection. The
|
|
17
17
|
* schemastery object resolver merges unknown keys by default (strict flag is
|
package/lib/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,CAAC,MAAM,0BAA0B,CAAA;AA8BxC;;;;;GAKG;AACH,MAAM,WAAW,GAAwB,IAAI,GAAG,CAAC;IAC/C,SAAS;IACT,UAAU;IACV,OAAO;IACP,cAAc;IACd,aAAa;IACb,kBAAkB;CACnB,CAAC,CAAA;AAEF;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7B,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;IACnC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;IACpB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IACpC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IACjD,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;CACxD,CAAC,CAAA;AAEF,SAAS,gBAAgB,CAAC,KAAyB;IACjD,2EAA2E;IAC3E,2EAA2E;IAC3E,kEAAkE;IAClE,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAA;AAC7D,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAY;IAC/C,IAAI,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAClE,MAAM,IAAI,SAAS,CAAC,mDAAmD,CAAC,CAAA;IAC1E,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACnC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,oCAAoC,GAAG,GAAG,CAAC,CAAA;QAC7D,CAAC;IACH,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAA;IAC1B,wEAAwE;IACxE,yEAAyE;IACzE,yDAAyD;IACzD,MAAM,UAAU,GAAkB;QAChC,GAAG,MAAM;QACT,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,SAAS;QACtC,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,SAAS;KACjC,CAAA;IACD,IAAI,CAAC,UAAU,CAAC,OAAO;QAAE,OAAO,UAAU,CAAA;IAC1C,MAAM,OAAO,GAAa,EAAE,CAAA;IAC5B,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;IACpE,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,KAAK,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAC9D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,UAAU,CAAA;IAC3C,MAAM,cAAc,GAAG,OAAO,CAAC,MAAM,KAAK,CAAC;QACzC,CAAC,CAAC,mFAAmF;QACrF,CAAC,CAAC,eAAe,OAAO,CAAC,CAAC,CAAC,qDAAqD,CAAA;IAClF,OAAO,EAAE,GAAG,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,CAAA;AAC1D,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-advisor",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "dsh plugin bundle porting the omp advisor subsystem: a per-session reviewer model that observes the primary transcript and injects severity-ranked advice (nit/concern/blocker).",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/omdsh-dev/dsh-advisor"
|
|
9
|
+
},
|
|
6
10
|
"keywords": [
|
|
7
11
|
"dsh",
|
|
8
12
|
"dsh-plugin"
|
|
@@ -66,7 +70,7 @@
|
|
|
66
70
|
"@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.6",
|
|
67
71
|
"@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.6",
|
|
68
72
|
"react": "^18.2.0",
|
|
69
|
-
"schemastery": "^3.18.
|
|
73
|
+
"@deepseek-ai/schemastery": "^3.18.1"
|
|
70
74
|
},
|
|
71
75
|
"devDependencies": {
|
|
72
76
|
"@testing-library/dom": "^10.4.1",
|
|
@@ -79,7 +83,6 @@
|
|
|
79
83
|
"lightningcss": "^1.33.0",
|
|
80
84
|
"react": "^18.3.1",
|
|
81
85
|
"react-dom": "^18.3.1",
|
|
82
|
-
"schemastery": "^3.18.0",
|
|
83
86
|
"typescript": "^5.6.0",
|
|
84
87
|
"vitest": "^3.0.0"
|
|
85
88
|
},
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Release-prep version helper (plan dsh-advisor-ci-release, task 2 + 4):
|
|
4
|
+
* resolves the target version — explicit `X.Y.Z` / `X.Y.Z-prerelease`
|
|
5
|
+
* argument (e.g. 0.1.1-alpha.1) or an auto patch bump from package.json —
|
|
6
|
+
* refuses already-released versions (existing `v<version>` git tag), bumps
|
|
7
|
+
* package.json, inserts the `## [<version>]` section into CHANGELOG.md (from
|
|
8
|
+
* the same git-log notes the workflows use; keeps existing sections, no-op
|
|
9
|
+
* when already present), and prints `VERSION=<version>` for the workflow to
|
|
10
|
+
* capture. Node built-ins only, no new dependencies.
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* node scripts/prepare-release.mjs # auto patch bump
|
|
14
|
+
* node scripts/prepare-release.mjs 0.2.0 # explicit version
|
|
15
|
+
* node scripts/prepare-release.mjs 0.1.1-alpha.1 # explicit prerelease
|
|
16
|
+
*
|
|
17
|
+
* Exit codes: 0 = bumped and printed VERSION; 1 = rejected (unparseable
|
|
18
|
+
* version, existing tag, unparseable current package.json version, or
|
|
19
|
+
* CHANGELOG.md write error).
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { execFileSync } from 'node:child_process'
|
|
23
|
+
import { readFileSync, writeFileSync } from 'node:fs'
|
|
24
|
+
import { dirname, join } from 'node:path'
|
|
25
|
+
import { fileURLToPath } from 'node:url'
|
|
26
|
+
|
|
27
|
+
const REPO_ROOT = join(dirname(fileURLToPath(import.meta.url)), '..')
|
|
28
|
+
const PKG_PATH = join(REPO_ROOT, 'package.json')
|
|
29
|
+
const CHANGELOG_PATH = join(REPO_ROOT, 'CHANGELOG.md')
|
|
30
|
+
const CHANGELOG_HEADER =
|
|
31
|
+
'# Changelog\n\nAll notable changes to dsh-advisor are documented here. Generated from git log by the release-prep workflow.\n'
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Parse X.Y.Z or X.Y.Z[-prerelease] (numeric parts; optional prerelease
|
|
35
|
+
* suffix); null when not parseable. The suffix character set matches the
|
|
36
|
+
* workflows' guard regex `[0-9A-Za-z.-]+` (keep-simple: no leading-zero or
|
|
37
|
+
* empty-identifier rules), with one tightening: the suffix MUST contain at
|
|
38
|
+
* least one digit, so `0.1.1-alpha.1` / `0.1.1-rc.2` parse but `0.1.1-alpha`
|
|
39
|
+
* (no numeric identifier) and `0.1.1-` (empty suffix) are rejected. Returns
|
|
40
|
+
* { major, minor, patch, prerelease? } — prerelease is the raw suffix text
|
|
41
|
+
* (e.g. 'alpha.1') when present, undefined for formal versions.
|
|
42
|
+
*/
|
|
43
|
+
function parseVersion(value) {
|
|
44
|
+
const match = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]*[0-9][0-9A-Za-z.-]*))?$/.exec(value)
|
|
45
|
+
if (!match) return null
|
|
46
|
+
return {
|
|
47
|
+
major: Number(match[1]),
|
|
48
|
+
minor: Number(match[2]),
|
|
49
|
+
patch: Number(match[3]),
|
|
50
|
+
prerelease: match[4] === undefined ? undefined : match[4],
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const pkg = JSON.parse(readFileSync(PKG_PATH, 'utf8'))
|
|
55
|
+
|
|
56
|
+
let target
|
|
57
|
+
if (process.argv[2] !== undefined) {
|
|
58
|
+
target = parseVersion(process.argv[2])
|
|
59
|
+
if (target === null) {
|
|
60
|
+
console.error(`Error: invalid version "${process.argv[2]}". Expected X.Y.Z or X.Y.Z-prerelease (e.g. 0.2.0, 0.1.1-alpha.1).`)
|
|
61
|
+
process.exit(1)
|
|
62
|
+
}
|
|
63
|
+
} else {
|
|
64
|
+
const current = parseVersion(pkg.version)
|
|
65
|
+
if (current === null) {
|
|
66
|
+
console.error(`Error: cannot parse current package.json version "${pkg.version}".`)
|
|
67
|
+
process.exit(1)
|
|
68
|
+
}
|
|
69
|
+
// Auto patch bump: bump the numeric patch part and DROP any prerelease
|
|
70
|
+
// suffix (a prerelease base 0.1.1-alpha.1 with no explicit arg -> 0.1.2,
|
|
71
|
+
// i.e. the next formal patch after the 0.1.1 line). An explicit prerelease
|
|
72
|
+
// argument is the way to prepare another prerelease (e.g. 0.1.1-alpha.2).
|
|
73
|
+
target = { major: current.major, minor: current.minor, patch: current.patch + 1 }
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const version =
|
|
77
|
+
target.prerelease === undefined
|
|
78
|
+
? `${target.major}.${target.minor}.${target.patch}`
|
|
79
|
+
: `${target.major}.${target.minor}.${target.patch}-${target.prerelease}`
|
|
80
|
+
|
|
81
|
+
// Reject already-released versions: `git rev-parse v<version>` succeeds iff
|
|
82
|
+
// the tag exists. Works unchanged for prerelease tags (v0.1.1-alpha.1 is a
|
|
83
|
+
// plain tag name). Run from REPO_ROOT so the check is cwd-independent.
|
|
84
|
+
try {
|
|
85
|
+
execFileSync('git', ['rev-parse', `v${version}`], { cwd: REPO_ROOT, stdio: 'ignore' })
|
|
86
|
+
console.error(`Error: tag v${version} already exists — this version is already released.`)
|
|
87
|
+
process.exit(1)
|
|
88
|
+
} catch {
|
|
89
|
+
// Tag absent → OK to prepare.
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
pkg.version = version
|
|
93
|
+
// Preserve repo formatting: 2-space indent + trailing newline. The version
|
|
94
|
+
// line must be the only diff (verified by `git diff package.json` in the
|
|
95
|
+
// dry-run validation).
|
|
96
|
+
writeFileSync(PKG_PATH, `${JSON.stringify(pkg, null, 2)}\n`, 'utf8')
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Release notes since the previous release: first-parent commit subjects
|
|
100
|
+
* between the nearest ancestor tag of HEAD and HEAD. Same snippet the
|
|
101
|
+
* workflows use for the PR body — the CHANGELOG section and the PR body
|
|
102
|
+
* stay consistent. When no ancestor tag exists yet, the notes span the full
|
|
103
|
+
* first-parent history. Do NOT use "v$VERSION^": the version string is not a
|
|
104
|
+
* git ref — the bump commit is not tagged yet.
|
|
105
|
+
*/
|
|
106
|
+
function collectReleaseNotes() {
|
|
107
|
+
let prevTag = ''
|
|
108
|
+
try {
|
|
109
|
+
prevTag = execFileSync('git', ['describe', '--tags', '--abbrev=0', 'HEAD'], {
|
|
110
|
+
cwd: REPO_ROOT,
|
|
111
|
+
encoding: 'utf8',
|
|
112
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
113
|
+
}).trim()
|
|
114
|
+
} catch {
|
|
115
|
+
// No ancestor tag yet → full history.
|
|
116
|
+
}
|
|
117
|
+
const range = prevTag === '' ? 'HEAD' : `${prevTag}..HEAD`
|
|
118
|
+
return execFileSync('git', ['log', '--oneline', '--first-parent', range], {
|
|
119
|
+
cwd: REPO_ROOT,
|
|
120
|
+
encoding: 'utf8',
|
|
121
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
122
|
+
}).trim()
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Insert a `## [<version>] - <YYYY-MM-DD>` section under the `# Changelog`
|
|
127
|
+
* header, above the existing sections, from the same git-log notes the
|
|
128
|
+
* workflows use. Preserves all existing sections; no-op when the section for
|
|
129
|
+
* this version already exists (idempotent re-runs must not duplicate it);
|
|
130
|
+
* write failures exit 1.
|
|
131
|
+
*/
|
|
132
|
+
function updateChangelog(version) {
|
|
133
|
+
let content
|
|
134
|
+
try {
|
|
135
|
+
content = readFileSync(CHANGELOG_PATH, 'utf8')
|
|
136
|
+
} catch {
|
|
137
|
+
content = CHANGELOG_HEADER
|
|
138
|
+
}
|
|
139
|
+
// A 0-byte CHANGELOG.md (e.g. manual truncation) is treated as missing:
|
|
140
|
+
// an empty file must still bootstrap with the standard header, otherwise
|
|
141
|
+
// the new section would land at the top with leading blank lines and no
|
|
142
|
+
// `# Changelog` header.
|
|
143
|
+
if (content === '') {
|
|
144
|
+
content = CHANGELOG_HEADER
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (content.includes(`## [${version}]`)) {
|
|
148
|
+
return
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const notes = collectReleaseNotes()
|
|
152
|
+
const sectionHeader = `## [${version}] - ${new Date().toISOString().slice(0, 10)}`
|
|
153
|
+
const sectionBody =
|
|
154
|
+
notes === ''
|
|
155
|
+
? 'No commits between releases.'
|
|
156
|
+
: notes
|
|
157
|
+
.split('\n')
|
|
158
|
+
.map((line) => `- ${line}`)
|
|
159
|
+
.join('\n')
|
|
160
|
+
// The section's own trailing `\n` plus the inserted `\n` below form the
|
|
161
|
+
// blank-line separator between the new section and the existing sections.
|
|
162
|
+
const section = `${sectionHeader}\n\n${sectionBody}\n`
|
|
163
|
+
|
|
164
|
+
// Insert on the first `## [` section header via string slice: everything
|
|
165
|
+
// at and below the insertion point — including the file's exact trailing
|
|
166
|
+
// newline — is preserved byte-for-byte. (A split('\n')/splice/join('\n')
|
|
167
|
+
// round-trip would re-normalize line breaks and could alter the tail, e.g.
|
|
168
|
+
// appending a trailing newline that was not in the source file.)
|
|
169
|
+
const firstSectionMatch = /^## \[/m.exec(content)
|
|
170
|
+
const firstSectionIdx = firstSectionMatch === null ? -1 : firstSectionMatch.index
|
|
171
|
+
let next
|
|
172
|
+
if (firstSectionIdx === -1) {
|
|
173
|
+
// No sections yet — append the new section after the header block,
|
|
174
|
+
// keeping the file's own trailing-newline state.
|
|
175
|
+
next = content.endsWith('\n') ? `${content}\n${section}` : `${content}\n\n${section}`
|
|
176
|
+
} else {
|
|
177
|
+
next = `${content.slice(0, firstSectionIdx)}${section}\n${content.slice(firstSectionIdx)}`
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
try {
|
|
181
|
+
writeFileSync(CHANGELOG_PATH, next, 'utf8')
|
|
182
|
+
} catch (error) {
|
|
183
|
+
console.error(`Error: cannot write ${CHANGELOG_PATH}: ${error.message}`)
|
|
184
|
+
process.exit(1)
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
updateChangelog(version)
|
|
189
|
+
|
|
190
|
+
console.log(`VERSION=${version}`)
|