holo-codex 0.1.0

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.
Files changed (149) hide show
  1. package/.agents/plugins/marketplace.json +20 -0
  2. package/CONTRIBUTING.md +54 -0
  3. package/LICENSE +21 -0
  4. package/README.md +215 -0
  5. package/README.zh-CN.md +215 -0
  6. package/SECURITY.md +39 -0
  7. package/assets/brand/README.md +35 -0
  8. package/assets/brand/holo-codex-icon.svg +28 -0
  9. package/assets/brand/holo-codex-lockup.svg +49 -0
  10. package/assets/brand/holo-codex-mark.svg +33 -0
  11. package/assets/brand/holo-codex-plugin-card.png +0 -0
  12. package/assets/brand/holo-codex-plugin-card.svg +81 -0
  13. package/assets/brand/holo-codex-readme-hero.png +0 -0
  14. package/assets/brand/holo-codex-readme-hero.svg +140 -0
  15. package/assets/brand/holo-codex-social-preview.png +0 -0
  16. package/assets/brand/holo-codex-social-preview.svg +130 -0
  17. package/assets/brand/holo-codex-wordmark-options.svg +52 -0
  18. package/docs/checklists/agent-loop-first-delivery-audit.md +129 -0
  19. package/docs/examples/generic-loop-repo-hygiene.md +168 -0
  20. package/docs/install.md +190 -0
  21. package/docs/local-release-readiness.md +206 -0
  22. package/docs/release-checklist.md +144 -0
  23. package/docs/self-bootstrap.md +150 -0
  24. package/docs/trust-and-safety.md +45 -0
  25. package/package.json +83 -0
  26. package/plugins/autonomous-pr-loop/.codex-plugin/plugin.json +17 -0
  27. package/plugins/autonomous-pr-loop/.mcp.json +13 -0
  28. package/plugins/autonomous-pr-loop/bin/agent-loop.mjs +31 -0
  29. package/plugins/autonomous-pr-loop/core/artifacts.ts +164 -0
  30. package/plugins/autonomous-pr-loop/core/autonomy-policy.ts +206 -0
  31. package/plugins/autonomous-pr-loop/core/ci.ts +131 -0
  32. package/plugins/autonomous-pr-loop/core/cli-i18n.ts +123 -0
  33. package/plugins/autonomous-pr-loop/core/cli.ts +1413 -0
  34. package/plugins/autonomous-pr-loop/core/command-runner.ts +446 -0
  35. package/plugins/autonomous-pr-loop/core/command.ts +47 -0
  36. package/plugins/autonomous-pr-loop/core/config-editor.ts +140 -0
  37. package/plugins/autonomous-pr-loop/core/config.ts +293 -0
  38. package/plugins/autonomous-pr-loop/core/controller-host.ts +19 -0
  39. package/plugins/autonomous-pr-loop/core/dashboard-server.ts +536 -0
  40. package/plugins/autonomous-pr-loop/core/delivery-work-item.ts +217 -0
  41. package/plugins/autonomous-pr-loop/core/doctor.ts +335 -0
  42. package/plugins/autonomous-pr-loop/core/errors.ts +82 -0
  43. package/plugins/autonomous-pr-loop/core/gate-recovery.ts +176 -0
  44. package/plugins/autonomous-pr-loop/core/gates.ts +26 -0
  45. package/plugins/autonomous-pr-loop/core/generic-lifecycle.ts +399 -0
  46. package/plugins/autonomous-pr-loop/core/git.ts +213 -0
  47. package/plugins/autonomous-pr-loop/core/github.ts +269 -0
  48. package/plugins/autonomous-pr-loop/core/gitnexus.ts +90 -0
  49. package/plugins/autonomous-pr-loop/core/happy.ts +42 -0
  50. package/plugins/autonomous-pr-loop/core/hook-capture.ts +115 -0
  51. package/plugins/autonomous-pr-loop/core/hook-events.ts +22 -0
  52. package/plugins/autonomous-pr-loop/core/hook-installation.ts +85 -0
  53. package/plugins/autonomous-pr-loop/core/hook-observer.ts +84 -0
  54. package/plugins/autonomous-pr-loop/core/hook-policy.ts +423 -0
  55. package/plugins/autonomous-pr-loop/core/hook-router.ts +452 -0
  56. package/plugins/autonomous-pr-loop/core/index.ts +32 -0
  57. package/plugins/autonomous-pr-loop/core/local-install.ts +778 -0
  58. package/plugins/autonomous-pr-loop/core/locale.ts +60 -0
  59. package/plugins/autonomous-pr-loop/core/loop-shapes.ts +190 -0
  60. package/plugins/autonomous-pr-loop/core/mcp-controller.ts +1479 -0
  61. package/plugins/autonomous-pr-loop/core/notification-feed.ts +263 -0
  62. package/plugins/autonomous-pr-loop/core/plan-parser.ts +206 -0
  63. package/plugins/autonomous-pr-loop/core/plugin-paths.ts +32 -0
  64. package/plugins/autonomous-pr-loop/core/policy.ts +65 -0
  65. package/plugins/autonomous-pr-loop/core/pr-lifecycle.ts +464 -0
  66. package/plugins/autonomous-pr-loop/core/pr-selector.ts +284 -0
  67. package/plugins/autonomous-pr-loop/core/profiles.ts +439 -0
  68. package/plugins/autonomous-pr-loop/core/redaction.ts +17 -0
  69. package/plugins/autonomous-pr-loop/core/repo-root.ts +22 -0
  70. package/plugins/autonomous-pr-loop/core/review-comments.ts +77 -0
  71. package/plugins/autonomous-pr-loop/core/scope-guard.ts +179 -0
  72. package/plugins/autonomous-pr-loop/core/state-machine.ts +828 -0
  73. package/plugins/autonomous-pr-loop/core/state-types.ts +130 -0
  74. package/plugins/autonomous-pr-loop/core/storage.ts +2527 -0
  75. package/plugins/autonomous-pr-loop/core/types.ts +567 -0
  76. package/plugins/autonomous-pr-loop/core/worker-events.ts +412 -0
  77. package/plugins/autonomous-pr-loop/core/worker-policy.ts +72 -0
  78. package/plugins/autonomous-pr-loop/core/worker-prompts.ts +182 -0
  79. package/plugins/autonomous-pr-loop/core/worker.ts +809 -0
  80. package/plugins/autonomous-pr-loop/core/workflow-board.ts +1515 -0
  81. package/plugins/autonomous-pr-loop/hooks/dist/permission-request.js +2462 -0
  82. package/plugins/autonomous-pr-loop/hooks/dist/post-compact.js +2462 -0
  83. package/plugins/autonomous-pr-loop/hooks/dist/post-tool-use.js +2462 -0
  84. package/plugins/autonomous-pr-loop/hooks/dist/pre-compact.js +2462 -0
  85. package/plugins/autonomous-pr-loop/hooks/dist/pre-tool-use.js +3460 -0
  86. package/plugins/autonomous-pr-loop/hooks/dist/session-start.js +2462 -0
  87. package/plugins/autonomous-pr-loop/hooks/dist/stop.js +2462 -0
  88. package/plugins/autonomous-pr-loop/hooks/dist/user-prompt-submit.js +2462 -0
  89. package/plugins/autonomous-pr-loop/hooks/hooks.json +106 -0
  90. package/plugins/autonomous-pr-loop/hooks/observe-runner.ts +25 -0
  91. package/plugins/autonomous-pr-loop/hooks/permission-request.ts +4 -0
  92. package/plugins/autonomous-pr-loop/hooks/post-compact.ts +4 -0
  93. package/plugins/autonomous-pr-loop/hooks/post-tool-use.ts +4 -0
  94. package/plugins/autonomous-pr-loop/hooks/pre-compact.ts +4 -0
  95. package/plugins/autonomous-pr-loop/hooks/pre-tool-use.ts +44 -0
  96. package/plugins/autonomous-pr-loop/hooks/session-start.ts +4 -0
  97. package/plugins/autonomous-pr-loop/hooks/stop.ts +4 -0
  98. package/plugins/autonomous-pr-loop/hooks/user-prompt-submit.ts +4 -0
  99. package/plugins/autonomous-pr-loop/mcp-server/src/index.ts +87 -0
  100. package/plugins/autonomous-pr-loop/mcp-server/src/tools.ts +205 -0
  101. package/plugins/autonomous-pr-loop/package.json +9 -0
  102. package/plugins/autonomous-pr-loop/schemas/config.schema.json +74 -0
  103. package/plugins/autonomous-pr-loop/schemas/marketplace.schema.json +46 -0
  104. package/plugins/autonomous-pr-loop/schemas/plugin.schema.json +32 -0
  105. package/plugins/autonomous-pr-loop/schemas/state.schema.json +19 -0
  106. package/plugins/autonomous-pr-loop/schemas/worker-event.schema.json +19 -0
  107. package/plugins/autonomous-pr-loop/schemas/worker-result.schema.json +58 -0
  108. package/plugins/autonomous-pr-loop/scripts/agent-loop.ts +44 -0
  109. package/plugins/autonomous-pr-loop/skills/autonomous-pr-loop/SKILL.md +26 -0
  110. package/plugins/autonomous-pr-loop/skills/autonomous-pr-loop/agents/openai.yaml +6 -0
  111. package/plugins/autonomous-pr-loop/ui/index.html +26 -0
  112. package/plugins/autonomous-pr-loop/ui/public/favicon.svg +7 -0
  113. package/plugins/autonomous-pr-loop/ui/src/api.ts +639 -0
  114. package/plugins/autonomous-pr-loop/ui/src/app.tsx +238 -0
  115. package/plugins/autonomous-pr-loop/ui/src/components/ActivityBadge.tsx +31 -0
  116. package/plugins/autonomous-pr-loop/ui/src/components/BrandMark.tsx +36 -0
  117. package/plugins/autonomous-pr-loop/ui/src/components/Collapsible.tsx +6 -0
  118. package/plugins/autonomous-pr-loop/ui/src/components/CommandPreview.tsx +15 -0
  119. package/plugins/autonomous-pr-loop/ui/src/components/ConfigEditor.tsx +389 -0
  120. package/plugins/autonomous-pr-loop/ui/src/components/EmptyState.tsx +10 -0
  121. package/plugins/autonomous-pr-loop/ui/src/components/ErrorState.tsx +12 -0
  122. package/plugins/autonomous-pr-loop/ui/src/components/List.tsx +7 -0
  123. package/plugins/autonomous-pr-loop/ui/src/components/MetricRow.tsx +6 -0
  124. package/plugins/autonomous-pr-loop/ui/src/components/ResponsiveTable.tsx +65 -0
  125. package/plugins/autonomous-pr-loop/ui/src/components/RiskBadge.tsx +10 -0
  126. package/plugins/autonomous-pr-loop/ui/src/components/StatusBadge.tsx +29 -0
  127. package/plugins/autonomous-pr-loop/ui/src/components/TopMetric.tsx +10 -0
  128. package/plugins/autonomous-pr-loop/ui/src/fixtures.ts +1152 -0
  129. package/plugins/autonomous-pr-loop/ui/src/i18n.ts +1105 -0
  130. package/plugins/autonomous-pr-loop/ui/src/main.tsx +14 -0
  131. package/plugins/autonomous-pr-loop/ui/src/pages/CommandCenter.tsx +470 -0
  132. package/plugins/autonomous-pr-loop/ui/src/pages/CommandCenterParts.tsx +276 -0
  133. package/plugins/autonomous-pr-loop/ui/src/pages/agent-timeline/AgentTimelineView.tsx +73 -0
  134. package/plugins/autonomous-pr-loop/ui/src/pages/artifact-viewer/ArtifactViewer.tsx +44 -0
  135. package/plugins/autonomous-pr-loop/ui/src/pages/dry-run-preview/DryRunPreview.tsx +66 -0
  136. package/plugins/autonomous-pr-loop/ui/src/pages/event-ledger/EventLedger.tsx +17 -0
  137. package/plugins/autonomous-pr-loop/ui/src/pages/gate-center/GateCenter.tsx +34 -0
  138. package/plugins/autonomous-pr-loop/ui/src/pages/mission-control/MissionControl.tsx +104 -0
  139. package/plugins/autonomous-pr-loop/ui/src/pages/mission-control/WorkflowBoard.tsx +577 -0
  140. package/plugins/autonomous-pr-loop/ui/src/pages/notifications/NotificationsView.tsx +30 -0
  141. package/plugins/autonomous-pr-loop/ui/src/pages/plan-navigator/PlanNavigator.tsx +19 -0
  142. package/plugins/autonomous-pr-loop/ui/src/pages/policy-config/PolicyConfig.tsx +22 -0
  143. package/plugins/autonomous-pr-loop/ui/src/pages/pr-inbox/PrInbox.tsx +26 -0
  144. package/plugins/autonomous-pr-loop/ui/src/pages/recovery-center/RecoveryCenter.tsx +125 -0
  145. package/plugins/autonomous-pr-loop/ui/src/pages/scope-guard/ScopeGuard.tsx +16 -0
  146. package/plugins/autonomous-pr-loop/ui/src/pages/worker-runs/WorkerRuns.tsx +39 -0
  147. package/plugins/autonomous-pr-loop/ui/src/styles.css +2673 -0
  148. package/plugins/autonomous-pr-loop/ui/src/theme.ts +57 -0
  149. package/tsconfig.json +18 -0
@@ -0,0 +1,144 @@
1
+ # HOLO-Codex npm Release Checklist
2
+
3
+ Use this checklist for npm releases such as `v0.1.0`.
4
+
5
+ The public source release remains available at `https://github.com/tizerluo/HOLO-Codex`. The npm package is `holo-codex` and installs the stable `agent-loop` CLI. Compatibility identifiers remain unchanged: `agent-loop`, `.agent-loop/`, `autonomous-pr-loop`, and `plugins/autonomous-pr-loop/`.
6
+
7
+ ## Pre-Publish Validation
8
+
9
+ Run from the release checkout:
10
+
11
+ ```bash
12
+ pnpm install --frozen-lockfile
13
+ pnpm build:hooks
14
+ pnpm lint
15
+ pnpm test
16
+ npm pack --ignore-scripts --dry-run --json
17
+ npm view holo-codex name version dist-tags --json || true
18
+ ```
19
+
20
+ Before the first publish, `npm view holo-codex ...` should return `E404`. For later releases, confirm the registry version is lower than the version in `package.json`.
21
+
22
+ Review the pack output for accidental private material. The package must include the CLI, hooks dist, dashboard UI source, schemas, plugin metadata, MCP server, skills, public docs, and brand assets. It must not include tests, private planning/spec/research docs, `.agent-loop/`, raw logs, raw hook payloads, raw transcripts, or local backups.
23
+
24
+ Run a secret and local-state scan:
25
+
26
+ ```bash
27
+ rg -n "(ghp_|gho_|github_pat_|sk-[A-Za-z0-9]|dashboard token|AGENT_LOOP_MCP_TOKEN)" .
28
+ find . -path './.git' -prune -o -path './node_modules' -prune -o -name '.agent-loop' -print
29
+ ```
30
+
31
+ Expected result: no real tokens, no committed `.agent-loop/`, no raw hook payloads, no raw transcripts, no private handoff, and no historical `docs/plans/`, `docs/specs/`, or `docs/research/` material.
32
+
33
+ ## Tarball Smoke
34
+
35
+ ```bash
36
+ npm pack --ignore-scripts --json
37
+ tmp="$(mktemp -d)"
38
+ export CODEX_HOME="$tmp/codex-home"
39
+ mkdir -p "$tmp/target-repo"
40
+ git -C "$tmp/target-repo" init -b main
41
+ git -C "$tmp/target-repo" remote add origin https://github.com/example/holo-codex-smoke.git
42
+ npm install --prefix "$tmp/install" ./holo-codex-*.tgz
43
+ "$tmp/install/node_modules/.bin/agent-loop" --help
44
+ "$tmp/install/node_modules/.bin/agent-loop" --repo "$tmp/target-repo" init --json
45
+ "$tmp/install/node_modules/.bin/agent-loop" install-hooks --repo "$tmp/target-repo" --json
46
+ "$tmp/install/node_modules/.bin/agent-loop" --repo "$tmp/target-repo" local doctor --json
47
+ ```
48
+
49
+ Do not publish if this smoke fails.
50
+
51
+ ## Publish
52
+
53
+ Confirm npm authentication without printing tokens:
54
+
55
+ ```bash
56
+ npm whoami
57
+ npm ping --json
58
+ ```
59
+
60
+ Publish:
61
+
62
+ ```bash
63
+ npm publish --access public
64
+ ```
65
+
66
+ If npm requires 2FA, complete the interactive prompt locally. Do not paste npm tokens or one-time codes into docs, PR bodies, issue comments, commits, artifacts, or screenshots.
67
+
68
+ ## Post-Publish Smoke
69
+
70
+ Install from the registry in a fresh temporary prefix:
71
+
72
+ ```bash
73
+ tmp="$(mktemp -d)"
74
+ export CODEX_HOME="$tmp/codex-home"
75
+ mkdir -p "$tmp/target-repo"
76
+ git -C "$tmp/target-repo" init -b main
77
+ git -C "$tmp/target-repo" remote add origin https://github.com/example/holo-codex-smoke.git
78
+ npm install --prefix "$tmp/install" holo-codex
79
+ "$tmp/install/node_modules/.bin/agent-loop" --help
80
+ "$tmp/install/node_modules/.bin/agent-loop" local doctor --help
81
+ "$tmp/install/node_modules/.bin/agent-loop" --repo "$tmp/target-repo" init --json
82
+ "$tmp/install/node_modules/.bin/agent-loop" install-hooks --repo "$tmp/target-repo" --json
83
+ test -f "$tmp/install/node_modules/holo-codex/plugins/autonomous-pr-loop/.codex-plugin/plugin.json"
84
+ ```
85
+
86
+ Optional dashboard smoke:
87
+
88
+ ```bash
89
+ "$tmp/install/node_modules/.bin/agent-loop" --repo "$tmp/target-repo" dashboard
90
+ ```
91
+
92
+ Open the printed loopback URL and confirm Mission Control loads without a token in the URL. Do not copy the fallback token into release notes, screenshots, logs, or PR comments.
93
+
94
+ ## Source Install Smoke
95
+
96
+ Keep the source path working as a fallback and development path:
97
+
98
+ ```bash
99
+ git clone https://github.com/tizerluo/HOLO-Codex.git /tmp/holo-codex-release-smoke
100
+ cd /tmp/holo-codex-release-smoke
101
+ pnpm install --frozen-lockfile
102
+ pnpm lint
103
+ pnpm test
104
+ pnpm build:hooks
105
+ pnpm agent-loop local install --repo /path/to/sandbox-repo
106
+ agent-loop local doctor --repo /path/to/sandbox-repo
107
+ agent-loop --repo /path/to/sandbox-repo doctor
108
+ ```
109
+
110
+ ## Rollback Smoke
111
+
112
+ Use a fake or disposable `CODEX_HOME` unless a real rollback is explicitly intended:
113
+
114
+ ```bash
115
+ export CODEX_HOME=/tmp/holo-codex-release-codex-home
116
+ agent-loop local install --repo /path/to/sandbox-repo
117
+ agent-loop local snapshots
118
+ agent-loop local rollback --snapshot /path/to/snapshot
119
+ agent-loop local doctor --repo /path/to/sandbox-repo
120
+ ```
121
+
122
+ Expected result: hooks and binding registry restore from the snapshot, non-agent-loop hooks remain untouched, and malformed current hook files are preserved with a `.broken-<timestamp>` suffix when present.
123
+
124
+ ## GitHub Release
125
+
126
+ After publish and post-publish smoke pass:
127
+
128
+ ```bash
129
+ git tag v0.1.0
130
+ git push origin v0.1.0
131
+ gh release create v0.1.0 \
132
+ --repo tizerluo/HOLO-Codex \
133
+ --title "HOLO-Codex v0.1.0" \
134
+ --notes-file /path/to/release-notes.md
135
+ ```
136
+
137
+ Release notes must state:
138
+
139
+ - HOLO-Codex is an observable workflow loop control plane for long-running Codex work; PR delivery is the first bundled workflow.
140
+ - npm install path: `npm install --global holo-codex`.
141
+ - Source install path: `git clone https://github.com/tizerluo/HOLO-Codex.git`.
142
+ - Rollback uses `agent-loop local rollback --snapshot <snapshot>`.
143
+ - npm uninstall removes the package, but shared HOLO-Codex router entries in `~/.codex/hooks.json` must be removed manually only after all target repo bindings are gone.
144
+ - Runtime state, tokens, raw hook payloads, raw transcripts, and dashboard tokens must not be committed or shared.
@@ -0,0 +1,150 @@
1
+ # HOLO-Codex Self-Bootstrapping Workflow
2
+
3
+ 这份 runbook 说明 HOLO-Codex 如何使用自己的 `agent-loop` 交付流程维护自己。
4
+
5
+ 默认下一项工作来源是 **GitHub issues**。历史 plans/specs/research 不属于公开源码树;只有 issue 明确要求新增公开设计文档时,才新增新的公开文档。
6
+
7
+ ## 启动一次自举维护
8
+
9
+ 先从干净且最新的 `main` 开始:
10
+
11
+ ```bash
12
+ git status --short --branch
13
+ git switch main
14
+ git pull --ff-only origin main
15
+ pnpm agent-loop status --json
16
+ pnpm agent-loop observe --json
17
+ gh issue list --repo tizerluo/HOLO-Codex --state open --limit 30
18
+ ```
19
+
20
+ 如果目标是审计一次 dashboard-first 或 agent-loop-first 交付,使用 [Agent-loop-first Delivery Audit Checklist](./checklists/agent-loop-first-delivery-audit.md) 记录检查动作、证据位置和 PASS/PARTIAL/GAP 结论。
21
+
22
+ 如果 status 是 `BLOCKED`,不要直接开新实现分支。先通过 `status`、`observe`、`timeline`、`workers` 检查 gate:
23
+
24
+ ```bash
25
+ pnpm agent-loop timeline --limit 20 --json
26
+ pnpm agent-loop workers --events --json
27
+ ```
28
+
29
+ 如果 active terminal worker gate 已经过时,可以显式 recovery,再决定是否 resume:
30
+
31
+ ```bash
32
+ pnpm agent-loop recover --json
33
+ pnpm agent-loop resume
34
+ ```
35
+
36
+ 如果 gate 仍然有效,应该 stop run,或带 note approve gate。不要只在聊天里绕过 active gate;每个决定都必须留下 CLI、dashboard、event 或 PR 记录。
37
+
38
+ ## 选择下一项工作
39
+
40
+ 选择顺序:
41
+
42
+ 1. 用户明确指定的 issue 优先。
43
+ 2. 否则从 open GitHub issues 中,结合当前 handoff 优先级选择。
44
+ 3. manual goal 只用于很小的人工 override;如果目标不小,先创建或选择 GitHub issue。
45
+ 4. 公开源码树不依赖历史 `docs/specs` 或 `docs/plans` 队列;需要设计背景时,以当前 issue 和公开 docs 为准。
46
+
47
+ 开工前读取 issue body、当前 handoff 和相关文档。保持一个 issue 一个 PR。相关且安全的小发现应尽量在当前 PR 修掉,不要制造不必要的 follow-up issue。
48
+
49
+ 真实 `$pr-delivery-loop` 工作应先绑定 dashboard-visible run:
50
+
51
+ ```bash
52
+ pnpm agent-loop init
53
+ pnpm agent-loop install-hooks --repo "$PWD" --json
54
+ pnpm agent-loop delivery bind \
55
+ --issue ISSUE_NUMBER \
56
+ --title "Issue title" \
57
+ --url https://github.com/tizerluo/HOLO-Codex/issues/ISSUE_NUMBER \
58
+ --json
59
+ ```
60
+
61
+ Fresh repo 必须先 `init`,否则 `delivery bind` 没有 `.agent-loop/config.json` 和本地 SQLite 状态可写。已有 `.agent-loop/` 的仓库可以跳过重复初始化。
62
+
63
+ 后续手工 commander 动作、review report、CI/merge readiness 和 cleanup 应记录到同一个 run。阶段开始和完成优先使用 `pnpm agent-loop delivery stage ...`,让 Mission Control 在文件编辑前就能显示当前阶段:
64
+
65
+ ```bash
66
+ pnpm agent-loop delivery stage \
67
+ --run RUN_ID \
68
+ --stage build \
69
+ --substage implementation_active \
70
+ --status active \
71
+ --summary "Implementation started after plan approval." \
72
+ --json
73
+ ```
74
+
75
+ 普通证据、review report、CI/merge readiness 和 cleanup 仍可用 `pnpm agent-loop evidence append ...`。PR body、PR owner comment、tester/reviewer/Claude/AGY report comment 都应包含 run id,方便 GitHub 和 dashboard 互相对照。
76
+
77
+ Review/tester report 不只写自由文本 summary。派发、启动、完成、跳过或失败都应写结构化 review evidence:
78
+
79
+ ```bash
80
+ pnpm agent-loop evidence append \
81
+ --run RUN_ID \
82
+ --stage review \
83
+ --substage claude_acp_review \
84
+ --reviewer claude_acp \
85
+ --requirement required \
86
+ --progress complete \
87
+ --result pass \
88
+ --severity none \
89
+ --comment-url "https://github.com/OWNER/REPO/pull/PR#issuecomment-ID" \
90
+ --summary "Claude ACP review completed with PASS." \
91
+ --json
92
+ ```
93
+
94
+ `complete` review evidence 必须链接 PR issue comment;`block` 或 `p2_or_higher` 会让 merge readiness 保持阻塞,直到同 PR 修复或按规则路由。
95
+
96
+ ## 交付一个 PR
97
+
98
+ 每个 issue 使用这条 loop:
99
+
100
+ ```text
101
+ read issue and handoff
102
+ -> run GitNexus impact for code symbols to be edited
103
+ -> write or update the development plan
104
+ -> create branch from main
105
+ -> implement
106
+ -> run focused tests
107
+ -> run independent tester/reviewer when useful or requested
108
+ -> fix all real P0/P1/P2 findings
109
+ -> run pnpm lint, pnpm test, and GitNexus detect
110
+ -> commit, push, open PR
111
+ -> wait for CI/review
112
+ -> fix any CI/review blocker in the same PR
113
+ -> merge
114
+ -> switch main, pull, rebuild GitNexus index
115
+ ```
116
+
117
+ 合并后的固定收尾:
118
+
119
+ ```bash
120
+ git switch main
121
+ git pull --ff-only origin main
122
+ npx gitnexus analyze
123
+ git status --short --branch
124
+ ```
125
+
126
+ ## Review 和 follow-up 纪律
127
+
128
+ - P0/P1 必须在当前 PR 修。
129
+ - P2 如果相关且安全,应在当前 PR 修。
130
+ - 只有当问题真实、超出当前 issue、且不能安全地在当前 PR 完成时,才创建 follow-up issue。
131
+ - P3 polish 如果很小,通常直接在当前 PR 修;否则只记录,不制造 issue 噪音。
132
+ - CI failure 永远不是当前 PR 的非阻塞 follow-up。
133
+
134
+ ## CLI 安全注意
135
+
136
+ Mutating commands 包括 `recover`、`approve-gate`、`resume`、`stop`、`run`、`step`、`install-hooks`、`hooks install-router`、`hooks bind`、`hooks unbind`。`--help` 必须只打印 usage,不能修改 `.agent-loop` 状态或 hook registry。
137
+
138
+ Dashboard URL 只绑定 loopback。token 是本地 session secret,不能写入 commit、PR body、docs、logs、artifacts 或截图。
139
+
140
+ ## 修改本 runbook 时的验证
141
+
142
+ ```bash
143
+ pnpm test plugins/autonomous-pr-loop/tests/cli-run.test.ts
144
+ pnpm lint
145
+ pnpm test
146
+ pnpm agent-loop status --json
147
+ pnpm agent-loop observe --json
148
+ ```
149
+
150
+ 只有 PR 改 dashboard UI 或 live dashboard 行为时,才需要 Browser 验收。
@@ -0,0 +1,45 @@
1
+ # Trust And Safety
2
+
3
+ English: Safety boundaries keep workers scoped, supervisor actions auditable, and secrets out of durable artifacts.
4
+
5
+ 中文:安全边界确保 worker 只做受控实现,supervisor 操作可审计,密钥不会进入持久化 artifacts。
6
+
7
+ See also: [README](../README.md) / [中文 README](../README.zh-CN.md).
8
+
9
+ ## Worker Boundary
10
+
11
+ Delegated workers may edit workspace files and return structured results. They must not commit, push, create PRs, mark PRs ready, or merge. The supervisor owns Git and GitHub lifecycle actions.
12
+
13
+ Worker prompts, command policy, Codex sandboxing, and PR E hooks all reinforce this boundary.
14
+
15
+ ## Hooks Coverage
16
+
17
+ Hooks cover the Codex tool loop only. `PreToolUse` blocks destructive Git/GitHub commands and lifecycle actions when state gates are not satisfied.
18
+
19
+ Hooks do not intercept commands a user runs in an external Terminal.
20
+
21
+ ## MCP Mutations
22
+
23
+ Mutating MCP tools require `AGENT_LOOP_MCP_TOKEN`. Calls without the matching token return `needs_secret_or_login` and do not update loop state.
24
+
25
+ ## Merge Safety
26
+
27
+ `mergeMode` is the canonical merge policy. Legacy `allowAutoMerge` is accepted only as compatibility input. Merge still requires review, CI, open-comment, scope, and policy gates to pass.
28
+
29
+ ## Generic Loop Safety
30
+
31
+ `generic-loop` uses the same supervisor, storage, gate, artifact, and audit boundaries as `pr-loop`. Planning and review states run read-only. Write-capable generic states require profile-scoped write roots and still pass through scope guard and hook policy.
32
+
33
+ ## Dashboard Tokens
34
+
35
+ `agent-loop dashboard` prints the loopback URL on stdout and the session token on stderr. The dashboard login stores the token in browser localStorage and sends it as `x-agent-loop-token`. Mutation endpoints still require the token and loopback/origin guard. CLI `observe --json`, audit export, and normal dashboard URLs do not include the token.
36
+
37
+ ## Secrets And Logs
38
+
39
+ Do not write secrets to code, docs, reports, logs, artifacts, commits, or PR bodies. Store local credentials in the operating system keychain or the user's configured secret manager.
40
+
41
+ Command output may be stored as `.agent-loop/` artifacts. Review output before sharing it outside the local machine.
42
+
43
+ ## Runtime State
44
+
45
+ `.agent-loop/`, SQLite state files, WAL/SHM files, raw worker JSONL, and hook logs are runtime data and must not be committed.
package/package.json ADDED
@@ -0,0 +1,83 @@
1
+ {
2
+ "name": "holo-codex",
3
+ "version": "0.1.0",
4
+ "description": "Human On Loop Codex control plane for observable, recoverable Codex workflow loops.",
5
+ "license": "MIT",
6
+ "author": "tizerluo",
7
+ "homepage": "https://github.com/tizerluo/HOLO-Codex#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/tizerluo/HOLO-Codex.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/tizerluo/HOLO-Codex/issues"
14
+ },
15
+ "keywords": [
16
+ "codex",
17
+ "codex-plugin",
18
+ "agent",
19
+ "workflow",
20
+ "human-on-loop",
21
+ "observability",
22
+ "automation"
23
+ ],
24
+ "type": "module",
25
+ "bin": {
26
+ "agent-loop": "plugins/autonomous-pr-loop/bin/agent-loop.mjs"
27
+ },
28
+ "files": [
29
+ "README.md",
30
+ "README.zh-CN.md",
31
+ "LICENSE",
32
+ "SECURITY.md",
33
+ "CONTRIBUTING.md",
34
+ "assets/brand/",
35
+ "docs/checklists/",
36
+ "docs/examples/",
37
+ "docs/install.md",
38
+ "docs/local-release-readiness.md",
39
+ "docs/release-checklist.md",
40
+ "docs/self-bootstrap.md",
41
+ "docs/trust-and-safety.md",
42
+ ".agents/plugins/marketplace.json",
43
+ "plugins/autonomous-pr-loop/.codex-plugin/",
44
+ "plugins/autonomous-pr-loop/.mcp.json",
45
+ "plugins/autonomous-pr-loop/bin/",
46
+ "plugins/autonomous-pr-loop/core/",
47
+ "plugins/autonomous-pr-loop/hooks/",
48
+ "plugins/autonomous-pr-loop/mcp-server/",
49
+ "plugins/autonomous-pr-loop/package.json",
50
+ "plugins/autonomous-pr-loop/schemas/",
51
+ "plugins/autonomous-pr-loop/scripts/",
52
+ "plugins/autonomous-pr-loop/skills/",
53
+ "plugins/autonomous-pr-loop/ui/",
54
+ "tsconfig.json"
55
+ ],
56
+ "engines": {
57
+ "node": ">=22.5"
58
+ },
59
+ "scripts": {
60
+ "agent-loop": "tsx plugins/autonomous-pr-loop/scripts/agent-loop.ts",
61
+ "build:hooks": "esbuild plugins/autonomous-pr-loop/hooks/pre-tool-use.ts plugins/autonomous-pr-loop/hooks/post-tool-use.ts plugins/autonomous-pr-loop/hooks/user-prompt-submit.ts plugins/autonomous-pr-loop/hooks/stop.ts plugins/autonomous-pr-loop/hooks/session-start.ts plugins/autonomous-pr-loop/hooks/pre-compact.ts plugins/autonomous-pr-loop/hooks/post-compact.ts plugins/autonomous-pr-loop/hooks/permission-request.ts --bundle --platform=node --format=esm --outdir=plugins/autonomous-pr-loop/hooks/dist",
62
+ "prepack": "pnpm build:hooks",
63
+ "test": "vitest run",
64
+ "lint": "tsc --noEmit"
65
+ },
66
+ "dependencies": {
67
+ "lucide-react": "^1.17.0",
68
+ "react": "^19.2.7",
69
+ "react-dom": "^19.2.7",
70
+ "tsx": "^4.21.0",
71
+ "vite": "^8.0.16"
72
+ },
73
+ "devDependencies": {
74
+ "@testing-library/react": "^16.3.2",
75
+ "@types/node": "^25.0.1",
76
+ "@types/react": "^19.2.17",
77
+ "@types/react-dom": "^19.2.3",
78
+ "esbuild": "^0.28.1",
79
+ "jsdom": "^29.1.1",
80
+ "typescript": "^5.9.3",
81
+ "vitest": "^4.0.15"
82
+ }
83
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "autonomous-pr-loop",
3
+ "version": "0.1.0",
4
+ "description": "Human On Loop Codex control plane for observable, recoverable Codex workflow loops.",
5
+ "skills": "./skills/",
6
+ "interface": {
7
+ "displayName": "HOLO-Codex",
8
+ "shortDescription": "Turn long-running Codex workflows into observable Human On Loop systems.",
9
+ "longDescription": "A portable Codex plugin for durable workflow state, gates, evidence, hooks, worker orchestration, and the first bundled PR delivery workflow.",
10
+ "developerName": "tizerluo",
11
+ "category": "Engineering",
12
+ "capabilities": ["Write"],
13
+ "defaultPrompt": ["进入 HOLO-Codex,继续跑到 gate"],
14
+ "screenshots": ["../../../assets/brand/holo-codex-plugin-card.png"],
15
+ "brandColor": "#2563EB"
16
+ }
17
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "mcpServers": {
3
+ "autonomous-pr-loop": {
4
+ "cwd": ".",
5
+ "command": "pnpm",
6
+ "args": [
7
+ "exec",
8
+ "tsx",
9
+ "./mcp-server/src/index.ts"
10
+ ]
11
+ }
12
+ }
13
+ }
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env node
2
+ import { spawn } from "node:child_process";
3
+ import { createRequire } from "node:module";
4
+ import { dirname, resolve } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+
7
+ const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "../../..");
8
+ const script = resolve(packageRoot, "plugins/autonomous-pr-loop/scripts/agent-loop.ts");
9
+ const require = createRequire(import.meta.url);
10
+ const tsxLoader = require.resolve("tsx");
11
+ const child = spawn(process.execPath, ["--import", tsxLoader, script, ...process.argv.slice(2)], {
12
+ cwd: process.cwd(),
13
+ env: process.env,
14
+ stdio: "inherit"
15
+ });
16
+
17
+ process.on("SIGINT", () => {});
18
+ process.on("SIGTERM", () => {});
19
+
20
+ child.on("exit", (code, signal) => {
21
+ if (signal) {
22
+ process.kill(process.pid, signal);
23
+ return;
24
+ }
25
+ process.exit(code ?? 1);
26
+ });
27
+
28
+ child.on("error", (error) => {
29
+ process.stderr.write(`agent-loop: failed to start CLI runner: ${error.message}\n`);
30
+ process.exitCode = 1;
31
+ });
@@ -0,0 +1,164 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ import { AgentLoopError } from "./errors.js";
5
+ import { ARTIFACT_KINDS, type ArtifactKind, type ArtifactRecord } from "./state-types.js";
6
+ import type { AgentLoopStorage } from "./types.js";
7
+
8
+ export interface ArtifactWriter {
9
+ id: string;
10
+ path: string;
11
+ append(content: string | Buffer): void;
12
+ finalize(): ArtifactRecord;
13
+ }
14
+
15
+ /** Write a run artifact to disk, persist metadata, and return its record. */
16
+ export function writeArtifact(
17
+ repoRoot: string,
18
+ storage: AgentLoopStorage,
19
+ runId: string,
20
+ kind: ArtifactKind,
21
+ name: string,
22
+ content: string | Buffer
23
+ ): ArtifactRecord {
24
+ assertArtifactKind(kind);
25
+ const id = randomUUID();
26
+ const safeName = sanitizeName(name);
27
+ const path = join(repoRoot, ".agent-loop", "artifacts", runId, kind, safeName);
28
+ mkdirSync(dirname(path), { recursive: true });
29
+ writeFileSync(path, content);
30
+ const record = {
31
+ id,
32
+ runId,
33
+ kind,
34
+ name: safeName,
35
+ path,
36
+ sha256: sha256(readFileSync(path)),
37
+ createdAt: new Date().toISOString()
38
+ };
39
+ storage.insertArtifact(record);
40
+ return record;
41
+ }
42
+
43
+ /** Create an artifact file that can be appended while work is still running. */
44
+ export function createArtifactWriter(
45
+ repoRoot: string,
46
+ storage: AgentLoopStorage,
47
+ runId: string,
48
+ kind: ArtifactKind,
49
+ name: string
50
+ ): ArtifactWriter {
51
+ assertArtifactKind(kind);
52
+ const id = randomUUID();
53
+ const safeName = sanitizeName(name);
54
+ const path = join(repoRoot, ".agent-loop", "artifacts", runId, kind, safeName);
55
+ const hash = createHash("sha256");
56
+ let finalized: ArtifactRecord | undefined;
57
+ mkdirSync(dirname(path), { recursive: true });
58
+ writeFileSync(path, "");
59
+ return {
60
+ id,
61
+ path,
62
+ append(content: string | Buffer): void {
63
+ if (finalized) {
64
+ throw new AgentLoopError("artifact_integrity_error", `Artifact writer is already finalized: ${id}`);
65
+ }
66
+ appendFileSync(path, content);
67
+ hash.update(content);
68
+ },
69
+ finalize(): ArtifactRecord {
70
+ if (finalized) {
71
+ return finalized;
72
+ }
73
+ finalized = {
74
+ id,
75
+ runId,
76
+ kind,
77
+ name: safeName,
78
+ path,
79
+ sha256: hash.digest("hex"),
80
+ createdAt: new Date().toISOString()
81
+ };
82
+ storage.insertArtifact(finalized);
83
+ return finalized;
84
+ }
85
+ };
86
+ }
87
+
88
+ /** Read an artifact and verify the stored sha256 digest before returning content. */
89
+ export function readArtifact(
90
+ storage: AgentLoopStorage,
91
+ artifactId: string
92
+ ): { record: ArtifactRecord; content: Buffer } {
93
+ const record = readArtifactRecord(storage, artifactId);
94
+ if (!existsSync(record.path)) {
95
+ throw new AgentLoopError("artifact_integrity_error", `Artifact file is missing: ${record.id}`);
96
+ }
97
+ const content = readFileSync(record.path);
98
+ const actual = sha256(content);
99
+ if (actual !== record.sha256) {
100
+ throw new AgentLoopError("artifact_integrity_error", `Artifact sha256 mismatch: ${record.id}`, {
101
+ details: { expected: record.sha256, actual }
102
+ });
103
+ }
104
+ return { record: toArtifactRecord(record), content };
105
+ }
106
+
107
+ /** List artifacts for a run. */
108
+ export function listArtifacts(
109
+ storage: AgentLoopStorage,
110
+ runId: string
111
+ ): ArtifactRecord[] {
112
+ return storage.listArtifacts(runId).map(toArtifactRecord);
113
+ }
114
+
115
+ /** Link a persisted artifact id to an event. */
116
+ export function linkArtifactToEvent(
117
+ storage: AgentLoopStorage,
118
+ eventId: string,
119
+ artifactId: string
120
+ ): void {
121
+ storage.linkArtifactToEvent(eventId, artifactId);
122
+ }
123
+
124
+ function sha256(content: Buffer): string {
125
+ return createHash("sha256").update(content).digest("hex");
126
+ }
127
+
128
+ function sanitizeName(name: string): string {
129
+ return name.replaceAll("\\", "/").split("/").filter(Boolean).join("-");
130
+ }
131
+
132
+ function assertArtifactKind(kind: string): asserts kind is ArtifactKind {
133
+ if (!(ARTIFACT_KINDS as readonly string[]).includes(kind)) {
134
+ throw new AgentLoopError("storage_error", `Unsupported artifact kind: ${kind}`);
135
+ }
136
+ }
137
+
138
+ function readArtifactRecord(storage: AgentLoopStorage, artifactId: string): ReturnType<AgentLoopStorage["getArtifact"]> {
139
+ try {
140
+ return storage.getArtifact(artifactId);
141
+ } catch (error) {
142
+ if (error instanceof AgentLoopError) {
143
+ throw new AgentLoopError("artifact_integrity_error", `Artifact metadata is unavailable: ${artifactId}`, {
144
+ details: { cause: error.message, code: error.code }
145
+ });
146
+ }
147
+ throw error;
148
+ }
149
+ }
150
+
151
+ function toArtifactRecord(record: {
152
+ id: string;
153
+ runId: string;
154
+ kind: string;
155
+ name: string;
156
+ path: string;
157
+ sha256: string;
158
+ createdAt: string;
159
+ }): ArtifactRecord {
160
+ return {
161
+ ...record,
162
+ kind: record.kind as ArtifactKind
163
+ };
164
+ }