@mstar-harness/dsh 3.5.1 → 3.6.0-alpha.2

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/index.js CHANGED
@@ -4036,6 +4036,13 @@ function formatViolation(violation14) {
4036
4036
  function asRecord(value) {
4037
4037
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
4038
4038
  }
4039
+ var CATALOG_STATE_JOIN_LIMIT = 8;
4040
+ function joinCapped(items, cap, separator, render) {
4041
+ const visible = items.slice(0, cap).map(render);
4042
+ if (items.length > cap)
4043
+ visible.push(`+${items.length - cap} more`);
4044
+ return visible.join(separator);
4045
+ }
4039
4046
  function resolveSeamHard(harnessDir, config) {
4040
4047
  if (config.enforcement === "hard")
4041
4048
  return true;
@@ -5491,7 +5498,7 @@ function renderEngineStatusCatalog(source) {
5491
5498
  if (state.selection.kind === "active" && state.selection.warning !== undefined) {
5492
5499
  lines.push(`workflow warning: ${state.selection.warning.code} ${state.selection.warning.message}`);
5493
5500
  }
5494
- lines.push(`plans: ${state.plans.length === 0 ? "none registered" : state.plans.map((p) => `${p.id}(${p.status})`).join(" ")}`);
5501
+ lines.push(`plans: ${state.plans.length === 0 ? "none registered" : joinCapped(state.plans, CATALOG_STATE_JOIN_LIMIT, " ", (p) => `${p.id}(${p.status})`)}`);
5495
5502
  lines.push(`residuals: ${state.residuals.length === 0 ? "none open" : state.residuals.map((r) => `${r.severity} ${r.count}`).join(", ")}`);
5496
5503
  if (state.iterationBaseBranch !== null && state.targetBranch !== null) {
5497
5504
  const integration = state.specIntegrationBranch !== null ? ` (spec integration: ${state.specIntegrationBranch})` : "";
@@ -5504,7 +5511,7 @@ function renderEngineStatusCatalog(source) {
5504
5511
  ].filter((part) => part !== null).join("; ");
5505
5512
  if (policy !== "")
5506
5513
  lines.push(`policy: ${policy}`);
5507
- lines.push(`leases: ${state.leases.length === 0 ? "none active" : state.leases.map((l) => `${l.planId} → ${l.holder}${l.worktreePath !== null ? ` (${l.worktreePath})` : ""}`).join("; ")}`);
5514
+ lines.push(`leases: ${state.leases.length === 0 ? "none active" : joinCapped(state.leases, CATALOG_STATE_JOIN_LIMIT, "; ", (l) => `${l.planId} → ${l.holder}${l.worktreePath !== null ? ` (${l.worktreePath})` : ""}`)}`);
5508
5515
  if (state.knowledge !== null) {
5509
5516
  lines.push(`knowledge: ${state.knowledge.docCount} doc${state.knowledge.docCount === 1 ? "" : "s"} (${state.knowledge.categories.join(", ")})`);
5510
5517
  }
@@ -7206,112 +7213,111 @@ function unquote(value) {
7206
7213
  return value.length >= 2 && value.startsWith('"') && value.endsWith('"') ? value.slice(1, -1) : value;
7207
7214
  }
7208
7215
 
7209
- // src/gates/fallbacks-probe.ts
7210
- var FALLBACKS_ENTRY_NAME = "dsh-llm-fallbacks";
7211
- function fallbacksService(ctx) {
7212
- return ctx.get("llm-fallbacks");
7213
- }
7214
- function fallbacksEntry(ctx) {
7215
- const loader = ctx.get("loader");
7216
- if (loader === undefined)
7217
- return;
7218
- for (const entry of loader.entries()) {
7219
- if (entry.options.name !== FALLBACKS_ENTRY_NAME)
7220
- continue;
7221
- if (entry.options.group)
7222
- continue;
7223
- if (entry.disabled)
7224
- continue;
7225
- return entry;
7226
- }
7227
- return;
7228
- }
7229
- function fallbacksMounted(ctx) {
7230
- if (fallbacksService(ctx) !== undefined)
7231
- return true;
7232
- const entry = fallbacksEntry(ctx);
7233
- if (entry === undefined)
7234
- return false;
7235
- return entry.fiber !== undefined;
7236
- }
7237
-
7238
- // src/gates/fallbacks-decoration.ts
7239
- var DECORATION_LOGGER = "mstar/subagent-decoration";
7240
- var PERSONA_SECTION_NAME = "mstar:role-persona";
7241
- var PERSONA_SECTION_ORDER = 1;
7242
- var decorationLogSink = () => {};
7243
- function setDecorationLogger(sink) {
7244
- const prior = decorationLogSink;
7245
- decorationLogSink = sink;
7216
+ // src/gates/role-persona.ts
7217
+ var ROLE_PERSONA_LOGGER = "mstar/role-persona";
7218
+ var SUBAGENTS_SERVICE = "subagents";
7219
+ var rolePersonaLogSink = () => {};
7220
+ function setRolePersonaLogger(sink) {
7221
+ const prior = rolePersonaLogSink;
7222
+ rolePersonaLogSink = sink;
7246
7223
  return prior;
7247
7224
  }
7248
- var decorationAgentsDir;
7225
+ var rolePersonaAgentsDir;
7249
7226
  var mirrorAbsentDebugged = false;
7250
- function setDecorationAgentsDir(dir) {
7251
- const prior = decorationAgentsDir;
7252
- decorationAgentsDir = dir;
7227
+ function setRolePersonaAgentsDir(dir) {
7228
+ const prior = rolePersonaAgentsDir;
7229
+ rolePersonaAgentsDir = dir;
7253
7230
  mirrorAbsentDebugged = false;
7254
7231
  return prior;
7255
7232
  }
7256
- function seededTaskPrompt(child) {
7257
- for (const event of child.session.events) {
7258
- if (event.type !== "user/message")
7259
- continue;
7260
- const text = event.data.content.filter((block) => block.type === "text").map((block) => block.text).join(`
7261
- `);
7262
- if (text.trim().length > 0)
7263
- return text;
7264
- }
7265
- return;
7233
+ var wrapperCache = new WeakMap;
7234
+ function registerRolePersonaChannel(ctx, config) {
7235
+ const rolePersonas = config.rolePersonas;
7236
+ ctx.on("internal/get", (_readCtx, name, _error, next) => {
7237
+ const value = next();
7238
+ if (name !== SUBAGENTS_SERVICE)
7239
+ return value;
7240
+ try {
7241
+ return wrapSubagentsService(value, rolePersonas);
7242
+ } catch (error) {
7243
+ log2("warn", `role persona channel degraded to pass-through (subagent starts unaffected): ${errorMessage2(error)}`);
7244
+ return value;
7245
+ }
7246
+ });
7266
7247
  }
7267
- function decorateSubagentStart(ctx, config, info) {
7268
- try {
7269
- const personas = config.rolePersonas;
7270
- const agentsDir = decorationAgentsDir;
7271
- if ((personas == null || Object.keys(personas).length === 0) && agentsDir === undefined)
7272
- return;
7273
- const agents = ctx.get("agents");
7274
- if (agents === undefined) {
7275
- log2("debug", "agents service absent — mstar:role-persona decoration skipped (composition without dsh-agent)");
7276
- return;
7248
+ function wrapSubagentsService(value, rolePersonas) {
7249
+ if (typeof value !== "object" || value === null)
7250
+ return value;
7251
+ const service = value;
7252
+ if (typeof service.start !== "function" || typeof service.getProvider !== "function")
7253
+ return value;
7254
+ const cached = wrapperCache.get(value);
7255
+ if (cached !== undefined && cached.rolePersonas === rolePersonas)
7256
+ return cached.wrapper;
7257
+ const wrapper = Object.create(value);
7258
+ wrapper.start = (name, request) => {
7259
+ let merged = request;
7260
+ try {
7261
+ merged = withRolePersona(service, name, request, rolePersonas, "one-shot");
7262
+ } catch (error) {
7263
+ log2("warn", `role persona merge degraded to pass-through (subagent start unaffected): ${errorMessage2(error)}`);
7277
7264
  }
7278
- const child = agents.get(info.id);
7279
- if (child === undefined)
7280
- return;
7281
- const taskPrompt = seededTaskPrompt(child);
7282
- if (taskPrompt === undefined)
7283
- return;
7284
- const executeAs = parseAssignmentFields(assignmentHeaderRegion(taskPrompt)).executeAs;
7285
- if (executeAs === undefined)
7286
- return;
7287
- const persona = personaFor(executeAs, { rolePersonas: config.rolePersonas, agentsDir }, (message) => log2("warn", message));
7288
- if (persona === undefined) {
7289
- if (agentsDir === undefined && !mirrorAbsentDebugged) {
7290
- mirrorAbsentDebugged = true;
7291
- log2("debug", "harness-agents mirror absent — mstar:role-persona skipped (config-only lookups; mirror defaults unavailable)");
7265
+ return service.start(name, merged);
7266
+ };
7267
+ if (typeof service.startContinuable === "function") {
7268
+ wrapper.startContinuable = (spec) => {
7269
+ let merged = spec;
7270
+ try {
7271
+ const mergedRequest = withRolePersona(service, spec.provider, spec.request, rolePersonas, "continuable");
7272
+ if (mergedRequest !== spec.request)
7273
+ merged = { ...spec, request: mergedRequest };
7274
+ } catch (error) {
7275
+ log2("warn", `role persona merge degraded to pass-through (continuable subagent start unaffected): ${errorMessage2(error)}`);
7292
7276
  }
7293
- return;
7294
- }
7295
- child.ctx.systemPrompt.section({
7296
- name: PERSONA_SECTION_NAME,
7297
- order: PERSONA_SECTION_ORDER,
7298
- text: persona.text
7299
- });
7300
- if (fallbacksMounted(ctx)) {
7301
- log2("info", `dsh-llm-fallbacks mounted (v${fallbacksService(ctx)?.version ?? "unknown"}) — mstar:role-persona injected for role '${executeAs}'`);
7302
- } else {
7303
- log2("debug", `dsh-llm-fallbacks unmounted — mstar:role-persona injected from ${persona.source === "config" ? "mstar Config" : "harness-agents default"} for role '${executeAs}' (decoration channel unchanged)`);
7304
- }
7305
- } catch (error) {
7306
- log2("warn", `mstar:role-persona decoration aborted (degraded — subagent dispatch unaffected): ${errorMessage2(error)}`);
7277
+ return service.startContinuable(merged);
7278
+ };
7307
7279
  }
7280
+ wrapperCache.set(value, { rolePersonas, wrapper });
7281
+ return wrapper;
7282
+ }
7283
+ function withRolePersona(service, providerName, request, rolePersonas, surface) {
7284
+ if (request.persona !== undefined)
7285
+ return request;
7286
+ const personas = rolePersonas;
7287
+ const agentsDir = rolePersonaAgentsDir;
7288
+ if ((personas == null || Object.keys(personas).length === 0) && agentsDir === undefined)
7289
+ return request;
7290
+ const taskPrompt = (request.prompt ?? []).filter((block) => block.type === "text").map((block) => block.text ?? "").join(`
7291
+ `);
7292
+ if (taskPrompt.trim().length === 0)
7293
+ return request;
7294
+ const executeAs = parseAssignmentFields(assignmentHeaderRegion(taskPrompt)).executeAs;
7295
+ if (executeAs === undefined)
7296
+ return request;
7297
+ const persona = personaFor(executeAs, { rolePersonas: personas, agentsDir }, (message) => log2("warn", message));
7298
+ if (persona === undefined) {
7299
+ if (agentsDir === undefined && !mirrorAbsentDebugged) {
7300
+ mirrorAbsentDebugged = true;
7301
+ log2("debug", "harness-agents mirror absent — role persona skipped (config-only lookups; mirror defaults unavailable)");
7302
+ }
7303
+ return request;
7304
+ }
7305
+ const provider = service.getProvider(providerName);
7306
+ if (provider === undefined)
7307
+ return request;
7308
+ if (surface === "one-shot" ? provider.capabilities?.persona !== true : typeof provider.prepareContinuable !== "function") {
7309
+ log2("debug", surface === "one-shot" ? `subagent provider '${providerName}' lacks the persona capability — role persona for '${executeAs}' skipped (start proceeds unchanged)` : `subagent provider '${providerName}' does not support continuable children — role persona for '${executeAs}' skipped (the native continuable start fails loud its own way)`);
7310
+ return request;
7311
+ }
7312
+ log2("debug", `role persona delivered via the native subagent persona channel for role '${executeAs}' (${surface} start, source: ${persona.source === "config" ? "mstar Config" : "harness-agents default"})`);
7313
+ return { ...request, persona: persona.text };
7308
7314
  }
7309
7315
  function errorMessage2(error) {
7310
7316
  return error instanceof Error ? error.message : String(error);
7311
7317
  }
7312
7318
  function log2(level, message) {
7313
7319
  try {
7314
- decorationLogSink(level, message);
7320
+ rolePersonaLogSink(level, message);
7315
7321
  } catch {}
7316
7322
  }
7317
7323
 
@@ -7992,6 +7998,35 @@ ${mstarLoadLine(roleId)}` });
7992
7998
  return { declared, skipped, preserved, outcome };
7993
7999
  }
7994
8000
 
8001
+ // src/gates/fallbacks-probe.ts
8002
+ var FALLBACKS_ENTRY_NAME = "dsh-llm-fallbacks";
8003
+ function fallbacksService(ctx) {
8004
+ return ctx.get("llm-fallbacks");
8005
+ }
8006
+ function fallbacksEntry(ctx) {
8007
+ const loader = ctx.get("loader");
8008
+ if (loader === undefined)
8009
+ return;
8010
+ for (const entry of loader.entries()) {
8011
+ if (entry.options.name !== FALLBACKS_ENTRY_NAME)
8012
+ continue;
8013
+ if (entry.options.group)
8014
+ continue;
8015
+ if (entry.disabled)
8016
+ continue;
8017
+ return entry;
8018
+ }
8019
+ return;
8020
+ }
8021
+ function fallbacksMounted(ctx) {
8022
+ if (fallbacksService(ctx) !== undefined)
8023
+ return true;
8024
+ const entry = fallbacksEntry(ctx);
8025
+ if (entry === undefined)
8026
+ return false;
8027
+ return entry.fiber !== undefined;
8028
+ }
8029
+
7995
8030
  // src/gates/fallbacks-advisory.ts
7996
8031
  var ADVISORY_LOGGER = "mstar/fallbacks-advisory";
7997
8032
  var advisoryLogSink = () => {};
@@ -8276,12 +8311,6 @@ function engineStatusProvider(ctx, resolver, bootHarnessDir) {
8276
8311
  };
8277
8312
  }
8278
8313
  var DIGEST_PLAN_CAP = 8;
8279
- function joinCapped(items, cap, separator, render) {
8280
- const visible = items.slice(0, cap).map(render);
8281
- if (items.length > cap)
8282
- visible.push(`+${items.length - cap} more`);
8283
- return visible.join(separator);
8284
- }
8285
8314
  function engineStatusSummary(source) {
8286
8315
  const lines = [`mstar engine status: v${source.version}`];
8287
8316
  const state = source.state;
@@ -8404,16 +8433,14 @@ function apply(ctx, config) {
8404
8433
  else
8405
8434
  logger.info(message);
8406
8435
  });
8407
- setDecorationLogger((level, message) => {
8408
- const logger = ctx.logger(DECORATION_LOGGER);
8436
+ setRolePersonaLogger((level, message) => {
8437
+ const logger = ctx.logger(ROLE_PERSONA_LOGGER);
8409
8438
  if (level === "debug")
8410
8439
  logger.debug(message);
8411
- else if (level === "info")
8412
- logger.info(message);
8413
8440
  else
8414
8441
  logger.warn(message);
8415
8442
  });
8416
- setDecorationAgentsDir(packagedAgentsDir());
8443
+ setRolePersonaAgentsDir(packagedAgentsDir());
8417
8444
  setHarnessPromptLogger((level, message) => {
8418
8445
  const logger = ctx.logger(HARNESS_PROMPT_LOGGER);
8419
8446
  if (level === "debug")
@@ -8526,9 +8553,9 @@ function apply(ctx, config) {
8526
8553
  ctx.on("fs/write-intent", (target, actor, next) => seamWriteIntentListener(ctx, resolver, config, seam, target, actor, next), { prepend: true });
8527
8554
  }
8528
8555
  ctx.on("tools/pre-execute", (exec, next) => preExecuteListener(ctx, resolver, config, adapter, exec, next), { prepend: true });
8529
- ctx.events.on("subagent/start", (info) => {
8556
+ registerRolePersonaChannel(ctx, config);
8557
+ ctx.events.on("subagent/start", () => {
8530
8558
  runAdvisoryPass();
8531
- decorateSubagentStart(ctx, config, info);
8532
8559
  });
8533
8560
  const ttlMs = config.catalogTtlMs ?? DEFAULT_CATALOG_TTL_MS;
8534
8561
  const explicitKey = bootHarnessDir !== null ? EXPLICIT_CACHE_KEY : undefined;
@@ -8547,10 +8574,11 @@ function apply(ctx, config) {
8547
8574
  }
8548
8575
  export {
8549
8576
  skillLocalConfig,
8550
- setDecorationLogger,
8551
- setDecorationAgentsDir,
8577
+ setRolePersonaLogger,
8578
+ setRolePersonaAgentsDir,
8552
8579
  setAdvisoryLogger,
8553
8580
  runFallbacksAdvisory,
8581
+ registerRolePersonaChannel,
8554
8582
  recordWorkflowVerdict,
8555
8583
  recordSettle,
8556
8584
  recordDispatch,
@@ -8564,17 +8592,14 @@ export {
8564
8592
  lintCompoundWrite,
8565
8593
  lintAuditWrite,
8566
8594
  inject,
8567
- decorateSubagentStart,
8568
8595
  apply,
8569
8596
  SkillLintVetoError,
8570
8597
  SeamVetoError,
8571
8598
  SETTLE_SEAM,
8572
- PERSONA_SECTION_ORDER,
8573
- PERSONA_SECTION_NAME,
8599
+ ROLE_PERSONA_LOGGER,
8574
8600
  HarnessResolver,
8575
8601
  DshMstar,
8576
8602
  DshHostAdapter,
8577
- DECORATION_LOGGER,
8578
8603
  Config,
8579
8604
  AGENT_FLOW_MAX_EVENTS,
8580
8605
  AGENT_FLOW_FILE,
@@ -43,29 +43,33 @@ Canonical vs legacy residual definitions → **`mstar-artifacts` SKILL.md**("`
43
43
  ```json
44
44
  {
45
45
  "schema_version": 1,
46
- "id": "<plan-id-or-iteration-id>",
47
- "type": "plan | iteration",
48
- "status": "running | paused | completed | failed | stopped",
49
- "started_at": "YYYY-MM-DD",
50
- "ended_at": null,
51
- "updated_at": "YYYY-MM-DD",
46
+ "id": "iter-demo",
47
+ "type": "iteration",
48
+ "status": "running",
49
+ "started_at": "2026-08-30",
50
+ "updated_at": "2026-08-30",
52
51
  "phase": "phase-2-execute",
53
52
  "plans": [
54
53
  {
55
54
  "id": "plan-id",
56
55
  "title": "Plan title",
57
56
  "file": "{PLAN_DIR}/plan-id-feature-name.md",
58
- "status": "Todo | InProgress | InReview | Blocked | Done",
57
+ "status": "InProgress",
59
58
  "owner": "@project-manager",
60
59
  "agents": ["@fullstack-dev"],
61
60
  "progress": 0,
62
61
  "tags": [],
63
- "created_at": "YYYY-MM-DD",
64
- "updated_at": "YYYY-MM-DD",
62
+ "created_at": "2026-08-29",
63
+ "updated_at": "2026-08-30",
65
64
  "done_at": null,
66
65
  "notes": [],
67
66
  "metadata": {},
68
- "execution_lease": {}
67
+ "execution_lease": {
68
+ "holder": "omp:demo-session",
69
+ "claimed_at": "2026-08-30T02:30:00Z",
70
+ "worktree_path": "/tmp/worktrees/demo-plan",
71
+ "working_branch": "feature/demo-plan"
72
+ }
69
73
  }
70
74
  ],
71
75
  "execution_policy": {
@@ -73,14 +77,22 @@ Canonical vs legacy residual definitions → **`mstar-artifacts` SKILL.md**("`
73
77
  "worktree_mode": "",
74
78
  "push_policy": ""
75
79
  },
76
- "integration_merge_lease": {},
77
- "branch": { "base": "", "integration": "", "target": "" },
80
+ "integration_merge_lease": {
81
+ "holder": "omp:demo-session",
82
+ "claimed_at": "2026-08-30T03:00:00Z",
83
+ "plan_id": "plan-id",
84
+ "source_branch": "feature/demo-plan",
85
+ "target_branch": "iteration/iter-demo"
86
+ },
87
+ "branch": { "base": "main", "integration": "iteration/iter-demo", "target": "main" },
78
88
  "control_worktree_path": "/abs/repo/root",
79
89
  "legacy_metadata": {},
80
- "compass_ref": "iterations/<iteration-id>/delivery-compass.md"
90
+ "compass_ref": "iterations/iter-demo/delivery-compass.md"
81
91
  }
82
92
  ```
83
93
 
94
+ - The example above depicts the **held** state (both leases populated, illustrative placeholder values) and passes `validateWorkflowSnapshot`; the released state is **key absence** (delete-key-on-release below), never `null` or `{}`, and enum scalars (`type` / `status` / plan-row `status`) are always single values — the full enum sets are `type`: `plan | iteration`, snapshot `status`: `running | paused | completed | failed | stopped`, plan-row `status`: `Todo | InProgress | InReview | Blocked | Done`.
95
+
84
96
  - `plans[]` rows are the **legacy PlanRow shape verbatim** (unknown row fields preserved, never re-bucketed). Per-row `execution_lease` stays on the row; `integration_merge_lease` is **top-level** (the v1 root-`metadata` home is gone).
85
97
  - Terminal statuses (`completed` / `failed` / `stopped`) require `ended_at` and no dangling leases.
86
98
  - `execution_policy` keys are copied from v1 root `metadata` at migrate; values are accepted-but-opaque this iteration (no semantic gate).
@@ -31,6 +31,8 @@ The failure mode: "correct" code that is alien to the codebase — works but loo
31
31
 
32
32
  ## 2) Simplicity First
33
33
 
34
+ **Upstream invariants**: the global engineering rules live in `mstar-harness-core`(核心研发守则)——no backward-compat layers, simplest implementation, layered growth, modularity, dependency discipline, long-term architecture; this section is their implementation-level playbook.
35
+
34
36
  Implement the smallest durable slice that satisfies the request and acceptance criteria.
35
37
 
36
38
  **The Ladder.** A reflex hierarchy for every decision — stop at the first rung that holds:
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: mstar-harness-core
3
- description: Morning Star (启明星) harness **强制全局入口** —— 信息源优先级、最小交付循环、状态机与 Done 权限、Task category 路由(含 quick 禁豁免)、@explore 边界、长任务纪律、护栏不变量、反模式索引、Morning Star Skill 索引与宿主入口。**任何**非平凡任务开始前必须先 Read 本 skill;再按角色与任务 **按需** Read 其它 `mstar-*` 专题(勿默认通读全部)。`@project-manager` 开轮必读 + `mstar-dispatch-gates` / `mstar-phase-gates` / `mstar-conventions` 等;实现/审查/QA 必读本 skill + `mstar-coding-behavior` 及角色清单(见 `mstar-roles`)。Prepare/派发/Git/residual/QC 细则在专题 skill,不在此重复。
3
+ description: Morning Star (启明星) harness **强制全局入口** —— 信息源优先级、最小交付循环、状态机与 Done 权限、Task category 路由(含 quick 禁豁免)、@explore 边界、长任务纪律、核心研发守则、护栏不变量、反模式索引、Morning Star Skill 索引与宿主入口。**任何**非平凡任务开始前必须先 Read 本 skill;再按角色与任务 **按需** Read 其它 `mstar-*` 专题(勿默认通读全部)。`@project-manager` 开轮必读 + `mstar-dispatch-gates` / `mstar-phase-gates` / `mstar-conventions` 等;实现/审查/QA 必读本 skill + `mstar-coding-behavior` 及角色清单(见 `mstar-roles`)。Prepare/派发/Git/residual/QC 细则在专题 skill,不在此重复。
4
4
  ---
5
5
 
6
6
  # Morning Star Harness Core(启明星核心)
@@ -121,6 +121,18 @@ Read **`mstar-host`** after this skill; detect host per its table, then Read the
121
121
  | Kimi | `Agent`/`AgentSwarm`(仅 `coder`/`explore`/`plan`);角色绑定在 prompt(C5b);Plan 双写 → `references/kimi.md` · `kimi-plan-mode-bridge.md` |
122
122
  | 其它 | 同 `mstar-host` skill;按工具信号选 reference |
123
123
 
124
+ ## 核心研发守则
125
+
126
+ 全局工程不变量,适用于所有角色;实现级操作细节(The Ladder、surgical、debugging 等)→ **`mstar-coding-behavior`**。
127
+
128
+ - Do not preserve backward compatibility. Remove obsolete paths instead of adding compatibility layers, fallbacks, or migrations.
129
+ - Choose the simplest implementation that fully meets the current requirements. Avoid speculative abstractions, configuration, and indirection.
130
+ - Grow the system in layers. Start from the smallest version that works end to end, and add each new capability on top of a product that already works. Never trade a working product for unfinished complexity.
131
+ - Keep components modular and concerns clearly separated.
132
+ - Prefer established, well-maintained libraries when they reduce overall complexity or improve reliability. Do not reimplement common functionality without a clear reason.
133
+ - Lean on the dependencies already in the project before writing your own implementation or adding packages. Do not assume a library lacks a capability without checking its documentation and types.
134
+ - Make architectural decisions for the long term. Do not accept a stopgap that only works for now and is meant to be replaced later.
135
+
124
136
  ## 护栏(不变量)
125
137
 
126
138
  - 未经用户同意不改宿主配置文件与用户凭据。
@@ -45,7 +45,7 @@ Phase 5: PR merge-ready loop —— 至 mergeable + CI 全绿 + reviews resolved
45
45
  | **→ 迭代交付完成** | §5.5 exit checklist 全 `[x]` | PR mergeable;required CI 全绿;reviews resolved | Phase 4 开 PR 即宣称完成 |
46
46
  | **start → integration branch** | §1.6 Review & Edit chain | 三角色按序 invoke;**specs** 为主产出;**禁止** start 链向 `{KNOWLEDGE_DIR}/` 新增;writing-specialist corpus hygiene + compass `status: locked` | PM 代做专业编辑;并行三角色;product/architect 写 knowledge;临时笔记进 specs |
47
47
 
48
- > **Engine check (when available):** run `mstar iteration gate --workflow <id> --compass <delivery-compass.md>` (or `import { evaluatePhaseGate } from "@mstar-harness/engine"` in a host hook) to evaluate the transition gate above against the workflow snapshot. On `fail` (gate-blocking violations) -> do not proceed; fix and re-run. Note: during the Phase-3 window (`transition: phase-3-close`) the gate exits 1 until the §3.4 close items (`status: completed` + `end_date`) are written — that exit-1 is the expected "close work pending" signal (the exit checklist gates Phase 4, not the Phase-3 entry), so proceed with Phase 3 per the table below. Skill text below remains authoritative when the runtime is absent.
48
+ > **Engine check (when available):** run `mstar iteration gate --workflow <id> --compass <delivery-compass.md> --branch "$(git branch --show-current)" --integration <spec_integration_branch> --target <target_branch>` (or `import { evaluatePhaseGate } from "@mstar-harness/engine"` with the `currentBranch` / `specIntegrationBranch` / `prBaseBranch` probe inputs in a host hook) to evaluate the transition gate above against the workflow snapshot — the branch probes cover §3.5 exit item 5 (`EXIT_BRANCH_MISMATCH` when the commit checkout is not on `spec_integration_branch`; verify **before** the §3.5 close commit, not after). On `fail` (gate-blocking violations) -> do not proceed; fix and re-run. Note: during the Phase-3 window (`transition: phase-3-close`) the gate exits 1 until the §3.4 close items (`status: completed` + `end_date`) are written — that exit-1 is the expected "close work pending" signal (the exit checklist gates Phase 4, not the Phase-3 entry), so proceed with Phase 3 per the table below. Skill text below remains authoritative when the runtime is absent.
49
49
 
50
50
  **误判信号**:对话里出现 compound 摘要、roadmap 更新、或「所有 plan 已完成」但 **未** 打印 §3.1 / §3.5 checklist → 视为 **Phase 3 未执行**,回到 §3.0。
51
51
 
@@ -80,14 +80,24 @@ PM 打印 **iteration-close exit checklist**;全部为 `[x]` 后方可 `git co
80
80
  - [ ] 当前分支是 `spec_integration_branch`
81
81
  - [ ] PR base = snapshot `branch.target`(`target_branch`,与 compass frontmatter 一致);**不是**未记录的 `main`
82
82
 
83
- **Commit integration 分支**:
83
+ **Commit 前提(HARD — branch-anchored,防递交到控制分支)**:§3.5 的 commit 是 **branch 锚定**的——`git commit` 落在**当前检出分支**,`<spec_integration_branch>` 只出现在 push 参数里。当控制 worktree(或任一检出)不在 integration 分支时,未经下述核对直接执行本配方,compound 会把 tracked 的 `{KNOWLEDGE_DIR}/`、`{SPECS_DIR}/`、`CONCEPTS.md` 递交到控制分支(如 `main`),integration 分支的 PR 永远带不上这些 shared 产物。因此 **任何 `git add` 之前**必须先验分支;mismatch → **STOP**(不得 commit、不得 push、不得「先提交后挪」),改在正确检出上重做(见下)。
84
+
85
+ 1. 解析 `<spec_integration_branch>`:snapshot `branch.integration`(workflows/<id>/snapshot.json)→ 缺失时 compass frontmatter `spec_integration_branch`;仍缺 → STOP 补齐,不得默认 `main`。
86
+ 2. **先验后提交**(在执行 commit 的检出处):`git branch --show-current` === `<spec_integration_branch>`。§3.2–§3.4 产生的 tracked close 产物本就应处于未提交状态等待本 commit,**不要求**此处工作树干净。engine 可用 → 在 add/commit **前**运行 `mstar iteration gate --workflow <id> --compass <delivery-compass.md> --branch <current> --integration <spec_integration_branch> --target <target_branch>` 并确认 exit 无 `EXIT_BRANCH_MISMATCH` / `EXIT_PR_BASE_MISMATCH`(Phase-3 窗口预期的其它 exit-1 除外,见 Phase transition gates 注)。
87
+ 3. **mismatch 时**:不产生任何提交。tracked 子树(`{KNOWLEDGE_DIR}/`、`{SPECS_DIR}/`、`CONCEPTS.md`、迭代 package 中 tracked 部分)在**检出 `<spec_integration_branch>` 的 worktree** 重新写入或在 commit 前恢复(它们默认 tracked、随 Git 分支走;进程产物 plans/iterations/status/sdd 经 control 绝对路径不受影响)。然后重跑本 checklist。
88
+
89
+ **在 `<spec_integration_branch>` 检出上执行**:
84
90
 
85
91
  ```bash
86
- git add {ITERATION_DIR}/<id>/ {ITERATION_DIR}/README.md {KNOWLEDGE_DIR}/ CONCEPTS.md
92
+ git branch --show-current # must print <spec_integration_branch> — mismatch → STOP, see above
93
+ git add {ITERATION_DIR}/<id>/ {ITERATION_DIR}/README.md {KNOWLEDGE_DIR}/ {SPECS_DIR}/ CONCEPTS.md
94
+ git add STRATEGY.md # only if updated in §3.3 (tracked root file); skip line otherwise
87
95
  git commit -m "chore(iteration): close <iteration-id> — compound round, roadmap update"
88
96
  git push origin <spec_integration_branch>
89
97
  ```
90
98
 
99
+ Staging 说明:`{SPECS_DIR}` 为解析后的实际 specs 目录(候选链见 `mstar-conventions`,如 `{HARNESS_DIR}/specs/`、`docs/specs/`、`specs/`);本轮更新过才加入。§3.3 更新过的 tracked 项目层 roadmap tracker 若为 tracked 文件,一并 stage(gitignored 的 process 产物不进 commit)。
100
+
91
101
  PR 目标使用 snapshot `branch.target`;缺失时停止并补齐,不得默认 `main`。
92
102
 
93
103
  ## 3.6 可选:触发 compound-refresh
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mstar-harness/dsh",
3
- "version": "3.5.1",
3
+ "version": "3.6.0-alpha.2",
4
4
  "description": "Morning Star harness dsh (DeepSeek Harness) cordis function plugin — in-process engine gates (status/dispatch/lease) with hard refusal channels.",
5
5
  "keywords": [
6
6
  "dsh",
@@ -44,7 +44,7 @@
44
44
  },
45
45
  "client": {
46
46
  "inject": [
47
- "@deepseek-ai/dsh-client-runtime",
47
+ "@deepseek-ai/dsh-client-store",
48
48
  "@deepseek-ai/dsh-client-ui-conversation",
49
49
  "@deepseek-ai/dsh-client-locale"
50
50
  ],
@@ -56,31 +56,30 @@
56
56
  "test": "bun test",
57
57
  "typecheck:tests": "bunx tsc --noEmit -p tests/tsconfig.json",
58
58
  "bundle-assets": "bun run scripts/bundle-harness-assets.ts",
59
- "build": "bun run bundle-assets && rm -rf dist && bun build src/index.ts src/invariant.ts --target node --outdir dist --external @deepseek-ai/cordis --external @deepseek-ai/dsh-skill-filesystem --external @deepseek-ai/dsh-tools --external @deepseek-ai/dsh-llm --external dsh-llm-fallbacks && bun run build-client && bunx tsc",
59
+ "build": "bun run bundle-assets && rm -rf dist && bun build src/index.ts src/invariant.ts --target node --outdir dist --external @deepseek-ai/cordis --external @deepseek-ai/dsh-skill-filesystem --external @deepseek-ai/dsh-tools --external @deepseek-ai/dsh-llm && bun run build-client && bunx tsc",
60
60
  "build-client": "bun run scripts/build-client-bundle.ts",
61
61
  "prepublishOnly": "bun run build"
62
62
  },
63
63
  "engines": {
64
64
  "bun": ">=1.2.17"
65
65
  },
66
- "dependencies": {
67
- "dsh-llm-fallbacks": "^0.3.0"
68
- },
69
66
  "peerDependencies": {
70
- "@deepseek-ai/cordis": "^4.0.1",
71
- "@deepseek-ai/dsh-agent": "^0.1.1-rc.2",
72
- "@deepseek-ai/dsh-client-locale": "^0.1.1-rc.2",
73
- "@deepseek-ai/dsh-client-runtime": "^0.1.1-rc.2",
74
- "@deepseek-ai/dsh-client-ui-conversation": "^0.1.1-rc.2",
75
- "@deepseek-ai/dsh-client-ui-slots": "^0.1.1-rc.2",
76
- "@deepseek-ai/dsh-commands": "^0.1.1-rc.2",
77
- "@deepseek-ai/dsh-fs": "^0.1.1-rc.2",
78
- "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
79
- "@deepseek-ai/dsh-jobs": "^0.1.1-rc.2",
80
- "@deepseek-ai/dsh-llm": "^0.1.1-rc.2",
81
- "@deepseek-ai/dsh-skill": "^0.1.1-rc.2",
82
- "@deepseek-ai/dsh-skill-filesystem": "^0.1.1-rc.2",
83
- "@deepseek-ai/dsh-tools": "^0.1.1-rc.2"
67
+ "@deepseek-ai/cordis": "^4.0.2",
68
+ "@deepseek-ai/dsh-agent": "^0.1.2-alpha.2",
69
+ "@deepseek-ai/dsh-client-locale": "^0.1.2-alpha.2",
70
+ "@deepseek-ai/dsh-client-store": "^0.1.2-alpha.2",
71
+ "@deepseek-ai/dsh-client-ui-chat": "^0.1.2-alpha.2",
72
+ "@deepseek-ai/dsh-client-ui-conversation": "^0.1.2-alpha.2",
73
+ "@deepseek-ai/dsh-client-ui-renderer": "^0.1.2-alpha.2",
74
+ "@deepseek-ai/dsh-client-ui-slots": "^0.1.2-alpha.2",
75
+ "@deepseek-ai/dsh-commands": "^0.1.2-alpha.2",
76
+ "@deepseek-ai/dsh-fs": "^0.1.2-alpha.2",
77
+ "@deepseek-ai/dsh-invariants": "^0.1.2-alpha.2",
78
+ "@deepseek-ai/dsh-jobs": "^0.1.2-alpha.2",
79
+ "@deepseek-ai/dsh-llm": "^0.1.2-alpha.2",
80
+ "@deepseek-ai/dsh-skill": "^0.1.2-alpha.2",
81
+ "@deepseek-ai/dsh-skill-filesystem": "^0.1.2-alpha.2",
82
+ "@deepseek-ai/dsh-tools": "^0.1.2-alpha.2"
84
83
  },
85
84
  "publishConfig": {
86
85
  "access": "public"
@@ -91,6 +90,7 @@
91
90
  "@types/react": "~18.3.1",
92
91
  "js-yaml": "^4.1.0",
93
92
  "bun-types": "^1.2.17",
93
+ "dsh-llm-fallbacks": "^0.4.0-alpha.1",
94
94
  "schemastery": "^3.18.0",
95
95
  "typescript": "^5.9.3",
96
96
  "vitest": "^4.1.8",