@ronkovic/aad 0.3.3 → 0.3.5

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
@@ -63,13 +63,13 @@ cli (エントリポイント)
63
63
  ### インストール不要で実行 (推奨)
64
64
 
65
65
  ```bash
66
- bunx aad run requirements.md
66
+ bunx @ronkovic/aad run requirements.md
67
67
  ```
68
68
 
69
69
  ### グローバルインストール
70
70
 
71
71
  ```bash
72
- bun install -g aad
72
+ bun install -g @ronkovic/aad
73
73
  aad run requirements.md
74
74
  ```
75
75
 
@@ -151,14 +151,15 @@ aad resume <run_id>
151
151
  aad cleanup
152
152
  ```
153
153
 
154
- ### 4. Webダッシュボード (オプション)
154
+ ### 4. Webダッシュボード
155
155
 
156
+ ダッシュボードはデフォルトで有効です。`http://localhost:7333` でリアルタイムの進捗・ログ・依存グラフを確認できます。
157
+
158
+ 無効にする場合:
156
159
  ```bash
157
- aad run requirements.md --workers 4 --dashboard
160
+ aad run requirements.md --workers 4 --no-dashboard
158
161
  ```
159
162
 
160
- ブラウザで `http://localhost:7333` を開くと、リアルタイムで進捗・ログ・依存グラフを確認できます。
161
-
162
163
  ## 開発ガイド
163
164
 
164
165
  ### 環境セットアップ
@@ -264,16 +265,14 @@ AADはClaudeとの通信に2つのadapterを提供:
264
265
 
265
266
  サービスごとに使い分け可能:
266
267
 
267
- ```typescript
268
- const providerConfig = {
269
- default: 'cli',
270
- overrides: {
271
- splitter: 'sdk', // 構造化JSON出力
272
- reviewer: 'sdk', // 構造化レビュー結果
273
- }
274
- };
268
+ デフォルトは `sdk` です。CLIに変更する場合:
269
+
270
+ ```bash
271
+ aad run requirements.md --provider cli
275
272
  ```
276
273
 
274
+ サービスごとに使い分けも可能です(設定ファイルで指定)。
275
+
277
276
  ## トラブルシューティング
278
277
 
279
278
  ### ログの確認
@@ -286,7 +285,11 @@ cat .aad/docs/<run_id>/logs/structured.jsonl | bunx pino-pretty
286
285
  ### Worktreeが残っている
287
286
 
288
287
  ```bash
289
- aad cleanup --all
288
+ # 全AAD worktreeをクリーンアップ
289
+ aad cleanup
290
+
291
+ # 特定のrunのみ
292
+ aad cleanup <run_id>
290
293
  ```
291
294
 
292
295
  ### タスクがスタックした
@@ -296,7 +299,7 @@ aad cleanup --all
296
299
  aad status <run_id>
297
300
 
298
301
  # 強制クリーンアップ
299
- aad cleanup --run <run_id> --force
302
+ aad cleanup <run_id> --force
300
303
  ```
301
304
 
302
305
  ## ライセンス
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ronkovic/aad",
3
- "version": "0.3.3",
3
+ "version": "0.3.5",
4
4
  "description": "Autonomous Agent Development Orchestrator - Multi-agent TDD pipeline powered by Claude",
5
5
  "module": "src/main.ts",
6
6
  "type": "module",
@@ -102,10 +102,10 @@ export async function cleanupWorktrees(
102
102
  await worktreeManager.pruneWorktrees();
103
103
  logger.info("Pruned orphaned worktrees");
104
104
 
105
- // 4. Cleanup orphaned branches
105
+ // 4. Cleanup orphaned branches (always force-delete — AAD branches are safe to remove)
106
106
  const deletedBranches = runId
107
- ? await branchManager.cleanupOrphanBranches(runId)
108
- : await branchManager.cleanupOrphanBranches();
107
+ ? await branchManager.cleanupOrphanBranches(runId, true)
108
+ : await branchManager.cleanupOrphanBranches(undefined, true);
109
109
 
110
110
  if (deletedBranches.length > 0) {
111
111
  console.log(`\nDeleted ${deletedBranches.length} orphan branch(es):`);
@@ -122,7 +122,15 @@ export async function resumeRun(app: App, runIdStr: string): Promise<void> {
122
122
  stores: { runStore: stores.runStore, taskStore: stores.taskStore },
123
123
  logger,
124
124
  });
125
- registerTaskDispatchHandler({ app, runId, parentBranch: runState.parentBranch });
125
+ // Check if parent worktree exists from a previous run
126
+ const parentWorktreePath = `${process.cwd()}/.aad/worktrees/parent-${runId}`;
127
+ const parentWorktreeExists = await Bun.file(`${parentWorktreePath}/.git`).exists();
128
+ registerTaskDispatchHandler({
129
+ app,
130
+ runId,
131
+ parentBranch: runState.parentBranch,
132
+ parentWorktreePath: parentWorktreeExists ? parentWorktreePath : undefined,
133
+ });
126
134
 
127
135
  // 6. Dispatcher.start()
128
136
  dispatcher.start();
@@ -144,8 +144,17 @@ export async function runPipeline(app: App, requirementsPath: string, keepWorktr
144
144
  logger,
145
145
  });
146
146
 
147
- // 5. Register task dispatch handler (shared with resume)
148
- registerTaskDispatchHandler({ app, runId, parentBranch });
147
+ // 5. Create parent worktree for merging task branches
148
+ let parentWorktreePath: string | undefined;
149
+ try {
150
+ parentWorktreePath = await worktreeManager.createParentWorktree(runId, parentBranch);
151
+ logger.info({ parentWorktreePath }, "Parent worktree created for merging");
152
+ } catch (error) {
153
+ logger.warn({ error }, "Failed to create parent worktree, using repo root as fallback");
154
+ }
155
+
156
+ // 5.5. Register task dispatch handler (shared with resume)
157
+ registerTaskDispatchHandler({ app, runId, parentBranch, parentWorktreePath });
149
158
 
150
159
  // 6. 進捗表示
151
160
  const progressSpinner = createSpinner("Executing tasks...");
@@ -25,6 +25,9 @@ export interface TaskDispatchContext {
25
25
  app: App;
26
26
  runId: RunId;
27
27
  parentBranch: string;
28
+ /** Path to the parent worktree where task branches are merged into.
29
+ * If not provided, falls back to process.cwd() (repo root). */
30
+ parentWorktreePath?: string;
28
31
  }
29
32
 
30
33
  /**
@@ -32,7 +35,8 @@ export interface TaskDispatchContext {
32
35
  * Handles memory gate, worker state, worktree creation, and TDD pipeline execution.
33
36
  */
34
37
  export function registerTaskDispatchHandler(ctx: TaskDispatchContext): void {
35
- const { app, runId, parentBranch } = ctx;
38
+ const { app, runId, parentBranch, parentWorktreePath } = ctx;
39
+ const mergeTarget = parentWorktreePath ?? process.cwd();
36
40
  const { eventBus, logger, config, processManager, worktreeManager, providerRegistry, stores } = app;
37
41
 
38
42
  let memoryGateLock: Promise<void> = Promise.resolve();
@@ -63,7 +67,7 @@ export function registerTaskDispatchHandler(ctx: TaskDispatchContext): void {
63
67
 
64
68
  const provider = providerRegistry.getProvider("implementer");
65
69
  const result = await executeTddPipeline(
66
- task, workspace, branchName, parentBranch, process.cwd(),
70
+ task, workspace, branchName, parentBranch, mergeTarget,
67
71
  runId, app.config, provider, app.mergeService, eventBus,
68
72
  );
69
73
 
@@ -17,8 +17,26 @@ export interface MemoryStatus {
17
17
 
18
18
  /**
19
19
  * Get current system memory status (macOS only)
20
+ *
21
+ * Uses vm_stat but counts inactive + free + speculative as "available" memory.
22
+ * macOS aggressively caches files in inactive pages which are immediately
23
+ * reclaimable — counting only "free" pages dramatically underreports
24
+ * available memory (e.g. 0.2GB "free" when 4GB+ is actually available).
25
+ *
26
+ * Environment variable AAD_SKIP_MEMORY_CHECK=1 disables all memory checks.
20
27
  */
21
28
  export async function getMemoryStatus(): Promise<MemoryStatus> {
29
+ // Allow disabling memory checks entirely
30
+ if (process.env.AAD_SKIP_MEMORY_CHECK === "1") {
31
+ return {
32
+ totalGB: 16,
33
+ usedGB: 0,
34
+ freeGB: 16,
35
+ usedPercent: 0,
36
+ isLowMemory: false,
37
+ };
38
+ }
39
+
22
40
  const proc = Bun.spawn(["vm_stat"], { stdout: "pipe" });
23
41
  const stdout = await new Response(proc.stdout).text();
24
42
  const code = await proc.exited;
@@ -31,6 +49,7 @@ export async function getMemoryStatus(): Promise<MemoryStatus> {
31
49
  const inactiveMatch = stdout.match(/Pages inactive:\s+(\d+)/);
32
50
  const speculativeMatch = stdout.match(/Pages speculative:\s+(\d+)/);
33
51
  const wiredMatch = stdout.match(/Pages wired down:\s+(\d+)/);
52
+ const purgableMatch = stdout.match(/Pages purgeable:\s+(\d+)/);
34
53
 
35
54
  if (!pageSizeMatch || !freeMatch || !activeMatch || !inactiveMatch || !wiredMatch) {
36
55
  throw new Error("Failed to parse vm_stat output");
@@ -42,30 +61,33 @@ export async function getMemoryStatus(): Promise<MemoryStatus> {
42
61
  const inactivePages = parseInt(inactiveMatch[1]!, 10);
43
62
  const speculativePages = parseInt(speculativeMatch?.[1] ?? "0", 10);
44
63
  const wiredPages = parseInt(wiredMatch[1]!, 10);
64
+ const purgablePages = parseInt(purgableMatch?.[1] ?? "0", 10);
45
65
 
46
66
  // Calculate memory in GB
47
67
  const bytesToGB = (bytes: number) => bytes / (1024 * 1024 * 1024);
48
68
  const pagesToGB = (pages: number) => bytesToGB(pages * pageSize);
49
69
 
50
- const freeGB = pagesToGB(freePages + speculativePages);
51
- const usedGB = pagesToGB(activePages + inactivePages + wiredPages);
52
- const totalGB = freeGB + usedGB;
70
+ // Available = free + inactive + speculative + purgeable
71
+ // macOS reclaims inactive/purgeable pages on demand — they are effectively free
72
+ const availableGB = pagesToGB(freePages + inactivePages + speculativePages + purgablePages);
73
+ const usedGB = pagesToGB(activePages + wiredPages);
74
+ const totalGB = availableGB + usedGB;
53
75
  const usedPercent = (usedGB / totalGB) * 100;
54
76
 
55
- // Determine if memory is low
56
- const isLowMemory = freeGB < 2.0; // Less than 2GB free
77
+ // Determine if memory is low (using available, not just free)
78
+ const isLowMemory = availableGB < 2.0;
57
79
  let recommendedAction: string | undefined;
58
80
 
59
- if (freeGB < 1.5) {
60
- recommendedAction = "Critical: Free memory < 1.5GB. Close heavy applications (Chrome, Docker) before running AAD.";
61
- } else if (freeGB < 2.5) {
62
- recommendedAction = "Warning: Free memory < 2.5GB. Consider closing unnecessary applications.";
81
+ if (availableGB < 1.5) {
82
+ recommendedAction = "Critical: Available memory < 1.5GB. Close heavy applications (Chrome, Docker) before running AAD.";
83
+ } else if (availableGB < 2.5) {
84
+ recommendedAction = "Warning: Available memory < 2.5GB. Consider closing unnecessary applications.";
63
85
  }
64
86
 
65
87
  return {
66
88
  totalGB: Math.round(totalGB * 10) / 10,
67
89
  usedGB: Math.round(usedGB * 10) / 10,
68
- freeGB: Math.round(freeGB * 10) / 10,
90
+ freeGB: Math.round(availableGB * 10) / 10,
69
91
  usedPercent: Math.round(usedPercent),
70
92
  isLowMemory,
71
93
  recommendedAction,