docs(omo-codex): batch 93 (13 files)
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
# Normalize line endings: store LF in git, check out LF on every platform.
|
||||
# Required so biome's --check passes on Windows (default core.autocrlf=true).
|
||||
* text=auto eol=lf
|
||||
|
||||
# Explicit binary types
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.jpeg binary
|
||||
*.gif binary
|
||||
*.ico binary
|
||||
*.zip binary
|
||||
*.tgz binary
|
||||
*.gz binary
|
||||
@@ -0,0 +1,3 @@
|
||||
dist/
|
||||
node_modules/
|
||||
*.log
|
||||
@@ -0,0 +1,43 @@
|
||||
# Repository Conventions
|
||||
|
||||
Conventions for human contributors and AI agents working on this repository.
|
||||
|
||||
## Stack
|
||||
|
||||
- Node >=20 runtime.
|
||||
- npm package manager.
|
||||
- TypeScript 6 strict mode.
|
||||
- Biome 2 linting and formatting.
|
||||
- Vitest 4 test runner.
|
||||
|
||||
## Forbidden
|
||||
|
||||
- No `as any` or `as unknown`.
|
||||
- No `@ts-ignore` or `@ts-expect-error`.
|
||||
- No enums.
|
||||
- No non-null assertions.
|
||||
- No default exports. `vitest.config.ts` is exempt because the framework requires that shape.
|
||||
|
||||
## File Ceiling
|
||||
|
||||
- Keep each `src/` TypeScript file under 250 pure LOC.
|
||||
- Split by responsibility before a file reaches the ceiling.
|
||||
|
||||
## Test Discipline
|
||||
|
||||
- Use Vitest with nested `describe` names in `#given`, `#when`, and `#then` form, or inline `// given`, `// when`, and `// then` comments.
|
||||
- Never use Arrange-Act-Assert comments.
|
||||
- Keep fixtures in `test/fixtures/`.
|
||||
|
||||
## Build and Hooks
|
||||
|
||||
- Build output goes to `dist/`.
|
||||
- `hooks/hooks.json` registers Codex `Stop` and `SubagentStop` hooks.
|
||||
- Hook commands run `node ${PLUGIN_ROOT}/components/start-work-continuation/dist/cli.js hook stop` and `node ${PLUGIN_ROOT}/components/start-work-continuation/dist/cli.js hook subagent-stop`.
|
||||
|
||||
## Constraints
|
||||
|
||||
- Never let the hook block a Codex turn because of malformed input.
|
||||
- Never make a network call from the hook.
|
||||
- Keep the directive in `directive.md`. Do not inline it into TypeScript files.
|
||||
- The hook only continues sessions listed in `.omo/boulder.json` as `codex:<session_id>`.
|
||||
@@ -0,0 +1,5 @@
|
||||
# Changelog
|
||||
|
||||
## 0.1.0 - 2026-05-28
|
||||
|
||||
- Initial release: Stop and SubagentStop continuation injection.
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Yeongyu Kim
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,5 @@
|
||||
codex-start-work-continuation
|
||||
Copyright (c) 2026 Yeongyu Kim
|
||||
|
||||
This product includes software released under the MIT License.
|
||||
See LICENSE for the full text.
|
||||
@@ -0,0 +1,55 @@
|
||||
# codex-start-work-continuation
|
||||
|
||||
Codex Stop-hook continuation injector for the omo-codex `start-work` skill.
|
||||
|
||||
It reads `.omo/boulder.json` in the hook payload `cwd`, resolves the active work, inspects the active plan for incomplete top-level checkboxes, and emits Codex Stop-hook JSON when the plan still has work:
|
||||
|
||||
```json
|
||||
{"decision":"block","reason":"<directive>"}
|
||||
```
|
||||
|
||||
The `reason` is loaded from `directive.md` on every invocation and filled with current plan state. The hook returns no output when `stop_hook_active` is `true`, when no active Boulder work exists, when the work is completed, when the active work is not tied to `codex:<session_id>`, or when all top-level plan checkboxes are complete.
|
||||
|
||||
This pairs with the `start-work` skill at `plugin/skills/start-work/SKILL.md`. That skill writes `.omo/boulder.json` with Codex session ids prefixed as `codex:` so the hook can continue only its own active Codex session.
|
||||
|
||||
## Counted plan checkboxes
|
||||
|
||||
Only column-0 checkboxes under these sections are counted:
|
||||
|
||||
- `## TODOs`
|
||||
- `## Final Verification Wave`
|
||||
|
||||
Nested checkboxes under `### Acceptance Criteria`, `### Evidence`, and `### Definition of Done` are ignored.
|
||||
|
||||
## Smoke test
|
||||
|
||||
```bash
|
||||
TMP=$(mktemp -d)
|
||||
mkdir -p "$TMP/.omo/plans"
|
||||
cat > "$TMP/.omo/plans/test.md" <<EOF
|
||||
## TODOs
|
||||
- [ ] Task one
|
||||
- [ ] Task two
|
||||
EOF
|
||||
cat > "$TMP/.omo/boulder.json" <<EOF
|
||||
{"schema_version":2,"active_work_id":"w1","works":{"w1":{"work_id":"w1","active_plan":".omo/plans/test.md","plan_name":"test","session_ids":["codex:smoke-session"],"status":"active"}}}
|
||||
EOF
|
||||
PAYLOAD='{"session_id":"smoke-session","turn_id":"t1","transcript_path":"","cwd":"'"$TMP"'","hook_event_name":"Stop","model":"gpt-5.5","permission_mode":"default","stop_hook_active":false}'
|
||||
npm run build
|
||||
echo "$PAYLOAD" | node dist/cli.js hook stop
|
||||
|
||||
PAYLOAD_LOOP='{"session_id":"smoke-session","turn_id":"t1","transcript_path":"","cwd":"'"$TMP"'","hook_event_name":"Stop","model":"gpt-5.5","permission_mode":"default","stop_hook_active":true}'
|
||||
echo "$PAYLOAD_LOOP" | node dist/cli.js hook stop
|
||||
|
||||
rm -rf "$TMP"
|
||||
```
|
||||
|
||||
Expect the first command to print JSON containing `"decision":"block"`; expect the anti-loop command to print nothing.
|
||||
|
||||
## License
|
||||
|
||||
MIT. See `LICENSE`.
|
||||
|
||||
## Privacy
|
||||
|
||||
This plugin only reads local hook payloads, `.omo/boulder.json`, the active plan, and the bundled directive. It makes no network calls and stores no telemetry.
|
||||
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"$schema": "https://biomejs.dev/schemas/2.4.15/schema.json",
|
||||
"linter": {
|
||||
"enabled": true,
|
||||
"rules": {
|
||||
"recommended": true,
|
||||
"style": {
|
||||
"noDefaultExport": "error",
|
||||
"noEnum": "error",
|
||||
"noNonNullAssertion": "error",
|
||||
"useImportType": "error",
|
||||
"useConst": "error",
|
||||
"useNodejsImportProtocol": "off"
|
||||
},
|
||||
"complexity": {
|
||||
"useLiteralKeys": "off"
|
||||
},
|
||||
"suspicious": {
|
||||
"noExplicitAny": "error",
|
||||
"noTsIgnore": "error",
|
||||
"noControlCharactersInRegex": "off",
|
||||
"noEmptyInterface": "off"
|
||||
}
|
||||
}
|
||||
},
|
||||
"formatter": {
|
||||
"enabled": true,
|
||||
"formatWithErrors": false,
|
||||
"indentStyle": "tab",
|
||||
"indentWidth": 3,
|
||||
"lineWidth": 120
|
||||
},
|
||||
"files": {
|
||||
"includes": ["src/**/*.ts", "test/**/*.ts", "vitest.config.ts", "!**/node_modules/**/*", "!**/dist/**/*"]
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"includes": ["vitest.config.ts"],
|
||||
"linter": {
|
||||
"rules": {
|
||||
"style": {
|
||||
"noDefaultExport": "off"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<start-work-continuation>
|
||||
|
||||
You are mid-flight on a Prometheus work plan. The turn just ended without finishing the plan. This is an automatic continuation — keep going. Do NOT ask the user whether to continue; the contract is auto-continue until every top-level checkbox is `- [x]`.
|
||||
|
||||
# State
|
||||
|
||||
- Plan: `{{PLAN_NAME}}`
|
||||
- Plan file: `{{PLAN_PATH}}`
|
||||
- Boulder state: `{{BOULDER_PATH}}`
|
||||
- Remaining top-level checkboxes: `{{REMAINING_COUNT}}` of `{{TOTAL_COUNT}}`
|
||||
- Next incomplete task: `{{NEXT_TASK_LABEL}}`
|
||||
{{WORKTREE_BLOCK}}
|
||||
- Ledger: `{{LEDGER_PATH}}`
|
||||
- Your session id in boulder.json: `codex:{{SESSION_ID}}`
|
||||
|
||||
# What to do this turn
|
||||
|
||||
1. Read `{{PLAN_PATH}}` AND `{{LEDGER_PATH}}` first — ground truth for what remains and what evidence has already been recorded. The plan checkbox and the ledger are the only sources of truth; do not trust your own memory of prior turns.
|
||||
2. Pick the FIRST unchecked top-level checkbox in `## TODOs` or `## Final Verification Wave`. Ignore nested checkboxes under Acceptance Criteria / Evidence / Definition of Done.
|
||||
3. Follow the `start-work` skill in full. The skill is already loaded from your earlier turn — re-read its file at `packages/omo-codex/plugin/skills/start-work/SKILL.md` if you have lost context.
|
||||
4. Decompose the checkbox into atomic sub-tasks. Dispatch them in PARALLEL via `spawn_agent` calls in this same response unless a sub-task has a NAMED blocking dependency (input from another sub-task or shared file).
|
||||
5. Every sub-task message MUST include all 7 sections and name one Manual-QA channel with its exact tool and exact invocation (the literal `curl` / `send-keys` / `page.click` with concrete inputs and the binary PASS/FAIL observable), plus the applicable ultraqa adversarial classes, a captured artifact, and a cleanup receipt. Channels: HTTP call (`curl -i`); tmux (`send-keys` + `capture-pane`); browser use — use Chrome to drive the page, else download and use agent-browser (https://github.com/vercel-labs/agent-browser); computer use — OS-level GUI automation for a desktop app. Tests are the floor; the channel artifact plus probed adversarial classes are the ceiling. All are required.
|
||||
6. After verification of ALL sub-tasks under this checkbox: `apply_patch` the plan to change `- [ ]` → `- [x]`, re-read the plan to confirm the count decreased, append a `task-completed` line to the ledger, then continue.
|
||||
7. Do not start fresh on a sub-agent failure. Re-dispatch the same `task_name` with a fix-message: `FAILED: <exact error>` + `Diagnosis: <observation>` + `Fix: <instruction>`.
|
||||
|
||||
# Hard constraints
|
||||
|
||||
- No production code before a failing test exists. When the change touches existing behavior, PIN it first: write a baseline characterization test that passes on the unchanged code, with exact inputs, exact observable, and exact assertion. PIN → RED → GREEN → SURFACE.
|
||||
- No `--dry-run` as evidence. No "should work". No "tests pass" as completion proof.
|
||||
- No `as any` / `@ts-ignore` / `@ts-expect-error`. No deleting failing tests.
|
||||
- Probe every applicable ultraqa adversarial class (malformed input, prompt injection, cancel/resume, stale state, dirty worktree, hung or long commands, flaky tests, misleading success output, repeated interruptions) and capture the observable for each. A clean happy-path artifact alone is NOT a PASS when an applicable class went unprobed; record skipped classes with a one-line not-applicable reason.
|
||||
- Cleanup receipt is mandatory. Register each QA resource teardown (scripts, tmux assets, browser / agent-browser sessions, PIDs, ports, containers, temp dirs) as its own todo the moment it spawns, then execute it. Leftover PIDs / `tmux` sessions / browser contexts / bound ports / containers / temp dirs = BLOCKED, not PASS.
|
||||
- The worktree path (if set in boulder.json) governs every file edit and command. Do not stray into the main repo.
|
||||
- session_ids you write to boulder.json MUST be prefixed `codex:`. Bare ids on read are legacy `opencode:`.
|
||||
|
||||
# Stop conditions for THIS turn
|
||||
|
||||
- A top-level checkbox flipped to `- [x]` after the 5-phase QA gate (Phase 1 read, Phase 2 automated, Phase 3 channel scenario, Phase 4 adversarial-class probing, Phase 5 gate decision). Then the Stop hook will re-evaluate; if more checkboxes remain you will be continued again.
|
||||
- 3 same-failure cycles on one sub-task → escalate via `spawn_agent(agent_type="codex-ultrawork-reviewer", ...)` and stop dispatch.
|
||||
- Safety boundary (destructive command, secret exfiltration, production write) → stop and surface a safe substitute.
|
||||
- All top-level checkboxes `- [x]` AND (if gate triggered) `codex-ultrawork-reviewer` approved unconditionally → print the ORCHESTRATION COMPLETE block and end.
|
||||
|
||||
# Output discipline
|
||||
|
||||
- Surface only state changes: sub-agent dispatched, channel scenario PASS/FAIL with artifact path, checkbox marked, evidence appended to ledger.
|
||||
- Do NOT print "Should I continue?" — the Stop hook handles continuation.
|
||||
- Do NOT restate the full plan. Do NOT recap prior turns. The ledger and the plan file are the durable record.
|
||||
|
||||
Begin now. Pick the next checkbox, dispatch the parallel sub-agents, verify, mark, continue.
|
||||
|
||||
</start-work-continuation>
|
||||
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"name": "@code-yeongyu/codex-start-work-continuation",
|
||||
"version": "0.1.0",
|
||||
"description": "Codex Stop hook continuation injector for omo-codex start-work plans.",
|
||||
"type": "module",
|
||||
"packageManager": "npm@11.12.1",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/code-yeongyu/codex-start-work-continuation",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/code-yeongyu/codex-start-work-continuation.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/code-yeongyu/codex-start-work-continuation/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"codex",
|
||||
"codex-plugin",
|
||||
"start-work",
|
||||
"continuation",
|
||||
"hooks",
|
||||
"boulder"
|
||||
],
|
||||
"bin": {
|
||||
"omo-start-work-continuation": "./dist/cli.js"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc -p tsconfig.build.json",
|
||||
"test": "vitest --run",
|
||||
"test:watch": "vitest",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"lint": "biome check .",
|
||||
"lint:fix": "biome check --write .",
|
||||
"check": "tsc --noEmit && biome check . && npm run build"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"directive.md",
|
||||
"hooks",
|
||||
"README.md",
|
||||
"LICENSE",
|
||||
"NOTICE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "2.4.15",
|
||||
"@types/node": "^25.7.0",
|
||||
"typescript": "^6.0.3",
|
||||
"vitest": "^4.1.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"allowImportingTsExtensions": false,
|
||||
"declaration": true,
|
||||
"outDir": "dist",
|
||||
"rootDir": "src",
|
||||
"noEmit": false
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["test/**/*"]
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"lib": ["ESNext"],
|
||||
"strict": true,
|
||||
"exactOptionalPropertyTypes": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"noPropertyAccessFromIndexSignature": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"noImplicitOverride": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"esModuleInterop": true,
|
||||
"allowImportingTsExtensions": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"useDefineForClassFields": false,
|
||||
"types": ["node"],
|
||||
"noEmit": true
|
||||
},
|
||||
"include": ["src/**/*", "test/**/*", "vitest.config.ts"]
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { defineConfig } from "vitest/config";
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
include: ["test/**/*.test.ts"],
|
||||
environment: "node",
|
||||
pool: "threads",
|
||||
isolate: true,
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user