bit-office 1.2.0 → 1.2.1
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/dist/index.js +307 -291
- package/dist/index.js.map +1 -1
- package/dist/web/404.html +2 -2
- package/dist/web/_next/static/chunks/336.9c9378c53a6fb44e.js +1 -0
- package/dist/web/_next/static/chunks/368.61fa3954c03d8818.js +1 -0
- package/dist/web/_next/static/chunks/app/office/page-c4d6d4b7bf6b906f.js +1 -0
- package/dist/web/_next/static/chunks/{webpack-1b921ef42040f4d7.js → webpack-c82364bd627eb710.js} +1 -1
- package/dist/web/index.html +2 -2
- package/dist/web/index.txt +1 -1
- package/dist/web/join.html +2 -2
- package/dist/web/join.txt +1 -1
- package/dist/web/office.html +2 -2
- package/dist/web/office.txt +2 -2
- package/dist/web/pair.html +2 -2
- package/dist/web/pair.txt +1 -1
- package/dist/web/sw.js +1 -1
- package/package.json +1 -1
- package/dist/web/_next/static/chunks/336.3b48469aad2c6417.js +0 -1
- package/dist/web/_next/static/chunks/368.5516163baaf54ba9.js +0 -1
- package/dist/web/_next/static/chunks/app/office/page-31d54910f922915a.js +0 -1
- /package/dist/web/_next/static/{7Qn9ZRObqct6tz2cPYAn5 → 8cfKslBAKuXQUC3ILpBvL}/_buildManifest.js +0 -0
- /package/dist/web/_next/static/{7Qn9ZRObqct6tz2cPYAn5 → 8cfKslBAKuXQUC3ILpBvL}/_ssgManifest.js +0 -0
package/dist/index.js
CHANGED
|
@@ -4391,7 +4391,8 @@ var ProjectListEvent = external_exports.object({
|
|
|
4391
4391
|
endedAt: external_exports.number(),
|
|
4392
4392
|
agentNames: external_exports.array(external_exports.string()),
|
|
4393
4393
|
eventCount: external_exports.number(),
|
|
4394
|
-
preview: ProjectPreviewSchema
|
|
4394
|
+
preview: ProjectPreviewSchema,
|
|
4395
|
+
tokenUsage: external_exports.object({ inputTokens: external_exports.number(), outputTokens: external_exports.number() }).optional()
|
|
4395
4396
|
}))
|
|
4396
4397
|
});
|
|
4397
4398
|
var ProjectDataEvent = external_exports.object({
|
|
@@ -5335,14 +5336,14 @@ var CONFIG = {
|
|
|
5335
5336
|
};
|
|
5336
5337
|
|
|
5337
5338
|
// ../../packages/orchestrator/src/agent-session.ts
|
|
5338
|
-
import { spawn
|
|
5339
|
-
import
|
|
5340
|
-
import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, existsSync as
|
|
5339
|
+
import { spawn, execSync as execSync2 } from "child_process";
|
|
5340
|
+
import path4 from "path";
|
|
5341
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, existsSync as existsSync6 } from "fs";
|
|
5341
5342
|
import { homedir as homedir4 } from "os";
|
|
5342
5343
|
|
|
5343
5344
|
// ../../packages/orchestrator/src/preview-resolver.ts
|
|
5344
|
-
import { existsSync as
|
|
5345
|
-
import
|
|
5345
|
+
import { existsSync as existsSync5 } from "fs";
|
|
5346
|
+
import path3 from "path";
|
|
5346
5347
|
|
|
5347
5348
|
// ../../packages/orchestrator/src/resolve-path.ts
|
|
5348
5349
|
import path2 from "path";
|
|
@@ -5362,157 +5363,19 @@ function resolveAgentPath(filePath, projectDir, workspace) {
|
|
|
5362
5363
|
return void 0;
|
|
5363
5364
|
}
|
|
5364
5365
|
|
|
5365
|
-
// ../../packages/orchestrator/src/preview-server.ts
|
|
5366
|
-
import { spawn, execSync as execSync2 } from "child_process";
|
|
5367
|
-
import { existsSync as existsSync5 } from "fs";
|
|
5368
|
-
import path3 from "path";
|
|
5369
|
-
var STATIC_PORT = 9100;
|
|
5370
|
-
var PreviewServer = class {
|
|
5371
|
-
process = null;
|
|
5372
|
-
currentDir = null;
|
|
5373
|
-
isDetached = false;
|
|
5374
|
-
/**
|
|
5375
|
-
* Mode 1: Serve a static file directory on a fixed port.
|
|
5376
|
-
* Returns the preview URL for the given file.
|
|
5377
|
-
*/
|
|
5378
|
-
serve(filePath) {
|
|
5379
|
-
if (!existsSync5(filePath)) {
|
|
5380
|
-
console.log(`[PreviewServer] File not found: ${filePath}`);
|
|
5381
|
-
return void 0;
|
|
5382
|
-
}
|
|
5383
|
-
const dir = path3.dirname(filePath);
|
|
5384
|
-
const fileName = path3.basename(filePath);
|
|
5385
|
-
this.stop();
|
|
5386
|
-
try {
|
|
5387
|
-
this.process = spawn("npx", ["serve", dir, "-l", String(STATIC_PORT), "--no-clipboard"], {
|
|
5388
|
-
stdio: "ignore",
|
|
5389
|
-
detached: true
|
|
5390
|
-
});
|
|
5391
|
-
this.process.unref();
|
|
5392
|
-
this.currentDir = dir;
|
|
5393
|
-
this.isDetached = true;
|
|
5394
|
-
const url = `http://localhost:${STATIC_PORT}/${fileName}`;
|
|
5395
|
-
console.log(`[PreviewServer] Serving ${dir} on port ${STATIC_PORT}`);
|
|
5396
|
-
return url;
|
|
5397
|
-
} catch (e) {
|
|
5398
|
-
console.log(`[PreviewServer] Failed to start static serve: ${e}`);
|
|
5399
|
-
return void 0;
|
|
5400
|
-
}
|
|
5401
|
-
}
|
|
5402
|
-
/**
|
|
5403
|
-
* Mode 2: Run a command (e.g. "python app.py") and use the specified port.
|
|
5404
|
-
* The command is expected to start a server on the given port.
|
|
5405
|
-
* Returns the preview URL.
|
|
5406
|
-
*/
|
|
5407
|
-
runCommand(cmd, cwd, port) {
|
|
5408
|
-
this.stop();
|
|
5409
|
-
try {
|
|
5410
|
-
this.process = spawn(cmd, {
|
|
5411
|
-
shell: true,
|
|
5412
|
-
cwd,
|
|
5413
|
-
stdio: "ignore",
|
|
5414
|
-
detached: true
|
|
5415
|
-
});
|
|
5416
|
-
this.process.unref();
|
|
5417
|
-
this.currentDir = cwd;
|
|
5418
|
-
this.isDetached = true;
|
|
5419
|
-
const url = `http://localhost:${port}`;
|
|
5420
|
-
console.log(`[PreviewServer] Running "${cmd}" in ${cwd}, preview at port ${port}`);
|
|
5421
|
-
return url;
|
|
5422
|
-
} catch (e) {
|
|
5423
|
-
console.log(`[PreviewServer] Failed to run command: ${e}`);
|
|
5424
|
-
return void 0;
|
|
5425
|
-
}
|
|
5426
|
-
}
|
|
5427
|
-
/**
|
|
5428
|
-
* Mode 3: Launch a desktop/CLI process (no web preview URL).
|
|
5429
|
-
* Used for Pygame, Tkinter, Electron, terminal apps, etc.
|
|
5430
|
-
* NOT detached — GUI apps need the login session to access WindowServer (macOS).
|
|
5431
|
-
*/
|
|
5432
|
-
launchProcess(cmd, cwd) {
|
|
5433
|
-
this.stop();
|
|
5434
|
-
try {
|
|
5435
|
-
this.process = spawn(cmd, {
|
|
5436
|
-
shell: true,
|
|
5437
|
-
cwd,
|
|
5438
|
-
stdio: ["ignore", "ignore", "pipe"]
|
|
5439
|
-
});
|
|
5440
|
-
this.currentDir = cwd;
|
|
5441
|
-
this.isDetached = false;
|
|
5442
|
-
console.log(`[PreviewServer] Launched "${cmd}" in ${cwd} (pid=${this.process.pid})`);
|
|
5443
|
-
this.process.stderr?.on("data", (data) => {
|
|
5444
|
-
const msg = data.toString().trim();
|
|
5445
|
-
if (msg) console.log(`[PreviewServer] stderr: ${msg.slice(0, 200)}`);
|
|
5446
|
-
});
|
|
5447
|
-
this.process.on("exit", (code) => {
|
|
5448
|
-
console.log(`[PreviewServer] Process exited with code ${code}`);
|
|
5449
|
-
});
|
|
5450
|
-
} catch (e) {
|
|
5451
|
-
console.log(`[PreviewServer] Failed to launch process: ${e}`);
|
|
5452
|
-
}
|
|
5453
|
-
}
|
|
5454
|
-
/** Kill the current process and any orphan process on the static port */
|
|
5455
|
-
stop() {
|
|
5456
|
-
if (this.process) {
|
|
5457
|
-
try {
|
|
5458
|
-
if (this.isDetached && this.process.pid) {
|
|
5459
|
-
process.kill(-this.process.pid, "SIGTERM");
|
|
5460
|
-
} else {
|
|
5461
|
-
this.process.kill("SIGTERM");
|
|
5462
|
-
}
|
|
5463
|
-
} catch {
|
|
5464
|
-
try {
|
|
5465
|
-
this.process.kill("SIGTERM");
|
|
5466
|
-
} catch {
|
|
5467
|
-
}
|
|
5468
|
-
}
|
|
5469
|
-
this.process = null;
|
|
5470
|
-
this.currentDir = null;
|
|
5471
|
-
this.isDetached = false;
|
|
5472
|
-
console.log(`[PreviewServer] Stopped`);
|
|
5473
|
-
}
|
|
5474
|
-
this.killPortHolder(STATIC_PORT);
|
|
5475
|
-
}
|
|
5476
|
-
/** Kill whatever process is listening on the given port (best-effort). */
|
|
5477
|
-
killPortHolder(port) {
|
|
5478
|
-
try {
|
|
5479
|
-
const out = execSync2(`lsof -ti :${port}`, { encoding: "utf-8", timeout: 3e3 }).trim();
|
|
5480
|
-
if (out) {
|
|
5481
|
-
for (const pid of out.split("\n")) {
|
|
5482
|
-
const n = parseInt(pid, 10);
|
|
5483
|
-
if (n > 0) {
|
|
5484
|
-
try {
|
|
5485
|
-
process.kill(n, "SIGKILL");
|
|
5486
|
-
} catch {
|
|
5487
|
-
}
|
|
5488
|
-
}
|
|
5489
|
-
}
|
|
5490
|
-
console.log(`[PreviewServer] Killed orphan process(es) on port ${port}: ${out.replace(/\n/g, ", ")}`);
|
|
5491
|
-
}
|
|
5492
|
-
} catch {
|
|
5493
|
-
}
|
|
5494
|
-
}
|
|
5495
|
-
};
|
|
5496
|
-
var previewServer = new PreviewServer();
|
|
5497
|
-
|
|
5498
5366
|
// ../../packages/orchestrator/src/preview-resolver.ts
|
|
5499
5367
|
var EMPTY = { previewUrl: void 0, previewPath: void 0 };
|
|
5500
5368
|
function resolvePreview(input) {
|
|
5501
5369
|
const { cwd, workspace } = input;
|
|
5502
5370
|
if (input.previewCmd && input.previewPort) {
|
|
5503
|
-
|
|
5504
|
-
if (url) return { previewUrl: url, previewPath: void 0 };
|
|
5371
|
+
return EMPTY;
|
|
5505
5372
|
}
|
|
5506
5373
|
if (input.previewCmd && !input.previewPort) {
|
|
5507
|
-
console.log(`[PreviewResolver] Desktop app ready (user can Launch): ${input.previewCmd}`);
|
|
5508
5374
|
return EMPTY;
|
|
5509
5375
|
}
|
|
5510
5376
|
if (input.entryFile && /\.html?$/i.test(input.entryFile)) {
|
|
5511
5377
|
const absPath = resolveAgentPath(input.entryFile, cwd, workspace);
|
|
5512
|
-
if (absPath) {
|
|
5513
|
-
const url = previewServer.serve(absPath);
|
|
5514
|
-
if (url) return { previewUrl: url, previewPath: absPath };
|
|
5515
|
-
}
|
|
5378
|
+
if (absPath) return { previewUrl: void 0, previewPath: absPath };
|
|
5516
5379
|
}
|
|
5517
5380
|
if (input.stdout) {
|
|
5518
5381
|
const match = input.stdout.match(/PREVIEW:\s*(https?:\/\/[^\s*)\]>]+)/i);
|
|
@@ -5524,28 +5387,19 @@ function resolvePreview(input) {
|
|
|
5524
5387
|
const fileMatch = input.stdout.match(/(?:open\s+)?((?:\/[\w./_-]+|[\w./_-]+)\.html?)\b/i);
|
|
5525
5388
|
if (fileMatch) {
|
|
5526
5389
|
const absPath = resolveAgentPath(fileMatch[1], cwd, workspace);
|
|
5527
|
-
if (absPath) {
|
|
5528
|
-
const url = previewServer.serve(absPath);
|
|
5529
|
-
if (url) return { previewUrl: url, previewPath: absPath };
|
|
5530
|
-
}
|
|
5390
|
+
if (absPath) return { previewUrl: void 0, previewPath: absPath };
|
|
5531
5391
|
}
|
|
5532
5392
|
}
|
|
5533
5393
|
if (input.changedFiles) {
|
|
5534
5394
|
for (const f of input.changedFiles) {
|
|
5535
5395
|
if (!/\.html?$/i.test(f)) continue;
|
|
5536
5396
|
const absPath = resolveAgentPath(f, cwd, workspace);
|
|
5537
|
-
if (absPath) {
|
|
5538
|
-
const url = previewServer.serve(absPath);
|
|
5539
|
-
if (url) return { previewUrl: url, previewPath: absPath };
|
|
5540
|
-
}
|
|
5397
|
+
if (absPath) return { previewUrl: void 0, previewPath: absPath };
|
|
5541
5398
|
}
|
|
5542
5399
|
}
|
|
5543
5400
|
for (const candidate of CONFIG.preview.buildOutputCandidates) {
|
|
5544
|
-
const absPath =
|
|
5545
|
-
if (
|
|
5546
|
-
const url = previewServer.serve(absPath);
|
|
5547
|
-
if (url) return { previewUrl: url, previewPath: absPath };
|
|
5548
|
-
}
|
|
5401
|
+
const absPath = path3.join(cwd, candidate);
|
|
5402
|
+
if (existsSync5(absPath)) return { previewUrl: void 0, previewPath: absPath };
|
|
5549
5403
|
}
|
|
5550
5404
|
return EMPTY;
|
|
5551
5405
|
}
|
|
@@ -5611,10 +5465,10 @@ function extractFallbackSummary(raw, _hasFiles, _entryFile, _projectDir) {
|
|
|
5611
5465
|
|
|
5612
5466
|
// ../../packages/orchestrator/src/agent-session.ts
|
|
5613
5467
|
import { nanoid as nanoid3 } from "nanoid";
|
|
5614
|
-
var SESSION_FILE =
|
|
5468
|
+
var SESSION_FILE = path4.join(homedir4(), ".bit-office", "agent-sessions.json");
|
|
5615
5469
|
function loadSessionMap() {
|
|
5616
5470
|
try {
|
|
5617
|
-
if (
|
|
5471
|
+
if (existsSync6(SESSION_FILE)) return JSON.parse(readFileSync4(SESSION_FILE, "utf-8"));
|
|
5618
5472
|
} catch {
|
|
5619
5473
|
}
|
|
5620
5474
|
return {};
|
|
@@ -5623,8 +5477,8 @@ function clearSessionId(agentId) {
|
|
|
5623
5477
|
saveSessionId(agentId, null);
|
|
5624
5478
|
}
|
|
5625
5479
|
function saveSessionId(agentId, sessionId) {
|
|
5626
|
-
const dir =
|
|
5627
|
-
if (!
|
|
5480
|
+
const dir = path4.dirname(SESSION_FILE);
|
|
5481
|
+
if (!existsSync6(dir)) mkdirSync4(dir, { recursive: true });
|
|
5628
5482
|
const map = loadSessionMap();
|
|
5629
5483
|
if (sessionId) {
|
|
5630
5484
|
map[agentId] = sessionId;
|
|
@@ -5656,6 +5510,8 @@ var AgentSession = class {
|
|
|
5656
5510
|
stderrBuffer = "";
|
|
5657
5511
|
taskInputTokens = 0;
|
|
5658
5512
|
taskOutputTokens = 0;
|
|
5513
|
+
/** Dedup same-turn repeated usage in assistant messages */
|
|
5514
|
+
lastUsageSignature = "";
|
|
5659
5515
|
hasHistory;
|
|
5660
5516
|
sessionId;
|
|
5661
5517
|
taskQueue = [];
|
|
@@ -5761,6 +5617,7 @@ var AgentSession = class {
|
|
|
5761
5617
|
this.stderrBuffer = "";
|
|
5762
5618
|
this.taskInputTokens = 0;
|
|
5763
5619
|
this.taskOutputTokens = 0;
|
|
5620
|
+
this.lastUsageSignature = "";
|
|
5764
5621
|
this.onEvent({
|
|
5765
5622
|
type: "task:started",
|
|
5766
5623
|
agentId: this.agentId,
|
|
@@ -5812,12 +5669,12 @@ var AgentSession = class {
|
|
|
5812
5669
|
skipResume: isFirstExecute && this.hasHistory
|
|
5813
5670
|
});
|
|
5814
5671
|
try {
|
|
5815
|
-
const whichPath =
|
|
5672
|
+
const whichPath = execSync2(`which ${this.backend.command}`, { env: cleanEnv, encoding: "utf-8", timeout: 3e3 }).trim();
|
|
5816
5673
|
console.log(`[Agent ${this.name}] Binary: ${whichPath}, CLAUDECODE=${cleanEnv.CLAUDECODE ?? "unset"}, ENTRYPOINT=${cleanEnv.CLAUDE_CODE_ENTRYPOINT ?? "unset"}`);
|
|
5817
5674
|
} catch {
|
|
5818
5675
|
}
|
|
5819
5676
|
console.log(`[Agent ${this.name}] Spawning: ${this.backend.command} ${args.map((a) => a.length > 80 ? a.slice(0, 80) + "..." : a).join(" ")}`);
|
|
5820
|
-
this.process =
|
|
5677
|
+
this.process = spawn(this.backend.command, args, {
|
|
5821
5678
|
cwd,
|
|
5822
5679
|
env: cleanEnv,
|
|
5823
5680
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -5910,8 +5767,20 @@ var AgentSession = class {
|
|
|
5910
5767
|
if (msg.type === "assistant" && msg.message?.content) {
|
|
5911
5768
|
if (msg.message.usage) {
|
|
5912
5769
|
const usage = msg.message.usage;
|
|
5913
|
-
|
|
5914
|
-
|
|
5770
|
+
const turnIn = (usage.input_tokens ?? 0) + (usage.cache_creation_input_tokens ?? 0) + (usage.cache_read_input_tokens ?? 0);
|
|
5771
|
+
const turnOut = usage.output_tokens ?? 0;
|
|
5772
|
+
const sig = `${turnIn}:${turnOut}`;
|
|
5773
|
+
if (sig !== this.lastUsageSignature) {
|
|
5774
|
+
this.lastUsageSignature = sig;
|
|
5775
|
+
this.taskInputTokens += turnIn;
|
|
5776
|
+
this.taskOutputTokens += turnOut;
|
|
5777
|
+
this.onEvent({
|
|
5778
|
+
type: "token:update",
|
|
5779
|
+
agentId: this.agentId,
|
|
5780
|
+
inputTokens: this.taskInputTokens,
|
|
5781
|
+
outputTokens: this.taskOutputTokens
|
|
5782
|
+
});
|
|
5783
|
+
}
|
|
5915
5784
|
}
|
|
5916
5785
|
for (const block of msg.message.content) {
|
|
5917
5786
|
if (block.type === "text" && block.text) {
|
|
@@ -5922,12 +5791,27 @@ var AgentSession = class {
|
|
|
5922
5791
|
console.log(`[Agent ${this.name} thinking] ${block.thinking.slice(0, 120)}...`);
|
|
5923
5792
|
}
|
|
5924
5793
|
}
|
|
5925
|
-
} else if (msg.type === "result"
|
|
5926
|
-
if (
|
|
5927
|
-
|
|
5928
|
-
|
|
5794
|
+
} else if (msg.type === "result") {
|
|
5795
|
+
if (msg.usage) {
|
|
5796
|
+
const usage = msg.usage;
|
|
5797
|
+
const totalIn = (usage.input_tokens ?? 0) + (usage.cache_creation_input_tokens ?? 0) + (usage.cache_read_input_tokens ?? 0);
|
|
5798
|
+
const totalOut = usage.output_tokens ?? 0;
|
|
5799
|
+
this.taskInputTokens = totalIn;
|
|
5800
|
+
this.taskOutputTokens = totalOut;
|
|
5801
|
+
this.onEvent({
|
|
5802
|
+
type: "token:update",
|
|
5803
|
+
agentId: this.agentId,
|
|
5804
|
+
inputTokens: this.taskInputTokens,
|
|
5805
|
+
outputTokens: this.taskOutputTokens
|
|
5806
|
+
});
|
|
5807
|
+
}
|
|
5808
|
+
if (msg.result) {
|
|
5809
|
+
if (!this.stdoutBuffer) {
|
|
5810
|
+
this.stdoutBuffer = msg.result;
|
|
5811
|
+
handleTextLine(msg.result);
|
|
5812
|
+
}
|
|
5813
|
+
this._lastResultText = msg.result;
|
|
5929
5814
|
}
|
|
5930
|
-
this._lastResultText = msg.result;
|
|
5931
5815
|
}
|
|
5932
5816
|
continue;
|
|
5933
5817
|
} catch {
|
|
@@ -5948,11 +5832,18 @@ var AgentSession = class {
|
|
|
5948
5832
|
}
|
|
5949
5833
|
});
|
|
5950
5834
|
this.process.on("close", (code) => {
|
|
5835
|
+
const agentPid = this.process?.pid;
|
|
5951
5836
|
this.process = null;
|
|
5952
5837
|
if (this.taskTimeout) {
|
|
5953
5838
|
clearTimeout(this.taskTimeout);
|
|
5954
5839
|
this.taskTimeout = null;
|
|
5955
5840
|
}
|
|
5841
|
+
if (agentPid) {
|
|
5842
|
+
try {
|
|
5843
|
+
process.kill(-agentPid, "SIGTERM");
|
|
5844
|
+
} catch {
|
|
5845
|
+
}
|
|
5846
|
+
}
|
|
5956
5847
|
const remaining = jsonLineBuf.trim();
|
|
5957
5848
|
if (remaining) {
|
|
5958
5849
|
jsonLineBuf = "";
|
|
@@ -6078,7 +5969,7 @@ var AgentSession = class {
|
|
|
6078
5969
|
detectPreview() {
|
|
6079
5970
|
const result = this.extractResult();
|
|
6080
5971
|
const baseCwd = this.currentCwd ?? this.workspace;
|
|
6081
|
-
const cwd = result.projectDir ?
|
|
5972
|
+
const cwd = result.projectDir ? path4.isAbsolute(result.projectDir) ? result.projectDir : path4.join(baseCwd, result.projectDir) : baseCwd;
|
|
6082
5973
|
return resolvePreview({
|
|
6083
5974
|
entryFile: result.entryFile,
|
|
6084
5975
|
previewCmd: result.previewCmd,
|
|
@@ -6293,7 +6184,7 @@ var AgentManager = class {
|
|
|
6293
6184
|
|
|
6294
6185
|
// ../../packages/orchestrator/src/delegation.ts
|
|
6295
6186
|
import { nanoid as nanoid4 } from "nanoid";
|
|
6296
|
-
import
|
|
6187
|
+
import path5 from "path";
|
|
6297
6188
|
var DelegationRouter = class {
|
|
6298
6189
|
/** All per-task delegation metadata, keyed by taskId */
|
|
6299
6190
|
tasks = /* @__PURE__ */ new Map();
|
|
@@ -6480,7 +6371,7 @@ var DelegationRouter = class {
|
|
|
6480
6371
|
const dirPart = dirMatch[1].replace(/\/$/, "");
|
|
6481
6372
|
const leaderSession = this.agentManager.get(fromAgentId);
|
|
6482
6373
|
if (leaderSession) {
|
|
6483
|
-
repoPath =
|
|
6374
|
+
repoPath = path5.resolve(leaderSession.workspaceDir, dirPart);
|
|
6484
6375
|
}
|
|
6485
6376
|
}
|
|
6486
6377
|
}
|
|
@@ -6767,8 +6658,8 @@ ${resultLines2}`,
|
|
|
6767
6658
|
};
|
|
6768
6659
|
|
|
6769
6660
|
// ../../packages/orchestrator/src/prompt-templates.ts
|
|
6770
|
-
import { readFileSync as readFileSync5, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, existsSync as
|
|
6771
|
-
import
|
|
6661
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, existsSync as existsSync7 } from "fs";
|
|
6662
|
+
import path6 from "path";
|
|
6772
6663
|
var PROMPT_DEFAULTS = {
|
|
6773
6664
|
"leader-initial": `You are {{name}}, the Team Lead. {{personality}}
|
|
6774
6665
|
You CANNOT write code, run commands, or use any tools. You can ONLY delegate.
|
|
@@ -6862,7 +6753,7 @@ Check WHO sent this result, then follow the matching branch:
|
|
|
6862
6753
|
|
|
6863
6754
|
ENTRY_FILE: <from dev \u2014 e.g. index.html, dist/index.html. OMIT if dev didn't provide one>
|
|
6864
6755
|
PREVIEW_CMD: <from dev \u2014 e.g. "python app.py". OMIT if dev didn't provide one. NEVER use "npm run dev" or "npm start"!>
|
|
6865
|
-
PREVIEW_PORT: <from dev \u2014 e.g. 5000
|
|
6756
|
+
PREVIEW_PORT: <from dev \u2014 e.g. 5000. OMIT if dev didn't provide one>
|
|
6866
6757
|
SUMMARY: <2-3 sentence description of what was built>
|
|
6867
6758
|
|
|
6868
6759
|
RULES:
|
|
@@ -6873,95 +6764,65 @@ RULES:
|
|
|
6873
6764
|
- Do NOT include PROJECT_DIR \u2014 the system manages project directories automatically.`,
|
|
6874
6765
|
"worker-initial": `Your name is {{name}}, your role is {{role}}. {{personality}}
|
|
6875
6766
|
|
|
6876
|
-
|
|
6877
|
-
- Do the MINIMUM needed
|
|
6878
|
-
-
|
|
6879
|
-
-
|
|
6880
|
-
-
|
|
6881
|
-
|
|
6882
|
-
HARD LIMITS:
|
|
6883
|
-
- NEVER run "npm run dev", "npm start", "npx vite", "python -m http.server", or ANY command that starts a long-running server. These will hang forever and waste your budget. The system handles preview serving automatically.
|
|
6884
|
-
- Do NOT create backend servers, WebSocket servers, or any server-side code UNLESS the task explicitly requires one. Default to static HTML/CSS/JS.
|
|
6885
|
-
- You MAY install dependencies (npm install, pip install) and run ONE-SHOT build commands (npm run build, npx tsc). Never run watch/serve/dev commands.
|
|
6767
|
+
RULES:
|
|
6768
|
+
- Do the MINIMUM needed. Simple and working beats perfect.
|
|
6769
|
+
- NEVER run long-running commands (npm run dev, npm start, npx vite, live-server, python -m http.server). They hang forever and you will be killed. The system serves previews automatically.
|
|
6770
|
+
- Do NOT launch GUI apps (Pygame, Tkinter, Electron) or dev servers. You CANNOT see UI.
|
|
6771
|
+
- You MAY run one-shot commands: npm install, npm run build, npx tsc, syntax checks.
|
|
6772
|
+
- Default to static HTML/CSS/JS unless a backend is explicitly required.
|
|
6886
6773
|
{{soloHint}}
|
|
6887
6774
|
{{memory}}
|
|
6888
|
-
Start with one sentence describing your approach. Then do the work.
|
|
6889
|
-
|
|
6890
|
-
You are responsible for the COMPLETE deliverable \u2014 not just source files. This means:
|
|
6891
|
-
1. Project setup: create all config files needed (package.json, tsconfig, build config, requirements.txt, etc.)
|
|
6892
|
-
2. All source code
|
|
6893
|
-
3. Build & verify: if the project has a build step, RUN IT and fix errors until it passes
|
|
6894
|
-
4. Report how to run/preview the result (see deliverable types below)
|
|
6895
|
-
|
|
6896
|
-
VERIFICATION (MANDATORY before reporting STATUS: done):
|
|
6897
|
-
- If you created a package.json with a build script \u2192 run "npm run build" (ONE-SHOT), fix errors until it succeeds, confirm the output file exists. NEVER run "npm run dev" or "npm start" \u2014 these hang forever.
|
|
6898
|
-
- If your deliverable is an HTML file \u2192 confirm it exists and references valid scripts/styles
|
|
6899
|
-
- If your deliverable is a script (Python, Node, etc.) \u2192 run a syntax check (python -c "import ast; ast.parse(open('app.py').read())" or node --check app.js)
|
|
6900
|
-
- If NONE of the above apply \u2192 at minimum list the files and confirm the entry point exists
|
|
6901
|
-
- IMPORTANT: Do NOT launch GUI/desktop applications (Pygame, Tkinter, Electron, etc.) \u2014 they open windows that cannot be controlled. Do NOT start dev servers (vite, webpack-dev-server, live-server) \u2014 they never exit.
|
|
6902
|
-
- FINAL CHECK: confirm you can fill in at least ENTRY_FILE or PREVIEW_CMD (see deliverable types). If you cannot, your deliverable is incomplete \u2014 fix it before reporting.
|
|
6903
|
-
- Do NOT report STATUS: done unless verification passes. Fix problems yourself first.
|
|
6904
|
-
- STATUS: failed is ONLY for truly unsolvable problems (missing API keys, no network, system-level issues).
|
|
6905
|
-
|
|
6906
|
-
===== DELIVERABLE TYPES =====
|
|
6907
|
-
ALWAYS prefer type A (static web) unless the task EXPLICITLY requires a server or desktop app.
|
|
6908
|
-
Games, interactive demos, visualizations, and web pages should ALL be static HTML.
|
|
6909
6775
|
|
|
6910
|
-
|
|
6911
|
-
|
|
6912
|
-
|
|
6776
|
+
OUTPUT STYLE:
|
|
6777
|
+
- While working, output a SHORT status line (\u22648 words) at each major step, prefixed with \u2192. Example: "\u2192 Setting up project" or "\u2192 Building game logic". No other prose or narration. Do NOT write "Let me...", "I'll now...", "Looking at..." \u2014 just do the work.
|
|
6778
|
+
- After all work is done, output ONLY the structured result block below.
|
|
6913
6779
|
|
|
6914
|
-
|
|
6915
|
-
|
|
6916
|
-
|
|
6780
|
+
DELIVERABLE:
|
|
6781
|
+
- You own the COMPLETE deliverable: project setup, all source code, build & verify.
|
|
6782
|
+
- STATUS: failed is ONLY for truly unsolvable problems (missing API keys, system issues).
|
|
6917
6783
|
|
|
6918
|
-
|
|
6919
|
-
|
|
6784
|
+
VERIFY BEFORE REPORTING DONE (mandatory):
|
|
6785
|
+
- If package.json has a build script \u2192 run "npm run build" (one-shot), fix errors until it passes.
|
|
6786
|
+
- If HTML deliverable \u2192 confirm the file exists and references valid scripts/styles.
|
|
6787
|
+
- If script (Python/Node) \u2192 run syntax check (node --check / python -c "import ast; ...").
|
|
6788
|
+
- FINAL CHECK: you MUST be able to fill in ENTRY_FILE or PREVIEW_CMD below. If not, your deliverable is incomplete \u2014 fix it first.
|
|
6920
6789
|
|
|
6921
|
-
|
|
6790
|
+
DELIVERABLE TYPES (prefer A):
|
|
6791
|
+
A) STATIC WEB \u2192 ENTRY_FILE: index.html
|
|
6792
|
+
B) WEB SERVER (only if backend needed) \u2192 PREVIEW_CMD + PREVIEW_PORT
|
|
6793
|
+
C) DESKTOP/CLI \u2192 PREVIEW_CMD only
|
|
6922
6794
|
|
|
6795
|
+
RESULT FORMAT:
|
|
6923
6796
|
STATUS: done | failed
|
|
6924
|
-
FILES_CHANGED: (
|
|
6925
|
-
ENTRY_FILE: (type A
|
|
6926
|
-
PREVIEW_CMD: (types B
|
|
6927
|
-
PREVIEW_PORT: (type B only
|
|
6928
|
-
SUMMARY: (one sentence
|
|
6929
|
-
|
|
6930
|
-
You MUST provide at least ENTRY_FILE or PREVIEW_CMD. For games and interactive projects, ENTRY_FILE is almost always correct.
|
|
6797
|
+
FILES_CHANGED: (one per line)
|
|
6798
|
+
ENTRY_FILE: (type A)
|
|
6799
|
+
PREVIEW_CMD: (types B/C only)
|
|
6800
|
+
PREVIEW_PORT: (type B only)
|
|
6801
|
+
SUMMARY: (one sentence)
|
|
6931
6802
|
|
|
6932
6803
|
{{prompt}}`,
|
|
6933
6804
|
"worker-reviewer-initial": `Your name is {{name}}, your role is {{role}}. {{personality}}
|
|
6934
6805
|
|
|
6935
|
-
|
|
6936
|
-
-
|
|
6937
|
-
-
|
|
6938
|
-
-
|
|
6939
|
-
- Do NOT add features, error handling, or improvements that were not explicitly asked for.
|
|
6940
|
-
|
|
6941
|
-
HARD LIMITS:
|
|
6942
|
-
- NEVER run "npm run dev", "npm start", "npx vite", or ANY long-running server command. These hang forever. Only use one-shot commands like "npm run build" or "node --check".
|
|
6943
|
-
- Do NOT launch GUI/desktop applications (Pygame, Tkinter, Electron, etc.) to test them \u2014 they open windows that cannot be controlled. Use syntax checks, import checks, and code reading only.
|
|
6944
|
-
|
|
6945
|
-
Code Quality (must check):
|
|
6946
|
-
- Correctness: crashes, broken logic, missing files, syntax errors.
|
|
6947
|
-
- Verify the deliverable can actually run: check that entry point exists, dependencies are declared, build output is present. For GUI/desktop apps, verify via code review and syntax checks \u2014 do NOT run them.
|
|
6948
|
-
- VERIFY WITH TOOLS, not just the developer's summary. Run "ls" to confirm reported files exist. If ENTRY_FILE is claimed, check the file is there and references valid scripts/styles. Do not trust STATUS: done at face value.
|
|
6949
|
-
- Do NOT flag security issues in prototypes \u2014 this is a demo, not production code.
|
|
6806
|
+
RULES:
|
|
6807
|
+
- NEVER run servers, dev commands, or GUI apps. You CANNOT see UI.
|
|
6808
|
+
- ONLY use: code reading, "ls" to check files, "npm run build" (one-shot), syntax checks.
|
|
6809
|
+
- This is a prototype \u2014 do NOT nitpick style, naming, formatting, or security.
|
|
6950
6810
|
|
|
6951
|
-
|
|
6952
|
-
-
|
|
6953
|
-
-
|
|
6954
|
-
- Do NOT fail for polish, extras, or stretch goals \u2014 this is a prototype. Focus on whether the main functionality works.
|
|
6811
|
+
OUTPUT STYLE:
|
|
6812
|
+
- While reviewing, output a SHORT status line (\u22648 words) at each step, prefixed with \u2192. Example: "\u2192 Checking file structure" or "\u2192 Reading game logic". No other prose.
|
|
6813
|
+
- After review, output ONLY the verdict block below.
|
|
6955
6814
|
|
|
6956
|
-
|
|
6957
|
-
|
|
6815
|
+
REVIEW CHECKLIST:
|
|
6816
|
+
1. VERIFY files exist with "ls" \u2014 do NOT trust the developer's summary at face value. Check ENTRY_FILE is real and references valid scripts/styles.
|
|
6817
|
+
2. READ the code to verify logic. Check for crashes, broken logic, missing files, syntax errors.
|
|
6818
|
+
3. Feature completeness: compare against key features in your task. Flag CORE features missing/broken as ISSUES. Ignore polish/extras.
|
|
6958
6819
|
|
|
6959
6820
|
VERDICT: PASS | FAIL
|
|
6960
|
-
- PASS =
|
|
6961
|
-
- FAIL = crashes/bugs
|
|
6962
|
-
ISSUES: (numbered list
|
|
6963
|
-
SUGGESTIONS: (optional
|
|
6964
|
-
SUMMARY: (one sentence
|
|
6821
|
+
- PASS = runs without crashes AND core features implemented
|
|
6822
|
+
- FAIL = crashes/bugs prevent usage OR core features missing
|
|
6823
|
+
ISSUES: (numbered list)
|
|
6824
|
+
SUGGESTIONS: (optional, brief)
|
|
6825
|
+
SUMMARY: (one sentence)
|
|
6965
6826
|
|
|
6966
6827
|
{{prompt}}`,
|
|
6967
6828
|
"worker-continue": `{{prompt}}`,
|
|
@@ -7112,12 +6973,12 @@ var PromptEngine = class {
|
|
|
7112
6973
|
console.log(`[Prompts] No promptsDir configured, using ${Object.keys(PROMPT_DEFAULTS).length} default templates`);
|
|
7113
6974
|
return;
|
|
7114
6975
|
}
|
|
7115
|
-
if (!
|
|
6976
|
+
if (!existsSync7(this.promptsDir)) {
|
|
7116
6977
|
mkdirSync5(this.promptsDir, { recursive: true });
|
|
7117
6978
|
}
|
|
7118
6979
|
let written = 0;
|
|
7119
6980
|
for (const [name, content] of Object.entries(PROMPT_DEFAULTS)) {
|
|
7120
|
-
const filePath =
|
|
6981
|
+
const filePath = path6.join(this.promptsDir, `${name}.md`);
|
|
7121
6982
|
writeFileSync5(filePath, content, "utf-8");
|
|
7122
6983
|
written++;
|
|
7123
6984
|
}
|
|
@@ -7133,8 +6994,8 @@ var PromptEngine = class {
|
|
|
7133
6994
|
let defaulted = 0;
|
|
7134
6995
|
if (this.promptsDir) {
|
|
7135
6996
|
for (const name of Object.keys(PROMPT_DEFAULTS)) {
|
|
7136
|
-
const filePath =
|
|
7137
|
-
if (
|
|
6997
|
+
const filePath = path6.join(this.promptsDir, `${name}.md`);
|
|
6998
|
+
if (existsSync7(filePath)) {
|
|
7138
6999
|
try {
|
|
7139
7000
|
merged[name] = readFileSync5(filePath, "utf-8");
|
|
7140
7001
|
loaded++;
|
|
@@ -7397,7 +7258,7 @@ var PhaseMachine = class {
|
|
|
7397
7258
|
};
|
|
7398
7259
|
|
|
7399
7260
|
// ../../packages/orchestrator/src/result-finalizer.ts
|
|
7400
|
-
import
|
|
7261
|
+
import path7 from "path";
|
|
7401
7262
|
function finalizeTeamResult(ctx) {
|
|
7402
7263
|
const { result, teamPreview, teamChangedFiles, projectDir, workspace } = ctx;
|
|
7403
7264
|
if (teamChangedFiles.size > 0) {
|
|
@@ -7419,7 +7280,7 @@ function finalizeTeamResult(ctx) {
|
|
|
7419
7280
|
}
|
|
7420
7281
|
validateEntryFile(result, projectDir ?? workspace, workspace);
|
|
7421
7282
|
autoConstructPreviewCmd(result);
|
|
7422
|
-
if (!result.previewUrl) {
|
|
7283
|
+
if (!result.previewUrl && !result.previewPath) {
|
|
7423
7284
|
resolvePreviewUrlFromTeam(result, ctx);
|
|
7424
7285
|
}
|
|
7425
7286
|
}
|
|
@@ -7427,12 +7288,12 @@ function validateEntryFile(result, projectDir, workspace) {
|
|
|
7427
7288
|
if (!result.entryFile) return;
|
|
7428
7289
|
const resolved = resolveAgentPath(result.entryFile, projectDir, workspace);
|
|
7429
7290
|
if (resolved) {
|
|
7430
|
-
result.entryFile =
|
|
7291
|
+
result.entryFile = path7.relative(projectDir, resolved);
|
|
7431
7292
|
return;
|
|
7432
7293
|
}
|
|
7433
7294
|
const allFiles = result.changedFiles ?? [];
|
|
7434
|
-
const ext =
|
|
7435
|
-
const candidate = allFiles.map((f) =>
|
|
7295
|
+
const ext = path7.extname(result.entryFile).toLowerCase();
|
|
7296
|
+
const candidate = allFiles.map((f) => path7.basename(f)).find((f) => path7.extname(f).toLowerCase() === ext);
|
|
7436
7297
|
if (candidate) {
|
|
7437
7298
|
console.log(`[ResultFinalizer] entryFile "${result.entryFile}" not found, using "${candidate}" from changedFiles`);
|
|
7438
7299
|
result.entryFile = candidate;
|
|
@@ -7443,7 +7304,7 @@ function validateEntryFile(result, projectDir, workspace) {
|
|
|
7443
7304
|
}
|
|
7444
7305
|
function autoConstructPreviewCmd(result) {
|
|
7445
7306
|
if (!result.entryFile || result.previewCmd || /\.html?$/i.test(result.entryFile)) return;
|
|
7446
|
-
const ext =
|
|
7307
|
+
const ext = path7.extname(result.entryFile).toLowerCase();
|
|
7447
7308
|
const runner = CONFIG.preview.runners[ext];
|
|
7448
7309
|
if (runner) {
|
|
7449
7310
|
result.previewCmd = `${runner} ${result.entryFile}`;
|
|
@@ -7454,9 +7315,9 @@ function resolvePreviewUrlFromTeam(result, ctx) {
|
|
|
7454
7315
|
const { projectDir, workspace } = ctx;
|
|
7455
7316
|
const resolveDir = projectDir ?? workspace;
|
|
7456
7317
|
const workerPreview = ctx.detectWorkerPreview();
|
|
7457
|
-
if (workerPreview?.previewUrl) {
|
|
7458
|
-
result.previewUrl = workerPreview.previewUrl;
|
|
7459
|
-
result.previewPath = workerPreview.previewPath;
|
|
7318
|
+
if (workerPreview?.previewUrl || workerPreview?.previewPath) {
|
|
7319
|
+
if (workerPreview.previewUrl) result.previewUrl = workerPreview.previewUrl;
|
|
7320
|
+
if (workerPreview.previewPath) result.previewPath = workerPreview.previewPath;
|
|
7460
7321
|
return;
|
|
7461
7322
|
}
|
|
7462
7323
|
const allChangedFiles = result.changedFiles ?? [];
|
|
@@ -7468,19 +7329,17 @@ function resolvePreviewUrlFromTeam(result, ctx) {
|
|
|
7468
7329
|
cwd: resolveDir,
|
|
7469
7330
|
workspace
|
|
7470
7331
|
});
|
|
7471
|
-
if (preview.previewUrl)
|
|
7472
|
-
|
|
7473
|
-
result.previewPath = preview.previewPath;
|
|
7474
|
-
}
|
|
7332
|
+
if (preview.previewUrl) result.previewUrl = preview.previewUrl;
|
|
7333
|
+
if (preview.previewPath) result.previewPath = preview.previewPath;
|
|
7475
7334
|
}
|
|
7476
7335
|
|
|
7477
7336
|
// ../../packages/orchestrator/src/worktree.ts
|
|
7478
|
-
import { execSync as
|
|
7479
|
-
import
|
|
7337
|
+
import { execSync as execSync3 } from "child_process";
|
|
7338
|
+
import path8 from "path";
|
|
7480
7339
|
var TIMEOUT = 5e3;
|
|
7481
7340
|
function isGitRepo(cwd) {
|
|
7482
7341
|
try {
|
|
7483
|
-
|
|
7342
|
+
execSync3("git rev-parse --is-inside-work-tree", { cwd, stdio: "ignore", timeout: TIMEOUT });
|
|
7484
7343
|
return true;
|
|
7485
7344
|
} catch {
|
|
7486
7345
|
return false;
|
|
@@ -7488,12 +7347,12 @@ function isGitRepo(cwd) {
|
|
|
7488
7347
|
}
|
|
7489
7348
|
function createWorktree(workspace, agentId, taskId, agentName) {
|
|
7490
7349
|
if (!isGitRepo(workspace)) return null;
|
|
7491
|
-
const worktreeDir =
|
|
7350
|
+
const worktreeDir = path8.join(workspace, ".worktrees");
|
|
7492
7351
|
const worktreeName = `${agentId}-${taskId}`;
|
|
7493
|
-
const worktreePath =
|
|
7352
|
+
const worktreePath = path8.join(worktreeDir, worktreeName);
|
|
7494
7353
|
const branch = `agent/${agentName.toLowerCase().replace(/\s+/g, "-")}/${taskId}`;
|
|
7495
7354
|
try {
|
|
7496
|
-
|
|
7355
|
+
execSync3(`git worktree add "${worktreePath}" -b "${branch}"`, {
|
|
7497
7356
|
cwd: workspace,
|
|
7498
7357
|
stdio: "pipe",
|
|
7499
7358
|
timeout: TIMEOUT
|
|
@@ -7506,61 +7365,61 @@ function createWorktree(workspace, agentId, taskId, agentName) {
|
|
|
7506
7365
|
}
|
|
7507
7366
|
function mergeWorktree(workspace, worktreePath, branch) {
|
|
7508
7367
|
try {
|
|
7509
|
-
|
|
7368
|
+
execSync3(`git merge --no-ff "${branch}"`, {
|
|
7510
7369
|
cwd: workspace,
|
|
7511
7370
|
stdio: "pipe",
|
|
7512
7371
|
timeout: TIMEOUT
|
|
7513
7372
|
});
|
|
7514
7373
|
try {
|
|
7515
|
-
|
|
7374
|
+
execSync3(`git worktree remove "${worktreePath}"`, { cwd: workspace, stdio: "pipe", timeout: TIMEOUT });
|
|
7516
7375
|
} catch {
|
|
7517
7376
|
}
|
|
7518
7377
|
try {
|
|
7519
|
-
|
|
7378
|
+
execSync3(`git branch -d "${branch}"`, { cwd: workspace, stdio: "pipe", timeout: TIMEOUT });
|
|
7520
7379
|
} catch {
|
|
7521
7380
|
}
|
|
7522
7381
|
return { success: true };
|
|
7523
7382
|
} catch (err) {
|
|
7524
7383
|
let conflictFiles = [];
|
|
7525
7384
|
try {
|
|
7526
|
-
const output =
|
|
7385
|
+
const output = execSync3("git diff --name-only --diff-filter=U", {
|
|
7527
7386
|
cwd: workspace,
|
|
7528
7387
|
encoding: "utf-8",
|
|
7529
7388
|
timeout: TIMEOUT
|
|
7530
7389
|
}).trim();
|
|
7531
7390
|
conflictFiles = output ? output.split("\n") : [];
|
|
7532
|
-
|
|
7391
|
+
execSync3("git merge --abort", { cwd: workspace, stdio: "pipe", timeout: TIMEOUT });
|
|
7533
7392
|
} catch {
|
|
7534
7393
|
}
|
|
7535
7394
|
return { success: false, conflictFiles };
|
|
7536
7395
|
}
|
|
7537
7396
|
}
|
|
7538
7397
|
function removeWorktree(worktreePath, branch, workspace) {
|
|
7539
|
-
const cwd = workspace ??
|
|
7398
|
+
const cwd = workspace ?? path8.dirname(path8.dirname(worktreePath));
|
|
7540
7399
|
try {
|
|
7541
|
-
|
|
7400
|
+
execSync3(`git worktree remove --force "${worktreePath}"`, { cwd, stdio: "pipe", timeout: TIMEOUT });
|
|
7542
7401
|
} catch {
|
|
7543
7402
|
}
|
|
7544
7403
|
try {
|
|
7545
|
-
|
|
7404
|
+
execSync3(`git branch -D "${branch}"`, { cwd, stdio: "pipe", timeout: TIMEOUT });
|
|
7546
7405
|
} catch {
|
|
7547
7406
|
}
|
|
7548
7407
|
}
|
|
7549
7408
|
|
|
7550
7409
|
// ../../packages/orchestrator/src/memory.ts
|
|
7551
|
-
import { readFileSync as readFileSync6, writeFileSync as writeFileSync6, mkdirSync as mkdirSync6, existsSync as
|
|
7552
|
-
import
|
|
7410
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync6, mkdirSync as mkdirSync6, existsSync as existsSync8 } from "fs";
|
|
7411
|
+
import path9 from "path";
|
|
7553
7412
|
import { homedir as homedir5 } from "os";
|
|
7554
|
-
var MEMORY_DIR =
|
|
7413
|
+
var MEMORY_DIR = path9.join(homedir5(), ".bit-office", "memory");
|
|
7555
7414
|
function ensureDir() {
|
|
7556
|
-
if (!
|
|
7415
|
+
if (!existsSync8(MEMORY_DIR)) {
|
|
7557
7416
|
mkdirSync6(MEMORY_DIR, { recursive: true });
|
|
7558
7417
|
}
|
|
7559
7418
|
}
|
|
7560
7419
|
function loadStore() {
|
|
7561
|
-
const filePath =
|
|
7420
|
+
const filePath = path9.join(MEMORY_DIR, "memory.json");
|
|
7562
7421
|
try {
|
|
7563
|
-
if (
|
|
7422
|
+
if (existsSync8(filePath)) {
|
|
7564
7423
|
return JSON.parse(readFileSync6(filePath, "utf-8"));
|
|
7565
7424
|
}
|
|
7566
7425
|
} catch {
|
|
@@ -7569,7 +7428,7 @@ function loadStore() {
|
|
|
7569
7428
|
}
|
|
7570
7429
|
function saveStore(store) {
|
|
7571
7430
|
ensureDir();
|
|
7572
|
-
const filePath =
|
|
7431
|
+
const filePath = path9.join(MEMORY_DIR, "memory.json");
|
|
7573
7432
|
writeFileSync6(filePath, JSON.stringify(store, null, 2), "utf-8");
|
|
7574
7433
|
}
|
|
7575
7434
|
function recordReviewFeedback(reviewOutput) {
|
|
@@ -8210,6 +8069,149 @@ var Orchestrator = class extends EventEmitter {
|
|
|
8210
8069
|
}
|
|
8211
8070
|
};
|
|
8212
8071
|
|
|
8072
|
+
// ../../packages/orchestrator/src/preview-server.ts
|
|
8073
|
+
import { spawn as spawn2, execSync as execSync4 } from "child_process";
|
|
8074
|
+
import { existsSync as existsSync9 } from "fs";
|
|
8075
|
+
import path10 from "path";
|
|
8076
|
+
var STATIC_PORT = 9100;
|
|
8077
|
+
var COMMAND_PORT = 9101;
|
|
8078
|
+
var PreviewServer = class {
|
|
8079
|
+
process = null;
|
|
8080
|
+
currentDir = null;
|
|
8081
|
+
isDetached = false;
|
|
8082
|
+
/**
|
|
8083
|
+
* Mode 1: Serve a static file directory on a fixed port.
|
|
8084
|
+
* Returns the preview URL for the given file.
|
|
8085
|
+
*/
|
|
8086
|
+
serve(filePath) {
|
|
8087
|
+
if (!existsSync9(filePath)) {
|
|
8088
|
+
console.log(`[PreviewServer] File not found: ${filePath}`);
|
|
8089
|
+
return void 0;
|
|
8090
|
+
}
|
|
8091
|
+
const dir = path10.dirname(filePath);
|
|
8092
|
+
const fileName = path10.basename(filePath);
|
|
8093
|
+
this.stop();
|
|
8094
|
+
try {
|
|
8095
|
+
this.process = spawn2("npx", ["serve", dir, "-l", String(STATIC_PORT), "--no-clipboard"], {
|
|
8096
|
+
stdio: "ignore",
|
|
8097
|
+
detached: true
|
|
8098
|
+
});
|
|
8099
|
+
this.process.unref();
|
|
8100
|
+
this.currentDir = dir;
|
|
8101
|
+
this.isDetached = true;
|
|
8102
|
+
const url = `http://localhost:${STATIC_PORT}/${fileName}`;
|
|
8103
|
+
console.log(`[PreviewServer] Serving ${dir} on port ${STATIC_PORT}`);
|
|
8104
|
+
return url;
|
|
8105
|
+
} catch (e) {
|
|
8106
|
+
console.log(`[PreviewServer] Failed to start static serve: ${e}`);
|
|
8107
|
+
return void 0;
|
|
8108
|
+
}
|
|
8109
|
+
}
|
|
8110
|
+
/**
|
|
8111
|
+
* Mode 2: Run a command (e.g. "python app.py") and use a controlled port.
|
|
8112
|
+
* The agent-specified port is ALWAYS replaced with COMMAND_PORT to prevent
|
|
8113
|
+
* conflicts with the host system (e.g. Next.js on 3000).
|
|
8114
|
+
* Returns the preview URL.
|
|
8115
|
+
*/
|
|
8116
|
+
runCommand(cmd, cwd, agentPort) {
|
|
8117
|
+
this.stop();
|
|
8118
|
+
const port = COMMAND_PORT;
|
|
8119
|
+
cmd = cmd.replace(/\s+(?:--port|-p)\s+\d+/gi, "");
|
|
8120
|
+
if (agentPort) cmd = cmd.replace(new RegExp(`\\b${agentPort}\\b`, "g"), String(port));
|
|
8121
|
+
cmd = `${cmd} --port ${port}`;
|
|
8122
|
+
console.log(`[PreviewServer] Command: "${cmd}" (forced port ${port})`);
|
|
8123
|
+
this.killPortHolder(port);
|
|
8124
|
+
try {
|
|
8125
|
+
this.process = spawn2(cmd, {
|
|
8126
|
+
shell: true,
|
|
8127
|
+
cwd,
|
|
8128
|
+
stdio: "ignore",
|
|
8129
|
+
detached: true,
|
|
8130
|
+
env: { ...process.env, PORT: String(port) }
|
|
8131
|
+
});
|
|
8132
|
+
this.process.unref();
|
|
8133
|
+
this.currentDir = cwd;
|
|
8134
|
+
this.isDetached = true;
|
|
8135
|
+
const url = `http://localhost:${port}`;
|
|
8136
|
+
console.log(`[PreviewServer] Running "${cmd}" in ${cwd}, preview at port ${port}`);
|
|
8137
|
+
return url;
|
|
8138
|
+
} catch (e) {
|
|
8139
|
+
console.log(`[PreviewServer] Failed to run command: ${e}`);
|
|
8140
|
+
return void 0;
|
|
8141
|
+
}
|
|
8142
|
+
}
|
|
8143
|
+
/**
|
|
8144
|
+
* Mode 3: Launch a desktop/CLI process (no web preview URL).
|
|
8145
|
+
* Used for Pygame, Tkinter, Electron, terminal apps, etc.
|
|
8146
|
+
* NOT detached — GUI apps need the login session to access WindowServer (macOS).
|
|
8147
|
+
*/
|
|
8148
|
+
launchProcess(cmd, cwd) {
|
|
8149
|
+
this.stop();
|
|
8150
|
+
try {
|
|
8151
|
+
this.process = spawn2(cmd, {
|
|
8152
|
+
shell: true,
|
|
8153
|
+
cwd,
|
|
8154
|
+
stdio: ["ignore", "ignore", "pipe"]
|
|
8155
|
+
});
|
|
8156
|
+
this.currentDir = cwd;
|
|
8157
|
+
this.isDetached = false;
|
|
8158
|
+
console.log(`[PreviewServer] Launched "${cmd}" in ${cwd} (pid=${this.process.pid})`);
|
|
8159
|
+
this.process.stderr?.on("data", (data) => {
|
|
8160
|
+
const msg = data.toString().trim();
|
|
8161
|
+
if (msg) console.log(`[PreviewServer] stderr: ${msg.slice(0, 200)}`);
|
|
8162
|
+
});
|
|
8163
|
+
this.process.on("exit", (code) => {
|
|
8164
|
+
console.log(`[PreviewServer] Process exited with code ${code}`);
|
|
8165
|
+
});
|
|
8166
|
+
} catch (e) {
|
|
8167
|
+
console.log(`[PreviewServer] Failed to launch process: ${e}`);
|
|
8168
|
+
}
|
|
8169
|
+
}
|
|
8170
|
+
/** Kill the current process and any orphan process on managed ports */
|
|
8171
|
+
stop() {
|
|
8172
|
+
if (this.process) {
|
|
8173
|
+
try {
|
|
8174
|
+
if (this.isDetached && this.process.pid) {
|
|
8175
|
+
process.kill(-this.process.pid, "SIGTERM");
|
|
8176
|
+
} else {
|
|
8177
|
+
this.process.kill("SIGTERM");
|
|
8178
|
+
}
|
|
8179
|
+
} catch {
|
|
8180
|
+
try {
|
|
8181
|
+
this.process.kill("SIGTERM");
|
|
8182
|
+
} catch {
|
|
8183
|
+
}
|
|
8184
|
+
}
|
|
8185
|
+
this.process = null;
|
|
8186
|
+
this.currentDir = null;
|
|
8187
|
+
this.isDetached = false;
|
|
8188
|
+
console.log(`[PreviewServer] Stopped`);
|
|
8189
|
+
}
|
|
8190
|
+
this.killPortHolder(STATIC_PORT);
|
|
8191
|
+
this.killPortHolder(COMMAND_PORT);
|
|
8192
|
+
}
|
|
8193
|
+
/** Kill whatever process is listening on the given port (best-effort). */
|
|
8194
|
+
killPortHolder(port) {
|
|
8195
|
+
try {
|
|
8196
|
+
const out = execSync4(`lsof -ti :${port}`, { encoding: "utf-8", timeout: 3e3 }).trim();
|
|
8197
|
+
if (out) {
|
|
8198
|
+
for (const pid of out.split("\n")) {
|
|
8199
|
+
const n = parseInt(pid, 10);
|
|
8200
|
+
if (n > 0) {
|
|
8201
|
+
try {
|
|
8202
|
+
process.kill(n, "SIGKILL");
|
|
8203
|
+
} catch {
|
|
8204
|
+
}
|
|
8205
|
+
}
|
|
8206
|
+
}
|
|
8207
|
+
console.log(`[PreviewServer] Killed orphan process(es) on port ${port}: ${out.replace(/\n/g, ", ")}`);
|
|
8208
|
+
}
|
|
8209
|
+
} catch {
|
|
8210
|
+
}
|
|
8211
|
+
}
|
|
8212
|
+
};
|
|
8213
|
+
var previewServer = new PreviewServer();
|
|
8214
|
+
|
|
8213
8215
|
// ../../packages/orchestrator/src/index.ts
|
|
8214
8216
|
function createOrchestrator(options) {
|
|
8215
8217
|
return new Orchestrator(options);
|
|
@@ -8799,6 +8801,15 @@ function archiveProject(agents, team) {
|
|
|
8799
8801
|
}
|
|
8800
8802
|
}
|
|
8801
8803
|
}
|
|
8804
|
+
let totalInputTokens = 0;
|
|
8805
|
+
let totalOutputTokens = 0;
|
|
8806
|
+
for (const e of projectEvents) {
|
|
8807
|
+
if (e.type === "TASK_DONE" && e.result?.tokenUsage) {
|
|
8808
|
+
totalInputTokens += e.result.tokenUsage.inputTokens ?? 0;
|
|
8809
|
+
totalOutputTokens += e.result.tokenUsage.outputTokens ?? 0;
|
|
8810
|
+
}
|
|
8811
|
+
}
|
|
8812
|
+
const tokenUsage = totalInputTokens > 0 || totalOutputTokens > 0 ? { inputTokens: totalInputTokens, outputTokens: totalOutputTokens } : void 0;
|
|
8802
8813
|
const id = `${projectStartedAt}-${projectName || "project"}`;
|
|
8803
8814
|
const archive = {
|
|
8804
8815
|
id,
|
|
@@ -8808,7 +8819,8 @@ function archiveProject(agents, team) {
|
|
|
8808
8819
|
agents,
|
|
8809
8820
|
team,
|
|
8810
8821
|
events: projectEvents,
|
|
8811
|
-
preview
|
|
8822
|
+
preview,
|
|
8823
|
+
tokenUsage
|
|
8812
8824
|
};
|
|
8813
8825
|
try {
|
|
8814
8826
|
const filePath = path12.join(PROJECTS_DIR, `${id}.json`);
|
|
@@ -8836,7 +8848,8 @@ function listProjects() {
|
|
|
8836
8848
|
endedAt: raw.endedAt,
|
|
8837
8849
|
agentNames: raw.agents.map((a) => a.name),
|
|
8838
8850
|
eventCount: raw.events.length,
|
|
8839
|
-
preview: raw.preview
|
|
8851
|
+
preview: raw.preview,
|
|
8852
|
+
tokenUsage: raw.tokenUsage
|
|
8840
8853
|
});
|
|
8841
8854
|
} catch {
|
|
8842
8855
|
}
|
|
@@ -9015,6 +9028,8 @@ function mapOrchestratorEvent(e) {
|
|
|
9015
9028
|
persistTeamState();
|
|
9016
9029
|
return null;
|
|
9017
9030
|
}
|
|
9031
|
+
case "token:update":
|
|
9032
|
+
return { type: "TOKEN_UPDATE", agentId: e.agentId, inputTokens: e.inputTokens, outputTokens: e.outputTokens };
|
|
9018
9033
|
// New events (worktree, retry) — log only, no wire protocol equivalent yet
|
|
9019
9034
|
case "task:retrying":
|
|
9020
9035
|
console.log(`[Retry] Agent ${e.agentId} retrying task ${e.taskId} (attempt ${e.attempt}/${e.maxRetries})`);
|
|
@@ -9541,6 +9556,7 @@ async function main() {
|
|
|
9541
9556
|
orc.on("task:queued", forwardEvent);
|
|
9542
9557
|
orc.on("worktree:created", forwardEvent);
|
|
9543
9558
|
orc.on("worktree:merged", forwardEvent);
|
|
9559
|
+
orc.on("token:update", forwardEvent);
|
|
9544
9560
|
orc.on("agent:created", forwardEvent);
|
|
9545
9561
|
orc.on("agent:fired", forwardEvent);
|
|
9546
9562
|
orc.on("task:result-returned", forwardEvent);
|