chatroom-cli 1.73.0 → 1.74.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2167,6 +2167,7 @@ __export(exports_stdin_heredoc, {
2167
2167
  findReservedDelimiterLines: () => findReservedDelimiterLines,
2168
2168
  HANDOFF_STDIN_DELIMITER: () => HANDOFF_STDIN_DELIMITER,
2169
2169
  HANDOFF_MESSAGE_MARKER: () => HANDOFF_MESSAGE_MARKER,
2170
+ ENHANCER_STDIN_DELIMITER: () => ENHANCER_STDIN_DELIMITER,
2170
2171
  CONTEXT_STDIN_DELIMITER: () => CONTEXT_STDIN_DELIMITER,
2171
2172
  BACKLOG_STDIN_DELIMITER: () => BACKLOG_STDIN_DELIMITER,
2172
2173
  AGENTIC_QUERY_STDIN_DELIMITER: () => AGENTIC_QUERY_STDIN_DELIMITER
@@ -2205,13 +2206,14 @@ function findReservedDelimiterLines(content) {
2205
2206
  }
2206
2207
  return hits;
2207
2208
  }
2208
- var HANDOFF_STDIN_DELIMITER = "CHATROOM_HANDOFF_END", CONTEXT_STDIN_DELIMITER = "CHATROOM_CONTEXT_END", BACKLOG_STDIN_DELIMITER = "CHATROOM_BACKLOG_END", AGENTIC_QUERY_STDIN_DELIMITER = "CHATROOM_AGENTIC_QUERY_END", CLASSIFY_STDIN_DELIMITER = "CHATROOM_CLASSIFY_END", HANDOFF_MESSAGE_MARKER = "---MESSAGE---", RESERVED_STDIN_HEREDOC_DELIMITERS, RESERVED_STRUCTURED_PARAM_MARKERS;
2209
+ var HANDOFF_STDIN_DELIMITER = "CHATROOM_HANDOFF_END", CONTEXT_STDIN_DELIMITER = "CHATROOM_CONTEXT_END", BACKLOG_STDIN_DELIMITER = "CHATROOM_BACKLOG_END", AGENTIC_QUERY_STDIN_DELIMITER = "CHATROOM_AGENTIC_QUERY_END", ENHANCER_STDIN_DELIMITER = "CHATROOM_ENHANCER_END", CLASSIFY_STDIN_DELIMITER = "CHATROOM_CLASSIFY_END", HANDOFF_MESSAGE_MARKER = "---MESSAGE---", RESERVED_STDIN_HEREDOC_DELIMITERS, RESERVED_STRUCTURED_PARAM_MARKERS;
2209
2210
  var init_stdin_heredoc = __esm(() => {
2210
2211
  RESERVED_STDIN_HEREDOC_DELIMITERS = [
2211
2212
  HANDOFF_STDIN_DELIMITER,
2212
2213
  CONTEXT_STDIN_DELIMITER,
2213
2214
  BACKLOG_STDIN_DELIMITER,
2214
2215
  AGENTIC_QUERY_STDIN_DELIMITER,
2216
+ ENHANCER_STDIN_DELIMITER,
2215
2217
  CLASSIFY_STDIN_DELIMITER
2216
2218
  ];
2217
2219
  RESERVED_STRUCTURED_PARAM_MARKERS = [
@@ -9914,6 +9916,10 @@ var init_api2 = __esm(() => {
9914
9916
  });
9915
9917
 
9916
9918
  // src/api.ts
9919
+ var exports_api = {};
9920
+ __export(exports_api, {
9921
+ api: () => api
9922
+ });
9917
9923
  var init_api3 = __esm(() => {
9918
9924
  init_api2();
9919
9925
  });
@@ -76368,6 +76374,24 @@ var init_register_agent = __esm(() => {
76368
76374
  init_services();
76369
76375
  init_convex_error();
76370
76376
  });
76377
+
76378
+ // ../../services/backend/prompts/base/shared/context-rule.ts
76379
+ function getContextRuleBlock(contextNewCmd, contextHint) {
76380
+ return `**Context Rule:** Set a new context for every user message by default — skip ONLY when the message is clearly a follow-up of the current chatroom task. **Before running \`context new\`, run \`context read\` — if the pinned context already uses the same \`--trigger-message-id\` as this task's Origin Message ID, do NOT create another context** (avoids duplicate timeline dividers). Only the entry point role can set contexts:
76381
+ \`\`\`bash
76382
+ ${contextNewCmd}
76383
+ \`\`\`
76384
+ ${contextHint}`;
76385
+ }
76386
+
76387
+ // ../../services/backend/prompts/base/shared/token-activity-note.ts
76388
+ function getTokenActivityInProgressNote() {
76389
+ return "Begin working from the task content above. The daemon detects harness output (stdout tokens) and marks the task `in_progress` automatically — **do not run `task read`** unless you need backlog items or context details not shown in the delivery.";
76390
+ }
76391
+ function getNativeTokenActivityInProgressNote() {
76392
+ return "Begin working from the task content above. The daemon detects harness output (stdout tokens) and marks the task `in_progress` automatically.";
76393
+ }
76394
+
76371
76395
  // ../../services/backend/prompts/cli/context/context-template.ts
76372
76396
  function getContextViewTemplate() {
76373
76397
  return CONTEXT_VIEW_TEMPLATE;
@@ -76386,20 +76410,60 @@ var CONTEXT_VIEW_TEMPLATE = `## Goal
76386
76410
  - _Out-of-scope work or anti-patterns to skip._`;
76387
76411
 
76388
76412
  // ../../services/backend/prompts/cli/context/view-template.ts
76413
+ function contextViewTemplateCommand(params) {
76414
+ const prefix = params.cliEnvPrefix || "";
76415
+ return `${prefix}chatroom context view-template`;
76416
+ }
76389
76417
  var init_view_template = () => {};
76390
76418
 
76391
76419
  // ../../services/backend/prompts/cli/context/new.ts
76420
+ function contextNewHint(params) {
76421
+ const viewTemplateCmd = contextViewTemplateCommand({ cliEnvPrefix: params.cliEnvPrefix });
76422
+ return `REQUIRED: All context content MUST conform to the template. Run \`${viewTemplateCmd}\` (no flags). \`--trigger-message-id\` must be the task's \`origin-message-id\` attribute (never \`task-id\`). Use the pre-filled value in the command above when provided.`;
76423
+ }
76424
+ function contextNewCommand(params) {
76425
+ const prefix = params.cliEnvPrefix || "";
76426
+ const chatroomId = params.chatroomId || "CHATROOM_ID";
76427
+ const role = params.role || "ROLE";
76428
+ const triggerMessageId = params.triggerMessageId ?? "ORIGIN_MESSAGE_ID";
76429
+ const commandPrefix = `${prefix}chatroom context new --chatroom-id="${chatroomId}" --role="${role}" --trigger-message-id="${triggerMessageId}"`;
76430
+ return formatStdinHeredocCommand(commandPrefix, CONTEXT_STDIN_DELIMITER, getContextViewTemplate());
76431
+ }
76392
76432
  var init_new = __esm(() => {
76393
76433
  init_stdin_heredoc();
76394
76434
  init_view_template();
76395
76435
  });
76396
76436
 
76397
76437
  // ../../services/backend/prompts/cli/task-started/main-prompt.ts
76438
+ function getTaskStartedPrompt(ctx) {
76439
+ const { chatroomId, role, cliEnvPrefix, triggerMessageId } = ctx;
76440
+ const contextNewCmd = contextNewCommand({
76441
+ chatroomId,
76442
+ role,
76443
+ cliEnvPrefix,
76444
+ triggerMessageId
76445
+ });
76446
+ return `### Start working
76447
+
76448
+ ${getTokenActivityInProgressNote()}
76449
+
76450
+ ${getContextRuleBlock(contextNewCmd, contextNewHint({ cliEnvPrefix }))}`;
76451
+ }
76452
+ function getTaskStartedPromptForHandoffRecipient(_ctx) {
76453
+ return `### Start Working
76454
+
76455
+ The task body contains your work description. ${getTokenActivityInProgressNote()}`;
76456
+ }
76398
76457
  var init_main_prompt = __esm(() => {
76399
76458
  init_new();
76400
76459
  });
76401
76460
 
76402
76461
  // ../../services/backend/prompts/cli/task-started/index.ts
76462
+ var exports_task_started = {};
76463
+ __export(exports_task_started, {
76464
+ getTaskStartedPromptForHandoffRecipient: () => getTaskStartedPromptForHandoffRecipient,
76465
+ getTaskStartedPrompt: () => getTaskStartedPrompt
76466
+ });
76403
76467
  var init_task_started = __esm(() => {
76404
76468
  init_main_prompt();
76405
76469
  });
@@ -76421,6 +76485,14 @@ Exactly one active waiter should own task delivery at a time. Additional or back
76421
76485
 
76422
76486
  After interruption or restart: complete any in-progress work, then restore a single foreground blocking \`get-next-task\` so chatroom tasks can arrive again.`;
76423
76487
  }
76488
+ function getCompactionRecoveryNote(params) {
76489
+ const { cliEnvPrefix, chatroomId, role } = params;
76490
+ return `NOTE: If you are an agent that has undergone compaction or summarization, run:
76491
+ ${cliEnvPrefix}chatroom get-system-prompt --chatroom-id="${chatroomId}" --role="${role}"
76492
+ to reload your full system and role prompt. Then run:
76493
+ ${cliEnvPrefix}chatroom context read --chatroom-id="${chatroomId}" --role="${role}"
76494
+ to see your current chatroom task context.`;
76495
+ }
76424
76496
  var init_reminder = () => {};
76425
76497
  // ../../services/backend/prompts/utils/index.ts
76426
76498
  var init_utils3 = __esm(() => {
@@ -76428,16 +76500,65 @@ var init_utils3 = __esm(() => {
76428
76500
  });
76429
76501
 
76430
76502
  // ../../services/backend/prompts/base/shared/getting-started-content.ts
76503
+ function getContextGainingGuidance(params) {
76504
+ const { chatroomId, role, convexUrl, agentType } = params;
76505
+ const cliEnvPrefix = getCliEnvPrefix(convexUrl);
76506
+ const typeValue = agentType && agentType !== "unset" ? agentType : "<remote|custom>";
76507
+ return `## Getting Started
76508
+
76509
+ ### Workflow Loop
76510
+
76511
+ \`\`\`mermaid
76512
+ flowchart LR
76513
+ A([Start]) --> B[register-agent]
76514
+ B --> C[get-next-task
76515
+ chatroom task delivery]
76516
+ C --> D[Do Work]
76517
+ D --> E[handoff]
76518
+ E --> C
76519
+ \`\`\`
76520
+
76521
+ ### Task delivery and activity
76522
+
76523
+ When \`get-next-task\` delivers a chatroom task, the **full task content is included in the output**. ${getTokenActivityInProgressNote()}
76524
+
76525
+ ⚠️ Remember your two-level model: completing a **chatroom task** (Level B) does NOT end your **session** (Level A). After every handoff, you must run \`get-next-task\` again to continue the session.
76526
+
76527
+ ### Context Recovery (after compaction/summarization)
76528
+
76529
+ ${getCompactionRecoveryNote({ cliEnvPrefix, chatroomId, role })}
76530
+
76531
+ CLI harnesses do not support in-session compaction. After context is lost, the daemon performs a hard restart — you must run \`get-next-task\` again to rejoin the chatroom.
76532
+
76533
+ ### Register Agent
76534
+ Register your agent type before starting work.
76535
+
76536
+ \`\`\`bash
76537
+ ${cliEnvPrefix}chatroom register-agent --chatroom-id="${chatroomId}" --role="${role}" --type=${typeValue}
76538
+ \`\`\`
76539
+
76540
+ ### Get Next Task
76541
+ Listen for incoming tasks assigned to your role. A foreground \`get-next-task\` blocks until the user or team message is ready, then resolves with that message as a chatroom task—infer intent from the message rather than following numbered next-steps blindly.
76542
+
76543
+ \`\`\`bash
76544
+ ${cliEnvPrefix}chatroom get-next-task --chatroom-id="${chatroomId}" --role="${role}"
76545
+ \`\`\`
76546
+
76547
+ **This loop never ends.** A session (Level A) processes many chatroom tasks (Level B). Each handoff completes Level B — \`get-next-task\` continues Level A. Do not stop or exit after a handoff.
76548
+ `;
76549
+ }
76431
76550
  var init_getting_started_content = __esm(() => {
76432
76551
  init_reminder();
76433
76552
  init_utils3();
76434
76553
  });
76435
76554
 
76436
76555
  // ../../services/backend/prompts/cli/index.ts
76556
+ var getTaskStartedPrompt2, getTaskStartedPromptForHandoffRecipient2;
76437
76557
  var init_cli = __esm(() => {
76438
76558
  init_task_started();
76439
76559
  init_reminder();
76440
76560
  init_getting_started_content();
76561
+ ({ getTaskStartedPrompt: getTaskStartedPrompt2, getTaskStartedPromptForHandoffRecipient: getTaskStartedPromptForHandoffRecipient2 } = exports_task_started);
76441
76562
  });
76442
76563
 
76443
76564
  // src/commands/get-next-task/get-next-task-session-service.ts
@@ -77735,7 +77856,89 @@ function formatDecodeError(error) {
77735
77856
  return message;
77736
77857
  }
77737
77858
 
77859
+ // ../../services/backend/config/reliability.ts
77860
+ var HARNESS_SESSION_READY_TIMEOUT_MS = 5000, NATIVE_DELIVERY_RECONCILE_MS = 1e4, DAEMON_HEARTBEAT_INTERVAL_MS, DAEMON_HEARTBEAT_TTL_MS, AGENT_REQUEST_DEADLINE_MS = 120000, OBSERVED_FULL_PUSH_INTERVAL_MS, OBSERVED_SAFETY_POLL_MS = 30000, OBSERVED_SYNC_RECONCILE_MS, WORKSPACE_RECENCY_WINDOW_MS, WORKSPACE_LIST_RECONCILE_MS, CONNECTION_CLOSE_REQUEST_TTL_MS, ENHANCER_ATTEMPT_TIMEOUT_MS = 120000, ENHANCER_TERMINAL_JOB_RETENTION_MS, ENHANCER_CLI_POLL_INTERVAL_MS = 1000;
77861
+ var init_reliability = __esm(() => {
77862
+ DAEMON_HEARTBEAT_INTERVAL_MS = 5 * 60000;
77863
+ DAEMON_HEARTBEAT_TTL_MS = 6 * DAEMON_HEARTBEAT_INTERVAL_MS;
77864
+ OBSERVED_FULL_PUSH_INTERVAL_MS = 5 * 60000;
77865
+ OBSERVED_SYNC_RECONCILE_MS = 15 * 60000;
77866
+ WORKSPACE_RECENCY_WINDOW_MS = 7 * 24 * 60 * 60 * 1000;
77867
+ WORKSPACE_LIST_RECONCILE_MS = 60 * 60 * 1000;
77868
+ CONNECTION_CLOSE_REQUEST_TTL_MS = 10 * 60000;
77869
+ ENHANCER_TERMINAL_JOB_RETENTION_MS = 30 * 24 * 60 * 60 * 1000;
77870
+ });
77871
+
77872
+ // src/commands/enhancer/wait-for-job.ts
77873
+ var exports_wait_for_job = {};
77874
+ __export(exports_wait_for_job, {
77875
+ waitForEnhancerJob: () => waitForEnhancerJob
77876
+ });
77877
+ async function waitForEnhancerJob(chatroomId, jobId, deps) {
77878
+ const sessionId = await deps.getSessionId();
77879
+ if (!sessionId) {
77880
+ throw new Error("Not authenticated");
77881
+ }
77882
+ while (true) {
77883
+ const job = await deps.query(deps.endpoints.getJob, {
77884
+ sessionId,
77885
+ chatroomId,
77886
+ jobId
77887
+ });
77888
+ if (!job) {
77889
+ throw new Error("Enhancer job not found");
77890
+ }
77891
+ if (job.status === "complete") {
77892
+ return "complete";
77893
+ }
77894
+ if (job.status === "cancelled") {
77895
+ return "cancelled";
77896
+ }
77897
+ if (job.status === "failed") {
77898
+ return "failed";
77899
+ }
77900
+ if (job.status === "running" && job.runningSince) {
77901
+ const elapsed3 = Date.now() - job.runningSince;
77902
+ if (elapsed3 > ENHANCER_ATTEMPT_TIMEOUT_MS) {
77903
+ await deps.mutation(deps.endpoints.recordAttemptFailure, {
77904
+ sessionId,
77905
+ chatroomId,
77906
+ jobId,
77907
+ error: "Attempt timed out"
77908
+ });
77909
+ await sleep5(ENHANCER_CLI_POLL_INTERVAL_MS);
77910
+ continue;
77911
+ }
77912
+ }
77913
+ await sleep5(ENHANCER_CLI_POLL_INTERVAL_MS);
77914
+ }
77915
+ }
77916
+ function sleep5(ms) {
77917
+ return new Promise((resolve3) => setTimeout(resolve3, ms));
77918
+ }
77919
+ var init_wait_for_job = __esm(() => {
77920
+ init_reliability();
77921
+ });
77922
+
77738
77923
  // ../../services/backend/prompts/native/session-continuity.ts
77924
+ function getSessionContinuityLine(nativeIntegration) {
77925
+ if (nativeIntegration) {
77926
+ return "";
77927
+ }
77928
+ return "Completing a **chatroom task** (Level B) does NOT end your **session** (Level A). After every handoff, run `get-next-task` to continue.";
77929
+ }
77930
+ function getHandoffContinuityRule(nativeIntegration) {
77931
+ if (nativeIntegration) {
77932
+ return "";
77933
+ }
77934
+ return "⚠️ After ANY handoff (including to `user`), you must run `get-next-task` to stay in the session.";
77935
+ }
77936
+ function getOperatingModelLoopFooter(nativeIntegration) {
77937
+ return nativeIntegration ? "Hand off when complete" : "Run get-next-task";
77938
+ }
77939
+ function getNativePlannerDelegationWaitNote() {
77940
+ return `After delegating to the builder, **run handoff as your last action and end your turn** — no further tool calls after handoff. The system delivers their handback when they finish — do not poll \`messages list\`, sleep, or run other tools while waiting.`;
77941
+ }
77739
77942
  function getNativeHandoffTurnEndGuidance(nextRole) {
77740
77943
  const lines = [
77741
77944
  "",
@@ -77751,10 +77954,103 @@ function getNativeHandoffTurnEndGuidance(nextRole) {
77751
77954
  }
77752
77955
 
77753
77956
  // ../../services/backend/prompts/cli/handoff/command.ts
77957
+ function handoffCommand(params) {
77958
+ const prefix = params.cliEnvPrefix || "";
77959
+ const chatroomId = params.chatroomId || "<chatroom-id>";
77960
+ const role = params.role || "<role>";
77961
+ const nextRole = params.nextRole || "<target>";
77962
+ const placeholder = params.messagePlaceholder ?? "[Your message here]";
77963
+ const commandPrefix = `${prefix}chatroom handoff --chatroom-id="${chatroomId}" --role="${role}" --next-role="${nextRole}"`;
77964
+ return formatStdinHeredocCommand(commandPrefix, HANDOFF_STDIN_DELIMITER, placeholder, {
77965
+ messageMarker: HANDOFF_MESSAGE_MARKER
77966
+ });
77967
+ }
77754
77968
  var init_command2 = __esm(() => {
77755
77969
  init_stdin_heredoc();
77756
77970
  });
77971
+
77972
+ // ../../services/backend/prompts/types/sections.ts
77973
+ function createSection(id3, type, content) {
77974
+ return { id: id3, type, content };
77975
+ }
77976
+ function composeSections(sections) {
77977
+ return sections.filter((s) => s.content.trim()).map((s) => s.content).join(`
77978
+
77979
+ `).trim();
77980
+ }
77981
+
77757
77982
  // ../../services/backend/prompts/sections/commands-reference.ts
77983
+ function getCommandsReferenceSection(params) {
77984
+ const cliEnvPrefix = getCliEnvPrefix(params.convexUrl);
77985
+ const handoffCmd = handoffCommand({
77986
+ chatroomId: params.chatroomId,
77987
+ role: params.role,
77988
+ nextRole: "<target>",
77989
+ cliEnvPrefix
77990
+ });
77991
+ const waitCmd = getNextTaskCommand({
77992
+ chatroomId: params.chatroomId,
77993
+ role: params.role,
77994
+ cliEnvPrefix
77995
+ });
77996
+ const content = `### Commands
77997
+
77998
+ **Complete chatroom task and hand off:**
77999
+
78000
+ \`\`\`bash
78001
+ ${handoffCmd}
78002
+ \`\`\`
78003
+
78004
+ ${HANDOFF_BODY_GUIDANCE}
78005
+
78006
+ **Continue receiving messages after \`handoff\`:**
78007
+ \`\`\`
78008
+ ${waitCmd}
78009
+ \`\`\`
78010
+
78011
+ ${getNextTaskReminder()}
78012
+
78013
+ **Reference commands:**
78014
+ - List recent messages: \`${cliEnvPrefix}chatroom messages list --chatroom-id="${params.chatroomId}" --role="${params.role}" --sender-role=user --limit=5 --full\`
78015
+ - Git log: \`git log --oneline -10\`
78016
+
78017
+ **Recovery commands** (only needed after compaction/restart):
78018
+ - Reload system prompt: \`${cliEnvPrefix}chatroom get-system-prompt --chatroom-id="${params.chatroomId}" --role="${params.role}"\`
78019
+ - Reload role guidance: \`${roleGuidanceCommand({ chatroomId: params.chatroomId, role: params.role, cliEnvPrefix })}\`
78020
+ - Read current chatroom task context: \`${cliEnvPrefix}chatroom context read --chatroom-id="${params.chatroomId}" --role="${params.role}"\``;
78021
+ return createSection("commands-reference", "knowledge", content);
78022
+ }
78023
+ function getNativeCommandsReferenceSection(params) {
78024
+ const cliEnvPrefix = getCliEnvPrefix(params.convexUrl);
78025
+ const handoffCmd = handoffCommand({
78026
+ chatroomId: params.chatroomId,
78027
+ role: params.role,
78028
+ nextRole: "<target>",
78029
+ cliEnvPrefix
78030
+ });
78031
+ const content = `### Commands
78032
+
78033
+ **Complete chatroom task and hand off:**
78034
+
78035
+ \`\`\`bash
78036
+ ${handoffCmd}
78037
+ \`\`\`
78038
+
78039
+ ${HANDOFF_BODY_GUIDANCE}
78040
+
78041
+ **Do not run \`register-agent\`** — your session was registered when the harness started.
78042
+
78043
+ **Reference commands:**
78044
+ - List recent messages: \`${cliEnvPrefix}chatroom messages list --chatroom-id="${params.chatroomId}" --role="${params.role}" --sender-role=user --limit=5 --full\`
78045
+ - Git log: \`git log --oneline -10\`
78046
+
78047
+ **Recovery commands** (only needed after compaction/restart):
78048
+ - Reload system prompt: \`${cliEnvPrefix}chatroom get-system-prompt --chatroom-id="${params.chatroomId}" --role="${params.role}"\`
78049
+ - Reload role guidance: \`${roleGuidanceCommand({ chatroomId: params.chatroomId, role: params.role, cliEnvPrefix })}\`
78050
+ - Read current chatroom task context: \`${cliEnvPrefix}chatroom context read --chatroom-id="${params.chatroomId}" --role="${params.role}"\``;
78051
+ return createSection("commands-reference-native", "knowledge", content);
78052
+ }
78053
+ var HANDOFF_BODY_GUIDANCE = `Fill in the message using the matching template from \`<handoff-templates>\` in your task delivery output. Replace \`[Your message here]\` with that template content. The closing line must be exactly \`CHATROOM_HANDOFF_END\` (not \`EOF\`).`;
77758
78054
  var init_commands_reference = __esm(() => {
77759
78055
  init_command();
77760
78056
  init_reminder();
@@ -77763,25 +78059,650 @@ var init_commands_reference = __esm(() => {
77763
78059
  });
77764
78060
 
77765
78061
  // ../../services/backend/prompts/cli/backlog/command.ts
78062
+ function backlogAddCommand(params) {
78063
+ const prefix = params.cliEnvPrefix || "";
78064
+ const chatroomId = params.chatroomId || "<id>";
78065
+ const role = params.role || "<role>";
78066
+ const placeholder = params.contentPlaceholder ?? "Your backlog item content here";
78067
+ const commandPrefix = `${prefix}chatroom backlog add --chatroom-id=${chatroomId} --role=${role}`;
78068
+ return formatStdinHeredocCommand(commandPrefix, BACKLOG_STDIN_DELIMITER, placeholder);
78069
+ }
78070
+ function backlogUpdateCommand(params) {
78071
+ const prefix = params.cliEnvPrefix || "";
78072
+ const chatroomId = params.chatroomId || "<id>";
78073
+ const role = params.role || "<role>";
78074
+ const backlogItemId = params.backlogItemId || "<id>";
78075
+ const placeholder = params.contentPlaceholder ?? "New content here";
78076
+ const commandPrefix = `${prefix}chatroom backlog update --chatroom-id=${chatroomId} --role=${role} --backlog-item-id=${backlogItemId}`;
78077
+ return formatStdinHeredocCommand(commandPrefix, BACKLOG_STDIN_DELIMITER, placeholder);
78078
+ }
77766
78079
  var init_command3 = __esm(() => {
77767
78080
  init_stdin_heredoc();
77768
78081
  });
77769
78082
 
77770
78083
  // ../../services/backend/src/domain/usecase/skills/modules/backlog/index.ts
78084
+ var backlogSkill;
77771
78085
  var init_backlog = __esm(() => {
77772
78086
  init_command3();
78087
+ backlogSkill = {
78088
+ skillId: "backlog",
78089
+ name: "Backlog Reference",
78090
+ description: "Full backlog command reference: list/add/update, scoring, completion, close, export/import, and workflow guides.",
78091
+ getPrompt: (cliEnvPrefix) => `You have been activated with the "backlog" skill.
78092
+
78093
+ ## Command Reference
78094
+
78095
+ ### List
78096
+ \`\`\`
78097
+ ${cliEnvPrefix}chatroom backlog list --chatroom-id=<id> --role=<role>
78098
+ \`\`\`
78099
+ Options: \`--limit=<n>\`, \`--sort=date:desc|priority:desc\`, \`--filter=unscored\` (only items without a priority score)
78100
+
78101
+ The list output shows scoring info (complexity, value, priority) for each item if it has been scored.
78102
+
78103
+ ### History
78104
+ \`\`\`
78105
+ ${cliEnvPrefix}chatroom backlog history --chatroom-id=<id> --role=<role>
78106
+ \`\`\`
78107
+ Options: \`--from=YYYY-MM-DD\`, \`--to=YYYY-MM-DD\`, \`--limit=<n>\`
78108
+
78109
+ Defaults: last 30 days through today; shows completed and closed tasks in range.
78110
+
78111
+ Use \`history\` for finished work; use \`list\` for active backlog items.
78112
+
78113
+ ### Add
78114
+ Content via **stdin / heredoc** or \`--content-file\`:
78115
+
78116
+ \`\`\`
78117
+ ${backlogAddCommand({ cliEnvPrefix })}
78118
+ \`\`\`
78119
+
78120
+ \`\`\`
78121
+ ${cliEnvPrefix}chatroom backlog add --chatroom-id=<id> --role=<role> --content-file=./task.md
78122
+ \`\`\`
78123
+
78124
+ ### Update
78125
+ Replace the **text content** of an existing item. Allowed only while the item is in \`backlog\` status. Same input pattern as **add** (stdin/heredoc or \`--content-file\`).
78126
+
78127
+ \`\`\`
78128
+ ${backlogUpdateCommand({ cliEnvPrefix })}
78129
+ \`\`\`
78130
+
78131
+ \`\`\`
78132
+ ${cliEnvPrefix}chatroom backlog update --chatroom-id=<id> --role=<role> --backlog-item-id=<id> --content-file=./revised.md
78133
+ \`\`\`
78134
+
78135
+ Use **update** to revise a description in place instead of adding a superseding item.
78136
+
78137
+ ### Score
78138
+ **Requires at least one** of \`--complexity\`, \`--value\`, or \`--priority\` (you can combine multiple).
78139
+
78140
+ \`\`\`
78141
+ ${cliEnvPrefix}chatroom backlog score --chatroom-id=<id> --role=<role> --backlog-item-id=<id> \\
78142
+ [--complexity=<low|medium|high>] \\
78143
+ [--value=<low|medium|high>] \\
78144
+ [--priority=<n>]
78145
+ \`\`\`
78146
+
78147
+ \`--priority\` must be an integer (higher = more important). There is no enforced max in the CLI.
78148
+
78149
+ **Important**: Only score items that do not already have all three fields set (complexity, value, priority).
78150
+ Check the list output — items showing "Score: ..." are already scored. Skip them to avoid overwriting.
78151
+
78152
+ ### Complete
78153
+ \`\`\`
78154
+ ${cliEnvPrefix}chatroom backlog complete --chatroom-id=<id> --role=<role> --backlog-item-id=<id> [-f|--force]
78155
+ \`\`\`
78156
+
78157
+ Optional \`-f\` / \`--force\` is a registered flag (see \`chatroom backlog complete --help\`). It is **not** forwarded to the Convex mutation yet, so it does not change server behavior today; omit it unless your runbook says otherwise.
78158
+
78159
+ ### Reopen
78160
+ \`\`\`
78161
+ ${cliEnvPrefix}chatroom backlog reopen --chatroom-id=<id> --role=<role> --backlog-item-id=<id>
78162
+ \`\`\`
78163
+
78164
+ ### Mark for Review
78165
+ \`\`\`
78166
+ ${cliEnvPrefix}chatroom backlog mark-for-review --chatroom-id=<id> --role=<role> --backlog-item-id=<id>
78167
+ \`\`\`
78168
+
78169
+ ### Export
78170
+ \`\`\`
78171
+ ${cliEnvPrefix}chatroom backlog export --chatroom-id=<id> --role=<role> [--path=<directory>]
78172
+ \`\`\`
78173
+ Exports all backlog items (status=\`backlog\`) to a \`backlog-export.json\` file in the specified directory.
78174
+ Creates the directory if it doesn't exist.
78175
+ Default path (if \`--path\` is omitted): \`<cwd>/.chatroom/exports/\`
78176
+
78177
+ ### Import
78178
+ \`\`\`
78179
+ ${cliEnvPrefix}chatroom backlog import --chatroom-id=<id> --role=<role> [--path=<directory>]
78180
+ \`\`\`
78181
+ Imports backlog items from a \`backlog-export.json\` file in the specified directory.
78182
+ - **Idempotent**: skips items whose content already exists (matched by SHA-256 content hash)
78183
+ - **Staleness warning**: warns if the export is older than 7 days
78184
+ Default path (if \`--path\` is omitted): \`<cwd>/.chatroom/exports/\`
78185
+
78186
+ ### Close
78187
+ Retires an item as stale, superseded, or duplicate. **\`--reason\` is required** (audit trail).
78188
+
78189
+ \`\`\`
78190
+ ${cliEnvPrefix}chatroom backlog close --chatroom-id=<id> --role=<role> --backlog-item-id=<id> --reason="duplicate of XYZ"
78191
+ \`\`\`
78192
+
78193
+ ⚠️ **RESTRICTED: Only use when the user explicitly asks you to close an item.**
78194
+ Agents must NEVER close backlog items autonomously. If an item looks stale or already implemented, prefer \`mark-for-review\` so the user decides.
78195
+
78196
+ Give a concise, factual reason (e.g. \`User confirmed: shipped in PR #119\`).
78197
+
78198
+ ---
78199
+
78200
+ ## Lifecycle
78201
+
78202
+ Backlog items move through explicit statuses. **When you raise a PR for user review, use \`mark-for-review\` — not \`complete\`.** Only mark \`complete\` after the PR is merged and verified (or the user confirms).
78203
+
78204
+ \`\`\`mermaid
78205
+ stateDiagram-v2
78206
+ [*] --> backlog: user creates
78207
+ backlog --> pending_user_review: agent raises PR (mark-for-review)
78208
+ pending_user_review --> closed: user confirms / PR merged (complete)
78209
+ backlog --> closed: stale/superseded (close)
78210
+ closed --> backlog: reopen
78211
+ \`\`\`
78212
+
78213
+ ### Command decision table
78214
+
78215
+ | Situation | Command |
78216
+ |-----------|---------|
78217
+ | Fix PR opened, awaiting user review/merge | \`mark-for-review\` |
78218
+ | PR merged and verified | \`complete\` |
78219
+ | Stale/duplicate/won't fix | \`close --reason=...\` |
78220
+ | Mistakenly completed early | \`reopen\` then \`mark-for-review\` |
78221
+
78222
+ Reference: \`docs/plans/backlog-item-lifecycle-and-attachments.md\`
78223
+
78224
+ ---
78225
+
78226
+ ## Workflows
78227
+
78228
+ ### 1. Score Unscored Items
78229
+
78230
+ \`\`\`mermaid
78231
+ flowchart TD
78232
+ A([Start]) --> B[List backlog items]
78233
+ B --> C{Any unscored?}
78234
+ C -->|No| D([Done])
78235
+ C -->|Yes| E["Check item: does it already have complexity + value + priority set?"]
78236
+ E -->|Already scored| F[Skip — do not overwrite existing score]
78237
+ F --> C
78238
+ E -->|Not scored| G[Score item: complexity, value, priority]
78239
+ G --> C
78240
+ \`\`\`
78241
+
78242
+ An item is "already scored" if the list output shows "Score: complexity=... | value=... | priority=...".
78243
+
78244
+ ### 2. After Completing a Backlog Task (PR raised)
78245
+
78246
+ \`\`\`mermaid
78247
+ flowchart TD
78248
+ A([Implementation complete]) --> B[Open PR for user review]
78249
+ B --> C["mark-for-review (NOT complete)"]
78250
+ C --> D[Hand off to user with PR link + summary]
78251
+ D --> E([User reviews in Pending Review section])
78252
+ \`\`\`
78253
+
78254
+ Moves item to \`pending_user_review\`. User confirms completion (\`complete\`) or sends back for rework (\`reopen\`).
78255
+
78256
+ ### 3. Continuous Backlog Execution
78257
+
78258
+ Only activate when the user explicitly instructs autonomous execution
78259
+ (e.g. "work through the backlog", "autonomously implement backlog items").
78260
+
78261
+ \`\`\`mermaid
78262
+ flowchart TD
78263
+ A([Start]) --> B[List all backlog items]
78264
+ B --> C{Any unscored?}
78265
+ C -->|Yes| D["Score only items missing complexity/value/priority\\n(skip already-scored items)"] --> E[Re-list]
78266
+ C -->|No| E
78267
+ E --> F["Select items: complexity=low AND value=high"]
78268
+ F --> G{Qualifying items?}
78269
+ G -->|No| H([Hand off — no high-ROI items found])
78270
+ G -->|Yes| I[Take next item]
78271
+ I --> J{Already implemented?\\nCheck codebase / recent commits}
78272
+ J -->|Yes — stale| K["Mark for review\\n(note: already implemented)"]
78273
+ J -->|No| L[Implement: code changes + PR]
78274
+ L --> K
78275
+ K --> M[Mark item for review]
78276
+ M --> N{More items?}
78277
+ N -->|Yes| I
78278
+ N -->|No| O[Hand off to user with full summary]
78279
+ O --> P([Done])
78280
+ \`\`\`
78281
+
78282
+ Stale item = backlog task already present in the codebase. Mark immediately; skip implementation.
78283
+ ROI = low complexity × high value.
78284
+
78285
+ ### 4. Backlog Cleanup
78286
+
78287
+ Follow these steps to clean up the backlog by identifying and closing stale items.
78288
+
78289
+ 1. List all backlog items:
78290
+ \`\`\`
78291
+ ${cliEnvPrefix}chatroom backlog list --chatroom-id=<id> --role=<role>
78292
+ \`\`\`
78293
+
78294
+ 2. For each item, assess staleness:
78295
+ - Read the content carefully
78296
+ - If the item is still valid but the **wording is wrong**, use \`backlog update\` to fix the description in place (do not add a duplicate item)
78297
+ - Check if already implemented (look at recent commits, PRs, or existing code)
78298
+ - Check if superseded by a newer backlog item
78299
+
78300
+ 3. For stale items, mark for review:
78301
+ \`\`\`
78302
+ ${cliEnvPrefix}chatroom backlog mark-for-review --chatroom-id=<id> --role=<role> --backlog-item-id=<item-id>
78303
+ \`\`\`
78304
+ **Important:** Always mark for review — do NOT close directly. Let the user confirm.
78305
+
78306
+ 4. If you are the coordinator, delegate assessment to workers:
78307
+ - Builder checks codebase to determine if items are stale
78308
+ - Builder marks stale items for review and reports back
78309
+
78310
+ 5. Report summary: items reviewed, marked for review, kept, needs clarification
78311
+
78312
+ ### 5. Export / Import Backlog
78313
+
78314
+ Use export/import to transfer backlog items between workspaces or for backup.
78315
+ Default path: \`<cwd>/.chatroom/exports/\` — omit \`--path\` to use this.
78316
+
78317
+ **Export workflow:**
78318
+ \`\`\`mermaid
78319
+ flowchart TD
78320
+ A([Start]) --> B["Export backlog"]
78321
+ B --> C["chatroom backlog export\\n(writes to <cwd>/.chatroom/exports/ by default)"]
78322
+ C --> D["File written: backlog-export.json"]
78323
+ D --> E([Done — report file path to user])
78324
+ \`\`\`
78325
+
78326
+ **Import workflow:**
78327
+ \`\`\`mermaid
78328
+ flowchart TD
78329
+ A([Start]) --> B["Import backlog"]
78330
+ B --> C["chatroom backlog import\\n(reads from <cwd>/.chatroom/exports/ by default)"]
78331
+ C --> D{Staleness warning?}
78332
+ D -->|Yes — export > 7 days old| E["Warn user: export may be stale"]
78333
+ D -->|No| F["Import items (skip duplicates)"]
78334
+ E --> F
78335
+ F --> G["Report: total / imported / skipped"]
78336
+ G --> H([Done])
78337
+ \`\`\`
78338
+
78339
+ **Key points:**
78340
+ - Default path is \`<cwd>/.chatroom/exports/\` — no \`--path\` needed for standard usage
78341
+ - Use \`--path=<dir>\` to override with a custom directory
78342
+ - Imports are idempotent — running import twice with the same file won't create duplicates
78343
+ - Each item is identified by a SHA-256 hash of its content`
78344
+ };
77773
78345
  });
77774
78346
 
77775
78347
  // ../../services/backend/src/domain/usecase/skills/modules/code-review/index.ts
77776
- var init_code_review = () => {};
78348
+ var codeReviewSkill;
78349
+ var init_code_review = __esm(() => {
78350
+ codeReviewSkill = {
78351
+ skillId: "code-review",
78352
+ name: "Code Review",
78353
+ description: "Use this skill when reviewing, auditing, or giving feedback on code. Covers ten pillars: simplification, type drift, duplication, design patterns, security, test quality, ownership/observability, dead code elimination, incomplete implementations, and hallucinated content.",
78354
+ getPrompt: (_cliEnvPrefix) => `You have been activated with the "code-review" skill.
78355
+
78356
+ # AI Code Review — Tech Debt Prevention
78357
+
78358
+ You are reviewing code that was fully or partially generated by an AI tool. Your job is not
78359
+ just to check if it works — working code is the floor, not the ceiling. Your job is to assess
78360
+ whether it is maintainable, secure, and coherent with the broader codebase.
78361
+
78362
+ AI code is highly functional but architecturally blind. It implements the prompt without
78363
+ considering existing patterns, refactoring opportunities, or long-term cost. Research from
78364
+ 2025–2026 shows AI code carries 1.75x more logic errors, 1.64x more maintainability issues,
78365
+ and 1.57x more security findings than human-written code (CodeRabbit, 2025). 66% of developers
78366
+ report spending more time fixing AI output than it saved (Stack Overflow, 2026).
78367
+
78368
+ Apply the ten pillars below in priority order.
78369
+
78370
+ ---
78371
+
78372
+ ## How to run a review
78373
+
78374
+ 1. Read the code in full before making any comments — do not flag issues as you scan
78375
+ 2. Apply each pillar in order; stop and note findings as you go
78376
+ 3. Classify each finding as BLOCK (must fix before merge) or FLAG (must be addressed by author)
78377
+ 4. Summarise findings at the end using the output template below
78378
+ 5. If the PR is over ~300 lines of net-new AI code, recommend decomposition before review
78379
+
78380
+ ---
78381
+
78382
+ ## Pillar 1 — Simplification (Highest Priority)
78383
+
78384
+ AI generates more code than needed. The average developer checked in 75% more code in 2025
78385
+ than in 2022 — volume that the team now has to maintain. AI agents never suggest refactoring,
78386
+ so complexity accumulates silently.
78387
+
78388
+ Look for:
78389
+ - Functions over ~40 lines or classes over ~200 lines with no clear single responsibility
78390
+ - Monolithic architecture: 40–50% of AI code defaults to tightly-coupled structures that
78391
+ reverse a decade of modular progress (OX Security, 2025)
78392
+ - Phantom Bugs: logic handling highly improbable edge cases, adding complexity with no benefit
78393
+ (found in 20–30% of AI code)
78394
+ - Dead code, unused imports, or leftover scaffolding from generation
78395
+ - PRs that touch services, libraries, infrastructure, and tests in a single change
78396
+
78397
+ Ask: Is there a simpler path to the same outcome? Would a new team member understand this
78398
+ without help? Can this function be split without losing meaning?
78399
+
78400
+ Action: Flag any function over ~40 lines. Require decomposition or written justification
78401
+ before merge.
78402
+
78403
+ ---
78404
+
78405
+ ## Pillar 2 — Type Drift (High Priority)
78406
+
78407
+ AI generates code in isolation from the broader type system. Type inconsistencies introduced
78408
+ here surface later as null pointer exceptions, silent failures, and cross-service contract
78409
+ mismatches. A University of Naples study of 500k+ samples (Aug 2025) confirmed these are the
78410
+ most reliably catchable issues via static analysis — meaning they should never reach review.
78411
+
78412
+ Look for:
78413
+ - \`any\` usage: defeats TypeScript entirely; AI reaches for it when uncertain
78414
+ - Unsafe \`as\` assertions: suppresses the compiler rather than satisfying it
78415
+ - Missing \`strictNullChecks\` compliance — null/undefined slipping through unchecked
78416
+ - Boundary drift: API endpoints returning different shapes across execution paths
78417
+ - Configuration drift: divergent \`tsconfig\` settings or ESLint rules added incrementally
78418
+ - Leaked internals: AI exposing implementation details that should be encapsulated
78419
+
78420
+ Ask: Are all return types and parameters explicitly typed? Are API contract types shared and
78421
+ stable? Does this match existing type conventions, or introduce a new pattern?
78422
+
78423
+ Action: \`strict: true\` in \`tsconfig.json\` is a hard gate. Any PR disabling strict settings
78424
+ requires explicit team sign-off.
78425
+
78426
+ ---
78427
+
78428
+ ## Pillar 3 — Duplication (High Priority)
78429
+
78430
+ GitClear's 2025 analysis of 211 million changed lines found duplicated code blocks grew 8x
78431
+ in one year, and copy/pasted code surpassed refactored code for the first time in history.
78432
+ OX Security found "Bugs Déjà-Vu" in 70–80% of AI codebases: identical bugs recurring in
78433
+ multiple locations because logic was never abstracted.
78434
+
78435
+ Look for:
78436
+ - Duplicate utility logic across files — each instance works, but no shared abstraction exists
78437
+ - "Vanilla Style" rebuilds: AI reconstructing functionality from scratch instead of using
78438
+ existing libraries, SDKs, or internal utilities (40–50% of AI code, OX Security)
78439
+ - Duplicated validation, auth checks, and input sanitization
78440
+ - Copy-pasted try/catch blocks instead of centralised error handling
78441
+ - New dependencies that the existing codebase already covers
78442
+
78443
+ Ask: Does an equivalent utility already exist? Is this logic duplicated anywhere else?
78444
+ Use AST-level search, not just grep.
78445
+
78446
+ Action: Require a codebase search before approving any new utility function. Run SonarQube,
78447
+ CodeClimate, or Codacy as a PR gate for duplication thresholds.
78448
+
78449
+ ---
78450
+
78451
+ ## Pillar 4 — Design Pattern Compliance (Standard Priority)
78452
+
78453
+ AI implements the prompt. It does not check the ADR log, existing service patterns, or
78454
+ architectural conventions. OX Security identified "By-The-Book Fixation" in 80–90% of AI
78455
+ code: rigid application of generic best practices, missing the better solution for this
78456
+ specific context.
78457
+
78458
+ Look for:
78459
+ - Pattern violations: raw \`fetch\` where an API service layer exists; new state patterns where
78460
+ a store convention is already established
78461
+ - SOLID violations:
78462
+ - Single Responsibility: see Pillar 1
78463
+ - Open/Closed: code requiring modification rather than extension to add new behaviour
78464
+ - Dependency Inversion: hard-coded dependencies instead of injection
78465
+ - No refactoring suggestions — AI never proposes that a feature should trigger a refactor
78466
+ - Context blindness: ignoring ADRs, versioning strategy, or team-level conventions
78467
+
78468
+ Ask: Does this follow the patterns in this area of the codebase? Can this be extended without
78469
+ modification? Are dependencies injected?
78470
+
78471
+ Action: Maintain a living \`ARCHITECTURE.md\` or ADR log. Pass it as context to AI tools before
78472
+ generation, not after.
78473
+
78474
+ ---
78475
+
78476
+ ## Pillar 5 — Security (Standard Priority)
78477
+
78478
+ 45% of AI-generated code samples introduced OWASP Top 10 vulnerabilities in Veracode's 2025
78479
+ test of 100+ LLMs. CodeRabbit found AI code is 2.74x more likely to introduce XSS, 1.88x more
78480
+ likely to mishandle passwords, 1.82x more likely to implement insecure deserialization.
78481
+ OX Security calls this "insecure by dumbness" — not malicious, but structurally blind to
78482
+ security requirements that were not in the prompt.
78483
+
78484
+ Look for:
78485
+ - OWASP Top 10: injection (SQL, XSS, command), broken auth, insecure deserialization
78486
+ - "Worked on My Machine" syndrome (60–70% of AI code): missing environment awareness,
78487
+ hard-coded localhost references, assumed-present secrets
78488
+ - Missing auth/ownership checks — AI assumes the happy path; role gates rarely appear unprompted
78489
+ - Secrets, tokens, or credentials in source code
78490
+ - Deprecated API patterns from the model's training data
78491
+ - Excessive I/O (~8x human rate) and concurrency misuse (~2x human rate)
78492
+
78493
+ Ask: Are all inputs validated before use? Are auth checks present at every trust boundary?
78494
+ Does this code behave differently across environments?
78495
+
78496
+ Action: Run SAST tooling (Snyk, Semgrep, SonarQube) on every AI-generated PR as a CI gate.
78497
+ Manual review alone cannot keep pace with AI generation velocity.
78498
+
78499
+ ---
78500
+
78501
+ ## Pillar 6 — Test Quality (Standard Priority)
78502
+
78503
+ AI generates tests that look comprehensive but frequently are not. OX Security found "Fake
78504
+ Test Coverage" in 40–50% of AI codebases: inflated metrics, low signal. The failure mode is
78505
+ precise: AI tests its own assumptions, not the developer's intent. University of Naples (2025)
78506
+ confirmed that even code passing all functional benchmarks averaged 1.45–1.77 static issues
78507
+ per task.
78508
+
78509
+ Look for:
78510
+ - Tests that verify AI output is stable, not that it is correct by domain rules
78511
+ - Missing edge cases: empty inputs, boundary values, null handling, race conditions,
78512
+ business-rule violations
78513
+ - Coverage theater: tests that assert no exception was thrown and nothing more
78514
+ - No integration or contract tests — AI generates unit tests almost exclusively
78515
+ - Tests coupled to implementation: must be updated every time the code changes
78516
+
78517
+ Ask: Do these tests verify the domain intent? Would they catch a logic regression in the
78518
+ next PR? Are cross-service interactions tested?
78519
+
78520
+ Action: Test review is a separate pass from code review. Use mutation testing (Stryker,
78521
+ PITest) to validate whether tests catch real defects — coverage percentage is not sufficient.
78522
+
78523
+ ---
78524
+
78525
+ ## Pillar 7 — Ownership, Observability, Deployment (Standard Priority)
78526
+
78527
+ The most consistently missed category. ISACA's 2026 incident review found that the biggest
78528
+ AI failures of 2025 were organisational, not technical: weak controls and unclear ownership.
78529
+ Bright Security (2026) identified unclear ownership as one of the most dangerous patterns:
78530
+ code that works well enough that no one feels responsible for it. IBM's 2025 breach data found
78531
+ shadow AI added $670,000 average to breach costs.
78532
+
78533
+ Look for:
78534
+ - No named human owner — every AI-generated module needs someone who can explain it in a
78535
+ postmortem without reading it fresh
78536
+ - Missing structured logs, metrics emission, or tracing hooks
78537
+ - Swallowed exceptions: retry logic with no alerting; fallback paths invisible to operators
78538
+ - No environment-specific configuration, secrets management, or health check endpoints
78539
+ - Model versioning chaos: inconsistencies from team members using different AI tool versions
78540
+ - Shadow AI: code with no record of which tool or prompt produced it
78541
+
78542
+ Ask: Who owns this? Will production failures surface to operators? Does this behave
78543
+ differently across environments?
78544
+
78545
+ Action: Require every AI-generated module to have a named owner in CODEOWNERS. Add logging
78546
+ requirements to the PR template. Establish a team AI governance policy that tracks tools
78547
+ and model versions — treat this like any other dependency.
78548
+
78549
+ ---
78550
+
78551
+ ## Pillar 8 — Dead Code Elimination (Standard Priority)
78552
+
78553
+ AI generates code speculatively. It adds helper functions "just in case", creates abstractions
78554
+ for paths that never materialise, and leaves behind scaffolding from earlier generation
78555
+ attempts. GitClear's 2025 data showed a 75% increase in total code volume, much of it never
78556
+ executed. Dead code is not harmless — it misleads future readers, inflates bundle sizes, creates
78557
+ false positive search results, and adds surface area for bugs and security vulnerabilities
78558
+ in code that serves no purpose.
78559
+
78560
+ Look for:
78561
+ - Unreachable code: functions, methods, or branches that no call site ever invokes
78562
+ - Unused imports: modules imported but never referenced — common in AI-generated files
78563
+ - Commented-out code: old implementations left inline instead of being removed; version
78564
+ control already preserves history
78565
+ - Feature flags that are permanently off: conditional paths that were never enabled or have
78566
+ been superseded but not cleaned up
78567
+ - Orphaned configuration: environment variables, constants, or config entries with no consumer
78568
+ - Stale types and interfaces: type definitions for data shapes that no longer exist in the
78569
+ system
78570
+ - Unused dependencies: packages listed in \`package.json\` (or equivalent) that no source file
78571
+ imports
78572
+ - Vestigial error handling: catch blocks or fallback paths for conditions that can no longer
78573
+ occur due to upstream changes
78574
+ - Test helpers and fixtures for tests that have been deleted
78575
+
78576
+ Ask: Is every function called? Is every import used? Is every dependency exercised?
78577
+ Would removing this code change any observable behaviour?
78578
+
78579
+ Action: Run tree-shaking analysis and dead code detection tools (e.g., \`ts-prune\`,
78580
+ \`knip\`, \`depcheck\`, IDE unused-symbol highlighting) as part of CI. Treat dead code
78581
+ the same as duplication — it compounds over time and must be actively managed.
78582
+
78583
+ ---
78584
+
78585
+ ## Pillar 9 — Incomplete Implementations (Standard Priority)
78586
+
78587
+ AI tools often leave TODOs, stubs, "throw new Error('not implemented')", or placeholder
78588
+ returns when they hit uncertainty. The default assumption MUST be that these are bugs to fix,
78589
+ not features — unless the human explicitly requested a stub (e.g., scaffolding a future module).
78590
+
78591
+ Look for:
78592
+ - \`TODO\`, \`FIXME\`, \`XXX\`, \`HACK\` comments — especially without an assignee or ticket reference
78593
+ - Functions that throw "not implemented" / "unimplemented" errors
78594
+ - Empty function bodies or bodies that only return null/undefined/empty object as a placeholder
78595
+ - Switch/case branches with \`// handle later\` style comments
78596
+ - Conditional branches that silently fall through without handling a real case
78597
+ - Type definitions with fields marked \`any\` or \`unknown\` "to be refined later"
78598
+ - Tests with \`it.skip\`, \`xit\`, \`it.todo\` left in committed code without justification
78599
+
78600
+ Ask: Is every code path fully implemented? If a TODO exists, is there a tracked ticket and
78601
+ explicit reason it wasn't done now?
78602
+
78603
+ Action: Treat any TODO or stub as BLOCK unless the PR description or commit message explicitly
78604
+ justifies it (e.g., "scaffolding for follow-up PR #N"). Generated code with unprompted TODOs
78605
+ should be completed before merge, not after.
78606
+
78607
+ ---
78608
+
78609
+ ## Pillar 10 — Hallucinated Content & Magic Strings (Standard Priority)
78610
+
78611
+ AI generation frequently invents plausible-looking but incorrect values — API endpoints,
78612
+ env var names, library functions, config keys — and scatters magic strings/numbers across
78613
+ the codebase instead of consolidating them as named constants. Both fail at runtime or rot
78614
+ the codebase over time.
78615
+
78616
+ Look for:
78617
+ - Fabricated API endpoints, library functions, or package names that don't exist (verify against
78618
+ actual SDK docs / \`package.json\`)
78619
+ - Magic strings: status codes, role names, event types, feature flag keys appearing as inline
78620
+ literals across multiple files
78621
+ - Magic numbers: timeouts, limits, retry counts, port numbers without named constants
78622
+ - Placeholder content left in production paths: "lorem ipsum", "foo/bar", "example.com",
78623
+ "test@test.com"
78624
+ - Hardcoded URLs, file paths, or table/collection names that should come from config
78625
+ - Duplicated string literals that should be a single enum / const object
78626
+ - Configuration keys invented by the AI that don't match the project's actual config schema
78627
+
78628
+ Ask: Does every literal that carries domain meaning have a named home? Is every external
78629
+ reference (API, package, env var) verified to exist? Where SHOULD this constant live (entity
78630
+ enum, config module, shared constants file)?
78631
+
78632
+ Action: Consolidate magic literals into the canonical location for the codebase (typically
78633
+ enums alongside the relevant entity, or a dedicated constants module). For hallucinated
78634
+ references, treat as BLOCK — code that compiles against fictional APIs will fail in production.
78635
+
78636
+ ---
78637
+
78638
+ ## Output template
78639
+
78640
+ Use this format for every review. Do not skip sections.
78641
+
78642
+ \`\`\`
78643
+ ## AI Code Review — [filename or PR title]
78644
+
78645
+ ### Summary
78646
+ [2–3 sentences: overall quality signal, highest-risk area, recommended action]
78647
+
78648
+ ### BLOCK — must fix before merge
78649
+ [List findings. Format: PILLAR | finding | why it matters | suggested fix]
78650
+
78651
+ ### FLAG — author must respond
78652
+ [List findings. Same format.]
78653
+
78654
+ ### Passed
78655
+ [Pillars or areas with no significant findings]
78656
+
78657
+ ### Recommendation
78658
+ [ ] Approve [ ] Approve with flags addressed [ ] Decompose PR first [ ] Reject — rework required
78659
+ \`\`\``
78660
+ };
78661
+ });
77777
78662
 
77778
78663
  // ../../services/backend/src/domain/usecase/skills/registry.ts
78664
+ var SKILLS_REGISTRY;
77779
78665
  var init_registry3 = __esm(() => {
77780
78666
  init_backlog();
77781
78667
  init_code_review();
78668
+ SKILLS_REGISTRY = [backlogSkill, codeReviewSkill];
77782
78669
  });
77783
78670
 
77784
78671
  // ../../services/backend/prompts/sections/glossary.ts
78672
+ function formatGlossaryEntry(entry) {
78673
+ const skillNote = entry.linkedSkillId ? " (1 skill available)" : "";
78674
+ return [`- \`${entry.term}\`${skillNote}`, ` - ${entry.definition}`, ""];
78675
+ }
78676
+ function buildSkillsSection(cliEnvPrefix) {
78677
+ const lines = ["# Skills", ""];
78678
+ lines.push(`Run \`${cliEnvPrefix}chatroom skill list --chatroom-id=<id> --role=<role>\` to list all available skills.`);
78679
+ lines.push("");
78680
+ lines.push("## When to Activate Skills");
78681
+ lines.push("");
78682
+ lines.push("**Proactively activate skills** when your task matches their purpose:");
78683
+ for (const skill of SKILLS_REGISTRY) {
78684
+ lines.push(`- **${skill.skillId}**: ${skill.description}`);
78685
+ }
78686
+ lines.push("");
78687
+ lines.push("Don't wait for the user to ask — proactively activate the skill that matches the task.");
78688
+ return lines;
78689
+ }
78690
+ function getGlossarySection(params) {
78691
+ const cliEnvPrefix = getCliEnvPrefix(params.convexUrl);
78692
+ const lines = ["# Glossary", ""];
78693
+ const terms = params.nativeIntegration ? NATIVE_GLOSSARY_TERMS : GLOSSARY_TERMS;
78694
+ for (const entry of terms) {
78695
+ lines.push(...formatGlossaryEntry(entry));
78696
+ }
78697
+ if (params.compactSkills) {
78698
+ lines.push("# Skills", "");
78699
+ lines.push(`Run \`${cliEnvPrefix}chatroom skill list --chatroom-id=<id> --role=<role>\` to list available skills. Activate skills proactively when your task matches their purpose.`);
78700
+ } else {
78701
+ lines.push(...buildSkillsSection(cliEnvPrefix));
78702
+ }
78703
+ return createSection("glossary", "knowledge", lines.join(`
78704
+ `));
78705
+ }
77785
78706
  var GLOSSARY_TERMS, NATIVE_GLOSSARY_TERMS;
77786
78707
  var init_glossary = __esm(() => {
77787
78708
  init_registry3();
@@ -77832,10 +78753,249 @@ var init_glossary = __esm(() => {
77832
78753
  });
77833
78754
 
77834
78755
  // ../../services/backend/prompts/cli/roles/builder.ts
78756
+ function getBuilderFlowMermaid(nativeIntegration, codeChangesTarget, questionTarget) {
78757
+ const handoffNodes = ` D --> E[Commit work]
78758
+ E --> F{Code changes?}
78759
+ F -->|yes| G[Hand off to **${codeChangesTarget}**]
78760
+ F -->|no| H[Hand off to **${questionTarget}**]`;
78761
+ if (nativeIntegration) {
78762
+ return `flowchart TD
78763
+ A([Start]) --> B[Receive task]
78764
+ B --> D[Implement changes]
78765
+ ${handoffNodes}`;
78766
+ }
78767
+ return `flowchart TD
78768
+ A([Start]) --> B[Receive chatroom task]
78769
+ B --> D[Implement changes]
78770
+ ${handoffNodes}`;
78771
+ }
78772
+ function getBuilderGuidance(params) {
78773
+ const {
78774
+ questionTarget: questionTargetParam,
78775
+ codeChangesTarget: codeChangesTargetParam,
78776
+ nativeIntegration
78777
+ } = params;
78778
+ const questionTarget = questionTargetParam ?? "user";
78779
+ const codeChangesTarget = codeChangesTargetParam ?? "planner";
78780
+ return `
78781
+ ## Builder Operating Model
78782
+
78783
+ ${getSessionContinuityLine(nativeIntegration)}
78784
+
78785
+ You are responsible for implementing code changes based on requirements.
78786
+
78787
+ **Typical Flow:**
78788
+
78789
+ \`\`\`mermaid
78790
+ ${getBuilderFlowMermaid(nativeIntegration, codeChangesTarget, questionTarget)}
78791
+ \`\`\`
78792
+
78793
+ **Handoff Rules:**
78794
+ - **After code changes** → Hand off to \`${codeChangesTarget}\`
78795
+ - **For simple questions** → Can hand off directly to \`${questionTarget}\`
78796
+ ⚠️ If \`${questionTarget}\` is the user: the user can ONLY see the handoff-to-user message — progress reports and all other messages are invisible to them. Write the handoff as a complete, self-contained document: include all relevant context, results, and next steps without assuming the user read any prior conversation.
78797
+
78798
+ **Implementation Guidelines:**
78799
+ - Write clean, maintainable, well-documented code
78800
+ - Follow established patterns and best practices from the codebase
78801
+ - Handle edge cases and error scenarios
78802
+ - Commit work with descriptive, atomic commit messages
78803
+ `;
78804
+ }
77835
78805
  var init_builder = () => {};
78806
+
78807
+ // ../../services/backend/prompts/cli/sections/core-responsibilities.ts
78808
+ function getCoreResponsibilitiesSection(config3) {
78809
+ const qualityLine = config3.hasBuilder ? "If the user's requirements are not met, hand work back to the builder for rework." : "If the work doesn't meet requirements, revise it yourself before delivering.";
78810
+ return `**Core Responsibilities:**
78811
+ - **User Communication**: You are the ONLY role that communicates with the user. All responses to the user come through you.
78812
+ - **Handoff completeness**: The user can ONLY see the final handoff-to-\`user\` message. Write it as a complete, standalone document — do not reference prior messages or assume the user has context from earlier session text.
78813
+ - **Quality Accountability**: You are ultimately accountable for all work. ${qualityLine}`;
78814
+ }
78815
+
78816
+ // ../../services/backend/prompts/cli/sections/delegation-and-decomposition.ts
78817
+ function getDelegationAndDecompositionSection(config3) {
78818
+ if (!config3.hasBuilder) {
78819
+ return "";
78820
+ }
78821
+ return `**Delegation & Decomposition:**
78822
+
78823
+ Any task that requires code changes must be delegated to the builder — break it into small, focused slices and delegate them one at a time using a **Delegation Brief** (see **Delegation Guidelines** below).`;
78824
+ }
78825
+
78826
+ // ../../services/backend/prompts/cli/sections/delegation-guidelines.ts
78827
+ function buildCmdHelper(cliEnvPrefix, chatroomIdArg, roleArg) {
78828
+ return (subcommand) => `\`${cliEnvPrefix}chatroom ${subcommand} --chatroom-id=${chatroomIdArg} --role=${roleArg}\``;
78829
+ }
78830
+ function getDelegationBriefReference() {
78831
+ return "Use the **Handoff to `builder`** template in the task delivery `<handoff-templates>` section — follow that structure in your handoff message.";
78832
+ }
78833
+ function getSoloImplementationGuidelines(cmd, feedingNote) {
78834
+ return `**Implementation Guidelines:**
78835
+
78836
+ Break complex features into small, focused slices. For code review guidance, activate the \`code-review\` skill: ${cmd("skill activate code-review")}.
78837
+
78838
+ - Implement one slice at a time; each slice ≈ one focused review surface.
78839
+ - Review your own work before moving on; re-validate after rework.
78840
+ - ${feedingNote}.`;
78841
+ }
78842
+ function getBuilderDelegationGuidelines(cmd, feedingNote, delegationBriefRef) {
78843
+ return `**Delegation Guidelines:**
78844
+
78845
+ Break features into small, focused slices, then delegate them to the builder one at a time. For code review guidance, activate the \`code-review\` skill: ${cmd("skill activate code-review")}.
78846
+
78847
+ **Delegation rule:** If the task requires **any code changes** (new files, edits, deletions), you **must delegate to the builder** — regardless of how small the change is.
78848
+
78849
+ **Decision flow:**
78850
+ \`\`\`mermaid
78851
+ flowchart TD
78852
+ A[Receive task] --> B{Code changes needed?}
78853
+ B -->|Yes — any size| D[Write a Delegation Brief]
78854
+ D --> E[Hand off ONE slice to builder]
78855
+ E --> F[Review output]
78856
+ F -->|Not acceptable| G[Hand back with feedback]
78857
+ G --> E
78858
+ F -->|Acceptable| H{More slices?}
78859
+ H -->|Yes| E
78860
+ H -->|No| I[Deliver to user]
78861
+ B -->|No: question or clarification only| C[Answer directly → deliver to user]
78862
+ \`\`\`
78863
+
78864
+ **Default: delegate with a Delegation Brief.** ${delegationBriefRef}
78865
+
78866
+ **How to slice the work** — think about the phases a human engineer would actually go through to ship the work, then make each phase a slice. Some heuristics:
78867
+
78868
+ - **Each slice should name a concrete artifact** ("the X schema", "the Y entity", "the Z endpoint") — not a vague layer ("backend work", "implementation"). Weak builders fail when scope is unbounded.
78869
+ - **File-level detail, zero ambiguity.** List every file (full paths) and paste snippets until the builder cannot guess wrong — not vague layers ("backend work", "the component").
78870
+ - **You own technical design; the builder executes.** Per-file target code plus shared contracts in the brief — do not leave API shape for the builder to invent.
78871
+ - **Spell out what to avoid** — anti-patterns and recurring mistakes you have seen from builders on similar work (scope creep, wrong abstractions, forbidden refactors).
78872
+ - **One slice ≈ one focused review surface.** If you can't imagine reviewing it in one sitting, split it.
78873
+ - **Order by dependency**, not by team convention. A slice should be runnable/testable when its dependencies are done.
78874
+ - **Skip phases that don't apply** (e.g., no frontend for a backend-only change, no schema for a pure refactor).
78875
+
78876
+ **Code review:** For code-producing work, review before delivering. Activate the review framework with: ${cmd("skill activate code-review")}.
78877
+
78878
+ **Backlog items:** When the task originates from a backlog item, activate the backlog skill: ${cmd("skill activate backlog")}.
78879
+
78880
+ **If stuck:** After 2 failed rework attempts → step back, replan the slice, or deliver partial results with a clear explanation.
78881
+
78882
+ **Review loop:**
78883
+ - Review completed work before moving to the next slice.
78884
+ - Send back with specific feedback if requirements aren't met.
78885
+ - ${feedingNote}.`;
78886
+ }
78887
+ function getDelegationGuidelinesSection(config3, options) {
78888
+ const feedingNote = config3.hasBuilder ? "Feed slices to the builder incrementally — one at a time, not all at once" : "When implementing yourself, tackle one layer at a time — avoid large monolithic changes";
78889
+ const cliEnvPrefix = options?.cliEnvPrefix ?? "";
78890
+ const chatroomIdArg = options?.chatroomId ? `"${options.chatroomId}"` : "<id>";
78891
+ const roleArg = options?.role ? `"${options.role}"` : "<role>";
78892
+ const cmd = buildCmdHelper(cliEnvPrefix, chatroomIdArg, roleArg);
78893
+ if (!config3.hasBuilder) {
78894
+ return getSoloImplementationGuidelines(cmd, feedingNote);
78895
+ }
78896
+ return getBuilderDelegationGuidelines(cmd, feedingNote, getDelegationBriefReference());
78897
+ }
78898
+
77836
78899
  // ../../services/backend/prompts/cli/sections/handoff-rules.ts
78900
+ function buildHandoffRuleLines(config3) {
78901
+ return [
78902
+ config3.hasBuilder ? "- **To delegate implementation** → Hand off to `builder` with clear requirements" : "- **To implement** → Work on the chatroom task directly (you are acting as implementer)",
78903
+ "- **To deliver to user** → Hand off to `user` with a complete, standalone summary\n ⚠️ The user can ONLY see the handoff-to-user message — progress reports and all other messages are invisible to them. Write the handoff as a self-contained document: include all relevant context, results, and next steps without assuming the user read any prior conversation.",
78904
+ config3.hasBuilder ? "- **For rework** → Hand off back to `builder` with specific feedback on what needs to change" : "- **For rework** → Revise your implementation directly and re-validate"
78905
+ ].join(`
78906
+ `);
78907
+ }
78908
+ function getHandoffRulesSection(config3, nativeIntegration) {
78909
+ const continuityRule = getHandoffContinuityRule(nativeIntegration);
78910
+ const continuityBlock = continuityRule ? `${continuityRule}
78911
+
78912
+ ` : "";
78913
+ return `**Handoff Rules:**
78914
+
78915
+ ${continuityBlock}${buildHandoffRuleLines(config3)}`;
78916
+ }
77837
78917
  var init_handoff_rules = () => {};
78918
+
78919
+ // ../../services/backend/prompts/cli/sections/when-work-comes-back.ts
78920
+ function getWhenWorkComesBackSection(config3) {
78921
+ const reworkLine = config3.hasBuilder ? "3. If requirements are NOT met → hand back to `builder` for rework" : "3. If requirements are NOT met → revise your own implementation and re-validate";
78922
+ return `**When you receive work back from team members:**
78923
+ 1. Review the completed work against the original user request
78924
+ 2. If requirements are met → deliver to \`user\`
78925
+ ${reworkLine}
78926
+ 4. **No ceremonial handoffs** — never hand back just to acknowledge, thank, or echo receipt. A handback to the sender is only valid when it carries concrete rework feedback (step 3). Handoffs to \`user\` are reserved for the final deliverable from the entry-point role.`;
78927
+ }
78928
+
78929
+ // ../../services/backend/prompts/cli/sections/team-composition.ts
78930
+ function getTeamCompositionSection(teamMembers) {
78931
+ const isSoloRole = teamMembers.length === 1 && teamMembers[0]?.toLowerCase() === "solo";
78932
+ const nonPlannerMembers = teamMembers.filter((r) => r.toLowerCase() !== "planner");
78933
+ if (isSoloRole || nonPlannerMembers.length === 0) {
78934
+ return `**Team composition:** Solo team — you handle planning and implementation yourself.`;
78935
+ }
78936
+ const roleList = nonPlannerMembers.map((r) => `\`${r}\``).join(", ");
78937
+ return `**Team composition:** Duo team — you coordinate with ${roleList} for implementation.
78938
+
78939
+ **Agent presence:** This prompt does **not** tell you who is online. Other agents may be offline. Delegate code-changing work by handing off when appropriate; do not infer availability from team configuration or prior chat history.`;
78940
+ }
78941
+
77838
78942
  // ../../services/backend/prompts/cli/sections/operating-model.ts
78943
+ function getTaskIntakeNodes(nativeIntegration) {
78944
+ if (nativeIntegration) {
78945
+ return ` A([Start]) --> B[Receive user message]
78946
+ B --> E[Decompose into phases]`;
78947
+ }
78948
+ return ` A([Start]) --> B[Receive chatroom task from get-next-task]
78949
+ B --> E[Decompose into phases]`;
78950
+ }
78951
+ function getOperatingModelSection(config3, nativeIntegration) {
78952
+ if (config3.hasBuilder) {
78953
+ return getPlannerPlusBuilderOperatingModel(nativeIntegration);
78954
+ }
78955
+ return getPlannerSoloOperatingModel(nativeIntegration);
78956
+ }
78957
+ function getPlannerPlusBuilderOperatingModel(nativeIntegration) {
78958
+ const footer = getOperatingModelLoopFooter(nativeIntegration);
78959
+ const delegationNote = nativeIntegration ? getNativePlannerDelegationWaitNote() : "After delegating to the builder, hand off and wait for work to return.";
78960
+ return `**Operating model: Planner + Builder**
78961
+
78962
+ ${delegationNote}
78963
+
78964
+ \`\`\`mermaid
78965
+ flowchart TD
78966
+ ${getTaskIntakeNodes(nativeIntegration)}
78967
+ E --> F[Delegate ONE phase to builder]
78968
+ F --> G[Builder completes phase]
78969
+ G --> H[Builder hands off to planner]
78970
+ H --> I[Review builder output]
78971
+ I --> J{phase acceptable?}
78972
+ J -->|no| K[Hand back to builder with feedback]
78973
+ K --> F
78974
+ J -->|yes| L{more phases?}
78975
+ L -->|yes| F
78976
+ L -->|no| O[Deliver final result to user]
78977
+ O --> P[${footer}] --> B
78978
+ \`\`\``;
78979
+ }
78980
+ function getPlannerSoloOperatingModel(nativeIntegration) {
78981
+ const continueStep = nativeIntegration ? "Hand off when complete" : "Run `get-next-task` to continue the session (Level A continues after Level B completes)";
78982
+ const intakeSteps = nativeIntegration ? `1. Receive user message
78983
+ 2. Plan and implement` : `1. Receive chatroom task from get-next-task
78984
+ 2. Plan and implement`;
78985
+ if (nativeIntegration) {
78986
+ return `**Operating model: Planner Solo**
78987
+
78988
+ ${intakeSteps}
78989
+ 3. Deliver to **user**
78990
+ 4. ${continueStep}`;
78991
+ }
78992
+ return `**Operating model: Planner Solo**
78993
+
78994
+ ${intakeSteps}
78995
+ 3. Review your own work for quality
78996
+ 4. Deliver to **user**
78997
+ 5. ${continueStep}`;
78998
+ }
77839
78999
  var init_operating_model = () => {};
77840
79000
 
77841
79001
  // ../../services/backend/prompts/cli/sections/index.ts
@@ -77845,17 +79005,126 @@ var init_sections = __esm(() => {
77845
79005
  });
77846
79006
 
77847
79007
  // ../../services/backend/prompts/cli/roles/planner.ts
79008
+ function getPlannerGuidance(params) {
79009
+ const { convexUrl, teamRoles, chatroomId, role, nativeIntegration } = params;
79010
+ const cliEnvPrefix = getCliEnvPrefix(convexUrl);
79011
+ const members = teamRoles;
79012
+ const hasBuilder = members.some((r) => r.toLowerCase() === "builder");
79013
+ const teamConfig = { hasBuilder };
79014
+ return `## Planner Operating Model
79015
+
79016
+ ${getSessionContinuityLine(nativeIntegration)}
79017
+
79018
+ You are the team coordinator and the **single point of contact** for the user.
79019
+
79020
+ ${getTeamCompositionSection(members)}
79021
+
79022
+ ${getOperatingModelSection(teamConfig, nativeIntegration)}
79023
+
79024
+ ${getCoreResponsibilitiesSection(teamConfig)}
79025
+
79026
+ ${getDelegationAndDecompositionSection(teamConfig)}
79027
+
79028
+ ${getDelegationGuidelinesSection(teamConfig, { cliEnvPrefix, chatroomId, role })}
79029
+
79030
+ ${getHandoffRulesSection(teamConfig, nativeIntegration)}
79031
+
79032
+ ${getWhenWorkComesBackSection(teamConfig)}`;
79033
+ }
77848
79034
  var init_planner = __esm(() => {
77849
79035
  init_env();
77850
79036
  init_sections();
77851
79037
  });
77852
79038
 
77853
79039
  // ../../services/backend/prompts/teams/solo/prompts/solo.ts
79040
+ function getSoloGuidance(ctx) {
79041
+ const { teamRoles, nativeIntegration } = ctx;
79042
+ return `## Solo Operating Model
79043
+
79044
+ ${getSessionContinuityLine(nativeIntegration)}
79045
+
79046
+ You are an autonomous agent responsible for BOTH planning and implementing chatroom tasks independently.
79047
+
79048
+ **Solo Team Context:**
79049
+ - You are the ONLY team member — you plan, implement, and deliver
79050
+ - You communicate directly with the user (single point of contact)
79051
+ - There is no separate builder or planner — you fill all roles
79052
+ - You hand off directly to the user when work is complete
79053
+
79054
+ ${getTeamCompositionSection(teamRoles)}
79055
+
79056
+ ${getPlannerSoloOperatingModel(nativeIntegration)}
79057
+
79058
+ ${getCoreResponsibilitiesSection(SOLO_TEAM_CONFIG)}
79059
+
79060
+ **Implementation Guidelines:**
79061
+ - Write clean, maintainable, well-documented code
79062
+ - Follow established patterns and best practices from the codebase
79063
+ - Handle edge cases and error scenarios
79064
+ - Commit work with descriptive, atomic commit messages
79065
+
79066
+ ${getHandoffRulesSection(SOLO_TEAM_CONFIG, nativeIntegration)}
79067
+
79068
+ ${getWhenWorkComesBackSection(SOLO_TEAM_CONFIG)}`;
79069
+ }
79070
+ var SOLO_TEAM_CONFIG;
77854
79071
  var init_solo = __esm(() => {
77855
79072
  init_sections();
79073
+ SOLO_TEAM_CONFIG = { hasBuilder: false };
77856
79074
  });
77857
79075
 
77858
79076
  // ../../services/backend/prompts/cli/roles/fromContext.ts
79077
+ function toBuilderParams(ctx) {
79078
+ return {
79079
+ role: ctx.role,
79080
+ teamRoles: ctx.teamRoles,
79081
+ isEntryPoint: ctx.isEntryPoint,
79082
+ convexUrl: ctx.convexUrl,
79083
+ nativeIntegration: ctx.nativeIntegration
79084
+ };
79085
+ }
79086
+ function toPlannerParams(ctx) {
79087
+ return {
79088
+ role: ctx.role,
79089
+ teamRoles: ctx.teamRoles,
79090
+ isEntryPoint: ctx.isEntryPoint,
79091
+ convexUrl: ctx.convexUrl,
79092
+ chatroomId: ctx.chatroomId,
79093
+ nativeIntegration: ctx.nativeIntegration
79094
+ };
79095
+ }
79096
+ function getBaseBuilderGuidanceFromContext(ctx) {
79097
+ return getBuilderGuidance(toBuilderParams(ctx));
79098
+ }
79099
+ function toSoloParams(ctx) {
79100
+ return {
79101
+ role: ctx.role,
79102
+ teamRoles: ctx.teamRoles,
79103
+ isEntryPoint: ctx.isEntryPoint,
79104
+ convexUrl: ctx.convexUrl,
79105
+ chatroomId: ctx.chatroomId,
79106
+ nativeIntegration: ctx.nativeIntegration
79107
+ };
79108
+ }
79109
+ function getSoloGuidanceFromContext(ctx) {
79110
+ return getSoloGuidance(toSoloParams(ctx));
79111
+ }
79112
+ function getBasePlannerGuidanceFromContext(ctx) {
79113
+ return getPlannerGuidance(toPlannerParams(ctx));
79114
+ }
79115
+ function getBaseRoleGuidanceFromContext(ctx) {
79116
+ const normalizedRole = ctx.role.toLowerCase();
79117
+ if (normalizedRole === "planner") {
79118
+ return getBasePlannerGuidanceFromContext(ctx);
79119
+ }
79120
+ if (normalizedRole === "builder") {
79121
+ return getBaseBuilderGuidanceFromContext(ctx);
79122
+ }
79123
+ if (normalizedRole === "solo") {
79124
+ return getSoloGuidanceFromContext(ctx);
79125
+ }
79126
+ return "";
79127
+ }
77859
79128
  var init_fromContext = __esm(() => {
77860
79129
  init_builder();
77861
79130
  init_planner();
@@ -77863,32 +79132,229 @@ var init_fromContext = __esm(() => {
77863
79132
  });
77864
79133
 
77865
79134
  // ../../services/backend/prompts/teams/duo/prompts/builder.ts
79135
+ function getBuilderGuidance2(ctx) {
79136
+ return `
79137
+ **Duo Team Context:**
79138
+ - You work with a planner who coordinates work and communicates with the user
79139
+ - You do NOT communicate directly with the user — hand off to the planner instead
79140
+ - Focus on implementation; the planner handles user communication and delivery
79141
+ - After completing work, hand off back to planner
79142
+ - **NEVER hand off directly to \`user\`** — always go through the planner
79143
+
79144
+ ${getBuilderGuidance({ ...ctx, questionTarget: "planner", codeChangesTarget: "planner" })}
79145
+ `;
79146
+ }
77866
79147
  var init_builder2 = __esm(() => {
77867
79148
  init_builder();
77868
79149
  });
77869
79150
 
77870
79151
  // ../../services/backend/prompts/cli/roles/planner-guidance-context.ts
79152
+ function getPlannerGuidanceContext(ctx) {
79153
+ const { convexUrl, teamRoles, chatroomId, role } = ctx;
79154
+ const cliEnvPrefix = getCliEnvPrefix(convexUrl);
79155
+ const members = teamRoles;
79156
+ return {
79157
+ ...ctx,
79158
+ cliEnvPrefix,
79159
+ members,
79160
+ chatroomId,
79161
+ role
79162
+ };
79163
+ }
77871
79164
  var init_planner_guidance_context = __esm(() => {
77872
79165
  init_env();
77873
79166
  });
77874
79167
 
77875
79168
  // ../../services/backend/prompts/teams/duo/prompts/planner.ts
79169
+ function getPlannerGuidance2(ctx) {
79170
+ const { nativeIntegration, members, cliEnvPrefix, chatroomId, role } = getPlannerGuidanceContext(ctx);
79171
+ const operatingModelGuidance = getPlannerPlusBuilderOperatingModel(nativeIntegration);
79172
+ return `## Planner Operating Model
79173
+
79174
+ ${getSessionContinuityLine(nativeIntegration)}
79175
+
79176
+ You are the team coordinator and the **single point of contact** for the user.
79177
+
79178
+ **Duo Team Context:**
79179
+ - You are the entry point — you communicate directly with the user
79180
+ - You coordinate with the builder for implementation tasks
79181
+ - You are ultimately accountable for all work quality
79182
+ - After reviewing builder output, deliver results to the user
79183
+ - **Only you can hand off to \`user\`**
79184
+
79185
+ ${getTeamCompositionSection(members)}
79186
+
79187
+ ${operatingModelGuidance}
79188
+
79189
+ ${getCoreResponsibilitiesSection(DUO_TEAM_CONFIG)}
79190
+
79191
+ ${getDelegationAndDecompositionSection(DUO_TEAM_CONFIG)}
79192
+
79193
+ ${getDelegationGuidelinesSection(DUO_TEAM_CONFIG, {
79194
+ cliEnvPrefix,
79195
+ chatroomId,
79196
+ role
79197
+ })}
79198
+
79199
+ ${getHandoffRulesSection(DUO_TEAM_CONFIG, nativeIntegration)}
79200
+
79201
+ ${getWhenWorkComesBackSection(DUO_TEAM_CONFIG)}`;
79202
+ }
79203
+ var DUO_TEAM_CONFIG;
77876
79204
  var init_planner2 = __esm(() => {
77877
79205
  init_planner_guidance_context();
77878
79206
  init_sections();
79207
+ DUO_TEAM_CONFIG = { hasBuilder: true };
77879
79208
  });
77880
79209
 
77881
79210
  // ../../services/backend/prompts/teams/duo/prompts/fromContext.ts
79211
+ function toDuoBuilderParams(ctx) {
79212
+ return {
79213
+ role: ctx.role,
79214
+ teamRoles: ctx.teamRoles,
79215
+ isEntryPoint: ctx.isEntryPoint,
79216
+ convexUrl: ctx.convexUrl,
79217
+ nativeIntegration: ctx.nativeIntegration
79218
+ };
79219
+ }
79220
+ function toDuoPlannerParams(ctx) {
79221
+ return {
79222
+ role: ctx.role,
79223
+ teamRoles: ctx.teamRoles,
79224
+ isEntryPoint: ctx.isEntryPoint,
79225
+ convexUrl: ctx.convexUrl,
79226
+ chatroomId: ctx.chatroomId,
79227
+ nativeIntegration: ctx.nativeIntegration
79228
+ };
79229
+ }
79230
+ function getDuoBuilderGuidanceFromContext(ctx) {
79231
+ return getBuilderGuidance2(toDuoBuilderParams(ctx));
79232
+ }
79233
+ function getDuoPlannerGuidanceFromContext(ctx) {
79234
+ return getPlannerGuidance2(toDuoPlannerParams(ctx));
79235
+ }
79236
+ function getDuoRoleGuidanceFromContext(ctx) {
79237
+ const normalizedRole = ctx.role.toLowerCase();
79238
+ if (normalizedRole === "planner") {
79239
+ return getDuoPlannerGuidanceFromContext(ctx);
79240
+ }
79241
+ if (normalizedRole === "builder") {
79242
+ return getDuoBuilderGuidanceFromContext(ctx);
79243
+ }
79244
+ return null;
79245
+ }
77882
79246
  var init_fromContext2 = __esm(() => {
77883
79247
  init_builder2();
77884
79248
  init_planner2();
77885
79249
  });
77886
79250
 
77887
79251
  // ../../services/backend/prompts/teams/solo/prompts/fromContext.ts
79252
+ function toSoloParams2(ctx) {
79253
+ return {
79254
+ role: ctx.role,
79255
+ teamRoles: ctx.teamRoles,
79256
+ isEntryPoint: ctx.isEntryPoint,
79257
+ convexUrl: ctx.convexUrl,
79258
+ chatroomId: ctx.chatroomId,
79259
+ nativeIntegration: ctx.nativeIntegration
79260
+ };
79261
+ }
79262
+ function getSoloGuidanceFromContext2(ctx) {
79263
+ return getSoloGuidance(toSoloParams2(ctx));
79264
+ }
79265
+ function getSoloRoleGuidanceFromContext(ctx) {
79266
+ const normalizedRole = ctx.role.toLowerCase();
79267
+ if (normalizedRole === "solo") {
79268
+ return getSoloGuidanceFromContext2(ctx);
79269
+ }
79270
+ return null;
79271
+ }
77888
79272
  var init_fromContext3 = __esm(() => {
77889
79273
  init_solo();
77890
79274
  });
79275
+
79276
+ // ../../services/backend/src/domain/entities/team.ts
79277
+ function toTeam(chatroom) {
79278
+ if (!chatroom.teamId || !chatroom.teamRoles || chatroom.teamRoles.length === 0) {
79279
+ return null;
79280
+ }
79281
+ const entryPoint = chatroom.teamEntryPoint ?? chatroom.teamRoles[0];
79282
+ if (!entryPoint)
79283
+ return null;
79284
+ return {
79285
+ id: chatroom.teamId,
79286
+ name: chatroom.teamName ?? chatroom.teamId,
79287
+ roles: chatroom.teamRoles,
79288
+ entryPoint
79289
+ };
79290
+ }
79291
+ function getTeamEntryPoint(team) {
79292
+ return team.teamEntryPoint ?? team.teamRoles?.[0] ?? null;
79293
+ }
79294
+
77891
79295
  // ../../services/backend/prompts/selector-context.ts
79296
+ function detectTeamTypeByName(teamName) {
79297
+ const normalizedName = (teamName || "").toLowerCase();
79298
+ if (normalizedName.includes("solo"))
79299
+ return "solo";
79300
+ if (normalizedName.includes("duo"))
79301
+ return "duo";
79302
+ return null;
79303
+ }
79304
+ function isSoloTeamByRoles(teamRoles) {
79305
+ return teamRoles.some((r) => r.toLowerCase() === "solo") && teamRoles.length === 1;
79306
+ }
79307
+ function isDuoTeamByRoles(teamRoles) {
79308
+ const hasPlanner = teamRoles.some((r) => r.toLowerCase() === "planner");
79309
+ const hasBuilder = teamRoles.some((r) => r.toLowerCase() === "builder");
79310
+ return hasPlanner && hasBuilder && teamRoles.length === 2;
79311
+ }
79312
+ function detectTeamType(teamRoles, teamName) {
79313
+ const byName = detectTeamTypeByName(teamName);
79314
+ if (byName)
79315
+ return byName;
79316
+ if (isSoloTeamByRoles(teamRoles))
79317
+ return "solo";
79318
+ if (isDuoTeamByRoles(teamRoles))
79319
+ return "duo";
79320
+ return "unknown";
79321
+ }
79322
+ function buildSelectorContext(params) {
79323
+ const entryPoint = getTeamEntryPoint({ teamEntryPoint: params.teamEntryPoint, teamRoles: params.teamRoles }) ?? "builder";
79324
+ const teamConfig = toTeam({
79325
+ teamId: params.teamId,
79326
+ teamName: params.teamName,
79327
+ teamRoles: params.teamRoles,
79328
+ teamEntryPoint: params.teamEntryPoint
79329
+ }) ?? undefined;
79330
+ return {
79331
+ role: params.role,
79332
+ team: detectTeamType(params.teamRoles, params.teamName),
79333
+ teamConfig,
79334
+ workflow: params.workflow,
79335
+ teamRoles: params.teamRoles,
79336
+ isEntryPoint: params.role.toLowerCase() === entryPoint.toLowerCase(),
79337
+ convexUrl: params.convexUrl,
79338
+ chatroomId: params.chatroomId,
79339
+ agentType: params.agentType ?? "unset",
79340
+ nativeIntegration: params.nativeIntegration
79341
+ };
79342
+ }
79343
+ function getRoleGuidanceFromContext(ctx) {
79344
+ try {
79345
+ if (ctx.team === "solo") {
79346
+ const result = getSoloRoleGuidanceFromContext(ctx);
79347
+ if (result !== null)
79348
+ return result;
79349
+ }
79350
+ if (ctx.team === "duo") {
79351
+ const result = getDuoRoleGuidanceFromContext(ctx);
79352
+ if (result !== null)
79353
+ return result;
79354
+ }
79355
+ } catch {}
79356
+ return getBaseRoleGuidanceFromContext(ctx);
79357
+ }
77892
79358
  var init_selector_context = __esm(() => {
77893
79359
  init_fromContext();
77894
79360
  init_fromContext2();
@@ -77896,19 +79362,151 @@ var init_selector_context = __esm(() => {
77896
79362
  });
77897
79363
 
77898
79364
  // ../../services/backend/prompts/sections/role-guidance.ts
79365
+ function getRoleGuidanceSection(ctx) {
79366
+ const content = getRoleGuidanceFromContext(ctx);
79367
+ return createSection("role-guidance", "knowledge", content);
79368
+ }
77899
79369
  var init_role_guidance = __esm(() => {
77900
79370
  init_selector_context();
77901
79371
  });
77902
79372
 
77903
79373
  // ../../services/backend/prompts/templates.ts
77904
- var init_templates = () => {};
79374
+ function getRoleTemplate(role) {
79375
+ const normalizedRole = role.toLowerCase();
79376
+ const template = ROLE_TEMPLATES[normalizedRole];
79377
+ if (template) {
79378
+ return template;
79379
+ }
79380
+ return {
79381
+ role,
79382
+ title: role.charAt(0).toUpperCase() + role.slice(1),
79383
+ description: `You are participating as the ${role} in this collaborative workflow.`,
79384
+ responsibilities: [
79385
+ "Complete tasks assigned to your role",
79386
+ "Communicate clearly with other participants",
79387
+ "Hand off to the next appropriate role when done"
79388
+ ],
79389
+ defaultHandoffTarget: "user"
79390
+ };
79391
+ }
79392
+ var ROLE_TEMPLATES;
79393
+ var init_templates = __esm(() => {
79394
+ ROLE_TEMPLATES = {
79395
+ builder: {
79396
+ role: "builder",
79397
+ title: "Builder",
79398
+ description: "You are the implementer responsible for writing code and building solutions.",
79399
+ responsibilities: [
79400
+ "Implement solutions based on requirements",
79401
+ "Write clean, maintainable, well-documented code",
79402
+ "Follow established patterns and best practices",
79403
+ "Handle edge cases and error scenarios",
79404
+ "Provide clear summaries of what was built"
79405
+ ],
79406
+ defaultHandoffTarget: "planner"
79407
+ },
79408
+ planner: {
79409
+ role: "planner",
79410
+ title: "Planner",
79411
+ description: "You are the team coordinator responsible for user communication, task decomposition, and team management.",
79412
+ responsibilities: [
79413
+ "Communicate with the user as the single point of contact",
79414
+ "Decompose complex tasks into actionable work items",
79415
+ "Delegate work to available team members",
79416
+ "Review completed work against user requirements",
79417
+ "Manage the backlog and prioritize tasks",
79418
+ "Hand back work for rework if requirements are not met"
79419
+ ],
79420
+ defaultHandoffTarget: "builder"
79421
+ },
79422
+ architect: {
79423
+ role: "architect",
79424
+ title: "Architect",
79425
+ description: "You are the system designer responsible for planning and high-level architecture.",
79426
+ responsibilities: [
79427
+ "Analyze requirements and break down complex tasks",
79428
+ "Design system architecture and component structure",
79429
+ "Make technology and pattern decisions",
79430
+ "Create clear specifications for the builder",
79431
+ "Consider scalability, maintainability, and best practices"
79432
+ ],
79433
+ defaultHandoffTarget: "builder"
79434
+ },
79435
+ tester: {
79436
+ role: "tester",
79437
+ title: "Tester",
79438
+ description: "You are the QA specialist responsible for testing and validation.",
79439
+ responsibilities: [
79440
+ "Write and execute test cases",
79441
+ "Verify functionality works as expected",
79442
+ "Test edge cases and error handling",
79443
+ "Report bugs and issues clearly",
79444
+ "Confirm quality standards are met"
79445
+ ],
79446
+ defaultHandoffTarget: "user"
79447
+ },
79448
+ solo: {
79449
+ role: "solo",
79450
+ title: "Solo",
79451
+ description: "You are the autonomous agent responsible for both planning and executing tasks independently.",
79452
+ responsibilities: [
79453
+ "Communicate directly with the user as the single point of contact",
79454
+ "Decompose complex tasks into actionable work items",
79455
+ "Implement solutions: write clean, maintainable code",
79456
+ "Follow established patterns and best practices",
79457
+ "Handle edge cases and error scenarios",
79458
+ "Review and validate your own work for quality",
79459
+ "Deliver completed results to the user"
79460
+ ],
79461
+ defaultHandoffTarget: "user"
79462
+ }
79463
+ };
79464
+ });
77905
79465
 
77906
79466
  // ../../services/backend/prompts/sections/role-identity.ts
79467
+ function getTeamHeaderSection(teamName) {
79468
+ return createSection("team-header", "knowledge", `# ${teamName}`);
79469
+ }
79470
+ function getRoleTitleSection(ctx) {
79471
+ const template = getRoleTemplate(ctx.role);
79472
+ return createSection("role-title", "knowledge", `## Your Role: ${template.title.toUpperCase()}`);
79473
+ }
79474
+ function getRoleDescriptionSection(ctx) {
79475
+ const template = getRoleTemplate(ctx.role);
79476
+ return createSection("role-description", "knowledge", template.description);
79477
+ }
77907
79478
  var init_role_identity = __esm(() => {
77908
79479
  init_templates();
77909
79480
  });
77910
79481
 
77911
79482
  // ../../services/backend/prompts/native/system-prompt.ts
79483
+ function composeNativeSystemPrompt(input) {
79484
+ const { chatroomId, role, teamId, teamName, teamRoles, teamEntryPoint, convexUrl } = input;
79485
+ const selectorCtx = buildSelectorContext({
79486
+ role,
79487
+ teamRoles,
79488
+ teamId,
79489
+ teamName,
79490
+ teamEntryPoint,
79491
+ convexUrl,
79492
+ chatroomId,
79493
+ agentType: input.agentType,
79494
+ nativeIntegration: true
79495
+ });
79496
+ const sections = [
79497
+ getRoleTitleSection(selectorCtx),
79498
+ getGlossarySection({
79499
+ convexUrl,
79500
+ chatroomId,
79501
+ role,
79502
+ nativeIntegration: true,
79503
+ compactSkills: true
79504
+ }),
79505
+ getRoleGuidanceSection(selectorCtx),
79506
+ getNativeCommandsReferenceSection({ chatroomId, role, convexUrl })
79507
+ ];
79508
+ return composeSections(sections);
79509
+ }
77912
79510
  var init_system_prompt = __esm(() => {
77913
79511
  init_commands_reference();
77914
79512
  init_glossary();
@@ -77918,11 +79516,46 @@ var init_system_prompt = __esm(() => {
77918
79516
  });
77919
79517
 
77920
79518
  // ../../services/backend/prompts/native/task-started-content.ts
79519
+ function getNativeTaskStartedPrompt(ctx) {
79520
+ const contextNewCmd = contextNewCommand({
79521
+ chatroomId: ctx.chatroomId,
79522
+ role: ctx.role,
79523
+ cliEnvPrefix: ctx.cliEnvPrefix,
79524
+ triggerMessageId: ctx.triggerMessageId
79525
+ });
79526
+ return `### Start working
79527
+
79528
+ Entry-point roles receive user messages directly. ${getNativeTokenActivityInProgressNote()}
79529
+
79530
+ ${getContextRuleBlock(contextNewCmd, contextNewHint({ cliEnvPrefix: ctx.cliEnvPrefix }))}`;
79531
+ }
79532
+ function getNativeTaskStartedPromptForHandoffRecipient() {
79533
+ return `### Start Working
79534
+
79535
+ The task body contains your work description. Begin immediately.`;
79536
+ }
77921
79537
  var init_task_started_content = __esm(() => {
77922
79538
  init_new();
77923
79539
  });
77924
79540
 
77925
79541
  // ../../services/backend/prompts/sections/classification-guide.ts
79542
+ function getTaskIntakeContent(ctx) {
79543
+ const cliEnvPrefix = getCliEnvPrefix(ctx.convexUrl);
79544
+ const chatroomId = ctx.chatroomId ?? "";
79545
+ if (ctx.isEntryPoint) {
79546
+ return ctx.nativeIntegration ? getNativeTaskStartedPrompt({ chatroomId, role: ctx.role, cliEnvPrefix }) : getTaskStartedPrompt2({ chatroomId, role: ctx.role, cliEnvPrefix });
79547
+ }
79548
+ return ctx.nativeIntegration ? getNativeTaskStartedPromptForHandoffRecipient() : getTaskStartedPromptForHandoffRecipient2({
79549
+ chatroomId,
79550
+ role: ctx.role,
79551
+ cliEnvPrefix
79552
+ });
79553
+ }
79554
+ function getClassificationGuideSection(ctx) {
79555
+ const content = getTaskIntakeContent(ctx);
79556
+ const sectionId = ctx.isEntryPoint ? "task-intake-guide" : "handoff-recipient-guide";
79557
+ return createSection(sectionId, "knowledge", content);
79558
+ }
77926
79559
  var init_classification_guide = __esm(() => {
77927
79560
  init_cli();
77928
79561
  init_task_started_content();
@@ -77930,23 +79563,118 @@ var init_classification_guide = __esm(() => {
77930
79563
  });
77931
79564
 
77932
79565
  // ../../services/backend/prompts/sections/current-classification.ts
79566
+ function getCurrentClassificationSection(classification) {
79567
+ const info = {
79568
+ question: {
79569
+ label: "QUESTION",
79570
+ description: "User is asking a question. Can respond directly after answering."
79571
+ },
79572
+ new_feature: {
79573
+ label: "NEW FEATURE",
79574
+ description: "New functionality request."
79575
+ },
79576
+ follow_up: {
79577
+ label: "FOLLOW-UP",
79578
+ description: "Follow-up to previous task. Same rules as the original apply."
79579
+ }
79580
+ };
79581
+ const { label, description } = info[classification];
79582
+ const content = `### Current Task: ${label}
79583
+ ${description}`;
79584
+ return createSection("current-classification", "guidance", content);
79585
+ }
77933
79586
  var init_current_classification = () => {};
77934
79587
 
77935
79588
  // ../../services/backend/prompts/sections/getting-started.ts
79589
+ function getGettingStartedSection(ctx) {
79590
+ const content = getContextGainingGuidance({
79591
+ chatroomId: ctx.chatroomId ?? "",
79592
+ role: ctx.role,
79593
+ convexUrl: ctx.convexUrl,
79594
+ agentType: ctx.agentType
79595
+ });
79596
+ return createSection("getting-started", "knowledge", content);
79597
+ }
77936
79598
  var init_getting_started = __esm(() => {
77937
79599
  init_getting_started_content();
77938
79600
  });
77939
79601
 
77940
79602
  // ../../services/backend/prompts/sections/handoff-options.ts
79603
+ function getHandoffOptionsSection(params) {
79604
+ const roles = params.availableHandoffRoles.join(", ");
79605
+ const content = `### Handoff Options
79606
+ Available targets: ${roles}`;
79607
+ return createSection("handoff-options", "guidance", content);
79608
+ }
77941
79609
  var init_handoff_options = () => {};
77942
79610
 
77943
79611
  // ../../services/backend/prompts/sections/next-step.ts
79612
+ function getNextStepSection(params) {
79613
+ const cliEnvPrefix = getCliEnvPrefix(params.convexUrl);
79614
+ const waitCmd = getNextTaskCommand({
79615
+ chatroomId: params.chatroomId,
79616
+ role: params.role,
79617
+ cliEnvPrefix
79618
+ });
79619
+ const content = `### Next
79620
+
79621
+ Run:
79622
+
79623
+ \`\`\`bash
79624
+ ${waitCmd}
79625
+ \`\`\``;
79626
+ return createSection("next-step", "guidance", content);
79627
+ }
77944
79628
  var init_next_step = __esm(() => {
77945
79629
  init_command();
77946
79630
  init_utils3();
77947
79631
  });
77948
79632
 
77949
79633
  // ../../services/backend/prompts/sections/session-vs-chatroom-task.ts
79634
+ function getTwoLevelsTableSection() {
79635
+ return `## Two-Level Model: Session vs Chatroom Task
79636
+
79637
+ | Level | Name | Scope | Ends when |
79638
+ |-------|------|-------|-----------|
79639
+ | **A** | **Session** (harness turn) | The entire agent invocation — from startup to shutdown | You deliberately shut down or the harness exits |
79640
+ | **B** | **Chatroom task** | One discrete unit of work delivered by \`get-next-task\` | You run \`handoff\` to pass work to the next role |
79641
+
79642
+ **Completing Level B does NOT end Level A.**
79643
+ After every \`handoff\`, you must run \`get-next-task\` again to stay in the session and receive the next chatroom task.`;
79644
+ }
79645
+ function getSessionLifecycleSection() {
79646
+ return `### Session Lifecycle
79647
+
79648
+ A session starts when your harness launches you and ends only when the harness shuts down (or you explicitly stop).
79649
+ Within a session, you process many chatroom tasks sequentially:
79650
+
79651
+ \`get-next-task\` → do work → \`handoff\` → \`get-next-task\` → do work → \`handoff\` → …
79652
+
79653
+ Never exit or stop after a handoff — that closes the session (Level A) before the user is done with you.`;
79654
+ }
79655
+ function getSessionAntiPatternsSection() {
79656
+ return `### Common Mistakes
79657
+
79658
+ ❌ **Wrong:** Run \`handoff\`, then stop or wait for the user to re-invoke you.
79659
+ ✅ **Right:** Run \`handoff\`, then immediately run \`get-next-task\` in the foreground.
79660
+
79661
+ ❌ **Wrong:** Think "I finished the task, I'm done."
79662
+ ✅ **Right:** Think "I finished this chatroom task (Level B). The session (Level A) continues — run \`get-next-task\`."
79663
+
79664
+ ❌ **Wrong:** Run \`get-next-task\` in the background or skip it.
79665
+ ✅ **Right:** \`get-next-task\` must run in the **foreground** so the harness can deliver the next chatroom task.`;
79666
+ }
79667
+ function getSessionVsChatroomTaskSection() {
79668
+ const content = [
79669
+ getTwoLevelsTableSection(),
79670
+ "",
79671
+ getSessionLifecycleSection(),
79672
+ "",
79673
+ getSessionAntiPatternsSection()
79674
+ ].join(`
79675
+ `);
79676
+ return createSection("session-vs-chatroom-task", "guidance", content);
79677
+ }
77950
79678
  var init_session_vs_chatroom_task = () => {};
77951
79679
 
77952
79680
  // ../../services/backend/src/domain/entities/harness/claude-sdk.config.ts
@@ -78151,9 +79879,571 @@ var init_types = __esm(() => {
78151
79879
  "pi-sdk": piSdkCapabilities
78152
79880
  };
78153
79881
  });
79882
+
79883
+ // ../../services/backend/prompts/review-guidelines/review.ts
79884
+ function getReviewGuidelines() {
79885
+ return [REVIEW_PRINCIPLES, REVIEW_PROCESS, GUIDELINE_FILE_LOCATIONS, REJECTION_GUIDANCE].join(`
79886
+
79887
+ `);
79888
+ }
79889
+ var REVIEW_PRINCIPLES = `
79890
+ ## Review Principles
79891
+
79892
+ When reviewing completed work, you serve as the quality guardian between implementation and delivery.
79893
+
79894
+ ### Primary Goal: Maintainability & Extensibility
79895
+
79896
+ **The ultimate purpose of code review is to ensure the changes make it possible to continue building on the application.**
79897
+
79898
+ Every piece of code must be:
79899
+ - Easy to understand and modify later
79900
+ - Following patterns that scale
79901
+ - Not creating technical debt that slows future development
79902
+
79903
+ If code is hard to extend, hard to understand, or creates mess - it should be rejected or refactored, regardless of whether it "works."
79904
+
79905
+ ### Core Values
79906
+
79907
+ 1. **User Goal Alignment**
79908
+ The implementation must accomplish what the user originally requested.
79909
+ Compare the work against the ORIGINAL user request, not just the handoff summary.
79910
+
79911
+ 2. **Code Quality Over Speed**
79912
+ Maintain code quality: Use \`handoff\` to reject messy code that creates technical debt and slows future development.
79913
+
79914
+ 3. **Codebase Consistency**
79915
+ New code should follow existing patterns and conventions.
79916
+ Check guideline files for project-specific rules.
79917
+ Inconsistent code creates confusion and bugs.
79918
+
79919
+ 4. **Verification Over Trust**
79920
+ Check the actual changes, not just the summary.
79921
+ If something seems off, investigate. Trust but verify.
79922
+
79923
+ 5. **Be Direct and Specific**
79924
+ Be specific and clear in your \`handoff\` message: Vague feedback leads to confusion and rework. If something is wrong, say exactly what and why.
79925
+ If a refactor is needed, propose the exact approach.
79926
+ `, REVIEW_PROCESS = `
79927
+ ## Review Process
79928
+
79929
+ ### Phase 1: Context Review
79930
+
79931
+ Before looking at code, understand what was requested:
79932
+
79933
+ 1. Read the **original user request** in the context window
79934
+ 2. Note all requirements, constraints, and acceptance criteria
79935
+ 3. If a feature has metadata (title, description, tech-specs), review each point
79936
+ 4. If there are attached tasks, read their content
79937
+
79938
+ ### Phase 2: Change Inspection
79939
+
79940
+ Run these commands to inspect the implementation:
79941
+
79942
+ \`\`\`bash
79943
+ # Check for linting issues
79944
+ pnpm lint:fix
79945
+
79946
+ # View uncommitted changes
79947
+ git status
79948
+ git diff
79949
+
79950
+ # View recent commits
79951
+ git log --oneline -5
79952
+ git show HEAD
79953
+ \`\`\`
79954
+
79955
+ ### Phase 3: Code Review Checklist
79956
+
79957
+ **Functional Requirements:**
79958
+ - [ ] All requirements from original request are addressed
79959
+ - [ ] Edge cases are handled
79960
+ - [ ] Error handling is appropriate
79961
+
79962
+ **Code Quality:**
79963
+ - [ ] No \`any\` types - proper TypeScript typing required
79964
+ - [ ] No type assertions (\`as\`) hiding real type issues
79965
+ - [ ] React hooks used correctly (deps arrays, memoization)
79966
+ - [ ] No inline workarounds or hacks
79967
+
79968
+ **Codebase Consistency:**
79969
+ - [ ] Follows existing patterns in the codebase
79970
+ - [ ] Uses existing components/utilities where applicable
79971
+ - [ ] Styling follows design system (semantic tokens, not hardcoded colors)
79972
+
79973
+ **Guidelines Compliance:**
79974
+ - [ ] Check relevant guideline files were followed (see list below)
79975
+
79976
+ ### Phase 4: Decision
79977
+
79978
+ **Your feedback must be SPECIFIC and ACTIONABLE. Include clear guidance in your \`handoff\` message to help the builder make the right changes.**
79979
+
79980
+ **If changes are needed:**
79981
+ - State EXACTLY what is wrong (file, line, code snippet)
79982
+ - Explain WHY it's a problem (not just that it's wrong)
79983
+ - Provide the EXACT fix or approach you want to see
79984
+ - If multiple issues, number them clearly
79985
+
79986
+ Example of BAD feedback:
79987
+ > "The code could be cleaner"
79988
+
79989
+ Example of GOOD feedback:
79990
+ > "In \`TaskQueue.tsx\` line 45, you're using \`any\` type for the task parameter.
79991
+ > This hides type errors. Change to: \`task: Task\` using the imported Task type."
79992
+
79993
+ **If the code is a mess - REJECT IT:**
79994
+ - Use \`handoff\` to reject messy code that "works"
79995
+ - Propose the refactor approach explicitly in your \`handoff\` message
79996
+ - Large refactors are acceptable if they improve maintainability
79997
+ - The goal is code that can be built upon, not just code that runs
79998
+
79999
+ **If approved:**
80000
+ - Confirm ALL requirements from original request are met
80001
+ - Briefly summarize what was verified
80002
+ - Hand off to user
80003
+ `, GUIDELINE_FILE_LOCATIONS = `
80004
+ ## Guideline Files to Check
80005
+
80006
+ Different AI tools use different guideline file locations. Check any that exist:
80007
+
80008
+ ### Cursor IDE
80009
+ - \`.cursor/rules/*.md\` - Cursor rules files
80010
+ - \`.cursorrules\` - Root cursor rules
80011
+
80012
+ ### GitHub Copilot
80013
+ - \`.github/copilot-instructions.md\` - Copilot instructions
80014
+ - \`.github/copilot/*.md\` - Additional Copilot files
80015
+
80016
+ ### Claude / Anthropic
80017
+ - \`CLAUDE.md\` - Claude-specific instructions
80018
+ - \`.claude/*.md\` - Claude rules directory
80019
+
80020
+ ### OpenAI / Codex
80021
+ - \`.openai/guidelines.md\` - OpenAI guidelines
80022
+ - \`CODEX.md\` - Codex instructions
80023
+
80024
+ ### Generic Agent Files
80025
+ - \`AGENTS.md\` - Generic agent guidelines
80026
+ - \`.ai/*.md\` - AI-related instructions
80027
+ - \`DEVELOPMENT.md\` - Development guidelines
80028
+ - \`CONTRIBUTING.md\` - Contribution guidelines
80029
+
80030
+ ### Project-Specific
80031
+ - \`docs/design/*.md\` - Design guidelines
80032
+ - \`docs/style-guide.md\` - Style guides
80033
+ - \`guides/*.md\` - Project guides
80034
+
80035
+ **Important:** Adapt to what exists in THIS codebase. Not all projects have all files.
80036
+ `, REJECTION_GUIDANCE = `
80037
+ ## When to Reject or Request Refactors
80038
+
80039
+ **Use \`handoff\` to maintain code quality:** The goal is a maintainable codebase.
80040
+
80041
+ ### Reject When:
80042
+
80043
+ 1. **Requirements Not Met**
80044
+ - The original user request is not fully addressed
80045
+ - Key features are missing or only partially implemented
80046
+
80047
+ 2. **Significant Technical Debt**
80048
+ - Hacks or workarounds that will cause problems later
80049
+ - Code that is hard to understand or modify
80050
+ - Patterns that don't scale or won't work with future features
80051
+
80052
+ 3. **Type Safety Violations**
80053
+ - Widespread use of \`any\` or type assertions
80054
+ - Missing proper error types or return types
80055
+ - Type errors being suppressed rather than fixed
80056
+
80057
+ 4. **Architectural Issues**
80058
+ - Code in wrong location (logic in UI, UI in logic)
80059
+ - Duplication of existing functionality
80060
+ - Tight coupling that prevents testing/reuse
80061
+
80062
+ ### Propose Refactors When:
80063
+
80064
+ 1. **The fix is bigger than the feature**
80065
+ If cleaning up the code would take more effort than the original change,
80066
+ but the mess will compound over time - propose the refactor.
80067
+
80068
+ 2. **Patterns are inconsistent**
80069
+ If new code follows different patterns than existing code,
80070
+ propose alignment to the established pattern.
80071
+
80072
+ 3. **Abstractions are wrong**
80073
+ If the code is solving the problem at the wrong level of abstraction,
80074
+ propose the right approach even if it means starting over.
80075
+
80076
+ ### How to Propose Refactors:
80077
+
80078
+ 1. Explain the problem clearly
80079
+ 2. Describe the desired end state
80080
+ 3. Suggest whether to:
80081
+ - Fix now before merging
80082
+ - Create a follow-up task for later
80083
+ - Block on the refactor
80084
+
80085
+ **Remember:** Approving bad code costs more than rejecting it.
80086
+ `;
80087
+
78154
80088
  // ../../services/backend/prompts/review-guidelines/index.ts
78155
80089
  var init_review_guidelines = () => {};
80090
+
80091
+ // ../../services/backend/prompts/policies/security.ts
80092
+ function getSecurityPolicy() {
80093
+ return SECURITY_POLICY;
80094
+ }
80095
+ var SECURITY_POLICY = `
80096
+ ## Security Review Policy
80097
+
80098
+ These are general security principles. Adapt to your codebase's specific security requirements.
80099
+
80100
+ ### Authentication & Authorization
80101
+
80102
+ - [ ] Authentication checks are in place where required
80103
+ - [ ] Authorization verifies user has permission for the action
80104
+ - [ ] Session handling follows established patterns
80105
+ - [ ] No hardcoded credentials or secrets
80106
+
80107
+ ### Input Validation
80108
+
80109
+ - [ ] User input is validated before use
80110
+ - [ ] Input sanitization for database queries (SQL injection prevention)
80111
+ - [ ] Path traversal protection for file operations
80112
+ - [ ] Proper escaping for output contexts (XSS prevention)
80113
+
80114
+ ### Data Handling
80115
+
80116
+ - [ ] Sensitive data is not logged
80117
+ - [ ] PII is handled according to privacy requirements
80118
+ - [ ] Secrets use environment variables, not hardcoded values
80119
+ - [ ] .env files are not committed
80120
+
80121
+ ### API Security
80122
+
80123
+ - [ ] Rate limiting considerations for public endpoints
80124
+ - [ ] CORS configuration is appropriate
80125
+ - [ ] API responses don't leak sensitive information
80126
+ - [ ] Error messages don't expose internal details
80127
+
80128
+ ### Common Vulnerabilities to Check
80129
+
80130
+ 1. **Injection Attacks**
80131
+ - SQL/NoSQL injection
80132
+ - Command injection
80133
+ - Template injection
80134
+
80135
+ 2. **Broken Access Control**
80136
+ - Missing authorization checks
80137
+ - IDOR (Insecure Direct Object Reference)
80138
+ - Privilege escalation
80139
+
80140
+ 3. **Security Misconfiguration**
80141
+ - Debug mode in production
80142
+ - Exposed admin interfaces
80143
+ - Default credentials
80144
+
80145
+ 4. **Cryptographic Issues**
80146
+ - Weak hashing algorithms
80147
+ - Insecure random number generation
80148
+ - Improper key management
80149
+
80150
+ ### Codebase-Specific Security
80151
+
80152
+ Check these locations for security-related guidelines:
80153
+ - Security documentation in \`docs/security*.md\`
80154
+ - Authentication patterns in existing auth code
80155
+ - Existing security middleware/helpers
80156
+ - Security comments in sensitive code areas
80157
+
80158
+ **Important:** These are general guidelines. Always verify against your project's specific security requirements and compliance needs.
80159
+ `;
80160
+
80161
+ // ../../services/backend/prompts/policies/design.ts
80162
+ function getDesignPolicy() {
80163
+ return DESIGN_POLICY;
80164
+ }
80165
+ var DESIGN_POLICY = `
80166
+ ## Design Review Policy
80167
+
80168
+ These are general design principles. Adapt to your codebase's specific design system.
80169
+
80170
+ ### Design System Compliance
80171
+
80172
+ - [ ] Uses existing design tokens (colors, spacing, typography)
80173
+ - [ ] Follows established component patterns
80174
+ - [ ] Reuses existing components instead of creating duplicates
80175
+ - [ ] Styling uses semantic values, not hardcoded ones
80176
+
80177
+ ### Color Usage
80178
+
80179
+ **Semantic colors should be preferred:**
80180
+ - Use \`text-foreground\` not \`text-black\`
80181
+ - Use \`bg-card\` not \`bg-white\`
80182
+ - Use \`border-border\` not \`border-gray-200\`
80183
+
80184
+ **Dark mode support:**
80185
+ - All UI should work in both light and dark mode
80186
+ - Brand/status colors need dark variants (e.g., \`bg-red-50 dark:bg-red-950/20\`)
80187
+
80188
+ ### Component Patterns
80189
+
80190
+ - [ ] Components follow existing file structure conventions
80191
+ - [ ] Props are typed properly
80192
+ - [ ] Components are accessible (keyboard navigation, ARIA)
80193
+ - [ ] Responsive design is considered
80194
+
80195
+ ### Typography
80196
+
80197
+ - [ ] Uses established font sizes from the design system
80198
+ - [ ] Heading hierarchy is semantic (h1, h2, etc.)
80199
+ - [ ] Text is readable at all sizes
80200
+ - [ ] Font weights follow conventions
80201
+
80202
+ ### Spacing & Layout
80203
+
80204
+ - [ ] Uses design system spacing tokens
80205
+ - [ ] Layout is responsive
80206
+ - [ ] Alignment is consistent
80207
+ - [ ] Proper use of flexbox/grid patterns
80208
+
80209
+ ### UX Considerations
80210
+
80211
+ - [ ] Loading states are handled
80212
+ - [ ] Error states have clear messaging
80213
+ - [ ] Empty states are designed
80214
+ - [ ] Interactive elements have hover/focus states
80215
+
80216
+ ### Common Design Issues to Catch
80217
+
80218
+ 1. **Inconsistent Styling**
80219
+ - Different button styles for similar actions
80220
+ - Inconsistent spacing between elements
80221
+ - Mixed font sizes within components
80222
+
80223
+ 2. **Accessibility Gaps**
80224
+ - Missing keyboard navigation
80225
+ - Low color contrast
80226
+ - Missing ARIA labels
80227
+ - Focus states not visible
80228
+
80229
+ 3. **Hardcoded Values**
80230
+ - Magic numbers for spacing (use tokens)
80231
+ - Hardcoded colors (use semantic colors)
80232
+ - Fixed widths that break responsive
80233
+
80234
+ 4. **Component Duplication**
80235
+ - Recreating existing components
80236
+ - Copy-paste instead of abstraction
80237
+ - Similar patterns implemented differently
80238
+
80239
+ ### Codebase-Specific Design
80240
+
80241
+ Check these locations for design guidelines:
80242
+ - \`docs/design/*.md\` - Design documentation
80243
+ - \`components/ui/\` - Existing UI component library
80244
+ - \`tailwind.config.*\` - Theme configuration
80245
+ - \`globals.css\` or theme files - CSS custom properties
80246
+ - \`AGENTS.md\` or \`CLAUDE.md\` - May contain UI guidelines
80247
+
80248
+ **Important:** These are general guidelines. Always verify against your project's specific design system.
80249
+ `;
80250
+
80251
+ // ../../services/backend/prompts/policies/performance.ts
80252
+ function getPerformancePolicy() {
80253
+ return PERFORMANCE_POLICY;
80254
+ }
80255
+ var PERFORMANCE_POLICY = `
80256
+ ## Performance Review Policy
80257
+
80258
+ These are general performance principles. Adapt to your codebase's specific requirements.
80259
+
80260
+ ### Frontend Performance
80261
+
80262
+ **React/Component Performance:**
80263
+ - [ ] \`useMemo\` used for expensive computations
80264
+ - [ ] \`useCallback\` used for callback props passed to child components
80265
+ - [ ] \`React.memo\` considered for components receiving stable props
80266
+ - [ ] No unnecessary re-renders (check dependency arrays)
80267
+ - [ ] Large lists use virtualization where appropriate
80268
+
80269
+ **Bundle Size:**
80270
+ - [ ] No large dependencies added for simple functionality
80271
+ - [ ] Dynamic imports (\`lazy\`) used for route-level code splitting
80272
+ - [ ] Tree-shaking friendly imports (avoid \`import * as\`)
80273
+ - [ ] Images/assets are appropriately sized and optimized
80274
+
80275
+ **Rendering:**
80276
+ - [ ] No layout thrashing (reading and writing DOM in loops)
80277
+ - [ ] CSS animations use \`transform\` and \`opacity\` where possible
80278
+ - [ ] Avoid inline styles that change frequently
80279
+ - [ ] Consider \`will-change\` for animated elements
80280
+
80281
+ ### Backend Performance
80282
+
80283
+ **Database Queries:**
80284
+ - [ ] Queries use appropriate indexes
80285
+ - [ ] N+1 query patterns are avoided or justified
80286
+ - [ ] Pagination used for large result sets
80287
+ - [ ] Expensive queries are cached where appropriate
80288
+
80289
+ **API Design:**
80290
+ - [ ] Responses don't include unnecessary data
80291
+ - [ ] Batch endpoints available for bulk operations
80292
+ - [ ] Expensive operations are async/background where possible
80293
+ - [ ] Rate limiting considered for resource-intensive endpoints
80294
+
80295
+ **Memory & Resources:**
80296
+ - [ ] No memory leaks (event listeners cleaned up, subscriptions closed)
80297
+ - [ ] Large data structures are streamed, not loaded entirely
80298
+ - [ ] Connection pooling used for database/external services
80299
+ - [ ] Temporary files/resources are cleaned up
80300
+
80301
+ ### Common Performance Issues to Catch
80302
+
80303
+ 1. **Unnecessary Computation**
80304
+ - Computing values on every render
80305
+ - Recalculating derived data without memoization
80306
+ - Expensive operations in hot paths
80307
+
80308
+ 2. **Over-fetching**
80309
+ - Requesting more data than needed
80310
+ - Missing pagination on large datasets
80311
+ - Not using projection/select for specific fields
80312
+
80313
+ 3. **Under-caching**
80314
+ - Repeated identical API calls
80315
+ - Not caching expensive computations
80316
+ - Missing server-side caching for static data
80317
+
80318
+ 4. **Blocking Operations**
80319
+ - Synchronous operations blocking the event loop
80320
+ - Not using async patterns for I/O
80321
+ - Long-running operations without progress feedback
80322
+
80323
+ 5. **React-Specific Issues**
80324
+ - Missing dependency arrays causing infinite loops
80325
+ - Creating new objects/functions in render
80326
+ - Not using \`key\` prop properly in lists
80327
+ - State updates in useEffect without proper deps
80328
+
80329
+ ### Platform-Specific Considerations
80330
+
80331
+ **Next.js:**
80332
+ - Server Components for static content
80333
+ - Client Components for interactive elements
80334
+ - Image optimization with next/image
80335
+ - Route segment config for caching
80336
+
80337
+ **Convex:**
80338
+ - Query indexing for filtered/sorted data
80339
+ - Pagination for large result sets
80340
+ - Optimistic updates for better UX
80341
+ - Reactive queries vs. one-time fetches
80342
+
80343
+ **General Web:**
80344
+ - Core Web Vitals (LCP, FID, CLS)
80345
+ - Time to Interactive (TTI)
80346
+ - First Contentful Paint (FCP)
80347
+
80348
+ ### Questions to Ask
80349
+
80350
+ 1. "Will this scale with 10x/100x more data?"
80351
+ 2. "What happens with slow network conditions?"
80352
+ 3. "Are there any O(n²) or worse algorithms?"
80353
+ 4. "Could this operation be batched or debounced?"
80354
+ 5. "Is this computation necessary on every render?"
80355
+
80356
+ **Important:** These are general guidelines. Performance requirements vary by application.
80357
+ Focus on user-facing performance impact rather than micro-optimizations.
80358
+ `;
80359
+
78156
80360
  // ../../services/backend/prompts/generator.ts
80361
+ var exports_generator = {};
80362
+ __export(exports_generator, {
80363
+ getSecurityPolicy: () => getSecurityPolicy,
80364
+ getReviewGuidelines: () => getReviewGuidelines,
80365
+ getPerformancePolicy: () => getPerformancePolicy,
80366
+ getDesignPolicy: () => getDesignPolicy,
80367
+ generateRolePrompt: () => generateRolePrompt,
80368
+ generateHandoffOutput: () => generateHandoffOutput,
80369
+ generateGeneralInstructions: () => generateGeneralInstructions,
80370
+ composeSystemPrompt: () => composeSystemPrompt2,
80371
+ composeInitPrompt: () => composeInitPrompt,
80372
+ composeInitMessage: () => composeInitMessage
80373
+ });
80374
+ function generateGeneralInstructions(_input) {
80375
+ const sections = [];
80376
+ sections.push(getNextTaskGuidance());
80377
+ return sections.join(`
80378
+
80379
+ `);
80380
+ }
80381
+ function generateRolePrompt(ctx) {
80382
+ const selectorCtx = buildSelectorContext({
80383
+ role: ctx.role,
80384
+ teamRoles: ctx.teamRoles,
80385
+ teamId: ctx.teamId,
80386
+ teamName: ctx.teamName,
80387
+ teamEntryPoint: ctx.teamEntryPoint,
80388
+ convexUrl: ctx.convexUrl,
80389
+ chatroomId: ctx.chatroomId,
80390
+ workflow: ctx.currentClassification
80391
+ });
80392
+ const sections = [];
80393
+ sections.push(getRoleTitleSection(selectorCtx));
80394
+ sections.push(getRoleDescriptionSection(selectorCtx));
80395
+ sections.push(getGlossarySection({ convexUrl: ctx.convexUrl ?? "", chatroomId: ctx.chatroomId }));
80396
+ sections.push(getRoleGuidanceSection(selectorCtx));
80397
+ if (ctx.currentClassification) {
80398
+ sections.push(getCurrentClassificationSection(ctx.currentClassification));
80399
+ }
80400
+ sections.push(getHandoffOptionsSection({
80401
+ availableHandoffRoles: ctx.availableHandoffRoles
80402
+ }));
80403
+ sections.push(getCommandsReferenceSection({
80404
+ chatroomId: ctx.chatroomId,
80405
+ role: ctx.role,
80406
+ convexUrl: ctx.convexUrl
80407
+ }));
80408
+ return composeSections(sections);
80409
+ }
80410
+ function buildInitPromptSections(input, selectorCtx) {
80411
+ const { chatroomId, role, teamRoles, convexUrl } = input;
80412
+ const otherRoles = teamRoles.filter((r) => r.toLowerCase() !== role.toLowerCase());
80413
+ const handoffTargets = [...new Set([...otherRoles, "user"])];
80414
+ const sections = [
80415
+ getTeamHeaderSection(input.teamName),
80416
+ getRoleTitleSection(selectorCtx),
80417
+ getRoleDescriptionSection(selectorCtx),
80418
+ getGlossarySection({ convexUrl: convexUrl ?? "", chatroomId }),
80419
+ getSessionVsChatroomTaskSection(),
80420
+ getGettingStartedSection(selectorCtx),
80421
+ getClassificationGuideSection(selectorCtx),
80422
+ getRoleGuidanceSection(selectorCtx),
80423
+ getHandoffOptionsSection({ availableHandoffRoles: handoffTargets }),
80424
+ getCommandsReferenceSection({ chatroomId, role, convexUrl }),
80425
+ getNextStepSection({ chatroomId, role, convexUrl })
80426
+ ];
80427
+ return sections;
80428
+ }
80429
+ function composeSystemPrompt2(input) {
80430
+ if (isNativeHarness(input.agentHarness)) {
80431
+ return composeNativeSystemPrompt(input);
80432
+ }
80433
+ const { chatroomId, role, teamId, teamName, teamRoles, teamEntryPoint, convexUrl } = input;
80434
+ const selectorCtx = buildSelectorContext({
80435
+ role,
80436
+ teamRoles,
80437
+ teamId,
80438
+ teamName,
80439
+ teamEntryPoint,
80440
+ convexUrl,
80441
+ chatroomId,
80442
+ agentType: input.agentType,
80443
+ nativeIntegration: false
80444
+ });
80445
+ return composeSections(buildInitPromptSections(input, selectorCtx));
80446
+ }
78157
80447
  function generateHandoffOutput(params) {
78158
80448
  const { role, nextRole, chatroomId, convexUrl, supportsNativeIntegration } = params;
78159
80449
  const cliEnvPrefix = getCliEnvPrefix(convexUrl);
@@ -78171,6 +80461,17 @@ function generateHandoffOutput(params) {
78171
80461
  return lines.join(`
78172
80462
  `);
78173
80463
  }
80464
+ function composeInitMessage(_input) {
80465
+ return "";
80466
+ }
80467
+ function composeInitPrompt(input) {
80468
+ const systemPrompt = composeSystemPrompt2(input);
80469
+ const initMessage = composeInitMessage(input);
80470
+ const initPrompt = initMessage ? `${systemPrompt}
80471
+
80472
+ ${initMessage}` : systemPrompt;
80473
+ return { systemPrompt, initMessage, initPrompt };
80474
+ }
78174
80475
  var init_generator = __esm(() => {
78175
80476
  init_command();
78176
80477
  init_reminder();
@@ -79085,6 +81386,83 @@ var init_complete = __esm(() => {
79085
81386
  init_error_formatting();
79086
81387
  });
79087
81388
 
81389
+ // src/commands/enhancer/complete.ts
81390
+ var exports_complete2 = {};
81391
+ __export(exports_complete2, {
81392
+ enhancerComplete: () => enhancerComplete
81393
+ });
81394
+ async function createDefaultDeps10() {
81395
+ const client4 = await getConvexClient();
81396
+ return {
81397
+ backend: {
81398
+ mutation: (endpoint, args2) => client4.mutation(endpoint, args2),
81399
+ query: (endpoint, args2) => client4.query(endpoint, args2)
81400
+ },
81401
+ session: {
81402
+ getSessionId,
81403
+ getConvexUrl,
81404
+ getOtherSessionUrls
81405
+ }
81406
+ };
81407
+ }
81408
+ function handleCompleteError2(err) {
81409
+ return exports_Effect.sync(() => {
81410
+ if (err._tag === "NotAuthenticated") {
81411
+ formatAuthError(err.convexUrl, err.otherUrls);
81412
+ process.exit(1);
81413
+ }
81414
+ if (err._tag === "InvalidChatroomId") {
81415
+ formatChatroomIdError(err.id);
81416
+ process.exit(1);
81417
+ }
81418
+ console.error(`
81419
+ ❌ ERROR: Enhancer complete failed`);
81420
+ console.error(`
81421
+ ${err.errorData?.message ?? err.cause.message}`);
81422
+ process.exit(1);
81423
+ });
81424
+ }
81425
+ async function enhancerComplete(chatroomId, options) {
81426
+ const deps = await createDefaultDeps10();
81427
+ await exports_Effect.runPromise(enhancerCompleteEffect(chatroomId, options).pipe(exports_Effect.provide(commandServicesLayerFromDeps(deps)), exports_Effect.catchAll(handleCompleteError2)));
81428
+ }
81429
+ var enhancerCompleteEffect = (chatroomId, options) => exports_Effect.gen(function* () {
81430
+ const backend2 = yield* BackendService;
81431
+ const sessionId = yield* requireSessionIdEffect((a) => ({
81432
+ _tag: "NotAuthenticated",
81433
+ convexUrl: a.convexUrl,
81434
+ otherUrls: a.otherUrls
81435
+ }));
81436
+ yield* validateChatroomIdEffect(chatroomId, (id3) => ({
81437
+ _tag: "InvalidChatroomId",
81438
+ id: id3
81439
+ }));
81440
+ yield* backend2.mutation(api.web.enhancer.index.complete, {
81441
+ sessionId,
81442
+ chatroomId,
81443
+ jobId: options.jobId,
81444
+ enhancedContent: options.enhancedContent
81445
+ }).pipe(exports_Effect.mapError((cause3) => {
81446
+ let errorData;
81447
+ if (cause3 instanceof ConvexError) {
81448
+ errorData = cause3.data;
81449
+ }
81450
+ return { _tag: "CompleteFailed", cause: cause3, errorData };
81451
+ }));
81452
+ yield* exports_Effect.sync(() => {
81453
+ console.log(`✅ Enhancer job ${options.jobId} completed`);
81454
+ });
81455
+ });
81456
+ var init_complete2 = __esm(() => {
81457
+ init_values();
81458
+ init_esm();
81459
+ init_api3();
81460
+ init_storage();
81461
+ init_client2();
81462
+ init_services();
81463
+ init_error_formatting();
81464
+ });
81465
+
79088
81466
  // src/commands/backlog/backlog-fs-service.ts
79089
81467
  import * as nodeFs from "node:fs/promises";
79090
81468
  var BacklogFsService, BacklogFsServiceLive, BacklogFsServiceFrom = (ops) => exports_Layer.succeed(BacklogFsService, {
@@ -79191,7 +81569,7 @@ function buildBaseLayer(d) {
79191
81569
  function buildFsLayer(fs11) {
79192
81570
  return fs11 ? BacklogFsServiceFrom(fs11) : BacklogFsServiceLive;
79193
81571
  }
79194
- async function createDefaultDeps10() {
81572
+ async function createDefaultDeps11() {
79195
81573
  const client4 = await getConvexClient();
79196
81574
  const fs11 = await import("node:fs/promises");
79197
81575
  return {
@@ -79247,47 +81625,47 @@ function computeContentHash(content) {
79247
81625
  return createHash("sha256").update(content).digest("hex");
79248
81626
  }
79249
81627
  async function listBacklog(chatroomId, options, deps) {
79250
- const d = deps ?? await createDefaultDeps10();
81628
+ const d = deps ?? await createDefaultDeps11();
79251
81629
  await exports_Effect.runPromise(listBacklogEffect(chatroomId, options).pipe(exports_Effect.catchAll(handleBacklogError), exports_Effect.provide(buildBaseLayer(d))));
79252
81630
  }
79253
81631
  async function addBacklog(chatroomId, options, deps) {
79254
- const d = deps ?? await createDefaultDeps10();
81632
+ const d = deps ?? await createDefaultDeps11();
79255
81633
  await exports_Effect.runPromise(addBacklogEffect(chatroomId, options).pipe(exports_Effect.catchAll(handleBacklogError), exports_Effect.provide(buildBaseLayer(d))));
79256
81634
  }
79257
81635
  async function completeBacklog(chatroomId, options, deps) {
79258
- const d = deps ?? await createDefaultDeps10();
81636
+ const d = deps ?? await createDefaultDeps11();
79259
81637
  await exports_Effect.runPromise(completeBacklogEffect(chatroomId, options).pipe(exports_Effect.catchAll(handleBacklogError), exports_Effect.provide(buildBaseLayer(d))));
79260
81638
  }
79261
81639
  async function reopenBacklog(chatroomId, options, deps) {
79262
- const d = deps ?? await createDefaultDeps10();
81640
+ const d = deps ?? await createDefaultDeps11();
79263
81641
  await exports_Effect.runPromise(reopenBacklogEffect(chatroomId, options).pipe(exports_Effect.catchAll(handleBacklogError), exports_Effect.provide(buildBaseLayer(d))));
79264
81642
  }
79265
81643
  async function patchBacklog(chatroomId, options, deps) {
79266
- const d = deps ?? await createDefaultDeps10();
81644
+ const d = deps ?? await createDefaultDeps11();
79267
81645
  await exports_Effect.runPromise(patchBacklogEffect(chatroomId, options).pipe(exports_Effect.catchAll(handleBacklogError), exports_Effect.provide(buildBaseLayer(d))));
79268
81646
  }
79269
81647
  async function scoreBacklog(chatroomId, options, deps) {
79270
- const d = deps ?? await createDefaultDeps10();
81648
+ const d = deps ?? await createDefaultDeps11();
79271
81649
  await exports_Effect.runPromise(scoreBacklogEffect(chatroomId, options).pipe(exports_Effect.catchAll(handleBacklogError), exports_Effect.provide(buildBaseLayer(d))));
79272
81650
  }
79273
81651
  async function markForReviewBacklog(chatroomId, options, deps) {
79274
- const d = deps ?? await createDefaultDeps10();
81652
+ const d = deps ?? await createDefaultDeps11();
79275
81653
  await exports_Effect.runPromise(markForReviewBacklogEffect(chatroomId, options).pipe(exports_Effect.catchAll(handleBacklogError), exports_Effect.provide(buildBaseLayer(d))));
79276
81654
  }
79277
81655
  async function historyBacklog(chatroomId, options, deps) {
79278
- const d = deps ?? await createDefaultDeps10();
81656
+ const d = deps ?? await createDefaultDeps11();
79279
81657
  await exports_Effect.runPromise(historyBacklogEffect(chatroomId, options).pipe(exports_Effect.catchAll(handleBacklogError), exports_Effect.provide(buildBaseLayer(d))));
79280
81658
  }
79281
81659
  async function updateBacklog(chatroomId, options, deps) {
79282
- const d = deps ?? await createDefaultDeps10();
81660
+ const d = deps ?? await createDefaultDeps11();
79283
81661
  await exports_Effect.runPromise(updateBacklogEffect(chatroomId, options).pipe(exports_Effect.catchAll(handleBacklogError), exports_Effect.provide(buildBaseLayer(d))));
79284
81662
  }
79285
81663
  async function closeBacklog(chatroomId, options, deps) {
79286
- const d = deps ?? await createDefaultDeps10();
81664
+ const d = deps ?? await createDefaultDeps11();
79287
81665
  await exports_Effect.runPromise(closeBacklogEffect(chatroomId, options).pipe(exports_Effect.catchAll(handleBacklogError), exports_Effect.provide(buildBaseLayer(d))));
79288
81666
  }
79289
81667
  async function exportBacklog(chatroomId, options, deps) {
79290
- const d = deps ?? await createDefaultDeps10();
81668
+ const d = deps ?? await createDefaultDeps11();
79291
81669
  if (!d.fs) {
79292
81670
  console.error("❌ File system operations not available");
79293
81671
  process.exit(1);
@@ -79296,7 +81674,7 @@ async function exportBacklog(chatroomId, options, deps) {
79296
81674
  await exports_Effect.runPromise(exportBacklogEffect(chatroomId, options).pipe(exports_Effect.catchAll(handleBacklogError), exports_Effect.provide(exports_Layer.merge(buildBaseLayer(d), buildFsLayer(d.fs)))));
79297
81675
  }
79298
81676
  async function importBacklog(chatroomId, options, deps) {
79299
- const d = deps ?? await createDefaultDeps10();
81677
+ const d = deps ?? await createDefaultDeps11();
79300
81678
  if (!d.fs) {
79301
81679
  console.error("❌ File system operations not available");
79302
81680
  process.exit(1);
@@ -80057,7 +82435,7 @@ __export(exports_read, {
80057
82435
  taskReadEffect: () => taskReadEffect,
80058
82436
  taskRead: () => taskRead
80059
82437
  });
80060
- async function createDefaultDeps11() {
82438
+ async function createDefaultDeps12() {
80061
82439
  const client4 = await getConvexClient();
80062
82440
  return {
80063
82441
  backend: {
@@ -80099,7 +82477,7 @@ function handleTaskReadError(err) {
80099
82477
  });
80100
82478
  }
80101
82479
  async function taskRead(chatroomId, options, deps) {
80102
- const d = deps ?? await createDefaultDeps11();
82480
+ const d = deps ?? await createDefaultDeps12();
80103
82481
  const layer = commandServicesLayerFromDeps(d);
80104
82482
  await exports_Effect.runPromise(taskReadEffect(chatroomId, options).pipe(exports_Effect.catchAll((err) => handleTaskReadError(err)), exports_Effect.provide(layer)));
80105
82483
  }
@@ -80190,7 +82568,7 @@ __export(exports_skill, {
80190
82568
  activateSkillEffect: () => activateSkillEffect,
80191
82569
  activateSkill: () => activateSkill
80192
82570
  });
80193
- async function createDefaultDeps12() {
82571
+ async function createDefaultDeps13() {
80194
82572
  const client4 = await getConvexClient();
80195
82573
  return {
80196
82574
  backend: {
@@ -80259,12 +82637,12 @@ function handleActivateSkillError(err) {
80259
82637
  });
80260
82638
  }
80261
82639
  async function listSkills(chatroomId, options, deps) {
80262
- const d = deps ?? await createDefaultDeps12();
82640
+ const d = deps ?? await createDefaultDeps13();
80263
82641
  const layer = commandServicesLayerFromDeps(d);
80264
82642
  await exports_Effect.runPromise(listSkillsEffect(chatroomId, options).pipe(exports_Effect.catchAll((err) => handleListSkillsError(err)), exports_Effect.provide(layer)));
80265
82643
  }
80266
82644
  async function activateSkill(chatroomId, skillId, options, deps) {
80267
- const d = deps ?? await createDefaultDeps12();
82645
+ const d = deps ?? await createDefaultDeps13();
80268
82646
  const layer = commandServicesLayerFromDeps(d);
80269
82647
  await exports_Effect.runPromise(activateSkillEffect(chatroomId, skillId, options).pipe(exports_Effect.catchAll((err) => handleActivateSkillError(err)), exports_Effect.provide(layer)));
80270
82648
  }
@@ -80342,7 +82720,7 @@ __export(exports_messages, {
80342
82720
  listBySenderRoleEffect: () => listBySenderRoleEffect,
80343
82721
  listBySenderRole: () => listBySenderRole
80344
82722
  });
80345
- async function createDefaultDeps13() {
82723
+ async function createDefaultDeps14() {
80346
82724
  const client4 = await getConvexClient();
80347
82725
  return {
80348
82726
  backend: {
@@ -80403,12 +82781,12 @@ function handleMessagesError(err) {
80403
82781
  });
80404
82782
  }
80405
82783
  async function listBySenderRole(chatroomId, options, deps) {
80406
- const d = deps ?? await createDefaultDeps13();
82784
+ const d = deps ?? await createDefaultDeps14();
80407
82785
  const layer = commandServicesLayerFromDeps(d);
80408
82786
  await exports_Effect.runPromise(listBySenderRoleEffect(chatroomId, options).pipe(exports_Effect.catchAll((err) => handleMessagesError(err)), exports_Effect.provide(layer)));
80409
82787
  }
80410
82788
  async function listSinceMessage(chatroomId, options, deps) {
80411
- const d = deps ?? await createDefaultDeps13();
82789
+ const d = deps ?? await createDefaultDeps14();
80412
82790
  const layer = commandServicesLayerFromDeps(d);
80413
82791
  await exports_Effect.runPromise(listSinceMessageEffect(chatroomId, options).pipe(exports_Effect.catchAll((err) => handleMessagesError(err)), exports_Effect.provide(layer)));
80414
82792
  }
@@ -80538,7 +82916,7 @@ __export(exports_context2, {
80538
82916
  inspectContextEffect: () => inspectContextEffect,
80539
82917
  inspectContext: () => inspectContext
80540
82918
  });
80541
- async function createDefaultDeps14() {
82919
+ async function createDefaultDeps15() {
80542
82920
  const client4 = await getConvexClient();
80543
82921
  return {
80544
82922
  backend: {
@@ -80579,17 +82957,17 @@ function handleContextError(err) {
80579
82957
  });
80580
82958
  }
80581
82959
  async function readContext(chatroomId, options, deps) {
80582
- const d = deps ?? await createDefaultDeps14();
82960
+ const d = deps ?? await createDefaultDeps15();
80583
82961
  const layer = commandServicesLayerFromDeps(d);
80584
82962
  await exports_Effect.runPromise(readContextEffect(chatroomId, options).pipe(exports_Effect.catchAll((err) => handleContextError(err)), exports_Effect.provide(layer)));
80585
82963
  }
80586
82964
  async function newContext(chatroomId, options, deps) {
80587
- const d = deps ?? await createDefaultDeps14();
82965
+ const d = deps ?? await createDefaultDeps15();
80588
82966
  const layer = commandServicesLayerFromDeps(d);
80589
82967
  await exports_Effect.runPromise(newContextEffect(chatroomId, options).pipe(exports_Effect.catchAll((err) => handleContextError(err)), exports_Effect.provide(layer)));
80590
82968
  }
80591
82969
  async function listContexts(chatroomId, options, deps) {
80592
- const d = deps ?? await createDefaultDeps14();
82970
+ const d = deps ?? await createDefaultDeps15();
80593
82971
  const layer = commandServicesLayerFromDeps(d);
80594
82972
  await exports_Effect.runPromise(listContextsEffect(chatroomId, options).pipe(exports_Effect.catchAll((err) => handleContextError(err)), exports_Effect.provide(layer)));
80595
82973
  }
@@ -80597,7 +82975,7 @@ function viewTemplate() {
80597
82975
  return getContextViewTemplate();
80598
82976
  }
80599
82977
  async function inspectContext(chatroomId, options, deps) {
80600
- const d = deps ?? await createDefaultDeps14();
82978
+ const d = deps ?? await createDefaultDeps15();
80601
82979
  const layer = commandServicesLayerFromDeps(d);
80602
82980
  await exports_Effect.runPromise(inspectContextEffect(chatroomId, options).pipe(exports_Effect.catchAll((err) => handleContextError(err)), exports_Effect.provide(layer)));
80603
82981
  }
@@ -80838,7 +83216,7 @@ __export(exports_guidelines, {
80838
83216
  listGuidelineTypesEffect: () => listGuidelineTypesEffect,
80839
83217
  listGuidelineTypes: () => listGuidelineTypes
80840
83218
  });
80841
- async function createDefaultDeps15() {
83219
+ async function createDefaultDeps16() {
80842
83220
  const client4 = await getConvexClient();
80843
83221
  return {
80844
83222
  backend: {
@@ -80879,12 +83257,12 @@ function handleListGuidelineTypesError(err) {
80879
83257
  });
80880
83258
  }
80881
83259
  async function viewGuidelines(options, deps) {
80882
- const d = deps ?? await createDefaultDeps15();
83260
+ const d = deps ?? await createDefaultDeps16();
80883
83261
  const layer = layerFromDeps7(d);
80884
83262
  await exports_Effect.runPromise(viewGuidelinesEffect(options).pipe(exports_Effect.catchAll((err) => handleViewGuidelinesError(err)), exports_Effect.provide(layer)));
80885
83263
  }
80886
83264
  async function listGuidelineTypes(deps) {
80887
- const d = deps ?? await createDefaultDeps15();
83265
+ const d = deps ?? await createDefaultDeps16();
80888
83266
  const layer = layerFromDeps7(d);
80889
83267
  await exports_Effect.runPromise(listGuidelineTypesEffect().pipe(exports_Effect.catchAll((err) => handleListGuidelineTypesError(err)), exports_Effect.provide(layer)));
80890
83268
  }
@@ -80954,7 +83332,7 @@ __export(exports_artifact, {
80954
83332
  createArtifactEffect: () => createArtifactEffect,
80955
83333
  createArtifact: () => createArtifact
80956
83334
  });
80957
- async function createDefaultDeps16() {
83335
+ async function createDefaultDeps17() {
80958
83336
  const client4 = await getConvexClient();
80959
83337
  return {
80960
83338
  backend: {
@@ -80976,19 +83354,19 @@ function handleArtifactError(err) {
80976
83354
  });
80977
83355
  }
80978
83356
  async function createArtifact(chatroomId, options, deps) {
80979
- const d = deps ?? await createDefaultDeps16();
83357
+ const d = deps ?? await createDefaultDeps17();
80980
83358
  const layer = commandServicesLayerFromDeps(d);
80981
83359
  return exports_Effect.runPromise(createArtifactEffect(chatroomId, options).pipe(exports_Effect.catchAll((err) => handleArtifactError(err).pipe(exports_Effect.map(() => {
80982
83360
  return;
80983
83361
  }))), exports_Effect.provide(layer)));
80984
83362
  }
80985
83363
  async function viewArtifact(chatroomId, options, deps) {
80986
- const d = deps ?? await createDefaultDeps16();
83364
+ const d = deps ?? await createDefaultDeps17();
80987
83365
  const layer = commandServicesLayerFromDeps(d);
80988
83366
  await exports_Effect.runPromise(viewArtifactEffect(chatroomId, options).pipe(exports_Effect.catchAll((err) => handleArtifactError(err)), exports_Effect.provide(layer)));
80989
83367
  }
80990
83368
  async function viewManyArtifacts(chatroomId, options, deps) {
80991
- const d = deps ?? await createDefaultDeps16();
83369
+ const d = deps ?? await createDefaultDeps17();
80992
83370
  const layer = commandServicesLayerFromDeps(d);
80993
83371
  await exports_Effect.runPromise(viewManyArtifactsEffect(chatroomId, options).pipe(exports_Effect.catchAll((err) => handleArtifactError(err)), exports_Effect.provide(layer)));
80994
83372
  }
@@ -81338,7 +83716,7 @@ __export(exports_telegram, {
81338
83716
  sendMessageEffect: () => sendMessageEffect,
81339
83717
  sendMessage: () => sendMessage
81340
83718
  });
81341
- async function createDefaultDeps17() {
83719
+ async function createDefaultDeps18() {
81342
83720
  const client4 = await getConvexClient();
81343
83721
  return {
81344
83722
  backend: {
@@ -81420,7 +83798,7 @@ ${err.cause.message}`);
81420
83798
  });
81421
83799
  }
81422
83800
  async function sendMessage(options, deps) {
81423
- const d = deps ?? await createDefaultDeps17();
83801
+ const d = deps ?? await createDefaultDeps18();
81424
83802
  const layer = layerFromDeps8(d);
81425
83803
  await exports_Effect.runPromise(sendMessageEffect(options).pipe(exports_Effect.catchAll((err) => handleSendMessageError(err)), exports_Effect.provide(layer)));
81426
83804
  }
@@ -81471,18 +83849,6 @@ var init_featureFlags = __esm(() => {
81471
83849
  };
81472
83850
  });
81473
83851
 
81474
- // ../../services/backend/config/reliability.ts
81475
- var HARNESS_SESSION_READY_TIMEOUT_MS = 5000, NATIVE_DELIVERY_RECONCILE_MS = 1e4, DAEMON_HEARTBEAT_INTERVAL_MS, DAEMON_HEARTBEAT_TTL_MS, AGENT_REQUEST_DEADLINE_MS = 120000, OBSERVED_FULL_PUSH_INTERVAL_MS, OBSERVED_SAFETY_POLL_MS = 30000, OBSERVED_SYNC_RECONCILE_MS, WORKSPACE_RECENCY_WINDOW_MS, WORKSPACE_LIST_RECONCILE_MS, CONNECTION_CLOSE_REQUEST_TTL_MS;
81476
- var init_reliability = __esm(() => {
81477
- DAEMON_HEARTBEAT_INTERVAL_MS = 5 * 60000;
81478
- DAEMON_HEARTBEAT_TTL_MS = 6 * DAEMON_HEARTBEAT_INTERVAL_MS;
81479
- OBSERVED_FULL_PUSH_INTERVAL_MS = 5 * 60000;
81480
- OBSERVED_SYNC_RECONCILE_MS = 15 * 60000;
81481
- WORKSPACE_RECENCY_WINDOW_MS = 7 * 24 * 60 * 60 * 1000;
81482
- WORKSPACE_LIST_RECONCILE_MS = 60 * 60 * 1000;
81483
- CONNECTION_CLOSE_REQUEST_TTL_MS = 10 * 60000;
81484
- });
81485
-
81486
83852
  // src/commands/machine/daemon-start/command-event-types.ts
81487
83853
  function isDaemonCommandEventType(value) {
81488
83854
  return DAEMON_COMMAND_EVENT_TYPES.includes(value);
@@ -96924,7 +99290,7 @@ async function emitPhase(deps, event, phase, detail) {
96924
99290
  detail
96925
99291
  });
96926
99292
  }
96927
- function sleep5(ms) {
99293
+ function sleep6(ms) {
96928
99294
  return new Promise((resolve4) => setTimeout(resolve4, ms));
96929
99295
  }
96930
99296
  async function waitForHarnessSessionId(deps, event, pid) {
@@ -96946,7 +99312,7 @@ async function waitForHarnessSessionId(deps, event, pid) {
96946
99312
  if (slot?.harnessSessionId) {
96947
99313
  return slot.harnessSessionId;
96948
99314
  }
96949
- await sleep5(100);
99315
+ await sleep6(100);
96950
99316
  }
96951
99317
  await deps.session.backend.mutation(api.machines.emitHarnessSessionTimeout, {
96952
99318
  sessionId: deps.session.sessionId,
@@ -98454,7 +100820,7 @@ function logWaitingForShutdown(pid) {
98454
100820
  function logDaemonAlreadyRunning(pid) {
98455
100821
  console.error(`❌ Daemon already running for ${getConvexUrl()} (PID: ${pid})`);
98456
100822
  }
98457
- async function waitForLockOrTimeout(deadline, intervalMs, sleep6) {
100823
+ async function waitForLockOrTimeout(deadline, intervalMs, sleep7) {
98458
100824
  let loggedWait = false;
98459
100825
  while (Date.now() < deadline) {
98460
100826
  if (tryAcquireLock()) {
@@ -98465,16 +100831,16 @@ async function waitForLockOrTimeout(deadline, intervalMs, sleep6) {
98465
100831
  logWaitingForShutdown(pid);
98466
100832
  loggedWait = true;
98467
100833
  }
98468
- await sleep6(intervalMs);
100834
+ await sleep7(intervalMs);
98469
100835
  }
98470
100836
  return false;
98471
100837
  }
98472
100838
  async function acquireLockWithRetry(options) {
98473
100839
  const intervalMs = options?.intervalMs ?? LOCK_RETRY_INTERVAL_MS;
98474
100840
  const maxWaitMs = options?.maxWaitMs ?? LOCK_RETRY_MAX_WAIT_MS;
98475
- const sleep6 = options?.sleep ?? ((ms) => new Promise((resolve4) => setTimeout(resolve4, ms)));
100841
+ const sleep7 = options?.sleep ?? ((ms) => new Promise((resolve4) => setTimeout(resolve4, ms)));
98476
100842
  const deadline = Date.now() + maxWaitMs;
98477
- if (await waitForLockOrTimeout(deadline, intervalMs, sleep6)) {
100843
+ if (await waitForLockOrTimeout(deadline, intervalMs, sleep7)) {
98478
100844
  return true;
98479
100845
  }
98480
100846
  const { pid } = isDaemonRunning();
@@ -101470,6 +103836,104 @@ var init_start_subscriptions2 = __esm(() => {
101470
103836
  init_convex_agentic_query_run_repository();
101471
103837
  });
101472
103838
 
103839
+ // src/commands/machine/daemon-start/enhancer/constants.ts
103840
+ var ENHANCER_AGENT_ROLE = "enhancer";
103841
+
103842
+ // src/commands/machine/daemon-start/enhancer/job-subscriber.ts
103843
+ function startEnhancerJobSubscriber(sessionId, machineId, convexUrl, backend2, wsClient2, agentServices) {
103844
+ const inFlight = new Set;
103845
+ const unsub = wsClient2.onUpdate(api.daemon.enhancer.index.pendingForMachine, { sessionId, machineId }, (jobs) => {
103846
+ for (const job of jobs ?? []) {
103847
+ if (inFlight.has(job.jobId))
103848
+ continue;
103849
+ inFlight.add(job.jobId);
103850
+ (async () => {
103851
+ let claimed = false;
103852
+ let chatroomId = job.chatroomId;
103853
+ let jobId = job.jobId;
103854
+ try {
103855
+ const claim = await backend2.mutation(api.daemon.enhancer.index.claimForSpawn, {
103856
+ sessionId,
103857
+ jobId: job.jobId,
103858
+ machineId
103859
+ });
103860
+ if (!claim.claimed)
103861
+ return;
103862
+ claimed = true;
103863
+ const payload = await backend2.query(api.daemon.enhancer.index.getSpawnPayload, {
103864
+ sessionId,
103865
+ jobId: job.jobId
103866
+ });
103867
+ chatroomId = payload.chatroomId;
103868
+ jobId = payload.jobId;
103869
+ const service3 = agentServices.get(payload.agentHarness);
103870
+ if (!service3) {
103871
+ await backend2.mutation(api.web.enhancer.index.recordAttemptFailure, {
103872
+ sessionId,
103873
+ chatroomId: payload.chatroomId,
103874
+ jobId: payload.jobId,
103875
+ error: `Harness ${payload.agentHarness} not available on machine`
103876
+ });
103877
+ return;
103878
+ }
103879
+ const spawnResult = await service3.spawn({
103880
+ workingDir: payload.workingDir,
103881
+ prompt: createSpawnPrompt(payload.taskEnvelope),
103882
+ systemPrompt: payload.systemPrompt,
103883
+ model: payload.model,
103884
+ context: {
103885
+ machineId,
103886
+ chatroomId: payload.chatroomId,
103887
+ role: ENHANCER_AGENT_ROLE
103888
+ },
103889
+ resolvedConvexUrl: convexUrl
103890
+ });
103891
+ await new Promise((resolve4) => {
103892
+ spawnResult.onExit(() => resolve4());
103893
+ });
103894
+ const status3 = await backend2.query(api.web.enhancer.index.getJob, {
103895
+ sessionId,
103896
+ chatroomId: payload.chatroomId,
103897
+ jobId: payload.jobId
103898
+ });
103899
+ if (status3?.status === "running") {
103900
+ await backend2.mutation(api.web.enhancer.index.recordAttemptFailure, {
103901
+ sessionId,
103902
+ chatroomId: payload.chatroomId,
103903
+ jobId: payload.jobId,
103904
+ error: "Agent exited without completing enhancer job"
103905
+ });
103906
+ }
103907
+ } catch (err) {
103908
+ console.warn("[enhancer] spawn error:", err instanceof Error ? err.message : String(err));
103909
+ if (claimed) {
103910
+ await backend2.mutation(api.web.enhancer.index.recordAttemptFailure, {
103911
+ sessionId,
103912
+ chatroomId,
103913
+ jobId,
103914
+ error: err instanceof Error ? err.message : String(err)
103915
+ });
103916
+ }
103917
+ } finally {
103918
+ inFlight.delete(job.jobId);
103919
+ }
103920
+ })();
103921
+ }
103922
+ }, (err) => console.warn("[enhancer] subscription error:", err));
103923
+ return { stop: unsub };
103924
+ }
103925
+ var init_job_subscriber = __esm(() => {
103926
+ init_api3();
103927
+ });
103928
+
103929
+ // src/commands/machine/daemon-start/enhancer/start-subscriptions.ts
103930
+ function startEnhancerSubscriptions(sessionId, machineId, convexUrl, backend2, wsClient2, agentServices) {
103931
+ return startEnhancerJobSubscriber(sessionId, machineId, convexUrl, backend2, wsClient2, agentServices);
103932
+ }
103933
+ var init_start_subscriptions3 = __esm(() => {
103934
+ init_job_subscriber();
103935
+ });
103936
+
101473
103937
  // src/commands/machine/daemon-start/file-content-classifier.ts
101474
103938
  function extensionOf(path3) {
101475
103939
  const lastDot = path3.lastIndexOf(".");
@@ -108912,7 +111376,7 @@ async function discoverModelsForHarness(harness, service3) {
108912
111376
  async function discoverModels(agentServices) {
108913
111377
  return exports_Effect.runPromise(discoverModelsEffect(agentServices));
108914
111378
  }
108915
- function createDefaultDeps18() {
111379
+ function createDefaultDeps19() {
108916
111380
  return {
108917
111381
  backend: {
108918
111382
  mutation: async () => {
@@ -109250,7 +111714,7 @@ var init_init2 = __esm(() => {
109250
111714
  convexUrl,
109251
111715
  agentServices,
109252
111716
  cachedModels,
109253
- deps: createDefaultDeps18()
111717
+ deps: createDefaultDeps19()
109254
111718
  });
109255
111719
  yield* registerEventListenersEffect().pipe(exports_Effect.provide(daemonSessionToLayers(init2)));
109256
111720
  yield* logStartupEffect(cachedModels).pipe(exports_Effect.provide(daemonSessionToLayers(init2)));
@@ -112217,6 +114681,7 @@ var init_command_loop = __esm(() => {
112217
114681
  init_daemon_services();
112218
114682
  init_start_subscriptions();
112219
114683
  init_start_subscriptions2();
114684
+ init_start_subscriptions3();
112220
114685
  init_file_content_subscription();
112221
114686
  init_file_tree_subscription();
112222
114687
  init_file_write_subscription();
@@ -112403,6 +114868,7 @@ var init_command_loop = __esm(() => {
112403
114868
  }, wsClient2, activeSessions, harnesses);
112404
114869
  aqPendingPromptSubscriptionHandle = aqHandles.pendingPromptSubscriptionHandle;
112405
114870
  aqPendingHarnessSessionSubscriptionHandle = aqHandles.pendingHarnessSessionSubscriptionHandle;
114871
+ const enhancerSub = startEnhancerSubscriptions(session2.sessionId, session2.machineId, session2.convexUrl, session2.backend, wsClient2, session2.agentServices);
112406
114872
  }
112407
114873
  console.log(`
112408
114874
  Listening for commands...`);
@@ -112597,7 +115063,7 @@ async function isChatroomInstalledDefault() {
112597
115063
  return false;
112598
115064
  }
112599
115065
  }
112600
- async function createDefaultDeps19() {
115066
+ async function createDefaultDeps20() {
112601
115067
  const client4 = await getConvexClient();
112602
115068
  const fs12 = await import("fs/promises");
112603
115069
  return {
@@ -112672,7 +115138,7 @@ After installation, run this command again.`;
112672
115138
  });
112673
115139
  }
112674
115140
  async function installTool(options = {}, deps) {
112675
- const d = deps ?? await createDefaultDeps19();
115141
+ const d = deps ?? await createDefaultDeps20();
112676
115142
  const layer = layerFromDeps9(d);
112677
115143
  return exports_Effect.runPromise(installToolEffect(options).pipe(exports_Effect.catchAll((err) => handleInstallError(err)), exports_Effect.provide(layer)));
112678
115144
  }
@@ -113223,6 +115689,68 @@ handoffCommandGroup.requiredOption("--chatroom-id <id>", "Chatroom identifier").
113223
115689
  console.error("❌ Message is empty");
113224
115690
  process.exit(1);
113225
115691
  }
115692
+ const shouldEnhance = options.role.toLowerCase() === "planner" && options.nextRole.toLowerCase() === "builder";
115693
+ if (shouldEnhance) {
115694
+ const { api: api3 } = await Promise.resolve().then(() => (init_api3(), exports_api));
115695
+ const { getConvexClient: getConvexClient2 } = await Promise.resolve().then(() => (init_client2(), exports_client));
115696
+ const { getSessionId: getSessionId2 } = await Promise.resolve().then(() => (init_storage(), exports_storage));
115697
+ const { waitForEnhancerJob: waitForEnhancerJob2 } = await Promise.resolve().then(() => (init_wait_for_job(), exports_wait_for_job));
115698
+ const client4 = await getConvexClient2();
115699
+ const sessionId = await getSessionId2();
115700
+ if (sessionId) {
115701
+ try {
115702
+ const config4 = await client4.query(api3.web.enhancer.index.getConfig, {
115703
+ sessionId,
115704
+ chatroomId: options.chatroomId
115705
+ });
115706
+ if (config4 && config4.enabled) {
115707
+ const result = await client4.mutation(api3.web.enhancer.index.enqueueHandoff, {
115708
+ sessionId,
115709
+ chatroomId: options.chatroomId,
115710
+ senderRole: options.role,
115711
+ targetRole: options.nextRole,
115712
+ content: message
115713
+ });
115714
+ const jobId = result.jobId;
115715
+ const outcome = await waitForEnhancerJob2(options.chatroomId, jobId, {
115716
+ query: (endpoint, args2) => client4.query(endpoint, args2),
115717
+ mutation: (endpoint, args2) => client4.mutation(endpoint, args2),
115718
+ getSessionId: () => Promise.resolve(sessionId),
115719
+ endpoints: {
115720
+ getJob: api3.web.enhancer.index.getJob,
115721
+ recordAttemptFailure: api3.web.enhancer.index.recordAttemptFailure
115722
+ }
115723
+ });
115724
+ if (outcome === "failed") {
115725
+ console.error(`
115726
+ ❌ ERROR: Enhancer failed after all retries. No handoff was delivered.`);
115727
+ process.exit(1);
115728
+ }
115729
+ if (outcome === "cancelled" || outcome === "complete") {
115730
+ const { generateHandoffOutput: generateHandoffOutput2 } = await Promise.resolve().then(() => (init_generator(), exports_generator));
115731
+ const { getConvexUrl: getConvexUrl2 } = await Promise.resolve().then(() => (init_client2(), exports_client));
115732
+ const convexUrl = await getConvexUrl2();
115733
+ console.log(generateHandoffOutput2({
115734
+ role: options.role,
115735
+ nextRole: options.nextRole,
115736
+ chatroomId: options.chatroomId,
115737
+ convexUrl
115738
+ }));
115739
+ return;
115740
+ }
115741
+ }
115742
+ } catch (err) {
115743
+ const error51 = err;
115744
+ if (error51?.data?.code !== "ENHANCER_NOT_ENABLED") {
115745
+ console.error(`
115746
+ ❌ ERROR: Enhancer interception failed`);
115747
+ console.error(`
115748
+ ${error51?.data?.message ?? err.message}`);
115749
+ process.exit(1);
115750
+ }
115751
+ }
115752
+ }
115753
+ }
113226
115754
  const { handoff: handoff2 } = await Promise.resolve().then(() => (init_handoff(), exports_handoff));
113227
115755
  await handoff2(options.chatroomId, {
113228
115756
  role: options.role,
@@ -113257,6 +115785,29 @@ agenticQueryCommand.command("complete").description("Submit the structured agent
113257
115785
  result
113258
115786
  });
113259
115787
  });
115788
+ var enhancerCommand = program2.command("enhancer").description("Handoff enhancer commands");
115789
+ enhancerCommand.command("complete").description("Submit the enhanced handoff markdown").requiredOption("--chatroom-id <id>", "Chatroom identifier").requiredOption("--job-id <id>", "Enhancer job identifier").action(async (options) => {
115790
+ await maybeRequireAuth();
115791
+ const { decode: decode5 } = await Promise.resolve().then(() => exports_decode);
115792
+ const stdinContent = await readStdin();
115793
+ let body;
115794
+ try {
115795
+ const { ENHANCER_STDIN_DELIMITER: ENHANCER_STDIN_DELIMITER2, HANDOFF_MESSAGE_MARKER: HANDOFF_MESSAGE_MARKER2, validateStdinHeredocBody: validateStdinHeredocBody2 } = await Promise.resolve().then(() => (init_stdin_heredoc(), exports_stdin_heredoc));
115796
+ const decoded = decode5(stdinContent, { singleParam: "result" });
115797
+ body = decoded.result;
115798
+ body = body.replace(new RegExp(`^(${HANDOFF_MESSAGE_MARKER2}\\s*)+`, "i"), "").trim();
115799
+ validateStdinHeredocBody2(body, ENHANCER_STDIN_DELIMITER2);
115800
+ } catch (err) {
115801
+ console.error(`❌ Failed to decode stdin: ${err.message}`);
115802
+ process.exit(1);
115803
+ }
115804
+ if (!body?.trim()) {
115805
+ console.error("❌ Enhanced handoff body is empty");
115806
+ process.exit(1);
115807
+ }
115808
+ const { enhancerComplete: enhancerComplete2 } = await Promise.resolve().then(() => (init_complete2(), exports_complete2));
115809
+ await enhancerComplete2(options.chatroomId, { jobId: options.jobId, enhancedContent: body });
115810
+ });
113260
115811
  var backlogCommand = program2.command("backlog").description("Manage task queue and backlog");
113261
115812
  backlogCommand.command("list").description("List backlog items").requiredOption("--chatroom-id <id>", "Chatroom identifier").requiredOption("--role <role>", "Your role").option("--limit <n>", "Maximum number of items to show").option("--sort <sort>", "Sort order: date:desc (default) | priority:desc").option("--filter <filter>", "Filter: unscored (only items without priority score)").action(async (options) => {
113262
115813
  await maybeRequireAuth();
@@ -113541,4 +116092,4 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
113541
116092
  });
113542
116093
  program2.parse();
113543
116094
 
113544
- //# debugId=5D81C0C1AF371BE564756E2164756E21
116095
+ //# debugId=594320A213AD613364756E2164756E21