duaer-spec 0.6.0 → 0.6.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/.cursor/rules/agents-workflow.mdc +2 -1
- package/.cursor/rules/duaer-spec.mdc +4 -0
- package/.duaer/handoff.json +9 -0
- package/ADOPT.md +20 -30
- package/AGENTS.md +5 -2
- package/CHANGELOG.md +17 -32
- package/README.md +11 -3
- package/bin/duaer.mjs +120 -17
- package/docs/agent/branching-and-release.md +39 -8
- package/docs/agent/change-checklist.md +2 -1
- package/docs/agent/e2e-test-plan.md +4 -0
- package/package.json +2 -2
|
@@ -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
|
-
-
|
|
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
|
@@ -1,49 +1,39 @@
|
|
|
1
1
|
# Adopt duaer-spec
|
|
2
2
|
|
|
3
|
-
Install
|
|
4
|
-
Brief → work → accept **without** the human operating slash commands or CLI.
|
|
5
|
-
|
|
6
|
-
## Install (human, once)
|
|
3
|
+
## Install
|
|
7
4
|
|
|
8
5
|
```bash
|
|
9
6
|
npx duaer-spec init --here
|
|
10
|
-
# pin: npx github:fujiezee/duaer-spec@v0.6.0 duaer init --here
|
|
11
7
|
```
|
|
12
8
|
|
|
9
|
+
## Update
|
|
10
|
+
|
|
13
11
|
```bash
|
|
14
|
-
npx duaer-spec
|
|
15
|
-
npx duaer-spec init --here --ops # default integration note: develop
|
|
12
|
+
npx duaer-spec update
|
|
16
13
|
```
|
|
17
14
|
|
|
18
|
-
|
|
19
|
-
`feat/*` / `fix/*` for work. See
|
|
20
|
-
[`docs/agent/branching-and-release.md`](docs/agent/branching-and-release.md).
|
|
15
|
+
That’s it. If you customized local files, glance at `git diff` once.
|
|
21
16
|
|
|
22
|
-
|
|
17
|
+
Ensure the repo has **`main`** and **`develop`**. See
|
|
18
|
+
[`docs/agent/branching-and-release.md`](docs/agent/branching-and-release.md).
|
|
23
19
|
|
|
24
|
-
|
|
20
|
+
Then talk to the agent in plain language.
|
|
25
21
|
|
|
26
|
-
|
|
27
|
-
- Playbook skill `duaer-do` (agent follows it; human need not invoke it)
|
|
28
|
-
- Agent ops: `AGENTS.md`, branching/release docs, mandatory `.worktree/`
|
|
29
|
-
- Optional step skills for large jobs (agent-only)
|
|
22
|
+
## Options
|
|
30
23
|
|
|
31
|
-
|
|
24
|
+
```bash
|
|
25
|
+
npx duaer-spec init --here --method
|
|
26
|
+
npx duaer-spec init --here --ops
|
|
27
|
+
npx duaer-spec update --method # rare; usually omit
|
|
28
|
+
```
|
|
32
29
|
|
|
33
|
-
|
|
34
|
-
|---|---|
|
|
35
|
-
| `main` | Production / online |
|
|
36
|
-
| `develop` | Day-to-day integration |
|
|
37
|
-
| `feat/<name>` | Features → `develop` |
|
|
38
|
-
| `fix/<name>` | Fixes → `develop` (hotfix via `main` then back to `develop`) |
|
|
30
|
+
## What you get
|
|
39
31
|
|
|
40
|
-
|
|
32
|
+
- Autonomous job loop (ask → Brief → work → accept)
|
|
33
|
+
- `.duaer/handoff.json` + `duaer handoff` after worktree remove
|
|
34
|
+
- Agent ops: `main` / `develop` / `feat` / `fix` + `.worktree/`
|
|
41
35
|
|
|
42
36
|
## Precedence
|
|
43
37
|
|
|
44
|
-
1. `AGENTS.md`
|
|
45
|
-
2. `DUADER.md` / `.duaer/`
|
|
46
|
-
|
|
47
|
-
## Updates
|
|
48
|
-
|
|
49
|
-
`duaer init --force` (review the diff) or pin a tag.
|
|
38
|
+
1. `AGENTS.md`
|
|
39
|
+
2. `DUADER.md` / `.duaer/`
|
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
|
|
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,47 +1,32 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.6.
|
|
4
|
-
|
|
5
|
-
### Mandatory branch model + release flows
|
|
6
|
-
|
|
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`
|
|
3
|
+
## 0.6.2 — 2026-09-15
|
|
15
4
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
### Mandatory in-repo worktrees
|
|
5
|
+
### Simple update
|
|
19
6
|
|
|
20
|
-
-
|
|
21
|
-
-
|
|
7
|
+
- `npx duaer-spec update` refreshes an existing install (no `--force` flags to remember)
|
|
8
|
+
- Remembers prior init mode from `.duaer/duaer-init.json`
|
|
9
|
+
- README / ADOPT: install + update are each one line
|
|
22
10
|
|
|
23
|
-
## 0.
|
|
11
|
+
## 0.6.1 — 2026-09-15
|
|
24
12
|
|
|
25
|
-
###
|
|
13
|
+
### Worktree → develop service handoff
|
|
26
14
|
|
|
27
|
-
-
|
|
15
|
+
- `.duaer/handoff.json` + `duaer handoff [--run]`
|
|
16
|
+
- Mandatory restart on develop after worktree remove
|
|
28
17
|
|
|
29
|
-
## 0.
|
|
30
|
-
|
|
31
|
-
- `/duaer-do` + `duaer status` everyday path (later reframed as agent-internal)
|
|
32
|
-
|
|
33
|
-
## 0.3.0 — 2026-09-15
|
|
18
|
+
## 0.6.0 — 2026-09-15
|
|
34
19
|
|
|
35
|
-
-
|
|
20
|
+
- Mandatory `main` / `develop` / `feat/*` / `fix/*` + release flows
|
|
36
21
|
|
|
37
|
-
## 0.
|
|
22
|
+
## 0.5.1 — 2026-09-15
|
|
38
23
|
|
|
39
|
-
-
|
|
24
|
+
- Mandatory `.worktree/` (gitignored)
|
|
40
25
|
|
|
41
|
-
## 0.
|
|
26
|
+
## 0.5.0 — 2026-09-15
|
|
42
27
|
|
|
43
|
-
-
|
|
28
|
+
- Autonomous digital employee
|
|
44
29
|
|
|
45
|
-
## 0.
|
|
30
|
+
## 0.4.0 — 0.1.0
|
|
46
31
|
|
|
47
|
-
|
|
32
|
+
See git history for earlier notes.
|
package/README.md
CHANGED
|
@@ -13,8 +13,13 @@ talk; the employee runs the process.
|
|
|
13
13
|
npx duaer-spec init --here
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
## Update
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npx duaer-spec update
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Then use Cursor as usual — describe what you want.
|
|
18
23
|
|
|
19
24
|
## What the employee does (by itself)
|
|
20
25
|
|
|
@@ -38,10 +43,13 @@ everyday human UI.
|
|
|
38
43
|
Go-live and flows by issue type:
|
|
39
44
|
[`docs/agent/branching-and-release.md`](docs/agent/branching-and-release.md).
|
|
40
45
|
|
|
46
|
+
**After merge:** `duaer handoff [--run]` restarts local services on `develop`
|
|
47
|
+
(configure commands in `.duaer/handoff.json`).
|
|
48
|
+
|
|
41
49
|
## Optional
|
|
42
50
|
|
|
43
51
|
```bash
|
|
44
|
-
npx duaer-spec
|
|
52
|
+
npx duaer-spec init --here --method
|
|
45
53
|
```
|
|
46
54
|
|
|
47
55
|
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,16 @@ 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
|
-
|
|
30
|
-
|
|
30
|
+
Install: npx duaer-spec init --here
|
|
31
|
+
Update: npx duaer-spec update
|
|
31
32
|
|
|
32
|
-
|
|
33
|
+
Then talk to the agent in plain language.
|
|
33
34
|
|
|
34
|
-
|
|
35
|
-
duaer
|
|
36
|
-
duaer check | policy | version
|
|
35
|
+
Also:
|
|
36
|
+
duaer handoff [--run] Restart services on develop after worktree remove
|
|
37
|
+
duaer status | check | policy | version | help
|
|
37
38
|
|
|
38
|
-
Init: --all
|
|
39
|
-
|
|
40
|
-
Example:
|
|
41
|
-
npx duaer-spec init --here
|
|
39
|
+
Init options: --all | --method | --ops | --force | --branch <n> | --here
|
|
42
40
|
`
|
|
43
41
|
|
|
44
42
|
function parseArgs(argv) {
|
|
@@ -55,20 +53,29 @@ function parseArgs(argv) {
|
|
|
55
53
|
allJobs: false,
|
|
56
54
|
strict: false,
|
|
57
55
|
policyMode: null,
|
|
56
|
+
run: false,
|
|
57
|
+
modeExplicit: false,
|
|
58
58
|
}
|
|
59
59
|
const rest = args.slice(1)
|
|
60
60
|
for (let i = 0; i < rest.length; i++) {
|
|
61
61
|
const a = rest[i]
|
|
62
|
-
if (a === '--all')
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
else if (a === '--
|
|
62
|
+
if (a === '--all') {
|
|
63
|
+
out.mode = 'all'
|
|
64
|
+
out.modeExplicit = true
|
|
65
|
+
} else if (a === '--method') {
|
|
66
|
+
out.mode = 'method'
|
|
67
|
+
out.modeExplicit = true
|
|
68
|
+
} else if (a === '--ops') {
|
|
69
|
+
out.mode = 'ops'
|
|
70
|
+
out.modeExplicit = true
|
|
71
|
+
} else if (a === '--force') out.force = true
|
|
66
72
|
else if (a === '--here') out.dir = '.'
|
|
67
73
|
else if (a === '--workplace') out.workplace = true
|
|
68
74
|
else if (a === '--delivery') out.delivery = true
|
|
69
75
|
else if (a === '--job') out.job = true
|
|
70
76
|
else if (a === '--all-jobs') out.allJobs = true
|
|
71
77
|
else if (a === '--strict' || a === '--gate') out.strict = true
|
|
78
|
+
else if (a === '--run') out.run = true
|
|
72
79
|
else if (a === '--branch') {
|
|
73
80
|
out.branch = rest[++i]
|
|
74
81
|
if (!out.branch) throw new Error('--branch requires a value')
|
|
@@ -170,11 +177,37 @@ function writeDefaultPolicy(target, { force }) {
|
|
|
170
177
|
console.log(' .duaer/delivery-policy.json (mode=coach)')
|
|
171
178
|
}
|
|
172
179
|
|
|
180
|
+
function defaultHandoff() {
|
|
181
|
+
return {
|
|
182
|
+
schemaVersion: 1,
|
|
183
|
+
onWorktreeRemove: {
|
|
184
|
+
stop:
|
|
185
|
+
'Stop any process whose working directory is under the request worktree (dev servers, file watchers, local APIs).',
|
|
186
|
+
restartFromPrimary: true,
|
|
187
|
+
commands: [],
|
|
188
|
+
},
|
|
189
|
+
notes:
|
|
190
|
+
'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.',
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function writeDefaultHandoff(target, { force }) {
|
|
195
|
+
const path = join(target, '.duaer', 'handoff.json')
|
|
196
|
+
if (existsSync(path) && !force) {
|
|
197
|
+
console.log(`skip (exists): ${path}`)
|
|
198
|
+
return
|
|
199
|
+
}
|
|
200
|
+
ensureDir(dirname(path))
|
|
201
|
+
writeFileSync(path, JSON.stringify(defaultHandoff(), null, 2) + '\n')
|
|
202
|
+
console.log(' .duaer/handoff.json')
|
|
203
|
+
}
|
|
204
|
+
|
|
173
205
|
function installMethod(target, opts) {
|
|
174
206
|
console.log('Installing Duaer method…')
|
|
175
207
|
copyPath(join(PKG_ROOT, '.duaer'), join(target, '.duaer'), opts)
|
|
176
208
|
console.log(' .duaer/')
|
|
177
209
|
writeDefaultPolicy(target, opts)
|
|
210
|
+
writeDefaultHandoff(target, opts)
|
|
178
211
|
|
|
179
212
|
ensureDir(join(target, '.cursor', 'skills'))
|
|
180
213
|
const skillsRoot = join(PKG_ROOT, '.cursor', 'skills')
|
|
@@ -303,10 +336,31 @@ function cmdInit(opts) {
|
|
|
303
336
|
console.log(`
|
|
304
337
|
Hired.
|
|
305
338
|
|
|
306
|
-
|
|
307
|
-
|
|
339
|
+
Talk to the agent in plain language.
|
|
340
|
+
Later update: npx duaer-spec update
|
|
341
|
+
`)
|
|
342
|
+
}
|
|
308
343
|
|
|
309
|
-
|
|
344
|
+
function cmdUpdate(opts) {
|
|
345
|
+
const target = resolve(opts.dir)
|
|
346
|
+
const marker = readJson(join(target, '.duaer', 'duaer-init.json'), null)
|
|
347
|
+
if (!marker && !existsSync(join(target, '.duaer')) && !existsSync(join(target, 'DUADER.md'))) {
|
|
348
|
+
console.log('No duaer install found here. Use: npx duaer-spec init --here')
|
|
349
|
+
process.exitCode = 1
|
|
350
|
+
return
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (!opts.modeExplicit && marker?.mode && ['all', 'method', 'ops'].includes(marker.mode)) {
|
|
354
|
+
opts.mode = marker.mode
|
|
355
|
+
}
|
|
356
|
+
if (marker?.branch) opts.branch = marker.branch
|
|
357
|
+
opts.force = true
|
|
358
|
+
|
|
359
|
+
console.log(`Updating → ${PKG.version}`)
|
|
360
|
+
cmdInit(opts)
|
|
361
|
+
console.log(`
|
|
362
|
+
Updated.
|
|
363
|
+
If you customized constitution / baseline / handoff commands, check git diff once.
|
|
310
364
|
`)
|
|
311
365
|
}
|
|
312
366
|
|
|
@@ -596,6 +650,49 @@ Not a git merge lock.
|
|
|
596
650
|
`)
|
|
597
651
|
}
|
|
598
652
|
|
|
653
|
+
function cmdHandoff(opts) {
|
|
654
|
+
const target = resolve(opts.dir)
|
|
655
|
+
const cfg = readJson(join(target, '.duaer', 'handoff.json'), defaultHandoff())
|
|
656
|
+
const block = cfg.onWorktreeRemove || {}
|
|
657
|
+
const commands = Array.isArray(block.commands) ? block.commands.filter(Boolean) : []
|
|
658
|
+
|
|
659
|
+
console.log(`Handoff @ ${target}`)
|
|
660
|
+
console.log('(worktree → merged develop / hotfix main)\n')
|
|
661
|
+
console.log('1. Confirm request branch is merged into develop (hotfix: main + back-merge develop)')
|
|
662
|
+
console.log(`2. Stop: ${block.stop || defaultHandoff().onWorktreeRemove.stop}`)
|
|
663
|
+
console.log('3. git worktree remove .worktree/<id> && git branch -d feat|fix/<name>')
|
|
664
|
+
console.log('4. Restart from primary checkout on the merged branch:\n')
|
|
665
|
+
|
|
666
|
+
if (!commands.length) {
|
|
667
|
+
console.log(' (no commands in .duaer/handoff.json)')
|
|
668
|
+
console.log(' Add e.g. "npm run dev" under onWorktreeRemove.commands')
|
|
669
|
+
console.log(' If you started a server in the worktree, re-run that same command here.')
|
|
670
|
+
} else {
|
|
671
|
+
for (const c of commands) console.log(` $ ${c}`)
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
if (opts.run) {
|
|
675
|
+
if (!commands.length) {
|
|
676
|
+
console.log('\n--run: nothing to start (commands empty).')
|
|
677
|
+
return
|
|
678
|
+
}
|
|
679
|
+
console.log('')
|
|
680
|
+
for (const c of commands) {
|
|
681
|
+
const child = spawn(c, {
|
|
682
|
+
shell: true,
|
|
683
|
+
cwd: target,
|
|
684
|
+
detached: true,
|
|
685
|
+
stdio: 'ignore',
|
|
686
|
+
})
|
|
687
|
+
child.unref()
|
|
688
|
+
console.log(`started (detached) pid=${child.pid}: ${c}`)
|
|
689
|
+
}
|
|
690
|
+
console.log('\nServices should now be bound to the primary checkout, not .worktree/.')
|
|
691
|
+
} else if (commands.length) {
|
|
692
|
+
console.log('\nTip: duaer handoff --run # start the commands above in the background')
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
|
|
599
696
|
function main() {
|
|
600
697
|
let opts
|
|
601
698
|
try {
|
|
@@ -611,9 +708,15 @@ function main() {
|
|
|
611
708
|
case 'init':
|
|
612
709
|
cmdInit(opts)
|
|
613
710
|
break
|
|
711
|
+
case 'update':
|
|
712
|
+
cmdUpdate(opts)
|
|
713
|
+
break
|
|
614
714
|
case 'check':
|
|
615
715
|
cmdCheck(opts)
|
|
616
716
|
break
|
|
717
|
+
case 'handoff':
|
|
718
|
+
cmdHandoff(opts)
|
|
719
|
+
break
|
|
617
720
|
case 'job':
|
|
618
721
|
case 'status':
|
|
619
722
|
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
|
-
→
|
|
52
|
-
|
|
53
|
-
|
|
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
|
-
|
|
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
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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 | `npx duaer-spec update` refreshes an existing install | 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 | `duaer update` | One-line refresh |
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "duaer-spec",
|
|
3
|
-
"version": "0.6.
|
|
4
|
-
"description": "Digital employees: autonomous
|
|
3
|
+
"version": "0.6.2",
|
|
4
|
+
"description": "Digital employees: autonomous delivery; main/develop/feat/fix; simple update",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"duaer": "bin/duaer.mjs",
|