@mstar-harness/dsh 3.5.1 → 3.6.0-alpha.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/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
  - 未经用户同意不改宿主配置文件与用户凭据。
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.1",
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",
@@ -1,108 +0,0 @@
1
- /**
2
- * Role-based subagent decoration at the `subagent/start` seam (plan
3
- * `20260814-dsh-fallbacks-integration` Task 2).
4
- *
5
- * Decoration rides the `subagent/start` EMIT — NOT `tools/pre-execute`:
6
- * tool args are deep-frozen snapshots and persona/`agentOptions` come from
7
- * the tool-subagent's own Config, never call args. The listener is
8
- * SYNCHRONOUS (the section must register before the child's first LLM call)
9
- * and resolves the published child via `ctx.get('agents')?.get(info.id)` —
10
- * documented in the `@deepseek-ai/dsh-subagent` event contract ("For
11
- * in-process providers, `ctx.agents.get(info.id)` resolves during this
12
- * notification"). The registered section is agent-scoped on `Agent.ctx`
13
- * (contributions are agent-local and unwind on disposal — the
14
- * hooks-claude-code precedent).
15
- *
16
- * Role identity uses the engine Assignment header grammar — the SAME
17
- * parsers the dispatch gate uses (`assignmentHeaderRegion` +
18
- * `parseAssignmentFields`) — over the child's seeded task prompt (the
19
- * child session's first `user/message`). Persona lookup (plan
20
- * `20260815-dsh-fallbacks-personas` Task 3) is the single
21
- * {@link personaFor} surface — `Config.rolePersonas[executeAs]` →
22
- * `harness-agents/` mirror default → skip (never gated on `roleMap` or on
23
- * the fallbacks mounted state: unmounted fallbacks degrades to the same
24
- * injection with exactly one debug log; probe at the decision point, no
25
- * cache). `roleMap` is a taxonomy bridge for logging + future rule-driven
26
- * interop only. The mirror root is bound at apply (`setDecorationAgentsDir`
27
- * ← `packagedAgentsDir()`), package-relative so the shipped bundle works
28
- * from any launch cwd.
29
- *
30
- * Degradation (the listener never throws — contained like the dispatch
31
- * gate's degrade path): `agents` service absent → skip + one debug log
32
- * (documented Known Limitation for compositions without dsh-agent);
33
- * child unresolved / non-Assignment / role-unmatched → silent no-op
34
- * (role-unmatched with the mirror present and no eligible shell stays
35
- * silent; with NO mirror the config-miss path logs ONE debug per apply —
36
- * case (e) semantics). A throwing log sink is contained inside the log
37
- * helper itself (plan QC F-002) — the sink must not escape the listener
38
- * either.
39
- *
40
- * Persona text is rendered by dsh system-prompt's STRICT `{{...}}`
41
- * interpolation, so persona values MUST NOT contain `{{` paired with a
42
- * later `}}` — the Config schema rejects such values at plugin mount (see
43
- * `_shared.ts` `rolePersonas` / `PERSONA_INTERPOLATION_HAZARD`); a mirror
44
- * default carrying the hazard is warned + skipped at extraction (never a
45
- * boot throw).
46
- *
47
- * Module boundary: no barrel — the entry imports this module by explicit
48
- * relative path and re-exports the public names verbatim.
49
- */
50
- import type { Context } from '@deepseek-ai/cordis';
51
- import type { Config } from './_shared.ts';
52
- /** Logger label for the subagent decoration (dsh logger naming: `<scope>/<subject>`). */
53
- export declare const DECORATION_LOGGER = "mstar/subagent-decoration";
54
- /** The decoration's system-prompt section name (agent-scoped on `Agent.ctx`). */
55
- export declare const PERSONA_SECTION_NAME = "mstar:role-persona";
56
- /** Prompt order of the persona section — renders right after the deployment persona slot (order 0). */
57
- export declare const PERSONA_SECTION_ORDER = 1;
58
- /**
59
- * Structural view of the `subagent/start` emit payload the decoration
60
- * consumes (`@deepseek-ai/dsh-subagent` `SubagentRunInfo` — the plugin
61
- * carries no dsh-subagent dependency; same pattern as the probe's
62
- * `LoaderEntryView` and agent-flow's `TaskDoneSnapshot`). Only `id` is
63
- * consumed; the rest keeps the view faithful to the published contract.
64
- */
65
- export interface SubagentRunInfoView {
66
- /** Unique identity shared with the paired terminal event. */
67
- readonly runId: unknown;
68
- /** Provider name recorded when the child was first created. */
69
- readonly provider: string;
70
- /** The child agent's id. */
71
- readonly id: string;
72
- /** Snapshot of whether the run's local agent was present when start fulfilled. */
73
- readonly local: boolean;
74
- }
75
- /** Decoration log levels the module sink understands. */
76
- export type DecorationLogLevel = 'debug' | 'info' | 'warn';
77
- /** Module-level decoration log sink — bound by `apply` to `ctx.logger(DECORATION_LOGGER)` (agent-flow ledger precedent). */
78
- export type DecorationLogSink = (level: DecorationLogLevel, message: string) => void;
79
- /**
80
- * Bind the decoration log sink (the entry `apply` binds it to
81
- * `ctx.logger(DECORATION_LOGGER)`). Returns the PRIOR sink so a caller can
82
- * restore it (test pattern: agent-flow `setAgentFlowLogger`).
83
- */
84
- export declare function setDecorationLogger(sink: DecorationLogSink): DecorationLogSink;
85
- /**
86
- * Bind the persona-defaults mirror root. Returns the PRIOR binding so a
87
- * caller can restore it (test pattern: {@link setDecorationLogger}).
88
- * @param dir - the mirror root, or `undefined` to disable mirror defaults.
89
- */
90
- export declare function setDecorationAgentsDir(dir: string | undefined): string | undefined;
91
- /**
92
- * Decorate one `subagent/start` emit: resolve the child, extract its seeded
93
- * task prompt, and — when the prompt is Assignment-shaped and
94
- * `rolePersonas[executeAs]` is configured — register the persona as the
95
- * child's `mstar:role-persona` system-prompt section (agent-scoped on
96
- * `Agent.ctx`, unwinds on child disposal). Synchronous by design: the
97
- * section must register before the child's first LLM call.
98
- *
99
- * Never throws — every failure mode degrades (skip + one log line at most),
100
- * matching the dispatch gate's contained degrade path; the dispatch itself
101
- * is never affected.
102
- *
103
- * @param ctx - the plugin's registrant context (the app composition root).
104
- * @param config - validated plugin configuration (`rolePersonas` is the only
105
- * payload source; `roleMap` is never consulted for injection).
106
- * @param info - the `subagent/start` emit payload.
107
- */
108
- export declare function decorateSubagentStart(ctx: Context, config: Config, info: SubagentRunInfoView): void;