@angar2/taskery 1.0.3 → 1.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.
package/bin/prepare.js CHANGED
@@ -5,6 +5,7 @@ const os = require('os');
5
5
  const { execFileSync } = require('child_process');
6
6
  const L = require('./lib');
7
7
  const B = require('./backlog');
8
+ const H = require('./hosts');
8
9
 
9
10
  const SLUG_RE = /^[a-z0-9]+(-[a-z0-9]+)*$/;
10
11
 
@@ -82,32 +83,6 @@ function nextNumber(main) {
82
83
  return max + 1;
83
84
  }
84
85
 
85
- function worktreePaths(main) {
86
- const out = L.git(main, ['worktree', 'list', '--porcelain']);
87
- return out
88
- .split('\n')
89
- .filter((l) => l.startsWith('worktree '))
90
- .map((l) => l.slice('worktree '.length));
91
- }
92
-
93
- // Orca 워크트리 — 만든 뒤 브랜치 이름을 리포 규칙대로 바꾼다(§3-4)
94
- function createOrcaWorktree(main, { name, parent, branch }) {
95
- const before = new Set(worktreePaths(main));
96
- try {
97
- execFileSync('orca', ['worktree', 'create', '--repo', `path:${main}`, '--name', name, '--base-branch', parent, '--json'], {
98
- encoding: 'utf8',
99
- stdio: ['ignore', 'pipe', 'pipe'],
100
- });
101
- } catch (e) {
102
- L.fail(`Orca 워크트리를 만들지 못했다: ${((e.stderr || '') + (e.stdout || '')).toString().trim() || e.message}`);
103
- }
104
- const created = worktreePaths(main).filter((p) => !before.has(p));
105
- if (created.length !== 1) L.fail(`Orca가 만든 워크트리를 찾지 못했다(새 워크트리 ${created.length}개). 'git worktree list'로 확인한다.`);
106
- const wt = created[0];
107
- L.git(wt, ['branch', '-m', branch]);
108
- return wt;
109
- }
110
-
111
86
  function createTaskeryWorktree(main, { projectId, nnn, slug, parent, branch }) {
112
87
  const root = path.join(os.homedir(), '.taskery', 'worktrees', projectId);
113
88
  fs.mkdirSync(root, { recursive: true });
@@ -255,6 +230,7 @@ async function prepareTask(ctx, a) {
255
230
  const noWorktree = noBranch || !!a['no-worktree'];
256
231
  const parent = checkMain(main);
257
232
 
233
+ const host = H.current();
258
234
  const opened = await L.withLock(main, 'number', async () => {
259
235
  const fromNums = a.from ? B.parseFromList(main, a.from) : [];
260
236
  const num = nextNumber(main);
@@ -266,17 +242,12 @@ async function prepareTask(ctx, a) {
266
242
  const startCommit = L.git(main, ['rev-parse', 'HEAD']);
267
243
 
268
244
  let worktree = null;
269
- let by = '생략';
270
245
  if (noBranch) {
271
246
  // 본진의 현재 브랜치(부모)에서 그대로 일한다
272
247
  } else if (noWorktree) {
273
248
  L.git(main, ['checkout', '-b', branch]);
274
- } else if (L.inOrca()) {
275
- worktree = createOrcaWorktree(main, { name: `TASK-${nnn}-${a.slug}`, parent, branch });
276
- by = 'orca';
277
249
  } else {
278
250
  worktree = createTaskeryWorktree(main, { projectId: manifest.projectId, nnn, slug: a.slug, parent, branch });
279
- by = 'taskery';
280
251
  }
281
252
  L.ensureExclude(main, manifest.buildOutput);
282
253
  if (worktree) plant(main, worktree);
@@ -294,7 +265,6 @@ async function prepareTask(ctx, a) {
294
265
  doc,
295
266
  branch,
296
267
  parent,
297
- by,
298
268
  worktree,
299
269
  noWorktree,
300
270
  noBranch,
@@ -323,16 +293,20 @@ async function prepareTask(ctx, a) {
323
293
  else if (noWorktree) out.push(`- 브랜치: ${branch} — 본진을 이 브랜치로 옮겼다(--no-worktree). 본진에서 일한다.`);
324
294
  else {
325
295
  out.push(`- 브랜치: ${branch}`);
326
- out.push(`- 워크트리: ${worktree} (${by === 'orca' ? 'Orca가 만듦' : 'taskery가 만듦'})`);
296
+ out.push(`- 워크트리: ${worktree}`);
327
297
  }
328
298
  if (st.from) out.push(`- 백로그: ${st.from.join(', ')} — 진행`);
329
299
  if (itemNote) out.push(`- 알림: ${itemNote}`);
330
300
  for (const n of fromNotes) out.push(`- 알림: ${n}`);
331
- return { out, worktree };
301
+ return { out, worktree, parent };
332
302
  });
333
303
 
334
304
  // ⑤ 워크트리 준비 — 번호 잠금 밖에서 한다(동시에 여는 태스크끼리 기다리지 않게)
335
305
  const out = opened.out;
306
+ // 이 세션이 도는 터미널 앱의 목록에 워크트리를 붙인다(붙이는 방법이 있는 앱만)
307
+ if (opened.worktree && host && host.attach) {
308
+ for (const n of host.attach(main, { worktree: opened.worktree, parent: opened.parent })) out.push(`- 알림: ${n}`);
309
+ }
336
310
  if (opened.worktree) {
337
311
  const prep = [...cloneBuildOutputs(main, opened.worktree, manifest.buildOutput), ...(await installPackages(opened.worktree))];
338
312
  for (const n of prep) out.push(`- 준비: ${n}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@angar2/taskery",
3
- "version": "1.0.3",
3
+ "version": "1.1.0",
4
4
  "description": "AI 코딩 에이전트(Claude Code·Codex)에게 일을 태스크 단위로 맡겨 기획·개발·테스트·병합까지 진행하게 하는 작업 체계",
5
5
  "bin": {
6
6
  "taskery": "bin/taskery.js",
@@ -44,9 +44,11 @@
44
44
  | `backlog-add "<제목>" [--type <종류>]` | 백로그 번호를 발급해 `BACKLOG.md` 열린 항목 맨 위에 빈 양식 |
45
45
  | `backlog-get [BL-번호]` | 번호를 주면 그 항목 전문, 없으면 열린 항목 목록 |
46
46
  | `backlog-mark <BL-번호> <TASK>` | `--from` 없이 연 태스크를 백로그 항목에 연결 |
47
- | `orca-dispatch-task <TASK> [--agent claude\|codex --model <모델>] [--manual] [--scope "<맡는 일>"] [--avoid "<손대지 않는 것>"] [--read "<먼저 읽을 것>"] [--extra "<그 밖>"]` | Orca 새 탭에 태스크 세션을 띄우고 첫 지시문을 보낸다(`--manual`이 아니면 `--agent`·`--model` 필수, 탭 handle은 `.state`에 남는다). `--manual`이면 띄우지 않고 작업 폴더·실행 안내와 함께 사용자가 붙여 넣을 첫 지시문을 출력한다(손 전달) |
47
+ | `dispatch-task <TASK> [--agent claude\|codex --model <모델>] [--manual] [--scope "<맡는 일>"] [--avoid "<손대지 않는 것>"] [--read "<먼저 읽을 것>"] [--extra "<그 밖>"]` | 이 세션이 도는 터미널 앱(Orca·Herdr)의 새 탭에 태스크 세션을 띄우고 첫 지시문을 보낸다(`--manual`이 아니면 `--agent`·`--model` 필수, 탭 기록은 `.state`에 남는다). 에이전트가 확인 창에서 멈춰 다시 부르면 열린 탭에 첫 지시만 보낸다. `--manual`이면 띄우지 않고 작업 폴더·실행 안내와 함께 사용자가 붙여 넣을 첫 지시문을 출력한다(손 전달) |
48
+ | `send-task <TASK> "<말>"` | 띄운 태스크 탭에 말을 보낸다. 앞에 `[오케스트레이션]`을 붙인다 |
49
+ | `read-task <TASK>` | 띄운 태스크 탭의 지금 화면을 읽는다 |
48
50
  | `report-task <TASK> "<한 줄>"` | 태스크 세션이 오케스트레이션에 보고 한 줄을 남긴다(`.taskery/reports.log`) |
49
- | `wait-reports` | 오케스트레이션이 백그라운드 셸로 걸어 두는 대기. 안 읽은 보고가 생기면 출력하고 끝나고, 보고 없이 60분이면 오래 조용한 태스크 탭 목록과 함께 끝난다 (CLI만) |
51
+ | `wait-reports` | 오케스트레이션이 백그라운드 셸로 걸어 두는 대기. 안 읽은 보고가 생기면 출력하고 끝나고, 보고 없이 60분이면 살펴볼 태스크 탭 목록(터미널 앱이 알려 주는 신호로 고른다)과 함께 끝난다 (CLI만) |
50
52
  | `init` · `update` · `add <claude\|codex>` | 설치 · 갱신 · 플랫폼 추가 (CLI만) |
51
53
 
52
54
  태스크 명령(`approve-plan`~`merge-task`)에 `--range "<새 범위>"`를 붙이면 태스크 문서 헤더 표의 범위 칸만 바뀐다.
@@ -59,7 +61,7 @@
59
61
  ## 5. 워크트리
60
62
 
61
63
  - 모든 태스크는 브랜치와 워크트리를 분기한다. 태스크 수행은 그 워크트리 안에서 한다.
62
- - 워크트리는 Orca 탭 안이면 Orca가, 아니면 `~/.taskery/worktrees/<projectId>/`에 taskery가 만든다.
64
+ - 워크트리는 어느 터미널 앱 안이든 `~/.taskery/worktrees/<projectId>/`에 taskery가 만든다. Orca·Herdr 안이면 그 앱의 목록에 부모 브랜치의 하위로 붙는다.
63
65
  - 부모 브랜치 = 본진(리포 원래 폴더)이 서 있는 브랜치다. 본진은 다른 태스크가 병합받는 자리라 부모 브랜치에 그대로 둔다.
64
66
  - 생략은 사용자가 명시할 때만: `--no-worktree`(본진에서 브랜치만), `--no-branch`(본진의 현재 브랜치에서). 생략 태스크가 열려 있는 동안 본진이 부모 브랜치를 떠나 있거나 커밋 안 된 코드를 가지면, 다른 태스크의 `prepare-task`·`merge-task`가 원인 태스크를 알리고 멈춘다.
65
67
  - 워크트리를 지우는 일은 태스크를 연 주인이 본진에서 `close-task`로 한다. 정리가 막혀 남은 것은 `prune`으로 정리한다.
@@ -111,3 +113,5 @@
111
113
  | 2026-10-01 | S3 — 오케스트레이션 명령 `orca-dispatch-task`·`report-task`·`wait-reports`와 `reports.log`를 더했다 |
112
114
  | 2026-10-01 | S2 — `prune`·`backlog-*`·`prepare-task --from`·`status`의 시작할 수 있는 태스크, 새 워크트리 준비(빌드 결과 폴더 APFS 복제·exclude 등록·닫을 때 본진 씨앗 갱신·`npm ci`)를 더했다 |
113
115
  | 2026-10-09 | 첫 지시문 정형화 — orca-dispatch-task의 --note를 칸별 인자로 바꾸고 손 전달(--manual)을 더했다. wait-reports 기다리는 시간을 60분으로 늘렸다 |
116
+ | 2026-11-12 | 터미널 앱 어댑터 — orca-dispatch-task를 dispatch-task로 바꾸고 send-task·read-task를 더했다. Herdr에서도 태스크 탭을 띄운다 |
117
+ | 2026-11-13 | 워크트리를 어느 터미널 앱 안이든 taskery가 만들고 앱 목록에는 부모 브랜치의 하위로 붙인다 |
@@ -1,16 +1,16 @@
1
1
  ---
2
2
  name: task-orche
3
- description: 오케스트레이션 — 백로그를 태스크로 기획하고, 태스크마다 열어 Orca 새 탭의 태스크 세션에 맡기고, 보고를 받아 끝난 태스크를 정리한다
3
+ description: 오케스트레이션 — 백로그를 태스크로 기획하고, 태스크마다 열어 새 탭의 태스크 세션에 맡기고, 보고를 받아 끝난 태스크를 정리한다
4
4
  ---
5
5
 
6
6
  # task-orche
7
7
 
8
8
  오케스트레이션 세션이 본진에서 여러 태스크를 기획·배분·정리하는 스킬이다.
9
9
 
10
- - 태스크는 서브에이전트에 맡기지 않는다. 태스크 세션은 Orca 새 탭의 독립 세션이며, 사용자가 그 탭에서 확인하고 개입할 수 있어야 한다.
11
- - 태스크마다 `task-init`(여는 일)을 이 세션이 하고, `orca-dispatch-task`로 태스크 세션을 띄운다. 에이전트와 모델은 사용자가 정하고, 정하지 않았으면 태스크 구성 확인 때 묻는다.
10
+ - 태스크는 서브에이전트에 맡기지 않는다. 태스크 세션은 이 세션이 도는 터미널 앱의 새 탭에서 도는 독립 세션이며, 사용자가 그 탭에서 확인하고 개입할 수 있어야 한다.
11
+ - 태스크마다 `task-init`(여는 일)을 이 세션이 하고, `dispatch-task`로 태스크 세션을 띄운다. 어느 터미널 앱에 띄울지는 명령이 정한다. 에이전트와 모델은 사용자가 정하고, 정하지 않았으면 태스크 구성 확인 때 묻는다.
12
12
  - 첫 지시문의 역할·작업 방식은 명령이 같은 문장으로 채운다. 이 세션은 이번 태스크만의 지시를 칸별로 넘긴다 — `--scope`(맡는 일)·`--avoid`(손대지 않는 것)·`--read`(태스크 문서·플랜 문서 말고 먼저 읽을 것)·`--extra`(그 밖). 리포 규칙(`*.local.md`)에 이미 있는 것과 첫 지시문에 이미 있는 것(보고·멈춤 등)은 다시 쓰지 않는다. 필요 없는 칸은 비운다.
13
- - **손 전달**: Orca를 쓸 수 없거나(Orca 밖·탭 띄우기 실패) 사용자가 태스크 세션을 직접 열겠다고 하면 `orca-dispatch-task --manual`로 부른다. 명령이 내는 작업 폴더·실행 안내·첫 지시문을 사용자에게 전해 붙여 넣어 달라고 하고, `wait-reports`가 걸려 있지 않으면 곧바로 건다(사용자가 언제 붙여 넣든 보고는 `reports.log`에 남는다).
13
+ - **손 전달**: 명령이 탭을 띄울 수 없다고 하거나(지원하는 터미널 앱 밖·탭 띄우기 실패) 사용자가 태스크 세션을 직접 열겠다고 하면 `dispatch-task --manual`로 부른다. 명령이 내는 작업 폴더·실행 안내·첫 지시문을 사용자에게 전해 붙여 넣어 달라고 하고, `wait-reports`가 걸려 있지 않으면 곧바로 건다(사용자가 언제 붙여 넣든 보고는 `reports.log`에 남는다).
14
14
  - 손으로 연 세션에 보낼 말도 `[오케스트레이션]`을 붙여 사용자에게 전달을 부탁한다.
15
15
  - 마무리 완료 보고(병합, 또는 병합이 없는 태스크의 마무리)가 오면 `close-task`로 정리하고, 연결된 백로그와 남은 태스크를 확인한다.
16
16
  - 보고에 `.local` 규칙 제안이 담겨 오면 사용자에게 보여 주고, 사용자가 이 세션에서 승인하면 이 세션이 `.local`에 넣는다.
@@ -21,18 +21,19 @@ description: 오케스트레이션 — 백로그를 태스크로 기획하고,
21
21
  사용자가 준 지침(동시 진행 수·순서·제외할 태스크)이 있으면 그것을 먼저 따른다.
22
22
 
23
23
  - **태스크 구성 확인**: 무엇을 어떤 태스크로 묶어 어떤 순서·에이전트로 진행할지 사용자가 아직 보지 않았다면, 태스크를 열기 전에 표 하나(태스크별 백로그 항목·한 줄 목표·크기·스위치·선행 태스크·에이전트와 모델)로 보여 주고 확인받는다. 사용자의 지시가 이미 구성과 진행 방식을 정했으면(예: "로드맵 30건을 순서대로 진행해") 다시 묻지 않고 그대로 진행한다. 정한 구성은 `PLAN.md` 태스크 목록에 항목으로 적고(이미 있으면 그대로), 태스크를 열 때 `--item`으로 잇는다 — 아직 열지 않은 태스크도 대화가 아니라 파일에 남는다.
24
- - **여러 태스크를 한꺼번에 열 때**: 백로그 읽기·태스크 나누기·이름·크기·스위치는 모든 태스크를 한 번에 본 뒤 정한다. `prepare-task`와 `orca-dispatch-task`는 태스크마다 동시에 불러도 된다.
24
+ - **여러 태스크를 한꺼번에 열 때**: 백로그 읽기·태스크 나누기·이름·크기·스위치는 모든 태스크를 한 번에 본 뒤 정한다. `prepare-task`와 `dispatch-task`는 태스크마다 동시에 불러도 된다.
25
25
  - **동시에 돌려도 되는가**: `PLAN.md`에 적힌 선행 태스크가 모두 끝난 항목만 연다(`prepare-task --item <항목 번호>` — 선행이 끝나기 전에 열면 선행 코드가 없는 부모에서 갈라진다)(끝났는지는 `status`가 보여 준다). 선행 관계가 없어도 같은 파일을 크게 만지는 태스크끼리는 동시에 돌리면 병합 때 충돌하기 쉬우므로 순서를 두는 편이 낫다.
26
26
  - **태스크가 많을 때**: 동시에 진행하는 태스크 세션 수에 상한을 둔다. 사용자가 정하지 않았으면 시작 전에 한 번 묻는다. 태스크 하나가 끝나 정리되면 시작할 수 있는 다음 태스크로 빈자리를 채운다.
27
27
  - **순서가 정해진 로드맵일 때**: 시작할 수 있는 태스크가 한 번에 하나뿐이므로 하나씩 돌아간다. 태스크가 끝나 정리되면 곧바로 새 탭에 다음 태스크를 맡긴다.
28
+ - **띄우기가 확인 창에서 멈출 때**: `dispatch-task`가 에이전트가 확인 창(폴더 신뢰 등)에서 멈췄다고 하면, `read-task`로 그 탭 화면을 읽어 무엇을 묻는지 보고 "TASK-012 — 폴더 신뢰 확인 대기, TASK-012 탭에서 확인해 주세요"처럼 한 줄로 알린다. 사용자가 확인했다고 하면 `dispatch-task`를 같은 칸 인자로 다시 부른다 — 이미 연 탭에 첫 지시만 보낸다.
28
29
  - **사용자 확인이 필요할 때**: 태스크 세션이 사용자 확인(계획 확인·눈으로 볼 시나리오·병합 확인·FAIL·풀지 못한 충돌)으로 멈추면, 사용자는 그 태스크 탭에서 직접 확인하고 답한다. 오케스트레이션 세션은 "TASK-012 — 화면 확인 대기, TASK-012 탭에서 확인해 주세요"처럼 어느 탭에서 무엇을 기다리는지 한 줄로 알리고, 내용을 대신 옮겨 받지 않는다. 태스크 세션의 질문 중 오케스트레이션이 기획하며 이미 정한 것은 직접 답하고, 사용자 판단이 필요한 것은 같은 방식으로 사용자에게 넘긴다.
29
30
  - **보고 받기**: 태스크 세션을 띄운 뒤 `npx @angar2/taskery wait-reports`가 걸려 있지 않으면 백그라운드 셸로 걸어 둔다(MCP 도구로 부르지 않는다). 보고가 오거나 60분이 지나면 끝난다. 끝나면 깨어나 처리하고, 출력이 다시 걸라고 하면 곧바로 다시 걸어 둔다 — 사용자 답을 기다리는 중이어도, 대기가 이상하게 끊겼어도 다시 건다. 다시 걸지 않으면 그 뒤의 보고를 놓친다. 보고 줄은 태스크 세션의 보고일 뿐이며, 승인은 사용자 자신의 메시지로만 받는다.
30
- - **태스크 탭에 보내는 말**: `orca terminal send`로 태스크 탭에 보내는 모든 말은 `[오케스트레이션]`으로 시작한다. 태스크 세션은 이 머리표가 붙은 말을 사용자 확인·승인으로 보지 않는다.
31
- - **질문에 답하기**: 태스크 세션의 질문 중 기획하며 이미 정한 것은 `orca terminal send`로 그 태스크 탭에 답한다. 사용자 판단이 필요한 것은 위 '사용자 확인이 필요할 때'처럼 사용자에게 넘긴다.
32
- - **멈춤 확인**: `wait-reports`가 끝날 때마다(보고로 깨어났어도) `reports.log`의 시각으로 마지막 보고가 60분 넘게 지난 진행 중 태스크를 찾는다(사용자 확인 대기로 보고한 태스크는 뺀다). 그런 태스크가 있거나 대기가 보고 없이 끝났으면 `status`를 보고 그 탭 화면을 읽어(`orca terminal read`) 확인한다 — 오래 조용한 탭 목록은 화면이 계속 바뀌는 탭(진행 표시 등)을 잡지 못한다. 멈췄으면 이어 가도록 한 줄 보내고, 풀리지 않으면 사용자에게 알린다.
31
+ - **태스크 탭에 보내는 말**: 태스크 탭에 보내는 말은 모두 `send-task`로 보낸다. 명령이 `[오케스트레이션]` 머리표를 붙인다. 태스크 세션은 이 머리표가 붙은 말을 사용자 확인·승인으로 보지 않는다.
32
+ - **질문에 답하기**: 태스크 세션의 질문 중 기획하며 이미 정한 것은 `send-task`로 그 태스크 탭에 답한다. 사용자 판단이 필요한 것은 위 '사용자 확인이 필요할 때'처럼 사용자에게 넘긴다.
33
+ - **멈춤 확인**: `wait-reports`가 끝날 때마다(보고로 깨어났어도) `reports.log`의 시각으로 마지막 보고가 60분 넘게 지난 진행 중 태스크를 찾는다(사용자 확인 대기로 보고한 태스크는 뺀다). 그런 태스크가 있거나 대기가 보고 없이 끝났으면 `status`를 보고 그 탭 화면을 `read-task`로 읽어 확인한다 — `wait-reports`가 함께 내는 살펴볼 탭 목록은 터미널 앱이 알려 주는 신호로만 고른 것이라 놓치는 탭이 있다. 멈췄으면 이어 가도록 `send-task`로 한 줄 보내고, 풀리지 않으면 사용자에게 알린다.
33
34
  - **오래 운영할 때**: 진행 상황을 대화 기억에 기대지 않는다. 대화가 요약된 뒤에도 `PLAN.md`·각 태스크 문서·`status`로 어디까지 왔는지 다시 확인하고 이어 간다.
34
35
  - **더 시작할 수 없을 때**: 진행 중인 태스크가 없고 시작할 수 있는 태스크도 없으면, 남은 태스크와 막힌 이유를 사용자에게 보고한다.
35
36
 
36
37
  ## 부르는 명령
37
38
 
38
- - `prepare-task`, `orca-dispatch-task`, `wait-reports`, `close-task`
39
+ - `prepare-task`, `dispatch-task`, `send-task`, `read-task`, `wait-reports`, `close-task`