@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/README.i18n.yaml +2 -2
- package/README.md +15 -17
- package/README.zh.md +15 -17
- package/dist/client/index.d.ts +1 -1
- package/dist/client/panel/PanelView.d.ts +2 -2
- package/dist/client/panel/use-mstar-engine-status.d.ts +8 -8
- package/dist/client.js +5 -5
- package/dist/gates/_shared.d.ts +46 -14
- package/dist/gates/agent-personas.d.ts +3 -3
- package/dist/gates/fallbacks-advisory.d.ts +2 -2
- package/dist/gates/fallbacks-probe.d.ts +12 -6
- package/dist/gates/fallbacks-seeds.d.ts +12 -10
- package/dist/gates/fallbacks-structural.d.ts +101 -0
- package/dist/gates/goal-bridge.d.ts +1 -1
- package/dist/gates/role-persona.d.ts +191 -0
- package/dist/gates/system-prompt.d.ts +7 -5
- package/dist/index.d.ts +2 -2
- package/dist/index.js +136 -111
- package/harness-skills/mstar-artifacts/references/status-and-residuals.md +25 -13
- package/harness-skills/mstar-coding-behavior/SKILL.md +2 -0
- package/harness-skills/mstar-harness-core/SKILL.md +13 -1
- package/package.json +20 -20
- package/dist/gates/fallbacks-decoration.d.ts +0 -108
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
|
|
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
|
|
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/
|
|
7210
|
-
var
|
|
7211
|
-
|
|
7212
|
-
|
|
7213
|
-
|
|
7214
|
-
|
|
7215
|
-
|
|
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
|
|
7225
|
+
var rolePersonaAgentsDir;
|
|
7249
7226
|
var mirrorAbsentDebugged = false;
|
|
7250
|
-
function
|
|
7251
|
-
const prior =
|
|
7252
|
-
|
|
7227
|
+
function setRolePersonaAgentsDir(dir) {
|
|
7228
|
+
const prior = rolePersonaAgentsDir;
|
|
7229
|
+
rolePersonaAgentsDir = dir;
|
|
7253
7230
|
mirrorAbsentDebugged = false;
|
|
7254
7231
|
return prior;
|
|
7255
7232
|
}
|
|
7256
|
-
|
|
7257
|
-
|
|
7258
|
-
|
|
7259
|
-
|
|
7260
|
-
const
|
|
7261
|
-
|
|
7262
|
-
|
|
7263
|
-
|
|
7264
|
-
|
|
7265
|
-
|
|
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
|
|
7268
|
-
|
|
7269
|
-
|
|
7270
|
-
|
|
7271
|
-
|
|
7272
|
-
|
|
7273
|
-
|
|
7274
|
-
|
|
7275
|
-
|
|
7276
|
-
|
|
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
|
-
|
|
7279
|
-
|
|
7280
|
-
|
|
7281
|
-
|
|
7282
|
-
|
|
7283
|
-
|
|
7284
|
-
|
|
7285
|
-
|
|
7286
|
-
|
|
7287
|
-
|
|
7288
|
-
|
|
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
|
-
|
|
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
|
-
|
|
8408
|
-
const logger = ctx.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
|
-
|
|
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
|
|
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
|
-
|
|
8551
|
-
|
|
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
|
-
|
|
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": "
|
|
47
|
-
"type": "
|
|
48
|
-
"status": "running
|
|
49
|
-
"started_at": "
|
|
50
|
-
"
|
|
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": "
|
|
57
|
+
"status": "InProgress",
|
|
59
58
|
"owner": "@project-manager",
|
|
60
59
|
"agents": ["@fullstack-dev"],
|
|
61
60
|
"progress": 0,
|
|
62
61
|
"tags": [],
|
|
63
|
-
"created_at": "
|
|
64
|
-
"updated_at": "
|
|
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
|
-
|
|
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
|
|
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
|
|
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.
|
|
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-
|
|
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
|
|
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.
|
|
71
|
-
"@deepseek-ai/dsh-agent": "^0.1.
|
|
72
|
-
"@deepseek-ai/dsh-client-locale": "^0.1.
|
|
73
|
-
"@deepseek-ai/dsh-client-
|
|
74
|
-
"@deepseek-ai/dsh-client-ui-
|
|
75
|
-
"@deepseek-ai/dsh-client-ui-
|
|
76
|
-
"@deepseek-ai/dsh-
|
|
77
|
-
"@deepseek-ai/dsh-
|
|
78
|
-
"@deepseek-ai/dsh-
|
|
79
|
-
"@deepseek-ai/dsh-
|
|
80
|
-
"@deepseek-ai/dsh-
|
|
81
|
-
"@deepseek-ai/dsh-
|
|
82
|
-
"@deepseek-ai/dsh-
|
|
83
|
-
"@deepseek-ai/dsh-
|
|
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;
|