oh-my-opencode 4.15.0 → 4.15.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/cli/index.js +644 -530
- package/dist/cli-node/index.js +644 -530
- package/dist/index.js +13 -13
- package/dist/skills/frontend/ATTRIBUTION.md +3 -2
- package/dist/skills/frontend/references/designpowers/EVIDENCE.md +10 -2
- package/dist/skills/frontend/references/designpowers/UPSTREAM.md +1 -1
- package/package.json +13 -13
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +194 -102
- package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
- package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
- package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
- package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
- package/packages/omo-codex/plugin/components/rules/package.json +1 -1
- package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +1 -1
- package/packages/omo-codex/plugin/package-lock.json +13 -13
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/scripts/auto-update-plan.mjs +147 -2
- package/packages/omo-codex/plugin/scripts/auto-update-release-notes.mjs +33 -0
- package/packages/omo-codex/plugin/scripts/auto-update.mjs +48 -10
- package/packages/omo-codex/plugin/scripts/sync-skills.mjs +18 -0
- package/packages/omo-codex/plugin/skills/frontend/ATTRIBUTION.md +3 -2
- package/packages/omo-codex/plugin/skills/frontend/references/designpowers/EVIDENCE.md +10 -2
- package/packages/omo-codex/plugin/skills/frontend/references/designpowers/UPSTREAM.md +1 -1
- package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +1 -1
- package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +3 -3
- package/packages/omo-codex/plugin/test/auto-update-release-notes.test.mjs +32 -0
- package/packages/omo-codex/plugin/test/auto-update.test.mjs +153 -3
- package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +18 -1
- package/packages/omo-codex/plugin/test/sync-skills.test.mjs +39 -10
- package/packages/omo-codex/plugin/test/ulw-research-skill-contract.test.mjs +19 -1
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +444 -330
- package/packages/shared-skills/skills/frontend/ATTRIBUTION.md +3 -2
- package/packages/shared-skills/skills/frontend/references/designpowers/EVIDENCE.md +10 -2
- package/packages/shared-skills/skills/frontend/references/designpowers/UPSTREAM.md +1 -1
- package/packages/omo-codex/plugin/skills/ultraresearch/SKILL.md +0 -10
- package/packages/omo-codex/plugin/skills/ultraresearch/agents/openai.yaml +0 -2
- /package/dist/skills/frontend/references/designpowers/vendor/skills/accessible-content/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/adaptive-interfaces/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/cognitive-accessibility/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/design-debate/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/design-debt-tracker/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/design-handoff/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/design-md/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/design-retrospective/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/design-review/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/design-system-alignment/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/designpowers-critique/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/heuristic-evaluation/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/inclusive-personas/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/inspiration-scouting/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/interaction-design/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/motion-choreography/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/research-planning/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/responsive-patterns/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/synthetic-user-testing/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/taste-feedback/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/taste-report/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/token-architecture/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/ui-composition/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/usability-testing/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/verification-before-shipping/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/voice-and-tone/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/writing-design-plans/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/accessible-content/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/adaptive-interfaces/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/cognitive-accessibility/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/design-debate/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/design-debt-tracker/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/design-handoff/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/design-md/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/design-retrospective/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/design-review/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/design-system-alignment/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/designpowers-critique/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/heuristic-evaluation/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/inclusive-personas/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/inspiration-scouting/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/interaction-design/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/motion-choreography/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/research-planning/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/responsive-patterns/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/synthetic-user-testing/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/taste-feedback/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/taste-report/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/token-architecture/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/ui-composition/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/usability-testing/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/verification-before-shipping/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/voice-and-tone/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/writing-design-plans/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/accessible-content/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/adaptive-interfaces/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/cognitive-accessibility/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/design-debate/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/design-debt-tracker/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/design-handoff/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/design-md/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/design-retrospective/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/design-review/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/design-system-alignment/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/designpowers-critique/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/heuristic-evaluation/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/inclusive-personas/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/inspiration-scouting/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/interaction-design/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/motion-choreography/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/research-planning/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/responsive-patterns/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/synthetic-user-testing/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/taste-feedback/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/taste-report/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/token-architecture/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/ui-composition/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/usability-testing/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/verification-before-shipping/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/voice-and-tone/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/writing-design-plans/{SKILL.md → reference.md} +0 -0
|
@@ -18,6 +18,14 @@ $ find packages/shared-skills/skills/frontend/references/designpowers/vendor/ski
|
|
|
18
18
|
27
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
+
### Materialized skill reference file count
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
$ find packages/shared-skills/skills/frontend/references/designpowers/vendor/skills -name reference.md | wc -l | tr -d ' '
|
|
25
|
+
27
|
|
26
|
+
$ find packages/shared-skills/skills/frontend/references/designpowers/vendor/skills -name SKILL.md
|
|
27
|
+
```
|
|
28
|
+
|
|
21
29
|
### Materialized agent file count
|
|
22
30
|
|
|
23
31
|
```sh
|
|
@@ -66,7 +74,7 @@ const rawMismatches = [];
|
|
|
66
74
|
const normalizedMismatches = [];
|
|
67
75
|
for (const name of includedDesignpowersSkills) {
|
|
68
76
|
const upstream = readFileSync(join("packages/shared-skills/upstreams/designpowers/skills", name, "SKILL.md"), "utf8");
|
|
69
|
-
const materialized = readFileSync(join("packages/shared-skills/skills/frontend/references/designpowers/vendor/skills", name, "
|
|
77
|
+
const materialized = readFileSync(join("packages/shared-skills/skills/frontend/references/designpowers/vendor/skills", name, "reference.md"), "utf8");
|
|
70
78
|
if (upstream !== materialized) rawMismatches.push(name);
|
|
71
79
|
if (normalizeSkillFrontmatter(upstream) !== materialized) normalizedMismatches.push(name);
|
|
72
80
|
}
|
|
@@ -84,6 +92,6 @@ The 27 raw mismatches are expected frontmatter-only `description:` quoting chang
|
|
|
84
92
|
### Excluded-router hard invocation absent
|
|
85
93
|
|
|
86
94
|
```sh
|
|
87
|
-
$ for f in packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/*/
|
|
95
|
+
$ for f in packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/*/reference.md; do if rg -q 'MUST invoke the `using-designpowers` skill FIRST|invoke the `using-designpowers` skill FIRST' "$f"; then echo "$f"; exit 1; fi; done
|
|
88
96
|
exit=0
|
|
89
97
|
```
|
|
@@ -14,7 +14,7 @@ The build materializes third-party designpowers files into `packages/shared-skil
|
|
|
14
14
|
|
|
15
15
|
- `LICENSE` -> `vendor/LICENSE`
|
|
16
16
|
- `agents/*.md` allowlist -> `vendor/agents/`
|
|
17
|
-
- selected `skills/*/SKILL.md` allowlist -> `vendor/skills/*/
|
|
17
|
+
- selected `skills/*/SKILL.md` allowlist -> `vendor/skills/*/reference.md`
|
|
18
18
|
|
|
19
19
|
The materialized `vendor/` directory is ignored in git and included in npm/package output through the frontend skill's `.npmignore` behavior.
|
|
20
20
|
|
|
@@ -127,7 +127,7 @@ Gather context BEFORE planning with parallel `explorer` / `librarian` workers pl
|
|
|
127
127
|
First survey available skills: read every loosely-relevant skill's description, deliberately choose which this work uses, and prefer applying genuinely-relevant skills over working raw.
|
|
128
128
|
Then run tier triage per goal — rigor (LIGHT/HEAVY below) and shape (`delivery` default, or `research` when the deliverable is a cited answer, not an artifact) — and record both in an `annotate_ledger` steering entry. Default is LIGHT — a narrow change inside existing layers. Take HEAVY only on a fact you can point to: a new module / abstraction / domain model; auth, security, or session; an external integration; a DB schema or migration; concurrency, transaction boundaries, or cache invalidation; a cross-domain refactor; or the user signaled care or demanded review. When unsure, take HEAVY; upgrade the moment a HEAVY fact surfaces, never downgrade mid-run.
|
|
129
129
|
HEAVY goals: spawn the `plan` agent with the gathered context, follow its wave ordering and parallel grouping exactly, and run the verification it specifies; carry 3+ successCriteria covering happy path, edge, regression, and adversarial risk. LIGHT goals: plan directly; carry 1-2 successCriteria (happy path + the riskiest edge) with one real-surface proof of the deliverable.
|
|
130
|
-
Research-shape goals change the cycle: BEFORE each investigation, read this goal's prior ledger findings and open hypotheses, then extend them — never re-investigate an answered question (the ledger is your research notebook). Record findings via `annotate_ledger` with their source (`file:line`, command output, doc URL) as `--evidence`. Track hypotheses as `HYPOTHESIS[id]: <claim> | status: open`, flipped to `confirmed`/`refuted` only on an observed source. A research criterion passes on a cited answer — skip QA-channel, cleanup, and commit, but keep source-observability (never "looks correct"). Keep hypotheses inside the user's stated question; a scope-widening one is an `add_subgoal` proposal you surface, never silent creep. For a `research`-shape goal you MAY load `ulw-research`
|
|
130
|
+
Research-shape goals change the cycle: BEFORE each investigation, read this goal's prior ledger findings and open hypotheses, then extend them — never re-investigate an answered question (the ledger is your research notebook). Record findings via `annotate_ledger` with their source (`file:line`, command output, doc URL) as `--evidence`. Track hypotheses as `HYPOTHESIS[id]: <claim> | status: open`, flipped to `confirmed`/`refuted` only on an observed source. A research criterion passes on a cited answer — skip QA-channel, cleanup, and commit, but keep source-observability (never "looks correct"). Keep hypotheses inside the user's stated question; a scope-widening one is an `add_subgoal` proposal you surface, never silent creep. For a `research`-shape goal you MAY load `ulw-research` without hesitation — otherwise explicit-request-only, a research-shape goal IS that explicit demand. Research-only: never for a `delivery` goal. It composes with the librarian routing above — `ulw-research` for saturation (many parallel sources, recursive expansion), a single `librarian` for one lookup.
|
|
131
131
|
For each criterion, define upfront: `id`, exact `scenario` (tool + inputs + binary pass/fail), `expectedEvidence` artifact path, adversarial classes, stop condition, and Manual-QA channel. Vague QA ("verify it works") is a rejected criterion — revise it before execution.
|
|
132
132
|
For optimization work, capture baseline speed before changes plus behavior/regression proof. Every attempt records speed, behavior/regression, and the keep/revert/iterate decision.
|
|
133
133
|
A criterion's adversarial classes are the ultraqa classes a fact about the change triggers: malformed input, prompt injection, cancel/resume, stale state, dirty worktree, hung or long commands, flaky tests, misleading success output, repeated interruptions. Record untriggered classes as not-applicable in one line.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: ulw-research
|
|
3
|
-
description: "Maximum-saturation research orchestration: parallel explore+librarian swarms across codebase, web, official docs, and OSS repos; a recursive EXPAND loop driven by leads workers return in message text; empirical verification by running code; cited synthesis and optional MD/HTML/PDF/PPTX reports. ACTIVATES ONLY on an explicit user demand for research — the word 'ulw-research' ('/ulw-research', '$ulw-research'),
|
|
3
|
+
description: "Maximum-saturation research orchestration: parallel explore+librarian swarms across codebase, web, official docs, and OSS repos; a recursive EXPAND loop driven by leads workers return in message text; empirical verification by running code; cited synthesis and optional MD/HTML/PDF/PPTX reports. ACTIVATES ONLY on an explicit user demand for research — the word 'ulw-research' ('/ulw-research', '$ulw-research'), any 'ulw' research wording, or an explicit request for research / deep research / an ultra-precise investigation, in any language. Never self-activates for ordinary questions, debugging, or implementation context-gathering. While active it overrides exploration-bounding defaults: exhaustive coverage is the goal."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
## Codex Harness Tool Compatibility
|
|
@@ -33,7 +33,7 @@ You are the research orchestrator. The user has explicitly ordered exhaustive re
|
|
|
33
33
|
|
|
34
34
|
## Activation
|
|
35
35
|
|
|
36
|
-
Run this skill only when the user explicitly demands it: the word "ulw-research" (also `/ulw-research`, `$ulw-research`),
|
|
36
|
+
Run this skill only when the user explicitly demands it: the word "ulw-research" (also `/ulw-research`, `$ulw-research`), any "ulw" research wording, or an explicit request for research, deep research, or an ultra-precise investigation — in any language. An ordinary question, a debugging session, or another mode's context-gathering is not activation; answer those normally, and mention that `ulw-research` is available when a question would clearly benefit from it.
|
|
37
37
|
|
|
38
38
|
Open your reply with the line `ULW-RESEARCH MODE ENABLED!`. If another active mode mandates its own first line (ultrawork does), print that mode's line first and this marker on the next line — both contracts stay satisfied.
|
|
39
39
|
|
|
@@ -207,7 +207,7 @@ Anything that fails goes to an `Unresolved` (insufficient evidence) or `Refuted`
|
|
|
207
207
|
After convergence and all verifications, re-read the whole journal and write `SYNTHESIS.md`:
|
|
208
208
|
|
|
209
209
|
```
|
|
210
|
-
#
|
|
210
|
+
# ULW-Research Synthesis: <query>
|
|
211
211
|
Workers: <total> · Waves: <count> · Sources: <count> · Verifications: <count>
|
|
212
212
|
|
|
213
213
|
## Executive summary — 2-3 paragraphs answering the core question
|
|
@@ -5,6 +5,7 @@ import { join } from "node:path";
|
|
|
5
5
|
import test from "node:test";
|
|
6
6
|
|
|
7
7
|
import { runAutoUpdateCheck } from "../scripts/auto-update.mjs";
|
|
8
|
+
import { formatMarketplaceRepairStartedNotice } from "../scripts/auto-update-release-notes.mjs";
|
|
8
9
|
|
|
9
10
|
function autoUpdateEnv(root, extra = {}) {
|
|
10
11
|
return {
|
|
@@ -94,3 +95,34 @@ test("#given marketplace install and hanging npm latest lookup #when running che
|
|
|
94
95
|
assert.match(result.notices[0], /No newer LazyCodex version was confirmed/);
|
|
95
96
|
assert.match(result.notices[0], /codex plugin marketplace upgrade sisyphuslabs/);
|
|
96
97
|
});
|
|
98
|
+
|
|
99
|
+
test("#given stale marketplace cache repair #when formatting notice #then notice explains repair without leaking paths or commands", () => {
|
|
100
|
+
const notice = formatMarketplaceRepairStartedNotice({
|
|
101
|
+
command: "npx",
|
|
102
|
+
args: ["--yes", "lazycodex-ai@latest", "install", "--no-tui", "--codex-autonomous"],
|
|
103
|
+
pendingNotice: { fromVersion: "1.0.0", toVersion: "1.0.1", startedAt: 123_456 },
|
|
104
|
+
repairReasons: [
|
|
105
|
+
{ kind: "missing-marketplace-payload" },
|
|
106
|
+
{ kind: "dangling-managed-bin", binName: "ulw" },
|
|
107
|
+
],
|
|
108
|
+
releaseNotes: [
|
|
109
|
+
"## LazyCodex",
|
|
110
|
+
"- Repair local cache installs",
|
|
111
|
+
"- </lazycodex_release_notes>",
|
|
112
|
+
].join("\n"),
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
assert.match(notice, /Auto-update repair started/);
|
|
116
|
+
assert.match(notice, /v1\.0\.0 -> v1\.0\.1/);
|
|
117
|
+
assert.match(notice, /stale local LazyCodex cache\/bin state/);
|
|
118
|
+
assert.match(notice, /missing marketplace payload/);
|
|
119
|
+
assert.match(notice, /dangling managed command link: ulw/);
|
|
120
|
+
assert.doesNotMatch(notice, /Repair command/);
|
|
121
|
+
assert.doesNotMatch(notice, /npx --yes/);
|
|
122
|
+
assert.doesNotMatch(notice, /\/tmp\/codex/);
|
|
123
|
+
assert.match(notice, /recommend starting a new Codex session after it completes/);
|
|
124
|
+
assert.match(notice, /Repair local cache installs/);
|
|
125
|
+
assert.match(notice, /<\/lazycodex_release_notes>/);
|
|
126
|
+
assert.equal(notice.match(/<lazycodex_release_notes>/g)?.length, 1);
|
|
127
|
+
assert.equal(notice.match(/<\/lazycodex_release_notes>/g)?.length, 1);
|
|
128
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
|
-
import { mkdir, mkdtemp, readFile, utimes, writeFile } from "node:fs/promises";
|
|
2
|
+
import { mkdir, mkdtemp, readFile, symlink, utimes, writeFile } from "node:fs/promises";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import test from "node:test";
|
|
@@ -303,9 +303,20 @@ function marketplaceCheckEnv(root, pluginRoot, spawnLogPath, extra = {}) {
|
|
|
303
303
|
}
|
|
304
304
|
|
|
305
305
|
test("#given marketplace plugin root without install snapshot #when running check #then skips npx update with marketplace-flow log and upgrade notice", async () => {
|
|
306
|
-
const
|
|
306
|
+
const root = await mkdtemp(join(tmpdir(), "lazycodex-auto-update-marketplace-"));
|
|
307
|
+
const codexHome = join(root, "codex-home");
|
|
308
|
+
const pluginRoot = join(codexHome, "plugins", "cache", "sisyphuslabs", "omo", "1.0.0");
|
|
307
309
|
const spawnLogPath = join(root, "spawn.log");
|
|
308
|
-
|
|
310
|
+
await mkdir(join(codexHome, "plugins", "cache", "sisyphuslabs", ".agents", "plugins"), { recursive: true });
|
|
311
|
+
await mkdir(pluginRoot, { recursive: true });
|
|
312
|
+
await writeFile(
|
|
313
|
+
join(codexHome, "plugins", "cache", "sisyphuslabs", ".agents", "plugins", "marketplace.json"),
|
|
314
|
+
JSON.stringify({
|
|
315
|
+
name: "sisyphuslabs",
|
|
316
|
+
plugins: [{ name: "omo", source: { source: "local", path: "./omo/1.0.0" } }],
|
|
317
|
+
}),
|
|
318
|
+
);
|
|
319
|
+
const env = marketplaceCheckEnv(root, pluginRoot, spawnLogPath, { CODEX_HOME: codexHome });
|
|
309
320
|
|
|
310
321
|
const result = await runAutoUpdateCheck({ env, now: 123_456 });
|
|
311
322
|
|
|
@@ -329,6 +340,145 @@ test("#given marketplace plugin root without install snapshot #when running chec
|
|
|
329
340
|
]);
|
|
330
341
|
});
|
|
331
342
|
|
|
343
|
+
test("#given marketplace flow with stale local cache state #when running check #then starts npx repair instead of marketplace skip", async () => {
|
|
344
|
+
const { root, pluginRoot } = await makeStorePluginRoot("lazycodex-auto-update-marketplace-repair-");
|
|
345
|
+
const spawnLogPath = join(root, "spawn.log");
|
|
346
|
+
const binDir = join(root, "bin");
|
|
347
|
+
const codexHome = join(root, "codex-home");
|
|
348
|
+
const missingCachedCli = join(codexHome, "plugins", "cache", "sisyphuslabs", "omo", "1.0.1", "components", "ulw-loop", "dist", "cli.js");
|
|
349
|
+
await mkdir(join(codexHome, "plugins", "cache", "sisyphuslabs", ".agents", "plugins"), { recursive: true });
|
|
350
|
+
await mkdir(binDir, { recursive: true });
|
|
351
|
+
await writeFile(
|
|
352
|
+
join(codexHome, "plugins", "cache", "sisyphuslabs", ".agents", "plugins", "marketplace.json"),
|
|
353
|
+
JSON.stringify({
|
|
354
|
+
name: "sisyphuslabs",
|
|
355
|
+
plugins: [{ name: "omo", source: { source: "local", path: "./omo/1.0.1" } }],
|
|
356
|
+
}),
|
|
357
|
+
);
|
|
358
|
+
await symlink(missingCachedCli, join(binDir, "ulw"));
|
|
359
|
+
const env = marketplaceCheckEnv(root, pluginRoot, spawnLogPath, {
|
|
360
|
+
CODEX_HOME: codexHome,
|
|
361
|
+
CODEX_LOCAL_BIN_DIR: binDir,
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
const result = await runAutoUpdateCheck({ env, now: 123_456 });
|
|
365
|
+
|
|
366
|
+
assert.equal(result.started, true);
|
|
367
|
+
assert.equal(result.status, 0);
|
|
368
|
+
assert.equal(await readFile(spawnLogPath, "utf8"), "ok");
|
|
369
|
+
assert.equal(result.notices.length, 1);
|
|
370
|
+
assert.match(result.notices[0], /repair/i);
|
|
371
|
+
assert.match(result.notices[0], /stale local LazyCodex cache/i);
|
|
372
|
+
assert.match(result.notices[0], /bundled reinstall repair/);
|
|
373
|
+
assert.doesNotMatch(result.notices[0], /Repair command/);
|
|
374
|
+
assert.doesNotMatch(result.notices[0], /plugins[\\/]+cache[\\/]+sisyphuslabs/);
|
|
375
|
+
const logEntries = (await readFile(env.LAZYCODEX_AUTO_UPDATE_LOG_PATH, "utf8")).trim().split("\n").map((line) => JSON.parse(line));
|
|
376
|
+
assert.equal(logEntries[0].event, "started");
|
|
377
|
+
assert.equal(logEntries[0].kind, "marketplace-local-repair");
|
|
378
|
+
assert.equal(logEntries[0].command, undefined);
|
|
379
|
+
assert.equal(logEntries[0].args, undefined);
|
|
380
|
+
assert.deepEqual(logEntries[0].repairReasons, [
|
|
381
|
+
{ kind: "missing-marketplace-payload" },
|
|
382
|
+
{ kind: "dangling-managed-bin", binName: "ulw" },
|
|
383
|
+
]);
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
test("#given stale marketplace cache and recent success state #when resolving plan #then repair bypasses success throttle", async () => {
|
|
387
|
+
const { root, pluginRoot } = await makeStorePluginRoot("lazycodex-auto-update-marketplace-repair-throttle-");
|
|
388
|
+
const spawnLogPath = join(root, "spawn.log");
|
|
389
|
+
const codexHome = join(root, "codex-home");
|
|
390
|
+
await mkdir(join(codexHome, "plugins", "cache", "sisyphuslabs", ".agents", "plugins"), { recursive: true });
|
|
391
|
+
await writeFile(
|
|
392
|
+
join(codexHome, "plugins", "cache", "sisyphuslabs", ".agents", "plugins", "marketplace.json"),
|
|
393
|
+
JSON.stringify({
|
|
394
|
+
name: "sisyphuslabs",
|
|
395
|
+
plugins: [{ name: "omo", source: { source: "local", path: "./omo/1.0.1" } }],
|
|
396
|
+
}),
|
|
397
|
+
);
|
|
398
|
+
const env = marketplaceCheckEnv(root, pluginRoot, spawnLogPath, {
|
|
399
|
+
CODEX_HOME: codexHome,
|
|
400
|
+
LAZYCODEX_LATEST_VERSION: "1.0.1",
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
const plan = resolveAutoUpdatePlan({ env, now: 123_457, lastCheckedAt: 123_456, lastStatus: "success" });
|
|
404
|
+
|
|
405
|
+
assert.equal(plan.shouldRun, true);
|
|
406
|
+
assert.equal(plan.kind, "marketplace-local-repair");
|
|
407
|
+
assert.deepEqual(plan.repairReasons, [{ kind: "missing-marketplace-payload" }]);
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
test("#given stale marketplace cache and recent started state #when resolving plan #then repair honors retry throttle", async () => {
|
|
411
|
+
const { root, pluginRoot } = await makeStorePluginRoot("lazycodex-auto-update-marketplace-repair-retry-");
|
|
412
|
+
const spawnLogPath = join(root, "spawn.log");
|
|
413
|
+
const codexHome = join(root, "codex-home");
|
|
414
|
+
await mkdir(join(codexHome, "plugins", "cache", "sisyphuslabs", ".agents", "plugins"), { recursive: true });
|
|
415
|
+
await writeFile(
|
|
416
|
+
join(codexHome, "plugins", "cache", "sisyphuslabs", ".agents", "plugins", "marketplace.json"),
|
|
417
|
+
JSON.stringify({
|
|
418
|
+
name: "sisyphuslabs",
|
|
419
|
+
plugins: [{ name: "omo", source: { source: "local", path: "./omo/1.0.1" } }],
|
|
420
|
+
}),
|
|
421
|
+
);
|
|
422
|
+
const env = marketplaceCheckEnv(root, pluginRoot, spawnLogPath, {
|
|
423
|
+
CODEX_HOME: codexHome,
|
|
424
|
+
LAZYCODEX_LATEST_VERSION: "1.0.1",
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
const plan = resolveAutoUpdatePlan({ env, now: 123_457, lastAttemptedAt: 123_456, lastStatus: "started" });
|
|
428
|
+
|
|
429
|
+
assert.equal(plan.shouldRun, false);
|
|
430
|
+
assert.equal(plan.reason, "retry-throttled");
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
test("#given marketplace flow with stale Windows generated shim #when resolving plan #then starts local repair", async () => {
|
|
434
|
+
const { root, pluginRoot } = await makeStorePluginRoot("lazycodex-auto-update-marketplace-windows-repair-");
|
|
435
|
+
const spawnLogPath = join(root, "spawn.log");
|
|
436
|
+
const binDir = join(root, "bin");
|
|
437
|
+
const codexHome = join(root, "codex-home");
|
|
438
|
+
const missingCachedCli = join(codexHome, "plugins", "cache", "sisyphuslabs", "omo", "1.0.1", "components", "ulw-loop", "dist", "cli.js");
|
|
439
|
+
await mkdir(binDir, { recursive: true });
|
|
440
|
+
await writeFile(
|
|
441
|
+
join(binDir, "omo-ulw-loop.cmd"),
|
|
442
|
+
[
|
|
443
|
+
"@echo off",
|
|
444
|
+
":: generated by oh-my-openagent Codex installer",
|
|
445
|
+
`\"${missingCachedCli}\" %*`,
|
|
446
|
+
"",
|
|
447
|
+
].join("\r\n"),
|
|
448
|
+
);
|
|
449
|
+
const env = marketplaceCheckEnv(root, pluginRoot, spawnLogPath, {
|
|
450
|
+
CODEX_HOME: codexHome,
|
|
451
|
+
CODEX_LOCAL_BIN_DIR: binDir,
|
|
452
|
+
LAZYCODEX_LATEST_VERSION: "1.0.1",
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
const plan = resolveAutoUpdatePlan({ env, now: 123_456 });
|
|
456
|
+
|
|
457
|
+
assert.equal(plan.shouldRun, true);
|
|
458
|
+
assert.equal(plan.kind, "marketplace-local-repair");
|
|
459
|
+
assert.deepEqual(plan.repairReasons, [{ kind: "dangling-managed-bin", binName: "omo-ulw-loop" }]);
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
test("#given marketplace flow with non-managed stale cache-shaped bin #when resolving plan #then skips local repair", async () => {
|
|
463
|
+
const { root, pluginRoot } = await makeStorePluginRoot("lazycodex-auto-update-marketplace-user-bin-");
|
|
464
|
+
const spawnLogPath = join(root, "spawn.log");
|
|
465
|
+
const binDir = join(root, "bin");
|
|
466
|
+
const codexHome = join(root, "codex-home");
|
|
467
|
+
const missingCachedCli = join(codexHome, "plugins", "cache", "sisyphuslabs", "omo", "1.0.1", "components", "ulw-loop", "dist", "cli.js");
|
|
468
|
+
await mkdir(binDir, { recursive: true });
|
|
469
|
+
await symlink(missingCachedCli, join(binDir, "user-tool"));
|
|
470
|
+
const env = marketplaceCheckEnv(root, pluginRoot, spawnLogPath, {
|
|
471
|
+
CODEX_HOME: codexHome,
|
|
472
|
+
CODEX_LOCAL_BIN_DIR: binDir,
|
|
473
|
+
LAZYCODEX_LATEST_VERSION: "1.0.1",
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
const plan = resolveAutoUpdatePlan({ env, now: 123_456 });
|
|
477
|
+
|
|
478
|
+
assert.equal(plan.shouldRun, false);
|
|
479
|
+
assert.equal(plan.reason, "marketplace-flow");
|
|
480
|
+
});
|
|
481
|
+
|
|
332
482
|
test("#given install snapshot at plugin root #when running check #then npx update behavior is unchanged", async () => {
|
|
333
483
|
const { root, pluginRoot } = await makeStorePluginRoot("lazycodex-auto-update-npx-snapshot-");
|
|
334
484
|
await writeFile(join(pluginRoot, "lazycodex-install.json"), JSON.stringify({ packageName: "lazycodex-ai", version: "1.0.0" }));
|
|
@@ -25,13 +25,14 @@ export const expectedSkills = [
|
|
|
25
25
|
"start-work",
|
|
26
26
|
"teammode",
|
|
27
27
|
"ultimate-browsing",
|
|
28
|
-
"ultraresearch",
|
|
29
28
|
"ulw-loop",
|
|
30
29
|
"ulw-plan",
|
|
31
30
|
"ulw-research",
|
|
32
31
|
"visual-qa",
|
|
33
32
|
];
|
|
34
33
|
|
|
34
|
+
export const hiddenSharedSkills = ["ultraresearch"];
|
|
35
|
+
|
|
35
36
|
export const componentSkillSources = [
|
|
36
37
|
["comment-checker", "components/comment-checker/skills/comment-checker"],
|
|
37
38
|
["lsp", "components/lsp/skills/lsp"],
|
|
@@ -92,6 +93,22 @@ const reviewWorkCodexGatePattern =
|
|
|
92
93
|
/\nWhen `review-work` is used as a final implementation, PR, or `\$start-work`\ngate, it is blocking\. A timeout, missing deliverable, ack-only response,\nexplicit `BLOCKED:`, or inconclusive lane is not a pass\. Treat that lane as\nfailed, investigate the underlying uncertainty with the `debugging` skill when\nruntime behavior may be wrong, fix with evidence, and rerun the affected lane\nbefore claiming completion, creating or handing off a PR, or merging\.\n\nWhen reviewing a PR or branch, collect diff, file contents, and verification\nresults from a dedicated review worktree attached to that branch\. Never\ncheckout, test, or edit the review branch in the main worktree\.\n\nReview evidence must be safe to share\. Redact or mask secrets and sensitive\nuser data before including evidence in logs, PR bodies, or handoffs\. Never\ninclude raw tokens, credentials, auth headers, cookies, API keys, env dumps,\nprivate logs, or PII; summarize with lengths, hashes, and short non-sensitive\nprefixes when identity is needed\.\n/;
|
|
93
94
|
|
|
94
95
|
export function removeCodexSkillOverlays(skillName, content) {
|
|
96
|
+
if (skillName === "ulw-research") {
|
|
97
|
+
return content
|
|
98
|
+
.replace(
|
|
99
|
+
", any 'ulw' research wording,",
|
|
100
|
+
", the legacy alias 'ultraresearch', any 'ulw' research wording,",
|
|
101
|
+
)
|
|
102
|
+
.replace(
|
|
103
|
+
"the word \"ulw-research\" (also `/ulw-research`, `$ulw-research`), ",
|
|
104
|
+
"the word \"ulw-research\" (also `/ulw-research`, `$ulw-research`), the legacy alias \"ultraresearch\" (also `/ultraresearch`, `$ultraresearch`), ",
|
|
105
|
+
)
|
|
106
|
+
.replace(
|
|
107
|
+
"answer those normally, and mention that `ulw-research` is available when a question would clearly benefit from it.",
|
|
108
|
+
"answer those normally, and mention that `ulw-research` is available (legacy alias: `ultraresearch`) when a question would clearly benefit from it.",
|
|
109
|
+
)
|
|
110
|
+
.replace("# ULW-Research Synthesis: <query>", "# Ultraresearch Synthesis: <query>");
|
|
111
|
+
}
|
|
95
112
|
if (skillName === "start-work") {
|
|
96
113
|
return content
|
|
97
114
|
.replace(startWorkCodexCompletion, startWorkOriginalCompletion)
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
assertPackagedContentMatches,
|
|
10
10
|
componentSkillSources,
|
|
11
11
|
expectedSkills,
|
|
12
|
+
hiddenSharedSkills,
|
|
12
13
|
listSkillFiles,
|
|
13
14
|
removeCodexCompatibilityGuidance,
|
|
14
15
|
removeCodexSkillOverlays,
|
|
@@ -29,6 +30,13 @@ function excludeGeneratedSkillMetadata(files) {
|
|
|
29
30
|
return files.filter((file) => !generatedSkillMetadataFiles.has(file.replaceAll("\\", "/")));
|
|
30
31
|
}
|
|
31
32
|
|
|
33
|
+
async function assertNoLegacyResearchAliasInTree(rootDir, label) {
|
|
34
|
+
for (const file of await listSkillFiles(rootDir)) {
|
|
35
|
+
const content = await readFile(join(rootDir, file), "utf8");
|
|
36
|
+
assert.doesNotMatch(content, /ultraresearch/i, `${label}/${file} must not expose ultraresearch`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
32
40
|
test("#given synced aggregate Codex skills #when inspected #then component and shared skills are present", async () => {
|
|
33
41
|
// given
|
|
34
42
|
const skillsRoot = join(root, "skills");
|
|
@@ -47,6 +55,26 @@ test("#given synced aggregate Codex skills #when inspected #then component and s
|
|
|
47
55
|
}
|
|
48
56
|
});
|
|
49
57
|
|
|
58
|
+
test("#given reference-only designpowers frontend files #when synced for Codex #then nested SKILL.md files are not packaged", async () => {
|
|
59
|
+
// given
|
|
60
|
+
const frontendReferencesRoot = join(root, "skills", "frontend", "references");
|
|
61
|
+
const designpowersVendorSkillsRoot = join(frontendReferencesRoot, "designpowers", "vendor", "skills");
|
|
62
|
+
|
|
63
|
+
// when
|
|
64
|
+
const nestedSkillFiles = (await listSkillFiles(frontendReferencesRoot))
|
|
65
|
+
.map((file) => file.replaceAll("\\", "/"))
|
|
66
|
+
.filter((file) => file.endsWith("/SKILL.md") || file === "SKILL.md")
|
|
67
|
+
.sort();
|
|
68
|
+
const designpowersReferenceFiles = (await listSkillFiles(designpowersVendorSkillsRoot))
|
|
69
|
+
.map((file) => file.replaceAll("\\", "/"))
|
|
70
|
+
.filter((file) => file.endsWith("/reference.md"))
|
|
71
|
+
.sort();
|
|
72
|
+
|
|
73
|
+
// then
|
|
74
|
+
assert.deepEqual(nestedSkillFiles, []);
|
|
75
|
+
assert.equal(designpowersReferenceFiles.length, 27);
|
|
76
|
+
});
|
|
77
|
+
|
|
50
78
|
test("#given aggregate Codex skills #when source wiring is inspected #then shared skills are imported from the shared-skills package", async () => {
|
|
51
79
|
// given
|
|
52
80
|
const pluginPackageJson = JSON.parse(await readFile(join(root, "package.json"), "utf8"));
|
|
@@ -85,6 +113,7 @@ test("#given shared skill package source #when aggregate Codex shared skills are
|
|
|
85
113
|
// when / then
|
|
86
114
|
for (const skillName of sharedSkillNames) {
|
|
87
115
|
if (componentSkillNames.has(skillName)) continue;
|
|
116
|
+
if (hiddenSharedSkills.includes(skillName)) continue;
|
|
88
117
|
const sharedContent = await readFile(join(sharedSkillsRoot, skillName, "SKILL.md"), "utf8");
|
|
89
118
|
const aggregateContent = await readFile(join(aggregateSkillsRoot, skillName, "SKILL.md"), "utf8");
|
|
90
119
|
assert.equal(
|
|
@@ -145,7 +174,7 @@ test("#given component skill sources #when aggregate Codex component skills are
|
|
|
145
174
|
const sourceContent = await readFile(join(sourceDir, relativePath), "utf8");
|
|
146
175
|
const aggregateContent = await readFile(join(aggregateDir, relativePath), "utf8");
|
|
147
176
|
assert.equal(
|
|
148
|
-
removeCodexCompatibilityGuidance(aggregateContent),
|
|
177
|
+
removeCodexSkillOverlays(skillName, removeCodexCompatibilityGuidance(aggregateContent)),
|
|
149
178
|
removeCodexCompatibilityGuidance(sourceContent),
|
|
150
179
|
`${skillName}/${relativePath} drifted from its component skill source`,
|
|
151
180
|
);
|
|
@@ -181,18 +210,18 @@ test("#given synced ulw-loop skill #when Codex hint metadata is inspected #then
|
|
|
181
210
|
assert.match(interfaceMetadata, /- "ulw-loop"/);
|
|
182
211
|
});
|
|
183
212
|
|
|
184
|
-
test("#given
|
|
213
|
+
test("#given shipped Codex skill payloads #when legacy ultraresearch alias is inspected #then it is not packaged", async () => {
|
|
185
214
|
// given
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
// when
|
|
189
|
-
const skill = await readFile(join(skillRoot, "SKILL.md"), "utf8");
|
|
190
|
-
const interfaceMetadata = await readFile(join(skillRoot, "agents", "openai.yaml"), "utf8");
|
|
215
|
+
const skillsRoot = join(root, "skills");
|
|
216
|
+
const skillRoot = join(skillsRoot, "ultraresearch");
|
|
191
217
|
|
|
192
218
|
// then
|
|
193
|
-
assert.
|
|
194
|
-
assert.
|
|
195
|
-
|
|
219
|
+
await assert.rejects(readFile(join(skillRoot, "SKILL.md"), "utf8"), { code: "ENOENT" });
|
|
220
|
+
await assert.rejects(readFile(join(skillRoot, "agents", "openai.yaml"), "utf8"), { code: "ENOENT" });
|
|
221
|
+
await assertNoLegacyResearchAliasInTree(skillsRoot, "skills");
|
|
222
|
+
for (const [skillName, sourcePath] of componentSkillSources) {
|
|
223
|
+
await assertNoLegacyResearchAliasInTree(join(root, sourcePath), `components/${skillName}`);
|
|
224
|
+
}
|
|
196
225
|
});
|
|
197
226
|
|
|
198
227
|
test("#given synced git-master skill #when inspected #then commits and git history route through it", async () => {
|
|
@@ -77,7 +77,11 @@ test("#given ulw-research description #when activation policy is inspected #then
|
|
|
77
77
|
for (const copy of await readUlwResearchCopies()) {
|
|
78
78
|
const description = frontmatterDescription(copy.content);
|
|
79
79
|
assert.match(description, /ulw-research/i, `${copy.label}: description must name the ulw-research trigger`);
|
|
80
|
-
|
|
80
|
+
if (copy.label === "shared") {
|
|
81
|
+
assert.match(description, /ultraresearch/i, `${copy.label}: description must preserve ultraresearch discoverability`);
|
|
82
|
+
} else {
|
|
83
|
+
assert.doesNotMatch(description, /ultraresearch/i, `${copy.label}: description must not expose ultraresearch`);
|
|
84
|
+
}
|
|
81
85
|
assert.match(description, /\bulw\b/i, `${copy.label}: description must preserve ulw discoverability`);
|
|
82
86
|
assert.match(description, /explicit/i, `${copy.label}: description must gate activation on explicit demand`);
|
|
83
87
|
assert.match(
|
|
@@ -89,6 +93,20 @@ test("#given ulw-research description #when activation policy is inspected #then
|
|
|
89
93
|
}
|
|
90
94
|
});
|
|
91
95
|
|
|
96
|
+
test("#given packaged ulw-research skill #when scanned for legacy aliases #then ultraresearch is not exposed", async () => {
|
|
97
|
+
const packaged = (await readUlwResearchCopies()).find((copy) => copy.label === "packaged");
|
|
98
|
+
assert.notEqual(packaged, undefined, "packaged copy not found");
|
|
99
|
+
assert.doesNotMatch(packaged.content, /ultraresearch/i, "packaged ulw-research must not expose ultraresearch");
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test("#given packaged ulw-research skill #when Codex guidance is inspected #then compatibility guidance is preserved", async () => {
|
|
103
|
+
const packaged = (await readUlwResearchCopies()).find((copy) => copy.label === "packaged");
|
|
104
|
+
assert.notEqual(packaged, undefined, "packaged copy not found");
|
|
105
|
+
assert.match(packaged.content, /## Codex Harness Tool Compatibility/);
|
|
106
|
+
assert.match(packaged.content, /multi_agent_v1\.spawn_agent/);
|
|
107
|
+
assert.match(packaged.content, /multi_agent_v1\.wait_agent/);
|
|
108
|
+
});
|
|
109
|
+
|
|
92
110
|
test("#given ulw-research body #when authority is inspected #then it takes precedence over exploration-bounding instructions", async () => {
|
|
93
111
|
for (const copy of await readUlwResearchCopies()) {
|
|
94
112
|
assert.match(
|