taskplane 0.29.2 → 0.30.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/gitignore-patterns.mjs +11 -8
- package/bin/rpc-wrapper.mjs +410 -357
- package/bin/taskplane.mjs +533 -250
- package/extensions/reviewer-extension.ts +17 -11
- package/extensions/taskplane/abort.ts +50 -18
- package/extensions/taskplane/agent-bridge-extension.ts +232 -105
- package/extensions/taskplane/agent-host.ts +224 -97
- package/extensions/taskplane/cleanup.ts +71 -42
- package/extensions/taskplane/config-loader.ts +142 -58
- package/extensions/taskplane/config-schema.ts +6 -13
- package/extensions/taskplane/config.ts +10 -2
- package/extensions/taskplane/diagnostic-reports.ts +59 -47
- package/extensions/taskplane/diagnostics.ts +13 -13
- package/extensions/taskplane/discovery.ts +35 -61
- package/extensions/taskplane/engine-worker.ts +53 -46
- package/extensions/taskplane/engine.ts +1760 -602
- package/extensions/taskplane/execution.ts +426 -206
- package/extensions/taskplane/extension.ts +1073 -598
- package/extensions/taskplane/formatting.ts +136 -124
- package/extensions/taskplane/git.ts +0 -2
- package/extensions/taskplane/lane-runner.ts +542 -311
- package/extensions/taskplane/mailbox.ts +57 -49
- package/extensions/taskplane/merge.ts +662 -383
- package/extensions/taskplane/messages.ts +109 -51
- package/extensions/taskplane/migrations.ts +1 -1
- package/extensions/taskplane/path-resolver.ts +8 -9
- package/extensions/taskplane/persistence.ts +425 -262
- package/extensions/taskplane/process-registry.ts +36 -7
- package/extensions/taskplane/quality-gate.ts +107 -55
- package/extensions/taskplane/resume.ts +774 -267
- package/extensions/taskplane/sessions.ts +1 -1
- package/extensions/taskplane/settings-tui.ts +505 -164
- package/extensions/taskplane/sidecar-telemetry.ts +25 -10
- package/extensions/taskplane/supervisor.ts +477 -270
- package/extensions/taskplane/task-executor-core.ts +178 -53
- package/extensions/taskplane/types.ts +186 -108
- package/extensions/taskplane/verification.ts +27 -22
- package/extensions/taskplane/waves.ts +59 -43
- package/extensions/taskplane/workspace.ts +14 -12
- package/extensions/taskplane/worktree.ts +218 -196
- package/package.json +14 -2
|
@@ -24,7 +24,16 @@
|
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
26
|
import { join, dirname } from "path";
|
|
27
|
-
import {
|
|
27
|
+
import {
|
|
28
|
+
existsSync,
|
|
29
|
+
mkdirSync,
|
|
30
|
+
writeFileSync,
|
|
31
|
+
readFileSync,
|
|
32
|
+
readdirSync,
|
|
33
|
+
renameSync,
|
|
34
|
+
unlinkSync,
|
|
35
|
+
appendFileSync,
|
|
36
|
+
} from "fs";
|
|
28
37
|
import { randomBytes } from "crypto";
|
|
29
38
|
import type { MailboxMessage, MailboxMessageType, WriteMailboxMessageOpts } from "./types.ts";
|
|
30
39
|
import { MAILBOX_DIR_NAME, MAILBOX_MAX_CONTENT_BYTES, MAILBOX_MESSAGE_TYPES } from "./types.ts";
|
|
@@ -85,7 +94,6 @@ export function broadcastInboxDir(stateRoot: string, batchId: string): string {
|
|
|
85
94
|
return join(stateRoot, ".pi", MAILBOX_DIR_NAME, batchId, "_broadcast", "inbox");
|
|
86
95
|
}
|
|
87
96
|
|
|
88
|
-
|
|
89
97
|
// ── Write ────────────────────────────────────────────────────────────
|
|
90
98
|
|
|
91
99
|
/**
|
|
@@ -116,8 +124,8 @@ export function writeMailboxMessage(
|
|
|
116
124
|
if (contentBytes > MAILBOX_MAX_CONTENT_BYTES) {
|
|
117
125
|
throw new Error(
|
|
118
126
|
`Mailbox message content exceeds ${MAILBOX_MAX_CONTENT_BYTES} byte limit ` +
|
|
119
|
-
|
|
120
|
-
|
|
127
|
+
`(${contentBytes} bytes). Steering messages should be concise directives. ` +
|
|
128
|
+
`Write larger context to a file and reference it by path.`,
|
|
121
129
|
);
|
|
122
130
|
}
|
|
123
131
|
|
|
@@ -140,9 +148,10 @@ export function writeMailboxMessage(
|
|
|
140
148
|
};
|
|
141
149
|
|
|
142
150
|
// Determine inbox directory
|
|
143
|
-
const inboxDir =
|
|
144
|
-
|
|
145
|
-
|
|
151
|
+
const inboxDir =
|
|
152
|
+
to === "_broadcast"
|
|
153
|
+
? broadcastInboxDir(stateRoot, batchId)
|
|
154
|
+
: sessionInboxDir(stateRoot, batchId, to);
|
|
146
155
|
|
|
147
156
|
// Ensure inbox directory exists
|
|
148
157
|
mkdirSync(inboxDir, { recursive: true });
|
|
@@ -171,7 +180,6 @@ export function writeMailboxMessage(
|
|
|
171
180
|
return message;
|
|
172
181
|
}
|
|
173
182
|
|
|
174
|
-
|
|
175
183
|
// ── Read ─────────────────────────────────────────────────────────────
|
|
176
184
|
|
|
177
185
|
/**
|
|
@@ -208,7 +216,7 @@ export function readInbox(
|
|
|
208
216
|
}
|
|
209
217
|
|
|
210
218
|
// Filter: only *.msg.json files (excludes .msg.json.tmp, .tmp, etc.)
|
|
211
|
-
const msgFiles = entries.filter(f => f.endsWith(".msg.json") && !f.endsWith(".msg.json.tmp"));
|
|
219
|
+
const msgFiles = entries.filter((f) => f.endsWith(".msg.json") && !f.endsWith(".msg.json.tmp"));
|
|
212
220
|
|
|
213
221
|
const results: Array<{ filename: string; message: MailboxMessage }> = [];
|
|
214
222
|
|
|
@@ -228,17 +236,13 @@ export function readInbox(
|
|
|
228
236
|
try {
|
|
229
237
|
parsed = JSON.parse(raw);
|
|
230
238
|
} catch {
|
|
231
|
-
process.stderr.write(
|
|
232
|
-
`[mailbox] WARNING: malformed JSON in ${filename}, skipping\n`,
|
|
233
|
-
);
|
|
239
|
+
process.stderr.write(`[mailbox] WARNING: malformed JSON in ${filename}, skipping\n`);
|
|
234
240
|
continue;
|
|
235
241
|
}
|
|
236
242
|
|
|
237
243
|
// Validate shape
|
|
238
244
|
if (!isValidMailboxMessage(parsed)) {
|
|
239
|
-
process.stderr.write(
|
|
240
|
-
`[mailbox] WARNING: invalid message shape in ${filename}, skipping\n`,
|
|
241
|
-
);
|
|
245
|
+
process.stderr.write(`[mailbox] WARNING: invalid message shape in ${filename}, skipping\n`);
|
|
242
246
|
continue;
|
|
243
247
|
}
|
|
244
248
|
|
|
@@ -265,7 +269,6 @@ export function readInbox(
|
|
|
265
269
|
return results;
|
|
266
270
|
}
|
|
267
271
|
|
|
268
|
-
|
|
269
272
|
// ── Acknowledge ──────────────────────────────────────────────────────
|
|
270
273
|
|
|
271
274
|
/**
|
|
@@ -312,7 +315,6 @@ export function ackMessage(inboxDir: string, filename: string): boolean {
|
|
|
312
315
|
}
|
|
313
316
|
}
|
|
314
317
|
|
|
315
|
-
|
|
316
318
|
// ── Validation ───────────────────────────────────────────────────────
|
|
317
319
|
|
|
318
320
|
/**
|
|
@@ -334,13 +336,14 @@ export function isValidMailboxMessage(obj: unknown): obj is MailboxMessage {
|
|
|
334
336
|
typeof m.batchId === "string" &&
|
|
335
337
|
typeof m.from === "string" &&
|
|
336
338
|
typeof m.to === "string" &&
|
|
337
|
-
typeof m.timestamp === "number" &&
|
|
338
|
-
|
|
339
|
+
typeof m.timestamp === "number" &&
|
|
340
|
+
Number.isFinite(m.timestamp) &&
|
|
341
|
+
typeof m.type === "string" &&
|
|
342
|
+
MAILBOX_MESSAGE_TYPES.has(m.type) &&
|
|
339
343
|
typeof m.content === "string"
|
|
340
344
|
);
|
|
341
345
|
}
|
|
342
346
|
|
|
343
|
-
|
|
344
347
|
// ── Outbox (Agent → Supervisor, TP-106) ─────────────────────────
|
|
345
348
|
|
|
346
349
|
/**
|
|
@@ -413,8 +416,14 @@ export function writeOutboxMessage(
|
|
|
413
416
|
writeFileSync(tempPath, JSON.stringify(message, null, 2) + "\n", "utf-8");
|
|
414
417
|
renameSync(tempPath, finalPath);
|
|
415
418
|
} catch (err) {
|
|
416
|
-
try {
|
|
417
|
-
|
|
419
|
+
try {
|
|
420
|
+
if (existsSync(tempPath)) unlinkSync(tempPath);
|
|
421
|
+
} catch {
|
|
422
|
+
/* cleanup */
|
|
423
|
+
}
|
|
424
|
+
throw new Error(
|
|
425
|
+
`Failed to write outbox message: ${err instanceof Error ? err.message : String(err)}`,
|
|
426
|
+
);
|
|
418
427
|
}
|
|
419
428
|
|
|
420
429
|
return message;
|
|
@@ -430,11 +439,7 @@ export function writeOutboxMessage(
|
|
|
430
439
|
*
|
|
431
440
|
* @since TP-106
|
|
432
441
|
*/
|
|
433
|
-
export function readOutbox(
|
|
434
|
-
stateRoot: string,
|
|
435
|
-
batchId: string,
|
|
436
|
-
agentId: string,
|
|
437
|
-
): MailboxMessage[] {
|
|
442
|
+
export function readOutbox(stateRoot: string, batchId: string, agentId: string): MailboxMessage[] {
|
|
438
443
|
const outboxDir = sessionOutboxDir(stateRoot, batchId, agentId);
|
|
439
444
|
if (!existsSync(outboxDir)) return [];
|
|
440
445
|
|
|
@@ -445,7 +450,7 @@ export function readOutbox(
|
|
|
445
450
|
return [];
|
|
446
451
|
}
|
|
447
452
|
|
|
448
|
-
const msgFiles = entries.filter(f => f.endsWith(".msg.json") && !f.endsWith(".msg.json.tmp"));
|
|
453
|
+
const msgFiles = entries.filter((f) => f.endsWith(".msg.json") && !f.endsWith(".msg.json.tmp"));
|
|
449
454
|
const messages: MailboxMessage[] = [];
|
|
450
455
|
|
|
451
456
|
for (const filename of msgFiles) {
|
|
@@ -455,7 +460,9 @@ export function readOutbox(
|
|
|
455
460
|
if (isValidMailboxMessage(parsed)) {
|
|
456
461
|
messages.push(parsed);
|
|
457
462
|
}
|
|
458
|
-
} catch {
|
|
463
|
+
} catch {
|
|
464
|
+
/* skip malformed */
|
|
465
|
+
}
|
|
459
466
|
}
|
|
460
467
|
|
|
461
468
|
messages.sort((a, b) => a.timestamp - b.timestamp);
|
|
@@ -484,12 +491,19 @@ export function readOutboxHistory(
|
|
|
484
491
|
const outboxDir = sessionOutboxDir(stateRoot, batchId, agentId);
|
|
485
492
|
const results: Array<{ message: MailboxMessage; acked: boolean }> = [];
|
|
486
493
|
|
|
487
|
-
for (const [dir, acked] of [
|
|
494
|
+
for (const [dir, acked] of [
|
|
495
|
+
[outboxDir, false],
|
|
496
|
+
[join(outboxDir, "processed"), true],
|
|
497
|
+
] as const) {
|
|
488
498
|
if (!existsSync(dir)) continue;
|
|
489
499
|
let entries: string[];
|
|
490
|
-
try {
|
|
500
|
+
try {
|
|
501
|
+
entries = readdirSync(dir);
|
|
502
|
+
} catch {
|
|
503
|
+
continue;
|
|
504
|
+
}
|
|
491
505
|
|
|
492
|
-
const msgFiles = entries.filter(f => f.endsWith(".msg.json") && !f.endsWith(".msg.json.tmp"));
|
|
506
|
+
const msgFiles = entries.filter((f) => f.endsWith(".msg.json") && !f.endsWith(".msg.json.tmp"));
|
|
493
507
|
for (const filename of msgFiles) {
|
|
494
508
|
try {
|
|
495
509
|
const raw = readFileSync(join(dir, filename), "utf-8");
|
|
@@ -497,7 +511,9 @@ export function readOutboxHistory(
|
|
|
497
511
|
if (isValidMailboxMessage(parsed)) {
|
|
498
512
|
results.push({ message: parsed, acked });
|
|
499
513
|
}
|
|
500
|
-
} catch {
|
|
514
|
+
} catch {
|
|
515
|
+
/* skip malformed */
|
|
516
|
+
}
|
|
501
517
|
}
|
|
502
518
|
}
|
|
503
519
|
|
|
@@ -557,11 +573,7 @@ export function ackOutboxMessage(
|
|
|
557
573
|
*
|
|
558
574
|
* @since TP-187 (#538)
|
|
559
575
|
*/
|
|
560
|
-
export function drainAgentOutbox(
|
|
561
|
-
stateRoot: string,
|
|
562
|
-
batchId: string,
|
|
563
|
-
agentId: string,
|
|
564
|
-
): number {
|
|
576
|
+
export function drainAgentOutbox(stateRoot: string, batchId: string, agentId: string): number {
|
|
565
577
|
const outboxDir = sessionOutboxDir(stateRoot, batchId, agentId);
|
|
566
578
|
if (!existsSync(outboxDir)) return 0;
|
|
567
579
|
|
|
@@ -587,7 +599,11 @@ export function drainAgentOutbox(
|
|
|
587
599
|
|
|
588
600
|
if (entry.endsWith(".msg.json")) {
|
|
589
601
|
if (!processedDirEnsured) {
|
|
590
|
-
try {
|
|
602
|
+
try {
|
|
603
|
+
mkdirSync(processedDir, { recursive: true });
|
|
604
|
+
} catch {
|
|
605
|
+
/* fall through to rename error handling */
|
|
606
|
+
}
|
|
591
607
|
processedDirEnsured = true;
|
|
592
608
|
}
|
|
593
609
|
const dstPath = join(processedDir, entry);
|
|
@@ -632,23 +648,17 @@ export function drainAgentOutbox(
|
|
|
632
648
|
*
|
|
633
649
|
* @since TP-091
|
|
634
650
|
*/
|
|
635
|
-
export function discoverMailboxAgentIds(
|
|
636
|
-
stateRoot: string,
|
|
637
|
-
batchId: string,
|
|
638
|
-
): string[] {
|
|
651
|
+
export function discoverMailboxAgentIds(stateRoot: string, batchId: string): string[] {
|
|
639
652
|
const mbRoot = join(stateRoot, ".pi", MAILBOX_DIR_NAME, batchId);
|
|
640
653
|
if (!existsSync(mbRoot)) return [];
|
|
641
654
|
try {
|
|
642
655
|
const entries = readdirSync(mbRoot, { withFileTypes: true });
|
|
643
|
-
return entries
|
|
644
|
-
.filter(e => e.isDirectory() && e.name !== "_broadcast")
|
|
645
|
-
.map(e => e.name);
|
|
656
|
+
return entries.filter((e) => e.isDirectory() && e.name !== "_broadcast").map((e) => e.name);
|
|
646
657
|
} catch {
|
|
647
658
|
return [];
|
|
648
659
|
}
|
|
649
660
|
}
|
|
650
661
|
|
|
651
|
-
|
|
652
662
|
export type MailboxAuditEventType =
|
|
653
663
|
| "message_sent"
|
|
654
664
|
| "message_delivered"
|
|
@@ -694,7 +704,6 @@ export function appendMailboxAuditEvent(
|
|
|
694
704
|
}
|
|
695
705
|
}
|
|
696
706
|
|
|
697
|
-
|
|
698
707
|
// ── Broadcast (TP-106) ────────────────────────────────────────
|
|
699
708
|
|
|
700
709
|
/**
|
|
@@ -721,7 +730,6 @@ export function writeBroadcastMessage(
|
|
|
721
730
|
});
|
|
722
731
|
}
|
|
723
732
|
|
|
724
|
-
|
|
725
733
|
// ── Rate Limiting (TP-106) ─────────────────────────────────────
|
|
726
734
|
|
|
727
735
|
/** Default rate limit: max 1 message per agent per 30 seconds. */
|