chatroom-cli 1.73.1 → 1.75.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
@@ -77736,6 +77857,24 @@ function formatDecodeError(error) {
77736
77857
  }
77737
77858
 
77738
77859
  // ../../services/backend/prompts/native/session-continuity.ts
77860
+ function getSessionContinuityLine(nativeIntegration) {
77861
+ if (nativeIntegration) {
77862
+ return "";
77863
+ }
77864
+ return "Completing a **chatroom task** (Level B) does NOT end your **session** (Level A). After every handoff, run `get-next-task` to continue.";
77865
+ }
77866
+ function getHandoffContinuityRule(nativeIntegration) {
77867
+ if (nativeIntegration) {
77868
+ return "";
77869
+ }
77870
+ return "⚠️ After ANY handoff (including to `user`), you must run `get-next-task` to stay in the session.";
77871
+ }
77872
+ function getOperatingModelLoopFooter(nativeIntegration) {
77873
+ return nativeIntegration ? "Hand off when complete" : "Run get-next-task";
77874
+ }
77875
+ function getNativePlannerDelegationWaitNote() {
77876
+ 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.`;
77877
+ }
77739
77878
  function getNativeHandoffTurnEndGuidance(nextRole) {
77740
77879
  const lines = [
77741
77880
  "",
@@ -77751,10 +77890,103 @@ function getNativeHandoffTurnEndGuidance(nextRole) {
77751
77890
  }
77752
77891
 
77753
77892
  // ../../services/backend/prompts/cli/handoff/command.ts
77893
+ function handoffCommand(params) {
77894
+ const prefix = params.cliEnvPrefix || "";
77895
+ const chatroomId = params.chatroomId || "<chatroom-id>";
77896
+ const role = params.role || "<role>";
77897
+ const nextRole = params.nextRole || "<target>";
77898
+ const placeholder = params.messagePlaceholder ?? "[Your message here]";
77899
+ const commandPrefix = `${prefix}chatroom handoff --chatroom-id="${chatroomId}" --role="${role}" --next-role="${nextRole}"`;
77900
+ return formatStdinHeredocCommand(commandPrefix, HANDOFF_STDIN_DELIMITER, placeholder, {
77901
+ messageMarker: HANDOFF_MESSAGE_MARKER
77902
+ });
77903
+ }
77754
77904
  var init_command2 = __esm(() => {
77755
77905
  init_stdin_heredoc();
77756
77906
  });
77907
+
77908
+ // ../../services/backend/prompts/types/sections.ts
77909
+ function createSection(id3, type, content) {
77910
+ return { id: id3, type, content };
77911
+ }
77912
+ function composeSections(sections) {
77913
+ return sections.filter((s) => s.content.trim()).map((s) => s.content).join(`
77914
+
77915
+ `).trim();
77916
+ }
77917
+
77757
77918
  // ../../services/backend/prompts/sections/commands-reference.ts
77919
+ function getCommandsReferenceSection(params) {
77920
+ const cliEnvPrefix = getCliEnvPrefix(params.convexUrl);
77921
+ const handoffCmd = handoffCommand({
77922
+ chatroomId: params.chatroomId,
77923
+ role: params.role,
77924
+ nextRole: "<target>",
77925
+ cliEnvPrefix
77926
+ });
77927
+ const waitCmd = getNextTaskCommand({
77928
+ chatroomId: params.chatroomId,
77929
+ role: params.role,
77930
+ cliEnvPrefix
77931
+ });
77932
+ const content = `### Commands
77933
+
77934
+ **Complete chatroom task and hand off:**
77935
+
77936
+ \`\`\`bash
77937
+ ${handoffCmd}
77938
+ \`\`\`
77939
+
77940
+ ${HANDOFF_BODY_GUIDANCE}
77941
+
77942
+ **Continue receiving messages after \`handoff\`:**
77943
+ \`\`\`
77944
+ ${waitCmd}
77945
+ \`\`\`
77946
+
77947
+ ${getNextTaskReminder()}
77948
+
77949
+ **Reference commands:**
77950
+ - List recent messages: \`${cliEnvPrefix}chatroom messages list --chatroom-id="${params.chatroomId}" --role="${params.role}" --sender-role=user --limit=5 --full\`
77951
+ - Git log: \`git log --oneline -10\`
77952
+
77953
+ **Recovery commands** (only needed after compaction/restart):
77954
+ - Reload system prompt: \`${cliEnvPrefix}chatroom get-system-prompt --chatroom-id="${params.chatroomId}" --role="${params.role}"\`
77955
+ - Reload role guidance: \`${roleGuidanceCommand({ chatroomId: params.chatroomId, role: params.role, cliEnvPrefix })}\`
77956
+ - Read current chatroom task context: \`${cliEnvPrefix}chatroom context read --chatroom-id="${params.chatroomId}" --role="${params.role}"\``;
77957
+ return createSection("commands-reference", "knowledge", content);
77958
+ }
77959
+ function getNativeCommandsReferenceSection(params) {
77960
+ const cliEnvPrefix = getCliEnvPrefix(params.convexUrl);
77961
+ const handoffCmd = handoffCommand({
77962
+ chatroomId: params.chatroomId,
77963
+ role: params.role,
77964
+ nextRole: "<target>",
77965
+ cliEnvPrefix
77966
+ });
77967
+ const content = `### Commands
77968
+
77969
+ **Complete chatroom task and hand off:**
77970
+
77971
+ \`\`\`bash
77972
+ ${handoffCmd}
77973
+ \`\`\`
77974
+
77975
+ ${HANDOFF_BODY_GUIDANCE}
77976
+
77977
+ **Do not run \`register-agent\`** — your session was registered when the harness started.
77978
+
77979
+ **Reference commands:**
77980
+ - List recent messages: \`${cliEnvPrefix}chatroom messages list --chatroom-id="${params.chatroomId}" --role="${params.role}" --sender-role=user --limit=5 --full\`
77981
+ - Git log: \`git log --oneline -10\`
77982
+
77983
+ **Recovery commands** (only needed after compaction/restart):
77984
+ - Reload system prompt: \`${cliEnvPrefix}chatroom get-system-prompt --chatroom-id="${params.chatroomId}" --role="${params.role}"\`
77985
+ - Reload role guidance: \`${roleGuidanceCommand({ chatroomId: params.chatroomId, role: params.role, cliEnvPrefix })}\`
77986
+ - Read current chatroom task context: \`${cliEnvPrefix}chatroom context read --chatroom-id="${params.chatroomId}" --role="${params.role}"\``;
77987
+ return createSection("commands-reference-native", "knowledge", content);
77988
+ }
77989
+ 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
77990
  var init_commands_reference = __esm(() => {
77759
77991
  init_command();
77760
77992
  init_reminder();
@@ -77763,25 +77995,650 @@ var init_commands_reference = __esm(() => {
77763
77995
  });
77764
77996
 
77765
77997
  // ../../services/backend/prompts/cli/backlog/command.ts
77998
+ function backlogAddCommand(params) {
77999
+ const prefix = params.cliEnvPrefix || "";
78000
+ const chatroomId = params.chatroomId || "<id>";
78001
+ const role = params.role || "<role>";
78002
+ const placeholder = params.contentPlaceholder ?? "Your backlog item content here";
78003
+ const commandPrefix = `${prefix}chatroom backlog add --chatroom-id=${chatroomId} --role=${role}`;
78004
+ return formatStdinHeredocCommand(commandPrefix, BACKLOG_STDIN_DELIMITER, placeholder);
78005
+ }
78006
+ function backlogUpdateCommand(params) {
78007
+ const prefix = params.cliEnvPrefix || "";
78008
+ const chatroomId = params.chatroomId || "<id>";
78009
+ const role = params.role || "<role>";
78010
+ const backlogItemId = params.backlogItemId || "<id>";
78011
+ const placeholder = params.contentPlaceholder ?? "New content here";
78012
+ const commandPrefix = `${prefix}chatroom backlog update --chatroom-id=${chatroomId} --role=${role} --backlog-item-id=${backlogItemId}`;
78013
+ return formatStdinHeredocCommand(commandPrefix, BACKLOG_STDIN_DELIMITER, placeholder);
78014
+ }
77766
78015
  var init_command3 = __esm(() => {
77767
78016
  init_stdin_heredoc();
77768
78017
  });
77769
78018
 
77770
78019
  // ../../services/backend/src/domain/usecase/skills/modules/backlog/index.ts
78020
+ var backlogSkill;
77771
78021
  var init_backlog = __esm(() => {
77772
78022
  init_command3();
78023
+ backlogSkill = {
78024
+ skillId: "backlog",
78025
+ name: "Backlog Reference",
78026
+ description: "Full backlog command reference: list/add/update, scoring, completion, close, export/import, and workflow guides.",
78027
+ getPrompt: (cliEnvPrefix) => `You have been activated with the "backlog" skill.
78028
+
78029
+ ## Command Reference
78030
+
78031
+ ### List
78032
+ \`\`\`
78033
+ ${cliEnvPrefix}chatroom backlog list --chatroom-id=<id> --role=<role>
78034
+ \`\`\`
78035
+ Options: \`--limit=<n>\`, \`--sort=date:desc|priority:desc\`, \`--filter=unscored\` (only items without a priority score)
78036
+
78037
+ The list output shows scoring info (complexity, value, priority) for each item if it has been scored.
78038
+
78039
+ ### History
78040
+ \`\`\`
78041
+ ${cliEnvPrefix}chatroom backlog history --chatroom-id=<id> --role=<role>
78042
+ \`\`\`
78043
+ Options: \`--from=YYYY-MM-DD\`, \`--to=YYYY-MM-DD\`, \`--limit=<n>\`
78044
+
78045
+ Defaults: last 30 days through today; shows completed and closed tasks in range.
78046
+
78047
+ Use \`history\` for finished work; use \`list\` for active backlog items.
78048
+
78049
+ ### Add
78050
+ Content via **stdin / heredoc** or \`--content-file\`:
78051
+
78052
+ \`\`\`
78053
+ ${backlogAddCommand({ cliEnvPrefix })}
78054
+ \`\`\`
78055
+
78056
+ \`\`\`
78057
+ ${cliEnvPrefix}chatroom backlog add --chatroom-id=<id> --role=<role> --content-file=./task.md
78058
+ \`\`\`
78059
+
78060
+ ### Update
78061
+ 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\`).
78062
+
78063
+ \`\`\`
78064
+ ${backlogUpdateCommand({ cliEnvPrefix })}
78065
+ \`\`\`
78066
+
78067
+ \`\`\`
78068
+ ${cliEnvPrefix}chatroom backlog update --chatroom-id=<id> --role=<role> --backlog-item-id=<id> --content-file=./revised.md
78069
+ \`\`\`
78070
+
78071
+ Use **update** to revise a description in place instead of adding a superseding item.
78072
+
78073
+ ### Score
78074
+ **Requires at least one** of \`--complexity\`, \`--value\`, or \`--priority\` (you can combine multiple).
78075
+
78076
+ \`\`\`
78077
+ ${cliEnvPrefix}chatroom backlog score --chatroom-id=<id> --role=<role> --backlog-item-id=<id> \\
78078
+ [--complexity=<low|medium|high>] \\
78079
+ [--value=<low|medium|high>] \\
78080
+ [--priority=<n>]
78081
+ \`\`\`
78082
+
78083
+ \`--priority\` must be an integer (higher = more important). There is no enforced max in the CLI.
78084
+
78085
+ **Important**: Only score items that do not already have all three fields set (complexity, value, priority).
78086
+ Check the list output — items showing "Score: ..." are already scored. Skip them to avoid overwriting.
78087
+
78088
+ ### Complete
78089
+ \`\`\`
78090
+ ${cliEnvPrefix}chatroom backlog complete --chatroom-id=<id> --role=<role> --backlog-item-id=<id> [-f|--force]
78091
+ \`\`\`
78092
+
78093
+ 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.
78094
+
78095
+ ### Reopen
78096
+ \`\`\`
78097
+ ${cliEnvPrefix}chatroom backlog reopen --chatroom-id=<id> --role=<role> --backlog-item-id=<id>
78098
+ \`\`\`
78099
+
78100
+ ### Mark for Review
78101
+ \`\`\`
78102
+ ${cliEnvPrefix}chatroom backlog mark-for-review --chatroom-id=<id> --role=<role> --backlog-item-id=<id>
78103
+ \`\`\`
78104
+
78105
+ ### Export
78106
+ \`\`\`
78107
+ ${cliEnvPrefix}chatroom backlog export --chatroom-id=<id> --role=<role> [--path=<directory>]
78108
+ \`\`\`
78109
+ Exports all backlog items (status=\`backlog\`) to a \`backlog-export.json\` file in the specified directory.
78110
+ Creates the directory if it doesn't exist.
78111
+ Default path (if \`--path\` is omitted): \`<cwd>/.chatroom/exports/\`
78112
+
78113
+ ### Import
78114
+ \`\`\`
78115
+ ${cliEnvPrefix}chatroom backlog import --chatroom-id=<id> --role=<role> [--path=<directory>]
78116
+ \`\`\`
78117
+ Imports backlog items from a \`backlog-export.json\` file in the specified directory.
78118
+ - **Idempotent**: skips items whose content already exists (matched by SHA-256 content hash)
78119
+ - **Staleness warning**: warns if the export is older than 7 days
78120
+ Default path (if \`--path\` is omitted): \`<cwd>/.chatroom/exports/\`
78121
+
78122
+ ### Close
78123
+ Retires an item as stale, superseded, or duplicate. **\`--reason\` is required** (audit trail).
78124
+
78125
+ \`\`\`
78126
+ ${cliEnvPrefix}chatroom backlog close --chatroom-id=<id> --role=<role> --backlog-item-id=<id> --reason="duplicate of XYZ"
78127
+ \`\`\`
78128
+
78129
+ ⚠️ **RESTRICTED: Only use when the user explicitly asks you to close an item.**
78130
+ Agents must NEVER close backlog items autonomously. If an item looks stale or already implemented, prefer \`mark-for-review\` so the user decides.
78131
+
78132
+ Give a concise, factual reason (e.g. \`User confirmed: shipped in PR #119\`).
78133
+
78134
+ ---
78135
+
78136
+ ## Lifecycle
78137
+
78138
+ 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).
78139
+
78140
+ \`\`\`mermaid
78141
+ stateDiagram-v2
78142
+ [*] --> backlog: user creates
78143
+ backlog --> pending_user_review: agent raises PR (mark-for-review)
78144
+ pending_user_review --> closed: user confirms / PR merged (complete)
78145
+ backlog --> closed: stale/superseded (close)
78146
+ closed --> backlog: reopen
78147
+ \`\`\`
78148
+
78149
+ ### Command decision table
78150
+
78151
+ | Situation | Command |
78152
+ |-----------|---------|
78153
+ | Fix PR opened, awaiting user review/merge | \`mark-for-review\` |
78154
+ | PR merged and verified | \`complete\` |
78155
+ | Stale/duplicate/won't fix | \`close --reason=...\` |
78156
+ | Mistakenly completed early | \`reopen\` then \`mark-for-review\` |
78157
+
78158
+ Reference: \`docs/plans/backlog-item-lifecycle-and-attachments.md\`
78159
+
78160
+ ---
78161
+
78162
+ ## Workflows
78163
+
78164
+ ### 1. Score Unscored Items
78165
+
78166
+ \`\`\`mermaid
78167
+ flowchart TD
78168
+ A([Start]) --> B[List backlog items]
78169
+ B --> C{Any unscored?}
78170
+ C -->|No| D([Done])
78171
+ C -->|Yes| E["Check item: does it already have complexity + value + priority set?"]
78172
+ E -->|Already scored| F[Skip — do not overwrite existing score]
78173
+ F --> C
78174
+ E -->|Not scored| G[Score item: complexity, value, priority]
78175
+ G --> C
78176
+ \`\`\`
78177
+
78178
+ An item is "already scored" if the list output shows "Score: complexity=... | value=... | priority=...".
78179
+
78180
+ ### 2. After Completing a Backlog Task (PR raised)
78181
+
78182
+ \`\`\`mermaid
78183
+ flowchart TD
78184
+ A([Implementation complete]) --> B[Open PR for user review]
78185
+ B --> C["mark-for-review (NOT complete)"]
78186
+ C --> D[Hand off to user with PR link + summary]
78187
+ D --> E([User reviews in Pending Review section])
78188
+ \`\`\`
78189
+
78190
+ Moves item to \`pending_user_review\`. User confirms completion (\`complete\`) or sends back for rework (\`reopen\`).
78191
+
78192
+ ### 3. Continuous Backlog Execution
78193
+
78194
+ Only activate when the user explicitly instructs autonomous execution
78195
+ (e.g. "work through the backlog", "autonomously implement backlog items").
78196
+
78197
+ \`\`\`mermaid
78198
+ flowchart TD
78199
+ A([Start]) --> B[List all backlog items]
78200
+ B --> C{Any unscored?}
78201
+ C -->|Yes| D["Score only items missing complexity/value/priority\\n(skip already-scored items)"] --> E[Re-list]
78202
+ C -->|No| E
78203
+ E --> F["Select items: complexity=low AND value=high"]
78204
+ F --> G{Qualifying items?}
78205
+ G -->|No| H([Hand off — no high-ROI items found])
78206
+ G -->|Yes| I[Take next item]
78207
+ I --> J{Already implemented?\\nCheck codebase / recent commits}
78208
+ J -->|Yes — stale| K["Mark for review\\n(note: already implemented)"]
78209
+ J -->|No| L[Implement: code changes + PR]
78210
+ L --> K
78211
+ K --> M[Mark item for review]
78212
+ M --> N{More items?}
78213
+ N -->|Yes| I
78214
+ N -->|No| O[Hand off to user with full summary]
78215
+ O --> P([Done])
78216
+ \`\`\`
78217
+
78218
+ Stale item = backlog task already present in the codebase. Mark immediately; skip implementation.
78219
+ ROI = low complexity × high value.
78220
+
78221
+ ### 4. Backlog Cleanup
78222
+
78223
+ Follow these steps to clean up the backlog by identifying and closing stale items.
78224
+
78225
+ 1. List all backlog items:
78226
+ \`\`\`
78227
+ ${cliEnvPrefix}chatroom backlog list --chatroom-id=<id> --role=<role>
78228
+ \`\`\`
78229
+
78230
+ 2. For each item, assess staleness:
78231
+ - Read the content carefully
78232
+ - 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)
78233
+ - Check if already implemented (look at recent commits, PRs, or existing code)
78234
+ - Check if superseded by a newer backlog item
78235
+
78236
+ 3. For stale items, mark for review:
78237
+ \`\`\`
78238
+ ${cliEnvPrefix}chatroom backlog mark-for-review --chatroom-id=<id> --role=<role> --backlog-item-id=<item-id>
78239
+ \`\`\`
78240
+ **Important:** Always mark for review — do NOT close directly. Let the user confirm.
78241
+
78242
+ 4. If you are the coordinator, delegate assessment to workers:
78243
+ - Builder checks codebase to determine if items are stale
78244
+ - Builder marks stale items for review and reports back
78245
+
78246
+ 5. Report summary: items reviewed, marked for review, kept, needs clarification
78247
+
78248
+ ### 5. Export / Import Backlog
78249
+
78250
+ Use export/import to transfer backlog items between workspaces or for backup.
78251
+ Default path: \`<cwd>/.chatroom/exports/\` — omit \`--path\` to use this.
78252
+
78253
+ **Export workflow:**
78254
+ \`\`\`mermaid
78255
+ flowchart TD
78256
+ A([Start]) --> B["Export backlog"]
78257
+ B --> C["chatroom backlog export\\n(writes to <cwd>/.chatroom/exports/ by default)"]
78258
+ C --> D["File written: backlog-export.json"]
78259
+ D --> E([Done — report file path to user])
78260
+ \`\`\`
78261
+
78262
+ **Import workflow:**
78263
+ \`\`\`mermaid
78264
+ flowchart TD
78265
+ A([Start]) --> B["Import backlog"]
78266
+ B --> C["chatroom backlog import\\n(reads from <cwd>/.chatroom/exports/ by default)"]
78267
+ C --> D{Staleness warning?}
78268
+ D -->|Yes — export > 7 days old| E["Warn user: export may be stale"]
78269
+ D -->|No| F["Import items (skip duplicates)"]
78270
+ E --> F
78271
+ F --> G["Report: total / imported / skipped"]
78272
+ G --> H([Done])
78273
+ \`\`\`
78274
+
78275
+ **Key points:**
78276
+ - Default path is \`<cwd>/.chatroom/exports/\` — no \`--path\` needed for standard usage
78277
+ - Use \`--path=<dir>\` to override with a custom directory
78278
+ - Imports are idempotent — running import twice with the same file won't create duplicates
78279
+ - Each item is identified by a SHA-256 hash of its content`
78280
+ };
77773
78281
  });
77774
78282
 
77775
78283
  // ../../services/backend/src/domain/usecase/skills/modules/code-review/index.ts
77776
- var init_code_review = () => {};
78284
+ var codeReviewSkill;
78285
+ var init_code_review = __esm(() => {
78286
+ codeReviewSkill = {
78287
+ skillId: "code-review",
78288
+ name: "Code Review",
78289
+ 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.",
78290
+ getPrompt: (_cliEnvPrefix) => `You have been activated with the "code-review" skill.
78291
+
78292
+ # AI Code Review — Tech Debt Prevention
78293
+
78294
+ You are reviewing code that was fully or partially generated by an AI tool. Your job is not
78295
+ just to check if it works — working code is the floor, not the ceiling. Your job is to assess
78296
+ whether it is maintainable, secure, and coherent with the broader codebase.
78297
+
78298
+ AI code is highly functional but architecturally blind. It implements the prompt without
78299
+ considering existing patterns, refactoring opportunities, or long-term cost. Research from
78300
+ 2025–2026 shows AI code carries 1.75x more logic errors, 1.64x more maintainability issues,
78301
+ and 1.57x more security findings than human-written code (CodeRabbit, 2025). 66% of developers
78302
+ report spending more time fixing AI output than it saved (Stack Overflow, 2026).
78303
+
78304
+ Apply the ten pillars below in priority order.
78305
+
78306
+ ---
78307
+
78308
+ ## How to run a review
78309
+
78310
+ 1. Read the code in full before making any comments — do not flag issues as you scan
78311
+ 2. Apply each pillar in order; stop and note findings as you go
78312
+ 3. Classify each finding as BLOCK (must fix before merge) or FLAG (must be addressed by author)
78313
+ 4. Summarise findings at the end using the output template below
78314
+ 5. If the PR is over ~300 lines of net-new AI code, recommend decomposition before review
78315
+
78316
+ ---
78317
+
78318
+ ## Pillar 1 — Simplification (Highest Priority)
78319
+
78320
+ AI generates more code than needed. The average developer checked in 75% more code in 2025
78321
+ than in 2022 — volume that the team now has to maintain. AI agents never suggest refactoring,
78322
+ so complexity accumulates silently.
78323
+
78324
+ Look for:
78325
+ - Functions over ~40 lines or classes over ~200 lines with no clear single responsibility
78326
+ - Monolithic architecture: 40–50% of AI code defaults to tightly-coupled structures that
78327
+ reverse a decade of modular progress (OX Security, 2025)
78328
+ - Phantom Bugs: logic handling highly improbable edge cases, adding complexity with no benefit
78329
+ (found in 20–30% of AI code)
78330
+ - Dead code, unused imports, or leftover scaffolding from generation
78331
+ - PRs that touch services, libraries, infrastructure, and tests in a single change
78332
+
78333
+ Ask: Is there a simpler path to the same outcome? Would a new team member understand this
78334
+ without help? Can this function be split without losing meaning?
78335
+
78336
+ Action: Flag any function over ~40 lines. Require decomposition or written justification
78337
+ before merge.
78338
+
78339
+ ---
78340
+
78341
+ ## Pillar 2 — Type Drift (High Priority)
78342
+
78343
+ AI generates code in isolation from the broader type system. Type inconsistencies introduced
78344
+ here surface later as null pointer exceptions, silent failures, and cross-service contract
78345
+ mismatches. A University of Naples study of 500k+ samples (Aug 2025) confirmed these are the
78346
+ most reliably catchable issues via static analysis — meaning they should never reach review.
78347
+
78348
+ Look for:
78349
+ - \`any\` usage: defeats TypeScript entirely; AI reaches for it when uncertain
78350
+ - Unsafe \`as\` assertions: suppresses the compiler rather than satisfying it
78351
+ - Missing \`strictNullChecks\` compliance — null/undefined slipping through unchecked
78352
+ - Boundary drift: API endpoints returning different shapes across execution paths
78353
+ - Configuration drift: divergent \`tsconfig\` settings or ESLint rules added incrementally
78354
+ - Leaked internals: AI exposing implementation details that should be encapsulated
78355
+
78356
+ Ask: Are all return types and parameters explicitly typed? Are API contract types shared and
78357
+ stable? Does this match existing type conventions, or introduce a new pattern?
78358
+
78359
+ Action: \`strict: true\` in \`tsconfig.json\` is a hard gate. Any PR disabling strict settings
78360
+ requires explicit team sign-off.
78361
+
78362
+ ---
78363
+
78364
+ ## Pillar 3 — Duplication (High Priority)
78365
+
78366
+ GitClear's 2025 analysis of 211 million changed lines found duplicated code blocks grew 8x
78367
+ in one year, and copy/pasted code surpassed refactored code for the first time in history.
78368
+ OX Security found "Bugs Déjà-Vu" in 70–80% of AI codebases: identical bugs recurring in
78369
+ multiple locations because logic was never abstracted.
78370
+
78371
+ Look for:
78372
+ - Duplicate utility logic across files — each instance works, but no shared abstraction exists
78373
+ - "Vanilla Style" rebuilds: AI reconstructing functionality from scratch instead of using
78374
+ existing libraries, SDKs, or internal utilities (40–50% of AI code, OX Security)
78375
+ - Duplicated validation, auth checks, and input sanitization
78376
+ - Copy-pasted try/catch blocks instead of centralised error handling
78377
+ - New dependencies that the existing codebase already covers
78378
+
78379
+ Ask: Does an equivalent utility already exist? Is this logic duplicated anywhere else?
78380
+ Use AST-level search, not just grep.
78381
+
78382
+ Action: Require a codebase search before approving any new utility function. Run SonarQube,
78383
+ CodeClimate, or Codacy as a PR gate for duplication thresholds.
78384
+
78385
+ ---
78386
+
78387
+ ## Pillar 4 — Design Pattern Compliance (Standard Priority)
78388
+
78389
+ AI implements the prompt. It does not check the ADR log, existing service patterns, or
78390
+ architectural conventions. OX Security identified "By-The-Book Fixation" in 80–90% of AI
78391
+ code: rigid application of generic best practices, missing the better solution for this
78392
+ specific context.
78393
+
78394
+ Look for:
78395
+ - Pattern violations: raw \`fetch\` where an API service layer exists; new state patterns where
78396
+ a store convention is already established
78397
+ - SOLID violations:
78398
+ - Single Responsibility: see Pillar 1
78399
+ - Open/Closed: code requiring modification rather than extension to add new behaviour
78400
+ - Dependency Inversion: hard-coded dependencies instead of injection
78401
+ - No refactoring suggestions — AI never proposes that a feature should trigger a refactor
78402
+ - Context blindness: ignoring ADRs, versioning strategy, or team-level conventions
78403
+
78404
+ Ask: Does this follow the patterns in this area of the codebase? Can this be extended without
78405
+ modification? Are dependencies injected?
78406
+
78407
+ Action: Maintain a living \`ARCHITECTURE.md\` or ADR log. Pass it as context to AI tools before
78408
+ generation, not after.
78409
+
78410
+ ---
78411
+
78412
+ ## Pillar 5 — Security (Standard Priority)
78413
+
78414
+ 45% of AI-generated code samples introduced OWASP Top 10 vulnerabilities in Veracode's 2025
78415
+ test of 100+ LLMs. CodeRabbit found AI code is 2.74x more likely to introduce XSS, 1.88x more
78416
+ likely to mishandle passwords, 1.82x more likely to implement insecure deserialization.
78417
+ OX Security calls this "insecure by dumbness" — not malicious, but structurally blind to
78418
+ security requirements that were not in the prompt.
78419
+
78420
+ Look for:
78421
+ - OWASP Top 10: injection (SQL, XSS, command), broken auth, insecure deserialization
78422
+ - "Worked on My Machine" syndrome (60–70% of AI code): missing environment awareness,
78423
+ hard-coded localhost references, assumed-present secrets
78424
+ - Missing auth/ownership checks — AI assumes the happy path; role gates rarely appear unprompted
78425
+ - Secrets, tokens, or credentials in source code
78426
+ - Deprecated API patterns from the model's training data
78427
+ - Excessive I/O (~8x human rate) and concurrency misuse (~2x human rate)
78428
+
78429
+ Ask: Are all inputs validated before use? Are auth checks present at every trust boundary?
78430
+ Does this code behave differently across environments?
78431
+
78432
+ Action: Run SAST tooling (Snyk, Semgrep, SonarQube) on every AI-generated PR as a CI gate.
78433
+ Manual review alone cannot keep pace with AI generation velocity.
78434
+
78435
+ ---
78436
+
78437
+ ## Pillar 6 — Test Quality (Standard Priority)
78438
+
78439
+ AI generates tests that look comprehensive but frequently are not. OX Security found "Fake
78440
+ Test Coverage" in 40–50% of AI codebases: inflated metrics, low signal. The failure mode is
78441
+ precise: AI tests its own assumptions, not the developer's intent. University of Naples (2025)
78442
+ confirmed that even code passing all functional benchmarks averaged 1.45–1.77 static issues
78443
+ per task.
78444
+
78445
+ Look for:
78446
+ - Tests that verify AI output is stable, not that it is correct by domain rules
78447
+ - Missing edge cases: empty inputs, boundary values, null handling, race conditions,
78448
+ business-rule violations
78449
+ - Coverage theater: tests that assert no exception was thrown and nothing more
78450
+ - No integration or contract tests — AI generates unit tests almost exclusively
78451
+ - Tests coupled to implementation: must be updated every time the code changes
78452
+
78453
+ Ask: Do these tests verify the domain intent? Would they catch a logic regression in the
78454
+ next PR? Are cross-service interactions tested?
78455
+
78456
+ Action: Test review is a separate pass from code review. Use mutation testing (Stryker,
78457
+ PITest) to validate whether tests catch real defects — coverage percentage is not sufficient.
78458
+
78459
+ ---
78460
+
78461
+ ## Pillar 7 — Ownership, Observability, Deployment (Standard Priority)
78462
+
78463
+ The most consistently missed category. ISACA's 2026 incident review found that the biggest
78464
+ AI failures of 2025 were organisational, not technical: weak controls and unclear ownership.
78465
+ Bright Security (2026) identified unclear ownership as one of the most dangerous patterns:
78466
+ code that works well enough that no one feels responsible for it. IBM's 2025 breach data found
78467
+ shadow AI added $670,000 average to breach costs.
78468
+
78469
+ Look for:
78470
+ - No named human owner — every AI-generated module needs someone who can explain it in a
78471
+ postmortem without reading it fresh
78472
+ - Missing structured logs, metrics emission, or tracing hooks
78473
+ - Swallowed exceptions: retry logic with no alerting; fallback paths invisible to operators
78474
+ - No environment-specific configuration, secrets management, or health check endpoints
78475
+ - Model versioning chaos: inconsistencies from team members using different AI tool versions
78476
+ - Shadow AI: code with no record of which tool or prompt produced it
78477
+
78478
+ Ask: Who owns this? Will production failures surface to operators? Does this behave
78479
+ differently across environments?
78480
+
78481
+ Action: Require every AI-generated module to have a named owner in CODEOWNERS. Add logging
78482
+ requirements to the PR template. Establish a team AI governance policy that tracks tools
78483
+ and model versions — treat this like any other dependency.
78484
+
78485
+ ---
78486
+
78487
+ ## Pillar 8 — Dead Code Elimination (Standard Priority)
78488
+
78489
+ AI generates code speculatively. It adds helper functions "just in case", creates abstractions
78490
+ for paths that never materialise, and leaves behind scaffolding from earlier generation
78491
+ attempts. GitClear's 2025 data showed a 75% increase in total code volume, much of it never
78492
+ executed. Dead code is not harmless — it misleads future readers, inflates bundle sizes, creates
78493
+ false positive search results, and adds surface area for bugs and security vulnerabilities
78494
+ in code that serves no purpose.
78495
+
78496
+ Look for:
78497
+ - Unreachable code: functions, methods, or branches that no call site ever invokes
78498
+ - Unused imports: modules imported but never referenced — common in AI-generated files
78499
+ - Commented-out code: old implementations left inline instead of being removed; version
78500
+ control already preserves history
78501
+ - Feature flags that are permanently off: conditional paths that were never enabled or have
78502
+ been superseded but not cleaned up
78503
+ - Orphaned configuration: environment variables, constants, or config entries with no consumer
78504
+ - Stale types and interfaces: type definitions for data shapes that no longer exist in the
78505
+ system
78506
+ - Unused dependencies: packages listed in \`package.json\` (or equivalent) that no source file
78507
+ imports
78508
+ - Vestigial error handling: catch blocks or fallback paths for conditions that can no longer
78509
+ occur due to upstream changes
78510
+ - Test helpers and fixtures for tests that have been deleted
78511
+
78512
+ Ask: Is every function called? Is every import used? Is every dependency exercised?
78513
+ Would removing this code change any observable behaviour?
78514
+
78515
+ Action: Run tree-shaking analysis and dead code detection tools (e.g., \`ts-prune\`,
78516
+ \`knip\`, \`depcheck\`, IDE unused-symbol highlighting) as part of CI. Treat dead code
78517
+ the same as duplication — it compounds over time and must be actively managed.
78518
+
78519
+ ---
78520
+
78521
+ ## Pillar 9 — Incomplete Implementations (Standard Priority)
78522
+
78523
+ AI tools often leave TODOs, stubs, "throw new Error('not implemented')", or placeholder
78524
+ returns when they hit uncertainty. The default assumption MUST be that these are bugs to fix,
78525
+ not features — unless the human explicitly requested a stub (e.g., scaffolding a future module).
78526
+
78527
+ Look for:
78528
+ - \`TODO\`, \`FIXME\`, \`XXX\`, \`HACK\` comments — especially without an assignee or ticket reference
78529
+ - Functions that throw "not implemented" / "unimplemented" errors
78530
+ - Empty function bodies or bodies that only return null/undefined/empty object as a placeholder
78531
+ - Switch/case branches with \`// handle later\` style comments
78532
+ - Conditional branches that silently fall through without handling a real case
78533
+ - Type definitions with fields marked \`any\` or \`unknown\` "to be refined later"
78534
+ - Tests with \`it.skip\`, \`xit\`, \`it.todo\` left in committed code without justification
78535
+
78536
+ Ask: Is every code path fully implemented? If a TODO exists, is there a tracked ticket and
78537
+ explicit reason it wasn't done now?
78538
+
78539
+ Action: Treat any TODO or stub as BLOCK unless the PR description or commit message explicitly
78540
+ justifies it (e.g., "scaffolding for follow-up PR #N"). Generated code with unprompted TODOs
78541
+ should be completed before merge, not after.
78542
+
78543
+ ---
78544
+
78545
+ ## Pillar 10 — Hallucinated Content & Magic Strings (Standard Priority)
78546
+
78547
+ AI generation frequently invents plausible-looking but incorrect values — API endpoints,
78548
+ env var names, library functions, config keys — and scatters magic strings/numbers across
78549
+ the codebase instead of consolidating them as named constants. Both fail at runtime or rot
78550
+ the codebase over time.
78551
+
78552
+ Look for:
78553
+ - Fabricated API endpoints, library functions, or package names that don't exist (verify against
78554
+ actual SDK docs / \`package.json\`)
78555
+ - Magic strings: status codes, role names, event types, feature flag keys appearing as inline
78556
+ literals across multiple files
78557
+ - Magic numbers: timeouts, limits, retry counts, port numbers without named constants
78558
+ - Placeholder content left in production paths: "lorem ipsum", "foo/bar", "example.com",
78559
+ "test@test.com"
78560
+ - Hardcoded URLs, file paths, or table/collection names that should come from config
78561
+ - Duplicated string literals that should be a single enum / const object
78562
+ - Configuration keys invented by the AI that don't match the project's actual config schema
78563
+
78564
+ Ask: Does every literal that carries domain meaning have a named home? Is every external
78565
+ reference (API, package, env var) verified to exist? Where SHOULD this constant live (entity
78566
+ enum, config module, shared constants file)?
78567
+
78568
+ Action: Consolidate magic literals into the canonical location for the codebase (typically
78569
+ enums alongside the relevant entity, or a dedicated constants module). For hallucinated
78570
+ references, treat as BLOCK — code that compiles against fictional APIs will fail in production.
78571
+
78572
+ ---
78573
+
78574
+ ## Output template
78575
+
78576
+ Use this format for every review. Do not skip sections.
78577
+
78578
+ \`\`\`
78579
+ ## AI Code Review — [filename or PR title]
78580
+
78581
+ ### Summary
78582
+ [2–3 sentences: overall quality signal, highest-risk area, recommended action]
78583
+
78584
+ ### BLOCK — must fix before merge
78585
+ [List findings. Format: PILLAR | finding | why it matters | suggested fix]
78586
+
78587
+ ### FLAG — author must respond
78588
+ [List findings. Same format.]
78589
+
78590
+ ### Passed
78591
+ [Pillars or areas with no significant findings]
78592
+
78593
+ ### Recommendation
78594
+ [ ] Approve [ ] Approve with flags addressed [ ] Decompose PR first [ ] Reject — rework required
78595
+ \`\`\``
78596
+ };
78597
+ });
77777
78598
 
77778
78599
  // ../../services/backend/src/domain/usecase/skills/registry.ts
78600
+ var SKILLS_REGISTRY;
77779
78601
  var init_registry3 = __esm(() => {
77780
78602
  init_backlog();
77781
78603
  init_code_review();
78604
+ SKILLS_REGISTRY = [backlogSkill, codeReviewSkill];
77782
78605
  });
77783
78606
 
77784
78607
  // ../../services/backend/prompts/sections/glossary.ts
78608
+ function formatGlossaryEntry(entry) {
78609
+ const skillNote = entry.linkedSkillId ? " (1 skill available)" : "";
78610
+ return [`- \`${entry.term}\`${skillNote}`, ` - ${entry.definition}`, ""];
78611
+ }
78612
+ function buildSkillsSection(cliEnvPrefix) {
78613
+ const lines = ["# Skills", ""];
78614
+ lines.push(`Run \`${cliEnvPrefix}chatroom skill list --chatroom-id=<id> --role=<role>\` to list all available skills.`);
78615
+ lines.push("");
78616
+ lines.push("## When to Activate Skills");
78617
+ lines.push("");
78618
+ lines.push("**Proactively activate skills** when your task matches their purpose:");
78619
+ for (const skill of SKILLS_REGISTRY) {
78620
+ lines.push(`- **${skill.skillId}**: ${skill.description}`);
78621
+ }
78622
+ lines.push("");
78623
+ lines.push("Don't wait for the user to ask — proactively activate the skill that matches the task.");
78624
+ return lines;
78625
+ }
78626
+ function getGlossarySection(params) {
78627
+ const cliEnvPrefix = getCliEnvPrefix(params.convexUrl);
78628
+ const lines = ["# Glossary", ""];
78629
+ const terms = params.nativeIntegration ? NATIVE_GLOSSARY_TERMS : GLOSSARY_TERMS;
78630
+ for (const entry of terms) {
78631
+ lines.push(...formatGlossaryEntry(entry));
78632
+ }
78633
+ if (params.compactSkills) {
78634
+ lines.push("# Skills", "");
78635
+ 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.`);
78636
+ } else {
78637
+ lines.push(...buildSkillsSection(cliEnvPrefix));
78638
+ }
78639
+ return createSection("glossary", "knowledge", lines.join(`
78640
+ `));
78641
+ }
77785
78642
  var GLOSSARY_TERMS, NATIVE_GLOSSARY_TERMS;
77786
78643
  var init_glossary = __esm(() => {
77787
78644
  init_registry3();
@@ -77832,10 +78689,249 @@ var init_glossary = __esm(() => {
77832
78689
  });
77833
78690
 
77834
78691
  // ../../services/backend/prompts/cli/roles/builder.ts
78692
+ function getBuilderFlowMermaid(nativeIntegration, codeChangesTarget, questionTarget) {
78693
+ const handoffNodes = ` D --> E[Commit work]
78694
+ E --> F{Code changes?}
78695
+ F -->|yes| G[Hand off to **${codeChangesTarget}**]
78696
+ F -->|no| H[Hand off to **${questionTarget}**]`;
78697
+ if (nativeIntegration) {
78698
+ return `flowchart TD
78699
+ A([Start]) --> B[Receive task]
78700
+ B --> D[Implement changes]
78701
+ ${handoffNodes}`;
78702
+ }
78703
+ return `flowchart TD
78704
+ A([Start]) --> B[Receive chatroom task]
78705
+ B --> D[Implement changes]
78706
+ ${handoffNodes}`;
78707
+ }
78708
+ function getBuilderGuidance(params) {
78709
+ const {
78710
+ questionTarget: questionTargetParam,
78711
+ codeChangesTarget: codeChangesTargetParam,
78712
+ nativeIntegration
78713
+ } = params;
78714
+ const questionTarget = questionTargetParam ?? "user";
78715
+ const codeChangesTarget = codeChangesTargetParam ?? "planner";
78716
+ return `
78717
+ ## Builder Operating Model
78718
+
78719
+ ${getSessionContinuityLine(nativeIntegration)}
78720
+
78721
+ You are responsible for implementing code changes based on requirements.
78722
+
78723
+ **Typical Flow:**
78724
+
78725
+ \`\`\`mermaid
78726
+ ${getBuilderFlowMermaid(nativeIntegration, codeChangesTarget, questionTarget)}
78727
+ \`\`\`
78728
+
78729
+ **Handoff Rules:**
78730
+ - **After code changes** → Hand off to \`${codeChangesTarget}\`
78731
+ - **For simple questions** → Can hand off directly to \`${questionTarget}\`
78732
+ ⚠️ 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.
78733
+
78734
+ **Implementation Guidelines:**
78735
+ - Write clean, maintainable, well-documented code
78736
+ - Follow established patterns and best practices from the codebase
78737
+ - Handle edge cases and error scenarios
78738
+ - Commit work with descriptive, atomic commit messages
78739
+ `;
78740
+ }
77835
78741
  var init_builder = () => {};
78742
+
78743
+ // ../../services/backend/prompts/cli/sections/core-responsibilities.ts
78744
+ function getCoreResponsibilitiesSection(config3) {
78745
+ 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.";
78746
+ return `**Core Responsibilities:**
78747
+ - **User Communication**: You are the ONLY role that communicates with the user. All responses to the user come through you.
78748
+ - **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.
78749
+ - **Quality Accountability**: You are ultimately accountable for all work. ${qualityLine}`;
78750
+ }
78751
+
78752
+ // ../../services/backend/prompts/cli/sections/delegation-and-decomposition.ts
78753
+ function getDelegationAndDecompositionSection(config3) {
78754
+ if (!config3.hasBuilder) {
78755
+ return "";
78756
+ }
78757
+ return `**Delegation & Decomposition:**
78758
+
78759
+ 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).`;
78760
+ }
78761
+
78762
+ // ../../services/backend/prompts/cli/sections/delegation-guidelines.ts
78763
+ function buildCmdHelper(cliEnvPrefix, chatroomIdArg, roleArg) {
78764
+ return (subcommand) => `\`${cliEnvPrefix}chatroom ${subcommand} --chatroom-id=${chatroomIdArg} --role=${roleArg}\``;
78765
+ }
78766
+ function getDelegationBriefReference() {
78767
+ return "Use the **Handoff to `builder`** template in the task delivery `<handoff-templates>` section — follow that structure in your handoff message.";
78768
+ }
78769
+ function getSoloImplementationGuidelines(cmd, feedingNote) {
78770
+ return `**Implementation Guidelines:**
78771
+
78772
+ Break complex features into small, focused slices. For code review guidance, activate the \`code-review\` skill: ${cmd("skill activate code-review")}.
78773
+
78774
+ - Implement one slice at a time; each slice ≈ one focused review surface.
78775
+ - Review your own work before moving on; re-validate after rework.
78776
+ - ${feedingNote}.`;
78777
+ }
78778
+ function getBuilderDelegationGuidelines(cmd, feedingNote, delegationBriefRef) {
78779
+ return `**Delegation Guidelines:**
78780
+
78781
+ 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")}.
78782
+
78783
+ **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.
78784
+
78785
+ **Decision flow:**
78786
+ \`\`\`mermaid
78787
+ flowchart TD
78788
+ A[Receive task] --> B{Code changes needed?}
78789
+ B -->|Yes — any size| D[Write a Delegation Brief]
78790
+ D --> E[Hand off ONE slice to builder]
78791
+ E --> F[Review output]
78792
+ F -->|Not acceptable| G[Hand back with feedback]
78793
+ G --> E
78794
+ F -->|Acceptable| H{More slices?}
78795
+ H -->|Yes| E
78796
+ H -->|No| I[Deliver to user]
78797
+ B -->|No: question or clarification only| C[Answer directly → deliver to user]
78798
+ \`\`\`
78799
+
78800
+ **Default: delegate with a Delegation Brief.** ${delegationBriefRef}
78801
+
78802
+ **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:
78803
+
78804
+ - **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.
78805
+ - **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").
78806
+ - **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.
78807
+ - **Spell out what to avoid** — anti-patterns and recurring mistakes you have seen from builders on similar work (scope creep, wrong abstractions, forbidden refactors).
78808
+ - **One slice ≈ one focused review surface.** If you can't imagine reviewing it in one sitting, split it.
78809
+ - **Order by dependency**, not by team convention. A slice should be runnable/testable when its dependencies are done.
78810
+ - **Skip phases that don't apply** (e.g., no frontend for a backend-only change, no schema for a pure refactor).
78811
+
78812
+ **Code review:** For code-producing work, review before delivering. Activate the review framework with: ${cmd("skill activate code-review")}.
78813
+
78814
+ **Backlog items:** When the task originates from a backlog item, activate the backlog skill: ${cmd("skill activate backlog")}.
78815
+
78816
+ **If stuck:** After 2 failed rework attempts → step back, replan the slice, or deliver partial results with a clear explanation.
78817
+
78818
+ **Review loop:**
78819
+ - Review completed work before moving to the next slice.
78820
+ - Send back with specific feedback if requirements aren't met.
78821
+ - ${feedingNote}.`;
78822
+ }
78823
+ function getDelegationGuidelinesSection(config3, options) {
78824
+ 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";
78825
+ const cliEnvPrefix = options?.cliEnvPrefix ?? "";
78826
+ const chatroomIdArg = options?.chatroomId ? `"${options.chatroomId}"` : "<id>";
78827
+ const roleArg = options?.role ? `"${options.role}"` : "<role>";
78828
+ const cmd = buildCmdHelper(cliEnvPrefix, chatroomIdArg, roleArg);
78829
+ if (!config3.hasBuilder) {
78830
+ return getSoloImplementationGuidelines(cmd, feedingNote);
78831
+ }
78832
+ return getBuilderDelegationGuidelines(cmd, feedingNote, getDelegationBriefReference());
78833
+ }
78834
+
77836
78835
  // ../../services/backend/prompts/cli/sections/handoff-rules.ts
78836
+ function buildHandoffRuleLines(config3) {
78837
+ return [
78838
+ 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)",
78839
+ "- **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.",
78840
+ 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"
78841
+ ].join(`
78842
+ `);
78843
+ }
78844
+ function getHandoffRulesSection(config3, nativeIntegration) {
78845
+ const continuityRule = getHandoffContinuityRule(nativeIntegration);
78846
+ const continuityBlock = continuityRule ? `${continuityRule}
78847
+
78848
+ ` : "";
78849
+ return `**Handoff Rules:**
78850
+
78851
+ ${continuityBlock}${buildHandoffRuleLines(config3)}`;
78852
+ }
77837
78853
  var init_handoff_rules = () => {};
78854
+
78855
+ // ../../services/backend/prompts/cli/sections/when-work-comes-back.ts
78856
+ function getWhenWorkComesBackSection(config3) {
78857
+ 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";
78858
+ return `**When you receive work back from team members:**
78859
+ 1. Review the completed work against the original user request
78860
+ 2. If requirements are met → deliver to \`user\`
78861
+ ${reworkLine}
78862
+ 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.`;
78863
+ }
78864
+
78865
+ // ../../services/backend/prompts/cli/sections/team-composition.ts
78866
+ function getTeamCompositionSection(teamMembers) {
78867
+ const isSoloRole = teamMembers.length === 1 && teamMembers[0]?.toLowerCase() === "solo";
78868
+ const nonPlannerMembers = teamMembers.filter((r) => r.toLowerCase() !== "planner");
78869
+ if (isSoloRole || nonPlannerMembers.length === 0) {
78870
+ return `**Team composition:** Solo team — you handle planning and implementation yourself.`;
78871
+ }
78872
+ const roleList = nonPlannerMembers.map((r) => `\`${r}\``).join(", ");
78873
+ return `**Team composition:** Duo team — you coordinate with ${roleList} for implementation.
78874
+
78875
+ **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.`;
78876
+ }
78877
+
77838
78878
  // ../../services/backend/prompts/cli/sections/operating-model.ts
78879
+ function getTaskIntakeNodes(nativeIntegration) {
78880
+ if (nativeIntegration) {
78881
+ return ` A([Start]) --> B[Receive user message]
78882
+ B --> E[Decompose into phases]`;
78883
+ }
78884
+ return ` A([Start]) --> B[Receive chatroom task from get-next-task]
78885
+ B --> E[Decompose into phases]`;
78886
+ }
78887
+ function getOperatingModelSection(config3, nativeIntegration) {
78888
+ if (config3.hasBuilder) {
78889
+ return getPlannerPlusBuilderOperatingModel(nativeIntegration);
78890
+ }
78891
+ return getPlannerSoloOperatingModel(nativeIntegration);
78892
+ }
78893
+ function getPlannerPlusBuilderOperatingModel(nativeIntegration) {
78894
+ const footer = getOperatingModelLoopFooter(nativeIntegration);
78895
+ const delegationNote = nativeIntegration ? getNativePlannerDelegationWaitNote() : "After delegating to the builder, hand off and wait for work to return.";
78896
+ return `**Operating model: Planner + Builder**
78897
+
78898
+ ${delegationNote}
78899
+
78900
+ \`\`\`mermaid
78901
+ flowchart TD
78902
+ ${getTaskIntakeNodes(nativeIntegration)}
78903
+ E --> F[Delegate ONE phase to builder]
78904
+ F --> G[Builder completes phase]
78905
+ G --> H[Builder hands off to planner]
78906
+ H --> I[Review builder output]
78907
+ I --> J{phase acceptable?}
78908
+ J -->|no| K[Hand back to builder with feedback]
78909
+ K --> F
78910
+ J -->|yes| L{more phases?}
78911
+ L -->|yes| F
78912
+ L -->|no| O[Deliver final result to user]
78913
+ O --> P[${footer}] --> B
78914
+ \`\`\``;
78915
+ }
78916
+ function getPlannerSoloOperatingModel(nativeIntegration) {
78917
+ const continueStep = nativeIntegration ? "Hand off when complete" : "Run `get-next-task` to continue the session (Level A continues after Level B completes)";
78918
+ const intakeSteps = nativeIntegration ? `1. Receive user message
78919
+ 2. Plan and implement` : `1. Receive chatroom task from get-next-task
78920
+ 2. Plan and implement`;
78921
+ if (nativeIntegration) {
78922
+ return `**Operating model: Planner Solo**
78923
+
78924
+ ${intakeSteps}
78925
+ 3. Deliver to **user**
78926
+ 4. ${continueStep}`;
78927
+ }
78928
+ return `**Operating model: Planner Solo**
78929
+
78930
+ ${intakeSteps}
78931
+ 3. Review your own work for quality
78932
+ 4. Deliver to **user**
78933
+ 5. ${continueStep}`;
78934
+ }
77839
78935
  var init_operating_model = () => {};
77840
78936
 
77841
78937
  // ../../services/backend/prompts/cli/sections/index.ts
@@ -77845,17 +78941,126 @@ var init_sections = __esm(() => {
77845
78941
  });
77846
78942
 
77847
78943
  // ../../services/backend/prompts/cli/roles/planner.ts
78944
+ function getPlannerGuidance(params) {
78945
+ const { convexUrl, teamRoles, chatroomId, role, nativeIntegration } = params;
78946
+ const cliEnvPrefix = getCliEnvPrefix(convexUrl);
78947
+ const members = teamRoles;
78948
+ const hasBuilder = members.some((r) => r.toLowerCase() === "builder");
78949
+ const teamConfig = { hasBuilder };
78950
+ return `## Planner Operating Model
78951
+
78952
+ ${getSessionContinuityLine(nativeIntegration)}
78953
+
78954
+ You are the team coordinator and the **single point of contact** for the user.
78955
+
78956
+ ${getTeamCompositionSection(members)}
78957
+
78958
+ ${getOperatingModelSection(teamConfig, nativeIntegration)}
78959
+
78960
+ ${getCoreResponsibilitiesSection(teamConfig)}
78961
+
78962
+ ${getDelegationAndDecompositionSection(teamConfig)}
78963
+
78964
+ ${getDelegationGuidelinesSection(teamConfig, { cliEnvPrefix, chatroomId, role })}
78965
+
78966
+ ${getHandoffRulesSection(teamConfig, nativeIntegration)}
78967
+
78968
+ ${getWhenWorkComesBackSection(teamConfig)}`;
78969
+ }
77848
78970
  var init_planner = __esm(() => {
77849
78971
  init_env();
77850
78972
  init_sections();
77851
78973
  });
77852
78974
 
77853
78975
  // ../../services/backend/prompts/teams/solo/prompts/solo.ts
78976
+ function getSoloGuidance(ctx) {
78977
+ const { teamRoles, nativeIntegration } = ctx;
78978
+ return `## Solo Operating Model
78979
+
78980
+ ${getSessionContinuityLine(nativeIntegration)}
78981
+
78982
+ You are an autonomous agent responsible for BOTH planning and implementing chatroom tasks independently.
78983
+
78984
+ **Solo Team Context:**
78985
+ - You are the ONLY team member — you plan, implement, and deliver
78986
+ - You communicate directly with the user (single point of contact)
78987
+ - There is no separate builder or planner — you fill all roles
78988
+ - You hand off directly to the user when work is complete
78989
+
78990
+ ${getTeamCompositionSection(teamRoles)}
78991
+
78992
+ ${getPlannerSoloOperatingModel(nativeIntegration)}
78993
+
78994
+ ${getCoreResponsibilitiesSection(SOLO_TEAM_CONFIG)}
78995
+
78996
+ **Implementation Guidelines:**
78997
+ - Write clean, maintainable, well-documented code
78998
+ - Follow established patterns and best practices from the codebase
78999
+ - Handle edge cases and error scenarios
79000
+ - Commit work with descriptive, atomic commit messages
79001
+
79002
+ ${getHandoffRulesSection(SOLO_TEAM_CONFIG, nativeIntegration)}
79003
+
79004
+ ${getWhenWorkComesBackSection(SOLO_TEAM_CONFIG)}`;
79005
+ }
79006
+ var SOLO_TEAM_CONFIG;
77854
79007
  var init_solo = __esm(() => {
77855
79008
  init_sections();
79009
+ SOLO_TEAM_CONFIG = { hasBuilder: false };
77856
79010
  });
77857
79011
 
77858
79012
  // ../../services/backend/prompts/cli/roles/fromContext.ts
79013
+ function toBuilderParams(ctx) {
79014
+ return {
79015
+ role: ctx.role,
79016
+ teamRoles: ctx.teamRoles,
79017
+ isEntryPoint: ctx.isEntryPoint,
79018
+ convexUrl: ctx.convexUrl,
79019
+ nativeIntegration: ctx.nativeIntegration
79020
+ };
79021
+ }
79022
+ function toPlannerParams(ctx) {
79023
+ return {
79024
+ role: ctx.role,
79025
+ teamRoles: ctx.teamRoles,
79026
+ isEntryPoint: ctx.isEntryPoint,
79027
+ convexUrl: ctx.convexUrl,
79028
+ chatroomId: ctx.chatroomId,
79029
+ nativeIntegration: ctx.nativeIntegration
79030
+ };
79031
+ }
79032
+ function getBaseBuilderGuidanceFromContext(ctx) {
79033
+ return getBuilderGuidance(toBuilderParams(ctx));
79034
+ }
79035
+ function toSoloParams(ctx) {
79036
+ return {
79037
+ role: ctx.role,
79038
+ teamRoles: ctx.teamRoles,
79039
+ isEntryPoint: ctx.isEntryPoint,
79040
+ convexUrl: ctx.convexUrl,
79041
+ chatroomId: ctx.chatroomId,
79042
+ nativeIntegration: ctx.nativeIntegration
79043
+ };
79044
+ }
79045
+ function getSoloGuidanceFromContext(ctx) {
79046
+ return getSoloGuidance(toSoloParams(ctx));
79047
+ }
79048
+ function getBasePlannerGuidanceFromContext(ctx) {
79049
+ return getPlannerGuidance(toPlannerParams(ctx));
79050
+ }
79051
+ function getBaseRoleGuidanceFromContext(ctx) {
79052
+ const normalizedRole = ctx.role.toLowerCase();
79053
+ if (normalizedRole === "planner") {
79054
+ return getBasePlannerGuidanceFromContext(ctx);
79055
+ }
79056
+ if (normalizedRole === "builder") {
79057
+ return getBaseBuilderGuidanceFromContext(ctx);
79058
+ }
79059
+ if (normalizedRole === "solo") {
79060
+ return getSoloGuidanceFromContext(ctx);
79061
+ }
79062
+ return "";
79063
+ }
77859
79064
  var init_fromContext = __esm(() => {
77860
79065
  init_builder();
77861
79066
  init_planner();
@@ -77863,32 +79068,229 @@ var init_fromContext = __esm(() => {
77863
79068
  });
77864
79069
 
77865
79070
  // ../../services/backend/prompts/teams/duo/prompts/builder.ts
79071
+ function getBuilderGuidance2(ctx) {
79072
+ return `
79073
+ **Duo Team Context:**
79074
+ - You work with a planner who coordinates work and communicates with the user
79075
+ - You do NOT communicate directly with the user — hand off to the planner instead
79076
+ - Focus on implementation; the planner handles user communication and delivery
79077
+ - After completing work, hand off back to planner
79078
+ - **NEVER hand off directly to \`user\`** — always go through the planner
79079
+
79080
+ ${getBuilderGuidance({ ...ctx, questionTarget: "planner", codeChangesTarget: "planner" })}
79081
+ `;
79082
+ }
77866
79083
  var init_builder2 = __esm(() => {
77867
79084
  init_builder();
77868
79085
  });
77869
79086
 
77870
79087
  // ../../services/backend/prompts/cli/roles/planner-guidance-context.ts
79088
+ function getPlannerGuidanceContext(ctx) {
79089
+ const { convexUrl, teamRoles, chatroomId, role } = ctx;
79090
+ const cliEnvPrefix = getCliEnvPrefix(convexUrl);
79091
+ const members = teamRoles;
79092
+ return {
79093
+ ...ctx,
79094
+ cliEnvPrefix,
79095
+ members,
79096
+ chatroomId,
79097
+ role
79098
+ };
79099
+ }
77871
79100
  var init_planner_guidance_context = __esm(() => {
77872
79101
  init_env();
77873
79102
  });
77874
79103
 
77875
79104
  // ../../services/backend/prompts/teams/duo/prompts/planner.ts
79105
+ function getPlannerGuidance2(ctx) {
79106
+ const { nativeIntegration, members, cliEnvPrefix, chatroomId, role } = getPlannerGuidanceContext(ctx);
79107
+ const operatingModelGuidance = getPlannerPlusBuilderOperatingModel(nativeIntegration);
79108
+ return `## Planner Operating Model
79109
+
79110
+ ${getSessionContinuityLine(nativeIntegration)}
79111
+
79112
+ You are the team coordinator and the **single point of contact** for the user.
79113
+
79114
+ **Duo Team Context:**
79115
+ - You are the entry point — you communicate directly with the user
79116
+ - You coordinate with the builder for implementation tasks
79117
+ - You are ultimately accountable for all work quality
79118
+ - After reviewing builder output, deliver results to the user
79119
+ - **Only you can hand off to \`user\`**
79120
+
79121
+ ${getTeamCompositionSection(members)}
79122
+
79123
+ ${operatingModelGuidance}
79124
+
79125
+ ${getCoreResponsibilitiesSection(DUO_TEAM_CONFIG)}
79126
+
79127
+ ${getDelegationAndDecompositionSection(DUO_TEAM_CONFIG)}
79128
+
79129
+ ${getDelegationGuidelinesSection(DUO_TEAM_CONFIG, {
79130
+ cliEnvPrefix,
79131
+ chatroomId,
79132
+ role
79133
+ })}
79134
+
79135
+ ${getHandoffRulesSection(DUO_TEAM_CONFIG, nativeIntegration)}
79136
+
79137
+ ${getWhenWorkComesBackSection(DUO_TEAM_CONFIG)}`;
79138
+ }
79139
+ var DUO_TEAM_CONFIG;
77876
79140
  var init_planner2 = __esm(() => {
77877
79141
  init_planner_guidance_context();
77878
79142
  init_sections();
79143
+ DUO_TEAM_CONFIG = { hasBuilder: true };
77879
79144
  });
77880
79145
 
77881
79146
  // ../../services/backend/prompts/teams/duo/prompts/fromContext.ts
79147
+ function toDuoBuilderParams(ctx) {
79148
+ return {
79149
+ role: ctx.role,
79150
+ teamRoles: ctx.teamRoles,
79151
+ isEntryPoint: ctx.isEntryPoint,
79152
+ convexUrl: ctx.convexUrl,
79153
+ nativeIntegration: ctx.nativeIntegration
79154
+ };
79155
+ }
79156
+ function toDuoPlannerParams(ctx) {
79157
+ return {
79158
+ role: ctx.role,
79159
+ teamRoles: ctx.teamRoles,
79160
+ isEntryPoint: ctx.isEntryPoint,
79161
+ convexUrl: ctx.convexUrl,
79162
+ chatroomId: ctx.chatroomId,
79163
+ nativeIntegration: ctx.nativeIntegration
79164
+ };
79165
+ }
79166
+ function getDuoBuilderGuidanceFromContext(ctx) {
79167
+ return getBuilderGuidance2(toDuoBuilderParams(ctx));
79168
+ }
79169
+ function getDuoPlannerGuidanceFromContext(ctx) {
79170
+ return getPlannerGuidance2(toDuoPlannerParams(ctx));
79171
+ }
79172
+ function getDuoRoleGuidanceFromContext(ctx) {
79173
+ const normalizedRole = ctx.role.toLowerCase();
79174
+ if (normalizedRole === "planner") {
79175
+ return getDuoPlannerGuidanceFromContext(ctx);
79176
+ }
79177
+ if (normalizedRole === "builder") {
79178
+ return getDuoBuilderGuidanceFromContext(ctx);
79179
+ }
79180
+ return null;
79181
+ }
77882
79182
  var init_fromContext2 = __esm(() => {
77883
79183
  init_builder2();
77884
79184
  init_planner2();
77885
79185
  });
77886
79186
 
77887
79187
  // ../../services/backend/prompts/teams/solo/prompts/fromContext.ts
79188
+ function toSoloParams2(ctx) {
79189
+ return {
79190
+ role: ctx.role,
79191
+ teamRoles: ctx.teamRoles,
79192
+ isEntryPoint: ctx.isEntryPoint,
79193
+ convexUrl: ctx.convexUrl,
79194
+ chatroomId: ctx.chatroomId,
79195
+ nativeIntegration: ctx.nativeIntegration
79196
+ };
79197
+ }
79198
+ function getSoloGuidanceFromContext2(ctx) {
79199
+ return getSoloGuidance(toSoloParams2(ctx));
79200
+ }
79201
+ function getSoloRoleGuidanceFromContext(ctx) {
79202
+ const normalizedRole = ctx.role.toLowerCase();
79203
+ if (normalizedRole === "solo") {
79204
+ return getSoloGuidanceFromContext2(ctx);
79205
+ }
79206
+ return null;
79207
+ }
77888
79208
  var init_fromContext3 = __esm(() => {
77889
79209
  init_solo();
77890
79210
  });
79211
+
79212
+ // ../../services/backend/src/domain/entities/team.ts
79213
+ function toTeam(chatroom) {
79214
+ if (!chatroom.teamId || !chatroom.teamRoles || chatroom.teamRoles.length === 0) {
79215
+ return null;
79216
+ }
79217
+ const entryPoint = chatroom.teamEntryPoint ?? chatroom.teamRoles[0];
79218
+ if (!entryPoint)
79219
+ return null;
79220
+ return {
79221
+ id: chatroom.teamId,
79222
+ name: chatroom.teamName ?? chatroom.teamId,
79223
+ roles: chatroom.teamRoles,
79224
+ entryPoint
79225
+ };
79226
+ }
79227
+ function getTeamEntryPoint(team) {
79228
+ return team.teamEntryPoint ?? team.teamRoles?.[0] ?? null;
79229
+ }
79230
+
77891
79231
  // ../../services/backend/prompts/selector-context.ts
79232
+ function detectTeamTypeByName(teamName) {
79233
+ const normalizedName = (teamName || "").toLowerCase();
79234
+ if (normalizedName.includes("solo"))
79235
+ return "solo";
79236
+ if (normalizedName.includes("duo"))
79237
+ return "duo";
79238
+ return null;
79239
+ }
79240
+ function isSoloTeamByRoles(teamRoles) {
79241
+ return teamRoles.some((r) => r.toLowerCase() === "solo") && teamRoles.length === 1;
79242
+ }
79243
+ function isDuoTeamByRoles(teamRoles) {
79244
+ const hasPlanner = teamRoles.some((r) => r.toLowerCase() === "planner");
79245
+ const hasBuilder = teamRoles.some((r) => r.toLowerCase() === "builder");
79246
+ return hasPlanner && hasBuilder && teamRoles.length === 2;
79247
+ }
79248
+ function detectTeamType(teamRoles, teamName) {
79249
+ const byName = detectTeamTypeByName(teamName);
79250
+ if (byName)
79251
+ return byName;
79252
+ if (isSoloTeamByRoles(teamRoles))
79253
+ return "solo";
79254
+ if (isDuoTeamByRoles(teamRoles))
79255
+ return "duo";
79256
+ return "unknown";
79257
+ }
79258
+ function buildSelectorContext(params) {
79259
+ const entryPoint = getTeamEntryPoint({ teamEntryPoint: params.teamEntryPoint, teamRoles: params.teamRoles }) ?? "builder";
79260
+ const teamConfig = toTeam({
79261
+ teamId: params.teamId,
79262
+ teamName: params.teamName,
79263
+ teamRoles: params.teamRoles,
79264
+ teamEntryPoint: params.teamEntryPoint
79265
+ }) ?? undefined;
79266
+ return {
79267
+ role: params.role,
79268
+ team: detectTeamType(params.teamRoles, params.teamName),
79269
+ teamConfig,
79270
+ workflow: params.workflow,
79271
+ teamRoles: params.teamRoles,
79272
+ isEntryPoint: params.role.toLowerCase() === entryPoint.toLowerCase(),
79273
+ convexUrl: params.convexUrl,
79274
+ chatroomId: params.chatroomId,
79275
+ agentType: params.agentType ?? "unset",
79276
+ nativeIntegration: params.nativeIntegration
79277
+ };
79278
+ }
79279
+ function getRoleGuidanceFromContext(ctx) {
79280
+ try {
79281
+ if (ctx.team === "solo") {
79282
+ const result = getSoloRoleGuidanceFromContext(ctx);
79283
+ if (result !== null)
79284
+ return result;
79285
+ }
79286
+ if (ctx.team === "duo") {
79287
+ const result = getDuoRoleGuidanceFromContext(ctx);
79288
+ if (result !== null)
79289
+ return result;
79290
+ }
79291
+ } catch {}
79292
+ return getBaseRoleGuidanceFromContext(ctx);
79293
+ }
77892
79294
  var init_selector_context = __esm(() => {
77893
79295
  init_fromContext();
77894
79296
  init_fromContext2();
@@ -77896,19 +79298,151 @@ var init_selector_context = __esm(() => {
77896
79298
  });
77897
79299
 
77898
79300
  // ../../services/backend/prompts/sections/role-guidance.ts
79301
+ function getRoleGuidanceSection(ctx) {
79302
+ const content = getRoleGuidanceFromContext(ctx);
79303
+ return createSection("role-guidance", "knowledge", content);
79304
+ }
77899
79305
  var init_role_guidance = __esm(() => {
77900
79306
  init_selector_context();
77901
79307
  });
77902
79308
 
77903
79309
  // ../../services/backend/prompts/templates.ts
77904
- var init_templates = () => {};
79310
+ function getRoleTemplate(role) {
79311
+ const normalizedRole = role.toLowerCase();
79312
+ const template = ROLE_TEMPLATES[normalizedRole];
79313
+ if (template) {
79314
+ return template;
79315
+ }
79316
+ return {
79317
+ role,
79318
+ title: role.charAt(0).toUpperCase() + role.slice(1),
79319
+ description: `You are participating as the ${role} in this collaborative workflow.`,
79320
+ responsibilities: [
79321
+ "Complete tasks assigned to your role",
79322
+ "Communicate clearly with other participants",
79323
+ "Hand off to the next appropriate role when done"
79324
+ ],
79325
+ defaultHandoffTarget: "user"
79326
+ };
79327
+ }
79328
+ var ROLE_TEMPLATES;
79329
+ var init_templates = __esm(() => {
79330
+ ROLE_TEMPLATES = {
79331
+ builder: {
79332
+ role: "builder",
79333
+ title: "Builder",
79334
+ description: "You are the implementer responsible for writing code and building solutions.",
79335
+ responsibilities: [
79336
+ "Implement solutions based on requirements",
79337
+ "Write clean, maintainable, well-documented code",
79338
+ "Follow established patterns and best practices",
79339
+ "Handle edge cases and error scenarios",
79340
+ "Provide clear summaries of what was built"
79341
+ ],
79342
+ defaultHandoffTarget: "planner"
79343
+ },
79344
+ planner: {
79345
+ role: "planner",
79346
+ title: "Planner",
79347
+ description: "You are the team coordinator responsible for user communication, task decomposition, and team management.",
79348
+ responsibilities: [
79349
+ "Communicate with the user as the single point of contact",
79350
+ "Decompose complex tasks into actionable work items",
79351
+ "Delegate work to available team members",
79352
+ "Review completed work against user requirements",
79353
+ "Manage the backlog and prioritize tasks",
79354
+ "Hand back work for rework if requirements are not met"
79355
+ ],
79356
+ defaultHandoffTarget: "builder"
79357
+ },
79358
+ architect: {
79359
+ role: "architect",
79360
+ title: "Architect",
79361
+ description: "You are the system designer responsible for planning and high-level architecture.",
79362
+ responsibilities: [
79363
+ "Analyze requirements and break down complex tasks",
79364
+ "Design system architecture and component structure",
79365
+ "Make technology and pattern decisions",
79366
+ "Create clear specifications for the builder",
79367
+ "Consider scalability, maintainability, and best practices"
79368
+ ],
79369
+ defaultHandoffTarget: "builder"
79370
+ },
79371
+ tester: {
79372
+ role: "tester",
79373
+ title: "Tester",
79374
+ description: "You are the QA specialist responsible for testing and validation.",
79375
+ responsibilities: [
79376
+ "Write and execute test cases",
79377
+ "Verify functionality works as expected",
79378
+ "Test edge cases and error handling",
79379
+ "Report bugs and issues clearly",
79380
+ "Confirm quality standards are met"
79381
+ ],
79382
+ defaultHandoffTarget: "user"
79383
+ },
79384
+ solo: {
79385
+ role: "solo",
79386
+ title: "Solo",
79387
+ description: "You are the autonomous agent responsible for both planning and executing tasks independently.",
79388
+ responsibilities: [
79389
+ "Communicate directly with the user as the single point of contact",
79390
+ "Decompose complex tasks into actionable work items",
79391
+ "Implement solutions: write clean, maintainable code",
79392
+ "Follow established patterns and best practices",
79393
+ "Handle edge cases and error scenarios",
79394
+ "Review and validate your own work for quality",
79395
+ "Deliver completed results to the user"
79396
+ ],
79397
+ defaultHandoffTarget: "user"
79398
+ }
79399
+ };
79400
+ });
77905
79401
 
77906
79402
  // ../../services/backend/prompts/sections/role-identity.ts
79403
+ function getTeamHeaderSection(teamName) {
79404
+ return createSection("team-header", "knowledge", `# ${teamName}`);
79405
+ }
79406
+ function getRoleTitleSection(ctx) {
79407
+ const template = getRoleTemplate(ctx.role);
79408
+ return createSection("role-title", "knowledge", `## Your Role: ${template.title.toUpperCase()}`);
79409
+ }
79410
+ function getRoleDescriptionSection(ctx) {
79411
+ const template = getRoleTemplate(ctx.role);
79412
+ return createSection("role-description", "knowledge", template.description);
79413
+ }
77907
79414
  var init_role_identity = __esm(() => {
77908
79415
  init_templates();
77909
79416
  });
77910
79417
 
77911
79418
  // ../../services/backend/prompts/native/system-prompt.ts
79419
+ function composeNativeSystemPrompt(input) {
79420
+ const { chatroomId, role, teamId, teamName, teamRoles, teamEntryPoint, convexUrl } = input;
79421
+ const selectorCtx = buildSelectorContext({
79422
+ role,
79423
+ teamRoles,
79424
+ teamId,
79425
+ teamName,
79426
+ teamEntryPoint,
79427
+ convexUrl,
79428
+ chatroomId,
79429
+ agentType: input.agentType,
79430
+ nativeIntegration: true
79431
+ });
79432
+ const sections = [
79433
+ getRoleTitleSection(selectorCtx),
79434
+ getGlossarySection({
79435
+ convexUrl,
79436
+ chatroomId,
79437
+ role,
79438
+ nativeIntegration: true,
79439
+ compactSkills: true
79440
+ }),
79441
+ getRoleGuidanceSection(selectorCtx),
79442
+ getNativeCommandsReferenceSection({ chatroomId, role, convexUrl })
79443
+ ];
79444
+ return composeSections(sections);
79445
+ }
77912
79446
  var init_system_prompt = __esm(() => {
77913
79447
  init_commands_reference();
77914
79448
  init_glossary();
@@ -77918,11 +79452,46 @@ var init_system_prompt = __esm(() => {
77918
79452
  });
77919
79453
 
77920
79454
  // ../../services/backend/prompts/native/task-started-content.ts
79455
+ function getNativeTaskStartedPrompt(ctx) {
79456
+ const contextNewCmd = contextNewCommand({
79457
+ chatroomId: ctx.chatroomId,
79458
+ role: ctx.role,
79459
+ cliEnvPrefix: ctx.cliEnvPrefix,
79460
+ triggerMessageId: ctx.triggerMessageId
79461
+ });
79462
+ return `### Start working
79463
+
79464
+ Entry-point roles receive user messages directly. ${getNativeTokenActivityInProgressNote()}
79465
+
79466
+ ${getContextRuleBlock(contextNewCmd, contextNewHint({ cliEnvPrefix: ctx.cliEnvPrefix }))}`;
79467
+ }
79468
+ function getNativeTaskStartedPromptForHandoffRecipient() {
79469
+ return `### Start Working
79470
+
79471
+ The task body contains your work description. Begin immediately.`;
79472
+ }
77921
79473
  var init_task_started_content = __esm(() => {
77922
79474
  init_new();
77923
79475
  });
77924
79476
 
77925
79477
  // ../../services/backend/prompts/sections/classification-guide.ts
79478
+ function getTaskIntakeContent(ctx) {
79479
+ const cliEnvPrefix = getCliEnvPrefix(ctx.convexUrl);
79480
+ const chatroomId = ctx.chatroomId ?? "";
79481
+ if (ctx.isEntryPoint) {
79482
+ return ctx.nativeIntegration ? getNativeTaskStartedPrompt({ chatroomId, role: ctx.role, cliEnvPrefix }) : getTaskStartedPrompt2({ chatroomId, role: ctx.role, cliEnvPrefix });
79483
+ }
79484
+ return ctx.nativeIntegration ? getNativeTaskStartedPromptForHandoffRecipient() : getTaskStartedPromptForHandoffRecipient2({
79485
+ chatroomId,
79486
+ role: ctx.role,
79487
+ cliEnvPrefix
79488
+ });
79489
+ }
79490
+ function getClassificationGuideSection(ctx) {
79491
+ const content = getTaskIntakeContent(ctx);
79492
+ const sectionId = ctx.isEntryPoint ? "task-intake-guide" : "handoff-recipient-guide";
79493
+ return createSection(sectionId, "knowledge", content);
79494
+ }
77926
79495
  var init_classification_guide = __esm(() => {
77927
79496
  init_cli();
77928
79497
  init_task_started_content();
@@ -77930,23 +79499,118 @@ var init_classification_guide = __esm(() => {
77930
79499
  });
77931
79500
 
77932
79501
  // ../../services/backend/prompts/sections/current-classification.ts
79502
+ function getCurrentClassificationSection(classification) {
79503
+ const info = {
79504
+ question: {
79505
+ label: "QUESTION",
79506
+ description: "User is asking a question. Can respond directly after answering."
79507
+ },
79508
+ new_feature: {
79509
+ label: "NEW FEATURE",
79510
+ description: "New functionality request."
79511
+ },
79512
+ follow_up: {
79513
+ label: "FOLLOW-UP",
79514
+ description: "Follow-up to previous task. Same rules as the original apply."
79515
+ }
79516
+ };
79517
+ const { label, description } = info[classification];
79518
+ const content = `### Current Task: ${label}
79519
+ ${description}`;
79520
+ return createSection("current-classification", "guidance", content);
79521
+ }
77933
79522
  var init_current_classification = () => {};
77934
79523
 
77935
79524
  // ../../services/backend/prompts/sections/getting-started.ts
79525
+ function getGettingStartedSection(ctx) {
79526
+ const content = getContextGainingGuidance({
79527
+ chatroomId: ctx.chatroomId ?? "",
79528
+ role: ctx.role,
79529
+ convexUrl: ctx.convexUrl,
79530
+ agentType: ctx.agentType
79531
+ });
79532
+ return createSection("getting-started", "knowledge", content);
79533
+ }
77936
79534
  var init_getting_started = __esm(() => {
77937
79535
  init_getting_started_content();
77938
79536
  });
77939
79537
 
77940
79538
  // ../../services/backend/prompts/sections/handoff-options.ts
79539
+ function getHandoffOptionsSection(params) {
79540
+ const roles = params.availableHandoffRoles.join(", ");
79541
+ const content = `### Handoff Options
79542
+ Available targets: ${roles}`;
79543
+ return createSection("handoff-options", "guidance", content);
79544
+ }
77941
79545
  var init_handoff_options = () => {};
77942
79546
 
77943
79547
  // ../../services/backend/prompts/sections/next-step.ts
79548
+ function getNextStepSection(params) {
79549
+ const cliEnvPrefix = getCliEnvPrefix(params.convexUrl);
79550
+ const waitCmd = getNextTaskCommand({
79551
+ chatroomId: params.chatroomId,
79552
+ role: params.role,
79553
+ cliEnvPrefix
79554
+ });
79555
+ const content = `### Next
79556
+
79557
+ Run:
79558
+
79559
+ \`\`\`bash
79560
+ ${waitCmd}
79561
+ \`\`\``;
79562
+ return createSection("next-step", "guidance", content);
79563
+ }
77944
79564
  var init_next_step = __esm(() => {
77945
79565
  init_command();
77946
79566
  init_utils3();
77947
79567
  });
77948
79568
 
77949
79569
  // ../../services/backend/prompts/sections/session-vs-chatroom-task.ts
79570
+ function getTwoLevelsTableSection() {
79571
+ return `## Two-Level Model: Session vs Chatroom Task
79572
+
79573
+ | Level | Name | Scope | Ends when |
79574
+ |-------|------|-------|-----------|
79575
+ | **A** | **Session** (harness turn) | The entire agent invocation — from startup to shutdown | You deliberately shut down or the harness exits |
79576
+ | **B** | **Chatroom task** | One discrete unit of work delivered by \`get-next-task\` | You run \`handoff\` to pass work to the next role |
79577
+
79578
+ **Completing Level B does NOT end Level A.**
79579
+ After every \`handoff\`, you must run \`get-next-task\` again to stay in the session and receive the next chatroom task.`;
79580
+ }
79581
+ function getSessionLifecycleSection() {
79582
+ return `### Session Lifecycle
79583
+
79584
+ A session starts when your harness launches you and ends only when the harness shuts down (or you explicitly stop).
79585
+ Within a session, you process many chatroom tasks sequentially:
79586
+
79587
+ \`get-next-task\` → do work → \`handoff\` → \`get-next-task\` → do work → \`handoff\` → …
79588
+
79589
+ Never exit or stop after a handoff — that closes the session (Level A) before the user is done with you.`;
79590
+ }
79591
+ function getSessionAntiPatternsSection() {
79592
+ return `### Common Mistakes
79593
+
79594
+ ❌ **Wrong:** Run \`handoff\`, then stop or wait for the user to re-invoke you.
79595
+ ✅ **Right:** Run \`handoff\`, then immediately run \`get-next-task\` in the foreground.
79596
+
79597
+ ❌ **Wrong:** Think "I finished the task, I'm done."
79598
+ ✅ **Right:** Think "I finished this chatroom task (Level B). The session (Level A) continues — run \`get-next-task\`."
79599
+
79600
+ ❌ **Wrong:** Run \`get-next-task\` in the background or skip it.
79601
+ ✅ **Right:** \`get-next-task\` must run in the **foreground** so the harness can deliver the next chatroom task.`;
79602
+ }
79603
+ function getSessionVsChatroomTaskSection() {
79604
+ const content = [
79605
+ getTwoLevelsTableSection(),
79606
+ "",
79607
+ getSessionLifecycleSection(),
79608
+ "",
79609
+ getSessionAntiPatternsSection()
79610
+ ].join(`
79611
+ `);
79612
+ return createSection("session-vs-chatroom-task", "guidance", content);
79613
+ }
77950
79614
  var init_session_vs_chatroom_task = () => {};
77951
79615
 
77952
79616
  // ../../services/backend/src/domain/entities/harness/claude-sdk.config.ts
@@ -78151,9 +79815,571 @@ var init_types = __esm(() => {
78151
79815
  "pi-sdk": piSdkCapabilities
78152
79816
  };
78153
79817
  });
79818
+
79819
+ // ../../services/backend/prompts/review-guidelines/review.ts
79820
+ function getReviewGuidelines() {
79821
+ return [REVIEW_PRINCIPLES, REVIEW_PROCESS, GUIDELINE_FILE_LOCATIONS, REJECTION_GUIDANCE].join(`
79822
+
79823
+ `);
79824
+ }
79825
+ var REVIEW_PRINCIPLES = `
79826
+ ## Review Principles
79827
+
79828
+ When reviewing completed work, you serve as the quality guardian between implementation and delivery.
79829
+
79830
+ ### Primary Goal: Maintainability & Extensibility
79831
+
79832
+ **The ultimate purpose of code review is to ensure the changes make it possible to continue building on the application.**
79833
+
79834
+ Every piece of code must be:
79835
+ - Easy to understand and modify later
79836
+ - Following patterns that scale
79837
+ - Not creating technical debt that slows future development
79838
+
79839
+ If code is hard to extend, hard to understand, or creates mess - it should be rejected or refactored, regardless of whether it "works."
79840
+
79841
+ ### Core Values
79842
+
79843
+ 1. **User Goal Alignment**
79844
+ The implementation must accomplish what the user originally requested.
79845
+ Compare the work against the ORIGINAL user request, not just the handoff summary.
79846
+
79847
+ 2. **Code Quality Over Speed**
79848
+ Maintain code quality: Use \`handoff\` to reject messy code that creates technical debt and slows future development.
79849
+
79850
+ 3. **Codebase Consistency**
79851
+ New code should follow existing patterns and conventions.
79852
+ Check guideline files for project-specific rules.
79853
+ Inconsistent code creates confusion and bugs.
79854
+
79855
+ 4. **Verification Over Trust**
79856
+ Check the actual changes, not just the summary.
79857
+ If something seems off, investigate. Trust but verify.
79858
+
79859
+ 5. **Be Direct and Specific**
79860
+ Be specific and clear in your \`handoff\` message: Vague feedback leads to confusion and rework. If something is wrong, say exactly what and why.
79861
+ If a refactor is needed, propose the exact approach.
79862
+ `, REVIEW_PROCESS = `
79863
+ ## Review Process
79864
+
79865
+ ### Phase 1: Context Review
79866
+
79867
+ Before looking at code, understand what was requested:
79868
+
79869
+ 1. Read the **original user request** in the context window
79870
+ 2. Note all requirements, constraints, and acceptance criteria
79871
+ 3. If a feature has metadata (title, description, tech-specs), review each point
79872
+ 4. If there are attached tasks, read their content
79873
+
79874
+ ### Phase 2: Change Inspection
79875
+
79876
+ Run these commands to inspect the implementation:
79877
+
79878
+ \`\`\`bash
79879
+ # Check for linting issues
79880
+ pnpm lint:fix
79881
+
79882
+ # View uncommitted changes
79883
+ git status
79884
+ git diff
79885
+
79886
+ # View recent commits
79887
+ git log --oneline -5
79888
+ git show HEAD
79889
+ \`\`\`
79890
+
79891
+ ### Phase 3: Code Review Checklist
79892
+
79893
+ **Functional Requirements:**
79894
+ - [ ] All requirements from original request are addressed
79895
+ - [ ] Edge cases are handled
79896
+ - [ ] Error handling is appropriate
79897
+
79898
+ **Code Quality:**
79899
+ - [ ] No \`any\` types - proper TypeScript typing required
79900
+ - [ ] No type assertions (\`as\`) hiding real type issues
79901
+ - [ ] React hooks used correctly (deps arrays, memoization)
79902
+ - [ ] No inline workarounds or hacks
79903
+
79904
+ **Codebase Consistency:**
79905
+ - [ ] Follows existing patterns in the codebase
79906
+ - [ ] Uses existing components/utilities where applicable
79907
+ - [ ] Styling follows design system (semantic tokens, not hardcoded colors)
79908
+
79909
+ **Guidelines Compliance:**
79910
+ - [ ] Check relevant guideline files were followed (see list below)
79911
+
79912
+ ### Phase 4: Decision
79913
+
79914
+ **Your feedback must be SPECIFIC and ACTIONABLE. Include clear guidance in your \`handoff\` message to help the builder make the right changes.**
79915
+
79916
+ **If changes are needed:**
79917
+ - State EXACTLY what is wrong (file, line, code snippet)
79918
+ - Explain WHY it's a problem (not just that it's wrong)
79919
+ - Provide the EXACT fix or approach you want to see
79920
+ - If multiple issues, number them clearly
79921
+
79922
+ Example of BAD feedback:
79923
+ > "The code could be cleaner"
79924
+
79925
+ Example of GOOD feedback:
79926
+ > "In \`TaskQueue.tsx\` line 45, you're using \`any\` type for the task parameter.
79927
+ > This hides type errors. Change to: \`task: Task\` using the imported Task type."
79928
+
79929
+ **If the code is a mess - REJECT IT:**
79930
+ - Use \`handoff\` to reject messy code that "works"
79931
+ - Propose the refactor approach explicitly in your \`handoff\` message
79932
+ - Large refactors are acceptable if they improve maintainability
79933
+ - The goal is code that can be built upon, not just code that runs
79934
+
79935
+ **If approved:**
79936
+ - Confirm ALL requirements from original request are met
79937
+ - Briefly summarize what was verified
79938
+ - Hand off to user
79939
+ `, GUIDELINE_FILE_LOCATIONS = `
79940
+ ## Guideline Files to Check
79941
+
79942
+ Different AI tools use different guideline file locations. Check any that exist:
79943
+
79944
+ ### Cursor IDE
79945
+ - \`.cursor/rules/*.md\` - Cursor rules files
79946
+ - \`.cursorrules\` - Root cursor rules
79947
+
79948
+ ### GitHub Copilot
79949
+ - \`.github/copilot-instructions.md\` - Copilot instructions
79950
+ - \`.github/copilot/*.md\` - Additional Copilot files
79951
+
79952
+ ### Claude / Anthropic
79953
+ - \`CLAUDE.md\` - Claude-specific instructions
79954
+ - \`.claude/*.md\` - Claude rules directory
79955
+
79956
+ ### OpenAI / Codex
79957
+ - \`.openai/guidelines.md\` - OpenAI guidelines
79958
+ - \`CODEX.md\` - Codex instructions
79959
+
79960
+ ### Generic Agent Files
79961
+ - \`AGENTS.md\` - Generic agent guidelines
79962
+ - \`.ai/*.md\` - AI-related instructions
79963
+ - \`DEVELOPMENT.md\` - Development guidelines
79964
+ - \`CONTRIBUTING.md\` - Contribution guidelines
79965
+
79966
+ ### Project-Specific
79967
+ - \`docs/design/*.md\` - Design guidelines
79968
+ - \`docs/style-guide.md\` - Style guides
79969
+ - \`guides/*.md\` - Project guides
79970
+
79971
+ **Important:** Adapt to what exists in THIS codebase. Not all projects have all files.
79972
+ `, REJECTION_GUIDANCE = `
79973
+ ## When to Reject or Request Refactors
79974
+
79975
+ **Use \`handoff\` to maintain code quality:** The goal is a maintainable codebase.
79976
+
79977
+ ### Reject When:
79978
+
79979
+ 1. **Requirements Not Met**
79980
+ - The original user request is not fully addressed
79981
+ - Key features are missing or only partially implemented
79982
+
79983
+ 2. **Significant Technical Debt**
79984
+ - Hacks or workarounds that will cause problems later
79985
+ - Code that is hard to understand or modify
79986
+ - Patterns that don't scale or won't work with future features
79987
+
79988
+ 3. **Type Safety Violations**
79989
+ - Widespread use of \`any\` or type assertions
79990
+ - Missing proper error types or return types
79991
+ - Type errors being suppressed rather than fixed
79992
+
79993
+ 4. **Architectural Issues**
79994
+ - Code in wrong location (logic in UI, UI in logic)
79995
+ - Duplication of existing functionality
79996
+ - Tight coupling that prevents testing/reuse
79997
+
79998
+ ### Propose Refactors When:
79999
+
80000
+ 1. **The fix is bigger than the feature**
80001
+ If cleaning up the code would take more effort than the original change,
80002
+ but the mess will compound over time - propose the refactor.
80003
+
80004
+ 2. **Patterns are inconsistent**
80005
+ If new code follows different patterns than existing code,
80006
+ propose alignment to the established pattern.
80007
+
80008
+ 3. **Abstractions are wrong**
80009
+ If the code is solving the problem at the wrong level of abstraction,
80010
+ propose the right approach even if it means starting over.
80011
+
80012
+ ### How to Propose Refactors:
80013
+
80014
+ 1. Explain the problem clearly
80015
+ 2. Describe the desired end state
80016
+ 3. Suggest whether to:
80017
+ - Fix now before merging
80018
+ - Create a follow-up task for later
80019
+ - Block on the refactor
80020
+
80021
+ **Remember:** Approving bad code costs more than rejecting it.
80022
+ `;
80023
+
78154
80024
  // ../../services/backend/prompts/review-guidelines/index.ts
78155
80025
  var init_review_guidelines = () => {};
80026
+
80027
+ // ../../services/backend/prompts/policies/security.ts
80028
+ function getSecurityPolicy() {
80029
+ return SECURITY_POLICY;
80030
+ }
80031
+ var SECURITY_POLICY = `
80032
+ ## Security Review Policy
80033
+
80034
+ These are general security principles. Adapt to your codebase's specific security requirements.
80035
+
80036
+ ### Authentication & Authorization
80037
+
80038
+ - [ ] Authentication checks are in place where required
80039
+ - [ ] Authorization verifies user has permission for the action
80040
+ - [ ] Session handling follows established patterns
80041
+ - [ ] No hardcoded credentials or secrets
80042
+
80043
+ ### Input Validation
80044
+
80045
+ - [ ] User input is validated before use
80046
+ - [ ] Input sanitization for database queries (SQL injection prevention)
80047
+ - [ ] Path traversal protection for file operations
80048
+ - [ ] Proper escaping for output contexts (XSS prevention)
80049
+
80050
+ ### Data Handling
80051
+
80052
+ - [ ] Sensitive data is not logged
80053
+ - [ ] PII is handled according to privacy requirements
80054
+ - [ ] Secrets use environment variables, not hardcoded values
80055
+ - [ ] .env files are not committed
80056
+
80057
+ ### API Security
80058
+
80059
+ - [ ] Rate limiting considerations for public endpoints
80060
+ - [ ] CORS configuration is appropriate
80061
+ - [ ] API responses don't leak sensitive information
80062
+ - [ ] Error messages don't expose internal details
80063
+
80064
+ ### Common Vulnerabilities to Check
80065
+
80066
+ 1. **Injection Attacks**
80067
+ - SQL/NoSQL injection
80068
+ - Command injection
80069
+ - Template injection
80070
+
80071
+ 2. **Broken Access Control**
80072
+ - Missing authorization checks
80073
+ - IDOR (Insecure Direct Object Reference)
80074
+ - Privilege escalation
80075
+
80076
+ 3. **Security Misconfiguration**
80077
+ - Debug mode in production
80078
+ - Exposed admin interfaces
80079
+ - Default credentials
80080
+
80081
+ 4. **Cryptographic Issues**
80082
+ - Weak hashing algorithms
80083
+ - Insecure random number generation
80084
+ - Improper key management
80085
+
80086
+ ### Codebase-Specific Security
80087
+
80088
+ Check these locations for security-related guidelines:
80089
+ - Security documentation in \`docs/security*.md\`
80090
+ - Authentication patterns in existing auth code
80091
+ - Existing security middleware/helpers
80092
+ - Security comments in sensitive code areas
80093
+
80094
+ **Important:** These are general guidelines. Always verify against your project's specific security requirements and compliance needs.
80095
+ `;
80096
+
80097
+ // ../../services/backend/prompts/policies/design.ts
80098
+ function getDesignPolicy() {
80099
+ return DESIGN_POLICY;
80100
+ }
80101
+ var DESIGN_POLICY = `
80102
+ ## Design Review Policy
80103
+
80104
+ These are general design principles. Adapt to your codebase's specific design system.
80105
+
80106
+ ### Design System Compliance
80107
+
80108
+ - [ ] Uses existing design tokens (colors, spacing, typography)
80109
+ - [ ] Follows established component patterns
80110
+ - [ ] Reuses existing components instead of creating duplicates
80111
+ - [ ] Styling uses semantic values, not hardcoded ones
80112
+
80113
+ ### Color Usage
80114
+
80115
+ **Semantic colors should be preferred:**
80116
+ - Use \`text-foreground\` not \`text-black\`
80117
+ - Use \`bg-card\` not \`bg-white\`
80118
+ - Use \`border-border\` not \`border-gray-200\`
80119
+
80120
+ **Dark mode support:**
80121
+ - All UI should work in both light and dark mode
80122
+ - Brand/status colors need dark variants (e.g., \`bg-red-50 dark:bg-red-950/20\`)
80123
+
80124
+ ### Component Patterns
80125
+
80126
+ - [ ] Components follow existing file structure conventions
80127
+ - [ ] Props are typed properly
80128
+ - [ ] Components are accessible (keyboard navigation, ARIA)
80129
+ - [ ] Responsive design is considered
80130
+
80131
+ ### Typography
80132
+
80133
+ - [ ] Uses established font sizes from the design system
80134
+ - [ ] Heading hierarchy is semantic (h1, h2, etc.)
80135
+ - [ ] Text is readable at all sizes
80136
+ - [ ] Font weights follow conventions
80137
+
80138
+ ### Spacing & Layout
80139
+
80140
+ - [ ] Uses design system spacing tokens
80141
+ - [ ] Layout is responsive
80142
+ - [ ] Alignment is consistent
80143
+ - [ ] Proper use of flexbox/grid patterns
80144
+
80145
+ ### UX Considerations
80146
+
80147
+ - [ ] Loading states are handled
80148
+ - [ ] Error states have clear messaging
80149
+ - [ ] Empty states are designed
80150
+ - [ ] Interactive elements have hover/focus states
80151
+
80152
+ ### Common Design Issues to Catch
80153
+
80154
+ 1. **Inconsistent Styling**
80155
+ - Different button styles for similar actions
80156
+ - Inconsistent spacing between elements
80157
+ - Mixed font sizes within components
80158
+
80159
+ 2. **Accessibility Gaps**
80160
+ - Missing keyboard navigation
80161
+ - Low color contrast
80162
+ - Missing ARIA labels
80163
+ - Focus states not visible
80164
+
80165
+ 3. **Hardcoded Values**
80166
+ - Magic numbers for spacing (use tokens)
80167
+ - Hardcoded colors (use semantic colors)
80168
+ - Fixed widths that break responsive
80169
+
80170
+ 4. **Component Duplication**
80171
+ - Recreating existing components
80172
+ - Copy-paste instead of abstraction
80173
+ - Similar patterns implemented differently
80174
+
80175
+ ### Codebase-Specific Design
80176
+
80177
+ Check these locations for design guidelines:
80178
+ - \`docs/design/*.md\` - Design documentation
80179
+ - \`components/ui/\` - Existing UI component library
80180
+ - \`tailwind.config.*\` - Theme configuration
80181
+ - \`globals.css\` or theme files - CSS custom properties
80182
+ - \`AGENTS.md\` or \`CLAUDE.md\` - May contain UI guidelines
80183
+
80184
+ **Important:** These are general guidelines. Always verify against your project's specific design system.
80185
+ `;
80186
+
80187
+ // ../../services/backend/prompts/policies/performance.ts
80188
+ function getPerformancePolicy() {
80189
+ return PERFORMANCE_POLICY;
80190
+ }
80191
+ var PERFORMANCE_POLICY = `
80192
+ ## Performance Review Policy
80193
+
80194
+ These are general performance principles. Adapt to your codebase's specific requirements.
80195
+
80196
+ ### Frontend Performance
80197
+
80198
+ **React/Component Performance:**
80199
+ - [ ] \`useMemo\` used for expensive computations
80200
+ - [ ] \`useCallback\` used for callback props passed to child components
80201
+ - [ ] \`React.memo\` considered for components receiving stable props
80202
+ - [ ] No unnecessary re-renders (check dependency arrays)
80203
+ - [ ] Large lists use virtualization where appropriate
80204
+
80205
+ **Bundle Size:**
80206
+ - [ ] No large dependencies added for simple functionality
80207
+ - [ ] Dynamic imports (\`lazy\`) used for route-level code splitting
80208
+ - [ ] Tree-shaking friendly imports (avoid \`import * as\`)
80209
+ - [ ] Images/assets are appropriately sized and optimized
80210
+
80211
+ **Rendering:**
80212
+ - [ ] No layout thrashing (reading and writing DOM in loops)
80213
+ - [ ] CSS animations use \`transform\` and \`opacity\` where possible
80214
+ - [ ] Avoid inline styles that change frequently
80215
+ - [ ] Consider \`will-change\` for animated elements
80216
+
80217
+ ### Backend Performance
80218
+
80219
+ **Database Queries:**
80220
+ - [ ] Queries use appropriate indexes
80221
+ - [ ] N+1 query patterns are avoided or justified
80222
+ - [ ] Pagination used for large result sets
80223
+ - [ ] Expensive queries are cached where appropriate
80224
+
80225
+ **API Design:**
80226
+ - [ ] Responses don't include unnecessary data
80227
+ - [ ] Batch endpoints available for bulk operations
80228
+ - [ ] Expensive operations are async/background where possible
80229
+ - [ ] Rate limiting considered for resource-intensive endpoints
80230
+
80231
+ **Memory & Resources:**
80232
+ - [ ] No memory leaks (event listeners cleaned up, subscriptions closed)
80233
+ - [ ] Large data structures are streamed, not loaded entirely
80234
+ - [ ] Connection pooling used for database/external services
80235
+ - [ ] Temporary files/resources are cleaned up
80236
+
80237
+ ### Common Performance Issues to Catch
80238
+
80239
+ 1. **Unnecessary Computation**
80240
+ - Computing values on every render
80241
+ - Recalculating derived data without memoization
80242
+ - Expensive operations in hot paths
80243
+
80244
+ 2. **Over-fetching**
80245
+ - Requesting more data than needed
80246
+ - Missing pagination on large datasets
80247
+ - Not using projection/select for specific fields
80248
+
80249
+ 3. **Under-caching**
80250
+ - Repeated identical API calls
80251
+ - Not caching expensive computations
80252
+ - Missing server-side caching for static data
80253
+
80254
+ 4. **Blocking Operations**
80255
+ - Synchronous operations blocking the event loop
80256
+ - Not using async patterns for I/O
80257
+ - Long-running operations without progress feedback
80258
+
80259
+ 5. **React-Specific Issues**
80260
+ - Missing dependency arrays causing infinite loops
80261
+ - Creating new objects/functions in render
80262
+ - Not using \`key\` prop properly in lists
80263
+ - State updates in useEffect without proper deps
80264
+
80265
+ ### Platform-Specific Considerations
80266
+
80267
+ **Next.js:**
80268
+ - Server Components for static content
80269
+ - Client Components for interactive elements
80270
+ - Image optimization with next/image
80271
+ - Route segment config for caching
80272
+
80273
+ **Convex:**
80274
+ - Query indexing for filtered/sorted data
80275
+ - Pagination for large result sets
80276
+ - Optimistic updates for better UX
80277
+ - Reactive queries vs. one-time fetches
80278
+
80279
+ **General Web:**
80280
+ - Core Web Vitals (LCP, FID, CLS)
80281
+ - Time to Interactive (TTI)
80282
+ - First Contentful Paint (FCP)
80283
+
80284
+ ### Questions to Ask
80285
+
80286
+ 1. "Will this scale with 10x/100x more data?"
80287
+ 2. "What happens with slow network conditions?"
80288
+ 3. "Are there any O(n²) or worse algorithms?"
80289
+ 4. "Could this operation be batched or debounced?"
80290
+ 5. "Is this computation necessary on every render?"
80291
+
80292
+ **Important:** These are general guidelines. Performance requirements vary by application.
80293
+ Focus on user-facing performance impact rather than micro-optimizations.
80294
+ `;
80295
+
78156
80296
  // ../../services/backend/prompts/generator.ts
80297
+ var exports_generator = {};
80298
+ __export(exports_generator, {
80299
+ getSecurityPolicy: () => getSecurityPolicy,
80300
+ getReviewGuidelines: () => getReviewGuidelines,
80301
+ getPerformancePolicy: () => getPerformancePolicy,
80302
+ getDesignPolicy: () => getDesignPolicy,
80303
+ generateRolePrompt: () => generateRolePrompt,
80304
+ generateHandoffOutput: () => generateHandoffOutput,
80305
+ generateGeneralInstructions: () => generateGeneralInstructions,
80306
+ composeSystemPrompt: () => composeSystemPrompt2,
80307
+ composeInitPrompt: () => composeInitPrompt,
80308
+ composeInitMessage: () => composeInitMessage
80309
+ });
80310
+ function generateGeneralInstructions(_input) {
80311
+ const sections = [];
80312
+ sections.push(getNextTaskGuidance());
80313
+ return sections.join(`
80314
+
80315
+ `);
80316
+ }
80317
+ function generateRolePrompt(ctx) {
80318
+ const selectorCtx = buildSelectorContext({
80319
+ role: ctx.role,
80320
+ teamRoles: ctx.teamRoles,
80321
+ teamId: ctx.teamId,
80322
+ teamName: ctx.teamName,
80323
+ teamEntryPoint: ctx.teamEntryPoint,
80324
+ convexUrl: ctx.convexUrl,
80325
+ chatroomId: ctx.chatroomId,
80326
+ workflow: ctx.currentClassification
80327
+ });
80328
+ const sections = [];
80329
+ sections.push(getRoleTitleSection(selectorCtx));
80330
+ sections.push(getRoleDescriptionSection(selectorCtx));
80331
+ sections.push(getGlossarySection({ convexUrl: ctx.convexUrl ?? "", chatroomId: ctx.chatroomId }));
80332
+ sections.push(getRoleGuidanceSection(selectorCtx));
80333
+ if (ctx.currentClassification) {
80334
+ sections.push(getCurrentClassificationSection(ctx.currentClassification));
80335
+ }
80336
+ sections.push(getHandoffOptionsSection({
80337
+ availableHandoffRoles: ctx.availableHandoffRoles
80338
+ }));
80339
+ sections.push(getCommandsReferenceSection({
80340
+ chatroomId: ctx.chatroomId,
80341
+ role: ctx.role,
80342
+ convexUrl: ctx.convexUrl
80343
+ }));
80344
+ return composeSections(sections);
80345
+ }
80346
+ function buildInitPromptSections(input, selectorCtx) {
80347
+ const { chatroomId, role, teamRoles, convexUrl } = input;
80348
+ const otherRoles = teamRoles.filter((r) => r.toLowerCase() !== role.toLowerCase());
80349
+ const handoffTargets = [...new Set([...otherRoles, "user"])];
80350
+ const sections = [
80351
+ getTeamHeaderSection(input.teamName),
80352
+ getRoleTitleSection(selectorCtx),
80353
+ getRoleDescriptionSection(selectorCtx),
80354
+ getGlossarySection({ convexUrl: convexUrl ?? "", chatroomId }),
80355
+ getSessionVsChatroomTaskSection(),
80356
+ getGettingStartedSection(selectorCtx),
80357
+ getClassificationGuideSection(selectorCtx),
80358
+ getRoleGuidanceSection(selectorCtx),
80359
+ getHandoffOptionsSection({ availableHandoffRoles: handoffTargets }),
80360
+ getCommandsReferenceSection({ chatroomId, role, convexUrl }),
80361
+ getNextStepSection({ chatroomId, role, convexUrl })
80362
+ ];
80363
+ return sections;
80364
+ }
80365
+ function composeSystemPrompt2(input) {
80366
+ if (isNativeHarness(input.agentHarness)) {
80367
+ return composeNativeSystemPrompt(input);
80368
+ }
80369
+ const { chatroomId, role, teamId, teamName, teamRoles, teamEntryPoint, convexUrl } = input;
80370
+ const selectorCtx = buildSelectorContext({
80371
+ role,
80372
+ teamRoles,
80373
+ teamId,
80374
+ teamName,
80375
+ teamEntryPoint,
80376
+ convexUrl,
80377
+ chatroomId,
80378
+ agentType: input.agentType,
80379
+ nativeIntegration: false
80380
+ });
80381
+ return composeSections(buildInitPromptSections(input, selectorCtx));
80382
+ }
78157
80383
  function generateHandoffOutput(params) {
78158
80384
  const { role, nextRole, chatroomId, convexUrl, supportsNativeIntegration } = params;
78159
80385
  const cliEnvPrefix = getCliEnvPrefix(convexUrl);
@@ -78171,6 +80397,17 @@ function generateHandoffOutput(params) {
78171
80397
  return lines.join(`
78172
80398
  `);
78173
80399
  }
80400
+ function composeInitMessage(_input) {
80401
+ return "";
80402
+ }
80403
+ function composeInitPrompt(input) {
80404
+ const systemPrompt = composeSystemPrompt2(input);
80405
+ const initMessage = composeInitMessage(input);
80406
+ const initPrompt = initMessage ? `${systemPrompt}
80407
+
80408
+ ${initMessage}` : systemPrompt;
80409
+ return { systemPrompt, initMessage, initPrompt };
80410
+ }
78174
80411
  var init_generator = __esm(() => {
78175
80412
  init_command();
78176
80413
  init_reminder();
@@ -79085,6 +81322,83 @@ var init_complete = __esm(() => {
79085
81322
  init_error_formatting();
79086
81323
  });
79087
81324
 
81325
+ // src/commands/enhancer/complete.ts
81326
+ var exports_complete2 = {};
81327
+ __export(exports_complete2, {
81328
+ enhancerComplete: () => enhancerComplete
81329
+ });
81330
+ async function createDefaultDeps10() {
81331
+ const client4 = await getConvexClient();
81332
+ return {
81333
+ backend: {
81334
+ mutation: (endpoint, args2) => client4.mutation(endpoint, args2),
81335
+ query: (endpoint, args2) => client4.query(endpoint, args2)
81336
+ },
81337
+ session: {
81338
+ getSessionId,
81339
+ getConvexUrl,
81340
+ getOtherSessionUrls
81341
+ }
81342
+ };
81343
+ }
81344
+ function handleCompleteError2(err) {
81345
+ return exports_Effect.sync(() => {
81346
+ if (err._tag === "NotAuthenticated") {
81347
+ formatAuthError(err.convexUrl, err.otherUrls);
81348
+ process.exit(1);
81349
+ }
81350
+ if (err._tag === "InvalidChatroomId") {
81351
+ formatChatroomIdError(err.id);
81352
+ process.exit(1);
81353
+ }
81354
+ console.error(`
81355
+ ❌ ERROR: Enhancer complete failed`);
81356
+ console.error(`
81357
+ ${err.errorData?.message ?? err.cause.message}`);
81358
+ process.exit(1);
81359
+ });
81360
+ }
81361
+ async function enhancerComplete(chatroomId, options) {
81362
+ const deps = await createDefaultDeps10();
81363
+ await exports_Effect.runPromise(enhancerCompleteEffect(chatroomId, options).pipe(exports_Effect.provide(commandServicesLayerFromDeps(deps)), exports_Effect.catchAll(handleCompleteError2)));
81364
+ }
81365
+ var enhancerCompleteEffect = (chatroomId, options) => exports_Effect.gen(function* () {
81366
+ const backend2 = yield* BackendService;
81367
+ const sessionId = yield* requireSessionIdEffect((a) => ({
81368
+ _tag: "NotAuthenticated",
81369
+ convexUrl: a.convexUrl,
81370
+ otherUrls: a.otherUrls
81371
+ }));
81372
+ yield* validateChatroomIdEffect(chatroomId, (id3) => ({
81373
+ _tag: "InvalidChatroomId",
81374
+ id: id3
81375
+ }));
81376
+ yield* backend2.mutation(api.web.enhancer.index.complete, {
81377
+ sessionId,
81378
+ chatroomId,
81379
+ jobId: options.jobId,
81380
+ enhancedContent: options.enhancedContent
81381
+ }).pipe(exports_Effect.mapError((cause3) => {
81382
+ let errorData;
81383
+ if (cause3 instanceof ConvexError) {
81384
+ errorData = cause3.data;
81385
+ }
81386
+ return { _tag: "CompleteFailed", cause: cause3, errorData };
81387
+ }));
81388
+ yield* exports_Effect.sync(() => {
81389
+ console.log(`✅ Enhancer job ${options.jobId} completed`);
81390
+ });
81391
+ });
81392
+ var init_complete2 = __esm(() => {
81393
+ init_values();
81394
+ init_esm();
81395
+ init_api3();
81396
+ init_storage();
81397
+ init_client2();
81398
+ init_services();
81399
+ init_error_formatting();
81400
+ });
81401
+
79088
81402
  // src/commands/backlog/backlog-fs-service.ts
79089
81403
  import * as nodeFs from "node:fs/promises";
79090
81404
  var BacklogFsService, BacklogFsServiceLive, BacklogFsServiceFrom = (ops) => exports_Layer.succeed(BacklogFsService, {
@@ -79191,7 +81505,7 @@ function buildBaseLayer(d) {
79191
81505
  function buildFsLayer(fs11) {
79192
81506
  return fs11 ? BacklogFsServiceFrom(fs11) : BacklogFsServiceLive;
79193
81507
  }
79194
- async function createDefaultDeps10() {
81508
+ async function createDefaultDeps11() {
79195
81509
  const client4 = await getConvexClient();
79196
81510
  const fs11 = await import("node:fs/promises");
79197
81511
  return {
@@ -79247,47 +81561,47 @@ function computeContentHash(content) {
79247
81561
  return createHash("sha256").update(content).digest("hex");
79248
81562
  }
79249
81563
  async function listBacklog(chatroomId, options, deps) {
79250
- const d = deps ?? await createDefaultDeps10();
81564
+ const d = deps ?? await createDefaultDeps11();
79251
81565
  await exports_Effect.runPromise(listBacklogEffect(chatroomId, options).pipe(exports_Effect.catchAll(handleBacklogError), exports_Effect.provide(buildBaseLayer(d))));
79252
81566
  }
79253
81567
  async function addBacklog(chatroomId, options, deps) {
79254
- const d = deps ?? await createDefaultDeps10();
81568
+ const d = deps ?? await createDefaultDeps11();
79255
81569
  await exports_Effect.runPromise(addBacklogEffect(chatroomId, options).pipe(exports_Effect.catchAll(handleBacklogError), exports_Effect.provide(buildBaseLayer(d))));
79256
81570
  }
79257
81571
  async function completeBacklog(chatroomId, options, deps) {
79258
- const d = deps ?? await createDefaultDeps10();
81572
+ const d = deps ?? await createDefaultDeps11();
79259
81573
  await exports_Effect.runPromise(completeBacklogEffect(chatroomId, options).pipe(exports_Effect.catchAll(handleBacklogError), exports_Effect.provide(buildBaseLayer(d))));
79260
81574
  }
79261
81575
  async function reopenBacklog(chatroomId, options, deps) {
79262
- const d = deps ?? await createDefaultDeps10();
81576
+ const d = deps ?? await createDefaultDeps11();
79263
81577
  await exports_Effect.runPromise(reopenBacklogEffect(chatroomId, options).pipe(exports_Effect.catchAll(handleBacklogError), exports_Effect.provide(buildBaseLayer(d))));
79264
81578
  }
79265
81579
  async function patchBacklog(chatroomId, options, deps) {
79266
- const d = deps ?? await createDefaultDeps10();
81580
+ const d = deps ?? await createDefaultDeps11();
79267
81581
  await exports_Effect.runPromise(patchBacklogEffect(chatroomId, options).pipe(exports_Effect.catchAll(handleBacklogError), exports_Effect.provide(buildBaseLayer(d))));
79268
81582
  }
79269
81583
  async function scoreBacklog(chatroomId, options, deps) {
79270
- const d = deps ?? await createDefaultDeps10();
81584
+ const d = deps ?? await createDefaultDeps11();
79271
81585
  await exports_Effect.runPromise(scoreBacklogEffect(chatroomId, options).pipe(exports_Effect.catchAll(handleBacklogError), exports_Effect.provide(buildBaseLayer(d))));
79272
81586
  }
79273
81587
  async function markForReviewBacklog(chatroomId, options, deps) {
79274
- const d = deps ?? await createDefaultDeps10();
81588
+ const d = deps ?? await createDefaultDeps11();
79275
81589
  await exports_Effect.runPromise(markForReviewBacklogEffect(chatroomId, options).pipe(exports_Effect.catchAll(handleBacklogError), exports_Effect.provide(buildBaseLayer(d))));
79276
81590
  }
79277
81591
  async function historyBacklog(chatroomId, options, deps) {
79278
- const d = deps ?? await createDefaultDeps10();
81592
+ const d = deps ?? await createDefaultDeps11();
79279
81593
  await exports_Effect.runPromise(historyBacklogEffect(chatroomId, options).pipe(exports_Effect.catchAll(handleBacklogError), exports_Effect.provide(buildBaseLayer(d))));
79280
81594
  }
79281
81595
  async function updateBacklog(chatroomId, options, deps) {
79282
- const d = deps ?? await createDefaultDeps10();
81596
+ const d = deps ?? await createDefaultDeps11();
79283
81597
  await exports_Effect.runPromise(updateBacklogEffect(chatroomId, options).pipe(exports_Effect.catchAll(handleBacklogError), exports_Effect.provide(buildBaseLayer(d))));
79284
81598
  }
79285
81599
  async function closeBacklog(chatroomId, options, deps) {
79286
- const d = deps ?? await createDefaultDeps10();
81600
+ const d = deps ?? await createDefaultDeps11();
79287
81601
  await exports_Effect.runPromise(closeBacklogEffect(chatroomId, options).pipe(exports_Effect.catchAll(handleBacklogError), exports_Effect.provide(buildBaseLayer(d))));
79288
81602
  }
79289
81603
  async function exportBacklog(chatroomId, options, deps) {
79290
- const d = deps ?? await createDefaultDeps10();
81604
+ const d = deps ?? await createDefaultDeps11();
79291
81605
  if (!d.fs) {
79292
81606
  console.error("❌ File system operations not available");
79293
81607
  process.exit(1);
@@ -79296,7 +81610,7 @@ async function exportBacklog(chatroomId, options, deps) {
79296
81610
  await exports_Effect.runPromise(exportBacklogEffect(chatroomId, options).pipe(exports_Effect.catchAll(handleBacklogError), exports_Effect.provide(exports_Layer.merge(buildBaseLayer(d), buildFsLayer(d.fs)))));
79297
81611
  }
79298
81612
  async function importBacklog(chatroomId, options, deps) {
79299
- const d = deps ?? await createDefaultDeps10();
81613
+ const d = deps ?? await createDefaultDeps11();
79300
81614
  if (!d.fs) {
79301
81615
  console.error("❌ File system operations not available");
79302
81616
  process.exit(1);
@@ -80057,7 +82371,7 @@ __export(exports_read, {
80057
82371
  taskReadEffect: () => taskReadEffect,
80058
82372
  taskRead: () => taskRead
80059
82373
  });
80060
- async function createDefaultDeps11() {
82374
+ async function createDefaultDeps12() {
80061
82375
  const client4 = await getConvexClient();
80062
82376
  return {
80063
82377
  backend: {
@@ -80099,7 +82413,7 @@ function handleTaskReadError(err) {
80099
82413
  });
80100
82414
  }
80101
82415
  async function taskRead(chatroomId, options, deps) {
80102
- const d = deps ?? await createDefaultDeps11();
82416
+ const d = deps ?? await createDefaultDeps12();
80103
82417
  const layer = commandServicesLayerFromDeps(d);
80104
82418
  await exports_Effect.runPromise(taskReadEffect(chatroomId, options).pipe(exports_Effect.catchAll((err) => handleTaskReadError(err)), exports_Effect.provide(layer)));
80105
82419
  }
@@ -80190,7 +82504,7 @@ __export(exports_skill, {
80190
82504
  activateSkillEffect: () => activateSkillEffect,
80191
82505
  activateSkill: () => activateSkill
80192
82506
  });
80193
- async function createDefaultDeps12() {
82507
+ async function createDefaultDeps13() {
80194
82508
  const client4 = await getConvexClient();
80195
82509
  return {
80196
82510
  backend: {
@@ -80259,12 +82573,12 @@ function handleActivateSkillError(err) {
80259
82573
  });
80260
82574
  }
80261
82575
  async function listSkills(chatroomId, options, deps) {
80262
- const d = deps ?? await createDefaultDeps12();
82576
+ const d = deps ?? await createDefaultDeps13();
80263
82577
  const layer = commandServicesLayerFromDeps(d);
80264
82578
  await exports_Effect.runPromise(listSkillsEffect(chatroomId, options).pipe(exports_Effect.catchAll((err) => handleListSkillsError(err)), exports_Effect.provide(layer)));
80265
82579
  }
80266
82580
  async function activateSkill(chatroomId, skillId, options, deps) {
80267
- const d = deps ?? await createDefaultDeps12();
82581
+ const d = deps ?? await createDefaultDeps13();
80268
82582
  const layer = commandServicesLayerFromDeps(d);
80269
82583
  await exports_Effect.runPromise(activateSkillEffect(chatroomId, skillId, options).pipe(exports_Effect.catchAll((err) => handleActivateSkillError(err)), exports_Effect.provide(layer)));
80270
82584
  }
@@ -80342,7 +82656,7 @@ __export(exports_messages, {
80342
82656
  listBySenderRoleEffect: () => listBySenderRoleEffect,
80343
82657
  listBySenderRole: () => listBySenderRole
80344
82658
  });
80345
- async function createDefaultDeps13() {
82659
+ async function createDefaultDeps14() {
80346
82660
  const client4 = await getConvexClient();
80347
82661
  return {
80348
82662
  backend: {
@@ -80403,12 +82717,12 @@ function handleMessagesError(err) {
80403
82717
  });
80404
82718
  }
80405
82719
  async function listBySenderRole(chatroomId, options, deps) {
80406
- const d = deps ?? await createDefaultDeps13();
82720
+ const d = deps ?? await createDefaultDeps14();
80407
82721
  const layer = commandServicesLayerFromDeps(d);
80408
82722
  await exports_Effect.runPromise(listBySenderRoleEffect(chatroomId, options).pipe(exports_Effect.catchAll((err) => handleMessagesError(err)), exports_Effect.provide(layer)));
80409
82723
  }
80410
82724
  async function listSinceMessage(chatroomId, options, deps) {
80411
- const d = deps ?? await createDefaultDeps13();
82725
+ const d = deps ?? await createDefaultDeps14();
80412
82726
  const layer = commandServicesLayerFromDeps(d);
80413
82727
  await exports_Effect.runPromise(listSinceMessageEffect(chatroomId, options).pipe(exports_Effect.catchAll((err) => handleMessagesError(err)), exports_Effect.provide(layer)));
80414
82728
  }
@@ -80538,7 +82852,7 @@ __export(exports_context2, {
80538
82852
  inspectContextEffect: () => inspectContextEffect,
80539
82853
  inspectContext: () => inspectContext
80540
82854
  });
80541
- async function createDefaultDeps14() {
82855
+ async function createDefaultDeps15() {
80542
82856
  const client4 = await getConvexClient();
80543
82857
  return {
80544
82858
  backend: {
@@ -80579,17 +82893,17 @@ function handleContextError(err) {
80579
82893
  });
80580
82894
  }
80581
82895
  async function readContext(chatroomId, options, deps) {
80582
- const d = deps ?? await createDefaultDeps14();
82896
+ const d = deps ?? await createDefaultDeps15();
80583
82897
  const layer = commandServicesLayerFromDeps(d);
80584
82898
  await exports_Effect.runPromise(readContextEffect(chatroomId, options).pipe(exports_Effect.catchAll((err) => handleContextError(err)), exports_Effect.provide(layer)));
80585
82899
  }
80586
82900
  async function newContext(chatroomId, options, deps) {
80587
- const d = deps ?? await createDefaultDeps14();
82901
+ const d = deps ?? await createDefaultDeps15();
80588
82902
  const layer = commandServicesLayerFromDeps(d);
80589
82903
  await exports_Effect.runPromise(newContextEffect(chatroomId, options).pipe(exports_Effect.catchAll((err) => handleContextError(err)), exports_Effect.provide(layer)));
80590
82904
  }
80591
82905
  async function listContexts(chatroomId, options, deps) {
80592
- const d = deps ?? await createDefaultDeps14();
82906
+ const d = deps ?? await createDefaultDeps15();
80593
82907
  const layer = commandServicesLayerFromDeps(d);
80594
82908
  await exports_Effect.runPromise(listContextsEffect(chatroomId, options).pipe(exports_Effect.catchAll((err) => handleContextError(err)), exports_Effect.provide(layer)));
80595
82909
  }
@@ -80597,7 +82911,7 @@ function viewTemplate() {
80597
82911
  return getContextViewTemplate();
80598
82912
  }
80599
82913
  async function inspectContext(chatroomId, options, deps) {
80600
- const d = deps ?? await createDefaultDeps14();
82914
+ const d = deps ?? await createDefaultDeps15();
80601
82915
  const layer = commandServicesLayerFromDeps(d);
80602
82916
  await exports_Effect.runPromise(inspectContextEffect(chatroomId, options).pipe(exports_Effect.catchAll((err) => handleContextError(err)), exports_Effect.provide(layer)));
80603
82917
  }
@@ -80838,7 +83152,7 @@ __export(exports_guidelines, {
80838
83152
  listGuidelineTypesEffect: () => listGuidelineTypesEffect,
80839
83153
  listGuidelineTypes: () => listGuidelineTypes
80840
83154
  });
80841
- async function createDefaultDeps15() {
83155
+ async function createDefaultDeps16() {
80842
83156
  const client4 = await getConvexClient();
80843
83157
  return {
80844
83158
  backend: {
@@ -80879,12 +83193,12 @@ function handleListGuidelineTypesError(err) {
80879
83193
  });
80880
83194
  }
80881
83195
  async function viewGuidelines(options, deps) {
80882
- const d = deps ?? await createDefaultDeps15();
83196
+ const d = deps ?? await createDefaultDeps16();
80883
83197
  const layer = layerFromDeps7(d);
80884
83198
  await exports_Effect.runPromise(viewGuidelinesEffect(options).pipe(exports_Effect.catchAll((err) => handleViewGuidelinesError(err)), exports_Effect.provide(layer)));
80885
83199
  }
80886
83200
  async function listGuidelineTypes(deps) {
80887
- const d = deps ?? await createDefaultDeps15();
83201
+ const d = deps ?? await createDefaultDeps16();
80888
83202
  const layer = layerFromDeps7(d);
80889
83203
  await exports_Effect.runPromise(listGuidelineTypesEffect().pipe(exports_Effect.catchAll((err) => handleListGuidelineTypesError(err)), exports_Effect.provide(layer)));
80890
83204
  }
@@ -80954,7 +83268,7 @@ __export(exports_artifact, {
80954
83268
  createArtifactEffect: () => createArtifactEffect,
80955
83269
  createArtifact: () => createArtifact
80956
83270
  });
80957
- async function createDefaultDeps16() {
83271
+ async function createDefaultDeps17() {
80958
83272
  const client4 = await getConvexClient();
80959
83273
  return {
80960
83274
  backend: {
@@ -80976,19 +83290,19 @@ function handleArtifactError(err) {
80976
83290
  });
80977
83291
  }
80978
83292
  async function createArtifact(chatroomId, options, deps) {
80979
- const d = deps ?? await createDefaultDeps16();
83293
+ const d = deps ?? await createDefaultDeps17();
80980
83294
  const layer = commandServicesLayerFromDeps(d);
80981
83295
  return exports_Effect.runPromise(createArtifactEffect(chatroomId, options).pipe(exports_Effect.catchAll((err) => handleArtifactError(err).pipe(exports_Effect.map(() => {
80982
83296
  return;
80983
83297
  }))), exports_Effect.provide(layer)));
80984
83298
  }
80985
83299
  async function viewArtifact(chatroomId, options, deps) {
80986
- const d = deps ?? await createDefaultDeps16();
83300
+ const d = deps ?? await createDefaultDeps17();
80987
83301
  const layer = commandServicesLayerFromDeps(d);
80988
83302
  await exports_Effect.runPromise(viewArtifactEffect(chatroomId, options).pipe(exports_Effect.catchAll((err) => handleArtifactError(err)), exports_Effect.provide(layer)));
80989
83303
  }
80990
83304
  async function viewManyArtifacts(chatroomId, options, deps) {
80991
- const d = deps ?? await createDefaultDeps16();
83305
+ const d = deps ?? await createDefaultDeps17();
80992
83306
  const layer = commandServicesLayerFromDeps(d);
80993
83307
  await exports_Effect.runPromise(viewManyArtifactsEffect(chatroomId, options).pipe(exports_Effect.catchAll((err) => handleArtifactError(err)), exports_Effect.provide(layer)));
80994
83308
  }
@@ -81338,7 +83652,7 @@ __export(exports_telegram, {
81338
83652
  sendMessageEffect: () => sendMessageEffect,
81339
83653
  sendMessage: () => sendMessage
81340
83654
  });
81341
- async function createDefaultDeps17() {
83655
+ async function createDefaultDeps18() {
81342
83656
  const client4 = await getConvexClient();
81343
83657
  return {
81344
83658
  backend: {
@@ -81420,7 +83734,7 @@ ${err.cause.message}`);
81420
83734
  });
81421
83735
  }
81422
83736
  async function sendMessage(options, deps) {
81423
- const d = deps ?? await createDefaultDeps17();
83737
+ const d = deps ?? await createDefaultDeps18();
81424
83738
  const layer = layerFromDeps8(d);
81425
83739
  await exports_Effect.runPromise(sendMessageEffect(options).pipe(exports_Effect.catchAll((err) => handleSendMessageError(err)), exports_Effect.provide(layer)));
81426
83740
  }
@@ -81472,7 +83786,7 @@ var init_featureFlags = __esm(() => {
81472
83786
  });
81473
83787
 
81474
83788
  // ../../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;
83789
+ 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_TERMINAL_JOB_RETENTION_MS;
81476
83790
  var init_reliability = __esm(() => {
81477
83791
  DAEMON_HEARTBEAT_INTERVAL_MS = 5 * 60000;
81478
83792
  DAEMON_HEARTBEAT_TTL_MS = 6 * DAEMON_HEARTBEAT_INTERVAL_MS;
@@ -81481,6 +83795,7 @@ var init_reliability = __esm(() => {
81481
83795
  WORKSPACE_RECENCY_WINDOW_MS = 7 * 24 * 60 * 60 * 1000;
81482
83796
  WORKSPACE_LIST_RECONCILE_MS = 60 * 60 * 1000;
81483
83797
  CONNECTION_CLOSE_REQUEST_TTL_MS = 10 * 60000;
83798
+ ENHANCER_TERMINAL_JOB_RETENTION_MS = 30 * 24 * 60 * 60 * 1000;
81484
83799
  });
81485
83800
 
81486
83801
  // src/commands/machine/daemon-start/command-event-types.ts
@@ -101470,6 +103785,108 @@ var init_start_subscriptions2 = __esm(() => {
101470
103785
  init_convex_agentic_query_run_repository();
101471
103786
  });
101472
103787
 
103788
+ // src/commands/machine/daemon-start/enhancer/constants.ts
103789
+ var ENHANCER_AGENT_ROLE = "enhancer";
103790
+
103791
+ // src/commands/machine/daemon-start/enhancer/job-subscriber.ts
103792
+ function startEnhancerJobSubscriber(sessionId, machineId, convexUrl, backend2, wsClient2, agentServices) {
103793
+ const inFlight = new Set;
103794
+ const unsub = wsClient2.onUpdate(api.daemon.enhancer.index.pendingForMachine, { sessionId, machineId }, (jobs) => {
103795
+ for (const job of jobs ?? []) {
103796
+ if (inFlight.has(job.jobId))
103797
+ continue;
103798
+ inFlight.add(job.jobId);
103799
+ (async () => {
103800
+ let claimed = false;
103801
+ let chatroomId = job.chatroomId;
103802
+ let jobId = job.jobId;
103803
+ try {
103804
+ const claim = await backend2.mutation(api.daemon.enhancer.index.claimForSpawn, {
103805
+ sessionId,
103806
+ jobId: job.jobId,
103807
+ machineId
103808
+ });
103809
+ if (!claim.claimed)
103810
+ return;
103811
+ claimed = true;
103812
+ const payload = await backend2.query(api.daemon.enhancer.index.getSpawnPayload, {
103813
+ sessionId,
103814
+ jobId: job.jobId
103815
+ });
103816
+ chatroomId = payload.chatroomId;
103817
+ jobId = payload.jobId;
103818
+ const service3 = agentServices.get(payload.agentHarness);
103819
+ if (!service3) {
103820
+ await backend2.mutation(api.web.enhancer.index.recordAttemptFailure, {
103821
+ sessionId,
103822
+ chatroomId: payload.chatroomId,
103823
+ jobId: payload.jobId,
103824
+ error: `Harness ${payload.agentHarness} not available on machine`
103825
+ });
103826
+ return;
103827
+ }
103828
+ const spawnResult = await service3.spawn({
103829
+ workingDir: payload.workingDir,
103830
+ prompt: createSpawnPrompt(payload.taskEnvelope),
103831
+ systemPrompt: payload.systemPrompt,
103832
+ model: payload.model,
103833
+ context: {
103834
+ machineId,
103835
+ chatroomId: payload.chatroomId,
103836
+ role: ENHANCER_AGENT_ROLE
103837
+ },
103838
+ resolvedConvexUrl: convexUrl
103839
+ });
103840
+ spawnResult.onLogLine?.((line) => {
103841
+ process.stdout.write(`${line}
103842
+ `);
103843
+ });
103844
+ await new Promise((resolve4) => {
103845
+ spawnResult.onExit(() => resolve4());
103846
+ });
103847
+ const status3 = await backend2.query(api.web.enhancer.index.getJob, {
103848
+ sessionId,
103849
+ chatroomId: payload.chatroomId,
103850
+ jobId: payload.jobId
103851
+ });
103852
+ if (status3?.status === "running") {
103853
+ await backend2.mutation(api.web.enhancer.index.recordAttemptFailure, {
103854
+ sessionId,
103855
+ chatroomId: payload.chatroomId,
103856
+ jobId: payload.jobId,
103857
+ error: "Agent exited without completing enhancer job"
103858
+ });
103859
+ }
103860
+ } catch (err) {
103861
+ console.warn("[enhancer] spawn error:", err instanceof Error ? err.message : String(err));
103862
+ if (claimed) {
103863
+ await backend2.mutation(api.web.enhancer.index.recordAttemptFailure, {
103864
+ sessionId,
103865
+ chatroomId,
103866
+ jobId,
103867
+ error: err instanceof Error ? err.message : String(err)
103868
+ });
103869
+ }
103870
+ } finally {
103871
+ inFlight.delete(job.jobId);
103872
+ }
103873
+ })();
103874
+ }
103875
+ }, (err) => console.warn("[enhancer] subscription error:", err));
103876
+ return { stop: unsub };
103877
+ }
103878
+ var init_job_subscriber = __esm(() => {
103879
+ init_api3();
103880
+ });
103881
+
103882
+ // src/commands/machine/daemon-start/enhancer/start-subscriptions.ts
103883
+ function startEnhancerSubscriptions(sessionId, machineId, convexUrl, backend2, wsClient2, agentServices) {
103884
+ return startEnhancerJobSubscriber(sessionId, machineId, convexUrl, backend2, wsClient2, agentServices);
103885
+ }
103886
+ var init_start_subscriptions3 = __esm(() => {
103887
+ init_job_subscriber();
103888
+ });
103889
+
101473
103890
  // src/commands/machine/daemon-start/file-content-classifier.ts
101474
103891
  function extensionOf(path3) {
101475
103892
  const lastDot = path3.lastIndexOf(".");
@@ -108912,7 +111329,7 @@ async function discoverModelsForHarness(harness, service3) {
108912
111329
  async function discoverModels(agentServices) {
108913
111330
  return exports_Effect.runPromise(discoverModelsEffect(agentServices));
108914
111331
  }
108915
- function createDefaultDeps18() {
111332
+ function createDefaultDeps19() {
108916
111333
  return {
108917
111334
  backend: {
108918
111335
  mutation: async () => {
@@ -109250,7 +111667,7 @@ var init_init2 = __esm(() => {
109250
111667
  convexUrl,
109251
111668
  agentServices,
109252
111669
  cachedModels,
109253
- deps: createDefaultDeps18()
111670
+ deps: createDefaultDeps19()
109254
111671
  });
109255
111672
  yield* registerEventListenersEffect().pipe(exports_Effect.provide(daemonSessionToLayers(init2)));
109256
111673
  yield* logStartupEffect(cachedModels).pipe(exports_Effect.provide(daemonSessionToLayers(init2)));
@@ -112217,6 +114634,7 @@ var init_command_loop = __esm(() => {
112217
114634
  init_daemon_services();
112218
114635
  init_start_subscriptions();
112219
114636
  init_start_subscriptions2();
114637
+ init_start_subscriptions3();
112220
114638
  init_file_content_subscription();
112221
114639
  init_file_tree_subscription();
112222
114640
  init_file_write_subscription();
@@ -112403,6 +114821,7 @@ var init_command_loop = __esm(() => {
112403
114821
  }, wsClient2, activeSessions, harnesses);
112404
114822
  aqPendingPromptSubscriptionHandle = aqHandles.pendingPromptSubscriptionHandle;
112405
114823
  aqPendingHarnessSessionSubscriptionHandle = aqHandles.pendingHarnessSessionSubscriptionHandle;
114824
+ const enhancerSub = startEnhancerSubscriptions(session2.sessionId, session2.machineId, session2.convexUrl, session2.backend, wsClient2, session2.agentServices);
112406
114825
  }
112407
114826
  console.log(`
112408
114827
  Listening for commands...`);
@@ -112597,7 +115016,7 @@ async function isChatroomInstalledDefault() {
112597
115016
  return false;
112598
115017
  }
112599
115018
  }
112600
- async function createDefaultDeps19() {
115019
+ async function createDefaultDeps20() {
112601
115020
  const client4 = await getConvexClient();
112602
115021
  const fs12 = await import("fs/promises");
112603
115022
  return {
@@ -112672,7 +115091,7 @@ After installation, run this command again.`;
112672
115091
  });
112673
115092
  }
112674
115093
  async function installTool(options = {}, deps) {
112675
- const d = deps ?? await createDefaultDeps19();
115094
+ const d = deps ?? await createDefaultDeps20();
112676
115095
  const layer = layerFromDeps9(d);
112677
115096
  return exports_Effect.runPromise(installToolEffect(options).pipe(exports_Effect.catchAll((err) => handleInstallError(err)), exports_Effect.provide(layer)));
112678
115097
  }
@@ -113223,6 +115642,50 @@ handoffCommandGroup.requiredOption("--chatroom-id <id>", "Chatroom identifier").
113223
115642
  console.error("❌ Message is empty");
113224
115643
  process.exit(1);
113225
115644
  }
115645
+ const shouldEnhance = options.role.toLowerCase() === "planner" && options.nextRole.toLowerCase() === "builder";
115646
+ if (shouldEnhance) {
115647
+ const { api: api3 } = await Promise.resolve().then(() => (init_api3(), exports_api));
115648
+ const { getConvexClient: getConvexClient2 } = await Promise.resolve().then(() => (init_client2(), exports_client));
115649
+ const { getSessionId: getSessionId2 } = await Promise.resolve().then(() => (init_storage(), exports_storage));
115650
+ const client4 = await getConvexClient2();
115651
+ const sessionId = await getSessionId2();
115652
+ if (sessionId) {
115653
+ try {
115654
+ const config4 = await client4.query(api3.web.enhancer.index.getConfig, {
115655
+ sessionId,
115656
+ chatroomId: options.chatroomId
115657
+ });
115658
+ if (config4 && config4.enabled) {
115659
+ await client4.mutation(api3.web.enhancer.index.enqueueHandoff, {
115660
+ sessionId,
115661
+ chatroomId: options.chatroomId,
115662
+ senderRole: options.role,
115663
+ targetRole: options.nextRole,
115664
+ content: message
115665
+ });
115666
+ const { generateHandoffOutput: generateHandoffOutput2 } = await Promise.resolve().then(() => (init_generator(), exports_generator));
115667
+ const { getConvexUrl: getConvexUrl2 } = await Promise.resolve().then(() => (init_client2(), exports_client));
115668
+ const convexUrl = await getConvexUrl2();
115669
+ console.log(generateHandoffOutput2({
115670
+ role: options.role,
115671
+ nextRole: options.nextRole,
115672
+ chatroomId: options.chatroomId,
115673
+ convexUrl
115674
+ }));
115675
+ return;
115676
+ }
115677
+ } catch (err) {
115678
+ const error51 = err;
115679
+ if (error51?.data?.code !== "ENHANCER_NOT_ENABLED") {
115680
+ console.error(`
115681
+ ❌ ERROR: Enhancer interception failed`);
115682
+ console.error(`
115683
+ ${error51?.data?.message ?? err.message}`);
115684
+ process.exit(1);
115685
+ }
115686
+ }
115687
+ }
115688
+ }
113226
115689
  const { handoff: handoff2 } = await Promise.resolve().then(() => (init_handoff(), exports_handoff));
113227
115690
  await handoff2(options.chatroomId, {
113228
115691
  role: options.role,
@@ -113257,6 +115720,29 @@ agenticQueryCommand.command("complete").description("Submit the structured agent
113257
115720
  result
113258
115721
  });
113259
115722
  });
115723
+ var enhancerCommand = program2.command("enhancer").description("Handoff enhancer commands");
115724
+ 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) => {
115725
+ await maybeRequireAuth();
115726
+ const { decode: decode5 } = await Promise.resolve().then(() => exports_decode);
115727
+ const stdinContent = await readStdin();
115728
+ let body;
115729
+ try {
115730
+ 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));
115731
+ const decoded = decode5(stdinContent, { singleParam: "result" });
115732
+ body = decoded.result;
115733
+ body = body.replace(new RegExp(`^(${HANDOFF_MESSAGE_MARKER2}\\s*)+`, "i"), "").trim();
115734
+ validateStdinHeredocBody2(body, ENHANCER_STDIN_DELIMITER2);
115735
+ } catch (err) {
115736
+ console.error(`❌ Failed to decode stdin: ${err.message}`);
115737
+ process.exit(1);
115738
+ }
115739
+ if (!body?.trim()) {
115740
+ console.error("❌ Enhanced handoff body is empty");
115741
+ process.exit(1);
115742
+ }
115743
+ const { enhancerComplete: enhancerComplete2 } = await Promise.resolve().then(() => (init_complete2(), exports_complete2));
115744
+ await enhancerComplete2(options.chatroomId, { jobId: options.jobId, enhancedContent: body });
115745
+ });
113260
115746
  var backlogCommand = program2.command("backlog").description("Manage task queue and backlog");
113261
115747
  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
115748
  await maybeRequireAuth();
@@ -113541,4 +116027,4 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
113541
116027
  });
113542
116028
  program2.parse();
113543
116029
 
113544
- //# debugId=5D81C0C1AF371BE564756E2164756E21
116030
+ //# debugId=84E53044E3B850A464756E2164756E21