@mstar-harness/opencode 2.0.1 → 2.0.3
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/CHANGELOG.md +18 -0
- package/dist/mstar.js +48 -30
- package/harness-skills/mstar-host/references/omp.md +11 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,24 @@ The monorepo root [CHANGELOG.md](../../CHANGELOG.md) summarizes cross-surface re
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [2.0.3] - 2026-08-09
|
|
10
|
+
|
|
11
|
+
### Bundled harness skills (`harness-skills/` at publish)
|
|
12
|
+
|
|
13
|
+
- Version alignment with harness **2.0.3** (no OpenCode package API change).
|
|
14
|
+
|
|
15
|
+
See root [CHANGELOG.md](../../CHANGELOG.md) **2.0.3**.
|
|
16
|
+
|
|
17
|
+
## [2.0.2] - 2026-08-08
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- OpenCode plugin entry now default-exports `{ server: MorningStarHarnessPlugin }` so helper function exports are not registered as plugins (fixes `plugin config hook failed: N.config` / `N.dispose` on startup).
|
|
22
|
+
|
|
23
|
+
- Version alignment with harness **2.0.2** (no OpenCode package API change).
|
|
24
|
+
|
|
25
|
+
See root [CHANGELOG.md](../../CHANGELOG.md) **2.0.2**.
|
|
26
|
+
|
|
9
27
|
## [2.0.1] - 2026-08-08
|
|
10
28
|
|
|
11
29
|
### Fixed
|
package/dist/mstar.js
CHANGED
|
@@ -223,6 +223,43 @@ function assertDefaultBranchProtected(branch, opts = {}) {
|
|
|
223
223
|
}
|
|
224
224
|
return { ok: violations.length === 0, violations };
|
|
225
225
|
}
|
|
226
|
+
var ASSIGNMENT_HEADING_RE = /^#{1,6}\s+Assignment\s*$/m;
|
|
227
|
+
var ASSIGNMENT_FIELD_RE = /^[ \t]*(?:[-*][ \t]+)?\*{0,2}(Execute as|Delegation|Task category)\*{0,2}[ \t]*:[ \t]*(\S.*)$/gm;
|
|
228
|
+
function isAssignmentShaped(assignmentText) {
|
|
229
|
+
return ASSIGNMENT_HEADING_RE.test(assignmentText) || assignmentText.match(ASSIGNMENT_FIELD_RE) !== null;
|
|
230
|
+
}
|
|
231
|
+
function composeDispatchGate(text, opts = {}) {
|
|
232
|
+
const silent = {
|
|
233
|
+
ok: true,
|
|
234
|
+
violations: [],
|
|
235
|
+
shaped: false,
|
|
236
|
+
enforcement: { hard: false, source: "none" }
|
|
237
|
+
};
|
|
238
|
+
try {
|
|
239
|
+
if (!isAssignmentShaped(text))
|
|
240
|
+
return silent;
|
|
241
|
+
const violations = [];
|
|
242
|
+
const writable = opts.writable !== false;
|
|
243
|
+
violations.push(...validateAssignmentFields(text, { writable }).violations);
|
|
244
|
+
const agent = (opts.agent ?? "").trim();
|
|
245
|
+
if (agent !== "") {
|
|
246
|
+
violations.push(...antiRecursionPrecheck(agent, parseAssignmentFields(text).executeAs ?? "").violations);
|
|
247
|
+
}
|
|
248
|
+
if (writable) {
|
|
249
|
+
const forms = parseAssignmentBranchForms(text);
|
|
250
|
+
const branch = forms.createForm?.name ?? forms.workingBranch ?? forms.directOn?.branch ?? process.env.MSTAR_WORKING_BRANCH;
|
|
251
|
+
if (branch !== undefined && branch.trim() !== "") {
|
|
252
|
+
const directOnException = parseBranchPolicyDirectOnBranch(text) === branch.trim();
|
|
253
|
+
violations.push(...assertDefaultBranchProtected(branch.trim(), { directOnException }).violations);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
const enforcement = parseEnforcementFlag(assignmentHeaderRegion(text));
|
|
257
|
+
const gate = { ok: violations.length === 0, violations };
|
|
258
|
+
return { ...applyEnforcement(gate, { hard: enforcement.hard }), shaped: true, enforcement };
|
|
259
|
+
} catch {
|
|
260
|
+
return silent;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
226
263
|
function antiRecursionPrecheck(subagentType, executeAs) {
|
|
227
264
|
const binding = subagentType.trim().toLowerCase();
|
|
228
265
|
const role = executeAs.trim().toLowerCase();
|
|
@@ -633,48 +670,25 @@ function validateStatusWrite(targetPath, opts = {}) {
|
|
|
633
670
|
return null;
|
|
634
671
|
}
|
|
635
672
|
}
|
|
636
|
-
var ASSIGNMENT_HEADING_RE = /^#{1,6}\s+Assignment\s*$/m;
|
|
637
|
-
var ASSIGNMENT_FIELD_RE = /^[ \t]*(?:[-*][ \t]+)?\*{0,2}(Execute as|Delegation|Task category)\*{0,2}[ \t]*:[ \t]*(\S.*)$/gm;
|
|
638
|
-
function isAssignmentShaped(assignmentText) {
|
|
639
|
-
if (typeof assignmentText !== "string")
|
|
640
|
-
return false;
|
|
641
|
-
return ASSIGNMENT_HEADING_RE.test(assignmentText) || assignmentText.match(ASSIGNMENT_FIELD_RE) !== null;
|
|
642
|
-
}
|
|
643
673
|
function validateDispatchAssignment(assignmentText, opts = {}) {
|
|
644
674
|
const log = opts.log ?? defaultStatusLogger;
|
|
645
675
|
try {
|
|
646
|
-
if (typeof assignmentText !== "string"
|
|
676
|
+
if (typeof assignmentText !== "string") {
|
|
647
677
|
return { ok: true, violations: [] };
|
|
648
678
|
}
|
|
649
|
-
const
|
|
650
|
-
const
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
const binding = opts.subagentType ?? "";
|
|
654
|
-
if (binding.trim() !== "") {
|
|
655
|
-
violations.push(...antiRecursionPrecheck(binding, fields.executeAs ?? "").violations);
|
|
656
|
-
}
|
|
657
|
-
if (writable !== false) {
|
|
658
|
-
const forms = parseAssignmentBranchForms(assignmentText);
|
|
659
|
-
const branch = forms.createForm?.name ?? forms.workingBranch ?? forms.directOn?.branch ?? process.env.MSTAR_WORKING_BRANCH;
|
|
660
|
-
if (branch !== undefined && branch.trim() !== "") {
|
|
661
|
-
const directOnException = parseBranchPolicyDirectOnBranch(assignmentText) === branch.trim();
|
|
662
|
-
violations.push(...assertDefaultBranchProtected(branch.trim(), { directOnException }).violations);
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
|
-
const result = { ok: violations.length === 0, violations };
|
|
666
|
-
const enforcement = parseEnforcementFlag(assignmentHeaderRegion(assignmentText));
|
|
667
|
-
if (!result.ok) {
|
|
668
|
-
for (const violation of result.violations) {
|
|
679
|
+
const writable = isReadOnlyAssignmentRole(parseAssignmentFields(assignmentText).executeAs ?? "") ? false : undefined;
|
|
680
|
+
const composed = composeDispatchGate(assignmentText, { agent: opts.subagentType ?? "", writable });
|
|
681
|
+
if (!composed.ok) {
|
|
682
|
+
for (const violation of composed.violations) {
|
|
669
683
|
const fix = violation.fix ? ` (fix: ${violation.fix})` : "";
|
|
670
|
-
if (enforcement.hard) {
|
|
684
|
+
if (composed.enforcement.hard) {
|
|
671
685
|
log("error", `assignment validation (hard gate): [${violation.severity}] ${violation.code}: ${violation.message}${fix} — hardBlocked per Enforcement: hard; refusal requires a host refusal channel (skill: mstar-dispatch-gates)`);
|
|
672
686
|
} else {
|
|
673
687
|
log("warn", `assignment validation: [${violation.severity}] ${violation.code}: ${violation.message}${fix}`);
|
|
674
688
|
}
|
|
675
689
|
}
|
|
676
690
|
}
|
|
677
|
-
return
|
|
691
|
+
return composed;
|
|
678
692
|
} catch (error) {
|
|
679
693
|
log("error", `assignment validation aborted: ${error.message}`);
|
|
680
694
|
return null;
|
|
@@ -772,8 +786,12 @@ var MorningStarHarnessPlugin = async () => {
|
|
|
772
786
|
}
|
|
773
787
|
};
|
|
774
788
|
};
|
|
789
|
+
var mstar_default = {
|
|
790
|
+
server: MorningStarHarnessPlugin
|
|
791
|
+
};
|
|
775
792
|
export {
|
|
776
793
|
validateStatusWrite,
|
|
777
794
|
validateDispatchAssignment,
|
|
795
|
+
mstar_default as default,
|
|
778
796
|
MorningStarHarnessPlugin
|
|
779
797
|
};
|
|
@@ -208,6 +208,17 @@ Cannot emit required **N** → **`Blocked`**.
|
|
|
208
208
|
| Plugin commands | `/iteration-start`, `/iteration-drive`, `/iteration-loop` (filename-based) |
|
|
209
209
|
| Session entry | `/skill:pm` → `mstar-harness-core` via pm **Read next** |
|
|
210
210
|
|
|
211
|
+
## In-process engine binding (omp ≥ 17.2.11)
|
|
212
|
+
|
|
213
|
+
- **Surfaces** (repo root = plugin root): `hooks/pre/mstar-gates.ts` — one `tool_call` pre-hook that returns `{ block: true, reason }` (structured refusal the model sees as the tool error) or `undefined` (pass); `tools/mstar_{status_validate,dispatch_validate,lease_verify,path_resolve,iteration_gate,worktree_check}/index.ts` — six model-callable validator tools (engine validators only, Zod params via `pi.zod`).
|
|
214
|
+
- **Enforcement semantics**: block ONLY under `Enforcement: hard`. The status gate reads the harness compass frontmatter (`enforcement: hard`, active/locked iterations only); the dispatch gate reads each Assignment's own header flag (`assignmentHeaderRegion` — a body example never hardens). Soft / no flag → silent pass. Rollback = unset the flag. Never global.
|
|
215
|
+
- **Engine dependency**: the adapters import the published engine package (root `package.json` `dependencies` entry). omp git/npm plugin installs run `bun install <spec>` in the plugins tree → declared deps installed; a bare `-l` / `omp plugin link` symlink install without `node_modules` cannot resolve the modules.
|
|
216
|
+
- **Graceful degradation (explicit)**: module load failure → `mstar_*` tools skipped, hook absent (no blocking), `commands/*.md` shell-out fallback intact. Caveat: a partial failure is SILENT — no in-band signal that gates are off; verify with `omp -p '/extensions'`.
|
|
217
|
+
- **`MSTAR_HARNESS_DIR` override**: the hook and tools discover `{HARNESS_DIR}` via `resolveHarnessDir`, which probes only `.mstar/` → `.agents/` → `.plans/`/`plans/` roots. Repos using a non-standard harness root (e.g. this plugin repo's own `.harness/`) MUST export `MSTAR_HARNESS_DIR` (absolute path) in the omp session env — without it the status gate does not cover those roots and tools like `mstar_path_resolve` / `mstar_lease_verify` error out (parity with the opencode binding).
|
|
218
|
+
- **Edit-path limitation**: the status gate validates the on-disk file for `edit` events (pre-edit state) — a corrupting edit is caught by the next write or `mstar_status_validate` (known v1 limitation, parity with opencode).
|
|
219
|
+
- **`mstar_iteration_gate` engine requirement**: the tool requires an engine build exporting `parseCompassFrontmatter` (next published release). On older engines the tool reports an explicit upgrade error instead of loading — no silent absence; CLI fallback: `mstar iteration gate`.
|
|
220
|
+
- **Reload**: edits are picked up by a new session (`?mtime` cache-buster); in-session `/reload-plugins` (omp ≥ 17.2.11) applies them without a new session.
|
|
221
|
+
|
|
211
222
|
## Files, shell, and approvals
|
|
212
223
|
|
|
213
224
|
- Prefer host search/edit tools over shell find/sed when available.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mstar-harness/opencode",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3",
|
|
4
4
|
"description": "Morning Star harness OpenCode plugin — skills bootstrap + engine-backed runtime hooks (status lint, dispatch validation, Enforcement: hard gates).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -36,6 +36,6 @@
|
|
|
36
36
|
"access": "public"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@mstar-harness/engine": "2.0.
|
|
39
|
+
"@mstar-harness/engine": "2.0.3"
|
|
40
40
|
}
|
|
41
41
|
}
|