Commit Graph

68 Commits

Author SHA1 Message Date
Danny Kim 0ee3ac7687 Update the root-only test count in the note description
Check / check (pull_request) Successful in 47s
2026-10-18 03:05:37 +09:00
Danny Kim 4a88458a8f Stop installing Deno in the action 2026-10-18 03:05:36 +09:00
Danny Kim 7d25b759fb Spawn child processes directly and drop the Deno.Command shim 2026-10-18 03:05:36 +09:00
Danny Kim 6ad859be62 Set the agreed tsconfig strictness flags and drop exactOptionalPropertyTypes
Check / check (pull_request) Successful in 44s
2026-10-18 03:05:15 +09:00
Danny Kim 8b5c249248 Note the planned modules plugin and fix a sentence case in the alias notes
Check / check (pull_request) Successful in 38s
2026-10-17 23:14:27 +09:00
Danny Kim 5af53b0882 Wrap the long doc comment lines in the project lint plugin 2026-10-17 23:14:27 +09:00
Danny Kim eba9b9c57c Keep main's one-line guards where no rule needs braces
Check / check (pull_request) Successful in 37s
2026-10-17 18:52:49 +09:00
Danny Kim 3cbe4171ea Describe the Deno size limits in the notes 2026-10-17 18:50:24 +09:00
Danny Kim cd1864e1a9 Restore helper layout in auth, isolation, runtime, and profiles from main 2026-10-17 18:49:28 +09:00
Danny Kim 0c5059e3b4 Restore post.ts from main 2026-10-17 18:48:15 +09:00
Danny Kim c6fc183ad6 Restore run.ts from main 2026-10-17 18:46:52 +09:00
Danny Kim 1f54518320 Match Deno size limits 2026-10-17 18:46:52 +09:00
Danny Kim 999a089374 Prune notes that don't apply to bot-agents and keep aliases on direct src subfolders
Check / check (pull_request) Successful in 38s
2026-10-17 18:12:47 +09:00
Danny Kim 166476dee9 State alias rule v2 in AGENTS.md
Check / check (pull_request) Successful in 37s
2026-10-17 16:02:20 +09:00
Danny Kim c778c00068 Allow .mts and .mjs imports in no-asset-imports
Check / check (pull_request) Successful in 42s
2026-10-17 15:59:45 +09:00
Danny Kim 6b87ff66b9 Fix the quoted old rule name in the alias notes
Check / check (pull_request) Successful in 2m30s
2026-10-17 15:46:05 +09:00
Danny Kim d2d3cbffdb Switch to the renamed @cunarist/eslint-plugin-modules
Check / check (pull_request) Successful in 2m10s
2026-10-17 15:43:47 +09:00
Danny Kim bfa8269801 Route tests through a #testing alias, ban ../ imports, and document the alias ownership rule
Check / check (pull_request) Successful in 46s
2026-10-17 14:45:52 +09:00
Danny Kim 15fe481181 Prune migration notes and align the notes with the current lint setup
Check / check (pull_request) Successful in 39s
2026-10-16 23:41:04 +09:00
Danny Kim 662e946fad Drop the scripts lint override and accept Oxfmt's standard package.json order 2026-10-16 23:41:04 +09:00
Danny Kim ffb7cb9a75 Rename no-non-ts-imports to no-asset-imports, allow .js subpaths, and compare node types by enum member 2026-10-16 23:41:04 +09:00
Danny Kim 2e09945a6a Document that scripts is flat with no subfolders or index files
Check / check (pull_request) Successful in 39s
2026-10-16 23:19:03 +09:00
Danny Kim 934a3cfd03 Remove Deno lint references from the project lint plugin comments
Check / check (pull_request) Successful in 38s
2026-10-16 23:15:37 +09:00
Danny Kim b170f25c7d Document that package.json aliases may target only direct subfolders of src
Agents / agent (pull_request) Has been skipped
Check / check (pull_request) Successful in 1m18s
2026-10-16 22:08:23 +09:00
Danny Kim 006bbe6b0c Move the action from Deno to Node.js and Vite+ (#20)
## Summary

Moves `commons/bot-agents` off Deno. The action's TypeScript now runs directly on the job image's Node.js (`node src/<phase>.ts`, using Node's built-in type stripping), with no build step and still no runtime dependency. Repository checks move to Vite+ (`vp check`, `vp test`).

## What changed

- **Runtime.** `action.yml` runs `prepare.ts`, `run.ts`, and `post.ts` with `node` instead of `deno run -A`. `package.json` (`"type": "module"`, `engines.node >=24.2` for `import.meta.main`) is now copied into the root-owned source copy by `scripts/protect-source.sh`.
- **Profiles.** `profiles.yml` → `profiles.json`, with the same content (encrypted values unchanged), parsed with `JSON.parse`. This drops the only runtime dependency (`@std/yaml`).
- **Deno APIs → Node.**
  - `src/command.ts` wraps `child_process.spawn` with the old `Deno.Command` shapes: `output()`/`spawn()`, `clearEnv`, `uid`/`gid`, and Deno's stdio defaults (stdin inherited; stdout/stderr piped for `output()`, inherited for `spawn()`). A signal exit maps to `128 + signo`. Status settles on process exit.
  - `src/errors.ts` maps `NotFound` to `ENOENT`/`ESRCH`.
  - fs, path, stream, and readline calls are mapped one for one. `makeTempFile` becomes an exclusive `wx` 0600 create.
- **Size refactors.** These are needed for Oxlint's default limits. There are no behavior changes and no overrides for source files.
  - `run.ts` is split into `run-context.ts`, `agents.ts`, and `agent-{claude,codex,opencode}.ts`.
  - `post.ts` is split into `post.ts` and `post-artifacts.ts`.
  - `parseCredentials`, `readOutcome`, and `postRuntime` are broken into helpers.
  - Loops that awaited sequentially became recursion or a `reduce` chain, so they stay sequential. `/proc` status reads became `Promise.all`.
  - `src/json.ts` adds type guards in place of `as` casts.
- **Tests.** The 58 `Deno.test` cases were converted to Vitest with the codemod, and its TODOs were finished by hand.
  - Unit tests are `src/*.test.ts`; the repository-level workflow test is `tests/workflow.test.ts`.
  - Root-only tests are now `test.skipIf(!IS_ROOT)`, so they show as skipped instead of silently passing.
  - New `tests/entrypoints.test.ts` runs each phase under real Node to prove its whole import graph loads.
- **Config.** The only config files are `package.json`, `tsconfig.json`, and `vite.config.ts`, plus `package-lock.json`.
  - Lint uses Oxlint correctness/suspicious/pedantic/perf at error, with default limits and type-aware checks.
  - `scripts/project-lint.ts` holds the rule list. It maps Deno's `recommended` rules that fall outside those categories, adds the template's `id-match`, `no-disable-comments`, and `no-non-ts-imports`, and maps Deno's `no-window`/`no-process-global`/`no-node-globals` to `no-restricted-globals` (so `process`/`Buffer` come from `node:` imports).
- **CI.** `.gitea/workflows/check.yml` runs `node --version`, `npm ci`, `npx vp check`, and `npx vp test` in the default runner image.
- **Formatting.** Oxfmt formatting is a separate first commit, so the second commit shows only the semantic diff.
- **AGENTS.md** is updated for the new toolchain.

## Deviations / risks

- **Live `@main` switch.** Six consumer repos use `commons/bot-agents@main`, so merging switches all of them at once. Suggested before merging: tag the current `main` (e.g. `deno-final`) as a rollback target, and canary this branch from one consumer (`uses: …/commons/bot-agents@node-migration`) on a throwaway PR.
- **Node version.** `post.ts` relies on `import.meta.main`, which needs Node ≥ 24.2. DANNYEC's cached `node:24-bookworm` minor is unknown (`forcePull=false`), and the CI job now prints `node --version` to confirm it.
- **Deno stays in the global install.** `deno` remains in the action's global npm install because agents still verify Deno-based consumers (memona, memona-home). Remove it once those repos move.
- **`prefer-readonly-parameter-types` is off.** This pedantic rule is turned off, as in the explicit-types template and the app repos, because Node/web types (`Response`, `Stats`, `RequestInit`) can never satisfy it. `scripts/**` has one narrow override (`no-unsafe-enum-comparison`) for AST node `type` comparisons.
- **Stricter validation of malformed input.** For valid input, behavior is unchanged. A few validations are stricter where the old code would have used a malformed value:
  - Gitea `/user` and comment responses are checked.
  - The runtime manifest and the outcome's profile type are checked against known values.
  - Some type-check errors are now `TypeError` (same messages).
- **@cunarist lint plugins.** "CI fails until @cunarist/eslint-plugin-* are published" does **not** apply here. This repo's Deno setup enabled no plugin, so it depends on none of `@cunarist/eslint-plugin-*`, and CI can pass as is.

## Verification

- `vp check`: formatting, lint (0 warnings), and type check all pass.
- `vp test` as a normal user: 56 passed, 5 root-only skipped.
- `vp test` as root in `node:24-bookworm` (Node v24.22.0, the CI image): all 61 passed, including the UID isolation, process cleanup, and `prepare.ts` cleanup tests.
- End-to-end smoke as root in `node:24-bookworm`, with fake `codex`/`claude`/`npx` binaries and a fake Gitea, through `protect-source.sh` → `prepare.ts` → `run.ts` → `post.ts`:
  - Codex hit "usage limit" and fell through to Claude.
  - Agents ran as UIDs 20000/20001 without the master key.
  - The Codex login was persisted to `/root/.codex/auth.json` (0600).
  - The PR review with an inline comment was posted with the reviewer token.
  - Runtime credentials were removed and the git author was configured.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Reviewed-on: #20
Reviewed-by: bot <noreply@capsulizers.com>
Co-authored-by: Danny Kim <temeddix@gmail.com>
Co-committed-by: Danny Kim <temeddix@gmail.com>
2026-10-16 12:43:37 +00:00
Danny Kim f001a71c61 Recognize sign-in failures for every agent and fall through (#19)
Co-authored-by: Danny Kim <temeddix@gmail.com>
Co-committed-by: Danny Kim <temeddix@gmail.com>
2026-10-12 02:51:28 +00:00
Danny Kim ea20f6d629 Show the selected bot profile and add OpenRouter fallback (#18)
Uses Codex first, then Claude, then OpenCode through OpenRouter when quota is exhausted.

Every generated comment and review now identifies the selected profile and model in a final quote. The dependent action interface remains one master key.

Verified formatting, lint, type checks, encrypted profile decryption, current OpenCode CLI flags, and 45 tests.

Reviewed-on: #18
Reviewed-by: bot <noreply@capsulizers.com>
Co-authored-by: Danny Kim <temeddix@gmail.com>
Co-committed-by: Danny Kim <temeddix@gmail.com>
2026-09-24 01:39:49 +00:00
Danny Kim 4ecdf5adc0 Require AI-bot review on every PR (#17)
Co-authored-by: Danny Kim <temeddix@gmail.com>
Co-committed-by: Danny Kim <temeddix@gmail.com>
2026-09-23 20:43:02 +00:00
Danny Kim 3626db0876 Recognize Claude weekly limits (#16)
Recognize Claude’s actual weekly-limit message and continue to the next configured profile.

The regression uses the production message from the failed migration review. Root suite: 38 passed.

Reviewed-on: #16
Co-authored-by: Danny Kim <temeddix@gmail.com>
Co-committed-by: Danny Kim <temeddix@gmail.com>
2026-09-23 20:27:47 +00:00
Danny Kim 535a7a486c Fix the packaged prompt path (#15)
Resolve the packaged prompt from the repository root after TypeScript moved into `src/`.

Adds a regression test that verifies every module-relative runtime asset exists. Root suite: 38 passed.

Reviewed-on: #15
Co-authored-by: Danny Kim <temeddix@gmail.com>
Co-committed-by: Danny Kim <temeddix@gmail.com>
2026-09-23 20:23:40 +00:00
Danny Kim e56ea246bf Centralize encrypted bot profiles (#14)
Centralize ordered bot profiles and encrypted credentials in `bot-agents`.

- Exposes one action input: `master-key`.
- Uses Gitea’s automatic job token internally; dependent repositories provide no author/reviewer/profile inputs.
- Keeps encrypted Claude and reviewer credentials in `profiles.yml`; tokenless Codex uses its persisted subscription login.
- Falls back only on recognized quota exhaustion, with a distinct UID/home per profile and descendant cleanup before fallback.
- Separates decryption, agent execution, and reviewer posting so privileged credentials never enter an agent process.
- Installs `obra/superpowers` with the standard Skills CLI; removes custom discovery code.
- Adds root-level isolation, rollback, symlink, fallback, posting, YAML, and self-workflow CI coverage.

Checks: formatting, lint, all entrypoint type checks, 35 tests as root, diff check, secret scan, and repository diagnostics.
Reviewed-on: #14
Co-authored-by: Danny Kim <temeddix@gmail.com>
Co-committed-by: Danny Kim <temeddix@gmail.com>
2026-09-23 20:15:29 +00:00
Danny Kim ba9e0c0787 Load Superpowers review instructions (#13)
Co-authored-by: Danny Kim <temeddix@gmail.com>
Co-committed-by: Danny Kim <temeddix@gmail.com>
v0.2.1
2026-09-16 12:16:09 +00:00
Danny Kim 58d3c12c25 Restore Superpowers reviews (#12)
Co-authored-by: Danny Kim <temeddix@gmail.com>
Co-committed-by: Danny Kim <temeddix@gmail.com>
v0.2.0
2026-09-16 04:27:22 +00:00
Danny Kim dcacac18e8 Make bot review setup self-contained (#11)
Co-authored-by: Danny Kim <temeddix@gmail.com>
Co-committed-by: Danny Kim <temeddix@gmail.com>
v0.1.0
2026-09-14 08:49:49 +00:00
bot 70d71aa4fd Inline comments (#10)
A finding about one line now lands on that line of the diff: the agent writes anchors as JSON, and the review posts them with the body in one call. Bad entries fail the run, and an anchor Gitea refuses falls back to posting the body alone.

Verified with deno fmt, lint and check.

Reviewed-on: #10
Co-authored-by: bot <temeddix@gmail.com>
Co-committed-by: bot <temeddix@gmail.com>
2026-09-14 00:11:35 +00:00
bot 2b51793c92 Review on request (#9)
A pull request comment that asks for a review now posts a real review, not a plain comment: the review file decides, the event no longer does.

Verified with deno fmt, lint and check.

Reviewed-on: #9
Co-authored-by: bot <temeddix@gmail.com>
Co-committed-by: bot <temeddix@gmail.com>
2026-09-13 23:48:04 +00:00
Danny Kim 4ed8b48b7a Verdict words (#8)
The review file starts with `Approved` or `Changes requested` instead of `Yes`/`No`/`With fixes`. The match is still the whole trimmed first line; `run.ts` prepends ✅, 🛑, or 💬 when posting, so the mark never takes part in the match.

Verified: `deno fmt`, `deno lint`, `deno check` pass; a scratch run of the matcher maps `Approved` → APPROVED, `Changes requested` → REQUEST_CHANGES, and `Approved, mostly`, `✅ Approved`, `Yes` → COMMENT.
Reviewed-on: #8
Co-authored-by: Danny Kim <temeddix@gmail.com>
Co-committed-by: Danny Kim <temeddix@gmail.com>
2026-09-13 17:21:34 +00:00
Danny Kim 0d109ebec8 Review file (#7)
The reviewer writes its review to a file whose first line is the verdict, instead of relying on a narration-free final message. Sonnet put `Yes` after three paragraphs of narration on memona #936 (review 595), which the fail-closed verdict posted as a plain comment.

Reviewed-on: #7
Co-authored-by: Danny Kim <temeddix@gmail.com>
Co-committed-by: Danny Kim <temeddix@gmail.com>
2026-09-13 16:54:54 +00:00
Danny Kim a2bc4c9541 Model input (#6)
Optional `model` input. Defaults move to the mid tiers, `claude-sonnet-5` and `gpt-5.6-terra`, since a run follows a fixed template plus the project's checks; a workflow can still pass a bigger model.

Reviewed-on: #6
Co-authored-by: Danny Kim <temeddix@gmail.com>
Co-committed-by: Danny Kim <temeddix@gmail.com>
2026-09-13 16:48:13 +00:00
Danny Kim 75d3593376 Author replies (#5)
The reviewer drops a finding the author has answered in the PR comments as intended or a false alarm, once the code or docs make that clear. Pairs with memona's merge-branch gate loop.

Reviewed-on: #5
Co-authored-by: Danny Kim <temeddix@gmail.com>
Co-committed-by: Danny Kim <temeddix@gmail.com>
2026-09-13 15:35:17 +00:00
Danny Kim 439f2b4e77 Checked-out head (#4)
Checked-out head (#4)

Co-authored-by: Danny Kim <temeddix@gmail.com>
Co-committed-by: Danny Kim <temeddix@gmail.com>
2026-09-13 15:06:27 +00:00
Danny Kim f0506adfea Fail-closed verdict (#3)
Fail-closed verdict (#3)

Co-authored-by: Danny Kim <temeddix@gmail.com>
Co-committed-by: Danny Kim <temeddix@gmail.com>
2026-09-13 14:57:01 +00:00
Danny Kim b8d0093ef2 Superpowers review (#2)
Superpowers review (#2)

Co-authored-by: Danny Kim <temeddix@gmail.com>
Co-committed-by: Danny Kim <temeddix@gmail.com>
2026-09-13 14:30:29 +00:00
Danny Kim 8c2041bbc5 Split tokens (#1)
The agent and the bot are now two accounts, and the runner is one Deno script.

- `author-token` (was `gitea-token`): commits, pushes, and opens pull requests; the agent sees it as `GITEA_TOKEN`, and commits use that account's login and email.
- `reviewer-token`: posts comments and reviews as the bot; withheld from the agent's environment so it can never approve as the bot.
- A `pull_request` run posts a review instead of a comment: `REQUEST_CHANGES` when the response mentions `@bot`, `COMMENT` when the run failed, `APPROVED` otherwise. Gitea refuses self-approval, so the two accounts must differ.
- The reviewer checks the whole repository against `commons/code-rules`, which is fetched and embedded in the prompt, and requests changes for violations even when the diff did not cause them.
- `run.ts` replaces the three shell scripts plus `jq`, `envsubst`, and `ansifilter`; only `deno` is added to the install step, per the rules' Deno-over-Node policy. A `.gitea` workflow runs `deno fmt`, `lint`, and `check`.

Callers must rename `gitea-token` and add `reviewer-token` (`write:issue` and `write:repository` scopes). A rejection stays until the bot reviews again, so callers that want it lifted after a fix should trigger on `pull_request: [opened, synchronize]`.

Verified with a fake `claude` binary against this PR in an isolated `HOME`: git author configured from the token, prompt rendered with rules and comment history, events streamed, reviewer token absent from the agent's environment, review posted (then deleted).

Reviewed-on: #1
Co-authored-by: Danny Kim <temeddix@gmail.com>
Co-committed-by: Danny Kim <temeddix@gmail.com>
2026-09-13 14:15:23 +00:00
Danny Kim e173c11cac Specify models 2026-08-09 22:41:11 +09:00
Danny Kim a791bc7033 Stream thinking and text from Claude 2026-07-21 02:30:22 +09:00
Danny Kim 66ee427697 Do not make the bot wait for external wakeup 2026-07-21 02:11:47 +09:00
Danny Kim 0a3e650664 Stream Claude output to console 2026-07-21 01:40:42 +09:00
Danny Kim 5039c728cb Add Claude 2026-07-18 02:25:32 +09:00
Danny Kim 4a4b3b9538 Do not give up after waiting other job 2026-07-18 01:52:17 +09:00