agentic-retro 0.1.0 → 0.1.2

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/README.md CHANGED
@@ -86,6 +86,7 @@ Using Codex? It asks you to trust the new session-end hook the first time a sess
86
86
 
87
87
  ## CLI commands
88
88
 
89
+ - `agentic-retro about` – print a short intro to what agentic-retro does
89
90
  - `agentic-retro setup` – interactive config, the human alternative to the setup skill
90
91
  - `agentic-retro config list | get <key> | set <key> <value>` – read or write one config key
91
92
  - `agentic-retro enqueue` – add a finished session to the queue (hooks call this)
@@ -10,8 +10,10 @@ import { syncOutcomes } from './lib/outcomes.js';
10
10
  import { notice } from './lib/notice.js';
11
11
  import { stats } from './lib/stats.js';
12
12
  import { installPi } from './lib/pi.js';
13
+ import { INTRO } from './lib/intro.js';
13
14
 
14
15
  const USAGE = `usage: agentic-retro <command>
16
+ about
15
17
  setup
16
18
  config list | get <key> | set <key> <value>
17
19
  enqueue [--harness <h>] [--session <id> --transcript <path> --cwd <dir>] (or hook JSON on stdin)
@@ -76,6 +78,7 @@ async function main() {
76
78
  if (command === 'notice') return notice(flags);
77
79
  if (command === 'stats') return stats(flags);
78
80
  if (command === 'install-pi') return installPi();
81
+ if (command === 'about') return process.stdout.write(INTRO);
79
82
  throw new Error(USAGE);
80
83
  }
81
84
 
@@ -1,5 +1,5 @@
1
1
  // Builds the command that starts the batch agent in each harness.
2
- import { readFileSync, existsSync } from 'node:fs';
2
+ import { readFileSync, existsSync, statSync } from 'node:fs';
3
3
  import { homedir } from 'node:os';
4
4
  import { join, dirname } from 'node:path';
5
5
  import { fileURLToPath } from 'node:url';
@@ -37,7 +37,15 @@ function sessionsOf(batchDir) {
37
37
  }
38
38
 
39
39
  function workDirs(config, sessions) {
40
- const paths = [...sessions.map((s) => s.repo), ...(config.editable ?? []).map(expandHome)];
40
+ const editable = (config.editable ?? []).map((path) => {
41
+ path = expandHome(path);
42
+ try {
43
+ return statSync(path).isFile() ? dirname(path) : path;
44
+ } catch {
45
+ return path;
46
+ }
47
+ });
48
+ const paths = [...sessions.flatMap((s) => [s.repo, s.cwd]), ...editable];
41
49
  return [...new Set(paths.filter(Boolean))];
42
50
  }
43
51
 
@@ -0,0 +1,6 @@
1
+ // The one-screen intro shown before setup asks anything. The setup skill prints it too, via `agentic-retro about`.
2
+ export const INTRO = `agentic-retro reviews your finished coding-agent sessions in batches and suggests improvements.
3
+ - It looks for code that could be clearer, agent setup (skills, instructions) that would have saved time, and repo changes that help agents work faster
4
+ - You get one pull request per repo, or a report you walk through with your agent
5
+ - Nothing lands without your review, unless you turn on auto-merge for low-risk changes
6
+ `;
@@ -39,7 +39,7 @@ export function syncOutcomes() {
39
39
  if (status !== 'open') setStatus(p, status);
40
40
  }
41
41
 
42
- for (const p of open()) {
42
+ for (const p of open().filter((p) => !p.pr)) {
43
43
  if (ledger.batchCount - p.batch >= expireAfterBatches) setStatus(p, 'expired');
44
44
  }
45
45
  saveLedger(ledger);
package/cli/lib/queue.js CHANGED
@@ -2,17 +2,21 @@
2
2
  import { execFileSync } from 'node:child_process';
3
3
  import { readdirSync } from 'node:fs';
4
4
  import { homedir } from 'node:os';
5
- import { join, basename } from 'node:path';
5
+ import { join, basename, resolve } from 'node:path';
6
6
  import { readJson, writeJson } from './paths.js';
7
7
  import { loadConfig } from './config.js';
8
8
  import { startBatch } from './runner.js';
9
9
 
10
- function repoOf(cwd) {
10
+ function repoOf(cwd, fallback = cwd) {
11
11
  try {
12
- return execFileSync('git', ['-C', cwd, 'rev-parse', '--show-toplevel'],
13
- { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
12
+ const options = { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] };
13
+ const commonDir = execFileSync('git', ['-C', cwd, 'rev-parse', '--git-common-dir'], options).replace(/\n$/, '');
14
+ // Git lists the shared identity first: the main checkout or its separate metadata directory.
15
+ const worktrees = execFileSync('git', ['--git-dir', resolve(cwd, commonDir), 'worktree', 'list', '--porcelain', '-z'], options);
16
+ const main = worktrees.split('\0').find((field) => field.startsWith('worktree '));
17
+ return main ? main.slice('worktree '.length) : fallback;
14
18
  } catch {
15
- return cwd;
19
+ return fallback;
16
20
  }
17
21
  }
18
22
 
@@ -43,8 +47,8 @@ export async function enqueue({ harness, sessionId, transcript, cwd }) {
43
47
  harness ||= harnessOf(transcript);
44
48
  if (!harness || !sessionId || !cwd) throw new Error('enqueue needs a harness, session, and cwd');
45
49
 
46
- const queue = readJson('queue.json', []);
47
- if (queue.some((s) => s.sessionId === sessionId)) return;
50
+ const queue = readJson('queue.json', []).map((s) => ({ ...s, repo: repoOf(s.cwd, s.repo) }));
51
+ if (queue.some((s) => s.sessionId === sessionId)) return writeJson('queue.json', queue);
48
52
  const entry = { harness, sessionId, transcript, cwd, repo: repoOf(cwd), endedAt: new Date().toISOString() };
49
53
  queue.push(entry);
50
54
 
package/cli/lib/setup.js CHANGED
@@ -3,6 +3,7 @@ import { createInterface } from 'node:readline';
3
3
  import { existsSync } from 'node:fs';
4
4
  import { delimiter, join } from 'node:path';
5
5
  import { loadConfig, saveConfig, getKey, parseValue } from './config.js';
6
+ import { INTRO } from './intro.js';
6
7
 
7
8
  const onPath = (bin) => (process.env.PATH || '').split(delimiter).some((dir) => existsSync(join(dir, bin)));
8
9
 
@@ -34,6 +35,7 @@ export async function setup() {
34
35
  const rl = createInterface({ input: process.stdin, output: process.stdout, terminal: false });
35
36
  const lines = rl[Symbol.asyncIterator]();
36
37
  const config = loadConfig();
38
+ process.stdout.write(`${INTRO}\nThese questions take about two minutes. Press Enter to keep the value in brackets.\n\n`);
37
39
 
38
40
  for (const [key, label, presets] of questions()) {
39
41
  const current = show(getKey(config, key));
package/package.json CHANGED
@@ -1,12 +1,24 @@
1
1
  {
2
2
  "name": "agentic-retro",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "agentic-retrospective: reviews finished agent coding sessions and proposes improvements",
5
5
  "type": "module",
6
- "bin": { "agentic-retro": "cli/agentic-retro.js" },
7
- "files": ["cli/", "skills/"],
8
- "engines": { "node": ">=20" },
9
- "scripts": { "test": "node --test test/*.test.js" },
6
+ "bin": {
7
+ "agentic-retro": "cli/agentic-retro.js"
8
+ },
9
+ "files": [
10
+ "cli/",
11
+ "skills/"
12
+ ],
13
+ "engines": {
14
+ "node": ">=20"
15
+ },
16
+ "scripts": {
17
+ "test": "node --test test/*.test.js"
18
+ },
10
19
  "license": "MIT",
11
- "repository": "github:ac8318740/agentic-retro"
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/ac8318740/agentic-retro.git"
23
+ }
12
24
  }
@@ -109,20 +109,25 @@ agentic-retro propose --repo <target repo path> --category <category> [--risk lo
109
109
 
110
110
  Do this once per target repo. Skip a target with no git remote, and put its proposals in a report file instead (5b).
111
111
 
112
+ Before you branch, read the repo's PR rules in its `AGENTS.md`, `CLAUDE.md`, `CONTRIBUTING.md` and CI workflows, such as a `dev` base branch or a version bump.
113
+
112
114
  ```bash
113
115
  git -C "$repo" fetch origin
114
- base=$(git -C "$repo" symbolic-ref --short refs/remotes/origin/HEAD | sed 's@^origin/@@')
116
+ base=$(git -C "$repo" symbolic-ref --short refs/remotes/origin/HEAD | sed 's@^origin/@@') # override with the rules' base
115
117
  wt=$(mktemp -d)/wt
116
118
  git -C "$repo" worktree add -b "agentic-retro/batch-<n>" "$wt" "origin/$base"
117
119
  ```
118
120
 
119
121
  1. Apply each proposal in `$wt`, then commit it on its own: `git -C "$wt" add -A && git -C "$wt" commit -m "P12: <title>"`
120
- 2. Push the branch: `git -C "$wt" push -u origin "agentic-retro/batch-<n>"`
121
- 3. Write the body per `writing-proposals.md`, then open the PR from `$wt`: `gh pr create --base "$base" --title "<title>" --body-file <file>`
122
- 4. Record the PR and commit on each proposal: `agentic-retro link P12 --pr <url> --commit <sha>`
123
- 5. Remove the worktree: `git -C "$repo" worktree remove "$wt"`
124
-
125
- When `autoMergeLowRisk` is `true`, low-risk agent-setup proposals go on a second branch, `agentic-retro/batch-<n>-low-risk`, with their own PR. Merge that PR with `gh pr merge --merge` once it opens. Everything else waits for the user.
122
+ 2. Do the steps the rules require in one last commit without a proposal ID, so dropping a proposal keeps them. When a step needs a command you cannot run, say so at the top of the PR body
123
+ 3. Push the branch: `git -C "$wt" push -u origin "agentic-retro/batch-<n>"`
124
+ 4. Make sure the `agentic-retro` label exists from `$wt`: `(cd "$wt" && gh label create agentic-retro --force)`
125
+ 5. Write the body per `writing-proposals.md`, then open the PR from `$wt`: `(cd "$wt" && gh pr create --base "$base" --title "<title>" --body-file <file> --label agentic-retro)`
126
+ 6. Wait for CI with `gh pr checks <url> --watch`, then fix each failure in a new commit and push
127
+ 7. Record the PR and commit on each proposal: `agentic-retro link P12 --pr <url> --commit <sha>`
128
+ 8. Remove the worktree: `git -C "$repo" worktree remove "$wt"`
129
+
130
+ When `autoMergeLowRisk` is `true`, low-risk agent-setup proposals go on a second branch, `agentic-retro/batch-<n>-low-risk`, with their own PR. Merge that PR with `gh pr merge --merge` once its checks pass. Everything else waits for the user.
126
131
 
127
132
  ## 5b. Report mode: one report file
128
133
 
@@ -41,7 +41,7 @@ Every agent-setup proposal carries a risk label.
41
41
  ## Where a change may go
42
42
 
43
43
  - **New things** go under `targets.preset`, such as `~/.claude/skills`
44
- - `targets.note` may name another place, such as "send spechub fixes to the spechub repo at <path>"
44
+ - `targets.note` may name another place, such as "send acme-skills fixes to its repo at <path>"
45
45
  - Follow the note when it covers the finding
46
46
  - **Edits to existing files** go only under a path listed in `editable`
47
47
  - Drop a finding against a file outside `editable`, however good it is
@@ -12,6 +12,10 @@ Walk the user through agentic-retro's config, one question at a time, then write
12
12
  1. Run `command -v agentic-retro`.
13
13
  2. If the command is missing, tell the user to run `npm install -g agentic-retro`, then stop.
14
14
 
15
+ ## Open with the intro
16
+
17
+ Run `agentic-retro about` and show its output to the user as is, before the first question. It says what agentic-retro does in a few lines. Add nothing to it.
18
+
15
19
  ## Ask each question
16
20
 
17
21
  Use the host's question tool (for example `AskUserQuestion`) when one is available. Otherwise ask in plain chat, one question at a time.
@@ -32,7 +36,7 @@ Offer the presets below for each question, and let the user type a different ans
32
36
  9. **Auto-merge** – merge low-risk agent-setup PRs automatically? Default off
33
37
  10. **Expire after** – batches an open proposal waits before it expires with no action, default 3
34
38
  11. **Targets** – where agent-setup proposals go: `~/.claude/skills`, `~/.codex/skills`, or a plugin repo path
35
- - Also ask for a free-text note the batch agent reads, for example: "I develop spechub; send spechub fixes to the spechub repo at ~/spechub"
39
+ - Also ask for a free-text note the batch agent reads, for example: "I maintain the acme-skills plugin; send fixes to its repo at ~/code/acme-skills"
36
40
  12. **Editable paths** – which paths proposals can write to, as a JSON list; every other path stays read-only
37
41
  13. **Notes** – free text, anything else the batch agents should know
38
42
 
@@ -52,7 +56,7 @@ agentic-retro config set output pr
52
56
  agentic-retro config set autoMergeLowRisk false
53
57
  agentic-retro config set expireAfterBatches 3
54
58
  agentic-retro config set targets.preset ~/.claude/skills
55
- agentic-retro config set targets.note "I develop spechub; send spechub fixes to ~/spechub"
59
+ agentic-retro config set targets.note "I maintain the acme-skills plugin; send fixes to its repo at ~/code/acme-skills"
56
60
  agentic-retro config set editable '["~/.claude/skills"]'
57
61
  agentic-retro config set notes "ask about this"
58
62
  ```