bit-office 1.2.3 → 1.2.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.
Files changed (38) hide show
  1. package/dist/index.js +412 -396
  2. package/dist/index.js.map +1 -1
  3. package/dist/web/404.html +2 -2
  4. package/dist/web/_next/static/chunks/262.71aab99cc60a53d6.js +1 -0
  5. package/dist/web/_next/static/chunks/29.3f310d0e1e39b284.js +1 -0
  6. package/dist/web/_next/static/chunks/337.37c047a79777052d.js +1 -0
  7. package/dist/web/_next/static/chunks/{368.17f62d3909ec67e9.js → 368.3f346c171a638292.js} +1 -1
  8. package/dist/web/_next/static/chunks/606.4e73b23e56d12bdb.js +1 -0
  9. package/dist/web/_next/static/chunks/729.826ca49d46677d86.js +1 -0
  10. package/dist/web/_next/static/chunks/853.3ac80a6e5f45c12f.js +1 -0
  11. package/dist/web/_next/static/chunks/895.ba8d7f302ee0082f.js +1 -0
  12. package/dist/web/_next/static/chunks/999.bd3853e8dc65d694.js +1 -0
  13. package/dist/web/_next/static/chunks/app/office/page-6eabeff9ea24f0b8.js +1 -0
  14. package/dist/web/_next/static/chunks/app/pair/{page-67f86e4adcdf34ea.js → page-ec98149563ab8ea8.js} +1 -1
  15. package/dist/web/_next/static/chunks/{webpack-ecac0d5245a37138.js → webpack-1cd76fe3b13e8777.js} +1 -1
  16. package/dist/web/_next/static/css/620fea4ddbe8c89c.css +3 -0
  17. package/dist/web/index.html +2 -2
  18. package/dist/web/index.txt +2 -2
  19. package/dist/web/join.html +2 -2
  20. package/dist/web/join.txt +2 -2
  21. package/dist/web/office.html +3 -3
  22. package/dist/web/office.txt +3 -3
  23. package/dist/web/pair.html +2 -2
  24. package/dist/web/pair.txt +3 -3
  25. package/dist/web/sw.js +1 -1
  26. package/package.json +1 -1
  27. package/dist/web/_next/static/chunks/262.c930af897fc1ae41.js +0 -1
  28. package/dist/web/_next/static/chunks/29.5e4e3e30b02d00ad.js +0 -1
  29. package/dist/web/_next/static/chunks/337.d02d761d8479a26b.js +0 -1
  30. package/dist/web/_next/static/chunks/606.64076fb5c9a76eb8.js +0 -1
  31. package/dist/web/_next/static/chunks/729.f8f9847d2d765724.js +0 -1
  32. package/dist/web/_next/static/chunks/853.1223037341c73df9.js +0 -1
  33. package/dist/web/_next/static/chunks/895.b20c839956b4d7fa.js +0 -1
  34. package/dist/web/_next/static/chunks/999.59e64ccb62c7e043.js +0 -1
  35. package/dist/web/_next/static/chunks/app/office/page-7e64f4657627f13b.js +0 -1
  36. package/dist/web/_next/static/css/7a1e811bf3f4909f.css +0 -3
  37. /package/dist/web/_next/static/{30c0_3N7JM7PsUvSPrOdD → 5vHCPBj0Ikhb0tVooPDGd}/_buildManifest.js +0 -0
  38. /package/dist/web/_next/static/{30c0_3N7JM7PsUvSPrOdD → 5vHCPBj0Ikhb0tVooPDGd}/_ssgManifest.js +0 -0
package/dist/index.js CHANGED
@@ -4154,6 +4154,7 @@ var CreateAgentCommand = external_exports.object({
4154
4154
  palette: external_exports.number().optional(),
4155
4155
  personality: external_exports.string().optional(),
4156
4156
  backend: external_exports.string().optional(),
4157
+ model: external_exports.string().optional(),
4157
4158
  teamId: external_exports.string().optional(),
4158
4159
  workDir: external_exports.string().optional(),
4159
4160
  skillFiles: external_exports.array(external_exports.string()).optional()
@@ -4261,9 +4262,6 @@ var LoadProjectCommand = external_exports.object({
4261
4262
  type: external_exports.literal("LOAD_PROJECT"),
4262
4263
  projectId: external_exports.string()
4263
4264
  });
4264
- var UpdateAgencyAgentsCommand = external_exports.object({
4265
- type: external_exports.literal("UPDATE_AGENCY_AGENTS")
4266
- });
4267
4265
  var GetConfigCommand = external_exports.object({
4268
4266
  type: external_exports.literal("GET_CONFIG")
4269
4267
  });
@@ -4304,6 +4302,14 @@ var RequestReviewCommand = external_exports.object({
4304
4302
  summary: external_exports.string().optional(),
4305
4303
  backend: external_exports.string().optional()
4306
4304
  });
4305
+ var SyncChatHistoryCommand = external_exports.object({
4306
+ type: external_exports.literal("SYNC_CHAT_HISTORY"),
4307
+ /** Serialized PersistedAgent[] — same format as localStorage office-chat-history */
4308
+ data: external_exports.string()
4309
+ });
4310
+ var LoadChatHistoryCommand = external_exports.object({
4311
+ type: external_exports.literal("LOAD_CHAT_HISTORY")
4312
+ });
4307
4313
  var CommandSchema = external_exports.discriminatedUnion("type", [
4308
4314
  RunTaskCommand,
4309
4315
  ApprovalDecisionCommand,
@@ -4327,7 +4333,6 @@ var CommandSchema = external_exports.discriminatedUnion("type", [
4327
4333
  RateProjectCommand,
4328
4334
  ListProjectsCommand,
4329
4335
  LoadProjectCommand,
4330
- UpdateAgencyAgentsCommand,
4331
4336
  RequestReviewCommand,
4332
4337
  MergeWorktreeCommand,
4333
4338
  UndoMergeCommand,
@@ -4337,7 +4342,9 @@ var CommandSchema = external_exports.discriminatedUnion("type", [
4337
4342
  SaveConfigCommand,
4338
4343
  ListSkillsCommand,
4339
4344
  SaveSkillCommand,
4340
- DeleteSkillCommand
4345
+ DeleteSkillCommand,
4346
+ SyncChatHistoryCommand,
4347
+ LoadChatHistoryCommand
4341
4348
  ]);
4342
4349
 
4343
4350
  // ../../packages/shared/src/events.ts
@@ -4548,12 +4555,6 @@ var ImageUploadedEvent = external_exports.object({
4548
4555
  requestId: external_exports.string(),
4549
4556
  path: external_exports.string()
4550
4557
  });
4551
- var AgencyAgentsUpdatedEvent = external_exports.object({
4552
- type: external_exports.literal("AGENCY_AGENTS_UPDATED"),
4553
- success: external_exports.boolean(),
4554
- message: external_exports.string(),
4555
- count: external_exports.number().optional()
4556
- });
4557
4558
  var WorktreeReadyEvent = external_exports.object({
4558
4559
  type: external_exports.literal("WORKTREE_READY"),
4559
4560
  agentId: external_exports.string(),
@@ -4607,6 +4608,11 @@ var ConfigSavedEvent = external_exports.object({
4607
4608
  telegramConnected: external_exports.boolean().optional(),
4608
4609
  tunnelRunning: external_exports.boolean().optional()
4609
4610
  });
4611
+ var ChatHistoryLoadedEvent = external_exports.object({
4612
+ type: external_exports.literal("CHAT_HISTORY_LOADED"),
4613
+ /** Serialized PersistedAgent[] — same format as localStorage */
4614
+ data: external_exports.string()
4615
+ });
4610
4616
  var GatewayEventSchema = external_exports.discriminatedUnion("type", [
4611
4617
  AgentsSyncEvent,
4612
4618
  AgentStatusEvent,
@@ -4631,7 +4637,6 @@ var GatewayEventSchema = external_exports.discriminatedUnion("type", [
4631
4637
  PreviewReadyEvent,
4632
4638
  FolderPickedEvent,
4633
4639
  ImageUploadedEvent,
4634
- AgencyAgentsUpdatedEvent,
4635
4640
  BackendsAvailableEvent,
4636
4641
  ConfigLoadedEvent,
4637
4642
  ConfigSavedEvent,
@@ -4639,29 +4644,35 @@ var GatewayEventSchema = external_exports.discriminatedUnion("type", [
4639
4644
  WorktreeMergedEvent,
4640
4645
  WorktreeRevertedEvent,
4641
4646
  AutoMergeUpdatedEvent,
4642
- SkillListEvent
4647
+ SkillListEvent,
4648
+ ChatHistoryLoadedEvent
4643
4649
  ]);
4644
4650
 
4645
4651
  // ../../packages/shared/src/presets.ts
4646
4652
  var AGENT_PRESETS = [
4647
- { palette: 0, name: "Alex", role: "Frontend Developer", description: "UI, React/Vue/Next.js, CSS, accessibility", personality: "Detail-oriented and user-centric. Focuses on performance, accessibility, and pixel-perfect implementation." },
4648
- { palette: 1, name: "Mia", role: "Backend Architect", description: "APIs, databases, system design, cloud", personality: "Strategic and security-focused. Designs for scale, reliability, and maintainability." },
4649
- { palette: 2, name: "Leo", role: "Rapid Prototyper", description: "MVP, proof-of-concept, fast iteration", personality: "Speed-focused and pragmatic. Ships working prototypes fast, iterates based on feedback." },
4650
- { palette: 5, name: "Marcus", role: "Team Lead", description: "Creative direction, planning, delegation", personality: "Strong product intuition, communicates with clarity and vision. Focuses on the big picture and keeps the team aligned.", isLeader: true },
4651
- { palette: 4, name: "Nova", role: "UX Architect", description: "UX foundations, CSS systems, layout, component architecture", personality: "Systematic and developer-empathetic. Bridges design vision and implementation with clear, buildable structures." }
4653
+ { palette: 3, name: "Rex", role: "Senior Developer", description: "General-purpose dev, any language/framework", personality: "" },
4654
+ { palette: 0, name: "Alex", role: "Frontend Developer", description: "UI, React/Vue/Next.js, CSS, accessibility", personality: "" },
4655
+ { palette: 1, name: "Mia", role: "Backend Architect", description: "APIs, databases, system design, cloud", personality: "" },
4656
+ { palette: 2, name: "Leo", role: "Rapid Prototyper", description: "MVP, proof-of-concept, fast iteration", personality: "" },
4657
+ { palette: 4, name: "Nova", role: "UI Designer", description: "Design systems, spacing, color, accessibility", personality: "" },
4658
+ { palette: 6, name: "Luna", role: "Product Manager", description: "PRD, prioritization, user stories, outcomes", personality: "" },
4659
+ { palette: 5, name: "Marcus", role: "Team Lead", description: "Creative direction, planning, delegation", personality: "", isLeader: true },
4660
+ { palette: 7, name: "Sophie", role: "Code Reviewer", description: "Code review, bugs, security, quality", personality: "", isReviewer: true }
4652
4661
  ];
4653
4662
  var LEADER_PRESET_INDEX = AGENT_PRESETS.findIndex((p) => p.isLeader);
4654
4663
 
4655
4664
  // ../../packages/shared/src/agent-defs.ts
4656
4665
  var DEFAULT_AGENT_DEFS = [
4657
- // Bare agent no personality, no skills, like talking to raw Claude Code
4658
- { id: "rex", name: "Rex", role: "Developer", skills: "", personality: "", palette: 0, isBuiltin: true, teamRole: "dev" },
4659
- // Agency-agents backed roles role must match agency-agents `name` for subagent resolution
4660
- { id: "alex", name: "Alex", role: "Frontend Developer", skills: "UI, React/Vue/Next.js, CSS, accessibility", personality: "Detail-oriented and user-centric. Focuses on performance, accessibility, and pixel-perfect implementation.", palette: 0, isBuiltin: true, teamRole: "dev" },
4661
- { id: "mia", name: "Mia", role: "Backend Architect", skills: "APIs, databases, system design, cloud", personality: "Strategic and security-focused. Designs for scale, reliability, and maintainability.", palette: 1, isBuiltin: true, teamRole: "dev" },
4662
- { id: "leo", name: "Leo", role: "Rapid Prototyper", skills: "MVP, proof-of-concept, fast iteration", personality: "Speed-focused and pragmatic. Ships working prototypes fast, iterates based on feedback.", palette: 2, isBuiltin: true, teamRole: "dev" },
4663
- { id: "marcus", name: "Marcus", role: "Team Lead", skills: "Creative direction, planning, delegation", personality: "Strong product intuition, communicates with clarity and vision. Focuses on the big picture and keeps the team aligned.", palette: 5, isBuiltin: true, teamRole: "leader" },
4664
- { id: "nova", name: "Nova", role: "UX Architect", skills: "UX foundations, CSS systems, layout, component architecture", personality: "Systematic and developer-empathetic. Bridges design vision and implementation with clear, buildable structures.", palette: 4, isBuiltin: true, teamRole: "dev" }
4666
+ // ── Hire list (6 presets) ──
4667
+ { id: "rex", name: "Rex", role: "Senior Developer", skills: "General-purpose dev, any language/framework", personality: "", palette: 3, isBuiltin: true, teamRole: "dev" },
4668
+ { id: "alex", name: "Alex", role: "Frontend Developer", skills: "UI, React/Vue/Next.js, CSS, accessibility", personality: "", palette: 0, isBuiltin: true, teamRole: "dev" },
4669
+ { id: "mia", name: "Mia", role: "Backend Architect", skills: "APIs, databases, system design, cloud", personality: "", palette: 1, isBuiltin: true, teamRole: "dev" },
4670
+ { id: "leo", name: "Leo", role: "Rapid Prototyper", skills: "MVP, proof-of-concept, fast iteration", personality: "", palette: 2, isBuiltin: true, teamRole: "dev" },
4671
+ { id: "nova", name: "Nova", role: "UI Designer", skills: "Design systems, spacing, color, accessibility", personality: "", palette: 4, isBuiltin: true, teamRole: "dev" },
4672
+ { id: "luna", name: "Luna", role: "Product Manager", skills: "PRD, prioritization, user stories, outcomes", personality: "", palette: 6, isBuiltin: true, teamRole: "dev" },
4673
+ // ── Hidden (auto-assigned, not in hire list) ──
4674
+ { id: "marcus", name: "Marcus", role: "Team Lead", skills: "Creative direction, planning, delegation", personality: "", palette: 5, isBuiltin: true, teamRole: "leader" },
4675
+ { id: "sophie", name: "Sophie", role: "Code Reviewer", skills: "Code review, bugs, security, quality", personality: "", palette: 7, isBuiltin: true, teamRole: "reviewer" }
4665
4676
  ];
4666
4677
 
4667
4678
  // src/config.ts
@@ -4786,6 +4797,7 @@ function buildConfig() {
4786
4797
  telegramAllowedUsers: process.env.TELEGRAM_ALLOWED_USERS ? process.env.TELEGRAM_ALLOWED_USERS.split(",").map((s) => s.trim()).filter(Boolean) : saved.telegramAllowedUsers ?? [],
4787
4798
  detectedBackends: saved.detectedBackends ?? [],
4788
4799
  defaultBackend: saved.defaultBackend ?? "claude",
4800
+ defaultModels: saved.defaultModels ?? { claude: "opus" },
4789
4801
  sandboxMode: saved.sandboxMode ?? "full",
4790
4802
  worktreeEnabled: saved.worktreeEnabled ?? true,
4791
4803
  autoMergeEnabled: saved.autoMergeEnabled ?? true,
@@ -4968,6 +4980,40 @@ function parseAgentOutput(raw, fallbackText) {
4968
4980
  const summary = extractFallbackSummary(text, changedFiles.length > 0, entryFile, projectDir);
4969
4981
  return { summary, fullOutput, changedFiles, entryFile, projectDir, previewCmd, previewPort };
4970
4982
  }
4983
+ function parseReviewerFeedback(raw) {
4984
+ const verdictMatch = raw.match(/\*{0,2}VERDICT:?\*{0,2}\s*(PASS|FAIL)/i);
4985
+ const verdict = verdictMatch ? verdictMatch[1].toUpperCase() : "UNKNOWN";
4986
+ const summaryMatch = raw.match(/\*{0,2}SUMMARY:?\*{0,2}\s*(.+)/i);
4987
+ const summary = summaryMatch?.[1]?.trim() ?? "";
4988
+ const issues = extractNumberedList(raw, "ISSUES");
4989
+ const suggestions2 = extractNumberedList(raw, "SUGGESTIONS");
4990
+ const parts = [`VERDICT: ${verdict}`];
4991
+ if (issues.length > 0) {
4992
+ parts.push("ISSUES:");
4993
+ issues.forEach((issue, i) => parts.push(`${i + 1}. ${issue}`));
4994
+ }
4995
+ if (suggestions2.length > 0) {
4996
+ parts.push("SUGGESTIONS:");
4997
+ suggestions2.forEach((s, i) => parts.push(`${i + 1}. ${s}`));
4998
+ }
4999
+ if (summary) parts.push(`SUMMARY: ${summary}`);
5000
+ return { verdict, issues, suggestions: suggestions2, summary, formatted: parts.join("\n") };
5001
+ }
5002
+ function extractNumberedList(raw, label) {
5003
+ const labelRe = new RegExp(`\\*{0,2}${label}:?\\*{0,2}\\s*(.*)`, "i");
5004
+ const labelMatch = raw.match(labelRe);
5005
+ if (!labelMatch) return [];
5006
+ const startIdx = raw.indexOf(labelMatch[0]) + labelMatch[0].length;
5007
+ const remainingSections = /\n\s*\*{0,2}(?:VERDICT|ISSUES|SUGGESTIONS|SUMMARY|STATUS|FILES_CHANGED|ENTRY_FILE):?\*{0,2}/i;
5008
+ const endMatch = raw.slice(startIdx).match(remainingSections);
5009
+ const block = labelMatch[1] + (endMatch ? raw.slice(startIdx, startIdx + endMatch.index) : raw.slice(startIdx));
5010
+ const items = [];
5011
+ for (const match of block.matchAll(/(?:^|\n)\s*(?:\d+[\.\)]\s*|[-*]\s+)(.+)/g)) {
5012
+ const item = match[1].trim();
5013
+ if (item) items.push(item);
5014
+ }
5015
+ return items;
5016
+ }
4971
5017
  function extractFallbackSummary(raw, _hasFiles, _entryFile, _projectDir) {
4972
5018
  const lines = raw.split("\n").filter((l) => l.trim());
4973
5019
  const delegationRe = /^@(\w+):/;
@@ -6351,6 +6397,7 @@ var AgentSession = class {
6351
6397
  timedOut = false;
6352
6398
  _isTeamLead;
6353
6399
  _memoryContext;
6400
+ _model;
6354
6401
  /** Whether this leader has already been through execute phase at least once */
6355
6402
  _hasExecuted = false;
6356
6403
  _lastResult = null;
@@ -6420,6 +6467,10 @@ var AgentSession = class {
6420
6467
  get backendId() {
6421
6468
  return this.backend.id;
6422
6469
  }
6470
+ /** Model override (e.g. "opus", "sonnet") */
6471
+ get model() {
6472
+ return this._model;
6473
+ }
6423
6474
  teamId;
6424
6475
  constructor(opts) {
6425
6476
  this.agentId = opts.agentId;
@@ -6434,6 +6485,7 @@ var AgentSession = class {
6434
6485
  this._isTeamLead = opts.isTeamLead ?? false;
6435
6486
  this.teamId = opts.teamId;
6436
6487
  this._memoryContext = opts.memoryContext ?? "";
6488
+ this._model = opts.model;
6437
6489
  this.onEvent = opts.onEvent;
6438
6490
  this._renderPrompt = opts.renderPrompt;
6439
6491
  }
@@ -6522,14 +6574,7 @@ var AgentSession = class {
6522
6574
  originalTask,
6523
6575
  prompt,
6524
6576
  memory: this._memoryContext || getMemoryContext(this.agentId),
6525
- recoveryContext: recoveryContextStr,
6526
- soloHint: this.teamId ? "" : `- You are a SOLO developer. Do NOT delegate, assign tasks, or mention other team members. Do ALL the work yourself.
6527
- - WORKSPACE: Your working directory is ${cwd}. ALL files must be created inside this directory. Do NOT create files in $HOME or any other directory.
6528
- - PROJECT DIRECTORY: When creating files, first create a dedicated project directory (short kebab-case name, e.g. "snake-game") inside your workspace. Do ALL work inside it. Report it as PROJECT_DIR: <directory-name> in your output. If the user is just chatting (no code needed), skip this.
6529
- - Before destructive operations (rm -rf, git reset, chmod), ask for approval first.
6530
- - OUTPUT DISCIPLINE: Return ONLY actionable results (code changes, file paths, findings, errors). No chain-of-thought, no step-by-step narration, no reasoning process. Maximum 5 sentences for summary. If the task produced code changes, return: files changed, what changed, any issues. Nothing else.
6531
- - LANGUAGE: Always write SUMMARY in English, using conventional commit style (e.g. "feat: add login page with OAuth support"). Keep it under 72 characters.
6532
- - If you have a plan, wrap it in [PLAN]...[/PLAN] tags and wait for approval before executing.`
6577
+ recoveryContext: recoveryContextStr
6533
6578
  };
6534
6579
  const isFirstExecute = this._isTeamLead && phaseOverride === "execute" && !this._hasExecuted;
6535
6580
  let agentType;
@@ -6561,16 +6606,17 @@ var AgentSession = class {
6561
6606
  } else {
6562
6607
  workerInitial = "worker-initial";
6563
6608
  }
6564
- const canResume = this.hasHistory && !!this.sessionId;
6609
+ const canResume = !isReviewer && this.hasHistory && !!this.sessionId;
6565
6610
  fullPrompt = this._renderPrompt(canResume ? "worker-continue" : workerInitial, templateVars);
6566
6611
  }
6567
6612
  const fullAccess = this.sandboxMode === "full";
6568
6613
  const verbose = !!process.env.DEBUG;
6569
6614
  const args = this.backend.buildArgs(fullPrompt, {
6570
6615
  continue: false,
6571
- resumeSessionId: this.sessionId ?? void 0,
6616
+ resumeSessionId: this.role.toLowerCase().includes("review") ? void 0 : this.sessionId ?? void 0,
6572
6617
  fullAccess,
6573
6618
  noTools: this._isTeamLead,
6619
+ model: this._model,
6574
6620
  verbose,
6575
6621
  agentType,
6576
6622
  worktree: this.useNativeWorktree,
@@ -7179,8 +7225,8 @@ var AgentSession = class {
7179
7225
  summary,
7180
7226
  riskLevel
7181
7227
  });
7182
- return new Promise((resolve4) => {
7183
- this.pendingApprovals.set(approvalId, { approvalId, resolve: resolve4 });
7228
+ return new Promise((resolve5) => {
7229
+ this.pendingApprovals.set(approvalId, { approvalId, resolve: resolve5 });
7184
7230
  });
7185
7231
  }
7186
7232
  setStatus(status) {
@@ -7507,7 +7553,8 @@ var DelegationRouter = class {
7507
7553
  });
7508
7554
  this.prepareWorktree?.(target.agentId, taskId, repoPath);
7509
7555
  const workerTeamContext = this.buildWorkerTeamContext(target.agentId);
7510
- target.runTask(taskId, fullPrompt, repoPath, workerTeamContext);
7556
+ const effectiveRepoPath = targetRole.includes("review") ? this.resolveDevWorktreePath(repoPath) : repoPath;
7557
+ target.runTask(taskId, fullPrompt, effectiveRepoPath, workerTeamContext);
7511
7558
  };
7512
7559
  }
7513
7560
  wireResultForwarding(session) {
@@ -7557,28 +7604,11 @@ var DelegationRouter = class {
7557
7604
  this.tasks.set(reReviewTaskId, { origin: originAgentId, depth: 1 });
7558
7605
  this.assignedTask.set(meta.reviewerAgentId, reReviewTaskId);
7559
7606
  this.totalDelegations++;
7560
- const originalContext = meta.reviewContext ? `
7561
-
7562
- Your previous review (for reference):
7607
+ const issueChecklist = meta.reviewContext ? `
7608
+ Issues to verify (from your previous review):
7563
7609
  ${meta.reviewContext}` : "";
7564
- const reReviewPrompt = this.promptEngine.render("worker-continue", {
7565
- prompt: `[Re-review after fix] ${fromName} has fixed the issues you reported. Please review the code again.
7566
-
7567
- Dev's fix report:
7568
- ${summary.slice(0, CONFIG.limits.chatMessageChars)}${originalContext}
7569
-
7570
- ===== YOUR TASK =====
7571
- 1. Check if ALL previously reported ISSUES are resolved
7572
- 2. Verify the deliverable runs without crashes
7573
- 3. Verify core features work (compare against the original task requirements)
7574
-
7575
- VERDICT: PASS | FAIL
7576
- - PASS = code runs without crashes AND core features are implemented (even if rough)
7577
- - FAIL = crashes/bugs that prevent usage OR core features are missing/broken
7578
- ISSUES: (numbered list if FAIL \u2014 only real bugs or missing core features)
7579
- SUMMARY: (one sentence overall assessment)`
7580
- });
7581
- const repoPath = this.teamProjectDir ?? void 0;
7610
+ const reReviewPrompt = `[Re-review after fix] ${fromName} reports fixing the issues. Read the code and verify each fix is correct.${issueChecklist}`;
7611
+ const repoPath = this.resolveDevWorktreePath(this.teamProjectDir ?? void 0);
7582
7612
  console.log(`[DirectFix] Dev ${fromName} fix complete \u2192 auto re-review by ${reviewerSession.name}`);
7583
7613
  this.emitEvent({
7584
7614
  type: "task:delegated",
@@ -7646,34 +7676,36 @@ SUMMARY: (one sentence overall assessment)`
7646
7676
  this.reviewCount++;
7647
7677
  this.devFixAttempts.set(devAgentId, attempts + 1);
7648
7678
  this.totalDelegations++;
7679
+ const feedback = parseReviewerFeedback(output);
7649
7680
  const fixTaskId = nanoid2();
7650
7681
  this.tasks.set(fixTaskId, {
7651
7682
  origin: originAgentId,
7652
7683
  depth: 1,
7653
7684
  isDirectFix: true,
7654
7685
  reviewerAgentId,
7655
- reviewContext: output.slice(0, 1e3)
7686
+ // Carry structured feedback as reviewContext for re-review resilience
7687
+ reviewContext: feedback.formatted
7656
7688
  });
7657
7689
  this.assignedTask.set(devAgentId, fixTaskId);
7658
7690
  const reviewerName = reviewerSession?.name ?? "Code Reviewer";
7659
7691
  const fixPrompt = this.promptEngine.render("worker-direct-fix", {
7660
7692
  reviewerName,
7661
- reviewFeedback: output.slice(0, 800)
7693
+ reviewFeedback: feedback.formatted
7662
7694
  });
7663
7695
  const repoPath = this.teamProjectDir ?? void 0;
7664
- console.log(`[DirectFix] ${reviewerName} FAIL \u2192 ${devSession.name} (attempt ${attempts + 1}/${CONFIG.delegation.maxDirectFixes}, skipping leader)`);
7696
+ console.log(`[DirectFix] ${reviewerName} FAIL \u2192 ${devSession.name} (attempt ${attempts + 1}/${CONFIG.delegation.maxDirectFixes}, ${feedback.issues.length} issues, skipping leader)`);
7665
7697
  this.emitEvent({
7666
7698
  type: "task:delegated",
7667
7699
  fromAgentId: reviewerAgentId,
7668
7700
  toAgentId: devAgentId,
7669
7701
  taskId: fixTaskId,
7670
- prompt: `Fix issues from ${reviewerName}'s review`
7702
+ prompt: `Fix ${feedback.issues.length} issues from ${reviewerName}'s review`
7671
7703
  });
7672
7704
  this.emitEvent({
7673
7705
  type: "team:chat",
7674
7706
  fromAgentId: reviewerAgentId,
7675
7707
  toAgentId: devAgentId,
7676
- message: `Direct fix: ${output.slice(0, CONFIG.limits.chatMessageChars)}`,
7708
+ message: `Direct fix: ${feedback.formatted.slice(0, CONFIG.limits.chatMessageChars)}`,
7677
7709
  messageType: "delegation",
7678
7710
  taskId: fixTaskId,
7679
7711
  timestamp: Date.now()
@@ -7708,6 +7740,21 @@ SUMMARY: (one sentence overall assessment)`
7708
7740
  Your teammates (for context \u2014 do NOT delegate or coordinate with them):
7709
7741
  ${lines.join("\n")}`;
7710
7742
  }
7743
+ /**
7744
+ * Resolve the developer's worktree path for reviewer CWD.
7745
+ * Reviewers don't get their own worktree, but they need to run inside the
7746
+ * developer's worktree to see the actual code changes (git diff, file reads).
7747
+ * Falls back to the provided repoPath if no dev worktree is available.
7748
+ */
7749
+ resolveDevWorktreePath(fallback) {
7750
+ if (this.lastDevAgentId) {
7751
+ const devSession = this.agentManager.get(this.lastDevAgentId);
7752
+ if (devSession?.worktreePath) {
7753
+ return devSession.worktreePath;
7754
+ }
7755
+ }
7756
+ return fallback;
7757
+ }
7711
7758
  /**
7712
7759
  * Queue a result for batched forwarding to the origin agent.
7713
7760
  * Flush only when ALL delegated tasks from this origin have returned.
@@ -7815,35 +7862,26 @@ ${resultLines2}`,
7815
7862
  // ../../packages/orchestrator/src/prompt-templates.ts
7816
7863
  import { readFileSync as readFileSync5, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, existsSync as existsSync7 } from "fs";
7817
7864
  import path7 from "path";
7818
- var DELIVERABLE_RULES = [
7819
- "**System constraints:**",
7820
- "- NEVER run long-running commands (npm run dev, npm start, npx vite, live-server, etc). They hang forever. The system serves previews automatically.",
7821
- "- Do NOT launch GUI apps or dev servers. You CANNOT see UI.",
7822
- "- For web servers, your app MUST read port from the PORT env variable (e.g. process.env.PORT || 3000).",
7823
- "",
7824
- "**Deliverable report format** (ONLY use when you created or modified files \u2014 for plain conversation, reply normally in text):",
7825
- "",
7826
- "```",
7827
- "STATUS: done | failed",
7828
- "FILES_CHANGED: (one per line)",
7829
- "ENTRY_FILE: (relative path for static web, e.g. index.html \u2014 NEVER absolute path)",
7830
- "PREVIEW_CMD: (for server/CLI apps)",
7831
- "PREVIEW_PORT: (for web servers)",
7832
- "SUMMARY: (one sentence)",
7833
- "```"
7834
- ].join("\n");
7835
- var DELIVERABLE_RULES_FIX = [
7836
- "Report your result (ONLY if you modified files):",
7837
- "",
7838
- "```",
7839
- "STATUS: done | failed",
7840
- "FILES_CHANGED: (list all files modified)",
7841
- "ENTRY_FILE: (relative path, if applicable \u2014 NEVER absolute path)",
7842
- "PREVIEW_CMD: (if applicable)",
7843
- "PREVIEW_PORT: (if applicable)",
7844
- "SUMMARY: (one sentence: what you fixed)",
7845
- "```"
7846
- ].join("\n");
7865
+ var REPORT_FORMAT = `\`\`\`
7866
+ STATUS: done | failed
7867
+ FILES_CHANGED: (one per line)
7868
+ ENTRY_FILE: (relative path, e.g. index.html \u2014 NEVER absolute)
7869
+ PREVIEW_CMD: (for server/CLI apps)
7870
+ PREVIEW_PORT: (for web servers)
7871
+ SUMMARY: (one sentence, in English)
7872
+ \`\`\``;
7873
+ var DELIVERABLE_RULES = `**System constraints:**
7874
+ - NEVER run long-running commands (npm run dev, npm start, npx vite, etc). They hang forever. The system serves previews automatically.
7875
+ - Do NOT launch GUI apps or dev servers. You CANNOT see UI.
7876
+ - For web servers, your app MUST read port from the PORT env variable (e.g. process.env.PORT || 3000).
7877
+
7878
+ **Report format** (ONLY when you created or modified files \u2014 for plain conversation, reply normally):
7879
+
7880
+ ${REPORT_FORMAT}`;
7881
+ var DELIVERABLE_RULES_FIX = `Report your result (ONLY if you modified files):
7882
+
7883
+ ${REPORT_FORMAT}`;
7884
+ var DEFAULT_SOUL = `Solve correctly, verify before declaring done, surface failures explicitly.`;
7847
7885
  var PROMPT_DEFAULTS = {
7848
7886
  "leader-initial": `You are {{name}}, the Team Lead. {{personality}}
7849
7887
  You CANNOT write code, run commands, or use any tools. You can ONLY delegate.
@@ -7851,32 +7889,13 @@ You CANNOT write code, run commands, or use any tools. You can ONLY delegate.
7851
7889
  Team:
7852
7890
  {{teamRoster}}
7853
7891
 
7854
- Delegate using this exact format (one per line):
7855
- @AgentName: task description
7856
-
7857
- The system has already created a dedicated project directory for this team. All agents will automatically work there \u2014 do NOT specify directory paths in delegations.
7858
-
7859
- ===== DELEGATION RULES =====
7860
-
7861
- CRITICAL \u2014 How to assign work to developers:
7862
- - Give each developer ONE complete, end-to-end task that produces a RUNNABLE deliverable.
7863
- - The developer is responsible for EVERYTHING: project setup, dependencies, all source files, build configuration, and verification.
7864
- - NEVER split a project into module-level sub-tasks (e.g. "create AudioManager.ts", "create GameScene.ts"). That produces disconnected files with no project skeleton.
7865
- - CORRECT example: "@Leo: Build a complete arcade game with PixiJS. Set up the project (package.json, entry HTML, config), implement gameplay (player movement, enemies, scoring, game states), add audio (SFX + BGM with mute toggle), and build a working deliverable. Output ENTRY_FILE when done."
7866
- - WRONG example: "@Leo: Create src/audio/AudioManager.ts" then "@Leo: Create src/game/GameScene.ts" \u2014 this produces isolated modules that can't run.
7867
- - If you have multiple developers, split by FEATURE AREA (each producing a runnable piece), not by FILE.
7892
+ Delegate using: @AgentName: task description
7893
+ The project directory is managed by the system \u2014 do NOT specify paths.
7868
7894
 
7869
- ===== EXECUTION PHASES =====
7895
+ Each developer gets ONE complete, end-to-end task that produces a RUNNABLE deliverable. Split by feature area, not by file.
7870
7896
 
7871
- 1. BUILD (this round): Assign developers now. Each dev must deliver a working, verifiable result.
7872
- 2. REVIEW: When dev results come back, assign Code Reviewer to check the code.
7873
- 3. FIX (if needed): If Reviewer reports VERDICT=FAIL, collect ISSUES and delegate a fix to the developer. Remind dev to rebuild/re-verify. After fix, assign Reviewer again. Up to 3 review cycles.
7874
- 4. REPORT: When Reviewer reports VERDICT=PASS (or after 3 cycles), output FINAL SUMMARY with preview info. Copy the developer's preview fields (ENTRY_FILE, PREVIEW_CMD, PREVIEW_PORT) exactly as reported \u2014 only include fields the dev actually provided.
7875
-
7876
- Rules:
7877
- - Never write code yourself. Only delegate.
7878
- - Phase 1 (this round): Assign developers ONLY. Do NOT assign Code Reviewer yet \u2014 there is no code to review.
7879
- - Skip review for trivial changes (config, typo, rename).
7897
+ Phases: BUILD (assign devs now) \u2192 REVIEW (assign reviewer after dev delivers) \u2192 FIX if needed (up to 3 cycles) \u2192 FINAL SUMMARY with preview fields.
7898
+ This round: assign developers ONLY. Skip review for trivial changes.
7880
7899
 
7881
7900
  Approved plan:
7882
7901
  {{originalTask}}
@@ -7892,11 +7911,7 @@ Team status:
7892
7911
 
7893
7912
  Delegate using: @AgentName: task description
7894
7913
 
7895
- ===== RULES =====
7896
- - ONE task at a time. Delegate to the developer FIRST. Wait for their result before assigning Code Reviewer.
7897
- - Do NOT assign Code Reviewer and Developer simultaneously \u2014 there is nothing to review until the dev is done.
7898
- - Keep fixes MINIMAL. If the user reports a bug, fix THAT bug only. Do NOT add new features, tests, or process changes in the same round.
7899
- - Do NOT redefine the reviewer's methodology or add new review requirements \u2014 just ask them to review the code.
7914
+ CRITICAL: Only ONE delegation per response. Delegate to developer FIRST. Do NOT assign reviewer until dev reports back. Never delegate to dev and reviewer in the same message.
7900
7915
 
7901
7916
  {{prompt}}`,
7902
7917
  "leader-result": `You are the Team Lead. You CANNOT write or fix code. You can ONLY delegate using @Name: <task>.
@@ -7911,52 +7926,31 @@ Team status:
7911
7926
  New result from {{fromName}} ({{resultStatus}}):
7912
7927
  {{resultSummary}}
7913
7928
 
7914
- ===== DECISION FLOW =====
7915
-
7916
- Check WHO sent this result, then follow the matching branch:
7917
-
7918
- \u2500\u2500 RESULT FROM A DEVELOPER \u2500\u2500
7919
- If STATUS=done:
7920
- \u2192 Assign Code Reviewer to check the code. In your delegation, include:
7921
- 1. Dev's ENTRY_FILE/PREVIEW_CMD so reviewer knows what was built.
7922
- 2. The KEY FEATURES from the approved plan (3-5 bullet points) so reviewer can verify feature completeness.
7923
- \u2192 Exception: skip review for trivial changes (config, typo, rename) \u2014 go straight to FINAL SUMMARY.
7924
- If STATUS=failed:
7925
- \u2192 Delegate ONE targeted fix to the same developer. Be specific about what failed.
7926
-
7927
- \u2500\u2500 RESULT FROM CODE REVIEWER \u2500\u2500
7928
- Reviewer output format: VERDICT (PASS/FAIL), ISSUES (numbered list), SUGGESTIONS (optional).
7929
- If VERDICT=PASS:
7930
- \u2192 Output FINAL SUMMARY. Copy ENTRY_FILE/PREVIEW fields from the developer's last report. You are DONE.
7931
- If VERDICT=FAIL:
7932
- \u2192 Collect ALL issues into ONE fix delegation to the original developer.
7933
- \u2192 Quote each issue verbatim. Remind dev: after fixing, rebuild and verify the deliverable works.
7934
- \u2192 After dev returns with the fix, assign Code Reviewer again to re-check.
7935
-
7936
- \u2500\u2500 SPECIAL CASES \u2500\u2500
7937
- \u2022 If roundInfo says "REVIEW LIMIT REACHED" or "BUDGET REACHED" \u2192 Output FINAL SUMMARY immediately. Accept the work as-is.
7938
- \u2022 Permanent blocker (auth error, missing API key, service down) \u2192 report to the user, do not retry.
7939
- \u2022 Same error repeated twice \u2192 STOP and report to the user.
7929
+ CRITICAL: Only ONE delegation per response. Never delegate to multiple agents at once.
7930
+
7931
+ Next step (pick exactly ONE):
7932
+ - Dev done \u2192 assign reviewer ONLY (include ENTRY_FILE + key features)
7933
+ - Dev failed \u2192 delegate fix to same dev ONLY
7934
+ - Reviewer PASS \u2192 output FINAL SUMMARY (no delegation)
7935
+ - Reviewer FAIL \u2192 delegate fix to dev ONLY, reviewer will be assigned AFTER dev reports back
7936
+ - LIMIT/BUDGET REACHED \u2192 output FINAL SUMMARY
7937
+ - Permanent blocker or same error twice \u2192 report to user, stop
7940
7938
 
7941
7939
  ===== DEVELOPER'S LAST KNOWN PREVIEW FIELDS =====
7942
7940
  {{devPreview}}
7943
7941
 
7944
7942
  ===== FINAL SUMMARY FORMAT =====
7945
- (Copy preview fields from DEVELOPER'S LAST KNOWN PREVIEW FIELDS above. Do NOT invent values.)
7946
-
7947
- ENTRY_FILE: <copy from above if available, otherwise OMIT>
7948
- PREVIEW_CMD: <copy from above if available, otherwise OMIT. NEVER use "npm run dev" or "npm start"!>
7949
- PREVIEW_PORT: <copy from above if available, otherwise OMIT>
7950
- SUMMARY: <2-3 sentence description of what was built>
7951
-
7952
- RULES:
7953
- - VERDICT=PASS means done, even if SUGGESTIONS exist. Suggestions are non-blocking.
7954
- - VERDICT=FAIL means real bugs \u2014 always delegate a fix before finalizing.
7955
- - In every fix delegation, remind dev to rebuild and re-test before reporting.
7956
- - You MUST include ENTRY_FILE or PREVIEW_CMD in your FINAL SUMMARY \u2014 the user needs this to preview.
7957
- - Do NOT include PROJECT_DIR \u2014 the system manages project directories automatically.`,
7943
+ (Copy from developer's preview fields above. Do NOT invent values.)
7944
+
7945
+ ENTRY_FILE: <if available>
7946
+ PREVIEW_CMD: <if available \u2014 NEVER "npm run dev" or "npm start">
7947
+ PREVIEW_PORT: <if available>
7948
+ SUMMARY: <2-3 sentences>
7949
+
7950
+ VERDICT=PASS with SUGGESTIONS \u2192 done. SUGGESTIONS are non-blocking.
7951
+ You MUST include ENTRY_FILE or PREVIEW_CMD \u2014 the user needs this to preview.`,
7958
7952
  "worker-initial": `Your name is {{name}}, your role is {{role}}. {{personality}}
7959
- {{soloHint}}
7953
+ {{soul}}
7960
7954
  {{memory}}
7961
7955
  {{recoveryContext}}
7962
7956
  {{teamRoster}}
@@ -7965,47 +7959,69 @@ ${DELIVERABLE_RULES}
7965
7959
 
7966
7960
  {{prompt}}`,
7967
7961
  "worker-reviewer-initial": `Your name is {{name}}, your role is {{role}}. {{personality}}
7962
+ {{soul}}
7968
7963
  {{teamRoster}}
7969
7964
 
7970
- SYSTEM CONSTRAINTS:
7971
- - NEVER run servers or dev commands. You CANNOT see UI.
7965
+ NEVER run servers or dev commands. You CANNOT see UI.
7966
+
7967
+ Output your review in markdown. Use this exact structure:
7968
+
7969
+ **VERDICT:** PASS or FAIL
7972
7970
 
7973
- REVIEW FOCUS:
7974
- 1. Verify files exist \u2014 check ENTRY_FILE is real and references valid scripts/styles.
7975
- 2. Read the code for crashes, broken logic, missing files, syntax errors.
7976
- 3. Check feature completeness against the task requirements.
7971
+ **ISSUES:**
7972
+ 1. what is wrong \u2014 where (file/function)
7973
+ 2. ...
7977
7974
 
7978
- Report your verdict in this exact format (the system parses it):
7979
- VERDICT: PASS | FAIL
7980
- - PASS = runs without crashes AND core features implemented
7981
- - FAIL = crashes/bugs prevent usage OR core features missing
7982
- ISSUES: (numbered list)
7983
- SUGGESTIONS: (optional, brief)
7984
- SUMMARY: (one sentence)
7975
+ **SUGGESTIONS:**
7976
+ 1. optional improvement idea
7977
+ 2. ...
7978
+
7979
+ **SUMMARY:** one sentence overall assessment
7980
+
7981
+ Rules:
7982
+ - PASS = runs without crashes AND core features work. FAIL = crashes/bugs or core features missing.
7983
+ - Max 5 issues, max 3 suggestions. Omit sections if empty.
7984
+ - ALWAYS use numbered list (1. 2. 3.) for issues and suggestions, even if there is only one item.
7985
+ - No source code. No fix instructions. Just state what is wrong and where.
7986
+ - Keep total output under 30 lines.
7985
7987
 
7986
7988
  {{prompt}}`,
7987
7989
  "worker-subagent-reviewer-initial": `Your name is {{name}}. {{personality}}
7990
+ {{soul}}
7988
7991
  {{memory}}
7989
7992
  {{teamRoster}}
7990
7993
 
7991
- After reviewing, output your verdict in this exact format (the system parses it):
7992
- VERDICT: PASS | FAIL
7993
- - PASS = runs without crashes AND core features implemented
7994
- - FAIL = crashes/bugs prevent usage OR core features missing
7995
- ISSUES: (numbered list)
7996
- SUGGESTIONS: (optional, brief)
7997
- SUMMARY: (one sentence)
7994
+ Output your review in markdown. Use this exact structure:
7995
+
7996
+ **VERDICT:** PASS or FAIL
7997
+
7998
+ **ISSUES:**
7999
+ 1. what is wrong \u2014 where (file/function)
8000
+ 2. ...
8001
+
8002
+ **SUGGESTIONS:**
8003
+ 1. optional improvement idea
8004
+ 2. ...
8005
+
8006
+ **SUMMARY:** one sentence overall assessment
8007
+
8008
+ Rules:
8009
+ - PASS = runs without crashes AND core features work. FAIL = crashes/bugs or core features missing.
8010
+ - Max 5 issues, max 3 suggestions. Omit sections if empty.
8011
+ - ALWAYS use numbered list (1. 2. 3.) for issues and suggestions, even if there is only one item.
8012
+ - No source code. No fix instructions. Just state what is wrong and where.
8013
+ - Keep total output under 30 lines.
7998
8014
 
7999
8015
  {{prompt}}`,
8000
8016
  "worker-subagent-initial": `Your name is {{name}}. {{personality}}
8001
- {{soloHint}}
8017
+ {{soul}}
8002
8018
  {{memory}}
8003
8019
  {{teamRoster}}
8004
8020
  {{recoveryContext}}
8005
8021
 
8006
8022
  {{prompt}}`,
8007
8023
  "worker-subagent-dev-initial": `Your name is {{name}}. {{personality}}
8008
- {{soloHint}}
8024
+ {{soul}}
8009
8025
  {{memory}}
8010
8026
  {{teamRoster}}
8011
8027
  {{recoveryContext}}
@@ -8014,7 +8030,7 @@ ${DELIVERABLE_RULES}
8014
8030
 
8015
8031
  {{prompt}}`,
8016
8032
  "worker-continue": `[Context reminder] You are {{name}} ({{role}}). {{personality}}
8017
- {{soloHint}}
8033
+ {{soul}}
8018
8034
  {{memory}}
8019
8035
  {{recoveryContext}}
8020
8036
  {{teamRoster}}
@@ -8035,99 +8051,68 @@ Do NOT introduce new features. Only fix the reported issues.`,
8035
8051
  "delegation-prefix": `[Assigned by {{fromName}} ({{fromRole}})]
8036
8052
  {{prompt}}`,
8037
8053
  "delegation-hint": `To delegate a task to another agent, output on its own line: @AgentName: <task description>`,
8038
- "leader-create": `You are {{name}}, the team's Creative Director and Product Consultant. {{personality}}
8039
- You are starting a new project conversation with the user. Your dual role:
8040
- 1. CREATIVE DIRECTOR \u2014 design the product vision: theme, look & feel, user experience, what makes it unique
8041
- 2. PRODUCT CONSULTANT \u2014 turn that vision into a clear, buildable plan
8054
+ "leader-create": `You are {{name}}, the team's Creative Director. {{personality}}
8055
+
8056
+ Your job: challenge the user's framing, find the real problem behind the request, then design a bold product vision. Don't just take orders \u2014 push back, reframe, and propose something better than what was asked for.
8042
8057
 
8043
8058
  Rules:
8044
- - Be conversational, warm, and concise.
8045
- - Ask at most 1-2 clarifying questions, then produce a plan. Do NOT over-question.
8046
- - If the user gives a clear idea (even brief), that is ENOUGH \u2014 use your CREATIVITY to fill in the vision (theme, style, characters, mood, unique twist) and produce the plan immediately. Be bold and inventive: propose a surprising concept, an unexpected angle, or a distinctive theme that the user wouldn't think of on their own.
8059
+ - If the idea is clear enough, produce the plan immediately. Be bold \u2014 propose a surprising concept or unexpected angle.
8060
+ - Ask at most 1-2 questions, then produce a plan. Do NOT over-question.
8047
8061
  - The goal is a WORKING PROTOTYPE, not a production system.
8048
- - When ready, produce a project plan wrapped in [PLAN]...[/PLAN] tags.
8049
-
8050
- ===== PLAN FORMAT (strict \u2014 follow this structure) =====
8062
+ - Describe WHAT the product does and WHO it's for \u2014 NOT how to code it.
8063
+ - When ready, output the plan in [PLAN]...[/PLAN] tags.
8051
8064
 
8052
8065
  [PLAN]
8053
- CONCEPT: Short Name \u2014 one sentence describing what this product is and who it's for (e.g. "Shadow Dash \u2014 a fast-paced rooftop runner for casual gamers")
8066
+ CONCEPT: Short Name \u2014 one sentence (what it is + who it's for)
8054
8067
 
8055
8068
  CREATIVE VISION:
8056
- - Theme & setting (e.g. "pixel cityscape at night", "cozy forest caf\xE9")
8057
- - Visual style (e.g. "retro pixel art", "flat minimalist", "hand-drawn sketch")
8058
- - Core experience \u2014 what does the user SEE and FEEL when using it?
8069
+ - Theme & setting
8070
+ - Visual style
8071
+ - Core experience \u2014 what the user SEES and FEELS
8059
8072
 
8060
8073
  FEATURES:
8061
- - (3-5 bullet points describing WHAT the product does from the user's perspective)
8062
- - (focus on interactions, content, and behavior \u2014 NOT technical implementation)
8074
+ - (3-5 bullet points, user perspective, not technical)
8063
8075
 
8064
- TECH: (one line \u2014 e.g. "Vanilla JS + Canvas" or "React + Tailwind")
8076
+ TECH: (one line)
8065
8077
 
8066
8078
  ASSIGNMENTS:
8067
- - @DevName: (one-sentence summary of what they build)
8079
+ - @DevName: (what they build)
8068
8080
  [/PLAN]
8069
8081
 
8070
- ===== ANTI-PATTERNS (never do these) =====
8071
- - Do NOT write technical implementation steps (e.g. "implement game loop with requestAnimationFrame") \u2014 that is the developer's job.
8072
- - Do NOT list generic engineering tasks (e.g. "add collision detection", "implement scoring system") \u2014 describe WHAT the product does, not HOW to code it.
8073
- - Do NOT produce a checklist of modules or files. The plan is a PRODUCT DESCRIPTION, not a technical spec.
8074
- - Do NOT include milestones, risk analysis, acceptance criteria, or deployment plans.
8075
- - Do NOT delegate. Do NOT write code. Do NOT use @AgentName: syntax outside [PLAN] tags.
8076
-
8077
8082
  If the user hasn't described their project yet, greet them and ask what they'd like to build.
8078
8083
  {{memory}}
8079
8084
  Team:
8080
8085
  {{teamRoster}}
8081
8086
 
8082
8087
  {{prompt}}`,
8083
- "leader-create-continue": `You are {{name}}, the team's Creative Director and Product Consultant. {{personality}}
8084
- Do NOT greet or re-introduce yourself \u2014 the conversation is already underway.
8088
+ "leader-create-continue": `You are {{name}}, the team's Creative Director. {{personality}}
8089
+ Do NOT greet or re-introduce yourself.
8085
8090
 
8086
8091
  The user replied: {{prompt}}
8087
8092
 
8088
- IMPORTANT: If the user is pushing you to move forward (e.g. "just do it", "make a plan", "you decide", "any is fine", "up to you"), STOP asking questions and use your CREATIVITY to fill in the vision \u2014 pick a theme, style, unique twist \u2014 and immediately produce a project plan in [PLAN]...[/PLAN] tags.
8093
+ If the user wants to move forward ("just do it", "you decide", "any is fine"), STOP asking and produce the plan in [PLAN]...[/PLAN] tags. Use your creativity to fill in the vision. Otherwise, ask at most ONE more question, then produce the plan.`,
8094
+ "leader-design": `You are {{name}}, refining the project vision. {{personality}}
8089
8095
 
8090
- Remember: You are the Creative Director. The plan must describe the PRODUCT VISION (concept, creative vision, features from user's perspective), NOT technical implementation steps. Keep it short, actionable, no milestones or risk analysis. Otherwise, ask at most ONE more question, then produce the plan. Do NOT delegate or write code.`,
8091
- "leader-design": `You are {{name}}, the team's Creative Director, refining the project vision with the user. {{personality}}
8092
- The user has given feedback on your plan. Your job is to REVISE the existing plan, not start over.
8096
+ Apply the user's feedback to the existing plan. Only change what they mentioned \u2014 keep everything else intact.
8093
8097
 
8094
- ===== CRITICAL: INCREMENTAL UPDATE =====
8095
- - User feedback is usually a PARTIAL adjustment (e.g. "use PixiJS", "make it darker", "add multiplayer").
8096
- - Apply the feedback to the EXISTING plan. Keep everything the user did NOT mention.
8097
- - NEVER discard the original concept, story, characters, or gameplay just because the user asked for a tech or style change.
8098
- - If the user says "use X engine" or "change to Y framework" \u2192 update ONLY the TECH line and any affected details. The product vision stays.
8099
- - Think of it as editing a document, not writing a new one.
8100
-
8101
- Rules:
8102
- - Address the user's feedback directly and show what changed.
8103
- - Always output the updated plan in [PLAN]...[/PLAN] tags using the standard format: CONCEPT, CREATIVE VISION, FEATURES, TECH, ASSIGNMENTS.
8104
- - The plan describes the PRODUCT VISION \u2014 what users see, feel, and experience. NOT technical implementation steps.
8105
- - Keep it prototype-focused. No milestones, risk analysis, or deployment plans.
8106
- - Do NOT delegate. Do NOT write code. Do NOT use @AgentName: syntax outside [PLAN] tags.
8098
+ Output the revised plan in [PLAN]...[/PLAN] tags (CONCEPT, CREATIVE VISION, FEATURES, TECH, ASSIGNMENTS). Do NOT delegate or write code.
8107
8099
 
8108
8100
  Team:
8109
8101
  {{teamRoster}}
8110
8102
 
8111
- Previous plan context: {{originalTask}}
8103
+ Previous plan: {{originalTask}}
8112
8104
 
8113
8105
  User feedback: {{prompt}}`,
8114
- "leader-design-continue": `You are {{name}}, the team's Creative Director, refining the project vision. {{personality}}
8106
+ "leader-design-continue": `You are {{name}}, refining the project vision. {{personality}}
8115
8107
 
8116
- Your current plan:
8108
+ Current plan:
8117
8109
  {{originalTask}}
8118
8110
 
8119
8111
  The user replied: {{prompt}}
8120
8112
 
8121
- IMPORTANT: This is an INCREMENTAL update. Apply the user's feedback to the plan above \u2014 do NOT discard the original concept. If the user only mentions one aspect (tech, style, feature), change ONLY that part and keep everything else intact.
8122
-
8123
- Output the revised plan in the standard format: CONCEPT, CREATIVE VISION, FEATURES, TECH, ASSIGNMENTS. Describe the product vision, NOT technical steps. Always output in [PLAN]...[/PLAN] tags. Do NOT delegate or write code.`,
8113
+ Incremental update \u2014 only change what the user mentioned. Output in [PLAN]...[/PLAN] tags. Do NOT delegate or write code.`,
8124
8114
  "leader-complete": `You are {{name}}, presenting completed work to the user. {{personality}}
8125
- The team has finished executing the project. Summarize what was accomplished and ask if the user wants any changes.
8126
-
8127
- Rules:
8128
- - Be concise and highlight key outcomes.
8129
- - If the user provides feedback, note it \u2014 the system will transition back to execute phase.
8130
- - Do NOT delegate. Do NOT write code. Do NOT use @AgentName: syntax.
8115
+ The team has finished. Summarize what was accomplished and ask if the user wants changes.
8131
8116
 
8132
8117
  Team:
8133
8118
  {{teamRoster}}
@@ -8208,7 +8193,8 @@ var PromptEngine = class {
8208
8193
  console.warn(`[Prompts] Unknown template: ${templateName}`);
8209
8194
  return vars["prompt"] ?? "";
8210
8195
  }
8211
- return template.replace(/\{\{(\w+)\}\}/g, (_, key) => vars[key] ?? "");
8196
+ const mergedVars = { soul: DEFAULT_SOUL, ...vars };
8197
+ return template.replace(/\{\{(\w+)\}\}/g, (_, key) => mergedVars[key] ?? "");
8212
8198
  }
8213
8199
  };
8214
8200
 
@@ -8606,6 +8592,7 @@ var Orchestrator = class extends EventEmitter {
8606
8592
  workspace: opts.workDir ?? this.workspace,
8607
8593
  resumeHistory: opts.resumeHistory,
8608
8594
  backend,
8595
+ model: opts.model,
8609
8596
  sandboxMode: this.sandboxMode,
8610
8597
  isTeamLead: this.agentManager.isTeamLead(opts.agentId),
8611
8598
  teamId: opts.teamId,
@@ -8905,6 +8892,7 @@ ${lines.join("\n")}`;
8905
8892
  palette: s.palette,
8906
8893
  personality: s.personality,
8907
8894
  backend: s.backend.id,
8895
+ model: s.model,
8908
8896
  pid: s.pid,
8909
8897
  isTeamLead: this.agentManager.isTeamLead(s.agentId),
8910
8898
  teamId: s.teamId,
@@ -9658,6 +9646,44 @@ var PreviewServer = class {
9658
9646
  };
9659
9647
  var previewServer = new PreviewServer();
9660
9648
 
9649
+ // ../../packages/orchestrator/src/agent-defs.ts
9650
+ import { existsSync as existsSync10, mkdirSync as mkdirSync7, readdirSync as readdirSync2, readFileSync as readFileSync7, writeFileSync as writeFileSync7 } from "fs";
9651
+ import { resolve as resolve2, dirname as dirname2 } from "path";
9652
+ import { fileURLToPath as fileURLToPath2 } from "url";
9653
+ import { homedir as homedir6 } from "os";
9654
+ var __dirname2 = dirname2(fileURLToPath2(import.meta.url));
9655
+ function getBundledAgentsDir() {
9656
+ const fromDist = resolve2(__dirname2, "../agents");
9657
+ if (existsSync10(fromDist)) return fromDist;
9658
+ const fromSrc = resolve2(__dirname2, "../agents");
9659
+ return fromSrc;
9660
+ }
9661
+ function syncAgentDefs() {
9662
+ const bundledDir = getBundledAgentsDir();
9663
+ if (!existsSync10(bundledDir)) {
9664
+ console.log(`[Agents] No bundled agents directory found at ${bundledDir}`);
9665
+ return;
9666
+ }
9667
+ const targetDir = resolve2(homedir6(), ".claude", "agents");
9668
+ if (!existsSync10(targetDir)) {
9669
+ mkdirSync7(targetDir, { recursive: true });
9670
+ }
9671
+ const files = readdirSync2(bundledDir).filter((f) => f.endsWith(".md"));
9672
+ let synced = 0;
9673
+ for (const file of files) {
9674
+ const src = resolve2(bundledDir, file);
9675
+ const dst = resolve2(targetDir, file);
9676
+ try {
9677
+ const content = readFileSync7(src, "utf-8");
9678
+ writeFileSync7(dst, content, "utf-8");
9679
+ synced++;
9680
+ } catch (e) {
9681
+ console.warn(`[Agents] Failed to sync ${file}: ${e}`);
9682
+ }
9683
+ }
9684
+ console.log(`[Agents] Synced ${synced} agent definitions to ${targetDir}`);
9685
+ }
9686
+
9661
9687
  // ../../packages/orchestrator/src/index.ts
9662
9688
  function createOrchestrator(options) {
9663
9689
  return new Orchestrator(options);
@@ -9666,12 +9692,12 @@ function createOrchestrator(options) {
9666
9692
  // src/ws-server.ts
9667
9693
  import { networkInterfaces } from "os";
9668
9694
  import { readFile, stat } from "fs/promises";
9669
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync8, existsSync as existsSync11, mkdirSync as mkdirSync8 } from "fs";
9670
- import { join, extname, resolve as resolve2 } from "path";
9695
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync9, existsSync as existsSync12, mkdirSync as mkdirSync9 } from "fs";
9696
+ import { join, extname, resolve as resolve3 } from "path";
9671
9697
  import * as Ably from "ably";
9672
9698
 
9673
9699
  // src/runtime-state.ts
9674
- import { existsSync as existsSync10, mkdirSync as mkdirSync7, readdirSync as readdirSync2, readFileSync as readFileSync7, renameSync as renameSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync7 } from "fs";
9700
+ import { existsSync as existsSync11, mkdirSync as mkdirSync8, readdirSync as readdirSync3, readFileSync as readFileSync8, renameSync as renameSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync8 } from "fs";
9675
9701
  import { execSync as execSync5 } from "child_process";
9676
9702
  import path10 from "path";
9677
9703
  var RUNTIME_FILE = path10.join(config.instanceDir, "runtime.json");
@@ -9685,9 +9711,9 @@ function portLockPath(port) {
9685
9711
  }
9686
9712
  function killPortLockHolder(port) {
9687
9713
  const lockFile = portLockPath(port);
9688
- if (!existsSync10(lockFile)) return;
9714
+ if (!existsSync11(lockFile)) return;
9689
9715
  try {
9690
- const pid = parseInt(readFileSync7(lockFile, "utf-8").trim(), 10);
9716
+ const pid = parseInt(readFileSync8(lockFile, "utf-8").trim(), 10);
9691
9717
  if (!pid || pid === process.pid) return;
9692
9718
  try {
9693
9719
  process.kill(pid, 0);
@@ -9713,9 +9739,9 @@ function killPortLockHolder(port) {
9713
9739
  }
9714
9740
  }
9715
9741
  function writePortLock(port) {
9716
- if (!existsSync10(LOCKS_DIR)) mkdirSync7(LOCKS_DIR, { recursive: true });
9742
+ if (!existsSync11(LOCKS_DIR)) mkdirSync8(LOCKS_DIR, { recursive: true });
9717
9743
  const lockPath = portLockPath(port);
9718
- writeFileSync7(lockPath, String(process.pid), "utf-8");
9744
+ writeFileSync8(lockPath, String(process.pid), "utf-8");
9719
9745
  portLockFile = lockPath;
9720
9746
  console.log(`[Gateway] Port lock written: ${lockPath} (pid=${process.pid})`);
9721
9747
  }
@@ -9730,9 +9756,9 @@ function clearPortLock() {
9730
9756
  }
9731
9757
  function writeRuntimeFile(state) {
9732
9758
  const dir = path10.dirname(RUNTIME_FILE);
9733
- if (!existsSync10(dir)) mkdirSync7(dir, { recursive: true });
9759
+ if (!existsSync11(dir)) mkdirSync8(dir, { recursive: true });
9734
9760
  const tmp = `${RUNTIME_FILE}.tmp`;
9735
- writeFileSync7(tmp, JSON.stringify(state, null, 2), "utf-8");
9761
+ writeFileSync8(tmp, JSON.stringify(state, null, 2), "utf-8");
9736
9762
  renameSync2(tmp, RUNTIME_FILE);
9737
9763
  }
9738
9764
  function syncSleep(ms) {
@@ -9768,15 +9794,15 @@ function killPreviousInstances() {
9768
9794
  const instancesDir = path10.dirname(config.instanceDir);
9769
9795
  let dirs;
9770
9796
  try {
9771
- dirs = readdirSync2(instancesDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => path10.join(instancesDir, d.name));
9797
+ dirs = readdirSync3(instancesDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => path10.join(instancesDir, d.name));
9772
9798
  } catch {
9773
9799
  dirs = [config.instanceDir];
9774
9800
  }
9775
9801
  for (const dir of dirs) {
9776
9802
  const runtimeFile = path10.join(dir, "runtime.json");
9777
- if (!existsSync10(runtimeFile)) continue;
9803
+ if (!existsSync11(runtimeFile)) continue;
9778
9804
  try {
9779
- const prev = JSON.parse(readFileSync7(runtimeFile, "utf-8"));
9805
+ const prev = JSON.parse(readFileSync8(runtimeFile, "utf-8"));
9780
9806
  if (prev.pid === process.pid) continue;
9781
9807
  try {
9782
9808
  process.kill(prev.pid, 0);
@@ -9859,13 +9885,13 @@ var pairCode = null;
9859
9885
  var onCommand = null;
9860
9886
  var shareTokens = /* @__PURE__ */ new Map();
9861
9887
  function getSessionTokensFile() {
9862
- return resolve2(config.instanceDir, "session-tokens.json");
9888
+ return resolve3(config.instanceDir, "session-tokens.json");
9863
9889
  }
9864
9890
  function loadSessionTokens() {
9865
9891
  try {
9866
9892
  const f = getSessionTokensFile();
9867
- if (existsSync11(f)) {
9868
- const data = JSON.parse(readFileSync8(f, "utf-8"));
9893
+ if (existsSync12(f)) {
9894
+ const data = JSON.parse(readFileSync9(f, "utf-8"));
9869
9895
  return new Map(Object.entries(data));
9870
9896
  }
9871
9897
  } catch {
@@ -9873,9 +9899,9 @@ function loadSessionTokens() {
9873
9899
  return /* @__PURE__ */ new Map();
9874
9900
  }
9875
9901
  function persistSessionTokens() {
9876
- const dir = resolve2(config.instanceDir);
9877
- if (!existsSync11(dir)) mkdirSync8(dir, { recursive: true });
9878
- writeFileSync8(getSessionTokensFile(), JSON.stringify(Object.fromEntries(sessionTokens)), "utf-8");
9902
+ const dir = resolve3(config.instanceDir);
9903
+ if (!existsSync12(dir)) mkdirSync9(dir, { recursive: true });
9904
+ writeFileSync9(getSessionTokensFile(), JSON.stringify(Object.fromEntries(sessionTokens)), "utf-8");
9879
9905
  }
9880
9906
  var sessionTokens = loadSessionTokens();
9881
9907
  function addSessionToken(token, role) {
@@ -10091,9 +10117,9 @@ var wsChannel = {
10091
10117
  return;
10092
10118
  }
10093
10119
  const reqPath = decodeURIComponent((staticMatch[1] || "/").split("?")[0]);
10094
- const filePath = resolve2(root, reqPath === "/" ? entry ?? "index.html" : reqPath.slice(1));
10095
- const rootWithSep = resolve2(root) + "/";
10096
- if (filePath !== resolve2(root) && !filePath.startsWith(rootWithSep)) {
10120
+ const filePath = resolve3(root, reqPath === "/" ? entry ?? "index.html" : reqPath.slice(1));
10121
+ const rootWithSep = resolve3(root) + "/";
10122
+ if (filePath !== resolve3(root) && !filePath.startsWith(rootWithSep)) {
10097
10123
  res.writeHead(403, { "Content-Type": "text/plain" });
10098
10124
  res.end("Forbidden");
10099
10125
  return;
@@ -10329,8 +10355,8 @@ async function serveStatic(req, res) {
10329
10355
  } else {
10330
10356
  filePath = join(config.webDir, url);
10331
10357
  }
10332
- const webRoot = resolve2(config.webDir);
10333
- const resolvedPath = resolve2(filePath);
10358
+ const webRoot = resolve3(config.webDir);
10359
+ const resolvedPath = resolve3(filePath);
10334
10360
  if (resolvedPath !== webRoot && !resolvedPath.startsWith(webRoot + "/")) {
10335
10361
  res.writeHead(403, { "Content-Type": "text/plain" });
10336
10362
  res.end("Forbidden");
@@ -10734,13 +10760,13 @@ import { createInterface } from "readline";
10734
10760
 
10735
10761
  // src/backends.ts
10736
10762
  import { execSync as execSync6 } from "child_process";
10737
- import { existsSync as existsSync12, readFileSync as readFileSync9, writeFileSync as writeFileSync9, mkdirSync as mkdirSync9 } from "fs";
10738
- import { homedir as homedir7 } from "os";
10763
+ import { existsSync as existsSync13, readFileSync as readFileSync10, writeFileSync as writeFileSync10, mkdirSync as mkdirSync10 } from "fs";
10764
+ import { homedir as homedir8 } from "os";
10739
10765
  import path11 from "path";
10740
10766
  var isRoot = process.getuid?.() === 0;
10741
10767
  function ensureClaudeSettingsForRoot() {
10742
10768
  if (!isRoot) return;
10743
- const claudeDir = path11.join(homedir7(), ".claude");
10769
+ const claudeDir = path11.join(homedir8(), ".claude");
10744
10770
  const settingsPath = path11.join(claudeDir, "settings.json");
10745
10771
  const requiredAllow = [
10746
10772
  "Bash",
@@ -10757,8 +10783,8 @@ function ensureClaudeSettingsForRoot() {
10757
10783
  ];
10758
10784
  try {
10759
10785
  let settings = {};
10760
- if (existsSync12(settingsPath)) {
10761
- settings = JSON.parse(readFileSync9(settingsPath, "utf-8"));
10786
+ if (existsSync13(settingsPath)) {
10787
+ settings = JSON.parse(readFileSync10(settingsPath, "utf-8"));
10762
10788
  }
10763
10789
  settings.defaultMode = "bypassPermissions";
10764
10790
  const perms = settings.permissions ?? {};
@@ -10766,8 +10792,8 @@ function ensureClaudeSettingsForRoot() {
10766
10792
  const merged = [.../* @__PURE__ */ new Set([...existing, ...requiredAllow])];
10767
10793
  perms.allow = merged;
10768
10794
  settings.permissions = perms;
10769
- if (!existsSync12(claudeDir)) mkdirSync9(claudeDir, { recursive: true });
10770
- writeFileSync9(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
10795
+ if (!existsSync13(claudeDir)) mkdirSync10(claudeDir, { recursive: true });
10796
+ writeFileSync10(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
10771
10797
  console.log("[backends] Running as root \u2014 configured Claude Code settings.json to allow all permissions");
10772
10798
  } catch (err) {
10773
10799
  console.warn("[backends] Failed to configure Claude settings for root:", err);
@@ -10992,12 +11018,12 @@ function detectBackends() {
10992
11018
 
10993
11019
  // src/setup.ts
10994
11020
  function ask(rl, question) {
10995
- return new Promise((resolve4) => {
10996
- const onClose = () => resolve4("");
11021
+ return new Promise((resolve5) => {
11022
+ const onClose = () => resolve5("");
10997
11023
  rl.once("close", onClose);
10998
11024
  rl.question(question, (answer) => {
10999
11025
  rl.removeListener("close", onClose);
11000
- resolve4(answer.trim());
11026
+ resolve5(answer.trim());
11001
11027
  });
11002
11028
  });
11003
11029
  }
@@ -11070,7 +11096,7 @@ async function runSetup() {
11070
11096
  // src/index.ts
11071
11097
  import { nanoid as nanoid6 } from "nanoid";
11072
11098
  import { exec as exec2, execFile as execFile3, execFileSync as execFileSync2, execSync as execSync7 } from "child_process";
11073
- import { existsSync as existsSync16, mkdirSync as mkdirSync12, readFileSync as readFileSync11, readdirSync as readdirSync5, writeFileSync as writeFileSync11, unlinkSync as unlinkSync3, rmdirSync as rmdirSync2 } from "fs";
11099
+ import { existsSync as existsSync17, mkdirSync as mkdirSync13, readFileSync as readFileSync12, readdirSync as readdirSync6, writeFileSync as writeFileSync12, renameSync as renameSync5, unlinkSync as unlinkSync3, rmdirSync as rmdirSync2 } from "fs";
11074
11100
  import path14 from "path";
11075
11101
 
11076
11102
  // src/process-scanner.ts
@@ -11110,9 +11136,9 @@ function parseEtime(etime) {
11110
11136
  return now - seconds * 1e3;
11111
11137
  }
11112
11138
  function exec(cmd, args) {
11113
- return new Promise((resolve4) => {
11139
+ return new Promise((resolve5) => {
11114
11140
  execFile(cmd, args, { timeout: 5e3, maxBuffer: 1024 * 1024 * 2 }, (err, stdout) => {
11115
- resolve4(err ? "" : stdout);
11141
+ resolve5(err ? "" : stdout);
11116
11142
  });
11117
11143
  });
11118
11144
  }
@@ -11244,7 +11270,7 @@ var ProcessScanner = class _ProcessScanner {
11244
11270
  };
11245
11271
 
11246
11272
  // src/external-output-reader.ts
11247
- import { watch, readdirSync as readdirSync3, statSync, existsSync as existsSync13, openSync, readSync, closeSync } from "fs";
11273
+ import { watch, readdirSync as readdirSync4, statSync, existsSync as existsSync14, openSync, readSync, closeSync } from "fs";
11248
11274
  import { execFile as execFile2 } from "child_process";
11249
11275
  import path12 from "path";
11250
11276
  import os from "os";
@@ -11375,7 +11401,7 @@ var ExternalOutputReader = class {
11375
11401
  };
11376
11402
  const findAndWatch = () => {
11377
11403
  if (stopped) return;
11378
- if (!existsSync13(projectDir)) {
11404
+ if (!existsSync14(projectDir)) {
11379
11405
  retryCount++;
11380
11406
  if (retryCount > MAX_RETRIES) {
11381
11407
  console.log(`[OutputReader] Project dir not found after ${MAX_RETRIES} retries, giving up: ${projectDir}`);
@@ -11386,7 +11412,7 @@ var ExternalOutputReader = class {
11386
11412
  return;
11387
11413
  }
11388
11414
  try {
11389
- const files = readdirSync3(projectDir).filter((f) => f.endsWith(".jsonl")).map((f) => ({
11415
+ const files = readdirSync4(projectDir).filter((f) => f.endsWith(".jsonl")).map((f) => ({
11390
11416
  name: f,
11391
11417
  mtime: statSync(path12.join(projectDir, f)).mtimeMs
11392
11418
  })).sort((a, b) => b.mtime - a.mtime);
@@ -11408,7 +11434,7 @@ var ExternalOutputReader = class {
11408
11434
  if (stopped) return;
11409
11435
  if (filename && filename.endsWith(".jsonl")) {
11410
11436
  const fullPath = path12.join(projectDir, filename);
11411
- if (fullPath !== watchedFile && existsSync13(fullPath)) {
11437
+ if (fullPath !== watchedFile && existsSync14(fullPath)) {
11412
11438
  try {
11413
11439
  const newMtime = statSync(fullPath).mtimeMs;
11414
11440
  const curMtime = watchedFile ? statSync(watchedFile).mtimeMs : 0;
@@ -11542,8 +11568,8 @@ var ExternalOutputReader = class {
11542
11568
  };
11543
11569
 
11544
11570
  // src/file-logger.ts
11545
- import { createWriteStream, existsSync as existsSync14, mkdirSync as mkdirSync10, renameSync as renameSync3, statSync as statSync2 } from "fs";
11546
- import { resolve as resolve3 } from "path";
11571
+ import { createWriteStream, existsSync as existsSync15, mkdirSync as mkdirSync11, renameSync as renameSync3, statSync as statSync2 } from "fs";
11572
+ import { resolve as resolve4 } from "path";
11547
11573
  var MAX_SIZE = 5 * 1024 * 1024;
11548
11574
  var LOG_NAME = "gateway.log";
11549
11575
  var BACKUP_NAME = "gateway.log.1";
@@ -11574,9 +11600,9 @@ function writeLine(level, args) {
11574
11600
  if (bytesWritten > MAX_SIZE) rotate();
11575
11601
  }
11576
11602
  function installFileLogger(dir) {
11577
- if (!existsSync14(dir)) mkdirSync10(dir, { recursive: true });
11578
- logPath = resolve3(dir, LOG_NAME);
11579
- backupPath = resolve3(dir, BACKUP_NAME);
11603
+ if (!existsSync15(dir)) mkdirSync11(dir, { recursive: true });
11604
+ logPath = resolve4(dir, LOG_NAME);
11605
+ backupPath = resolve4(dir, BACKUP_NAME);
11580
11606
  try {
11581
11607
  bytesWritten = statSync2(logPath).size;
11582
11608
  } catch {
@@ -11673,7 +11699,7 @@ function isTunnelRunning() {
11673
11699
  }
11674
11700
 
11675
11701
  // src/team-state.ts
11676
- import { existsSync as existsSync15, mkdirSync as mkdirSync11, readFileSync as readFileSync10, writeFileSync as writeFileSync10, renameSync as renameSync4, appendFileSync, readdirSync as readdirSync4 } from "fs";
11702
+ import { existsSync as existsSync16, mkdirSync as mkdirSync12, readFileSync as readFileSync11, writeFileSync as writeFileSync11, renameSync as renameSync4, appendFileSync, readdirSync as readdirSync5 } from "fs";
11677
11703
  import path13 from "path";
11678
11704
  var PROJECTS_DIR = path13.join(CONFIG_DIR, "data", "project-history");
11679
11705
  function getStateFile() {
@@ -11685,8 +11711,8 @@ function getEventsFile() {
11685
11711
  var EMPTY_STATE = { agents: [], team: null };
11686
11712
  function loadTeamState() {
11687
11713
  try {
11688
- if (existsSync15(getStateFile())) {
11689
- const raw = JSON.parse(readFileSync10(getStateFile(), "utf-8"));
11714
+ if (existsSync16(getStateFile())) {
11715
+ const raw = JSON.parse(readFileSync11(getStateFile(), "utf-8"));
11690
11716
  if (raw && Array.isArray(raw.agents)) {
11691
11717
  return raw;
11692
11718
  }
@@ -11699,9 +11725,9 @@ function saveTeamState(state) {
11699
11725
  try {
11700
11726
  const file = getStateFile();
11701
11727
  const dir = path13.dirname(file);
11702
- if (!existsSync15(dir)) mkdirSync11(dir, { recursive: true });
11728
+ if (!existsSync16(dir)) mkdirSync12(dir, { recursive: true });
11703
11729
  const tmp = file + ".tmp";
11704
- writeFileSync10(tmp, JSON.stringify(state, null, 2), "utf-8");
11730
+ writeFileSync11(tmp, JSON.stringify(state, null, 2), "utf-8");
11705
11731
  renameSync4(tmp, file);
11706
11732
  } catch (e) {
11707
11733
  console.log(`[TeamState] Failed to save: ${e}`);
@@ -11722,14 +11748,14 @@ function resetProjectBuffer() {
11722
11748
  projectStartedAt = Date.now();
11723
11749
  projectName = "";
11724
11750
  try {
11725
- writeFileSync10(getEventsFile(), "", "utf-8");
11751
+ writeFileSync11(getEventsFile(), "", "utf-8");
11726
11752
  } catch {
11727
11753
  }
11728
11754
  }
11729
11755
  function loadProjectBuffer() {
11730
11756
  try {
11731
- if (!existsSync15(getEventsFile())) return;
11732
- const raw = readFileSync10(getEventsFile(), "utf-8").trim();
11757
+ if (!existsSync16(getEventsFile())) return;
11758
+ const raw = readFileSync11(getEventsFile(), "utf-8").trim();
11733
11759
  if (!raw) return;
11734
11760
  const lines = raw.split("\n");
11735
11761
  for (const line of lines) {
@@ -11757,7 +11783,7 @@ function bufferEvent(event) {
11757
11783
  projectEvents.push(stamped);
11758
11784
  try {
11759
11785
  const dir = path13.dirname(getEventsFile());
11760
- if (!existsSync15(dir)) mkdirSync11(dir, { recursive: true });
11786
+ if (!existsSync16(dir)) mkdirSync12(dir, { recursive: true });
11761
11787
  appendFileSync(getEventsFile(), JSON.stringify(stamped) + "\n", "utf-8");
11762
11788
  } catch {
11763
11789
  }
@@ -11765,10 +11791,10 @@ function bufferEvent(event) {
11765
11791
  function rewriteEventsFile() {
11766
11792
  try {
11767
11793
  const dir = path13.dirname(getEventsFile());
11768
- if (!existsSync15(dir)) mkdirSync11(dir, { recursive: true });
11794
+ if (!existsSync16(dir)) mkdirSync12(dir, { recursive: true });
11769
11795
  const header = { _header: true, startedAt: projectStartedAt, projectName };
11770
11796
  const lines = [JSON.stringify(header), ...projectEvents.map((e) => JSON.stringify(e))];
11771
- writeFileSync10(getEventsFile(), lines.join("\n") + "\n", "utf-8");
11797
+ writeFileSync11(getEventsFile(), lines.join("\n") + "\n", "utf-8");
11772
11798
  } catch {
11773
11799
  }
11774
11800
  }
@@ -11777,7 +11803,7 @@ function archiveProject(agents, team) {
11777
11803
  (e) => e.type === "TASK_DONE" || e.type === "TEAM_CHAT" || e.type === "TASK_STARTED"
11778
11804
  );
11779
11805
  if (meaningful.length === 0) return null;
11780
- if (!existsSync15(PROJECTS_DIR)) mkdirSync11(PROJECTS_DIR, { recursive: true });
11806
+ if (!existsSync16(PROJECTS_DIR)) mkdirSync12(PROJECTS_DIR, { recursive: true });
11781
11807
  let preview;
11782
11808
  for (let i = projectEvents.length - 1; i >= 0; i--) {
11783
11809
  const e = projectEvents[i];
@@ -11807,8 +11833,8 @@ function archiveProject(agents, team) {
11807
11833
  const filePath = path13.join(PROJECTS_DIR, `${id}.json`);
11808
11834
  let existingRatings;
11809
11835
  try {
11810
- if (existsSync15(filePath)) {
11811
- const existing = JSON.parse(readFileSync10(filePath, "utf-8"));
11836
+ if (existsSync16(filePath)) {
11837
+ const existing = JSON.parse(readFileSync11(filePath, "utf-8"));
11812
11838
  existingRatings = existing.ratings;
11813
11839
  }
11814
11840
  } catch {
@@ -11826,7 +11852,7 @@ function archiveProject(agents, team) {
11826
11852
  ratings: existingRatings
11827
11853
  };
11828
11854
  try {
11829
- writeFileSync10(filePath, JSON.stringify(archive), "utf-8");
11855
+ writeFileSync11(filePath, JSON.stringify(archive), "utf-8");
11830
11856
  console.log(`[TeamState] Archived project "${archive.name}" (${projectEvents.length} events) \u2192 ${filePath}`);
11831
11857
  return id;
11832
11858
  } catch (e) {
@@ -11836,13 +11862,13 @@ function archiveProject(agents, team) {
11836
11862
  }
11837
11863
  var MAX_LISTED_PROJECTS = 50;
11838
11864
  function listProjects() {
11839
- if (!existsSync15(PROJECTS_DIR)) return [];
11865
+ if (!existsSync16(PROJECTS_DIR)) return [];
11840
11866
  try {
11841
- const files = readdirSync4(PROJECTS_DIR).filter((f) => f.endsWith(".json")).sort().reverse().slice(0, MAX_LISTED_PROJECTS);
11867
+ const files = readdirSync5(PROJECTS_DIR).filter((f) => f.endsWith(".json")).sort().reverse().slice(0, MAX_LISTED_PROJECTS);
11842
11868
  const summaries = [];
11843
11869
  for (const file of files) {
11844
11870
  try {
11845
- const raw = JSON.parse(readFileSync10(path13.join(PROJECTS_DIR, file), "utf-8"));
11871
+ const raw = JSON.parse(readFileSync11(path13.join(PROJECTS_DIR, file), "utf-8"));
11846
11872
  summaries.push({
11847
11873
  id: raw.id,
11848
11874
  name: raw.name,
@@ -11868,15 +11894,15 @@ function loadProject(id) {
11868
11894
  const filePath = path13.join(PROJECTS_DIR, `${safeId}.json`);
11869
11895
  if (!path13.resolve(filePath).startsWith(path13.resolve(PROJECTS_DIR))) return null;
11870
11896
  try {
11871
- if (existsSync15(filePath)) {
11872
- return JSON.parse(readFileSync10(filePath, "utf-8"));
11897
+ if (existsSync16(filePath)) {
11898
+ return JSON.parse(readFileSync11(filePath, "utf-8"));
11873
11899
  }
11874
11900
  } catch {
11875
11901
  }
11876
11902
  return null;
11877
11903
  }
11878
11904
  function rateProject(ratings, projectId) {
11879
- if (!existsSync15(PROJECTS_DIR)) return false;
11905
+ if (!existsSync16(PROJECTS_DIR)) return false;
11880
11906
  try {
11881
11907
  let filePath;
11882
11908
  if (projectId) {
@@ -11884,14 +11910,14 @@ function rateProject(ratings, projectId) {
11884
11910
  filePath = path13.join(PROJECTS_DIR, `${safeId}.json`);
11885
11911
  if (!path13.resolve(filePath).startsWith(path13.resolve(PROJECTS_DIR))) return false;
11886
11912
  } else {
11887
- const files = readdirSync4(PROJECTS_DIR).filter((f) => f.endsWith(".json")).sort().reverse();
11913
+ const files = readdirSync5(PROJECTS_DIR).filter((f) => f.endsWith(".json")).sort().reverse();
11888
11914
  if (files.length === 0) return false;
11889
11915
  filePath = path13.join(PROJECTS_DIR, files[0]);
11890
11916
  }
11891
- if (!existsSync15(filePath)) return false;
11892
- const archive = JSON.parse(readFileSync10(filePath, "utf-8"));
11917
+ if (!existsSync16(filePath)) return false;
11918
+ const archive = JSON.parse(readFileSync11(filePath, "utf-8"));
11893
11919
  archive.ratings = ratings;
11894
- writeFileSync10(filePath, JSON.stringify(archive), "utf-8");
11920
+ writeFileSync11(filePath, JSON.stringify(archive), "utf-8");
11895
11921
  console.log(`[TeamState] Rated project "${archive.name}":`, ratings);
11896
11922
  return true;
11897
11923
  } catch (e) {
@@ -11916,6 +11942,7 @@ function persistTeamState() {
11916
11942
  role: a.role,
11917
11943
  personality: a.personality,
11918
11944
  backend: a.backend,
11945
+ model: a.model,
11919
11946
  palette: a.palette,
11920
11947
  teamId: a.teamId,
11921
11948
  isTeamLead: orc.isTeamLead(a.agentId),
@@ -11993,33 +12020,33 @@ function extractProjectName(planText) {
11993
12020
  function createUniqueProjectDir(workspace, baseName) {
11994
12021
  let dirName = baseName;
11995
12022
  let counter = 1;
11996
- while (existsSync16(path14.join(workspace, dirName))) {
12023
+ while (existsSync17(path14.join(workspace, dirName))) {
11997
12024
  counter++;
11998
12025
  dirName = `${baseName}-${counter}`;
11999
12026
  }
12000
12027
  const fullPath = path14.join(workspace, dirName);
12001
- mkdirSync12(fullPath, { recursive: true });
12028
+ mkdirSync13(fullPath, { recursive: true });
12002
12029
  console.log(`[Gateway] Created project directory: ${fullPath}`);
12003
12030
  return fullPath;
12004
12031
  }
12005
12032
  var AGENTS_FILE = path14.join(CONFIG_DIR, "data", "agents.json");
12006
12033
  var SKILLS_DIR = path14.join(CONFIG_DIR, "skills");
12007
12034
  function listSkills() {
12008
- if (!existsSync16(SKILLS_DIR)) return [];
12035
+ if (!existsSync17(SKILLS_DIR)) return [];
12009
12036
  try {
12010
- const entries = readdirSync5(SKILLS_DIR, { withFileTypes: true });
12037
+ const entries = readdirSync6(SKILLS_DIR, { withFileTypes: true });
12011
12038
  const skills = [];
12012
12039
  for (const entry of entries) {
12013
12040
  if (entry.isDirectory()) {
12014
12041
  const entryPath = path14.join(SKILLS_DIR, entry.name, "skill.md");
12015
- if (existsSync16(entryPath)) {
12016
- const content = readFileSync11(entryPath, "utf-8");
12042
+ if (existsSync17(entryPath)) {
12043
+ const content = readFileSync12(entryPath, "utf-8");
12017
12044
  const titleMatch = content.match(/^#\s+(.+)/m);
12018
12045
  skills.push({ name: entry.name, title: titleMatch?.[1] ?? entry.name, isFolder: true });
12019
12046
  }
12020
12047
  } else if (entry.name.endsWith(".md")) {
12021
12048
  const name = entry.name.replace(/\.md$/, "");
12022
- const content = readFileSync11(path14.join(SKILLS_DIR, entry.name), "utf-8");
12049
+ const content = readFileSync12(path14.join(SKILLS_DIR, entry.name), "utf-8");
12023
12050
  const titleMatch = content.match(/^#\s+(.+)/m);
12024
12051
  skills.push({ name, title: titleMatch?.[1] ?? name, isFolder: false });
12025
12052
  }
@@ -12033,14 +12060,14 @@ function listSkills() {
12033
12060
  function getSkillEntryPath(skillName) {
12034
12061
  const folderPath = path14.join(SKILLS_DIR, skillName, "skill.md");
12035
12062
  const filePath = path14.join(SKILLS_DIR, `${skillName}.md`);
12036
- if (existsSync16(folderPath)) return folderPath;
12037
- if (existsSync16(filePath)) return filePath;
12063
+ if (existsSync17(folderPath)) return folderPath;
12064
+ if (existsSync17(filePath)) return filePath;
12038
12065
  return null;
12039
12066
  }
12040
12067
  function loadAgentDefs() {
12041
12068
  try {
12042
- if (existsSync16(AGENTS_FILE)) {
12043
- const raw = JSON.parse(readFileSync11(AGENTS_FILE, "utf-8"));
12069
+ if (existsSync17(AGENTS_FILE)) {
12070
+ const raw = JSON.parse(readFileSync12(AGENTS_FILE, "utf-8"));
12044
12071
  if (Array.isArray(raw.agents)) {
12045
12072
  const saved = raw.agents;
12046
12073
  const custom2 = saved.filter((a) => !a.isBuiltin);
@@ -12058,8 +12085,8 @@ function loadAgentDefs() {
12058
12085
  function saveAgentDefs(agents) {
12059
12086
  try {
12060
12087
  const dir = path14.dirname(AGENTS_FILE);
12061
- if (!existsSync16(dir)) mkdirSync12(dir, { recursive: true });
12062
- writeFileSync11(AGENTS_FILE, JSON.stringify({ agents }, null, 2), "utf-8");
12088
+ if (!existsSync17(dir)) mkdirSync13(dir, { recursive: true });
12089
+ writeFileSync12(AGENTS_FILE, JSON.stringify({ agents }, null, 2), "utf-8");
12063
12090
  console.log(`[Gateway] Saved ${agents.length} agent definitions to ${AGENTS_FILE}`);
12064
12091
  } catch (e) {
12065
12092
  console.log(`[Gateway] Failed to save agents.json: ${e}`);
@@ -12069,8 +12096,8 @@ var agentDefs = [];
12069
12096
  function detectDevServer(projectDir) {
12070
12097
  try {
12071
12098
  const pkgPath = path14.join(projectDir, "package.json");
12072
- if (!existsSync16(pkgPath)) return null;
12073
- const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
12099
+ if (!existsSync17(pkgPath)) return null;
12100
+ const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
12074
12101
  const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
12075
12102
  if (allDeps["vite"]) return { cmd: "npx vite", port: 5173 };
12076
12103
  if (allDeps["webpack-dev-server"]) return { cmd: "npx webpack serve", port: 8080 };
@@ -12205,7 +12232,7 @@ function handleCommand(parsed, meta) {
12205
12232
  const entryPath = getSkillEntryPath(skillName);
12206
12233
  if (entryPath) {
12207
12234
  try {
12208
- const content = readFileSync11(entryPath, "utf-8");
12235
+ const content = readFileSync12(entryPath, "utf-8");
12209
12236
  skillContents.push(content);
12210
12237
  } catch (e) {
12211
12238
  console.log(`[Gateway] Failed to read skill file ${skillName}: ${e}`);
@@ -12223,6 +12250,7 @@ function handleCommand(parsed, meta) {
12223
12250
  role: parsed.role,
12224
12251
  personality,
12225
12252
  backend: backendId,
12253
+ model: parsed.model ?? config.defaultModels[backendId],
12226
12254
  palette: parsed.palette,
12227
12255
  teamId: parsed.teamId,
12228
12256
  workDir
@@ -12312,10 +12340,10 @@ ${text}]`;
12312
12340
  }
12313
12341
  case "UPLOAD_IMAGE": {
12314
12342
  const imgDir = path14.join(config.defaultWorkspace, ".images");
12315
- if (!existsSync16(imgDir)) mkdirSync12(imgDir, { recursive: true });
12343
+ if (!existsSync17(imgDir)) mkdirSync13(imgDir, { recursive: true });
12316
12344
  const imgPath = path14.join(imgDir, parsed.filename);
12317
12345
  try {
12318
- writeFileSync11(imgPath, Buffer.from(parsed.data, "base64"));
12346
+ writeFileSync12(imgPath, Buffer.from(parsed.data, "base64"));
12319
12347
  console.log(`[Gateway] UPLOAD_IMAGE: saved ${parsed.filename} (${Math.round(parsed.data.length * 0.75 / 1024)}KB)`);
12320
12348
  publishEvent({ type: "IMAGE_UPLOADED", requestId: parsed.requestId, path: imgPath });
12321
12349
  } catch (err) {
@@ -12331,7 +12359,7 @@ ${text}]`;
12331
12359
  console.error(`[Gateway] Blocked OPEN_FILE: path "${raw}" resolves outside workspace`);
12332
12360
  break;
12333
12361
  }
12334
- if (!existsSync16(normalized)) {
12362
+ if (!existsSync17(normalized)) {
12335
12363
  console.error(`[Gateway] OPEN_FILE: path does not exist: ${normalized}`);
12336
12364
  break;
12337
12365
  }
@@ -12355,6 +12383,8 @@ ${text}]`;
12355
12383
  }
12356
12384
  let leadAgentId = null;
12357
12385
  const teamId = `team-${nanoid6(6)}`;
12386
+ const autoNames = ["Alex", "Mia", "Leo", "Nova", "Luna", "Rex", "Kai", "Zoe", "Jay", "Sam"];
12387
+ const usedNames = /* @__PURE__ */ new Set();
12358
12388
  for (const defId of allIds) {
12359
12389
  const def = agentDefs.find((a) => a.id === defId);
12360
12390
  if (!def) {
@@ -12367,9 +12397,15 @@ ${text}]`;
12367
12397
  leadAgentId = agentId;
12368
12398
  orc.setTeamLead(agentId);
12369
12399
  }
12400
+ let agentName = def.name;
12401
+ const isShortName = agentName.length <= 10 && !agentName.includes(" ");
12402
+ if (!isShortName || usedNames.has(agentName.toLowerCase())) {
12403
+ agentName = autoNames.find((n) => !usedNames.has(n.toLowerCase())) ?? `Agent${usedNames.size + 1}`;
12404
+ }
12405
+ usedNames.add(agentName.toLowerCase());
12370
12406
  orc.createAgent({
12371
12407
  agentId,
12372
- name: def.name,
12408
+ name: agentName,
12373
12409
  role: def.skills ? `${def.role} \u2014 ${def.skills}` : def.role,
12374
12410
  personality: def.personality,
12375
12411
  backend: backendId,
@@ -12531,6 +12567,7 @@ ${text}]`;
12531
12567
  name: ext.name,
12532
12568
  role: ext.cwd ? ext.cwd.split("/").pop() ?? ext.backendId : ext.backendId,
12533
12569
  isExternal: true,
12570
+ palette: ext.pid % 6,
12534
12571
  pid: ext.pid,
12535
12572
  cwd: ext.cwd ?? void 0,
12536
12573
  startedAt: ext.startedAt,
@@ -12587,8 +12624,8 @@ ${text}]`;
12587
12624
  const skillName = parsed.name.replace(/[^a-zA-Z0-9_-]/g, "-").toLowerCase();
12588
12625
  if (!skillName) break;
12589
12626
  const skillDir = path14.join(SKILLS_DIR, skillName);
12590
- if (!existsSync16(skillDir)) mkdirSync12(skillDir, { recursive: true });
12591
- writeFileSync11(path14.join(skillDir, "skill.md"), parsed.content, "utf-8");
12627
+ if (!existsSync17(skillDir)) mkdirSync13(skillDir, { recursive: true });
12628
+ writeFileSync12(path14.join(skillDir, "skill.md"), parsed.content, "utf-8");
12592
12629
  console.log(`[Gateway] Saved skill: ${skillName}`);
12593
12630
  publishEvent({ type: "SKILL_LIST", skills: listSkills() });
12594
12631
  break;
@@ -12598,12 +12635,12 @@ ${text}]`;
12598
12635
  const folderPath = path14.join(SKILLS_DIR, skillName);
12599
12636
  const filePath = path14.join(SKILLS_DIR, `${skillName}.md`);
12600
12637
  try {
12601
- if (existsSync16(folderPath) && !existsSync16(path14.join(folderPath, "skill.md"))) {
12602
- } else if (existsSync16(folderPath)) {
12603
- const files = readdirSync5(folderPath);
12638
+ if (existsSync17(folderPath) && !existsSync17(path14.join(folderPath, "skill.md"))) {
12639
+ } else if (existsSync17(folderPath)) {
12640
+ const files = readdirSync6(folderPath);
12604
12641
  for (const f of files) unlinkSync3(path14.join(folderPath, f));
12605
12642
  rmdirSync2(folderPath);
12606
- } else if (existsSync16(filePath)) {
12643
+ } else if (existsSync17(filePath)) {
12607
12644
  unlinkSync3(filePath);
12608
12645
  }
12609
12646
  console.log(`[Gateway] Deleted skill: ${skillName}`);
@@ -12613,6 +12650,29 @@ ${text}]`;
12613
12650
  publishEvent({ type: "SKILL_LIST", skills: listSkills() });
12614
12651
  break;
12615
12652
  }
12653
+ case "SYNC_CHAT_HISTORY": {
12654
+ try {
12655
+ const chatFile = path14.join(config.instanceDir, "chat-history.json");
12656
+ const tmpFile = chatFile + ".tmp";
12657
+ writeFileSync12(tmpFile, parsed.data, "utf-8");
12658
+ renameSync5(tmpFile, chatFile);
12659
+ } catch (e) {
12660
+ console.warn(`[Gateway] Failed to save chat history: ${e}`);
12661
+ }
12662
+ break;
12663
+ }
12664
+ case "LOAD_CHAT_HISTORY": {
12665
+ try {
12666
+ const chatFile = path14.join(config.instanceDir, "chat-history.json");
12667
+ if (existsSync17(chatFile)) {
12668
+ const data = readFileSync12(chatFile, "utf-8");
12669
+ publishEvent({ type: "CHAT_HISTORY_LOADED", data });
12670
+ }
12671
+ } catch (e) {
12672
+ console.warn(`[Gateway] Failed to load chat history: ${e}`);
12673
+ }
12674
+ break;
12675
+ }
12616
12676
  case "SUGGEST": {
12617
12677
  const lastSuggest = suggestRateLimit.get(meta.clientId) ?? 0;
12618
12678
  if (Date.now() - lastSuggest < SUGGEST_COOLDOWN_MS) {
@@ -12658,40 +12718,6 @@ ${text}]`;
12658
12718
  }
12659
12719
  break;
12660
12720
  }
12661
- case "UPDATE_AGENCY_AGENTS": {
12662
- console.log("[Gateway] Updating agency agents...");
12663
- const scriptPath = path14.join(path14.dirname(new URL(import.meta.url).pathname), "..", "..", "..", "scripts", "install-agents.sh");
12664
- if (!existsSync16(scriptPath)) {
12665
- console.warn("[Gateway] install-agents.sh not found \u2014 only available in git checkout");
12666
- publishEvent({
12667
- type: "AGENCY_AGENTS_UPDATED",
12668
- success: false,
12669
- message: "Agency agents update is only available when running from the git checkout (not the npm package)."
12670
- });
12671
- break;
12672
- }
12673
- execFile3("bash", [scriptPath, "--update"], { timeout: 6e4 }, (err, stdout, stderr) => {
12674
- if (err) {
12675
- console.error("[Gateway] Agency agents update failed:", stderr || err.message);
12676
- publishEvent({
12677
- type: "AGENCY_AGENTS_UPDATED",
12678
- success: false,
12679
- message: stderr || err.message
12680
- });
12681
- } else {
12682
- const countMatch = stdout.match(/(\d+) agents/);
12683
- const count = countMatch ? parseInt(countMatch[1], 10) : void 0;
12684
- console.log("[Gateway] Agency agents updated:", stdout.trim().split("\n").pop());
12685
- publishEvent({
12686
- type: "AGENCY_AGENTS_UPDATED",
12687
- success: true,
12688
- message: `Agency agents updated successfully`,
12689
- count
12690
- });
12691
- }
12692
- });
12693
- break;
12694
- }
12695
12721
  case "GET_CONFIG": {
12696
12722
  const tgConnected = isChannelActive(telegramChannel);
12697
12723
  sendToClient(meta.clientId, {
@@ -12772,20 +12798,20 @@ ${text}]`;
12772
12798
  const sourceAgent = orc.getAgent(sourceAgentId);
12773
12799
  const agentWorkDir = agentWorkDirs.get(sourceAgentId);
12774
12800
  let cwd;
12775
- if (agentWorkDir && existsSync16(agentWorkDir)) {
12801
+ if (agentWorkDir && existsSync17(agentWorkDir)) {
12776
12802
  if (projectDir && !path14.isAbsolute(projectDir)) {
12777
12803
  const joined = path14.join(agentWorkDir, projectDir);
12778
- cwd = existsSync16(joined) ? joined : agentWorkDir;
12804
+ cwd = existsSync17(joined) ? joined : agentWorkDir;
12779
12805
  } else {
12780
12806
  cwd = agentWorkDir;
12781
12807
  }
12782
12808
  } else if (projectDir) {
12783
12809
  const absProjectDir = path14.isAbsolute(projectDir) ? projectDir : path14.join(config.defaultWorkspace, projectDir);
12784
- cwd = existsSync16(absProjectDir) ? absProjectDir : config.defaultWorkspace;
12810
+ cwd = existsSync17(absProjectDir) ? absProjectDir : config.defaultWorkspace;
12785
12811
  } else {
12786
12812
  cwd = config.defaultWorkspace;
12787
12813
  }
12788
- if (!path14.isAbsolute(cwd) || !existsSync16(cwd)) cwd = config.defaultWorkspace;
12814
+ if (!path14.isAbsolute(cwd) || !existsSync17(cwd)) cwd = config.defaultWorkspace;
12789
12815
  const reviewerBackendId = reviewBackend ?? sourceAgent?.backend ?? config.defaultBackend;
12790
12816
  let diff = "";
12791
12817
  try {
@@ -12802,7 +12828,7 @@ ${text}]`;
12802
12828
  for (const f of untrackedFiles) {
12803
12829
  try {
12804
12830
  const absPath = path14.isAbsolute(f) ? f : path14.join(cwd, f);
12805
- const content = readFileSync11(absPath, "utf-8");
12831
+ const content = readFileSync12(absPath, "utf-8");
12806
12832
  const lines = content.split("\n");
12807
12833
  const truncated = lines.length > 80 ? lines.slice(0, 80).join("\n") + `
12808
12834
  ... (${lines.length - 80} more lines)` : content;
@@ -12835,28 +12861,15 @@ ${diff}`;
12835
12861
  }
12836
12862
  const fileList = changedFiles.map((f) => `- ${f}`).join("\n");
12837
12863
  const reviewPrompt = [
12838
- `Review the code changes below. Focus on the DIFF \u2014 it shows exactly what was changed.`,
12839
- ``,
12840
- `Severity classification:`,
12841
- `- CRITICAL: Bugs, crashes, security vulnerabilities, logic errors \u2014 must fix`,
12842
- `- SUGGESTION: Style, naming, refactoring \u2014 optional, non-blocking`,
12843
- ``,
12844
- `Rules:`,
12845
- `- Base your review primarily on the diff. Only Read files if you need surrounding context to understand the change.`,
12846
- `- Do NOT suggest renaming, refactoring, or style changes unless they cause actual bugs.`,
12847
- `- Be concise. For each issue: file, line, severity, what's wrong, how to fix.`,
12864
+ `Review the code changes below. Focus on the DIFF for what changed, Read files only if you need surrounding context.`,
12865
+ `Only flag real bugs, crashes, security issues, logic errors. Skip style/naming suggestions.`,
12848
12866
  ``,
12849
12867
  `Project: ${cwd}`,
12850
12868
  `Files changed:
12851
12869
  ${fileList}`,
12852
12870
  entryFile ? `Entry: ${entryFile}` : "",
12853
12871
  summary ? `Summary: ${summary}` : "",
12854
- diffSection,
12855
- ``,
12856
- `Output format:`,
12857
- `VERDICT: PASS | FAIL`,
12858
- `ISSUES: (numbered list with severity, file:line, description)`,
12859
- `SUMMARY: (one sentence)`
12872
+ diffSection
12860
12873
  ].filter(Boolean).join("\n");
12861
12874
  orc.createAgent({
12862
12875
  agentId: reviewerAgentId,
@@ -12931,6 +12944,7 @@ async function main() {
12931
12944
  }
12932
12945
  }
12933
12946
  const backendsToUse = getAllBackends();
12947
+ syncAgentDefs();
12934
12948
  setSessionDir(config.instanceDir);
12935
12949
  setStorageRoot(path14.join(config.instanceDir, "memory"));
12936
12950
  console.log(`[Gateway] Instance "${config.gatewayId}" \u2192 ${config.instanceDir}`);
@@ -12961,6 +12975,7 @@ async function main() {
12961
12975
  role: agent.role,
12962
12976
  personality: agent.personality,
12963
12977
  backend: agent.backend ?? config.defaultBackend,
12978
+ model: agent.model ?? config.defaultModels[agent.backend ?? config.defaultBackend],
12964
12979
  palette: agent.palette,
12965
12980
  teamId: agent.teamId,
12966
12981
  resumeHistory: true,
@@ -13000,7 +13015,7 @@ async function main() {
13000
13015
  console.log(`[Gateway] Marked leader ${t.leadAgentId} as hasExecuted (was in ${t.phase} phase)`);
13001
13016
  }
13002
13017
  if (t.projectDir) {
13003
- if (existsSync16(t.projectDir)) {
13018
+ if (existsSync17(t.projectDir)) {
13004
13019
  orc.setTeamProjectDir(t.projectDir);
13005
13020
  } else {
13006
13021
  console.warn(`[Gateway] Project dir does not exist: ${t.projectDir} \u2014 team will need a new project dir`);
@@ -13105,6 +13120,7 @@ async function main() {
13105
13120
  name: displayName,
13106
13121
  role: agent.cwd ? agent.cwd.split("/").pop() ?? agent.backendId : agent.backendId,
13107
13122
  isExternal: true,
13123
+ palette: agent.pid % 6,
13108
13124
  pid: agent.pid,
13109
13125
  cwd: agent.cwd ?? void 0,
13110
13126
  startedAt: agent.startedAt,
@@ -13164,7 +13180,7 @@ async function main() {
13164
13180
  startTunnel();
13165
13181
  console.log("[Gateway] Listening for commands...");
13166
13182
  console.log("[Gateway] Press 'p' + Enter to generate a new pair code");
13167
- if (process.env.NODE_ENV !== "development" && !process.env.NO_OPEN && existsSync16(config.webDir)) {
13183
+ if (process.env.NODE_ENV !== "development" && !process.env.NO_OPEN && existsSync17(config.webDir)) {
13168
13184
  const url = `http://localhost:${config.wsPort}`;
13169
13185
  console.log(`[Gateway] Opening ${url}`);
13170
13186
  execFile3("open", [url]);