@mstar-harness/dsh 3.0.1 → 3.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/dist/gates/agent-flow.d.ts +8 -0
- package/dist/gates/system-prompt.d.ts +7 -4
- package/dist/index.js +58 -18
- package/dist/types.d.ts +14 -0
- package/harness-skills/mstar-plan-artifacts/references/knowledge-and-designs.md +10 -0
- package/harness-skills/mstar-plan-conventions/references/artifact-storage-paths.md +1 -0
- package/harness-skills/mstar-project-governance/SKILL.md +1 -0
- package/package.json +1 -1
|
@@ -514,6 +514,14 @@ export declare function recordWorkflowVerdict(input: WorkflowVerdictInput): void
|
|
|
514
514
|
* <id>`), never the harness root — the dir parameter IS the workflow dir
|
|
515
515
|
* (the catalog passes `join(harnessDir, selection.dir)`; the writer appends
|
|
516
516
|
* there via `resolveAgentFlowWriteDir`).
|
|
517
|
+
*
|
|
518
|
+
* Large-file reads (plan `20260820-dsh-ledger-tail-read`): ledgers above
|
|
519
|
+
* `AGENT_FLOW_TAIL_READ_THRESHOLD_BYTES` are read as a bounded latest-first
|
|
520
|
+
* tail — seek from EOF, aligned to a line boundary, doubling backward until
|
|
521
|
+
* the window holds `limit` complete lines — so the catalog pays O(window) at
|
|
522
|
+
* the byte layer instead of parsing every historical line. Both paths feed
|
|
523
|
+
* the SAME parse funnel below (`ledgerContent` yields a `content` string),
|
|
524
|
+
* so tail/full parity is structural.
|
|
517
525
|
* @param workflowDir - the workflow dir whose `agent-flow.jsonl` is read.
|
|
518
526
|
* @param limit - explicit window bound: `undefined` → `AGENT_FLOW_DEFAULT_LIMIT`;
|
|
519
527
|
* otherwise `Math.max(0, Math.floor(limit))` — `0` requests the EMPTY window.
|
|
@@ -37,10 +37,13 @@
|
|
|
37
37
|
* re-registration, in zero-config and explicit-config deployments alike.
|
|
38
38
|
* - The context provider reuses the catalog's unified machine-summary
|
|
39
39
|
* source (`buildCatalogSources` — the SAME builder the engine-status
|
|
40
|
-
* pre-step catalog row uses) and projects
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
40
|
+
* pre-step catalog row uses) and projects the SLIM digest (plan
|
|
41
|
+
* `20260820-dsh-engine-status-slim` Task 2): the version watermark
|
|
42
|
+
* ALWAYS, plus ONE `workflow … | plans: …` line only when the active set
|
|
43
|
+
* selects a lifecycle (`state.selection.kind === 'active'`). Harness dir
|
|
44
|
+
* and enforcement live in `mstar:harness-rules`; residuals / leases /
|
|
45
|
+
* direction / iteration-gate detail stay exclusive to the pre-step row.
|
|
46
|
+
* v3 (plan `20260819-workflow-dsh-viz` Task 3): the
|
|
44
47
|
* digest reads ONLY the catalog row (`state` — itself aggregated from the
|
|
45
48
|
* SELECTED workflow snapshot + project registers) — no direct
|
|
46
49
|
* status.json / snapshot file reads to change. The build is TTL-memoized
|
package/dist/index.js
CHANGED
|
@@ -4193,7 +4193,7 @@ import { join as join11 } from "node:path";
|
|
|
4193
4193
|
import { createUserMessage } from "@deepseek-ai/dsh-llm";
|
|
4194
4194
|
|
|
4195
4195
|
// src/gates/agent-flow.ts
|
|
4196
|
-
import { appendFileSync, existsSync as existsSync11, mkdirSync as mkdirSync3, readFileSync as readFileSync7, renameSync as renameSync2, rmdirSync, statSync as statSync5, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
4196
|
+
import { appendFileSync, closeSync, existsSync as existsSync11, mkdirSync as mkdirSync3, openSync, readFileSync as readFileSync7, readSync, renameSync as renameSync2, rmdirSync, statSync as statSync5, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
4197
4197
|
import { join as join10 } from "node:path";
|
|
4198
4198
|
|
|
4199
4199
|
// src/gates/dispatch.ts
|
|
@@ -4812,6 +4812,7 @@ var AGENT_FLOW_FILE = "agent-flow.jsonl";
|
|
|
4812
4812
|
var AGENT_FLOW_MAX_EVENTS = 500;
|
|
4813
4813
|
var AGENT_FLOW_DEFAULT_LIMIT = 50;
|
|
4814
4814
|
var AGENT_FLOW_SIZE_GATE_BYTES = 64 * 1024;
|
|
4815
|
+
var AGENT_FLOW_TAIL_READ_THRESHOLD_BYTES = 64 * 1024;
|
|
4815
4816
|
var WORKFLOW_LEDGER_MAX_ID_LENGTH = 512;
|
|
4816
4817
|
var WORKFLOW_LEDGER_MAX_LABEL_LENGTH = 512;
|
|
4817
4818
|
var WORKFLOW_LEDGER_MAX_NAME_LENGTH = 1024;
|
|
@@ -5296,14 +5297,49 @@ function summaryOf(events) {
|
|
|
5296
5297
|
return { role, outcome, count };
|
|
5297
5298
|
}).sort((a, b) => b.count - a.count || a.role.localeCompare(b.role) || a.outcome.localeCompare(b.outcome));
|
|
5298
5299
|
}
|
|
5300
|
+
function ledgerContent(file, n) {
|
|
5301
|
+
const size = statSync5(file).size;
|
|
5302
|
+
if (size <= AGENT_FLOW_TAIL_READ_THRESHOLD_BYTES) {
|
|
5303
|
+
return readFileSync7(file, "utf8");
|
|
5304
|
+
}
|
|
5305
|
+
let windowBytes = AGENT_FLOW_TAIL_READ_THRESHOLD_BYTES;
|
|
5306
|
+
const fd = openSync(file, "r");
|
|
5307
|
+
try {
|
|
5308
|
+
for (;; ) {
|
|
5309
|
+
const start = Math.max(0, size - windowBytes);
|
|
5310
|
+
const buffer = Buffer.alloc(size - start);
|
|
5311
|
+
let read = 0;
|
|
5312
|
+
while (read < buffer.length) {
|
|
5313
|
+
const got = readSync(fd, buffer, read, buffer.length - read, start + read);
|
|
5314
|
+
if (got === 0)
|
|
5315
|
+
break;
|
|
5316
|
+
read += got;
|
|
5317
|
+
}
|
|
5318
|
+
let content = buffer.toString("utf8");
|
|
5319
|
+
if (start > 0) {
|
|
5320
|
+
const firstNewline = content.indexOf(`
|
|
5321
|
+
`);
|
|
5322
|
+
content = firstNewline >= 0 ? content.slice(firstNewline + 1) : "";
|
|
5323
|
+
}
|
|
5324
|
+
const completeLines = content.split(`
|
|
5325
|
+
`).length - 1;
|
|
5326
|
+
if (start === 0 || completeLines >= n)
|
|
5327
|
+
return content;
|
|
5328
|
+
windowBytes *= 2;
|
|
5329
|
+
}
|
|
5330
|
+
} finally {
|
|
5331
|
+
closeSync(fd);
|
|
5332
|
+
}
|
|
5333
|
+
}
|
|
5299
5334
|
function readAgentFlow(workflowDir, limit) {
|
|
5300
5335
|
const file = join10(workflowDir, AGENT_FLOW_FILE);
|
|
5301
5336
|
if (!existsSync11(file)) {
|
|
5302
5337
|
return { events: [], summary: [] };
|
|
5303
5338
|
}
|
|
5339
|
+
const n = limit === undefined ? AGENT_FLOW_DEFAULT_LIMIT : Math.max(0, Math.floor(limit));
|
|
5304
5340
|
let content;
|
|
5305
5341
|
try {
|
|
5306
|
-
content =
|
|
5342
|
+
content = ledgerContent(file, n);
|
|
5307
5343
|
} catch {
|
|
5308
5344
|
return null;
|
|
5309
5345
|
}
|
|
@@ -5320,7 +5356,6 @@ function readAgentFlow(workflowDir, limit) {
|
|
|
5320
5356
|
continue;
|
|
5321
5357
|
}
|
|
5322
5358
|
}
|
|
5323
|
-
const n = limit === undefined ? AGENT_FLOW_DEFAULT_LIMIT : Math.max(0, Math.floor(limit));
|
|
5324
5359
|
const latestFirst = events.reverse().slice(0, n);
|
|
5325
5360
|
return {
|
|
5326
5361
|
events: latestFirst.map(eventView),
|
|
@@ -5621,6 +5656,8 @@ function harnessStateSource(harnessDir) {
|
|
|
5621
5656
|
const executionPolicy = asRecord(snapshot.execution_policy);
|
|
5622
5657
|
return {
|
|
5623
5658
|
selection,
|
|
5659
|
+
workflowType: str(snapshot.type),
|
|
5660
|
+
workflowStatus: str(snapshot.status),
|
|
5624
5661
|
plans,
|
|
5625
5662
|
residuals,
|
|
5626
5663
|
residualFindings,
|
|
@@ -5643,6 +5680,8 @@ function harnessStateSource(harnessDir) {
|
|
|
5643
5680
|
function selectionErrorState(selection, rollup, harnessDir, compass) {
|
|
5644
5681
|
return {
|
|
5645
5682
|
selection,
|
|
5683
|
+
workflowType: null,
|
|
5684
|
+
workflowStatus: null,
|
|
5646
5685
|
plans: [],
|
|
5647
5686
|
residuals: [],
|
|
5648
5687
|
residualFindings: null,
|
|
@@ -8087,24 +8126,25 @@ function engineStatusProvider(ctx, resolver, bootHarnessDir) {
|
|
|
8087
8126
|
return engineStatusSummary(entry.source);
|
|
8088
8127
|
};
|
|
8089
8128
|
}
|
|
8129
|
+
var DIGEST_PLAN_CAP = 8;
|
|
8130
|
+
function joinCapped(items, cap, separator, render) {
|
|
8131
|
+
const visible = items.slice(0, cap).map(render);
|
|
8132
|
+
if (items.length > cap)
|
|
8133
|
+
visible.push(`+${items.length - cap} more`);
|
|
8134
|
+
return visible.join(separator);
|
|
8135
|
+
}
|
|
8090
8136
|
function engineStatusSummary(source) {
|
|
8091
|
-
const lines = [
|
|
8092
|
-
`mstar engine status: v${source.version} | harness ${stripInterpolationHazard(source.harnessDir ?? "none")} | enforcement ${source.enforcement.hard ? "hard" : "soft"}`
|
|
8093
|
-
];
|
|
8094
|
-
const iteration = source.iteration;
|
|
8095
|
-
if (iteration !== undefined) {
|
|
8096
|
-
const gate2 = iteration.gate;
|
|
8097
|
-
const codes = gate2.violations.map((v) => v.code).join(", ");
|
|
8098
|
-
lines.push(`iteration ${stripInterpolationHazard(iteration.iterationId)}: gate ${gate2.ok ? "PASS" : `FAIL (${codes})`} | transition ${gate2.transition} | all plans done ${gate2.all_plans_done}`);
|
|
8099
|
-
}
|
|
8137
|
+
const lines = [`mstar engine status: v${source.version}`];
|
|
8100
8138
|
const state = source.state;
|
|
8101
8139
|
if (state !== null) {
|
|
8102
|
-
const
|
|
8103
|
-
|
|
8104
|
-
|
|
8105
|
-
|
|
8106
|
-
|
|
8107
|
-
|
|
8140
|
+
const selection = state.selection;
|
|
8141
|
+
if (selection.kind === "active") {
|
|
8142
|
+
const pending = state.plans.filter((p) => p.status !== "Done");
|
|
8143
|
+
const plans = pending.length === 0 ? "none" : joinCapped(pending, DIGEST_PLAN_CAP, " ", (p) => `${stripInterpolationHazard(p.id)}(${stripInterpolationHazard(p.status)})`);
|
|
8144
|
+
const workflowType = stripInterpolationHazard(state.workflowType ?? "unknown");
|
|
8145
|
+
const workflowStatus = stripInterpolationHazard(state.workflowStatus ?? "unknown");
|
|
8146
|
+
lines.push(`workflow ${stripInterpolationHazard(selection.workflowId)} (${workflowType}) ${workflowStatus} | plans: ${plans}`);
|
|
8147
|
+
}
|
|
8108
8148
|
}
|
|
8109
8149
|
return lines.join(`
|
|
8110
8150
|
`);
|
package/dist/types.d.ts
CHANGED
|
@@ -199,6 +199,20 @@ export interface MstarHarnessState {
|
|
|
199
199
|
* read).
|
|
200
200
|
*/
|
|
201
201
|
readonly selection: WorkflowSelectionView;
|
|
202
|
+
/**
|
|
203
|
+
* The selected workflow snapshot's top-level `type` (`plan` / `iteration`),
|
|
204
|
+
* projected loose (`string`) like `HarnessPlanView.status`. ALWAYS-present
|
|
205
|
+
* nullable scalar (lossless JSON, never omitted): missing/empty → `null`;
|
|
206
|
+
* `null` on selection error (no snapshot read). Added for the slim
|
|
207
|
+
* `mstar:engine-status` digest (plan `20260820-dsh-engine-status-slim`).
|
|
208
|
+
*/
|
|
209
|
+
readonly workflowType: string | null;
|
|
210
|
+
/**
|
|
211
|
+
* The selected workflow snapshot's top-level lifecycle `status`
|
|
212
|
+
* (`running` / `paused`; a terminal word for a stale-but-registered entry,
|
|
213
|
+
* decision D3). Same ALWAYS-present nullable discipline as `workflowType`.
|
|
214
|
+
*/
|
|
215
|
+
readonly workflowStatus: string | null;
|
|
202
216
|
/** Registered plan rows (`plan_id`/`id` + `status`), snapshot plans[] order. */
|
|
203
217
|
readonly plans: readonly HarnessPlanView[];
|
|
204
218
|
/** Open `residual_findings` counts by severity (non-zero only). */
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
| **`{SPECS_DIR}`**(可选) | 冻结 v1-spec、ADR、program roadmap — **跨迭代长期权威** | 产品/API 规范性最高权威;**iteration-start** 由 product/architect 主写 |
|
|
16
16
|
| **`{ITERATION_DIR}`**(可选) | **`<iteration-id>/` package**(`delivery-compass.md` + `guides/`、`specs/`) | Agent handoff;迭代级草稿;close 时 compound **提升** → knowledge |
|
|
17
17
|
| **`{KNOWLEDGE_DIR}`**(可选) | 实现细节 SSOT、架构细则、契约说明、跨版本 tracker — **经 `mstar-compound` 结晶** | Agent handoff;**不**在 iteration-start 由 product/architect 新增 |
|
|
18
|
+
| **`{PROJECT_DIR}/<id>/references/`**(可选) | 主题化研究:surveys、epic roadmaps、第三方 notes — **与项目绑定**,非跨迭代 corpora | 项目所有者 / operator;engine 只列文件名,**无 markdown schema** |
|
|
18
19
|
| **`{PLAN_DIR}/`** | 单 plan 主文件、durable gate summary、可选 `residuals/` | 计划执行与长期决策留档 |
|
|
19
20
|
|
|
20
21
|
|
|
@@ -43,6 +44,14 @@
|
|
|
43
44
|
- 可选:目录级 `**{KNOWLEDGE_DIR}/AGENTS.md**` 承载命名、维护节奏、与 `{SPECS_DIR}` 的权威边界(Nexus 模式);harness 宽规则仍以 `mstar-plan-conventions` 与本 reference 为准。
|
|
44
45
|
- 初始化启用知识库时:创建空表头的 `README.md`,随文档递增行。
|
|
45
46
|
|
|
47
|
+
## `{PROJECT_DIR}/<id>/references/`(可选·主题化研究语料)
|
|
48
|
+
|
|
49
|
+
- **物理路径**:`**{PROJECT_DIR}/<id>/references/**`(默认 `{HARNESS_DIR}/projects/<id>/references/`;`.mstarc` `project_dir` 声明时用声明值)。
|
|
50
|
+
- **放什么**:**主题化研究** — surveys、epic roadmaps、第三方 notes,与拥有它的项目(`<id>`)绑定(compass ruling 1)。项目缺失用 `_default`(`{PROJECT_DIR}/_default/references/`)。
|
|
51
|
+
- **不放什么**:冻结规格 / ADR(→ `{SPECS_DIR}/`);compound 结晶的实现 SSOT(→ `{KNOWLEDGE_DIR}/`);迭代内 ranking notes 与草稿 spec(→ `{ITERATION_DIR}/<id>/guides|specs/`)。研究**不**迁入这三处 corpora,三处内容也**不**迁入 `references/`。
|
|
52
|
+
- **engine 职责边界**:`listProjectReferenceFiles(projectDir)` 只返回**文件名**(相对路径、`/` 分隔、code-unit 排序;跳过根级 `roadmap.md` / `residuals.json`;缺失目录 → `[]`);**不**读文件正文,**不**做 markdown schema 校验 — 归属语义是本 reference(技能散文)契约,不是 engine 校验。
|
|
53
|
+
- **历史 dump**:harness 根 `.mstar/references/` 已退役(dogfood 后缺省或仅一行 redirect);当前路径由 `mstar-project-governance` Scope 表与 `mstar-plan-conventions` `references/artifact-storage-paths.md` 命名。
|
|
54
|
+
|
|
46
55
|
## 文件命名
|
|
47
56
|
|
|
48
57
|
- 推荐:`<topic>-<qualifier>-v<N>.md`(例:`sync-contract-gap-analysis-v1.md`),便于同主题多版共存。
|
|
@@ -74,6 +83,7 @@
|
|
|
74
83
|
- `**{PLAN_DIR}/residuals/<plan-id>/`**:偏 **仍 open 的 R# 长文补充**(与 project register `entries[<plan-id>]` 配套,canonical 见 `mstar-plan-conventions` **SKILL.md** 开篇);见下文「open residual 散文详情」。
|
|
75
84
|
- `**{KNOWLEDGE_DIR}/**`:偏 **可复用的实现向设计上下文**(架构细则、决策、分析),可被后续 plan 或多会话反复引用。
|
|
76
85
|
- `**{ITERATION_DIR}/**`:偏 **某一迭代/版本** 的 package(compass + guides/specs),通常按版本索引而非按单 plan 长期复用。
|
|
86
|
+
- `**{PROJECT_DIR}/<id>/references/**`:偏 **主题化研究**(surveys、epic 备注、第三方 notes),随项目绑定;与 specs / knowledge / iteration guides 职责不混写。
|
|
77
87
|
- review bundle、gate summary、residuals、knowledge、iterations 可互链,但职责不混写。
|
|
78
88
|
|
|
79
89
|
---
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
| **workflow notes ledger** | `{HARNESS_DIR}/workflows/<id>/notes.jsonl`(gitignored;append-only 运行时笔记) | `mstar-plan-artifacts`、`mstar-iteration` |
|
|
21
21
|
| **project roadmap** | `.mstar/projects/<id>/roadmap.md`(gitignored;frontmatter `{project_id, title, status, created_at, milestones[]?, residuals_ref?}` + 正文约定) | `mstar-plan-artifacts`、`mstar-iteration` |
|
|
22
22
|
| **project register** | `.mstar/projects/<id>/residuals.json`(gitignored;open residual SSOT:`entries[<plan-id>]` 数组;项目缺失用 `_default`) | `mstar-plan-artifacts`、`mstar-review-qc` |
|
|
23
|
+
| **project references(研究语料)** | `.mstar/projects/<id>/references/`(gitignored;主题化 surveys / epic 备注 / 第三方 notes,与项目绑定;与 `{SPECS_DIR}` / `{KNOWLEDGE_DIR}` / `{ITERATION_DIR}` 不同) | `mstar-project-governance`、`mstar-plan-artifacts` |
|
|
23
24
|
| **迭代 package** | `.mstar/iterations/<iteration-id>/`(gitignored;`delivery-compass.md`、`guides/`、`specs/`、可选 `README.md`) | `mstar-iteration`(读写);close 时 `mstar-compound`(提升读;默认排除 compass) |
|
|
24
25
|
| **迭代索引** | `.mstar/iterations/README.md`(gitignored;一行 = 一次迭代) | `mstar-iteration`(读写) |
|
|
25
26
|
| **规格** | `{HARNESS_DIR}/specs/`(默认 tracked;解析见 `mstar-plan-conventions`) | `mstar-plan-artifacts` |
|
|
@@ -19,6 +19,7 @@ description: Morning Star 项目治理层约定 —— `projects/<id>/roadmap.md
|
|
|
19
19
|
|------|------|
|
|
20
20
|
| `roadmap.md` | 项目方向与目标(frontmatter machine-checkable + body 约定) |
|
|
21
21
|
| `residuals.json` | 项目 register:open residual 的 **SSOT**(`entries[<plan-id>]` 数组) |
|
|
22
|
+
| `references/` | 主题化研究语料(surveys / epic 备注 / 第三方 notes)。与 `{SPECS_DIR}`(冻结规格/ADR)、`{KNOWLEDGE_DIR}`(compound 结晶实现 SSOT)、`{ITERATION_DIR}`(迭代 package)**不同**;engine 只列文件名(`listProjectReferenceFiles`),**不做** markdown schema 校验 |
|
|
22
23
|
|
|
23
24
|
- **`_default` 回退**:无项目流程(未指定 project id 的 plan / 单 plan / hotfix)落到 **`projects/_default/`**(engine `_DEFAULT_PROJECT`)。项目归属由 plan 的 project id 决定;未归属即 `_default`。
|
|
24
25
|
- 本 skill 的 schema 事实与 **`packages/engine/src/project.ts`** 逐字一致(`validateRoadmap` / `validateProjectRegister` / `findingsCleanupGate` / `techDebtRollup`);技能文本是语义 SSOT,engine 是确定性校验。
|
package/package.json
CHANGED