duaer-spec 0.6.0 → 0.6.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.
@@ -42,7 +42,8 @@ cd .worktree/<request-id>
42
42
  - One logical change per commit; leave the worktree clean
43
43
  - User/protocol-visible changes update E2E scenario docs
44
44
  - Merge into **`develop`** when done (hotfix: **`main`**, then back-merge **`develop`**)
45
- - Stop worktree services → remove worktree → delete short branch
45
+ - **Handoff (mandatory):** stop worktree-bound processes → remove `.worktree/<id>`
46
+ restart from primary checkout on `develop` (`duaer handoff [--run]`, `.duaer/handoff.json`)
46
47
  - Push only when the user explicitly asks
47
48
  - Promote **`develop` → `main`** only when the user asks to go online
48
49
 
@@ -27,6 +27,10 @@ For new behavior, fixes, refactors that change product behavior, or architecture
27
27
  4. Do **not** dump a methodology tutorial unless they ask how Duaer works.
28
28
  5. Merge to **`develop`** when done (hotfix: **`main`**, then back-merge
29
29
  **`develop`**). Promote to **`main`** only if the user asks to go online.
30
+ 6. **Handoff (mandatory):** stop processes bound to `.worktree/<id>/`, remove
31
+ the worktree, then restart services from the primary checkout on `develop`
32
+ using `.duaer/handoff.json` / `duaer handoff [--run]`. Never leave the user
33
+ on a dead worktree server.
30
34
  See `docs/agent/branching-and-release.md`.
31
35
 
32
36
  ## Handoff
@@ -0,0 +1,9 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "onWorktreeRemove": {
4
+ "stop": "Stop any process whose working directory is under the request worktree (dev servers, file watchers, local APIs).",
5
+ "restartFromPrimary": true,
6
+ "commands": []
7
+ },
8
+ "notes": "After merging into develop (or hotfix main), stop worktree-bound processes, remove .worktree/<id>, then restart from the primary checkout. Add commands such as \"npm run dev\" when this project needs a local service after handoff. Empty commands = stop only; agent still reports handoff."
9
+ }
package/ADOPT.md CHANGED
@@ -7,26 +7,51 @@ Brief → work → accept **without** the human operating slash commands or CLI.
7
7
 
8
8
  ```bash
9
9
  npx duaer-spec init --here
10
- # pin: npx github:fujiezee/duaer-spec@v0.6.0 duaer init --here
10
+ # pin: npx github:fujiezee/duaer-spec@v0.6.1 duaer init --here
11
11
  ```
12
12
 
13
13
  ```bash
14
14
  npx duaer-spec init --here --method
15
- npx duaer-spec init --here --ops # default integration note: develop
15
+ npx duaer-spec init --here --ops
16
16
  ```
17
17
 
18
- Ensure the repo has **`main`** and **`develop`**. Agent ops require both, plus
19
- `feat/*` / `fix/*` for work. See
18
+ Ensure the repo has **`main`** and **`develop`**. See
20
19
  [`docs/agent/branching-and-release.md`](docs/agent/branching-and-release.md).
21
20
 
22
- After that: talk to the agent in plain language. Do not teach them `/duaer-*`.
21
+ After that: talk to the agent in plain language.
22
+
23
+ ## Updating an existing install
24
+
25
+ Already ran `duaer init` before? Refresh managed files:
26
+
27
+ ```bash
28
+ npx duaer-spec@latest init --here --force
29
+ ```
30
+
31
+ Then:
32
+
33
+ 1. **Review the git diff** — keep your project-specific edits to
34
+ `.duaer/memory/constitution.md`, `project-context.md`, `docs/baseline.md`,
35
+ and especially **`.duaer/handoff.json` `commands`** (your restart scripts).
36
+ 2. Restore any local overrides you still need.
37
+ 3. Confirm `.gitignore` still contains `.worktree/`.
38
+ 4. No need to re-learn slash commands — talk to the agent as before.
39
+
40
+ Pin a version if you prefer:
41
+
42
+ ```bash
43
+ npx duaer-spec@0.6.1 init --here --force
44
+ # or
45
+ npx github:fujiezee/duaer-spec@v0.6.1 duaer init --here --force
46
+ ```
47
+
48
+ Adopters are **not** auto-updated; re-run init when you want a newer revision.
23
49
 
24
50
  ## What gets installed
25
51
 
26
- - Always-on rule: agent runs the autonomous job loop on product work
27
- - Playbook skill `duaer-do` (agent follows it; human need not invoke it)
52
+ - Always-on autonomous job loop
53
+ - `.duaer/handoff.json` restart services on **develop** after worktree remove
28
54
  - Agent ops: `AGENTS.md`, branching/release docs, mandatory `.worktree/`
29
- - Optional step skills for large jobs (agent-only)
30
55
 
31
56
  ## Branch model (mandatory)
32
57
 
@@ -35,15 +60,11 @@ After that: talk to the agent in plain language. Do not teach them `/duaer-*`.
35
60
  | `main` | Production / online |
36
61
  | `develop` | Day-to-day integration |
37
62
  | `feat/<name>` | Features → `develop` |
38
- | `fix/<name>` | Fixes → `develop` (hotfix via `main` then back to `develop`) |
63
+ | `fix/<name>` | Fixes → `develop` (hotfix via `main`) |
39
64
 
40
- Go-live: promote `develop` `main` only when you ask to ship.
65
+ After merge: **`duaer handoff [--run]`** (stop worktree services restart on develop).
41
66
 
42
67
  ## Precedence
43
68
 
44
69
  1. `AGENTS.md` — how employees operate
45
70
  2. `DUADER.md` / `.duaer/` — how jobs are briefed
46
-
47
- ## Updates
48
-
49
- `duaer init --force` (review the diff) or pin a tag.
package/AGENTS.md CHANGED
@@ -251,7 +251,9 @@ git worktree prune
251
251
  * Use `git branch -d` (not `-D`)
252
252
  * Delete only your own worktree and branch
253
253
  * Never commit `.worktree/` (ignored)
254
- * Stop worktree-bound services before remove; restart from primary checkout if needed
254
+ * Stop worktree-bound services before remove; then restart from the primary
255
+ checkout on **`develop`** via `.duaer/handoff.json` / `duaer handoff [--run]`
256
+ (mandatory handoff — see [branching-and-release](docs/agent/branching-and-release.md))
255
257
 
256
258
  ## Development Workflow
257
259
 
@@ -267,7 +269,8 @@ git worktree prune
267
269
  10. Commit each logical change
268
270
  11. Refresh against latest **`develop`** (or **`main`** for hotfix)
269
271
  12. Merge into local **`develop`** (hotfix: **`main`**, then back-merge to **`develop`**)
270
- 13. Stop worktree services; remove worktree; delete short branch
272
+ 13. Stop worktree services; remove worktree; delete short branch; **handoff**
273
+ restart on `develop` (`duaer handoff [--run]` / `.duaer/handoff.json`)
271
274
  14. Push only when explicitly requested
272
275
  15. Promote **`develop` → `main`** only when the user explicitly asks to go online
273
276
 
package/CHANGELOG.md CHANGED
@@ -1,42 +1,41 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.6.1 — 2026-09-15
4
+
5
+ ### Worktree → develop service handoff
6
+
7
+ - Mandatory handoff after merge: stop worktree-bound processes, remove
8
+ `.worktree/<id>`, restart from primary checkout on `develop`
9
+ - `.duaer/handoff.json` configures restart commands (e.g. `npm run dev`)
10
+ - CLI: `duaer handoff` / `duaer handoff --run`
11
+ - Docs: update path for existing installs (`init --force` + review diff)
12
+
3
13
  ## 0.6.0 — 2026-09-15
4
14
 
5
15
  ### Mandatory branch model + release flows
6
16
 
7
- - Required branches: **`main`** (production), **`develop`** (integration),
8
- **`feat/*`**, **`fix/*`**
9
- - New doc: [`docs/agent/branching-and-release.md`](docs/agent/branching-and-release.md)
10
- — day-to-day, go-live, feature / bug / hotfix / issue / PR flows
11
- - Agent ops merge target is **`develop`**; promote to **`main`** only when
12
- shipping; hotfixes from `main` then back-merge `develop`
13
- - Worktree cleanup includes stopping services and restarting on `develop` if needed
14
- - `duaer init` default `--branch` is `develop`
17
+ - Required: `main` / `develop` / `feat/*` / `fix/*`
18
+ - [`docs/agent/branching-and-release.md`](docs/agent/branching-and-release.md)
15
19
 
16
20
  ## 0.5.1 — 2026-09-15
17
21
 
18
- ### Mandatory in-repo worktrees
19
-
20
- - Request worktrees **must** live under **`.worktree/<request-id>`**
21
- - `.worktree/` is gitignored; `duaer init` ensures the ignore rule
22
+ - Mandatory `.worktree/` (gitignored)
22
23
 
23
24
  ## 0.5.0 — 2026-09-15
24
25
 
25
- ### Autonomous digital employee
26
-
27
- - Humans ask; agents run Brief → work → accept without slash-command ops
26
+ - Autonomous digital employee (ask, don’t operate phases)
28
27
 
29
28
  ## 0.4.0 — 2026-09-15
30
29
 
31
- - `/duaer-do` + `duaer status` everyday path (later reframed as agent-internal)
30
+ - Everyday `/duaer-do` path (later agent-internal)
32
31
 
33
32
  ## 0.3.0 — 2026-09-15
34
33
 
35
- - Job handoff policy (`coach` / `strict` / `off`)
34
+ - Job handoff policy
36
35
 
37
36
  ## 0.2.0 — 2026-09-15
38
37
 
39
- - `delivery.json` handoff stamp
38
+ - `delivery.json`
40
39
 
41
40
  ## 0.1.1 — 2026-09-15
42
41
 
@@ -44,4 +43,4 @@
44
43
 
45
44
  ## 0.1.0 — 2026-09-15
46
45
 
47
- - First public methodology release
46
+ - First public release
package/README.md CHANGED
@@ -38,10 +38,21 @@ everyday human UI.
38
38
  Go-live and flows by issue type:
39
39
  [`docs/agent/branching-and-release.md`](docs/agent/branching-and-release.md).
40
40
 
41
+ **After merge:** `duaer handoff [--run]` restarts local services on `develop`
42
+ (configure commands in `.duaer/handoff.json`).
43
+
44
+ ## Updating
45
+
46
+ ```bash
47
+ npx duaer-spec@latest init --here --force # review diff; keep handoff commands
48
+ ```
49
+
50
+ Details: [`ADOPT.md`](ADOPT.md)#updating-an-existing-install
51
+
41
52
  ## Optional
42
53
 
43
54
  ```bash
44
- npx duaer-spec@0.6.0 init --here --method # method only
55
+ npx duaer-spec@0.6.1 init --here --method
45
56
  ```
46
57
 
47
58
  Details: [`ADOPT.md`](ADOPT.md) · Method: [`DUADER.md`](DUADER.md) · Ops: [`AGENTS.md`](AGENTS.md)
package/bin/duaer.mjs CHANGED
@@ -15,6 +15,7 @@ import {
15
15
  statSync,
16
16
  writeFileSync,
17
17
  } from 'node:fs'
18
+ import { spawn } from 'node:child_process'
18
19
  import { dirname, join, resolve } from 'node:path'
19
20
  import { fileURLToPath } from 'node:url'
20
21
 
@@ -26,19 +27,25 @@ const POLICY_MODES = new Set(['off', 'coach', 'strict'])
26
27
 
27
28
  const USAGE = `duaer — digital-employee delivery (duaer-spec ${PKG.version})
28
29
 
29
- Human (once):
30
- duaer init [--here] Install so the agent works as a digital employee
30
+ Human (once / update):
31
+ duaer init [--here] [--force] Install or refresh into a project
31
32
 
32
- After install: talk to the agent in plain language. Do not operate /duaer-* phases.
33
+ After install: talk to the agent in plain language.
33
34
 
34
- Agent / optional diagnostics:
35
+ Agent / optional:
36
+ duaer handoff [dir] [--run] After merge: print/restart services on develop
35
37
  duaer status [dir]
36
38
  duaer check | policy | version
37
39
 
38
40
  Init: --all (default) | --method | --ops | --force | --branch <n> (default: develop) | --here
39
41
 
42
+ Update existing install:
43
+ npx duaer-spec@latest init --here --force
44
+ # then review git diff; keep project-specific constitution / baseline / handoff commands
45
+
40
46
  Example:
41
47
  npx duaer-spec init --here
48
+ duaer handoff --run
42
49
  `
43
50
 
44
51
  function parseArgs(argv) {
@@ -55,6 +62,7 @@ function parseArgs(argv) {
55
62
  allJobs: false,
56
63
  strict: false,
57
64
  policyMode: null,
65
+ run: false,
58
66
  }
59
67
  const rest = args.slice(1)
60
68
  for (let i = 0; i < rest.length; i++) {
@@ -69,6 +77,7 @@ function parseArgs(argv) {
69
77
  else if (a === '--job') out.job = true
70
78
  else if (a === '--all-jobs') out.allJobs = true
71
79
  else if (a === '--strict' || a === '--gate') out.strict = true
80
+ else if (a === '--run') out.run = true
72
81
  else if (a === '--branch') {
73
82
  out.branch = rest[++i]
74
83
  if (!out.branch) throw new Error('--branch requires a value')
@@ -170,11 +179,37 @@ function writeDefaultPolicy(target, { force }) {
170
179
  console.log(' .duaer/delivery-policy.json (mode=coach)')
171
180
  }
172
181
 
182
+ function defaultHandoff() {
183
+ return {
184
+ schemaVersion: 1,
185
+ onWorktreeRemove: {
186
+ stop:
187
+ 'Stop any process whose working directory is under the request worktree (dev servers, file watchers, local APIs).',
188
+ restartFromPrimary: true,
189
+ commands: [],
190
+ },
191
+ notes:
192
+ 'After merging into develop, stop worktree processes, remove .worktree/<id>, then restart from the primary checkout. Add commands such as "npm run dev" when needed.',
193
+ }
194
+ }
195
+
196
+ function writeDefaultHandoff(target, { force }) {
197
+ const path = join(target, '.duaer', 'handoff.json')
198
+ if (existsSync(path) && !force) {
199
+ console.log(`skip (exists): ${path}`)
200
+ return
201
+ }
202
+ ensureDir(dirname(path))
203
+ writeFileSync(path, JSON.stringify(defaultHandoff(), null, 2) + '\n')
204
+ console.log(' .duaer/handoff.json')
205
+ }
206
+
173
207
  function installMethod(target, opts) {
174
208
  console.log('Installing Duaer method…')
175
209
  copyPath(join(PKG_ROOT, '.duaer'), join(target, '.duaer'), opts)
176
210
  console.log(' .duaer/')
177
211
  writeDefaultPolicy(target, opts)
212
+ writeDefaultHandoff(target, opts)
178
213
 
179
214
  ensureDir(join(target, '.cursor', 'skills'))
180
215
  const skillsRoot = join(PKG_ROOT, '.cursor', 'skills')
@@ -304,9 +339,10 @@ function cmdInit(opts) {
304
339
  Hired.
305
340
 
306
341
  You: describe work in Cursor (plain language).
307
- Agent: runs Brief → work → accept by itself do not operate slash phases.
342
+ Agent: runs Brief → work → accept; uses develop + .worktree/; after merge runs handoff.
308
343
 
309
- Optional diagnostic: duaer status
344
+ Update later: npx duaer-spec@latest init --here --force (review the diff)
345
+ Handoff: duaer handoff [--run] # restart services on develop after worktree remove
310
346
  `)
311
347
  }
312
348
 
@@ -596,6 +632,49 @@ Not a git merge lock.
596
632
  `)
597
633
  }
598
634
 
635
+ function cmdHandoff(opts) {
636
+ const target = resolve(opts.dir)
637
+ const cfg = readJson(join(target, '.duaer', 'handoff.json'), defaultHandoff())
638
+ const block = cfg.onWorktreeRemove || {}
639
+ const commands = Array.isArray(block.commands) ? block.commands.filter(Boolean) : []
640
+
641
+ console.log(`Handoff @ ${target}`)
642
+ console.log('(worktree → merged develop / hotfix main)\n')
643
+ console.log('1. Confirm request branch is merged into develop (hotfix: main + back-merge develop)')
644
+ console.log(`2. Stop: ${block.stop || defaultHandoff().onWorktreeRemove.stop}`)
645
+ console.log('3. git worktree remove .worktree/<id> && git branch -d feat|fix/<name>')
646
+ console.log('4. Restart from primary checkout on the merged branch:\n')
647
+
648
+ if (!commands.length) {
649
+ console.log(' (no commands in .duaer/handoff.json)')
650
+ console.log(' Add e.g. "npm run dev" under onWorktreeRemove.commands')
651
+ console.log(' If you started a server in the worktree, re-run that same command here.')
652
+ } else {
653
+ for (const c of commands) console.log(` $ ${c}`)
654
+ }
655
+
656
+ if (opts.run) {
657
+ if (!commands.length) {
658
+ console.log('\n--run: nothing to start (commands empty).')
659
+ return
660
+ }
661
+ console.log('')
662
+ for (const c of commands) {
663
+ const child = spawn(c, {
664
+ shell: true,
665
+ cwd: target,
666
+ detached: true,
667
+ stdio: 'ignore',
668
+ })
669
+ child.unref()
670
+ console.log(`started (detached) pid=${child.pid}: ${c}`)
671
+ }
672
+ console.log('\nServices should now be bound to the primary checkout, not .worktree/.')
673
+ } else if (commands.length) {
674
+ console.log('\nTip: duaer handoff --run # start the commands above in the background')
675
+ }
676
+ }
677
+
599
678
  function main() {
600
679
  let opts
601
680
  try {
@@ -614,6 +693,9 @@ function main() {
614
693
  case 'check':
615
694
  cmdCheck(opts)
616
695
  break
696
+ case 'handoff':
697
+ cmdHandoff(opts)
698
+ break
617
699
  case 'job':
618
700
  case 'status':
619
701
  cmdJob(opts)
@@ -48,9 +48,11 @@ update develop
48
48
  → git worktree add .worktree/<id> -b feat|fix/<name> develop
49
49
  → work only in that worktree (Duaer job loop as needed)
50
50
  → merge into local develop
51
- stop any server started in the worktree
52
- remove .worktree/<id>; delete feat|fix/<name>
53
- (optional) start/restart services from the primary checkout on develop
51
+ handoff (mandatory):
52
+ stop processes bound to the worktree
53
+ remove .worktree/<id>; delete feat|fix/<name>
54
+ restart services from the primary checkout on develop
55
+ (see .duaer/handoff.json / `duaer handoff [--run]`)
54
56
  → push develop only if the user asked
55
57
  ```
56
58
 
@@ -66,15 +68,44 @@ cd .worktree/feat-login
66
68
  cd ../.. # primary checkout
67
69
  git switch develop
68
70
  git merge feat/login
69
- # stop processes that used .worktree/feat-login
71
+
72
+ # Handoff — do not skip
73
+ # 1) stop anything started under .worktree/feat-login
70
74
  git worktree remove .worktree/feat-login
71
75
  git branch -d feat/login
76
+ # 2) restart on develop (primary checkout)
77
+ duaer handoff --run
78
+ # or: npm run dev # if listed in .duaer/handoff.json
72
79
  ```
73
80
 
74
- **After merge / before delete worktree:** if a local service was running from the
75
- worktree, stop it; if the user still needs it, start it again from the primary
76
- checkout on **`develop`** (merged tree). Do not expect the old worktree process
77
- to survive directory removal.
81
+ ### Worktree develop service handoff (mandatory)
82
+
83
+ Deleting a worktree **removes that directory**. Any server started there will
84
+ break. Agents **must**:
85
+
86
+ 1. Merge the request branch into **`develop`** (hotfix: **`main`**, then
87
+ back-merge **`develop`**)
88
+ 2. **Stop** processes whose cwd is under `.worktree/<id>/`
89
+ 3. `git worktree remove .worktree/<id>` and delete the short branch
90
+ 4. **Restart** from the **primary checkout** on the merged long-lived branch:
91
+ - Read `.duaer/handoff.json` → `onWorktreeRemove.commands`
92
+ - Run `duaer handoff` (prints the plan) or `duaer handoff --run` (starts
93
+ configured commands in the background from the project root)
94
+ - If `commands` is empty but the agent started a server in the worktree,
95
+ restart the **same** command from the primary checkout on `develop`
96
+ - Tell the user the new service is on the merged branch, not the old worktree
97
+
98
+ Configure per project by editing `.duaer/handoff.json`, for example:
99
+
100
+ ```json
101
+ {
102
+ "schemaVersion": 1,
103
+ "onWorktreeRemove": {
104
+ "restartFromPrimary": true,
105
+ "commands": ["npm run dev"]
106
+ }
107
+ }
108
+ ```
78
109
 
79
110
  ---
80
111
 
@@ -98,7 +98,8 @@ See [spec update guidance](workflow.md#3-spec-update-guidance).
98
98
  - [ ] Active job handoff considered by the **agent** (do not require the human to run CLI for routine work).
99
99
  - [ ] Branch refreshed against latest `develop` (hotfix: `main`).
100
100
  - [ ] Merged into local `develop` (hotfix: `main`, then back-merge `develop`).
101
- - [ ] Worktree services stopped; worktree removed; short branch deleted.
101
+ - [ ] Worktree services stopped; worktree removed; short branch deleted;
102
+ **handoff** restart on `develop` (`duaer handoff` / `.duaer/handoff.json`).
102
103
  - [ ] Only this request's logical changes included.
103
104
  - [ ] Push performed only if the user explicitly asked for this request.
104
105
  - [ ] `develop` → `main` promotion only if the user asked to go online.
@@ -33,6 +33,8 @@ the table for their app.
33
33
  | E2E-006 | `duaer-do` skill describes agent-triggered loop | manual |
34
34
  | E2E-007 | Request worktrees use `.worktree/<id>`; `.worktree/` gitignored | manual |
35
35
  | E2E-008 | Docs require main+develop+feat+fix and typed go-live flows | manual |
36
+ | E2E-009 | After merge, handoff restarts services on develop (`duaer handoff`) | manual |
37
+ | E2E-010 | ADOPT documents `init --force` update path for existing installs | manual |
36
38
 
37
39
  ## Traceability
38
40
 
@@ -46,3 +48,5 @@ the table for their app.
46
48
  | E2E-006 | `duaer-do` | Internal playbook |
47
49
  | E2E-007 | `.worktree/` + `.gitignore` | Mandatory isolation |
48
50
  | E2E-008 | `branching-and-release.md` | Branch + release matrix |
51
+ | E2E-009 | `.duaer/handoff.json` / `duaer handoff` | Service handoff |
52
+ | E2E-010 | `ADOPT.md` Updating | Existing installs |
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "duaer-spec",
3
- "version": "0.6.0",
4
- "description": "Digital employees: autonomous Spec→work→accept; mandatory main/develop/feat/fix",
3
+ "version": "0.6.1",
4
+ "description": "Digital employees: autonomous delivery; main/develop/feat/fix; worktree handoff",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "duaer": "bin/duaer.mjs",