@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 +19 -16
- package/package.json +1 -1
- package/src/modules/cli/commands/cleanup.ts +3 -3
- package/src/modules/cli/commands/resume.ts +9 -1
- package/src/modules/cli/commands/run.ts +11 -2
- package/src/modules/cli/commands/task-dispatch-handler.ts +6 -2
- package/src/shared/memory-check.ts +32 -10
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
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
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
|
-
|
|
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
|
|
302
|
+
aad cleanup <run_id> --force
|
|
300
303
|
```
|
|
301
304
|
|
|
302
305
|
## ライセンス
|
package/package.json
CHANGED
|
@@ -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
|
-
|
|
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.
|
|
148
|
-
|
|
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,
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
const
|
|
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 =
|
|
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 (
|
|
60
|
-
recommendedAction = "Critical:
|
|
61
|
-
} else if (
|
|
62
|
-
recommendedAction = "Warning:
|
|
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(
|
|
90
|
+
freeGB: Math.round(availableGB * 10) / 10,
|
|
69
91
|
usedPercent: Math.round(usedPercent),
|
|
70
92
|
isLowMemory,
|
|
71
93
|
recommendedAction,
|