chatroom-cli 1.117.6 → 1.119.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
|
@@ -26981,6 +26981,16 @@ var init_backend = __esm(() => {
|
|
|
26981
26981
|
};
|
|
26982
26982
|
});
|
|
26983
26983
|
|
|
26984
|
+
// src/infrastructure/services/cli-gateway.ts
|
|
26985
|
+
var CliGatewayService, CliGatewayServiceLive = (gateway) => exports_Layer.succeed(CliGatewayService, {
|
|
26986
|
+
handoff: (args2) => gateway.handoff(args2)
|
|
26987
|
+
});
|
|
26988
|
+
var init_cli_gateway = __esm(() => {
|
|
26989
|
+
init_esm();
|
|
26990
|
+
CliGatewayService = class CliGatewayService extends exports_Context.Tag("CliGatewayService")() {
|
|
26991
|
+
};
|
|
26992
|
+
});
|
|
26993
|
+
|
|
26984
26994
|
// src/infrastructure/services/session.ts
|
|
26985
26995
|
var SessionService, SessionServiceLive = (ops) => exports_Layer.succeed(SessionService, {
|
|
26986
26996
|
getSessionId: () => exports_Effect.promise(() => ops.getSessionId()),
|
|
@@ -26995,7 +27005,12 @@ var init_session = __esm(() => {
|
|
|
26995
27005
|
|
|
26996
27006
|
// src/infrastructure/services/command-effect-helpers.ts
|
|
26997
27007
|
function commandServicesLayerFromDeps(deps) {
|
|
26998
|
-
|
|
27008
|
+
const gateway = deps.gateway ?? {
|
|
27009
|
+
handoff: async () => {
|
|
27010
|
+
throw new Error("CLI gateway is unavailable");
|
|
27011
|
+
}
|
|
27012
|
+
};
|
|
27013
|
+
return exports_Layer.mergeAll(CliGatewayServiceLive(gateway), BackendServiceLive({
|
|
26999
27014
|
query: deps.backend.query,
|
|
27000
27015
|
mutation: deps.backend.mutation,
|
|
27001
27016
|
...deps.backend.action ? { action: deps.backend.action } : {}
|
|
@@ -27017,6 +27032,17 @@ function requireSessionIdEffect(fail11) {
|
|
|
27017
27032
|
return sessionId;
|
|
27018
27033
|
});
|
|
27019
27034
|
}
|
|
27035
|
+
function requireSessionForChatroomEffect(params) {
|
|
27036
|
+
return exports_Effect.gen(function* () {
|
|
27037
|
+
const sessionId = yield* requireSessionIdEffect(({ convexUrl, otherUrls }) => ({
|
|
27038
|
+
_tag: "NotAuthenticated",
|
|
27039
|
+
convexUrl,
|
|
27040
|
+
otherUrls
|
|
27041
|
+
}));
|
|
27042
|
+
yield* validateChatroomIdEffect(params.chatroomId, (id3) => ({ _tag: "InvalidChatroomId", id: id3 }));
|
|
27043
|
+
return sessionId;
|
|
27044
|
+
});
|
|
27045
|
+
}
|
|
27020
27046
|
function validateChatroomIdEffect(chatroomId, fail11) {
|
|
27021
27047
|
const valid = typeof chatroomId === "string" && chatroomId.length >= 20 && chatroomId.length <= 40;
|
|
27022
27048
|
return valid ? exports_Effect.void : exports_Effect.fail(fail11(chatroomId));
|
|
@@ -27024,6 +27050,7 @@ function validateChatroomIdEffect(chatroomId, fail11) {
|
|
|
27024
27050
|
var init_command_effect_helpers = __esm(() => {
|
|
27025
27051
|
init_esm();
|
|
27026
27052
|
init_backend();
|
|
27053
|
+
init_cli_gateway();
|
|
27027
27054
|
init_session();
|
|
27028
27055
|
});
|
|
27029
27056
|
|
|
@@ -27081,6 +27108,7 @@ var init_process = __esm(() => {
|
|
|
27081
27108
|
// src/infrastructure/services/index.ts
|
|
27082
27109
|
var init_services = __esm(() => {
|
|
27083
27110
|
init_backend();
|
|
27111
|
+
init_cli_gateway();
|
|
27084
27112
|
init_command_effect_helpers();
|
|
27085
27113
|
init_clock2();
|
|
27086
27114
|
init_fs();
|
|
@@ -27764,6 +27792,100 @@ var init_base_cli_agent_service = __esm(() => {
|
|
|
27764
27792
|
retrySchedule = exports_Schedule.exponential(exports_Duration.millis(DETECTION_RETRY_POLICY.initialDelayMs), DETECTION_RETRY_POLICY.backoffFactor).pipe(exports_Schedule.either(exports_Schedule.spaced(exports_Duration.millis(DETECTION_RETRY_POLICY.maxDelayMs))), exports_Schedule.compose(exports_Schedule.recurs(DETECTION_RETRY_POLICY.maxAttempts - 1)));
|
|
27765
27793
|
});
|
|
27766
27794
|
|
|
27795
|
+
// ../../services/backend/src/domain/entities/_shared/v-literals-of.ts
|
|
27796
|
+
var toLiteralValidators = (values3) => values3.map((v_) => v.literal(v_));
|
|
27797
|
+
var init_v_literals_of = __esm(() => {
|
|
27798
|
+
init_values();
|
|
27799
|
+
});
|
|
27800
|
+
|
|
27801
|
+
// ../../services/backend/src/domain/entities/agent.ts
|
|
27802
|
+
var AGENT_HARNESSES, AgentHarnessEnum, agentHarnessValidator, AGENT_TYPES, AgentTypeEnum, agentTypeValidator, MACHINE_COMMAND_TYPES, MachineCommandTypeEnum, machineCommandTypeValidator, MACHINE_COMMAND_STATUSES, MachineCommandStatusEnum, machineCommandStatusValidator, AgentStartReasonCode, AGENT_START_REASONS, DaemonStartReasonCode, agentStartReasonValidator, USER_EXPLICIT_START_REASONS, EXPLICIT_DAEMON_START_REASONS, isExplicitDaemonStart = (reason) => EXPLICIT_DAEMON_START_REASONS.includes(reason), AGENT_STOP_REASONS, agentPostStopDesiredStateValidator, AgentStopReasonEnum, MODEL_SOURCES, ModelSourceEnum, modelSourceValidator;
|
|
27803
|
+
var init_agent = __esm(() => {
|
|
27804
|
+
init_values();
|
|
27805
|
+
init_v_literals_of();
|
|
27806
|
+
AGENT_HARNESSES = [
|
|
27807
|
+
"opencode",
|
|
27808
|
+
"opencode-sdk",
|
|
27809
|
+
"pi",
|
|
27810
|
+
"pi-sdk",
|
|
27811
|
+
"cursor",
|
|
27812
|
+
"cursor-sdk",
|
|
27813
|
+
"claude",
|
|
27814
|
+
"claude-sdk",
|
|
27815
|
+
"codex-sdk",
|
|
27816
|
+
"copilot",
|
|
27817
|
+
"commandcode"
|
|
27818
|
+
];
|
|
27819
|
+
AgentHarnessEnum = Object.fromEntries(AGENT_HARNESSES.map((h) => [h, h]));
|
|
27820
|
+
agentHarnessValidator = v.union(...toLiteralValidators(AGENT_HARNESSES));
|
|
27821
|
+
AGENT_TYPES = ["remote", "custom"];
|
|
27822
|
+
AgentTypeEnum = Object.fromEntries(AGENT_TYPES.map((t) => [t, t]));
|
|
27823
|
+
agentTypeValidator = v.union(...toLiteralValidators(AGENT_TYPES));
|
|
27824
|
+
MACHINE_COMMAND_TYPES = ["start-agent", "restart-agent", "ping", "status"];
|
|
27825
|
+
MachineCommandTypeEnum = Object.fromEntries(MACHINE_COMMAND_TYPES.map((c) => [c, c]));
|
|
27826
|
+
machineCommandTypeValidator = v.union(...toLiteralValidators(MACHINE_COMMAND_TYPES));
|
|
27827
|
+
MACHINE_COMMAND_STATUSES = ["pending", "completed", "failed"];
|
|
27828
|
+
MachineCommandStatusEnum = Object.fromEntries(MACHINE_COMMAND_STATUSES.map((s) => [s, s]));
|
|
27829
|
+
machineCommandStatusValidator = v.union(...toLiteralValidators(MACHINE_COMMAND_STATUSES));
|
|
27830
|
+
AgentStartReasonCode = {
|
|
27831
|
+
USER_START: "user.start",
|
|
27832
|
+
USER_RESTART: "user.restart",
|
|
27833
|
+
USER_MANUAL_SPAWN: "user.manual_spawn",
|
|
27834
|
+
PLATFORM_TASK_MONITOR_NUDGE: "platform.task_monitor_nudge",
|
|
27835
|
+
PLATFORM_TASK_START_IN_NEW_SESSION: "platform.task_start_in_new_session",
|
|
27836
|
+
PLATFORM_PENDING_TASK_WAKE: "platform.pending_task_wake",
|
|
27837
|
+
PLATFORM_AUTO_RESTART_ON_NEW_CONTEXT: "platform.auto_restart_on_new_context",
|
|
27838
|
+
PLATFORM_TEAM_SWITCH: "platform.team_switch",
|
|
27839
|
+
TEST: "test"
|
|
27840
|
+
};
|
|
27841
|
+
AGENT_START_REASONS = [
|
|
27842
|
+
AgentStartReasonCode.USER_START,
|
|
27843
|
+
AgentStartReasonCode.USER_RESTART,
|
|
27844
|
+
AgentStartReasonCode.USER_MANUAL_SPAWN,
|
|
27845
|
+
AgentStartReasonCode.PLATFORM_TASK_MONITOR_NUDGE,
|
|
27846
|
+
AgentStartReasonCode.PLATFORM_TASK_START_IN_NEW_SESSION,
|
|
27847
|
+
AgentStartReasonCode.PLATFORM_PENDING_TASK_WAKE,
|
|
27848
|
+
AgentStartReasonCode.PLATFORM_AUTO_RESTART_ON_NEW_CONTEXT,
|
|
27849
|
+
AgentStartReasonCode.PLATFORM_TEAM_SWITCH,
|
|
27850
|
+
AgentStartReasonCode.TEST
|
|
27851
|
+
];
|
|
27852
|
+
DaemonStartReasonCode = {
|
|
27853
|
+
RESPAWN: "daemon.respawn"
|
|
27854
|
+
};
|
|
27855
|
+
agentStartReasonValidator = v.union(...toLiteralValidators(AGENT_START_REASONS));
|
|
27856
|
+
USER_EXPLICIT_START_REASONS = [
|
|
27857
|
+
AgentStartReasonCode.USER_START,
|
|
27858
|
+
AgentStartReasonCode.USER_RESTART
|
|
27859
|
+
];
|
|
27860
|
+
EXPLICIT_DAEMON_START_REASONS = [
|
|
27861
|
+
...USER_EXPLICIT_START_REASONS,
|
|
27862
|
+
AgentStartReasonCode.USER_MANUAL_SPAWN,
|
|
27863
|
+
AgentStartReasonCode.PLATFORM_TASK_MONITOR_NUDGE,
|
|
27864
|
+
AgentStartReasonCode.PLATFORM_PENDING_TASK_WAKE,
|
|
27865
|
+
AgentStartReasonCode.PLATFORM_TASK_START_IN_NEW_SESSION,
|
|
27866
|
+
DaemonStartReasonCode.RESPAWN
|
|
27867
|
+
];
|
|
27868
|
+
AGENT_STOP_REASONS = [
|
|
27869
|
+
"user.stop",
|
|
27870
|
+
"user.restart",
|
|
27871
|
+
"platform.dedup",
|
|
27872
|
+
"platform.team_switch",
|
|
27873
|
+
"platform.task_monitor_nudge",
|
|
27874
|
+
"platform.task_start_in_new_session",
|
|
27875
|
+
"daemon.respawn",
|
|
27876
|
+
"daemon.shutdown",
|
|
27877
|
+
"daemon.stop_timeout",
|
|
27878
|
+
"platform.ephemeral_task_complete",
|
|
27879
|
+
"platform.task_cancelled",
|
|
27880
|
+
"test"
|
|
27881
|
+
];
|
|
27882
|
+
agentPostStopDesiredStateValidator = v.union(v.literal("running"), v.literal("stopped"));
|
|
27883
|
+
AgentStopReasonEnum = Object.fromEntries(AGENT_STOP_REASONS.map((r) => [r, r]));
|
|
27884
|
+
MODEL_SOURCES = ["team_config", "none"];
|
|
27885
|
+
ModelSourceEnum = Object.fromEntries(MODEL_SOURCES.map((s) => [s, s]));
|
|
27886
|
+
modelSourceValidator = v.union(...toLiteralValidators(MODEL_SOURCES));
|
|
27887
|
+
});
|
|
27888
|
+
|
|
27767
27889
|
// ../../services/backend/src/domain/entities/harness/claude-sdk.config.ts
|
|
27768
27890
|
var claudeSdkCapabilities;
|
|
27769
27891
|
var init_claude_sdk_config = __esm(() => {
|
|
@@ -28230,7 +28352,7 @@ function createAgentProcessManagerService(deps) {
|
|
|
28230
28352
|
await awaitWithinDeadline(deps.execution.stop({
|
|
28231
28353
|
chatroomId: input.chatroomId,
|
|
28232
28354
|
role: input.role,
|
|
28233
|
-
reason:
|
|
28355
|
+
reason: DaemonStartReasonCode.RESPAWN,
|
|
28234
28356
|
pid: slot.pid,
|
|
28235
28357
|
workingDir: input.workingDir
|
|
28236
28358
|
}), remaining, input.signal);
|
|
@@ -28334,11 +28456,13 @@ function createAgentProcessManagerService(deps) {
|
|
|
28334
28456
|
resumeTurnForSlot: (input) => deps.execution.resumeTurnForSlot(input),
|
|
28335
28457
|
subscribeAgentTurnEnded: (handler) => deps.execution.subscribeAgentTurnEnded(handler),
|
|
28336
28458
|
subscribeAgentStarted: (handler) => deps.execution.subscribeAgentStarted(handler),
|
|
28337
|
-
subscribeAgentSessionLost: (handler) => deps.execution.subscribeAgentSessionLost(handler)
|
|
28459
|
+
subscribeAgentSessionLost: (handler) => deps.execution.subscribeAgentSessionLost(handler),
|
|
28460
|
+
subscribeAgentTurnProgress: (handler) => deps.execution.subscribeAgentTurnProgress(handler)
|
|
28338
28461
|
};
|
|
28339
28462
|
}
|
|
28340
28463
|
var NATIVE_DELIVERY_SLOT_WAIT_MS = 120000, SLOT_CHANGE_POLL_MS = 100;
|
|
28341
28464
|
var init_agent_process_manager_service = __esm(() => {
|
|
28465
|
+
init_agent();
|
|
28342
28466
|
init_types();
|
|
28343
28467
|
init_check_agent_slot();
|
|
28344
28468
|
});
|
|
@@ -28743,86 +28867,6 @@ var init_native_turn_phase = __esm(() => {
|
|
|
28743
28867
|
init_agent_slot();
|
|
28744
28868
|
});
|
|
28745
28869
|
|
|
28746
|
-
// ../../services/backend/src/domain/entities/_shared/v-literals-of.ts
|
|
28747
|
-
var toLiteralValidators = (values3) => values3.map((v_) => v.literal(v_));
|
|
28748
|
-
var init_v_literals_of = __esm(() => {
|
|
28749
|
-
init_values();
|
|
28750
|
-
});
|
|
28751
|
-
|
|
28752
|
-
// ../../services/backend/src/domain/entities/agent.ts
|
|
28753
|
-
var AGENT_HARNESSES, AgentHarnessEnum, agentHarnessValidator, AGENT_TYPES, AgentTypeEnum, agentTypeValidator, MACHINE_COMMAND_TYPES, MachineCommandTypeEnum, machineCommandTypeValidator, MACHINE_COMMAND_STATUSES, MachineCommandStatusEnum, machineCommandStatusValidator, AGENT_START_REASONS, AgentStartReasonEnum, agentStartReasonValidator, USER_EXPLICIT_START_REASONS, EXPLICIT_DAEMON_START_REASONS, isExplicitDaemonStart = (reason) => EXPLICIT_DAEMON_START_REASONS.includes(reason), AGENT_STOP_REASONS, agentPostStopDesiredStateValidator, AgentStopReasonEnum, MODEL_SOURCES, ModelSourceEnum, modelSourceValidator;
|
|
28754
|
-
var init_agent = __esm(() => {
|
|
28755
|
-
init_values();
|
|
28756
|
-
init_v_literals_of();
|
|
28757
|
-
AGENT_HARNESSES = [
|
|
28758
|
-
"opencode",
|
|
28759
|
-
"opencode-sdk",
|
|
28760
|
-
"pi",
|
|
28761
|
-
"pi-sdk",
|
|
28762
|
-
"cursor",
|
|
28763
|
-
"cursor-sdk",
|
|
28764
|
-
"claude",
|
|
28765
|
-
"claude-sdk",
|
|
28766
|
-
"codex-sdk",
|
|
28767
|
-
"copilot",
|
|
28768
|
-
"commandcode"
|
|
28769
|
-
];
|
|
28770
|
-
AgentHarnessEnum = Object.fromEntries(AGENT_HARNESSES.map((h) => [h, h]));
|
|
28771
|
-
agentHarnessValidator = v.union(...toLiteralValidators(AGENT_HARNESSES));
|
|
28772
|
-
AGENT_TYPES = ["remote", "custom"];
|
|
28773
|
-
AgentTypeEnum = Object.fromEntries(AGENT_TYPES.map((t) => [t, t]));
|
|
28774
|
-
agentTypeValidator = v.union(...toLiteralValidators(AGENT_TYPES));
|
|
28775
|
-
MACHINE_COMMAND_TYPES = ["start-agent", "restart-agent", "ping", "status"];
|
|
28776
|
-
MachineCommandTypeEnum = Object.fromEntries(MACHINE_COMMAND_TYPES.map((c) => [c, c]));
|
|
28777
|
-
machineCommandTypeValidator = v.union(...toLiteralValidators(MACHINE_COMMAND_TYPES));
|
|
28778
|
-
MACHINE_COMMAND_STATUSES = ["pending", "completed", "failed"];
|
|
28779
|
-
MachineCommandStatusEnum = Object.fromEntries(MACHINE_COMMAND_STATUSES.map((s) => [s, s]));
|
|
28780
|
-
machineCommandStatusValidator = v.union(...toLiteralValidators(MACHINE_COMMAND_STATUSES));
|
|
28781
|
-
AGENT_START_REASONS = [
|
|
28782
|
-
"user.start",
|
|
28783
|
-
"user.restart",
|
|
28784
|
-
"user.manual_spawn",
|
|
28785
|
-
"platform.task_monitor_nudge",
|
|
28786
|
-
"platform.task_start_in_new_session",
|
|
28787
|
-
"platform.pending_task_wake",
|
|
28788
|
-
"platform.auto_restart_on_new_context",
|
|
28789
|
-
"platform.team_switch",
|
|
28790
|
-
"test"
|
|
28791
|
-
];
|
|
28792
|
-
AgentStartReasonEnum = Object.fromEntries(AGENT_START_REASONS.map((r) => [r, r]));
|
|
28793
|
-
agentStartReasonValidator = v.union(...toLiteralValidators(AGENT_START_REASONS));
|
|
28794
|
-
USER_EXPLICIT_START_REASONS = [
|
|
28795
|
-
AgentStartReasonEnum["user.start"],
|
|
28796
|
-
AgentStartReasonEnum["user.restart"]
|
|
28797
|
-
];
|
|
28798
|
-
EXPLICIT_DAEMON_START_REASONS = [
|
|
28799
|
-
...USER_EXPLICIT_START_REASONS,
|
|
28800
|
-
AgentStartReasonEnum["user.manual_spawn"],
|
|
28801
|
-
AgentStartReasonEnum["platform.task_monitor_nudge"],
|
|
28802
|
-
AgentStartReasonEnum["platform.task_start_in_new_session"],
|
|
28803
|
-
"daemon.respawn"
|
|
28804
|
-
];
|
|
28805
|
-
AGENT_STOP_REASONS = [
|
|
28806
|
-
"user.stop",
|
|
28807
|
-
"user.restart",
|
|
28808
|
-
"platform.dedup",
|
|
28809
|
-
"platform.team_switch",
|
|
28810
|
-
"platform.task_monitor_nudge",
|
|
28811
|
-
"platform.task_start_in_new_session",
|
|
28812
|
-
"daemon.respawn",
|
|
28813
|
-
"daemon.shutdown",
|
|
28814
|
-
"daemon.stop_timeout",
|
|
28815
|
-
"platform.ephemeral_task_complete",
|
|
28816
|
-
"platform.task_cancelled",
|
|
28817
|
-
"test"
|
|
28818
|
-
];
|
|
28819
|
-
agentPostStopDesiredStateValidator = v.union(v.literal("running"), v.literal("stopped"));
|
|
28820
|
-
AgentStopReasonEnum = Object.fromEntries(AGENT_STOP_REASONS.map((r) => [r, r]));
|
|
28821
|
-
MODEL_SOURCES = ["team_config", "none"];
|
|
28822
|
-
ModelSourceEnum = Object.fromEntries(MODEL_SOURCES.map((s) => [s, s]));
|
|
28823
|
-
modelSourceValidator = v.union(...toLiteralValidators(MODEL_SOURCES));
|
|
28824
|
-
});
|
|
28825
|
-
|
|
28826
28870
|
// src/daemon/services/agent-process-service/infrastructure/adapters/orphan-process-tracker.ts
|
|
28827
28871
|
import { createHash } from "node:crypto";
|
|
28828
28872
|
import {
|
|
@@ -43645,7 +43689,7 @@ var init_agent_lifecycle_fact_schema = __esm(() => {
|
|
|
43645
43689
|
...agent,
|
|
43646
43690
|
kind: exports_external.literal("status"),
|
|
43647
43691
|
status: exports_external.enum(["offline", "starting", "waiting", "working", "stopping", "error"]),
|
|
43648
|
-
errorSource: exports_external.enum(["configuration", "runtime", "task", "
|
|
43692
|
+
errorSource: exports_external.enum(["configuration", "runtime", "task", "stop"]).optional(),
|
|
43649
43693
|
errorCode: exports_external.string().optional(),
|
|
43650
43694
|
errorMessage: exports_external.string().optional()
|
|
43651
43695
|
}),
|
|
@@ -44651,29 +44695,24 @@ async function emitNativeWaitingAfterSpawn(ctx, harness, opts) {
|
|
|
44651
44695
|
return false;
|
|
44652
44696
|
}
|
|
44653
44697
|
}
|
|
44654
|
-
function fireTokenActivity(
|
|
44698
|
+
function fireTokenActivity(onTurnProgress, chatroomId, role, now, lastReportedTokenAt, throttleMs) {
|
|
44655
44699
|
const t = now();
|
|
44656
44700
|
if (lastReportedTokenAt.value === 0 || t - lastReportedTokenAt.value >= throttleMs) {
|
|
44657
44701
|
lastReportedTokenAt.value = t;
|
|
44658
|
-
|
|
44659
|
-
sessionId,
|
|
44660
|
-
chatroomId,
|
|
44661
|
-
role
|
|
44662
|
-
}).catch(() => {});
|
|
44702
|
+
onTurnProgress({ chatroomId, role });
|
|
44663
44703
|
}
|
|
44664
44704
|
}
|
|
44665
44705
|
function wireTokenActivityReporting(opts) {
|
|
44666
44706
|
if (!isTeamAgentRole(opts.role))
|
|
44667
44707
|
return;
|
|
44708
|
+
const onTurnProgress = opts.onTurnProgress;
|
|
44709
|
+
if (!onTurnProgress)
|
|
44710
|
+
return;
|
|
44668
44711
|
if (opts.activityEmitter) {
|
|
44669
44712
|
opts.activityEmitter.onActivity((signal) => {
|
|
44670
44713
|
if (signal.kind !== "progress" || !signal.isFirstForTurn)
|
|
44671
44714
|
return;
|
|
44672
|
-
opts.
|
|
44673
|
-
sessionId: opts.sessionId,
|
|
44674
|
-
chatroomId: opts.chatroomId,
|
|
44675
|
-
role: opts.role
|
|
44676
|
-
}).catch(() => {});
|
|
44715
|
+
onTurnProgress({ chatroomId: opts.chatroomId, role: opts.role });
|
|
44677
44716
|
});
|
|
44678
44717
|
return;
|
|
44679
44718
|
}
|
|
@@ -44684,13 +44723,12 @@ function wireTokenActivityReporting(opts) {
|
|
|
44684
44723
|
if (!register)
|
|
44685
44724
|
return;
|
|
44686
44725
|
register(() => {
|
|
44687
|
-
fireTokenActivity(
|
|
44726
|
+
fireTokenActivity(onTurnProgress, opts.chatroomId, opts.role, now, lastReportedTokenAt, throttleMs);
|
|
44688
44727
|
});
|
|
44689
44728
|
}
|
|
44690
44729
|
var NATIVE_TOKEN_ACTIVITY_THROTTLE_MS = 30000;
|
|
44691
44730
|
var init_native_spawn_presence = __esm(() => {
|
|
44692
44731
|
init_types();
|
|
44693
|
-
init_api3();
|
|
44694
44732
|
init_agent_lifecycle_fact();
|
|
44695
44733
|
init_execution_kind();
|
|
44696
44734
|
});
|
|
@@ -44713,6 +44751,7 @@ class AgentProcessManager {
|
|
|
44713
44751
|
exitRetryQueue = [];
|
|
44714
44752
|
exitRetryTimer = null;
|
|
44715
44753
|
agentTurnEndedHandlers = new Set;
|
|
44754
|
+
agentTurnProgressHandlers = new Set;
|
|
44716
44755
|
agentTurnEndedSequence = 0;
|
|
44717
44756
|
agentStartedHandlers = new Set;
|
|
44718
44757
|
agentSessionLostHandlers = new Set;
|
|
@@ -44800,6 +44839,19 @@ class AgentProcessManager {
|
|
|
44800
44839
|
this.agentSessionLostHandlers.add(handler);
|
|
44801
44840
|
return () => this.agentSessionLostHandlers.delete(handler);
|
|
44802
44841
|
}
|
|
44842
|
+
subscribeAgentTurnProgress(handler) {
|
|
44843
|
+
this.agentTurnProgressHandlers.add(handler);
|
|
44844
|
+
return () => this.agentTurnProgressHandlers.delete(handler);
|
|
44845
|
+
}
|
|
44846
|
+
emitAgentTurnProgress(event) {
|
|
44847
|
+
for (const handler of this.agentTurnProgressHandlers) {
|
|
44848
|
+
try {
|
|
44849
|
+
handler(event);
|
|
44850
|
+
} catch (error51) {
|
|
44851
|
+
console.warn(`[AgentProcessManager] turn-progress handler failed for ${event.role}@${event.chatroomId}: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
44852
|
+
}
|
|
44853
|
+
}
|
|
44854
|
+
}
|
|
44803
44855
|
clearSlotRuntimeState(slot) {
|
|
44804
44856
|
slot.state = AGENT_SLOT_STATE.IDLE;
|
|
44805
44857
|
slot.pid = undefined;
|
|
@@ -45373,7 +45425,7 @@ class AgentProcessManager {
|
|
|
45373
45425
|
slot.state = AGENT_SLOT_STATE.STOPPING;
|
|
45374
45426
|
const stopGeneration = this.bumpStopGeneration(slot);
|
|
45375
45427
|
slot.stoppingSince = this.deps.clock.now();
|
|
45376
|
-
await this.doStop(key, slot, pid, { chatroomId, role, reason:
|
|
45428
|
+
await this.doStop(key, slot, pid, { chatroomId, role, reason: DaemonStartReasonCode.RESPAWN, workingDir }, stopGeneration);
|
|
45377
45429
|
}
|
|
45378
45430
|
}
|
|
45379
45431
|
async killPersistedProcessIfAlive(chatroomId, role, workingDir) {
|
|
@@ -45719,13 +45771,12 @@ class AgentProcessManager {
|
|
|
45719
45771
|
});
|
|
45720
45772
|
}
|
|
45721
45773
|
wireTokenActivityReporting({
|
|
45722
|
-
backend: this.deps.backend,
|
|
45723
|
-
sessionId: this.deps.sessionId,
|
|
45724
45774
|
chatroomId: opts.chatroomId,
|
|
45725
45775
|
role: opts.role,
|
|
45726
45776
|
spawnResult,
|
|
45727
45777
|
now: () => this.deps.clock.now(),
|
|
45728
|
-
activityEmitter: spawnResult.activityEmitter
|
|
45778
|
+
activityEmitter: spawnResult.activityEmitter,
|
|
45779
|
+
onTurnProgress: (event) => this.emitAgentTurnProgress(event)
|
|
45729
45780
|
});
|
|
45730
45781
|
}
|
|
45731
45782
|
async finalizeRunningSlot(key, slot, opts, spawnResult, wantResume) {
|
|
@@ -45742,7 +45793,7 @@ class AgentProcessManager {
|
|
|
45742
45793
|
await this.emitNativeWaiting(opts.chatroomId, opts.role, opts.agentHarness);
|
|
45743
45794
|
if (getHarnessCapabilities(opts.agentHarness).supportsNativeIntegration) {
|
|
45744
45795
|
for (const handler of this.agentStartedHandlers) {
|
|
45745
|
-
handler({ chatroomId: opts.chatroomId, role: opts.role }).catch((error51) => {
|
|
45796
|
+
handler({ chatroomId: opts.chatroomId, role: opts.role, reason: opts.reason }).catch((error51) => {
|
|
45746
45797
|
console.warn(`[AgentProcessManager] native delivery after start failed for ${opts.role}@${opts.chatroomId}: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
45747
45798
|
});
|
|
45748
45799
|
}
|
|
@@ -45763,6 +45814,9 @@ class AgentProcessManager {
|
|
|
45763
45814
|
}
|
|
45764
45815
|
async doEnsureRunning(key, slot, opts) {
|
|
45765
45816
|
slot.state = AGENT_SLOT_STATE.SPAWNING;
|
|
45817
|
+
const rateLimit = this.checkRateLimitGate(opts, slot);
|
|
45818
|
+
if (rateLimit)
|
|
45819
|
+
return rateLimit;
|
|
45766
45820
|
const authorization = await this.deps.backend.mutation(api.machines.authorizeAgentStart, {
|
|
45767
45821
|
sessionId: this.deps.sessionId,
|
|
45768
45822
|
machineId: this.deps.machineId,
|
|
@@ -45777,9 +45831,6 @@ class AgentProcessManager {
|
|
|
45777
45831
|
const wantResume = opts.wantResume;
|
|
45778
45832
|
console.log(`[AgentProcessManager] harness start: role=${opts.role} harness=${opts.agentHarness} wantResume=${wantResume} reason=${opts.reason}`);
|
|
45779
45833
|
try {
|
|
45780
|
-
const rateLimit = this.checkRateLimitGate(opts, slot);
|
|
45781
|
-
if (rateLimit)
|
|
45782
|
-
return rateLimit;
|
|
45783
45834
|
const workingDir = await this.validateWorkingDirGate(opts, slot);
|
|
45784
45835
|
if (workingDir)
|
|
45785
45836
|
return workingDir;
|
|
@@ -46193,7 +46244,7 @@ async function ensureColdSessionBeforeNativeInject(task, deps) {
|
|
|
46193
46244
|
agentHarness,
|
|
46194
46245
|
model,
|
|
46195
46246
|
workingDir,
|
|
46196
|
-
reason:
|
|
46247
|
+
reason: AgentStartReasonCode.PLATFORM_TASK_START_IN_NEW_SESSION,
|
|
46197
46248
|
wantResume: false
|
|
46198
46249
|
}, context5.signal);
|
|
46199
46250
|
return waitForHarnessSessionId(deps.agentMgr, chatroomId, role, context5.signal);
|
|
@@ -46941,6 +46992,8 @@ function createConvexNativeTaskDeliveryGateway(backend2) {
|
|
|
46941
46992
|
deliveryKind: "native_inject"
|
|
46942
46993
|
});
|
|
46943
46994
|
},
|
|
46995
|
+
readTask: async (args2) => await backend2.mutation(api.tasks.readTask, args2),
|
|
46996
|
+
markReceiptStarted: async (args2) => await backend2.mutation(api.taskDeliveryReceipts.markStarted, args2),
|
|
46944
46997
|
joinWaitingParticipant: async (args2) => {
|
|
46945
46998
|
await backend2.mutation(api.participants.join, {
|
|
46946
46999
|
...args2,
|
|
@@ -46987,6 +47040,7 @@ var init_convex_native_task_delivery_gateway = __esm(() => {
|
|
|
46987
47040
|
// src/daemon/services/task-service/service/task-service.ts
|
|
46988
47041
|
function createTaskService(deps) {
|
|
46989
47042
|
const gateway = createConvexNativeTaskDeliveryGateway(deps.backend);
|
|
47043
|
+
const handoffRepository = deps.handoffRepository;
|
|
46990
47044
|
const taskInboxState = new TaskInboxState;
|
|
46991
47045
|
const listeners = new Set;
|
|
46992
47046
|
let stopInboxWatch;
|
|
@@ -46996,6 +47050,120 @@ function createTaskService(deps) {
|
|
|
46996
47050
|
const scheduledEventIds = new Set;
|
|
46997
47051
|
const deliveredEventIds = new Set;
|
|
46998
47052
|
const taskChains = new Map;
|
|
47053
|
+
const maxBootstrapSweepFailures = 3;
|
|
47054
|
+
let bootstrapSweepPending = true;
|
|
47055
|
+
let bootstrapSweepFailures = 0;
|
|
47056
|
+
let bootstrapSweepInFlight = false;
|
|
47057
|
+
let bootstrapSweepPromise;
|
|
47058
|
+
const REDIVERY_ATTEMPT_CAP = 3;
|
|
47059
|
+
const turnEndAttemptCounts = new Map;
|
|
47060
|
+
const redeliveryExhaustedKeys = new Set;
|
|
47061
|
+
const redeliveryKey = (chatroomId, role, taskId) => `${chatroomId}:${role.toLowerCase()}:${taskId}`;
|
|
47062
|
+
const recordUncoveredTurnEnd = async (args2) => {
|
|
47063
|
+
const key = redeliveryKey(args2.chatroomId, args2.role, args2.taskId);
|
|
47064
|
+
if (redeliveryExhaustedKeys.has(key))
|
|
47065
|
+
return { exceeded: true };
|
|
47066
|
+
const attempts = (turnEndAttemptCounts.get(key) ?? 0) + 1;
|
|
47067
|
+
turnEndAttemptCounts.set(key, attempts);
|
|
47068
|
+
if (attempts < REDIVERY_ATTEMPT_CAP)
|
|
47069
|
+
return { exceeded: false };
|
|
47070
|
+
redeliveryExhaustedKeys.add(key);
|
|
47071
|
+
try {
|
|
47072
|
+
await gateway.recordDeliveryFailure({
|
|
47073
|
+
sessionId: deps.sessionId,
|
|
47074
|
+
machineId: deps.machineId,
|
|
47075
|
+
taskId: args2.taskId,
|
|
47076
|
+
reason: "redelivery_exhausted"
|
|
47077
|
+
});
|
|
47078
|
+
} catch (error51) {
|
|
47079
|
+
console.warn(`[TaskService] redelivery-exhausted failure record failed chatroom=${args2.chatroomId} role=${args2.role} task=${args2.taskId}: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
47080
|
+
}
|
|
47081
|
+
console.log(`[NativeDelivery:redelivery-exhausted] chatroom=${args2.chatroomId} role=${args2.role} task=${args2.taskId} attempts=${attempts} — release/redelivery stopped; agent restart (user.start) resets`);
|
|
47082
|
+
return { exceeded: true };
|
|
47083
|
+
};
|
|
47084
|
+
const isRedeliveryExhausted = (args2) => redeliveryExhaustedKeys.has(redeliveryKey(args2.chatroomId, args2.role, args2.taskId));
|
|
47085
|
+
const clearRedeliveryTrackingForTask = (chatroomId, role, taskId) => {
|
|
47086
|
+
const key = redeliveryKey(chatroomId, role, taskId);
|
|
47087
|
+
turnEndAttemptCounts.delete(key);
|
|
47088
|
+
redeliveryExhaustedKeys.delete(key);
|
|
47089
|
+
};
|
|
47090
|
+
const sweepUncoveredInProgressTasks = async () => {
|
|
47091
|
+
let released = 0;
|
|
47092
|
+
let failures3 = 0;
|
|
47093
|
+
for (const task of taskInboxState.listAll()) {
|
|
47094
|
+
if (task.status !== "in_progress")
|
|
47095
|
+
continue;
|
|
47096
|
+
try {
|
|
47097
|
+
const handoff = await handoffRepository.getLatest(task.chatroomId, task.agentConfig.role);
|
|
47098
|
+
if (handoff?.taskIds.includes(task.taskId))
|
|
47099
|
+
continue;
|
|
47100
|
+
const result = await gateway.releaseTaskAfterTurnFailure({
|
|
47101
|
+
sessionId: deps.sessionId,
|
|
47102
|
+
chatroomId: task.chatroomId,
|
|
47103
|
+
role: task.agentConfig.role,
|
|
47104
|
+
taskId: task.taskId
|
|
47105
|
+
});
|
|
47106
|
+
taskInboxState.markStatus(task.chatroomId, task.agentConfig.role, task.taskId, result.status, result.updatedAt);
|
|
47107
|
+
released += 1;
|
|
47108
|
+
} catch (error51) {
|
|
47109
|
+
failures3 += 1;
|
|
47110
|
+
console.warn(`[TaskService] bootstrap task release failed chatroom=${task.chatroomId} task=${task.taskId}: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
47111
|
+
}
|
|
47112
|
+
}
|
|
47113
|
+
if (failures3 > 0)
|
|
47114
|
+
throw new Error(`${failures3} bootstrap task release(s) failed`);
|
|
47115
|
+
return released;
|
|
47116
|
+
};
|
|
47117
|
+
const releaseTask = async (args2) => {
|
|
47118
|
+
const result = await gateway.releaseTaskAfterTurnFailure({
|
|
47119
|
+
sessionId: deps.sessionId,
|
|
47120
|
+
chatroomId: args2.chatroomId,
|
|
47121
|
+
role: args2.role,
|
|
47122
|
+
taskId: args2.taskId
|
|
47123
|
+
});
|
|
47124
|
+
taskInboxState.markStatus(args2.chatroomId, args2.role, args2.taskId, result.status, result.updatedAt);
|
|
47125
|
+
const currentTask = taskInboxState.getForRole(args2.chatroomId, args2.role, args2.taskId);
|
|
47126
|
+
if (currentTask?.status === "pending") {
|
|
47127
|
+
pendingTaskReconciliationWatcher.watch(currentTask);
|
|
47128
|
+
} else {
|
|
47129
|
+
pendingTaskReconciliationWatcher.clear(args2.chatroomId, args2.role, args2.taskId);
|
|
47130
|
+
}
|
|
47131
|
+
return result;
|
|
47132
|
+
};
|
|
47133
|
+
const clearRoleRedeliveryTracking = (chatroomId, role) => {
|
|
47134
|
+
const prefix = `${chatroomId}:${role.toLowerCase()}:`;
|
|
47135
|
+
for (const key of [...turnEndAttemptCounts.keys()]) {
|
|
47136
|
+
if (key.startsWith(prefix))
|
|
47137
|
+
turnEndAttemptCounts.delete(key);
|
|
47138
|
+
}
|
|
47139
|
+
for (const key of [...redeliveryExhaustedKeys]) {
|
|
47140
|
+
if (key.startsWith(prefix))
|
|
47141
|
+
redeliveryExhaustedKeys.delete(key);
|
|
47142
|
+
}
|
|
47143
|
+
};
|
|
47144
|
+
const runBootstrapSweep = () => {
|
|
47145
|
+
if (!bootstrapSweepPending)
|
|
47146
|
+
return Promise.resolve();
|
|
47147
|
+
if (bootstrapSweepInFlight)
|
|
47148
|
+
return bootstrapSweepPromise ?? Promise.resolve();
|
|
47149
|
+
bootstrapSweepInFlight = true;
|
|
47150
|
+
bootstrapSweepPromise = sweepUncoveredInProgressTasks().then(() => {
|
|
47151
|
+
bootstrapSweepPending = false;
|
|
47152
|
+
bootstrapSweepFailures = 0;
|
|
47153
|
+
}).catch((error51) => {
|
|
47154
|
+
bootstrapSweepFailures += 1;
|
|
47155
|
+
if (bootstrapSweepFailures >= maxBootstrapSweepFailures) {
|
|
47156
|
+
bootstrapSweepPending = false;
|
|
47157
|
+
console.warn("[TaskService] bootstrap sweep giving up after 3 failed attempts");
|
|
47158
|
+
} else {
|
|
47159
|
+
console.warn(`[TaskService] bootstrap sweep failed (attempt ${bootstrapSweepFailures}/3): ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
47160
|
+
}
|
|
47161
|
+
}).finally(() => {
|
|
47162
|
+
bootstrapSweepInFlight = false;
|
|
47163
|
+
bootstrapSweepPromise = undefined;
|
|
47164
|
+
});
|
|
47165
|
+
return bootstrapSweepPromise;
|
|
47166
|
+
};
|
|
46999
47167
|
const notifyForDelivery = async (notification) => {
|
|
47000
47168
|
const results = await Promise.all([...listeners].map((listener) => Promise.resolve(listener(notification))));
|
|
47001
47169
|
return {
|
|
@@ -47009,8 +47177,12 @@ function createTaskService(deps) {
|
|
|
47009
47177
|
const applyInboxEvent = (event) => {
|
|
47010
47178
|
if (event.eventType === "task_deleted" /* TaskDeleted */ || event.task.status === "completed") {
|
|
47011
47179
|
taskInboxState.remove(event.chatroomId, event.role, event.taskId, event.task.updatedAt);
|
|
47180
|
+
clearRedeliveryTrackingForTask(event.chatroomId, event.role, event.taskId);
|
|
47012
47181
|
return "handled";
|
|
47013
47182
|
}
|
|
47183
|
+
if (event.eventType === "task_assigned" /* TaskAssigned */) {
|
|
47184
|
+
clearRedeliveryTrackingForTask(event.chatroomId, event.role, event.taskId);
|
|
47185
|
+
}
|
|
47014
47186
|
return taskInboxState.upsert([
|
|
47015
47187
|
{
|
|
47016
47188
|
taskId: event.task.taskId,
|
|
@@ -47119,6 +47291,7 @@ function createTaskService(deps) {
|
|
|
47119
47291
|
});
|
|
47120
47292
|
const reconcileTaskStatuses = (tasks) => {
|
|
47121
47293
|
taskInboxState.reconcileStatuses(tasks);
|
|
47294
|
+
runBootstrapSweep();
|
|
47122
47295
|
for (const task of tasks) {
|
|
47123
47296
|
if (task.status === "pending" || task.status === "acknowledged") {
|
|
47124
47297
|
pendingTaskReconciliationWatcher.watch(task);
|
|
@@ -47158,7 +47331,9 @@ function createTaskService(deps) {
|
|
|
47158
47331
|
machineId: deps.machineId
|
|
47159
47332
|
});
|
|
47160
47333
|
reconcileTaskStatuses(statusTasks);
|
|
47334
|
+
await runBootstrapSweep();
|
|
47161
47335
|
} catch (error51) {
|
|
47336
|
+
bootstrapSweepPending = true;
|
|
47162
47337
|
console.warn("[TaskService] task-status bootstrap failed:", error51);
|
|
47163
47338
|
}
|
|
47164
47339
|
if (wsClient2 && !stopInboxWatch) {
|
|
@@ -47193,26 +47368,47 @@ function createTaskService(deps) {
|
|
|
47193
47368
|
acknowledgementRetryWatcher.stop();
|
|
47194
47369
|
pendingTaskReconciliationWatcher.stop();
|
|
47195
47370
|
taskChains.clear();
|
|
47371
|
+
handoffRepository.close();
|
|
47196
47372
|
},
|
|
47197
47373
|
listTasksForRole: (chatroomId, role) => taskInboxState.listForRole(chatroomId, role),
|
|
47198
47374
|
listAllTasks: () => taskInboxState.listAll(),
|
|
47199
47375
|
debugState: (chatroomId) => buildTaskServiceDebugState({ taskInboxState, chatroomId }),
|
|
47200
47376
|
taskInboxState,
|
|
47201
|
-
|
|
47202
|
-
|
|
47203
|
-
|
|
47204
|
-
|
|
47205
|
-
|
|
47206
|
-
|
|
47207
|
-
|
|
47208
|
-
taskInboxState.
|
|
47209
|
-
|
|
47210
|
-
|
|
47211
|
-
|
|
47212
|
-
|
|
47213
|
-
|
|
47377
|
+
recordHandoffOutcome: async ({
|
|
47378
|
+
chatroomId,
|
|
47379
|
+
role,
|
|
47380
|
+
targetRole,
|
|
47381
|
+
nextTask,
|
|
47382
|
+
taskIds: providedTaskIds
|
|
47383
|
+
}) => {
|
|
47384
|
+
const taskIds = providedTaskIds ?? taskInboxState.listForRole(chatroomId, role).filter((task) => task.status === "acknowledged" || task.status === "in_progress").map((task) => task.taskId);
|
|
47385
|
+
await handoffRepository.record({
|
|
47386
|
+
chatroomId,
|
|
47387
|
+
role,
|
|
47388
|
+
taskIds,
|
|
47389
|
+
...nextTask?.taskId ? { nextTaskId: nextTask.taskId } : {},
|
|
47390
|
+
targetRole,
|
|
47391
|
+
handedOffAt: Date.now()
|
|
47392
|
+
});
|
|
47393
|
+
const now = Date.now();
|
|
47394
|
+
for (const taskId of taskIds)
|
|
47395
|
+
taskInboxState.remove(chatroomId, role, taskId, now);
|
|
47396
|
+
if (nextTask)
|
|
47397
|
+
taskInboxState.upsert([nextTask]);
|
|
47398
|
+
},
|
|
47399
|
+
getLatestHandoff: (chatroomId, role) => handoffRepository.getLatest(chatroomId, role),
|
|
47400
|
+
sweepUncoveredInProgressTasks,
|
|
47401
|
+
releaseTaskAfterTurnFailure: (args2) => releaseTask(args2),
|
|
47402
|
+
handleAgentRestart: async ({ chatroomId, role }) => {
|
|
47403
|
+
clearRoleRedeliveryTracking(chatroomId, role);
|
|
47404
|
+
const inFlightTasks = taskInboxState.listForRole(chatroomId, role).filter((task) => task.status === "acknowledged" || task.status === "in_progress");
|
|
47405
|
+
for (const task of inFlightTasks) {
|
|
47406
|
+
try {
|
|
47407
|
+
await releaseTask({ chatroomId, role, taskId: task.taskId });
|
|
47408
|
+
} catch (error51) {
|
|
47409
|
+
console.warn(`[TaskService] agent-restart release failed chatroom=${chatroomId} role=${role} task=${task.taskId}: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
47410
|
+
}
|
|
47214
47411
|
}
|
|
47215
|
-
return result;
|
|
47216
47412
|
},
|
|
47217
47413
|
loadAssignedTaskForAction: async ({ chatroomId, role, taskId }) => {
|
|
47218
47414
|
const task = await gateway.loadAssignedTaskForAction({
|
|
@@ -47223,6 +47419,27 @@ function createTaskService(deps) {
|
|
|
47223
47419
|
});
|
|
47224
47420
|
return task?.chatroomId === chatroomId ? task : null;
|
|
47225
47421
|
},
|
|
47422
|
+
handleAgentTurnProgress: async ({ chatroomId, role, taskId }) => {
|
|
47423
|
+
const task = taskInboxState.getForRole(chatroomId, role, taskId);
|
|
47424
|
+
if (!task)
|
|
47425
|
+
return;
|
|
47426
|
+
if (task.status !== "acknowledged" && task.status !== "in_progress")
|
|
47427
|
+
return;
|
|
47428
|
+
if (task.status === "acknowledged") {
|
|
47429
|
+
try {
|
|
47430
|
+
await gateway.readTask({ sessionId: deps.sessionId, chatroomId, role, taskId });
|
|
47431
|
+
taskInboxState.markStatus(chatroomId, role, taskId, "in_progress", Date.now());
|
|
47432
|
+
} catch (error51) {
|
|
47433
|
+
console.warn(`[TaskService] turn-progress read failed chatroom=${chatroomId} role=${role} task=${taskId}: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
47434
|
+
return;
|
|
47435
|
+
}
|
|
47436
|
+
}
|
|
47437
|
+
try {
|
|
47438
|
+
await gateway.markReceiptStarted({ sessionId: deps.sessionId, chatroomId, role, taskId });
|
|
47439
|
+
} catch (error51) {
|
|
47440
|
+
console.warn(`[TaskService] turn-progress receipt mark failed chatroom=${chatroomId} role=${role} task=${taskId}: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
47441
|
+
}
|
|
47442
|
+
},
|
|
47226
47443
|
recordDeliveryFailure: ({ taskId, reason }) => gateway.recordDeliveryFailure({
|
|
47227
47444
|
sessionId: deps.sessionId,
|
|
47228
47445
|
machineId: deps.machineId,
|
|
@@ -47234,7 +47451,12 @@ function createTaskService(deps) {
|
|
|
47234
47451
|
machineId: deps.machineId,
|
|
47235
47452
|
taskId,
|
|
47236
47453
|
...expectedReason ? { expectedReason } : {}
|
|
47237
|
-
})
|
|
47454
|
+
}),
|
|
47455
|
+
recordUncoveredTurnEnd,
|
|
47456
|
+
isRedeliveryExhausted,
|
|
47457
|
+
clearRedeliveryTracking: ({ chatroomId, role }) => {
|
|
47458
|
+
clearRoleRedeliveryTracking(chatroomId, role);
|
|
47459
|
+
}
|
|
47238
47460
|
};
|
|
47239
47461
|
return service4;
|
|
47240
47462
|
}
|
|
@@ -47247,6 +47469,63 @@ var init_task_service = __esm(() => {
|
|
|
47247
47469
|
init_convex_native_task_delivery_gateway();
|
|
47248
47470
|
});
|
|
47249
47471
|
|
|
47472
|
+
// src/daemon/services/task-service/infrastructure/repository/task-handoff-repository.ts
|
|
47473
|
+
import { mkdirSync as mkdirSync2 } from "node:fs";
|
|
47474
|
+
import { dirname as dirname2 } from "node:path";
|
|
47475
|
+
import { DatabaseSync } from "node:sqlite";
|
|
47476
|
+
function normalizeRole(role) {
|
|
47477
|
+
return role.toLowerCase();
|
|
47478
|
+
}
|
|
47479
|
+
function mapRow(row) {
|
|
47480
|
+
const taskIds = JSON.parse(row.task_ids_json);
|
|
47481
|
+
if (!Array.isArray(taskIds) || !taskIds.every((taskId) => typeof taskId === "string")) {
|
|
47482
|
+
throw new Error("Invalid task handoff task_ids_json");
|
|
47483
|
+
}
|
|
47484
|
+
return {
|
|
47485
|
+
chatroomId: row.chatroom_id,
|
|
47486
|
+
role: row.role,
|
|
47487
|
+
taskIds,
|
|
47488
|
+
...row.next_task_id ? { nextTaskId: row.next_task_id } : {},
|
|
47489
|
+
targetRole: row.target_role,
|
|
47490
|
+
handedOffAt: row.handed_off_at
|
|
47491
|
+
};
|
|
47492
|
+
}
|
|
47493
|
+
function createTaskHandoffRepository(dbPath) {
|
|
47494
|
+
mkdirSync2(dirname2(dbPath), { recursive: true });
|
|
47495
|
+
const db = new DatabaseSync(dbPath);
|
|
47496
|
+
db.exec(`
|
|
47497
|
+
CREATE TABLE IF NOT EXISTS task_handoffs (
|
|
47498
|
+
chatroom_id TEXT NOT NULL,
|
|
47499
|
+
role TEXT NOT NULL,
|
|
47500
|
+
task_ids_json TEXT NOT NULL,
|
|
47501
|
+
next_task_id TEXT,
|
|
47502
|
+
target_role TEXT NOT NULL,
|
|
47503
|
+
handed_off_at INTEGER NOT NULL,
|
|
47504
|
+
PRIMARY KEY (chatroom_id, role)
|
|
47505
|
+
)
|
|
47506
|
+
`);
|
|
47507
|
+
return {
|
|
47508
|
+
async record(record2) {
|
|
47509
|
+
db.prepare(`INSERT INTO task_handoffs
|
|
47510
|
+
(chatroom_id, role, task_ids_json, next_task_id, target_role, handed_off_at)
|
|
47511
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
47512
|
+
ON CONFLICT(chatroom_id, role) DO UPDATE SET
|
|
47513
|
+
task_ids_json = excluded.task_ids_json,
|
|
47514
|
+
next_task_id = excluded.next_task_id,
|
|
47515
|
+
target_role = excluded.target_role,
|
|
47516
|
+
handed_off_at = excluded.handed_off_at`).run(record2.chatroomId, normalizeRole(record2.role), JSON.stringify(record2.taskIds), record2.nextTaskId ?? null, record2.targetRole, record2.handedOffAt);
|
|
47517
|
+
},
|
|
47518
|
+
async getLatest(chatroomId, role) {
|
|
47519
|
+
const row = db.prepare("SELECT chatroom_id, role, task_ids_json, next_task_id, target_role, handed_off_at FROM task_handoffs WHERE chatroom_id = ? AND role = ?").get(chatroomId, normalizeRole(role));
|
|
47520
|
+
return row ? mapRow(row) : null;
|
|
47521
|
+
},
|
|
47522
|
+
close() {
|
|
47523
|
+
db.close();
|
|
47524
|
+
}
|
|
47525
|
+
};
|
|
47526
|
+
}
|
|
47527
|
+
var init_task_handoff_repository = () => {};
|
|
47528
|
+
|
|
47250
47529
|
// src/daemon/services/task-service/infrastructure/adapters/daemon-audit-port.ts
|
|
47251
47530
|
function createDaemonAuditPort(logEvent) {
|
|
47252
47531
|
return { emit: (event) => logDaemonAuditEvent(logEvent, event) };
|
|
@@ -47279,6 +47558,9 @@ function decideNextDelivery(tasks, context5) {
|
|
|
47279
47558
|
if (!context5.isNativeHarness(context5.agentConfig.agentHarness)) {
|
|
47280
47559
|
return { kind: "failed", taskId: task.taskId, reason: "unsupported_harness" };
|
|
47281
47560
|
}
|
|
47561
|
+
if (context5.isRedeliveryExhausted(task.taskId)) {
|
|
47562
|
+
return { kind: "deduplicated", reason: "redelivery_exhausted", taskId: task.taskId };
|
|
47563
|
+
}
|
|
47282
47564
|
const blockReason = context5.explainNativeDeliveryBlock(task);
|
|
47283
47565
|
if (blockReason === "acknowledged_wrong_role") {
|
|
47284
47566
|
return { kind: "failed", taskId: task.taskId, reason: "assigned_elsewhere" };
|
|
@@ -47394,7 +47676,8 @@ class NativeTaskDeliveryCoordinator {
|
|
|
47394
47676
|
agentConfig,
|
|
47395
47677
|
configState,
|
|
47396
47678
|
isNativeHarness: taskService.isNativeHarness,
|
|
47397
|
-
explainNativeDeliveryBlock: taskService.explainNativeDeliveryBlock
|
|
47679
|
+
explainNativeDeliveryBlock: taskService.explainNativeDeliveryBlock,
|
|
47680
|
+
isRedeliveryExhausted: (taskId) => taskService.isRedeliveryExhausted({ chatroomId: firstTask.chatroomId, role, taskId })
|
|
47398
47681
|
});
|
|
47399
47682
|
const attemptId = `${Date.now()}-${firstTask.taskId}`;
|
|
47400
47683
|
const decisionReason = "reason" in decision ? decision.reason : undefined;
|
|
@@ -47465,6 +47748,7 @@ var init_task_service2 = __esm(() => {
|
|
|
47465
47748
|
init_native_task_injector_logic();
|
|
47466
47749
|
init_task_service();
|
|
47467
47750
|
init_convex_native_task_delivery_gateway();
|
|
47751
|
+
init_task_handoff_repository();
|
|
47468
47752
|
init_daemon_audit_port();
|
|
47469
47753
|
init_native_task_delivery_coordinator();
|
|
47470
47754
|
});
|
|
@@ -47485,7 +47769,7 @@ async function processTasksUpdate(taskService, configurationService, pass, isTas
|
|
|
47485
47769
|
agentHarness: agentConfig.agentHarness,
|
|
47486
47770
|
model: agentConfig.model ?? "",
|
|
47487
47771
|
workingDir: agentConfig.workingDir,
|
|
47488
|
-
reason:
|
|
47772
|
+
reason: AgentStartReasonCode.PLATFORM_PENDING_TASK_WAKE,
|
|
47489
47773
|
wantResume: false,
|
|
47490
47774
|
taskId: task.taskId
|
|
47491
47775
|
};
|
|
@@ -47567,6 +47851,7 @@ class AgentWorkManager {
|
|
|
47567
47851
|
unsubscribeAgentTurnEnded;
|
|
47568
47852
|
unsubscribeAgentStarted;
|
|
47569
47853
|
unsubscribeAgentSessionLost;
|
|
47854
|
+
unsubscribeAgentTurnProgress;
|
|
47570
47855
|
reconcileStates = new Map;
|
|
47571
47856
|
unsubscribeTaskService;
|
|
47572
47857
|
nativeTaskDeliveryQueue;
|
|
@@ -47599,16 +47884,33 @@ class AgentWorkManager {
|
|
|
47599
47884
|
releaseTaskAfterTurnFailure: deps.taskService.releaseTaskAfterTurnFailure,
|
|
47600
47885
|
recordDeliveryFailure: deps.taskService.recordDeliveryFailure,
|
|
47601
47886
|
clearDeliveryFailure: deps.taskService.clearDeliveryFailure,
|
|
47887
|
+
recordUncoveredTurnEnd: deps.taskService.recordUncoveredTurnEnd,
|
|
47888
|
+
isRedeliveryExhausted: deps.taskService.isRedeliveryExhausted,
|
|
47889
|
+
clearRedeliveryTracking: deps.taskService.clearRedeliveryTracking,
|
|
47602
47890
|
loadAssignedTaskForAction: deps.taskService.loadAssignedTaskForAction,
|
|
47603
47891
|
deliverNativeTask: (task, harnessSessionId, onTaskDelivered) => this.nativeTaskDeliveryQueue.enqueue({ task, harnessSessionId, onTaskDelivered })
|
|
47604
47892
|
};
|
|
47605
47893
|
this.unsubscribeAgentTurnEnded = deps.agentMgr.subscribeAgentTurnEnded((event) => this.handleAgentTurnEnded(event));
|
|
47606
47894
|
this.unsubscribeAgentStarted = deps.agentMgr.subscribeAgentStarted((event) => this.handleAgentStarted(event));
|
|
47607
47895
|
this.unsubscribeAgentSessionLost = deps.agentMgr.subscribeAgentSessionLost((event) => this.handleAgentSessionLost(event));
|
|
47896
|
+
this.unsubscribeAgentTurnProgress = deps.agentMgr.subscribeAgentTurnProgress((event) => {
|
|
47897
|
+
const activeTask = this.deps.agentTaskState.get(event);
|
|
47898
|
+
if (!activeTask)
|
|
47899
|
+
return;
|
|
47900
|
+
this.deps.taskService.handleAgentTurnProgress({ ...event, taskId: activeTask.taskId }).catch((error51) => {
|
|
47901
|
+
console.warn(`[AgentProcessManager] turn-progress handling failed for ${event.role}@${event.chatroomId}: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
47902
|
+
});
|
|
47903
|
+
});
|
|
47608
47904
|
this.unsubscribeTaskService = deps.taskService.subscribe((notification) => this.handleTaskServiceNotification(notification));
|
|
47609
47905
|
}
|
|
47610
47906
|
async handleAgentStarted(event) {
|
|
47611
47907
|
this.deps.agentTaskState.clear({ chatroomId: event.chatroomId, role: event.role });
|
|
47908
|
+
if (event.reason === "user.start") {
|
|
47909
|
+
this.deps.taskService.clearRedeliveryTracking({
|
|
47910
|
+
chatroomId: event.chatroomId,
|
|
47911
|
+
role: event.role
|
|
47912
|
+
});
|
|
47913
|
+
}
|
|
47612
47914
|
await this.requestReconcile({
|
|
47613
47915
|
chatroomId: event.chatroomId,
|
|
47614
47916
|
role: event.role,
|
|
@@ -47626,24 +47928,43 @@ class AgentWorkManager {
|
|
|
47626
47928
|
console.warn(`[NativeDelivery:failure] role=${event.role} chatroom=${event.chatroomId} operation=session-loss-reconcile error=${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
47627
47929
|
});
|
|
47628
47930
|
}
|
|
47931
|
+
async recoverTaskAfterUncoveredTurnEnd(event, activeTask, phase) {
|
|
47932
|
+
const { chatroomId, role } = event;
|
|
47933
|
+
const { exceeded } = await this.deps.taskService.recordUncoveredTurnEnd({
|
|
47934
|
+
chatroomId,
|
|
47935
|
+
role,
|
|
47936
|
+
taskId: activeTask.taskId
|
|
47937
|
+
});
|
|
47938
|
+
if (exceeded)
|
|
47939
|
+
return "exceeded";
|
|
47940
|
+
try {
|
|
47941
|
+
await this.deps.taskService.releaseTaskAfterTurnFailure({
|
|
47942
|
+
chatroomId,
|
|
47943
|
+
role,
|
|
47944
|
+
taskId: activeTask.taskId
|
|
47945
|
+
});
|
|
47946
|
+
} catch (error51) {
|
|
47947
|
+
console.error(`[NativeDelivery:${phase}-recovery-error] chatroom=${chatroomId} role=${role} task=${activeTask.taskId} turn=${event.completion.turnId} error=${error51 instanceof Error ? error51.stack ?? error51.message : String(error51)}`);
|
|
47948
|
+
return "recovery-failed";
|
|
47949
|
+
}
|
|
47950
|
+
return "released";
|
|
47951
|
+
}
|
|
47629
47952
|
async handleAgentTurnEnded(event) {
|
|
47630
47953
|
const completion = event.completion;
|
|
47631
47954
|
if (completion.status !== "completed") {
|
|
47632
|
-
const
|
|
47955
|
+
const activeTask2 = this.deps.agentTaskState.get({
|
|
47633
47956
|
chatroomId: event.chatroomId,
|
|
47634
47957
|
role: event.role
|
|
47635
47958
|
});
|
|
47636
47959
|
const errorDetail = completion.error;
|
|
47637
|
-
console.error(`[NativeDelivery:turn-failed] chatroom=${event.chatroomId} role=${event.role} task=${
|
|
47638
|
-
if (
|
|
47639
|
-
|
|
47640
|
-
|
|
47641
|
-
|
|
47642
|
-
|
|
47643
|
-
|
|
47644
|
-
|
|
47645
|
-
} catch (error51) {
|
|
47646
|
-
console.error(`[NativeDelivery:turn-failed-recovery-error] chatroom=${event.chatroomId} role=${event.role} task=${activeTask.taskId} turn=${completion.turnId} error=${error51 instanceof Error ? error51.stack ?? error51.message : String(error51)}`);
|
|
47960
|
+
console.error(`[NativeDelivery:turn-failed] chatroom=${event.chatroomId} role=${event.role} task=${activeTask2?.taskId ?? "none"} turn=${completion.turnId} status=${completion.status} source=${completion.source} error=${errorDetail ?? "none"}`);
|
|
47961
|
+
if (activeTask2) {
|
|
47962
|
+
const recovery = await this.recoverTaskAfterUncoveredTurnEnd(event, activeTask2, "turn-failed");
|
|
47963
|
+
if (recovery === "exceeded") {
|
|
47964
|
+
this.deps.agentTaskState.clear({ chatroomId: event.chatroomId, role: event.role });
|
|
47965
|
+
return { kind: "release-slot" };
|
|
47966
|
+
}
|
|
47967
|
+
if (recovery === "recovery-failed") {
|
|
47647
47968
|
return { kind: "hold-slot", reason: "task-recovery-failed" };
|
|
47648
47969
|
}
|
|
47649
47970
|
this.deps.agentTaskState.clear({ chatroomId: event.chatroomId, role: event.role });
|
|
@@ -47652,7 +47973,7 @@ class AgentWorkManager {
|
|
|
47652
47973
|
kind: "turn_failed",
|
|
47653
47974
|
chatroomId: event.chatroomId,
|
|
47654
47975
|
role: event.role,
|
|
47655
|
-
...
|
|
47976
|
+
...activeTask2?.taskId ? { taskId: activeTask2.taskId } : {},
|
|
47656
47977
|
...event.slot.harnessSessionId ? { harnessSessionId: event.slot.harnessSessionId } : {},
|
|
47657
47978
|
turnId: completion.turnId,
|
|
47658
47979
|
status: completion.status,
|
|
@@ -47672,6 +47993,19 @@ class AgentWorkManager {
|
|
|
47672
47993
|
}
|
|
47673
47994
|
return { kind: "release-slot" };
|
|
47674
47995
|
}
|
|
47996
|
+
const activeTask = this.deps.agentTaskState.get({
|
|
47997
|
+
chatroomId: event.chatroomId,
|
|
47998
|
+
role: event.role
|
|
47999
|
+
});
|
|
48000
|
+
if (activeTask) {
|
|
48001
|
+
const handoff = await this.deps.taskService.getLatestHandoff(event.chatroomId, event.role);
|
|
48002
|
+
if (!handoff?.taskIds.includes(activeTask.taskId)) {
|
|
48003
|
+
const recovery = await this.recoverTaskAfterUncoveredTurnEnd(event, activeTask, "turn-ended");
|
|
48004
|
+
if (recovery === "recovery-failed") {
|
|
48005
|
+
return { kind: "hold-slot", reason: "task-recovery-failed" };
|
|
48006
|
+
}
|
|
48007
|
+
}
|
|
48008
|
+
}
|
|
47675
48009
|
this.deps.agentTaskState.clear({ chatroomId: event.chatroomId, role: event.role });
|
|
47676
48010
|
try {
|
|
47677
48011
|
await this.deps.lifecycleOutbox.enqueue(buildAgentStatusFact({
|
|
@@ -47696,6 +48030,7 @@ class AgentWorkManager {
|
|
|
47696
48030
|
this.unsubscribeAgentTurnEnded();
|
|
47697
48031
|
this.unsubscribeAgentStarted();
|
|
47698
48032
|
this.unsubscribeAgentSessionLost();
|
|
48033
|
+
this.unsubscribeAgentTurnProgress();
|
|
47699
48034
|
this.unsubscribeTaskService?.();
|
|
47700
48035
|
this.unsubscribeTaskService = undefined;
|
|
47701
48036
|
this.nativeTaskDeliveryQueue.stop();
|
|
@@ -47809,6 +48144,11 @@ class AgentWorkManager {
|
|
|
47809
48144
|
});
|
|
47810
48145
|
return delivered;
|
|
47811
48146
|
}
|
|
48147
|
+
async handleAgentRestart(args2) {
|
|
48148
|
+
resetRoleDeliveryState(args2.chatroomId, args2.role);
|
|
48149
|
+
this.deps.agentTaskState.clear(args2);
|
|
48150
|
+
await this.deps.taskService.handleAgentRestart(args2);
|
|
48151
|
+
}
|
|
47812
48152
|
async requestReconcileForTasks(tasks, source) {
|
|
47813
48153
|
const roles = new Set(tasks.map((snapshot) => `${snapshot.chatroomId}:${snapshot.agentConfig.role.toLowerCase()}`));
|
|
47814
48154
|
await Promise.all([...roles].map((key) => {
|
|
@@ -47844,6 +48184,7 @@ var init_agent_work_manager = __esm(() => {
|
|
|
47844
48184
|
init_native_task_injector_logic();
|
|
47845
48185
|
init_convex_native_task_delivery_gateway();
|
|
47846
48186
|
init_daemon_audit_port();
|
|
48187
|
+
init_native_task_delivery_coordinator();
|
|
47847
48188
|
init_task_delivery_processor();
|
|
47848
48189
|
init_native_task_injector();
|
|
47849
48190
|
});
|
|
@@ -50852,12 +51193,12 @@ var init_model_provider = () => {};
|
|
|
50852
51193
|
// src/daemon/infrastructure/local/harness/services/cursor-sdk/cursor-sdk-package.ts
|
|
50853
51194
|
import { existsSync as existsSync2, readFileSync as readFileSync4 } from "node:fs";
|
|
50854
51195
|
import { createRequire as createRequire3 } from "node:module";
|
|
50855
|
-
import { dirname as
|
|
51196
|
+
import { dirname as dirname3, join as join8 } from "node:path";
|
|
50856
51197
|
import { fileURLToPath as fileURLToPath2, pathToFileURL } from "node:url";
|
|
50857
51198
|
function resolveChatroomCliRoot(moduleRef = import.meta.url) {
|
|
50858
51199
|
const filePath = moduleRef.startsWith("file:") ? fileURLToPath2(moduleRef) : moduleRef;
|
|
50859
|
-
let dir =
|
|
50860
|
-
while (dir !==
|
|
51200
|
+
let dir = dirname3(filePath);
|
|
51201
|
+
while (dir !== dirname3(dir)) {
|
|
50861
51202
|
const packageJsonPath = join8(dir, "package.json");
|
|
50862
51203
|
if (existsSync2(packageJsonPath)) {
|
|
50863
51204
|
const pkg = JSON.parse(readFileSync4(packageJsonPath, "utf8"));
|
|
@@ -50865,7 +51206,7 @@ function resolveChatroomCliRoot(moduleRef = import.meta.url) {
|
|
|
50865
51206
|
return dir;
|
|
50866
51207
|
}
|
|
50867
51208
|
}
|
|
50868
|
-
dir =
|
|
51209
|
+
dir = dirname3(dir);
|
|
50869
51210
|
}
|
|
50870
51211
|
throw new CursorSdkPackageError(`Could not locate chatroom-cli package root while resolving @cursor/sdk. ${REINSTALL_HINT}`);
|
|
50871
51212
|
}
|
|
@@ -50880,7 +51221,7 @@ function readPinnedSdkVersion(chatroomCliRoot) {
|
|
|
50880
51221
|
return match17[1];
|
|
50881
51222
|
}
|
|
50882
51223
|
function readInstalledSdkVersion(entryPath) {
|
|
50883
|
-
const packageJsonPath = join8(
|
|
51224
|
+
const packageJsonPath = join8(dirname3(entryPath), "..", "..", "package.json");
|
|
50884
51225
|
const pkg = JSON.parse(readFileSync4(packageJsonPath, "utf8"));
|
|
50885
51226
|
return pkg.version;
|
|
50886
51227
|
}
|
|
@@ -51781,12 +52122,12 @@ var init_claude = __esm(() => {
|
|
|
51781
52122
|
// src/daemon/infrastructure/local/harness/services/claude-sdk/claude-sdk-package.ts
|
|
51782
52123
|
import { existsSync as existsSync3, readFileSync as readFileSync5 } from "node:fs";
|
|
51783
52124
|
import { createRequire as createRequire4 } from "node:module";
|
|
51784
|
-
import { dirname as
|
|
52125
|
+
import { dirname as dirname4, join as join9 } from "node:path";
|
|
51785
52126
|
import { fileURLToPath as fileURLToPath3, pathToFileURL as pathToFileURL2 } from "node:url";
|
|
51786
52127
|
function resolveChatroomCliRoot2(moduleRef = import.meta.url) {
|
|
51787
52128
|
const filePath = moduleRef.startsWith("file:") ? fileURLToPath3(moduleRef) : moduleRef;
|
|
51788
|
-
let dir =
|
|
51789
|
-
while (dir !==
|
|
52129
|
+
let dir = dirname4(filePath);
|
|
52130
|
+
while (dir !== dirname4(dir)) {
|
|
51790
52131
|
const packageJsonPath = join9(dir, "package.json");
|
|
51791
52132
|
if (existsSync3(packageJsonPath)) {
|
|
51792
52133
|
const pkg = JSON.parse(readFileSync5(packageJsonPath, "utf8"));
|
|
@@ -51794,7 +52135,7 @@ function resolveChatroomCliRoot2(moduleRef = import.meta.url) {
|
|
|
51794
52135
|
return dir;
|
|
51795
52136
|
}
|
|
51796
52137
|
}
|
|
51797
|
-
dir =
|
|
52138
|
+
dir = dirname4(dir);
|
|
51798
52139
|
}
|
|
51799
52140
|
throw new ClaudeSdkPackageError(`Could not locate chatroom-cli package root while resolving ${CLAUDE_AGENT_SDK_PKG}. ${REINSTALL_HINT2}`);
|
|
51800
52141
|
}
|
|
@@ -51809,7 +52150,7 @@ function readPinnedSdkVersion2(chatroomCliRoot) {
|
|
|
51809
52150
|
return match17[1];
|
|
51810
52151
|
}
|
|
51811
52152
|
function readInstalledSdkVersion2(entryPath) {
|
|
51812
|
-
const packageJsonPath = join9(
|
|
52153
|
+
const packageJsonPath = join9(dirname4(entryPath), "package.json");
|
|
51813
52154
|
const pkg = JSON.parse(readFileSync5(packageJsonPath, "utf8"));
|
|
51814
52155
|
return pkg.version;
|
|
51815
52156
|
}
|
|
@@ -51835,7 +52176,7 @@ function resolveNativeCliBinaryPath(sdkEntryPath) {
|
|
|
51835
52176
|
const binaryName = process.platform === "win32" ? "claude.exe" : "claude";
|
|
51836
52177
|
let pkgDir;
|
|
51837
52178
|
try {
|
|
51838
|
-
pkgDir =
|
|
52179
|
+
pkgDir = dirname4(require3.resolve(`${platformPkg}/package.json`));
|
|
51839
52180
|
} catch {
|
|
51840
52181
|
throw new ClaudeSdkPackageError(`Native CLI binary package ${platformPkg} is not installed. ${REINSTALL_HINT2}`);
|
|
51841
52182
|
}
|
|
@@ -52771,12 +53112,12 @@ var init_codex_sdk_model_variants = __esm(() => {
|
|
|
52771
53112
|
// src/daemon/infrastructure/local/harness/services/codex-sdk/codex-sdk-package.ts
|
|
52772
53113
|
import { existsSync as existsSync4, readFileSync as readFileSync6, realpathSync, statSync } from "node:fs";
|
|
52773
53114
|
import { createRequire as createRequire5 } from "node:module";
|
|
52774
|
-
import { dirname as
|
|
53115
|
+
import { dirname as dirname5, join as join10 } from "node:path";
|
|
52775
53116
|
import { fileURLToPath as fileURLToPath4, pathToFileURL as pathToFileURL3 } from "node:url";
|
|
52776
53117
|
function resolveChatroomCliRoot3(moduleRef = import.meta.url) {
|
|
52777
53118
|
const filePath = moduleRef.startsWith("file:") ? fileURLToPath4(moduleRef) : moduleRef;
|
|
52778
|
-
let dir =
|
|
52779
|
-
while (dir !==
|
|
53119
|
+
let dir = dirname5(filePath);
|
|
53120
|
+
while (dir !== dirname5(dir)) {
|
|
52780
53121
|
const packageJsonPath = join10(dir, "package.json");
|
|
52781
53122
|
if (existsSync4(packageJsonPath)) {
|
|
52782
53123
|
const pkg = JSON.parse(readFileSync6(packageJsonPath, "utf8"));
|
|
@@ -52784,7 +53125,7 @@ function resolveChatroomCliRoot3(moduleRef = import.meta.url) {
|
|
|
52784
53125
|
return dir;
|
|
52785
53126
|
}
|
|
52786
53127
|
}
|
|
52787
|
-
dir =
|
|
53128
|
+
dir = dirname5(dir);
|
|
52788
53129
|
}
|
|
52789
53130
|
throw new CodexSdkPackageError(`Could not locate chatroom-cli package root while resolving @openai/codex-sdk. ${REINSTALL_HINT3}`);
|
|
52790
53131
|
}
|
|
@@ -52851,7 +53192,7 @@ function addPlatformPackageJsonCandidate(candidates, candidate) {
|
|
|
52851
53192
|
}
|
|
52852
53193
|
function resolvePlatformPackageJsonCandidates(platformPkg, chatroomCliRoot, codexPackageJson, chatroomRequire, codexRequire) {
|
|
52853
53194
|
const candidates = [];
|
|
52854
|
-
const codexPackageDir = realpathSync(
|
|
53195
|
+
const codexPackageDir = realpathSync(dirname5(codexPackageJson));
|
|
52855
53196
|
const platformPkgBaseName = platformPkg.includes("/") ? platformPkg.slice(platformPkg.indexOf("/") + 1) : platformPkg;
|
|
52856
53197
|
try {
|
|
52857
53198
|
addPlatformPackageJsonCandidate(candidates, codexRequire.resolve(`${platformPkg}/package.json`));
|
|
@@ -52895,7 +53236,7 @@ function resolveCodexExecutablePath(moduleRef = import.meta.url) {
|
|
|
52895
53236
|
throw new CodexSdkPackageError(`Native Codex CLI package ${platformPkg} is not installed. Ensure ${CODEX_NPM_NAME} is installed with optional dependencies. ${REINSTALL_HINT3}`);
|
|
52896
53237
|
}
|
|
52897
53238
|
for (const platformPackageJson of platformPackageJsonCandidates) {
|
|
52898
|
-
const vendorRoot = join10(
|
|
53239
|
+
const vendorRoot = join10(dirname5(platformPackageJson), "vendor");
|
|
52899
53240
|
const binaryPath = resolveNativeCodexBinary(vendorRoot, targetTriple, codexBinaryName);
|
|
52900
53241
|
if (binaryPath) {
|
|
52901
53242
|
return binaryPath;
|
|
@@ -52911,7 +53252,7 @@ async function importBundledCodexSdk(moduleRef = import.meta.url) {
|
|
|
52911
53252
|
if (installedVersion !== pinnedVersion) {
|
|
52912
53253
|
throw new CodexSdkPackageError(`@openai/codex-sdk@${installedVersion} does not match chatroom-cli pin (${pinnedVersion}). ${REINSTALL_HINT3}`);
|
|
52913
53254
|
}
|
|
52914
|
-
const distEntryPath = join10(
|
|
53255
|
+
const distEntryPath = join10(dirname5(packageJsonPath), "dist", "index.js");
|
|
52915
53256
|
if (!existsSync4(distEntryPath)) {
|
|
52916
53257
|
throw new CodexSdkPackageError(`@openai/codex-sdk entry file is missing: ${distEntryPath}. ${REINSTALL_HINT3}`);
|
|
52917
53258
|
}
|
|
@@ -55022,9 +55363,9 @@ var init_session_event_forwarder = __esm(() => {
|
|
|
55022
55363
|
});
|
|
55023
55364
|
|
|
55024
55365
|
// src/daemon/infrastructure/local/harness/services/opencode-sdk/session-metadata-store.ts
|
|
55025
|
-
import { existsSync as existsSync5, mkdirSync as
|
|
55366
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync7, writeFileSync as writeFileSync2 } from "node:fs";
|
|
55026
55367
|
import { homedir as homedir3 } from "node:os";
|
|
55027
|
-
import { dirname as
|
|
55368
|
+
import { dirname as dirname6, join as join11 } from "node:path";
|
|
55028
55369
|
|
|
55029
55370
|
class FileSessionMetadataStore {
|
|
55030
55371
|
filePath;
|
|
@@ -55041,9 +55382,9 @@ class FileSessionMetadataStore {
|
|
|
55041
55382
|
}
|
|
55042
55383
|
save(sessions) {
|
|
55043
55384
|
try {
|
|
55044
|
-
const dir =
|
|
55385
|
+
const dir = dirname6(this.filePath);
|
|
55045
55386
|
if (!existsSync5(dir)) {
|
|
55046
|
-
|
|
55387
|
+
mkdirSync3(dir, { recursive: true });
|
|
55047
55388
|
}
|
|
55048
55389
|
writeFileSync2(this.filePath, JSON.stringify(sessions, null, 2));
|
|
55049
55390
|
} catch {}
|
|
@@ -55591,12 +55932,12 @@ var init_opencode_sdk = __esm(() => {
|
|
|
55591
55932
|
|
|
55592
55933
|
// src/daemon/infrastructure/local/harness/services/pi-sdk/pi-sdk-package.ts
|
|
55593
55934
|
import { existsSync as existsSync6, readFileSync as readFileSync8 } from "node:fs";
|
|
55594
|
-
import { dirname as
|
|
55935
|
+
import { dirname as dirname7, join as join12 } from "node:path";
|
|
55595
55936
|
import { fileURLToPath as fileURLToPath5, pathToFileURL as pathToFileURL4 } from "node:url";
|
|
55596
55937
|
function resolveChatroomCliRoot4(moduleRef = import.meta.url) {
|
|
55597
55938
|
const filePath = moduleRef.startsWith("file:") ? fileURLToPath5(moduleRef) : moduleRef;
|
|
55598
|
-
let dir =
|
|
55599
|
-
while (dir !==
|
|
55939
|
+
let dir = dirname7(filePath);
|
|
55940
|
+
while (dir !== dirname7(dir)) {
|
|
55600
55941
|
const packageJsonPath = join12(dir, "package.json");
|
|
55601
55942
|
if (existsSync6(packageJsonPath)) {
|
|
55602
55943
|
const pkg = JSON.parse(readFileSync8(packageJsonPath, "utf8"));
|
|
@@ -55604,7 +55945,7 @@ function resolveChatroomCliRoot4(moduleRef = import.meta.url) {
|
|
|
55604
55945
|
return dir;
|
|
55605
55946
|
}
|
|
55606
55947
|
}
|
|
55607
|
-
dir =
|
|
55948
|
+
dir = dirname7(dir);
|
|
55608
55949
|
}
|
|
55609
55950
|
throw new PiSdkPackageError(`Could not locate chatroom-cli package root while resolving ${PI_CODING_AGENT_PKG}. ${REINSTALL_HINT4}`);
|
|
55610
55951
|
}
|
|
@@ -55619,18 +55960,18 @@ function readPinnedSdkVersion4(chatroomCliRoot) {
|
|
|
55619
55960
|
return match17[1];
|
|
55620
55961
|
}
|
|
55621
55962
|
function readInstalledSdkVersion4(entryPath) {
|
|
55622
|
-
const packageJsonPath = join12(
|
|
55963
|
+
const packageJsonPath = join12(dirname7(entryPath), "..", "package.json");
|
|
55623
55964
|
const pkg = JSON.parse(readFileSync8(packageJsonPath, "utf8"));
|
|
55624
55965
|
return pkg.version;
|
|
55625
55966
|
}
|
|
55626
55967
|
function resolvePiSdkEntryPathFromNodeModules(chatroomCliRoot) {
|
|
55627
55968
|
let dir = chatroomCliRoot;
|
|
55628
|
-
while (dir !==
|
|
55969
|
+
while (dir !== dirname7(dir)) {
|
|
55629
55970
|
const entryPath = join12(dir, "node_modules", PI_CODING_AGENT_PKG, "dist", "index.js");
|
|
55630
55971
|
if (existsSync6(entryPath)) {
|
|
55631
55972
|
return entryPath;
|
|
55632
55973
|
}
|
|
55633
|
-
dir =
|
|
55974
|
+
dir = dirname7(dir);
|
|
55634
55975
|
}
|
|
55635
55976
|
return;
|
|
55636
55977
|
}
|
|
@@ -63776,15 +64117,35 @@ async function requestLocalDaemon(port, event, payload) {
|
|
|
63776
64117
|
socket.connect();
|
|
63777
64118
|
});
|
|
63778
64119
|
const response = await socket.timeout(1e4).emitWithAck(event, payload);
|
|
63779
|
-
if (!response.ok)
|
|
63780
|
-
throw
|
|
64120
|
+
if (!response.ok) {
|
|
64121
|
+
throw toLocalDaemonServerError(response, event);
|
|
64122
|
+
}
|
|
63781
64123
|
return response.data;
|
|
63782
64124
|
} finally {
|
|
63783
64125
|
socket.disconnect();
|
|
63784
64126
|
}
|
|
63785
64127
|
}
|
|
64128
|
+
function toLocalDaemonServerError(response, event) {
|
|
64129
|
+
const error51 = response.error ?? {};
|
|
64130
|
+
return new LocalDaemonServerError({
|
|
64131
|
+
message: error51.message ?? `Daemon request failed: ${event}`,
|
|
64132
|
+
code: error51.code,
|
|
64133
|
+
details: error51.details
|
|
64134
|
+
});
|
|
64135
|
+
}
|
|
64136
|
+
var LocalDaemonServerError;
|
|
63786
64137
|
var init_local_daemon = __esm(() => {
|
|
63787
64138
|
init_esm_debug3();
|
|
64139
|
+
LocalDaemonServerError = class LocalDaemonServerError extends Error {
|
|
64140
|
+
code;
|
|
64141
|
+
details;
|
|
64142
|
+
constructor(error51) {
|
|
64143
|
+
super(error51.message ?? "Daemon request failed");
|
|
64144
|
+
this.name = "LocalDaemonServerError";
|
|
64145
|
+
this.code = error51.code;
|
|
64146
|
+
this.details = error51.details;
|
|
64147
|
+
}
|
|
64148
|
+
};
|
|
63788
64149
|
});
|
|
63789
64150
|
|
|
63790
64151
|
// src/daemon/entry/resolve-local-web-port.ts
|
|
@@ -63996,12 +64357,12 @@ var init_log_schema = __esm(() => {
|
|
|
63996
64357
|
});
|
|
63997
64358
|
|
|
63998
64359
|
// src/infrastructure/log-server/open-log-database.ts
|
|
63999
|
-
import { mkdirSync as
|
|
64000
|
-
import { dirname as
|
|
64001
|
-
import { DatabaseSync } from "node:sqlite";
|
|
64360
|
+
import { mkdirSync as mkdirSync4 } from "node:fs";
|
|
64361
|
+
import { dirname as dirname8 } from "node:path";
|
|
64362
|
+
import { DatabaseSync as DatabaseSync2 } from "node:sqlite";
|
|
64002
64363
|
function openLogDatabase(dbPath) {
|
|
64003
|
-
|
|
64004
|
-
const db = new
|
|
64364
|
+
mkdirSync4(dirname8(dbPath), { recursive: true });
|
|
64365
|
+
const db = new DatabaseSync2(dbPath);
|
|
64005
64366
|
db.exec("PRAGMA journal_mode = WAL");
|
|
64006
64367
|
db.exec("PRAGMA busy_timeout = 5000");
|
|
64007
64368
|
db.exec("PRAGMA synchronous = NORMAL");
|
|
@@ -64190,7 +64551,7 @@ var init_daemon_process_scan = __esm(() => {
|
|
|
64190
64551
|
|
|
64191
64552
|
// src/commands/machine/pid.ts
|
|
64192
64553
|
import { createHash as createHash2 } from "node:crypto";
|
|
64193
|
-
import { existsSync as existsSync8, readFileSync as readFileSync10, writeFileSync as writeFileSync3, unlinkSync as unlinkSync2, mkdirSync as
|
|
64554
|
+
import { existsSync as existsSync8, readFileSync as readFileSync10, writeFileSync as writeFileSync3, unlinkSync as unlinkSync2, mkdirSync as mkdirSync5 } from "node:fs";
|
|
64194
64555
|
import { homedir as homedir7 } from "node:os";
|
|
64195
64556
|
import { join as join16 } from "node:path";
|
|
64196
64557
|
function getUrlHash2() {
|
|
@@ -64202,7 +64563,7 @@ function getPidFileName() {
|
|
|
64202
64563
|
}
|
|
64203
64564
|
function ensureChatroomDir2() {
|
|
64204
64565
|
if (!existsSync8(CHATROOM_DIR3)) {
|
|
64205
|
-
|
|
64566
|
+
mkdirSync5(CHATROOM_DIR3, { recursive: true, mode: 448 });
|
|
64206
64567
|
}
|
|
64207
64568
|
}
|
|
64208
64569
|
function getPidFilePath() {
|
|
@@ -77212,11 +77573,11 @@ var init_pdfium_renderer = __esm(() => {
|
|
|
77212
77573
|
|
|
77213
77574
|
// ../../node_modules/.pnpm/@llamaindex+liteparse@1.5.3/node_modules/@llamaindex/liteparse/dist/src/engines/pdf/pdfjsImporter.js
|
|
77214
77575
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
77215
|
-
import { dirname as
|
|
77576
|
+
import { dirname as dirname9 } from "node:path";
|
|
77216
77577
|
async function importPdfJs() {
|
|
77217
77578
|
const pdfUrl = new URL("../../vendor/pdfjs/pdf.mjs", import.meta.url);
|
|
77218
77579
|
const pdfjs = await import(pdfUrl.href);
|
|
77219
|
-
const dirPath =
|
|
77580
|
+
const dirPath = dirname9(fileURLToPath6(pdfUrl));
|
|
77220
77581
|
return {
|
|
77221
77582
|
fn: pdfjs.getDocument,
|
|
77222
77583
|
dir: dirPath
|
|
@@ -98865,9 +99226,9 @@ function applyMarkupTags(markup, text) {
|
|
|
98865
99226
|
}
|
|
98866
99227
|
|
|
98867
99228
|
// ../../node_modules/.pnpm/@llamaindex+liteparse@1.5.3/node_modules/@llamaindex/liteparse/dist/src/processing/gridDebugLogger.js
|
|
98868
|
-
import { mkdirSync as
|
|
99229
|
+
import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
98869
99230
|
import { mkdir as mkdir4, writeFile as writeFile5 } from "fs/promises";
|
|
98870
|
-
import { dirname as
|
|
99231
|
+
import { dirname as dirname10 } from "path";
|
|
98871
99232
|
|
|
98872
99233
|
class GridDebugLogger {
|
|
98873
99234
|
config;
|
|
@@ -99194,14 +99555,14 @@ class GridDebugLogger {
|
|
|
99194
99555
|
flushSync() {
|
|
99195
99556
|
if (!this.config.outputPath || this.entries.length === 0)
|
|
99196
99557
|
return;
|
|
99197
|
-
|
|
99558
|
+
mkdirSync6(dirname10(this.config.outputPath), { recursive: true });
|
|
99198
99559
|
writeFileSync4(this.config.outputPath, this.formatEntries(), "utf-8");
|
|
99199
99560
|
this.entries = [];
|
|
99200
99561
|
}
|
|
99201
99562
|
async flush() {
|
|
99202
99563
|
if (!this.config.outputPath || this.entries.length === 0)
|
|
99203
99564
|
return;
|
|
99204
|
-
await mkdir4(
|
|
99565
|
+
await mkdir4(dirname10(this.config.outputPath), { recursive: true });
|
|
99205
99566
|
await writeFile5(this.config.outputPath, this.formatEntries(), "utf-8");
|
|
99206
99567
|
this.entries = [];
|
|
99207
99568
|
}
|
|
@@ -99252,7 +99613,7 @@ var init_gridDebugLogger = __esm(() => {
|
|
|
99252
99613
|
});
|
|
99253
99614
|
|
|
99254
99615
|
// ../../node_modules/.pnpm/@llamaindex+liteparse@1.5.3/node_modules/@llamaindex/liteparse/dist/src/processing/gridVisualizer.js
|
|
99255
|
-
import { mkdirSync as
|
|
99616
|
+
import { mkdirSync as mkdirSync7 } from "fs";
|
|
99256
99617
|
function escapeXml(s) {
|
|
99257
99618
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
99258
99619
|
}
|
|
@@ -99362,7 +99723,7 @@ async function renderGridVisualization(data, outputPath) {
|
|
|
99362
99723
|
}).composite([{ input: svgBuffer, top: 0, left: 0 }]).png({ compressionLevel: 6 }).toFile(outputPath);
|
|
99363
99724
|
}
|
|
99364
99725
|
async function renderAllVisualizations(pages, outputDir) {
|
|
99365
|
-
|
|
99726
|
+
mkdirSync7(outputDir, { recursive: true });
|
|
99366
99727
|
const paths = [];
|
|
99367
99728
|
for (const page of pages) {
|
|
99368
99729
|
const filePath = `${outputDir}/page-${page.pageNum}-grid.png`;
|
|
@@ -106625,15 +106986,15 @@ var init_team_presets = __esm(() => {
|
|
|
106625
106986
|
duo: {
|
|
106626
106987
|
structureId: TEAM_STRUCTURE_IDS.duo,
|
|
106627
106988
|
name: "Duo",
|
|
106628
|
-
description: "A planner and builder working as a pair, planner as coordinator, with optional ephemeral
|
|
106629
|
-
roles: ["planner", "
|
|
106989
|
+
description: "A planner and builder working as a pair, planner as coordinator, with optional ephemeral architect and optional ephemeral uiux-engineer roles",
|
|
106990
|
+
roles: ["planner", "architect", "uiux-engineer", "builder"],
|
|
106630
106991
|
entryPoint: "planner"
|
|
106631
106992
|
},
|
|
106632
106993
|
solo: {
|
|
106633
106994
|
structureId: TEAM_STRUCTURE_IDS.solo,
|
|
106634
106995
|
name: "Solo",
|
|
106635
|
-
description: "A single agent working independently, with optional ephemeral
|
|
106636
|
-
roles: ["solo", "
|
|
106996
|
+
description: "A single agent working independently, with optional ephemeral architect and optional ephemeral uiux-engineer roles",
|
|
106997
|
+
roles: ["solo", "architect", "uiux-engineer"],
|
|
106637
106998
|
entryPoint: "solo"
|
|
106638
106999
|
}
|
|
106639
107000
|
};
|
|
@@ -106829,6 +107190,22 @@ var init_agent2 = __esm(() => {
|
|
|
106829
107190
|
init_storage2();
|
|
106830
107191
|
});
|
|
106831
107192
|
|
|
107193
|
+
// ../../services/backend/prompts/cli/handoff/command.ts
|
|
107194
|
+
function handoffCommand(params) {
|
|
107195
|
+
const prefix = params.cliEnvPrefix || "";
|
|
107196
|
+
const chatroomId = params.chatroomId || "<chatroom-id>";
|
|
107197
|
+
const role = params.role || "<role>";
|
|
107198
|
+
const nextRole = params.nextRole || "<target>";
|
|
107199
|
+
const placeholder = params.messagePlaceholder ?? "[Your message here]";
|
|
107200
|
+
const commandPrefix = `${prefix}chatroom handoff --chatroom-id="${chatroomId}" --role="${role}" --next-role="${nextRole}"`;
|
|
107201
|
+
return formatStdinHeredocCommand(commandPrefix, HANDOFF_STDIN_DELIMITER, placeholder, {
|
|
107202
|
+
messageMarker: HANDOFF_MESSAGE_MARKER
|
|
107203
|
+
});
|
|
107204
|
+
}
|
|
107205
|
+
var init_command2 = __esm(() => {
|
|
107206
|
+
init_stdin_heredoc();
|
|
107207
|
+
});
|
|
107208
|
+
|
|
106832
107209
|
// ../../services/backend/prompts/native/handoff-visibility.ts
|
|
106833
107210
|
function recipientLabel(toRole) {
|
|
106834
107211
|
return toRole.toLowerCase() === "user" ? "The user" : `The \`${toRole}\` agent`;
|
|
@@ -106852,6 +107229,285 @@ Put your **complete** deliverable in the handoff message — not in session text
|
|
|
106852
107229
|
---`;
|
|
106853
107230
|
}
|
|
106854
107231
|
|
|
107232
|
+
// ../../services/backend/prompts/utils/file-reference-guidance.ts
|
|
107233
|
+
function getFileReferenceGuidanceComment() {
|
|
107234
|
+
return `<!-- File references (clickable in workspace UI): use repo-relative paths with a file extension — e.g. \`apps/webapp/src/modules/chatroom/foo.ts\` or [apps/webapp/src/foo.ts](apps/webapp/src/foo.ts). Avoid absolute paths, file:// prefixes, and paths without / or extension. -->`;
|
|
107235
|
+
}
|
|
107236
|
+
function getFileReferenceProofOfCompletionExample() {
|
|
107237
|
+
return `${getFileReferenceGuidanceComment()}
|
|
107238
|
+
- \`apps/webapp/src/path/to/file.ts\` — <what changed and why>`;
|
|
107239
|
+
}
|
|
107240
|
+
|
|
107241
|
+
// ../../services/backend/prompts/teams/architect-handoff-templates.ts
|
|
107242
|
+
function normalizeEntryPointRole(entryPointRole) {
|
|
107243
|
+
return entryPointRole.trim().toLowerCase() || "planner";
|
|
107244
|
+
}
|
|
107245
|
+
function getArchitectFocus() {
|
|
107246
|
+
return "module boundaries, APIs, schemas, indexes and queries, invariants, failure and recovery handling, tests, and implementation sequence";
|
|
107247
|
+
}
|
|
107248
|
+
function getArchitectRequirements() {
|
|
107249
|
+
return `
|
|
107250
|
+
- Cite repository evidence for domain model/entity ownership, lifecycle, invariants, identifiers, and relationships.
|
|
107251
|
+
- Define service and module boundaries, public and internal APIs, function signatures, and ownership of side effects.
|
|
107252
|
+
- Analyze concurrency and races: concurrent writers, idempotency, ordering and monotonicity, retries, transactions, and failure/recovery behavior.
|
|
107253
|
+
- Design read patterns first: primary read paths, indexes, projections/read models, query shapes, scan and transaction limits, and invalidation/subscription scope.
|
|
107254
|
+
- Account for Convex reactivity and bandwidth: query invalidation patterns, avoiding unnecessary reactive fanout, and separating high-frequency heartbeat/liveness/status fields from low-frequency identity/configuration fields.
|
|
107255
|
+
- Specify concrete schema, query, and mutation changes; migration/backfill sequence; tests; and verification order.`;
|
|
107256
|
+
}
|
|
107257
|
+
function getEntryPointToArchitectHandoffTemplate(entryPointRole) {
|
|
107258
|
+
const entryPoint = normalizeEntryPointRole(entryPointRole);
|
|
107259
|
+
return `${getHandoffRecipientVisibilityCallout("architect")}
|
|
107260
|
+
|
|
107261
|
+
## Handoff Template (${entryPoint} → architect)
|
|
107262
|
+
|
|
107263
|
+
The automatically injected \`<user-message>\` is the authoritative request. Add only concise context that the Architect needs to design within the existing repository and team scope.
|
|
107264
|
+
|
|
107265
|
+
Provide the request, relevant constraints, and the files or product surfaces that need inspection. Ask for one evidence-backed design focused on ${getArchitectFocus()}.
|
|
107266
|
+
|
|
107267
|
+
After completing the design, hand it back to \`${entryPoint}\` with the normal handoff command. Stop after the successful handoff; do not implement the design or delegate further work.
|
|
107268
|
+
|
|
107269
|
+
\`\`\`bash
|
|
107270
|
+
${handoffCommand({
|
|
107271
|
+
chatroomId: "<chatroom-id>",
|
|
107272
|
+
role: "architect",
|
|
107273
|
+
nextRole: entryPoint,
|
|
107274
|
+
cliEnvPrefix: ""
|
|
107275
|
+
})}
|
|
107276
|
+
\`\`\``;
|
|
107277
|
+
}
|
|
107278
|
+
function getArchitectToEntryPointHandoffTemplate(entryPointRole) {
|
|
107279
|
+
return renderArchitectToEntryPointHandoffTemplate(normalizeEntryPointRole(entryPointRole));
|
|
107280
|
+
}
|
|
107281
|
+
function getGenericArchitectToEntryPointHandoffTemplate() {
|
|
107282
|
+
return renderArchitectToEntryPointHandoffTemplate("<entry-point-role>", true);
|
|
107283
|
+
}
|
|
107284
|
+
function renderArchitectToEntryPointHandoffTemplate(entryPoint, generic = false) {
|
|
107285
|
+
const sharedContractsHeading = !generic && entryPoint === "planner" ? "## Shared contracts (planner-owned)" : "## Shared contracts (configured entry-point-owned)";
|
|
107286
|
+
const placeholderInstruction = generic ? " Replace `<entry-point-role>` with the configured entry-point role before running it." : "";
|
|
107287
|
+
return `${getHandoffRecipientVisibilityCallout(entryPoint)}
|
|
107288
|
+
|
|
107289
|
+
## Handoff Template (Architect → Entry Point)
|
|
107290
|
+
|
|
107291
|
+
Return exactly one recommended, evidence-backed design brief for the authoritative user request to the configured entry point. This is an advisory handback: do not implement code, edit files, spawn subagents, present alternatives, or expand scope. The injected \`<handoff-templates>\` block is the authoritative structure for this handoff; complete every section in order. Use \`Not Applicable.\` only when a section is genuinely inapplicable, with no explanation or filler.
|
|
107292
|
+
|
|
107293
|
+
## Summary
|
|
107294
|
+
<describe the design problem being solved, the repository/product surface where it fits, and the evidence-backed context; do not refer to hidden session text>
|
|
107295
|
+
|
|
107296
|
+
## Goal
|
|
107297
|
+
<state the one-sentence outcome this design delivers>
|
|
107298
|
+
|
|
107299
|
+
## Key Knowledge for High Quality Bar
|
|
107300
|
+
<cite the inspected repository patterns and complete the architect checklist below; do not provide a high-level essay>
|
|
107301
|
+
- Produce exactly one recommended design for ${getArchitectFocus()}.
|
|
107302
|
+
- Name concrete repository paths, existing abstractions, APIs/types, state/data flow, acceptance criteria, risks, and verification steps.
|
|
107303
|
+
${getArchitectRequirements()}
|
|
107304
|
+
|
|
107305
|
+
## Force Multipliers
|
|
107306
|
+
<name the existing abstractions, patterns, utilities, and platform conventions to reuse, and state why each reduces implementation risk or duplication>
|
|
107307
|
+
- Keep the design within the repository's established source-of-truth boundaries and avoid introducing a new registry or abstraction without evidence.
|
|
107308
|
+
|
|
107309
|
+
## Files to implement (exhaustive, file-level)
|
|
107310
|
+
List every file or product surface the implementer must create or modify. Mark each \`(Required)\` or \`(Optional)\`. For every file, give the exact responsibility, exported types/signatures/query shape, state/data/event boundaries, and target code detailed enough to implement without guessing.
|
|
107311
|
+
${getFileReferenceGuidanceComment()}
|
|
107312
|
+
|
|
107313
|
+
### \`<repo-relative/path.ext>\` (Required)
|
|
107314
|
+
**Change:** <precise add/modify/remove responsibility and why>
|
|
107315
|
+
|
|
107316
|
+
\`\`\`text
|
|
107317
|
+
// Target code, API/type signature, query shape, or migration/backfill step.
|
|
107318
|
+
// Enough detail that implementation requires no invention.
|
|
107319
|
+
\`\`\`
|
|
107320
|
+
|
|
107321
|
+
<add one block per file; do not collapse multiple files into a directory or vague layer>
|
|
107322
|
+
|
|
107323
|
+
${sharedContractsHeading}
|
|
107324
|
+
<list cross-file interfaces, schemas, API contracts, state/data boundaries, or write exactly \`Not Applicable.\` when genuinely inapplicable>
|
|
107325
|
+
|
|
107326
|
+
### Interfaces & types
|
|
107327
|
+
\`\`\`typescript
|
|
107328
|
+
// Shared signatures, schemas, query/mutation shapes, or state contracts.
|
|
107329
|
+
\`\`\`
|
|
107330
|
+
|
|
107331
|
+
### Reference snippets
|
|
107332
|
+
\`\`\`typescript
|
|
107333
|
+
// Canonical imports, call patterns, or data-flow examples.
|
|
107334
|
+
\`\`\`
|
|
107335
|
+
|
|
107336
|
+
## Requirements (acceptance criteria)
|
|
107337
|
+
- <one concrete, verifiable requirement per bullet; include exact data shape, API contract, migration result, and failure behavior>
|
|
107338
|
+
- Include repository test coverage for domain, concurrency, read-pattern, migration, and recovery risk areas.
|
|
107339
|
+
- Verify the implemented user-facing entry point or task-delivery path end-to-end; unit tests alone are insufficient.
|
|
107340
|
+
|
|
107341
|
+
## What to avoid
|
|
107342
|
+
- Do not implement code or edit files as the architect; this handoff is advisory only.
|
|
107343
|
+
- Do not present alternative designs, generic advice, or requirements without concrete evidence and file-level consequences.
|
|
107344
|
+
- Do not invent APIs, schema fields, query shapes, indexes, or source-of-truth locations when existing repository patterns apply.
|
|
107345
|
+
- <explicit task-specific anti-patterns, scope boundaries, and migration/source-of-truth pitfalls>
|
|
107346
|
+
|
|
107347
|
+
## Skills to activate
|
|
107348
|
+
- <relevant repository skills and why they apply, or write exactly \`Not Applicable.\` when none apply>
|
|
107349
|
+
|
|
107350
|
+
## Out of scope
|
|
107351
|
+
- <explicit files, flows, behavior, or migration work the implementer must not touch>
|
|
107352
|
+
|
|
107353
|
+
## Handoff
|
|
107354
|
+
Run the normal handoff command to the configured entry point with this complete design, then stop.${placeholderInstruction}
|
|
107355
|
+
|
|
107356
|
+
\`\`\`bash
|
|
107357
|
+
${handoffCommand({
|
|
107358
|
+
chatroomId: "<chatroom-id>",
|
|
107359
|
+
role: "architect",
|
|
107360
|
+
nextRole: entryPoint,
|
|
107361
|
+
cliEnvPrefix: ""
|
|
107362
|
+
})}
|
|
107363
|
+
\`\`\``;
|
|
107364
|
+
}
|
|
107365
|
+
var init_architect_handoff_templates = __esm(() => {
|
|
107366
|
+
init_command2();
|
|
107367
|
+
});
|
|
107368
|
+
|
|
107369
|
+
// ../../services/backend/prompts/teams/uiux-engineer-handoff-templates.ts
|
|
107370
|
+
function normalizeEntryPointRole2(entryPointRole) {
|
|
107371
|
+
return entryPointRole.trim().toLowerCase() || "planner";
|
|
107372
|
+
}
|
|
107373
|
+
function getUiuxEngineerFocus() {
|
|
107374
|
+
return "complete user flows, loading/empty/error/success states, component ownership, theme tokens and layout, keyboard and accessibility behavior, responsive details, and UI tests";
|
|
107375
|
+
}
|
|
107376
|
+
function getUiuxEngineerRequirements() {
|
|
107377
|
+
return `
|
|
107378
|
+
- Specify complete user flows with explicit loading, empty, error, success, disabled, and retry states where applicable.
|
|
107379
|
+
- Define exact keyboard shortcuts, focus order, keyboard navigation, focus restoration, and accessible semantics and labels.
|
|
107380
|
+
- Define component hierarchy and ownership, props/state/events, data boundaries, and interaction behavior.
|
|
107381
|
+
- Choose concrete existing ShadCN components with the Base UI backend and lucide-react/react-icons conventions; do not write "use an appropriate component."
|
|
107382
|
+
- Specify Tailwind utility classes or semantic theme-token classes for layout, spacing, sizing, typography, states, responsive behavior, and dark mode.
|
|
107383
|
+
- Specify responsive breakpoints/layout behavior, visual feedback, destructive-action safeguards, exact files/components, and the UI/integration/accessibility test plan.`;
|
|
107384
|
+
}
|
|
107385
|
+
function getEntryPointToUiuxEngineerHandoffTemplate(entryPointRole) {
|
|
107386
|
+
const entryPoint = normalizeEntryPointRole2(entryPointRole);
|
|
107387
|
+
return `${getHandoffRecipientVisibilityCallout("uiux-engineer")}
|
|
107388
|
+
|
|
107389
|
+
## Handoff Template (${entryPoint} → uiux-engineer)
|
|
107390
|
+
|
|
107391
|
+
The automatically injected \`<user-message>\` is the authoritative request. Add only concise context that the UI/UX Engineer needs to design within the existing repository and team scope.
|
|
107392
|
+
|
|
107393
|
+
Provide the request, relevant constraints, and the files or product surfaces that need inspection. Ask for one evidence-backed design focused on ${getUiuxEngineerFocus()}.
|
|
107394
|
+
|
|
107395
|
+
After completing the design, hand it back to \`${entryPoint}\` with the normal handoff command. Stop after the successful handoff; do not implement the design or delegate further work.
|
|
107396
|
+
|
|
107397
|
+
\`\`\`bash
|
|
107398
|
+
${handoffCommand({
|
|
107399
|
+
chatroomId: "<chatroom-id>",
|
|
107400
|
+
role: "uiux-engineer",
|
|
107401
|
+
nextRole: entryPoint,
|
|
107402
|
+
cliEnvPrefix: ""
|
|
107403
|
+
})}
|
|
107404
|
+
\`\`\``;
|
|
107405
|
+
}
|
|
107406
|
+
function getUiuxEngineerToEntryPointHandoffTemplate(entryPointRole) {
|
|
107407
|
+
return renderUiuxEngineerToEntryPointHandoffTemplate(normalizeEntryPointRole2(entryPointRole));
|
|
107408
|
+
}
|
|
107409
|
+
function getGenericUiuxEngineerToEntryPointHandoffTemplate() {
|
|
107410
|
+
return renderUiuxEngineerToEntryPointHandoffTemplate("<entry-point-role>", true);
|
|
107411
|
+
}
|
|
107412
|
+
function renderUiuxEngineerToEntryPointHandoffTemplate(entryPoint, generic = false) {
|
|
107413
|
+
const sharedContractsHeading = !generic && entryPoint === "planner" ? "## Shared contracts (planner-owned)" : "## Shared contracts (configured entry-point-owned)";
|
|
107414
|
+
const placeholderInstruction = generic ? " Replace `<entry-point-role>` with the configured entry-point role before running it." : "";
|
|
107415
|
+
return `${getHandoffRecipientVisibilityCallout(entryPoint)}
|
|
107416
|
+
|
|
107417
|
+
## Handoff Template (UI/UX Engineer → Entry Point)
|
|
107418
|
+
|
|
107419
|
+
Return exactly one recommended, evidence-backed design brief for the authoritative user request to the configured entry point. This is an advisory handback: do not implement code, edit files, spawn subagents, present alternatives, or expand scope. The injected \`<handoff-templates>\` block is the authoritative structure for this handoff; complete every section in order. Use \`Not Applicable.\` only when a section is genuinely inapplicable, with no explanation or filler.
|
|
107420
|
+
|
|
107421
|
+
## Summary
|
|
107422
|
+
<describe the design problem being solved, the repository/product surface where it fits, and the evidence-backed context; do not refer to hidden session text>
|
|
107423
|
+
|
|
107424
|
+
## Goal
|
|
107425
|
+
<state the one-sentence outcome this design delivers>
|
|
107426
|
+
|
|
107427
|
+
## Key Knowledge for High Quality Bar
|
|
107428
|
+
<cite the inspected repository patterns and complete the UI/UX engineer checklist below; do not provide a high-level essay>
|
|
107429
|
+
- Produce exactly one recommended design for ${getUiuxEngineerFocus()}.
|
|
107430
|
+
- Name concrete repository paths, existing components/tokens, props/state/events, data boundaries, acceptance criteria, risks, and verification steps.
|
|
107431
|
+
${getUiuxEngineerRequirements()}
|
|
107432
|
+
|
|
107433
|
+
## Force Multipliers
|
|
107434
|
+
<name the existing components, patterns, tokens, utilities, and platform conventions to reuse, and state why each reduces implementation risk or duplication>
|
|
107435
|
+
- Keep the design within the repository's established source-of-truth boundaries and avoid introducing a new registry or abstraction without evidence.
|
|
107436
|
+
|
|
107437
|
+
## Files to implement (exhaustive, file-level)
|
|
107438
|
+
List every file or product surface the implementer must create or modify. Mark each \`(Required)\` or \`(Optional)\`. For every file, give the exact responsibility, exported types/signatures/props, state/data/event boundaries, component hierarchy, and target Tailwind/theme-token snippet detailed enough to implement without guessing.
|
|
107439
|
+
${getFileReferenceGuidanceComment()}
|
|
107440
|
+
|
|
107441
|
+
### \`<repo-relative/path.ext>\` (Required)
|
|
107442
|
+
**Change:** <precise add/modify/remove responsibility and why>
|
|
107443
|
+
|
|
107444
|
+
\`\`\`text
|
|
107445
|
+
// Component hierarchy, props/state/events, test structure, or exact
|
|
107446
|
+
// Tailwind/theme-token classes. Enough detail that implementation requires no invention.
|
|
107447
|
+
\`\`\`
|
|
107448
|
+
|
|
107449
|
+
<add one block per file; do not collapse multiple files into a directory or vague layer>
|
|
107450
|
+
|
|
107451
|
+
${sharedContractsHeading}
|
|
107452
|
+
<list cross-file interfaces, component/data contracts, state boundaries, or write exactly \`Not Applicable.\` when genuinely inapplicable>
|
|
107453
|
+
|
|
107454
|
+
### Interfaces & types
|
|
107455
|
+
\`\`\`typescript
|
|
107456
|
+
// Shared props, state, events, query shapes, or accessibility contracts.
|
|
107457
|
+
\`\`\`
|
|
107458
|
+
|
|
107459
|
+
### Reference snippets
|
|
107460
|
+
\`\`\`tsx
|
|
107461
|
+
// Canonical component imports, hook usage, keyboard wiring, or layout examples.
|
|
107462
|
+
\`\`\`
|
|
107463
|
+
|
|
107464
|
+
## Requirements (acceptance criteria)
|
|
107465
|
+
- <one concrete, verifiable requirement per bullet; include exact states, interactions, semantics, classes/tokens, and responsive behavior>
|
|
107466
|
+
- Include UI, integration, and accessibility test coverage for the design's risk areas.
|
|
107467
|
+
- Verify the implemented user-facing entry point end-to-end; unit tests alone are insufficient.
|
|
107468
|
+
|
|
107469
|
+
## What to avoid
|
|
107470
|
+
- Do not implement code or edit files as the UI/UX engineer; this handoff is advisory only.
|
|
107471
|
+
- Do not present alternative designs, generic advice, or requirements without concrete evidence and file-level consequences.
|
|
107472
|
+
- Do not invent components, props, tokens, keyboard behavior, or source-of-truth locations when existing repository patterns apply.
|
|
107473
|
+
- <explicit task-specific anti-patterns, scope boundaries, and destructive-action/source-of-truth pitfalls>
|
|
107474
|
+
|
|
107475
|
+
## Skills to activate
|
|
107476
|
+
- <relevant repository skills and why they apply, or write exactly \`Not Applicable.\` when none apply>
|
|
107477
|
+
|
|
107478
|
+
## Out of scope
|
|
107479
|
+
- <explicit files, flows, behavior, or migration work the implementer must not touch>
|
|
107480
|
+
|
|
107481
|
+
## Handoff
|
|
107482
|
+
Run the normal handoff command to the configured entry point with this complete design, then stop.${placeholderInstruction}
|
|
107483
|
+
|
|
107484
|
+
\`\`\`bash
|
|
107485
|
+
${handoffCommand({
|
|
107486
|
+
chatroomId: "<chatroom-id>",
|
|
107487
|
+
role: "uiux-engineer",
|
|
107488
|
+
nextRole: entryPoint,
|
|
107489
|
+
cliEnvPrefix: ""
|
|
107490
|
+
})}
|
|
107491
|
+
\`\`\``;
|
|
107492
|
+
}
|
|
107493
|
+
var init_uiux_engineer_handoff_templates = __esm(() => {
|
|
107494
|
+
init_command2();
|
|
107495
|
+
});
|
|
107496
|
+
|
|
107497
|
+
// ../../services/backend/prompts/teams/duo/handoff-templates/architect.ts
|
|
107498
|
+
var duoArchitectHandoffContract;
|
|
107499
|
+
var init_architect = __esm(() => {
|
|
107500
|
+
init_architect_handoff_templates();
|
|
107501
|
+
duoArchitectHandoffContract = {
|
|
107502
|
+
role: "architect",
|
|
107503
|
+
receivesFrom: ["planner"],
|
|
107504
|
+
returnsTo: ["planner"],
|
|
107505
|
+
outboundTemplates: {
|
|
107506
|
+
planner: () => getArchitectToEntryPointHandoffTemplate("planner")
|
|
107507
|
+
}
|
|
107508
|
+
};
|
|
107509
|
+
});
|
|
107510
|
+
|
|
106855
107511
|
// ../../services/backend/prompts/utils/code-change-verification.ts
|
|
106856
107512
|
var CODE_CHANGE_VERIFICATION_CONFIRMATION = "- [ ] I confirm that I have run typecheck and tests for the project (only required if code changes were made)";
|
|
106857
107513
|
|
|
@@ -106865,15 +107521,6 @@ ${getDelegationBriefDisclosureComment()}`;
|
|
|
106865
107521
|
}
|
|
106866
107522
|
var DELEGATION_BRIEF_DISCLOSURE_CHECKBOX = "- [ ] I confirm the delegation brief is fully met: all (Required) files done, verified end-to-end, acceptance criteria pass";
|
|
106867
107523
|
|
|
106868
|
-
// ../../services/backend/prompts/utils/file-reference-guidance.ts
|
|
106869
|
-
function getFileReferenceGuidanceComment() {
|
|
106870
|
-
return `<!-- File references (clickable in workspace UI): use repo-relative paths with a file extension — e.g. \`apps/webapp/src/modules/chatroom/foo.ts\` or [apps/webapp/src/foo.ts](apps/webapp/src/foo.ts). Avoid absolute paths, file:// prefixes, and paths without / or extension. -->`;
|
|
106871
|
-
}
|
|
106872
|
-
function getFileReferenceProofOfCompletionExample() {
|
|
106873
|
-
return `${getFileReferenceGuidanceComment()}
|
|
106874
|
-
- \`apps/webapp/src/path/to/file.ts\` — <what changed and why>`;
|
|
106875
|
-
}
|
|
106876
|
-
|
|
106877
107524
|
// ../../services/backend/prompts/utils/handoff-section-guidance.ts
|
|
106878
107525
|
function getHandoffNotApplicableSectionComment(context5) {
|
|
106879
107526
|
return `<!-- REQUIRED. ${context5}, or write exactly "${HANDOFF_NOT_APPLICABLE_EXACT_TEXT}" with no explanation. Do not omit this section. -->`;
|
|
@@ -107014,214 +107661,6 @@ var init_builder = __esm(() => {
|
|
|
107014
107661
|
};
|
|
107015
107662
|
});
|
|
107016
107663
|
|
|
107017
|
-
// ../../services/backend/src/domain/usecase/enhancer/enhancer-handoff-content.ts
|
|
107018
|
-
var ENHANCER_USER_MESSAGE_PLACEHOLDER = "{{USER_MESSAGE}}";
|
|
107019
|
-
|
|
107020
|
-
// ../../services/backend/prompts/utils/data-query-design.ts
|
|
107021
|
-
function getDataQueryDesignTemplateBlock() {
|
|
107022
|
-
return `## Persistent state and query pattern design
|
|
107023
|
-
|
|
107024
|
-
**Goal:** Small updates must not cause large cache invalidations. High-frequency writes use projections to smaller tables.
|
|
107025
|
-
|
|
107026
|
-
### 1. Sources of concern
|
|
107027
|
-
| Source | Write frequency | Read pattern | Risk |
|
|
107028
|
-
|--------|---------------|--------------|------|
|
|
107029
|
-
| \`<table/mutation>\` | \`<frequency>\` | \`<pattern>\` | \`<scan / hot partition>\` |
|
|
107030
|
-
|
|
107031
|
-
### 2. Schema design
|
|
107032
|
-
**Hot path:** \`<table>\` — fields, projection from \`<source>\`
|
|
107033
|
-
**Cold path:** \`<table>\` — …
|
|
107034
|
-
|
|
107035
|
-
\`\`\`typescript
|
|
107036
|
-
// target schema shape
|
|
107037
|
-
\`\`\`
|
|
107038
|
-
|
|
107039
|
-
### 3. Index design (within limits)
|
|
107040
|
-
| Table | Index | Serves query | Budget |
|
|
107041
|
-
|-------|-------|--------------|--------|
|
|
107042
|
-
|
|
107043
|
-
### 4. Query design (within limits)
|
|
107044
|
-
| Query | Index | Rows scanned | Timeout | Invalidation scope |
|
|
107045
|
-
|-------|-------|--------------|---------|-------------------|
|
|
107046
|
-
|
|
107047
|
-
\`\`\`typescript
|
|
107048
|
-
// target query signature
|
|
107049
|
-
\`\`\`
|
|
107050
|
-
|
|
107051
|
-
<!-- Write exactly "Not Applicable." for the entire section if no persistence changes -->`;
|
|
107052
|
-
}
|
|
107053
|
-
|
|
107054
|
-
// ../../services/backend/prompts/utils/frontend-design-ux-checklist.ts
|
|
107055
|
-
function getFrontendDesignUxPlanningPrinciplesBlock() {
|
|
107056
|
-
return `<!-- Ground every flow in user history and repository patterns. Recommend one existing pattern when multiple exist; do not prescribe style choices the project has not adopted. -->`;
|
|
107057
|
-
}
|
|
107058
|
-
function getFrontendDesignUxFlowChecklistBlock() {
|
|
107059
|
-
return `**UX quality (complete for every interactive step in this flow):**
|
|
107060
|
-
- **States:** loading | empty | error | success — no blank panels, silent failures, or missing retry affordances
|
|
107061
|
-
- **Layout:** stable across async transitions — no layout shift when content arrives or state changes
|
|
107062
|
-
- **Patterns:** consistent with existing project components — cite the chosen pattern and repo-relative file
|
|
107063
|
-
- **Shortcuts:** aligned with project keyboard/shortcut conventions; document tab order and gaps
|
|
107064
|
-
- **Feedback:** timely response for async user actions
|
|
107065
|
-
- **Interaction affordance:** pointer cursor (or project equivalent) on clickable elements
|
|
107066
|
-
- **Safeguards:** confirmation before destructive actions; bulk operations confirmed with scope summary`;
|
|
107067
|
-
}
|
|
107068
|
-
|
|
107069
|
-
// ../../services/backend/prompts/utils/enhancer-feedback-template-body.ts
|
|
107070
|
-
function getEnhancerFeedbackTemplateBody() {
|
|
107071
|
-
return `<handoff-overview>
|
|
107072
|
-
## Summary
|
|
107073
|
-
<one paragraph: what we're building and the single design direction>
|
|
107074
|
-
|
|
107075
|
-
## User intent and constraints
|
|
107076
|
-
<explicit requirements from user messages; hard constraints that must not be violated>
|
|
107077
|
-
</handoff-overview>
|
|
107078
|
-
|
|
107079
|
-
<!-- UI collapses proofs, direction, frontend design, data design, and notes by default; overview and action required are expanded -->
|
|
107080
|
-
|
|
107081
|
-
<handoff-proofs>
|
|
107082
|
-
## Repository evidence
|
|
107083
|
-
<files read, current behavior verified, patterns reused — cite repo-relative paths and short snippets only>
|
|
107084
|
-
|
|
107085
|
-
${getHandoffQualityPrinciplesSectionBlock("design")}
|
|
107086
|
-
</handoff-proofs>
|
|
107087
|
-
|
|
107088
|
-
<handoff-direction>
|
|
107089
|
-
## Recommended design
|
|
107090
|
-
<!-- ONE design only. No Option A/B/C. -->
|
|
107091
|
-
|
|
107092
|
-
<2–4 sentences: the chosen architecture and why it fits the request and existing system>
|
|
107093
|
-
</handoff-direction>
|
|
107094
|
-
|
|
107095
|
-
<handoff-frontend-design>
|
|
107096
|
-
## Frontend / user-centric design
|
|
107097
|
-
|
|
107098
|
-
${getFrontendDesignUxPlanningPrinciplesBlock()}
|
|
107099
|
-
|
|
107100
|
-
### Flow 1: <name>
|
|
107101
|
-
**Entry:** User visits \`<route/page>\` from \`<source>\`.
|
|
107102
|
-
|
|
107103
|
-
| Step | User action | System response | UI state |
|
|
107104
|
-
|------|-------------|-----------------|----------|
|
|
107105
|
-
| 1 | User clicks \`<element label>\` | \`<navigation / modal / fetch>\` | \`<loading → success/error>\` |
|
|
107106
|
-
|
|
107107
|
-
${getFrontendDesignUxFlowChecklistBlock()}
|
|
107108
|
-
|
|
107109
|
-
**Expected interactions per element:**
|
|
107110
|
-
- \`<ElementName>\` (\`apps/webapp/src/...\`): click → \`<handler>\`; keyboard: \`<tab order>\`; disabled when \`<condition>\`
|
|
107111
|
-
|
|
107112
|
-
### Element, style, and layout specification
|
|
107113
|
-
|
|
107114
|
-
#### \`<ComponentName>\` — \`apps/webapp/src/path/to/Component.tsx\`
|
|
107115
|
-
**Change:** <create | modify>
|
|
107116
|
-
|
|
107117
|
-
**Layout:** \`<div className="...">\` — flex/grid, gaps, breakpoints
|
|
107118
|
-
|
|
107119
|
-
**States:** loading | empty | error | success
|
|
107120
|
-
|
|
107121
|
-
\`\`\`tsx
|
|
107122
|
-
export function ComponentName({ ... }: Props) {
|
|
107123
|
-
// target structure — props, classNames, branches
|
|
107124
|
-
}
|
|
107125
|
-
\`\`\`
|
|
107126
|
-
|
|
107127
|
-
<!-- Repeat per component; write exactly "Not Applicable." for the entire section if no UI -->
|
|
107128
|
-
</handoff-frontend-design>
|
|
107129
|
-
|
|
107130
|
-
<handoff-data-design>
|
|
107131
|
-
${getDataQueryDesignTemplateBlock()}
|
|
107132
|
-
</handoff-data-design>
|
|
107133
|
-
|
|
107134
|
-
<handoff-notes>
|
|
107135
|
-
## Open questions for user
|
|
107136
|
-
<decisions only the user can make, or write "Not Applicable.">
|
|
107137
|
-
</handoff-notes>
|
|
107138
|
-
|
|
107139
|
-
<handoff-action>
|
|
107140
|
-
## Recommended implementation sequence
|
|
107141
|
-
<!-- Ordered slices for the planner — references files from design sections. For large or multi-surface revisions, activate the defragmentation skill before delegating. -->
|
|
107142
|
-
|
|
107143
|
-
1. …
|
|
107144
|
-
2. …
|
|
107145
|
-
|
|
107146
|
-
## Files touched (index)
|
|
107147
|
-
- \`apps/webapp/src/...\` — …
|
|
107148
|
-
- \`services/backend/convex/...\` — …
|
|
107149
|
-
</handoff-action>`;
|
|
107150
|
-
}
|
|
107151
|
-
var init_enhancer_feedback_template_body = __esm(() => {
|
|
107152
|
-
init_handoff_quality_principles();
|
|
107153
|
-
});
|
|
107154
|
-
|
|
107155
|
-
// ../../services/backend/prompts/enhancer/handoff-templates.ts
|
|
107156
|
-
function roleLabel(role) {
|
|
107157
|
-
return role.charAt(0).toUpperCase() + role.slice(1).toLowerCase();
|
|
107158
|
-
}
|
|
107159
|
-
function getEntryPointToEnhancerHandoffTemplate(entryPointRole) {
|
|
107160
|
-
const label = roleLabel(entryPointRole);
|
|
107161
|
-
return `**Planning Request (${label} → Enhancer)** — after reading the user message and any pinned chatroom context, fill only <additional-context> below. The system injects the user message automatically — do not copy it.
|
|
107162
|
-
|
|
107163
|
-
\`\`\`markdown
|
|
107164
|
-
<user-message>
|
|
107165
|
-
<!-- Injected automatically from the originating user message — do not edit or copy the user message here -->
|
|
107166
|
-
${ENHANCER_USER_MESSAGE_PLACEHOLDER}
|
|
107167
|
-
</user-message>
|
|
107168
|
-
|
|
107169
|
-
<additional-context>
|
|
107170
|
-
## Goal
|
|
107171
|
-
<what the user wants in plain language — one short paragraph>
|
|
107172
|
-
</additional-context>
|
|
107173
|
-
\`\`\`
|
|
107174
|
-
|
|
107175
|
-
After handoff succeeds, **end your turn immediately**. The enhancer independently downloads the originating message history and returns design input as your next ${entryPointRole.toLowerCase()} task.`;
|
|
107176
|
-
}
|
|
107177
|
-
function getEnhancerToEntryPointHandoffTemplate(entryPointRole) {
|
|
107178
|
-
const normalizedRole = entryPointRole.toLowerCase();
|
|
107179
|
-
const label = roleLabel(entryPointRole);
|
|
107180
|
-
return `**Design Input (Enhancer → ${label})**
|
|
107181
|
-
|
|
107182
|
-
You are the design authority for this request. Recover conversation history, inspect the repository, and return **one** complete design — not options. The ${normalizedRole} agent verifies your design and delegates implementation.
|
|
107183
|
-
|
|
107184
|
-
**Rules:**
|
|
107185
|
-
- Design first — complete frontend and data/query sections before implementation sequencing.
|
|
107186
|
-
- **No alternative approaches** — one \`Recommended design\` only.
|
|
107187
|
-
- Frontend and data sections: code granularity (component names, props, classes, file paths, schema, indexes, queries).
|
|
107188
|
-
- Complete per-flow **UX quality** checklist in frontend design — states, layout stability, patterns, safeguards.
|
|
107189
|
-
- For large or multi-surface revisions, note in implementation sequence that the entry point should activate the \`defragmentation\` skill.
|
|
107190
|
-
- In \`<handoff-proofs>\`, complete **Proof of Principles** for how this design satisfies each quality principle (or "Not Applicable.").
|
|
107191
|
-
- Write "Not Applicable." only when a major design section truly does not apply.
|
|
107192
|
-
|
|
107193
|
-
\`\`\`markdown
|
|
107194
|
-
${getEnhancerFeedbackTemplateBody()}
|
|
107195
|
-
\`\`\`
|
|
107196
|
-
|
|
107197
|
-
Return only the design input markdown — no preamble. Follow this structure; use "Not Applicable." where a major section does not apply.`;
|
|
107198
|
-
}
|
|
107199
|
-
var init_handoff_templates = __esm(() => {
|
|
107200
|
-
init_enhancer_feedback_template_body();
|
|
107201
|
-
});
|
|
107202
|
-
|
|
107203
|
-
// ../../services/backend/prompts/teams/duo/handoff-templates/enhancer-to-planner.ts
|
|
107204
|
-
function getEnhancerToPlannerHandoffTemplate() {
|
|
107205
|
-
return getEnhancerToEntryPointHandoffTemplate("planner");
|
|
107206
|
-
}
|
|
107207
|
-
var init_enhancer_to_planner = __esm(() => {
|
|
107208
|
-
init_handoff_templates();
|
|
107209
|
-
});
|
|
107210
|
-
|
|
107211
|
-
// ../../services/backend/prompts/teams/duo/handoff-templates/enhancer.ts
|
|
107212
|
-
var duoEnhancerHandoffContract;
|
|
107213
|
-
var init_enhancer = __esm(() => {
|
|
107214
|
-
init_enhancer_to_planner();
|
|
107215
|
-
duoEnhancerHandoffContract = {
|
|
107216
|
-
role: "enhancer",
|
|
107217
|
-
receivesFrom: ["planner"],
|
|
107218
|
-
returnsTo: ["planner"],
|
|
107219
|
-
outboundTemplates: {
|
|
107220
|
-
planner: () => getEnhancerToPlannerHandoffTemplate()
|
|
107221
|
-
}
|
|
107222
|
-
};
|
|
107223
|
-
});
|
|
107224
|
-
|
|
107225
107664
|
// ../../services/backend/prompts/teams/duo/handoff-templates/planner-to-builder.ts
|
|
107226
107665
|
function getPlannerToBuilderHandoffTemplate() {
|
|
107227
107666
|
return `${getHandoffRecipientVisibilityCallout("builder")}
|
|
@@ -107298,14 +107737,6 @@ Keep one slice ≈ one focused review surface. Delegate slices incrementally —
|
|
|
107298
107737
|
}
|
|
107299
107738
|
var init_planner_to_builder = () => {};
|
|
107300
107739
|
|
|
107301
|
-
// ../../services/backend/prompts/teams/duo/handoff-templates/planner-to-enhancer.ts
|
|
107302
|
-
function getPlannerToEnhancerHandoffTemplate() {
|
|
107303
|
-
return getEntryPointToEnhancerHandoffTemplate("planner");
|
|
107304
|
-
}
|
|
107305
|
-
var init_planner_to_enhancer = __esm(() => {
|
|
107306
|
-
init_handoff_templates();
|
|
107307
|
-
});
|
|
107308
|
-
|
|
107309
107740
|
// ../../services/backend/prompts/utils/context-disclosure.ts
|
|
107310
107741
|
function getContextReadDisclosureComment(params = {}) {
|
|
107311
107742
|
const command = contextReadCommand(params);
|
|
@@ -107493,16 +107924,18 @@ var init_chat_handoff_template = () => {};
|
|
|
107493
107924
|
var duoPlannerHandoffContract;
|
|
107494
107925
|
var init_planner = __esm(() => {
|
|
107495
107926
|
init_planner_to_builder();
|
|
107496
|
-
init_planner_to_enhancer();
|
|
107497
107927
|
init_planner_to_user();
|
|
107498
107928
|
init_chat_handoff_template();
|
|
107929
|
+
init_architect_handoff_templates();
|
|
107930
|
+
init_uiux_engineer_handoff_templates();
|
|
107499
107931
|
duoPlannerHandoffContract = {
|
|
107500
107932
|
role: "planner",
|
|
107501
|
-
receivesFrom: ["user", "builder", "
|
|
107502
|
-
returnsTo: ["builder", "
|
|
107933
|
+
receivesFrom: ["user", "builder", "architect", "uiux-engineer"],
|
|
107934
|
+
returnsTo: ["builder", "architect", "uiux-engineer", "user"],
|
|
107503
107935
|
outboundTemplates: {
|
|
107504
107936
|
builder: () => getPlannerToBuilderHandoffTemplate(),
|
|
107505
|
-
|
|
107937
|
+
architect: () => getEntryPointToArchitectHandoffTemplate("planner"),
|
|
107938
|
+
"uiux-engineer": () => getEntryPointToUiuxEngineerHandoffTemplate("planner"),
|
|
107506
107939
|
user: (query) => query.conversationMode === "chat" ? getChatToUserHandoffTemplate() : getPlannerToUserReportTemplate({
|
|
107507
107940
|
chatroomId: query.chatroomId,
|
|
107508
107941
|
role: query.role,
|
|
@@ -107512,6 +107945,20 @@ var init_planner = __esm(() => {
|
|
|
107512
107945
|
};
|
|
107513
107946
|
});
|
|
107514
107947
|
|
|
107948
|
+
// ../../services/backend/prompts/teams/duo/handoff-templates/uiux-engineer.ts
|
|
107949
|
+
var duoUiuxEngineerHandoffContract;
|
|
107950
|
+
var init_uiux_engineer = __esm(() => {
|
|
107951
|
+
init_uiux_engineer_handoff_templates();
|
|
107952
|
+
duoUiuxEngineerHandoffContract = {
|
|
107953
|
+
role: "uiux-engineer",
|
|
107954
|
+
receivesFrom: ["planner"],
|
|
107955
|
+
returnsTo: ["planner"],
|
|
107956
|
+
outboundTemplates: {
|
|
107957
|
+
planner: () => getUiuxEngineerToEntryPointHandoffTemplate("planner")
|
|
107958
|
+
}
|
|
107959
|
+
};
|
|
107960
|
+
});
|
|
107961
|
+
|
|
107515
107962
|
// ../../services/backend/prompts/cli/handoff-templates/contracts.ts
|
|
107516
107963
|
function validateRoleHandoffContracts(contracts) {
|
|
107517
107964
|
const byRole = new Map;
|
|
@@ -107552,14 +107999,16 @@ function getDuoHandoffTemplate(query) {
|
|
|
107552
107999
|
return getter?.(query) ?? null;
|
|
107553
108000
|
}
|
|
107554
108001
|
var DUO_ROLE_HANDOFF_CONTRACTS, validatedDuoRoleHandoffContracts;
|
|
107555
|
-
var
|
|
108002
|
+
var init_handoff_templates = __esm(() => {
|
|
108003
|
+
init_architect();
|
|
107556
108004
|
init_builder();
|
|
107557
|
-
init_enhancer();
|
|
107558
108005
|
init_planner();
|
|
108006
|
+
init_uiux_engineer();
|
|
107559
108007
|
DUO_ROLE_HANDOFF_CONTRACTS = [
|
|
107560
108008
|
duoPlannerHandoffContract,
|
|
107561
108009
|
duoBuilderHandoffContract,
|
|
107562
|
-
|
|
108010
|
+
duoArchitectHandoffContract,
|
|
108011
|
+
duoUiuxEngineerHandoffContract
|
|
107563
108012
|
];
|
|
107564
108013
|
validatedDuoRoleHandoffContracts = (() => {
|
|
107565
108014
|
validateRoleHandoffContracts(DUO_ROLE_HANDOFF_CONTRACTS);
|
|
@@ -107567,16 +108016,16 @@ var init_handoff_templates2 = __esm(() => {
|
|
|
107567
108016
|
})();
|
|
107568
108017
|
});
|
|
107569
108018
|
|
|
107570
|
-
// ../../services/backend/prompts/teams/solo/handoff-templates/
|
|
107571
|
-
var
|
|
107572
|
-
var
|
|
107573
|
-
|
|
107574
|
-
|
|
107575
|
-
role: "
|
|
108019
|
+
// ../../services/backend/prompts/teams/solo/handoff-templates/architect.ts
|
|
108020
|
+
var soloArchitectHandoffContract;
|
|
108021
|
+
var init_architect2 = __esm(() => {
|
|
108022
|
+
init_architect_handoff_templates();
|
|
108023
|
+
soloArchitectHandoffContract = {
|
|
108024
|
+
role: "architect",
|
|
107576
108025
|
receivesFrom: ["solo"],
|
|
107577
108026
|
returnsTo: ["solo"],
|
|
107578
108027
|
outboundTemplates: {
|
|
107579
|
-
solo: () =>
|
|
108028
|
+
solo: () => getArchitectToEntryPointHandoffTemplate("solo")
|
|
107580
108029
|
}
|
|
107581
108030
|
};
|
|
107582
108031
|
});
|
|
@@ -107599,14 +108048,16 @@ var init_solo_to_user = __esm(() => {
|
|
|
107599
108048
|
var soloHandoffContract;
|
|
107600
108049
|
var init_solo = __esm(() => {
|
|
107601
108050
|
init_solo_to_user();
|
|
107602
|
-
init_handoff_templates();
|
|
107603
108051
|
init_chat_handoff_template();
|
|
108052
|
+
init_architect_handoff_templates();
|
|
108053
|
+
init_uiux_engineer_handoff_templates();
|
|
107604
108054
|
soloHandoffContract = {
|
|
107605
108055
|
role: "solo",
|
|
107606
|
-
receivesFrom: ["user", "
|
|
107607
|
-
returnsTo: ["
|
|
108056
|
+
receivesFrom: ["user", "architect", "uiux-engineer"],
|
|
108057
|
+
returnsTo: ["architect", "uiux-engineer", "user"],
|
|
107608
108058
|
outboundTemplates: {
|
|
107609
|
-
|
|
108059
|
+
architect: () => getEntryPointToArchitectHandoffTemplate("solo"),
|
|
108060
|
+
"uiux-engineer": () => getEntryPointToUiuxEngineerHandoffTemplate("solo"),
|
|
107610
108061
|
user: (query) => query.conversationMode === "chat" ? getChatToUserHandoffTemplate() : getSoloToUserReportTemplate({
|
|
107611
108062
|
chatroomId: query.chatroomId,
|
|
107612
108063
|
role: query.role,
|
|
@@ -107616,6 +108067,20 @@ var init_solo = __esm(() => {
|
|
|
107616
108067
|
};
|
|
107617
108068
|
});
|
|
107618
108069
|
|
|
108070
|
+
// ../../services/backend/prompts/teams/solo/handoff-templates/uiux-engineer.ts
|
|
108071
|
+
var soloUiuxEngineerHandoffContract;
|
|
108072
|
+
var init_uiux_engineer2 = __esm(() => {
|
|
108073
|
+
init_uiux_engineer_handoff_templates();
|
|
108074
|
+
soloUiuxEngineerHandoffContract = {
|
|
108075
|
+
role: "uiux-engineer",
|
|
108076
|
+
receivesFrom: ["solo"],
|
|
108077
|
+
returnsTo: ["solo"],
|
|
108078
|
+
outboundTemplates: {
|
|
108079
|
+
solo: () => getUiuxEngineerToEntryPointHandoffTemplate("solo")
|
|
108080
|
+
}
|
|
108081
|
+
};
|
|
108082
|
+
});
|
|
108083
|
+
|
|
107619
108084
|
// ../../services/backend/prompts/teams/solo/handoff-templates/index.ts
|
|
107620
108085
|
function listSoloRoleHandoffContracts() {
|
|
107621
108086
|
return validatedSoloRoleHandoffContracts;
|
|
@@ -107628,12 +108093,14 @@ function getSoloHandoffTemplate(query) {
|
|
|
107628
108093
|
return getter?.(query) ?? null;
|
|
107629
108094
|
}
|
|
107630
108095
|
var SOLO_ROLE_HANDOFF_CONTRACTS, validatedSoloRoleHandoffContracts;
|
|
107631
|
-
var
|
|
107632
|
-
|
|
108096
|
+
var init_handoff_templates2 = __esm(() => {
|
|
108097
|
+
init_architect2();
|
|
107633
108098
|
init_solo();
|
|
108099
|
+
init_uiux_engineer2();
|
|
107634
108100
|
SOLO_ROLE_HANDOFF_CONTRACTS = [
|
|
107635
108101
|
soloHandoffContract,
|
|
107636
|
-
|
|
108102
|
+
soloArchitectHandoffContract,
|
|
108103
|
+
soloUiuxEngineerHandoffContract
|
|
107637
108104
|
];
|
|
107638
108105
|
validatedSoloRoleHandoffContracts = (() => {
|
|
107639
108106
|
validateRoleHandoffContracts(SOLO_ROLE_HANDOFF_CONTRACTS);
|
|
@@ -107691,13 +108158,21 @@ function getHandoffTemplate(query) {
|
|
|
107691
108158
|
return getSoloHandoffTemplate(query);
|
|
107692
108159
|
return null;
|
|
107693
108160
|
}
|
|
107694
|
-
var
|
|
108161
|
+
var init_handoff_templates3 = __esm(() => {
|
|
108162
|
+
init_handoff_templates();
|
|
107695
108163
|
init_handoff_templates2();
|
|
107696
|
-
init_handoff_templates3();
|
|
107697
108164
|
});
|
|
107698
108165
|
|
|
107699
108166
|
// ../../services/backend/prompts/cli/handoff/view-template.ts
|
|
107700
108167
|
function viewHandoffTemplate(params) {
|
|
108168
|
+
if (params.nextRole === undefined) {
|
|
108169
|
+
const role = params.role.trim().toLowerCase();
|
|
108170
|
+
if (role === "architect")
|
|
108171
|
+
return getGenericArchitectToEntryPointHandoffTemplate();
|
|
108172
|
+
if (role === "uiux-engineer")
|
|
108173
|
+
return getGenericUiuxEngineerToEntryPointHandoffTemplate();
|
|
108174
|
+
throw new Error(`Role-only handoff template viewing is supported only for architect or uiux-engineer, not ${params.role}`);
|
|
108175
|
+
}
|
|
107701
108176
|
const template = getHandoffTemplate({
|
|
107702
108177
|
fromRole: params.role,
|
|
107703
108178
|
toRole: params.nextRole,
|
|
@@ -107710,7 +108185,9 @@ function viewHandoffTemplate(params) {
|
|
|
107710
108185
|
return template;
|
|
107711
108186
|
}
|
|
107712
108187
|
var init_view_template2 = __esm(() => {
|
|
107713
|
-
|
|
108188
|
+
init_architect_handoff_templates();
|
|
108189
|
+
init_uiux_engineer_handoff_templates();
|
|
108190
|
+
init_handoff_templates3();
|
|
107714
108191
|
});
|
|
107715
108192
|
|
|
107716
108193
|
// src/commands/handoff/view-template.ts
|
|
@@ -107755,12 +108232,12 @@ function listHandoffTemplatesCommand(params) {
|
|
|
107755
108232
|
});
|
|
107756
108233
|
if (!listing) {
|
|
107757
108234
|
const teamId = params.teamId ?? "duo";
|
|
107758
|
-
throw new Error(`No handoff contract for role "${params.role}" in team "${teamId}". Known roles: planner, builder
|
|
108235
|
+
throw new Error(`No handoff contract for role "${params.role}" in team "${teamId}". Known roles: planner, builder (duo) or solo.`);
|
|
107759
108236
|
}
|
|
107760
108237
|
return formatHandoffTemplateListing(listing);
|
|
107761
108238
|
}
|
|
107762
108239
|
var init_list_templates = __esm(() => {
|
|
107763
|
-
|
|
108240
|
+
init_handoff_templates3();
|
|
107764
108241
|
});
|
|
107765
108242
|
|
|
107766
108243
|
// src/commands/handoff/list-templates.ts
|
|
@@ -107944,36 +108421,26 @@ function getHandoffTurnEndGuidance(nextRole) {
|
|
|
107944
108421
|
return lines.join(`
|
|
107945
108422
|
`);
|
|
107946
108423
|
}
|
|
107947
|
-
function getNativeEnhancerRequestTurnEndGuidance() {
|
|
107948
|
-
return [
|
|
107949
|
-
"",
|
|
107950
|
-
"**Handoff complete. End your turn now — stop tool calls. The system will send you a message when further action is required.**",
|
|
107951
|
-
"Do **not** wait for enhancer input, poll, or monitor the enhancer job in this turn. The system delivers independent planning input as your next task when analysis completes."
|
|
107952
|
-
].join(`
|
|
107953
|
-
`);
|
|
107954
|
-
}
|
|
107955
108424
|
// ../../services/backend/prompts/sections/activated-skills.ts
|
|
107956
108425
|
var init_activated_skills = () => {};
|
|
107957
108426
|
|
|
107958
108427
|
// ../../services/backend/prompts/cli/backlog/command.ts
|
|
107959
|
-
var
|
|
108428
|
+
var init_command3 = __esm(() => {
|
|
107960
108429
|
init_stdin_heredoc();
|
|
107961
108430
|
});
|
|
107962
108431
|
|
|
107963
108432
|
// ../../services/backend/src/domain/usecase/skills/modules/backlog/index.ts
|
|
107964
108433
|
var init_backlog = __esm(() => {
|
|
107965
|
-
|
|
108434
|
+
init_command3();
|
|
107966
108435
|
});
|
|
107967
108436
|
|
|
107968
108437
|
// ../../services/backend/src/domain/usecase/skills/modules/code-review/index.ts
|
|
107969
108438
|
var init_code_review = () => {};
|
|
107970
|
-
|
|
107971
108439
|
// ../../services/backend/src/domain/usecase/skills/modules/data-design/index.ts
|
|
107972
108440
|
var init_data_design = () => {};
|
|
107973
108441
|
|
|
107974
108442
|
// ../../services/backend/src/domain/usecase/skills/modules/defragmentation/index.ts
|
|
107975
108443
|
var init_defragmentation = () => {};
|
|
107976
|
-
|
|
107977
108444
|
// ../../services/backend/src/domain/usecase/skills/modules/user-centricity/index.ts
|
|
107978
108445
|
var init_user_centricity = () => {};
|
|
107979
108446
|
|
|
@@ -108062,19 +108529,17 @@ var init_general_knowledge = __esm(() => {
|
|
|
108062
108529
|
init_utils3();
|
|
108063
108530
|
});
|
|
108064
108531
|
|
|
108065
|
-
// ../../services/backend/prompts/cli/handoff/command.ts
|
|
108066
|
-
var init_command3 = __esm(() => {
|
|
108067
|
-
init_stdin_heredoc();
|
|
108068
|
-
});
|
|
108069
|
-
|
|
108070
108532
|
// ../../services/backend/prompts/sections/commands-reference.ts
|
|
108071
108533
|
var init_commands_reference = __esm(() => {
|
|
108072
108534
|
init_general_knowledge();
|
|
108073
108535
|
init_command();
|
|
108074
108536
|
init_reminder();
|
|
108075
|
-
|
|
108537
|
+
init_command2();
|
|
108076
108538
|
init_utils3();
|
|
108077
108539
|
});
|
|
108540
|
+
|
|
108541
|
+
// ../../services/backend/prompts/cli/roles/architect.ts
|
|
108542
|
+
var init_architect3 = () => {};
|
|
108078
108543
|
// ../../services/backend/prompts/cli/sections/core-responsibilities.ts
|
|
108079
108544
|
var init_core_responsibilities = () => {};
|
|
108080
108545
|
// ../../services/backend/prompts/cli/sections/handoff-rules.ts
|
|
@@ -108098,24 +108563,15 @@ var init_builder2 = __esm(() => {
|
|
|
108098
108563
|
init_sections();
|
|
108099
108564
|
});
|
|
108100
108565
|
|
|
108101
|
-
// ../../services/backend/prompts/enhancer/history-retrieval.ts
|
|
108102
|
-
var init_history_retrieval = __esm(() => {
|
|
108103
|
-
init_guidance();
|
|
108104
|
-
});
|
|
108105
|
-
|
|
108106
|
-
// ../../services/backend/prompts/cli/roles/enhancer.ts
|
|
108107
|
-
var init_enhancer3 = __esm(() => {
|
|
108108
|
-
init_history_retrieval();
|
|
108109
|
-
init_env();
|
|
108110
|
-
init_sections();
|
|
108111
|
-
});
|
|
108112
|
-
|
|
108113
108566
|
// ../../services/backend/prompts/cli/roles/planner.ts
|
|
108114
108567
|
var init_planner2 = __esm(() => {
|
|
108115
108568
|
init_env();
|
|
108116
108569
|
init_sections();
|
|
108117
108570
|
});
|
|
108118
108571
|
|
|
108572
|
+
// ../../services/backend/prompts/cli/roles/uiux-engineer.ts
|
|
108573
|
+
var init_uiux_engineer3 = () => {};
|
|
108574
|
+
|
|
108119
108575
|
// ../../services/backend/prompts/cli/roles/planner-guidance-context.ts
|
|
108120
108576
|
var init_planner_guidance_context = __esm(() => {
|
|
108121
108577
|
init_env();
|
|
@@ -108127,12 +108583,18 @@ var init_solo2 = __esm(() => {
|
|
|
108127
108583
|
init_sections();
|
|
108128
108584
|
});
|
|
108129
108585
|
|
|
108130
|
-
// ../../services/backend/prompts/
|
|
108586
|
+
// ../../services/backend/prompts/teams/solo/prompts/fromContext.ts
|
|
108131
108587
|
var init_fromContext = __esm(() => {
|
|
108588
|
+
init_solo2();
|
|
108589
|
+
});
|
|
108590
|
+
|
|
108591
|
+
// ../../services/backend/prompts/cli/roles/fromContext.ts
|
|
108592
|
+
var init_fromContext2 = __esm(() => {
|
|
108593
|
+
init_architect3();
|
|
108132
108594
|
init_builder2();
|
|
108133
|
-
init_enhancer3();
|
|
108134
108595
|
init_planner2();
|
|
108135
|
-
|
|
108596
|
+
init_uiux_engineer3();
|
|
108597
|
+
init_fromContext();
|
|
108136
108598
|
});
|
|
108137
108599
|
|
|
108138
108600
|
// ../../services/backend/prompts/teams/duo/prompts/builder.ts
|
|
@@ -108147,20 +108609,15 @@ var init_planner3 = __esm(() => {
|
|
|
108147
108609
|
});
|
|
108148
108610
|
|
|
108149
108611
|
// ../../services/backend/prompts/teams/duo/prompts/fromContext.ts
|
|
108150
|
-
var
|
|
108612
|
+
var init_fromContext3 = __esm(() => {
|
|
108151
108613
|
init_builder3();
|
|
108152
108614
|
init_planner3();
|
|
108153
108615
|
});
|
|
108154
|
-
|
|
108155
|
-
// ../../services/backend/prompts/teams/solo/prompts/fromContext.ts
|
|
108156
|
-
var init_fromContext3 = __esm(() => {
|
|
108157
|
-
init_solo2();
|
|
108158
|
-
});
|
|
108159
108616
|
// ../../services/backend/prompts/selector-context.ts
|
|
108160
108617
|
var init_selector_context = __esm(() => {
|
|
108161
|
-
init_fromContext();
|
|
108162
108618
|
init_fromContext2();
|
|
108163
108619
|
init_fromContext3();
|
|
108620
|
+
init_fromContext();
|
|
108164
108621
|
});
|
|
108165
108622
|
|
|
108166
108623
|
// ../../services/backend/prompts/sections/role-guidance.ts
|
|
@@ -108169,7 +108626,9 @@ var init_role_guidance = __esm(() => {
|
|
|
108169
108626
|
});
|
|
108170
108627
|
|
|
108171
108628
|
// ../../services/backend/prompts/templates.ts
|
|
108172
|
-
var init_templates = () => {
|
|
108629
|
+
var init_templates = __esm(() => {
|
|
108630
|
+
init_agent_role();
|
|
108631
|
+
});
|
|
108173
108632
|
|
|
108174
108633
|
// ../../services/backend/prompts/sections/role-identity.ts
|
|
108175
108634
|
var init_role_identity = __esm(() => {
|
|
@@ -108216,40 +108675,12 @@ var init_session_vs_chatroom_task = () => {};
|
|
|
108216
108675
|
// ../../services/backend/prompts/review-guidelines/index.ts
|
|
108217
108676
|
var init_review_guidelines = () => {};
|
|
108218
108677
|
// ../../services/backend/prompts/generator.ts
|
|
108219
|
-
function isEnhancerRequestQueuedHandoff(params) {
|
|
108220
|
-
return params.enhancerRequestQueued === true && params.nextRole.toLowerCase() === "enhancer";
|
|
108221
|
-
}
|
|
108222
|
-
function getEnhancerRequestQueuedConfirmationLines(nativeIntegration) {
|
|
108223
|
-
const turnEndRule = nativeIntegration ? "**Handoff complete. End your turn now — stop tool calls. The system will send you a message when further action is required.** Do **not** wait for enhancer input, poll, monitor the enhancer, or re-submit the handoff. The system delivers independent planning input as your next task when analysis completes." : "**Run get-next-task now and end your turn — stop tool calls. The system will send you a message when further action is required.** Do **not** wait for enhancer input, poll, monitor the enhancer, or re-submit the handoff.";
|
|
108224
|
-
return [
|
|
108225
|
-
"✅ User request queued for handoff enhancer",
|
|
108226
|
-
"",
|
|
108227
|
-
"The user request was sent to the handoff enhancer (async). You will receive independent planning input as your next task when analysis completes.",
|
|
108228
|
-
turnEndRule
|
|
108229
|
-
];
|
|
108230
|
-
}
|
|
108231
108678
|
function generateHandoffOutput(params) {
|
|
108232
|
-
const {
|
|
108233
|
-
role,
|
|
108234
|
-
nextRole,
|
|
108235
|
-
chatroomId,
|
|
108236
|
-
convexUrl,
|
|
108237
|
-
supportsNativeIntegration,
|
|
108238
|
-
enhancerRequestQueued
|
|
108239
|
-
} = params;
|
|
108679
|
+
const { role, nextRole, chatroomId, convexUrl, supportsNativeIntegration } = params;
|
|
108240
108680
|
const cliEnvPrefix = getCliEnvPrefix(convexUrl);
|
|
108241
|
-
const
|
|
108242
|
-
nextRole,
|
|
108243
|
-
enhancerRequestQueued
|
|
108244
|
-
});
|
|
108245
|
-
const lines = [];
|
|
108246
|
-
if (enhancerRequest) {
|
|
108247
|
-
lines.push(...getEnhancerRequestQueuedConfirmationLines(supportsNativeIntegration));
|
|
108248
|
-
} else {
|
|
108249
|
-
lines.push(`✅ Chatroom task completed and handed off to ${nextRole}`);
|
|
108250
|
-
}
|
|
108681
|
+
const lines = [`✅ Chatroom task completed and handed off to ${nextRole}`];
|
|
108251
108682
|
if (supportsNativeIntegration) {
|
|
108252
|
-
lines.push(
|
|
108683
|
+
lines.push(getNativeHandoffTurnEndGuidance(nextRole));
|
|
108253
108684
|
} else {
|
|
108254
108685
|
lines.push("");
|
|
108255
108686
|
lines.push("✅ Level B complete (chatroom task handed off).");
|
|
@@ -108280,6 +108711,21 @@ var init_generator = __esm(() => {
|
|
|
108280
108711
|
init_review_guidelines();
|
|
108281
108712
|
});
|
|
108282
108713
|
|
|
108714
|
+
// src/infrastructure/cli-gateway/local-handoff-gateway.ts
|
|
108715
|
+
function createLocalHandoffGateway() {
|
|
108716
|
+
return {
|
|
108717
|
+
handoff: (args2) => requestLocalDaemon(resolveLocalWebPort(), "cli.handoff", args2).catch((error51) => {
|
|
108718
|
+
if (error51 instanceof LocalDaemonServerError)
|
|
108719
|
+
throw error51;
|
|
108720
|
+
throw new Error(`CLI gateway unavailable. Start the Chatroom daemon and retry. ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
108721
|
+
})
|
|
108722
|
+
};
|
|
108723
|
+
}
|
|
108724
|
+
var init_local_handoff_gateway = __esm(() => {
|
|
108725
|
+
init_local_daemon();
|
|
108726
|
+
init_resolve_local_web_port();
|
|
108727
|
+
});
|
|
108728
|
+
|
|
108283
108729
|
// src/infrastructure/deps/create-convex-command-deps.ts
|
|
108284
108730
|
async function createConvexCommandDeps() {
|
|
108285
108731
|
const client4 = await getConvexClient();
|
|
@@ -108305,7 +108751,8 @@ __export(exports_handoff, {
|
|
|
108305
108751
|
handoff: () => handoff
|
|
108306
108752
|
});
|
|
108307
108753
|
async function createDefaultDeps10() {
|
|
108308
|
-
|
|
108754
|
+
const deps = await createConvexCommandDeps();
|
|
108755
|
+
return { backend: deps.backend, gateway: createLocalHandoffGateway(), session: deps.session };
|
|
108309
108756
|
}
|
|
108310
108757
|
function handleHandoffError(err) {
|
|
108311
108758
|
return exports_Effect.sync(() => {
|
|
@@ -108376,27 +108823,24 @@ async function handoff(chatroomId, options, deps) {
|
|
|
108376
108823
|
}
|
|
108377
108824
|
var handoffEffect = (chatroomId, options) => exports_Effect.gen(function* () {
|
|
108378
108825
|
const session2 = yield* SessionService;
|
|
108379
|
-
const
|
|
108826
|
+
const gateway = yield* CliGatewayService;
|
|
108380
108827
|
const { role, message, nextRole } = options;
|
|
108381
|
-
const sessionId = yield*
|
|
108382
|
-
|
|
108383
|
-
|
|
108384
|
-
|
|
108385
|
-
|
|
108386
|
-
|
|
108387
|
-
|
|
108388
|
-
|
|
108389
|
-
|
|
108390
|
-
|
|
108391
|
-
sessionId,
|
|
108392
|
-
chatroomId,
|
|
108393
|
-
senderRole: role,
|
|
108394
|
-
content: message,
|
|
108395
|
-
targetRole: nextRole
|
|
108828
|
+
const sessionId = yield* requireSessionForChatroomEffect({ chatroomId });
|
|
108829
|
+
const result = yield* exports_Effect.tryPromise({
|
|
108830
|
+
try: () => gateway.handoff({
|
|
108831
|
+
sessionId,
|
|
108832
|
+
chatroomId,
|
|
108833
|
+
senderRole: role,
|
|
108834
|
+
content: message,
|
|
108835
|
+
targetRole: nextRole
|
|
108836
|
+
}),
|
|
108837
|
+
catch: (cause3) => cause3 instanceof Error ? cause3 : new Error(String(cause3))
|
|
108396
108838
|
}).pipe(exports_Effect.mapError((cause3) => {
|
|
108397
108839
|
let errorData;
|
|
108398
108840
|
if (cause3 instanceof ConvexError) {
|
|
108399
108841
|
errorData = cause3.data;
|
|
108842
|
+
} else if (cause3 instanceof LocalDaemonServerError && cause3.details) {
|
|
108843
|
+
errorData = cause3.details;
|
|
108400
108844
|
}
|
|
108401
108845
|
return { _tag: "HandoffFailed", cause: cause3, errorData };
|
|
108402
108846
|
}));
|
|
@@ -108413,8 +108857,7 @@ var handoffEffect = (chatroomId, options) => exports_Effect.gen(function* () {
|
|
|
108413
108857
|
nextRole,
|
|
108414
108858
|
chatroomId,
|
|
108415
108859
|
convexUrl,
|
|
108416
|
-
supportsNativeIntegration: result.supportsNativeIntegration
|
|
108417
|
-
enhancerRequestQueued: result.enhancerRequestQueued === true
|
|
108860
|
+
supportsNativeIntegration: result.supportsNativeIntegration
|
|
108418
108861
|
}));
|
|
108419
108862
|
});
|
|
108420
108863
|
});
|
|
@@ -108422,7 +108865,8 @@ var init_handoff = __esm(() => {
|
|
|
108422
108865
|
init_generator();
|
|
108423
108866
|
init_values();
|
|
108424
108867
|
init_esm();
|
|
108425
|
-
|
|
108868
|
+
init_local_daemon();
|
|
108869
|
+
init_local_handoff_gateway();
|
|
108426
108870
|
init_create_convex_command_deps();
|
|
108427
108871
|
init_services();
|
|
108428
108872
|
init_error_formatting();
|
|
@@ -109711,15 +110155,7 @@ async function activateSkill(chatroomId, skillId, options, deps) {
|
|
|
109711
110155
|
}
|
|
109712
110156
|
var listSkillsEffect = (chatroomId, _options) => exports_Effect.gen(function* () {
|
|
109713
110157
|
const backend2 = yield* BackendService;
|
|
109714
|
-
const sessionId = yield*
|
|
109715
|
-
_tag: "NotAuthenticated",
|
|
109716
|
-
convexUrl: a.convexUrl,
|
|
109717
|
-
otherUrls: a.otherUrls
|
|
109718
|
-
}));
|
|
109719
|
-
yield* validateChatroomIdEffect(chatroomId, (id3) => ({
|
|
109720
|
-
_tag: "InvalidChatroomId",
|
|
109721
|
-
id: id3
|
|
109722
|
-
}));
|
|
110158
|
+
const sessionId = yield* requireSessionForChatroomEffect({ chatroomId });
|
|
109723
110159
|
const skills = yield* backend2.query(api.skills.list, {
|
|
109724
110160
|
sessionId,
|
|
109725
110161
|
chatroomId
|
|
@@ -109739,15 +110175,7 @@ var listSkillsEffect = (chatroomId, _options) => exports_Effect.gen(function* ()
|
|
|
109739
110175
|
}), activateSkillEffect = (chatroomId, skillId, options) => exports_Effect.gen(function* () {
|
|
109740
110176
|
const session2 = yield* SessionService;
|
|
109741
110177
|
const backend2 = yield* BackendService;
|
|
109742
|
-
const sessionId = yield*
|
|
109743
|
-
_tag: "NotAuthenticated",
|
|
109744
|
-
convexUrl: a.convexUrl,
|
|
109745
|
-
otherUrls: a.otherUrls
|
|
109746
|
-
}));
|
|
109747
|
-
yield* validateChatroomIdEffect(chatroomId, (id3) => ({
|
|
109748
|
-
_tag: "InvalidChatroomId",
|
|
109749
|
-
id: id3
|
|
109750
|
-
}));
|
|
110178
|
+
const sessionId = yield* requireSessionForChatroomEffect({ chatroomId });
|
|
109751
110179
|
const convexUrl = yield* session2.getConvexUrl();
|
|
109752
110180
|
const result = yield* backend2.mutation(api.skills.activate, {
|
|
109753
110181
|
sessionId,
|
|
@@ -110163,15 +110591,7 @@ var PAGE_SIZE = 50, SINCE_PAGE_SIZE = 500, ABSOLUTE_MAX = 5000, DEFAULT_LIMIT =
|
|
|
110163
110591
|
}), downloadMessagesEffect = (chatroomId, options) => exports_Effect.gen(function* () {
|
|
110164
110592
|
const backend2 = yield* BackendService;
|
|
110165
110593
|
const fs11 = yield* MessagesFsService;
|
|
110166
|
-
const sessionId = yield*
|
|
110167
|
-
_tag: "NotAuthenticated",
|
|
110168
|
-
convexUrl: a.convexUrl,
|
|
110169
|
-
otherUrls: a.otherUrls
|
|
110170
|
-
}));
|
|
110171
|
-
yield* validateChatroomIdEffect(chatroomId, (id3) => ({
|
|
110172
|
-
_tag: "InvalidChatroomId",
|
|
110173
|
-
id: id3
|
|
110174
|
-
}));
|
|
110594
|
+
const sessionId = yield* requireSessionForChatroomEffect({ chatroomId });
|
|
110175
110595
|
const format4 = options.format ?? "linear";
|
|
110176
110596
|
const maxDownload = parseLimit(options.limit);
|
|
110177
110597
|
const outputDir = options.outputDir ?? resolveDownloadOutputDir(format4);
|
|
@@ -110442,15 +110862,7 @@ async function listSinceMessage(chatroomId, options, deps) {
|
|
|
110442
110862
|
}
|
|
110443
110863
|
var listBySenderRoleEffect = (chatroomId, options) => exports_Effect.gen(function* () {
|
|
110444
110864
|
const backend2 = yield* BackendService;
|
|
110445
|
-
const sessionId = yield*
|
|
110446
|
-
_tag: "NotAuthenticated",
|
|
110447
|
-
convexUrl: a.convexUrl,
|
|
110448
|
-
otherUrls: a.otherUrls
|
|
110449
|
-
}));
|
|
110450
|
-
yield* validateChatroomIdEffect(chatroomId, (id3) => ({
|
|
110451
|
-
_tag: "InvalidChatroomId",
|
|
110452
|
-
id: id3
|
|
110453
|
-
}));
|
|
110865
|
+
const sessionId = yield* requireSessionForChatroomEffect({ chatroomId });
|
|
110454
110866
|
const messages = yield* backend2.query(api.messages.listBySenderRole, {
|
|
110455
110867
|
sessionId,
|
|
110456
110868
|
chatroomId,
|
|
@@ -110485,15 +110897,7 @@ var listBySenderRoleEffect = (chatroomId, options) => exports_Effect.gen(functio
|
|
|
110485
110897
|
});
|
|
110486
110898
|
}), listSinceMessageEffect = (chatroomId, options) => exports_Effect.gen(function* () {
|
|
110487
110899
|
const backend2 = yield* BackendService;
|
|
110488
|
-
const sessionId = yield*
|
|
110489
|
-
_tag: "NotAuthenticated",
|
|
110490
|
-
convexUrl: a.convexUrl,
|
|
110491
|
-
otherUrls: a.otherUrls
|
|
110492
|
-
}));
|
|
110493
|
-
yield* validateChatroomIdEffect(chatroomId, (id3) => ({
|
|
110494
|
-
_tag: "InvalidChatroomId",
|
|
110495
|
-
id: id3
|
|
110496
|
-
}));
|
|
110900
|
+
const sessionId = yield* requireSessionForChatroomEffect({ chatroomId });
|
|
110497
110901
|
const messages = yield* backend2.query(api.messages.listSinceMessage, {
|
|
110498
110902
|
sessionId,
|
|
110499
110903
|
chatroomId,
|
|
@@ -110960,15 +111364,7 @@ async function viewManyArtifacts(chatroomId, options, deps) {
|
|
|
110960
111364
|
}
|
|
110961
111365
|
var createArtifactEffect = (chatroomId, options) => exports_Effect.gen(function* () {
|
|
110962
111366
|
const backend2 = yield* BackendService;
|
|
110963
|
-
const sessionId = yield*
|
|
110964
|
-
_tag: "NotAuthenticated",
|
|
110965
|
-
convexUrl: a.convexUrl,
|
|
110966
|
-
otherUrls: a.otherUrls
|
|
110967
|
-
}));
|
|
110968
|
-
yield* validateChatroomIdEffect(chatroomId, (id3) => ({
|
|
110969
|
-
_tag: "InvalidChatroomId",
|
|
110970
|
-
id: id3
|
|
110971
|
-
}));
|
|
111367
|
+
const sessionId = yield* requireSessionForChatroomEffect({ chatroomId });
|
|
110972
111368
|
if (!options.fromFile.endsWith(".md")) {
|
|
110973
111369
|
return yield* exports_Effect.fail({
|
|
110974
111370
|
_tag: "InvalidFileExtension",
|
|
@@ -111006,15 +111402,7 @@ var createArtifactEffect = (chatroomId, options) => exports_Effect.gen(function*
|
|
|
111006
111402
|
return artifactId;
|
|
111007
111403
|
}), viewArtifactEffect = (chatroomId, options) => exports_Effect.gen(function* () {
|
|
111008
111404
|
const backend2 = yield* BackendService;
|
|
111009
|
-
const sessionId = yield*
|
|
111010
|
-
_tag: "NotAuthenticated",
|
|
111011
|
-
convexUrl: a.convexUrl,
|
|
111012
|
-
otherUrls: a.otherUrls
|
|
111013
|
-
}));
|
|
111014
|
-
yield* validateChatroomIdEffect(chatroomId, (id3) => ({
|
|
111015
|
-
_tag: "InvalidChatroomId",
|
|
111016
|
-
id: id3
|
|
111017
|
-
}));
|
|
111405
|
+
const sessionId = yield* requireSessionForChatroomEffect({ chatroomId });
|
|
111018
111406
|
const artifact = yield* backend2.query(api.artifacts.get, {
|
|
111019
111407
|
sessionId,
|
|
111020
111408
|
artifactId: options.artifactId
|
|
@@ -111040,15 +111428,7 @@ var createArtifactEffect = (chatroomId, options) => exports_Effect.gen(function*
|
|
|
111040
111428
|
});
|
|
111041
111429
|
}), viewManyArtifactsEffect = (chatroomId, options) => exports_Effect.gen(function* () {
|
|
111042
111430
|
const backend2 = yield* BackendService;
|
|
111043
|
-
const sessionId = yield*
|
|
111044
|
-
_tag: "NotAuthenticated",
|
|
111045
|
-
convexUrl: a.convexUrl,
|
|
111046
|
-
otherUrls: a.otherUrls
|
|
111047
|
-
}));
|
|
111048
|
-
yield* validateChatroomIdEffect(chatroomId, (id3) => ({
|
|
111049
|
-
_tag: "InvalidChatroomId",
|
|
111050
|
-
id: id3
|
|
111051
|
-
}));
|
|
111431
|
+
const sessionId = yield* requireSessionForChatroomEffect({ chatroomId });
|
|
111052
111432
|
if (options.artifactIds.length === 0) {
|
|
111053
111433
|
return yield* exports_Effect.fail({ _tag: "NoArtifactIds" });
|
|
111054
111434
|
}
|
|
@@ -111446,12 +111826,12 @@ var init_durable_fifo_queue_schema = __esm(() => {
|
|
|
111446
111826
|
});
|
|
111447
111827
|
|
|
111448
111828
|
// src/daemon/infrastructure/outbox/lib/durable-fifo-queue-store.ts
|
|
111449
|
-
import { mkdirSync as
|
|
111450
|
-
import { dirname as
|
|
111451
|
-
import { DatabaseSync as
|
|
111829
|
+
import { mkdirSync as mkdirSync8 } from "node:fs";
|
|
111830
|
+
import { dirname as dirname11 } from "node:path";
|
|
111831
|
+
import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
|
|
111452
111832
|
function openDurableFifoQueueStore(dbPath) {
|
|
111453
|
-
|
|
111454
|
-
const db = new
|
|
111833
|
+
mkdirSync8(dirname11(dbPath), { recursive: true });
|
|
111834
|
+
const db = new DatabaseSync3(dbPath);
|
|
111455
111835
|
for (const sql of DURABLE_FIFO_QUEUE_MIGRATIONS)
|
|
111456
111836
|
db.exec(sql);
|
|
111457
111837
|
db.prepare("UPDATE fifo_outbox_entries SET status='pending', updated_at=? WHERE status='in_flight'").run(Date.now());
|
|
@@ -111868,7 +112248,8 @@ var AgentLifecycleOutboxService, AgentLifecycleOutboxServiceLive = (registry3, m
|
|
|
111868
112248
|
resumeTurnForSlot: (args2) => exports_Effect.promise(() => mgr.resumeTurnForSlot(args2)),
|
|
111869
112249
|
subscribeAgentTurnEnded: (handler) => processManagerService.subscribeAgentTurnEnded(handler),
|
|
111870
112250
|
subscribeAgentStarted: (handler) => processManagerService.subscribeAgentStarted(handler),
|
|
111871
|
-
subscribeAgentSessionLost: (handler) => processManagerService.subscribeAgentSessionLost(handler)
|
|
112251
|
+
subscribeAgentSessionLost: (handler) => processManagerService.subscribeAgentSessionLost(handler),
|
|
112252
|
+
subscribeAgentTurnProgress: (handler) => processManagerService.subscribeAgentTurnProgress(handler)
|
|
111872
112253
|
}), DaemonAgentProcessManagerCommandService, DaemonAgentProcessManagerCommandServiceLive = (service4) => exports_Layer.succeed(DaemonAgentProcessManagerCommandService, service4), DaemonSessionService, DaemonMutableStateService;
|
|
111873
112254
|
var init_daemon_services = __esm(() => {
|
|
111874
112255
|
init_esm();
|
|
@@ -112162,6 +112543,14 @@ var init_output_store = __esm(() => {
|
|
|
112162
112543
|
RUN_ID_RE = /^[a-z0-9]+$/i;
|
|
112163
112544
|
});
|
|
112164
112545
|
|
|
112546
|
+
// src/daemon/entry/task-handoff-repository-path.ts
|
|
112547
|
+
import { homedir as homedir9 } from "node:os";
|
|
112548
|
+
import { join as join22 } from "node:path";
|
|
112549
|
+
function resolveTaskHandoffRepositoryPath(machineId) {
|
|
112550
|
+
return join22(homedir9(), ".chatroom", "daemon", machineId, "task-handoffs.sqlite");
|
|
112551
|
+
}
|
|
112552
|
+
var init_task_handoff_repository_path = () => {};
|
|
112553
|
+
|
|
112165
112554
|
// src/infrastructure/services/harness-spawning/rate-limiter.ts
|
|
112166
112555
|
class SpawnRateLimiter {
|
|
112167
112556
|
config;
|
|
@@ -112617,6 +113006,7 @@ function assembleDaemonSessionInit(args2) {
|
|
|
112617
113006
|
convexUrl,
|
|
112618
113007
|
backend: deps.backend,
|
|
112619
113008
|
configurationService: agentConfigRegistry,
|
|
113009
|
+
handoffRepository: createTaskHandoffRepository(resolveTaskHandoffRepositoryPath(machineId)),
|
|
112620
113010
|
logEvent: activeLogEvent ?? (async () => {
|
|
112621
113011
|
return;
|
|
112622
113012
|
})
|
|
@@ -112657,9 +113047,6 @@ class NetworkRetryError {
|
|
|
112657
113047
|
this.attempt = attempt;
|
|
112658
113048
|
}
|
|
112659
113049
|
}
|
|
112660
|
-
function getActiveLogSink() {
|
|
112661
|
-
return activeLogSink;
|
|
112662
|
-
}
|
|
112663
113050
|
async function initDaemon(options = {}) {
|
|
112664
113051
|
activeLogSink = options.logSink;
|
|
112665
113052
|
activeLogEvent = options.logEvent;
|
|
@@ -112860,6 +113247,7 @@ var init_init_daemon = __esm(() => {
|
|
|
112860
113247
|
init_daemon_startup_log();
|
|
112861
113248
|
init_orphan_tracker();
|
|
112862
113249
|
init_output_store();
|
|
113250
|
+
init_task_handoff_repository_path();
|
|
112863
113251
|
init_pid();
|
|
112864
113252
|
init_storage();
|
|
112865
113253
|
init_client2();
|
|
@@ -112874,6 +113262,7 @@ var init_init_daemon = __esm(() => {
|
|
|
112874
113262
|
init_agent_process_service2();
|
|
112875
113263
|
init_chatroom_workspace_configuration_service();
|
|
112876
113264
|
init_service_interfaces();
|
|
113265
|
+
init_task_service2();
|
|
112877
113266
|
AUTH_WAIT_TIMEOUT_MS = 5 * 60 * 1000;
|
|
112878
113267
|
initDaemonEffect = exports_Effect.gen(function* () {
|
|
112879
113268
|
const lockAcquired = yield* exports_Effect.tryPromise({
|
|
@@ -117228,16 +117617,16 @@ var MAX_NAME_LENGTH = 256;
|
|
|
117228
117617
|
|
|
117229
117618
|
// src/infrastructure/services/workspace/workspace-resolver.ts
|
|
117230
117619
|
import { readFile as readFile7, readdir, stat as stat4 } from "node:fs/promises";
|
|
117231
|
-
import { join as
|
|
117620
|
+
import { join as join23, basename, resolve as resolve4 } from "node:path";
|
|
117232
117621
|
async function resolveGlobPatternStar(rootDir, cleaned) {
|
|
117233
|
-
const parentDir =
|
|
117622
|
+
const parentDir = join23(rootDir, cleaned.slice(0, -2));
|
|
117234
117623
|
try {
|
|
117235
117624
|
const entries2 = await readdir(parentDir, { withFileTypes: true });
|
|
117236
117625
|
const dirs = [];
|
|
117237
117626
|
for (const entry of entries2) {
|
|
117238
117627
|
if (!entry.isDirectory())
|
|
117239
117628
|
continue;
|
|
117240
|
-
const dirPath =
|
|
117629
|
+
const dirPath = join23(parentDir, entry.name);
|
|
117241
117630
|
if (resolve4(dirPath).startsWith(resolve4(rootDir))) {
|
|
117242
117631
|
dirs.push(dirPath);
|
|
117243
117632
|
}
|
|
@@ -117248,7 +117637,7 @@ async function resolveGlobPatternStar(rootDir, cleaned) {
|
|
|
117248
117637
|
}
|
|
117249
117638
|
}
|
|
117250
117639
|
async function resolveLiteralPath(rootDir, cleaned) {
|
|
117251
|
-
const dir =
|
|
117640
|
+
const dir = join23(rootDir, cleaned);
|
|
117252
117641
|
try {
|
|
117253
117642
|
if (!resolve4(dir).startsWith(resolve4(rootDir)))
|
|
117254
117643
|
return [];
|
|
@@ -117268,7 +117657,7 @@ async function resolveGlobPattern(rootDir, pattern) {
|
|
|
117268
117657
|
}
|
|
117269
117658
|
async function readPackageJson(dir) {
|
|
117270
117659
|
try {
|
|
117271
|
-
const content = await readFile7(
|
|
117660
|
+
const content = await readFile7(join23(dir, "package.json"), "utf-8");
|
|
117272
117661
|
const pkg = JSON.parse(content);
|
|
117273
117662
|
return {
|
|
117274
117663
|
name: pkg.name || basename(dir),
|
|
@@ -117280,7 +117669,7 @@ async function readPackageJson(dir) {
|
|
|
117280
117669
|
}
|
|
117281
117670
|
async function readPnpmWorkspacePatterns(rootDir) {
|
|
117282
117671
|
try {
|
|
117283
|
-
const content = await readFile7(
|
|
117672
|
+
const content = await readFile7(join23(rootDir, "pnpm-workspace.yaml"), "utf-8");
|
|
117284
117673
|
const patterns = [];
|
|
117285
117674
|
let inPackages = false;
|
|
117286
117675
|
for (const line of content.split(`
|
|
@@ -117307,7 +117696,7 @@ async function readPnpmWorkspacePatterns(rootDir) {
|
|
|
117307
117696
|
}
|
|
117308
117697
|
async function readPackageJsonWorkspacePatterns(rootDir) {
|
|
117309
117698
|
try {
|
|
117310
|
-
const content = await readFile7(
|
|
117699
|
+
const content = await readFile7(join23(rootDir, "package.json"), "utf-8");
|
|
117311
117700
|
const pkg = JSON.parse(content);
|
|
117312
117701
|
if (!pkg.workspaces)
|
|
117313
117702
|
return [];
|
|
@@ -117356,11 +117745,11 @@ var init_workspace_resolver = () => {};
|
|
|
117356
117745
|
|
|
117357
117746
|
// src/infrastructure/services/workspace/command-discovery.ts
|
|
117358
117747
|
import { access as access2, readFile as readFile8 } from "node:fs/promises";
|
|
117359
|
-
import { join as
|
|
117748
|
+
import { join as join24, relative, basename as basename2 } from "node:path";
|
|
117360
117749
|
async function detectPackageManager(workingDir) {
|
|
117361
117750
|
for (const { file: file2, manager } of LOCKFILE_MAP) {
|
|
117362
117751
|
try {
|
|
117363
|
-
await access2(
|
|
117752
|
+
await access2(join24(workingDir, file2));
|
|
117364
117753
|
return manager;
|
|
117365
117754
|
} catch {}
|
|
117366
117755
|
}
|
|
@@ -117429,7 +117818,7 @@ function collectRootScriptCommands(scripts, pm, scriptPrefix, rootSw) {
|
|
|
117429
117818
|
}
|
|
117430
117819
|
async function readRootPackageJson(workingDir, pm, scriptPrefix) {
|
|
117431
117820
|
let rootPackageName = basename2(workingDir);
|
|
117432
|
-
const pkg = await readJsonFile(
|
|
117821
|
+
const pkg = await readJsonFile(join24(workingDir, "package.json"), "root package.json");
|
|
117433
117822
|
if (!pkg)
|
|
117434
117823
|
return { commands: [], rootPackageName };
|
|
117435
117824
|
if (pkg.name)
|
|
@@ -117445,7 +117834,7 @@ async function readRootPackageJson(workingDir, pm, scriptPrefix) {
|
|
|
117445
117834
|
}
|
|
117446
117835
|
async function readTurboJson(workingDir, _turboPrefix, _rootSubWorkspace) {
|
|
117447
117836
|
const turboTaskNames = [];
|
|
117448
|
-
const turbo = await readJsonFile(
|
|
117837
|
+
const turbo = await readJsonFile(join24(workingDir, "turbo.json"), "turbo.json");
|
|
117449
117838
|
if (!turbo?.tasks || typeof turbo.tasks !== "object")
|
|
117450
117839
|
return turboTaskNames;
|
|
117451
117840
|
for (const taskName of Object.keys(turbo.tasks)) {
|
|
@@ -117458,7 +117847,7 @@ async function readTurboJson(workingDir, _turboPrefix, _rootSubWorkspace) {
|
|
|
117458
117847
|
async function readDenoJson(workingDir) {
|
|
117459
117848
|
const commands = [];
|
|
117460
117849
|
for (const fileName of ["deno.json", "deno.jsonc"]) {
|
|
117461
|
-
const deno = await readJsonFile(
|
|
117850
|
+
const deno = await readJsonFile(join24(workingDir, fileName), fileName);
|
|
117462
117851
|
if (!deno?.tasks || typeof deno.tasks !== "object")
|
|
117463
117852
|
continue;
|
|
117464
117853
|
const pkgName = deno.name ?? basename2(workingDir);
|
|
@@ -117481,7 +117870,7 @@ async function readMakefile(workingDir) {
|
|
|
117481
117870
|
const commands = [];
|
|
117482
117871
|
for (const fileName of ["Makefile", "makefile"]) {
|
|
117483
117872
|
try {
|
|
117484
|
-
const content = await readFile8(
|
|
117873
|
+
const content = await readFile8(join24(workingDir, fileName), "utf-8");
|
|
117485
117874
|
const targets = parseMakefileTargets(content);
|
|
117486
117875
|
if (targets.length === 0)
|
|
117487
117876
|
continue;
|
|
@@ -118056,7 +118445,7 @@ async function runRestartOrchestrator(deps, event) {
|
|
|
118056
118445
|
const { chatroomId, role } = event;
|
|
118057
118446
|
markRestartOrchestratorInFlight(chatroomId, role, event.correlationId);
|
|
118058
118447
|
try {
|
|
118059
|
-
|
|
118448
|
+
await deps.nativeDelivery.handleAgentRestart({ chatroomId, role });
|
|
118060
118449
|
await emitPhase(deps, event, "reset");
|
|
118061
118450
|
await emitPhase(deps, event, "spawn");
|
|
118062
118451
|
const spawnResult = await deps.runSerializedForAgent({ chatroomId, role, workingDir: event.workingDir }, { timeoutMs: HARNESS_SESSION_READY_TIMEOUT_MS }, async (ops, context5) => {
|
|
@@ -118067,7 +118456,7 @@ async function runRestartOrchestrator(deps, event) {
|
|
|
118067
118456
|
agentHarness: event.agentHarness,
|
|
118068
118457
|
model: event.model,
|
|
118069
118458
|
workingDir: event.workingDir,
|
|
118070
|
-
reason:
|
|
118459
|
+
reason: AgentStartReasonCode.USER_RESTART,
|
|
118071
118460
|
wantResume: event.wantResume
|
|
118072
118461
|
}, context5.signal);
|
|
118073
118462
|
});
|
|
@@ -118081,7 +118470,7 @@ async function runRestartOrchestrator(deps, event) {
|
|
|
118081
118470
|
await deps.runSerializedForAgent({ chatroomId, role, workingDir: event.workingDir }, { timeoutMs: HARNESS_SESSION_READY_TIMEOUT_MS }, (ops, context5) => ops.stopAgent({
|
|
118082
118471
|
chatroomId,
|
|
118083
118472
|
role,
|
|
118084
|
-
reason:
|
|
118473
|
+
reason: AgentStartReasonCode.USER_RESTART,
|
|
118085
118474
|
pid: spawnResult.pid,
|
|
118086
118475
|
workingDir: event.workingDir
|
|
118087
118476
|
}, context5.signal));
|
|
@@ -118112,12 +118501,12 @@ async function runRestartOrchestrator(deps, event) {
|
|
|
118112
118501
|
}
|
|
118113
118502
|
var init_restart_orchestrator = __esm(() => {
|
|
118114
118503
|
init_reliability();
|
|
118504
|
+
init_agent();
|
|
118115
118505
|
init_build_agent_restart_event();
|
|
118116
118506
|
init_restart_orchestrator_in_flight();
|
|
118117
118507
|
init_api3();
|
|
118118
118508
|
init_convex_error();
|
|
118119
118509
|
init_execution_kind();
|
|
118120
|
-
init_service_interfaces();
|
|
118121
118510
|
});
|
|
118122
118511
|
|
|
118123
118512
|
// src/daemon/entry/bridge/agent-control-bridge.ts
|
|
@@ -118272,19 +118661,6 @@ async function startAgent2(deps, input) {
|
|
|
118272
118661
|
});
|
|
118273
118662
|
}
|
|
118274
118663
|
|
|
118275
|
-
// src/daemon/entry/enhancer/enhancer-drain-registry.ts
|
|
118276
|
-
function setEnhancerDrainHandler(fn2) {
|
|
118277
|
-
drainFn = fn2;
|
|
118278
|
-
}
|
|
118279
|
-
async function drainPendingEnhancerJobsIfRegistered() {
|
|
118280
|
-
if (drainFn)
|
|
118281
|
-
await drainFn();
|
|
118282
|
-
}
|
|
118283
|
-
function clearEnhancerDrainHandlerForTests() {
|
|
118284
|
-
drainFn = null;
|
|
118285
|
-
}
|
|
118286
|
-
var drainFn = null;
|
|
118287
|
-
|
|
118288
118664
|
// src/daemon/entry/events/agent/on-request-start-agent.ts
|
|
118289
118665
|
var onRequestStartAgentEffect = (event) => exports_Effect.gen(function* () {
|
|
118290
118666
|
const processManagerService = yield* DaemonAgentProcessManagerCommandService;
|
|
@@ -118301,7 +118677,6 @@ var onRequestStartAgentEffect = (event) => exports_Effect.gen(function* () {
|
|
|
118301
118677
|
deadline: event.deadline,
|
|
118302
118678
|
wantResume: event.wantResume
|
|
118303
118679
|
});
|
|
118304
|
-
await drainPendingEnhancerJobsIfRegistered();
|
|
118305
118680
|
});
|
|
118306
118681
|
});
|
|
118307
118682
|
var init_on_request_start_agent = __esm(() => {
|
|
@@ -118637,435 +119012,19 @@ async function dispatchCommandInboundEvent(event) {
|
|
|
118637
119012
|
}
|
|
118638
119013
|
var handler2;
|
|
118639
119014
|
|
|
118640
|
-
// src/daemon/entry/
|
|
118641
|
-
|
|
118642
|
-
|
|
118643
|
-
// src/daemon/entry/enhancer/enhancer-log.ts
|
|
118644
|
-
function formatEnhancerLogLine(message) {
|
|
118645
|
-
const trimmed = message.trimEnd();
|
|
118646
|
-
if (trimmed.startsWith(ENHANCER_LOG_PREFIX))
|
|
118647
|
-
return trimmed;
|
|
118648
|
-
return `${ENHANCER_LOG_PREFIX} ${trimmed}`;
|
|
118649
|
-
}
|
|
118650
|
-
function createEnhancerLogWriter(logSink, context5, clock4 = () => Date.now()) {
|
|
118651
|
-
return {
|
|
118652
|
-
write(message) {
|
|
118653
|
-
const formatted = formatEnhancerLogLine(message);
|
|
118654
|
-
logSink?.write({
|
|
118655
|
-
timestamp: clock4(),
|
|
118656
|
-
level: "info",
|
|
118657
|
-
source: `harness:${context5.harness}`,
|
|
118658
|
-
stream: "stdout",
|
|
118659
|
-
message: formatted,
|
|
118660
|
-
metadata: {
|
|
118661
|
-
chatroomId: context5.chatroomId,
|
|
118662
|
-
role: ENHANCER_AGENT_ROLE,
|
|
118663
|
-
harness: context5.harness,
|
|
118664
|
-
...context5.pid !== undefined ? { pid: context5.pid } : {}
|
|
118665
|
-
}
|
|
118666
|
-
});
|
|
118667
|
-
}
|
|
118668
|
-
};
|
|
118669
|
-
}
|
|
118670
|
-
var ENHANCER_LOG_PREFIX = "[enhancer]";
|
|
118671
|
-
var init_enhancer_log = () => {};
|
|
118672
|
-
|
|
118673
|
-
// src/daemon/entry/enhancer/enhancer-spawn-registry.ts
|
|
118674
|
-
function registerEnhancerSpawn(handle) {
|
|
118675
|
-
const handles = byChatroom.get(handle.chatroomId) ?? new Set;
|
|
118676
|
-
handles.add(handle);
|
|
118677
|
-
byChatroom.set(handle.chatroomId, handles);
|
|
118678
|
-
}
|
|
118679
|
-
function unregisterEnhancerSpawn(handle) {
|
|
118680
|
-
const handles = byChatroom.get(handle.chatroomId);
|
|
118681
|
-
if (!handles)
|
|
118682
|
-
return;
|
|
118683
|
-
handles.delete(handle);
|
|
118684
|
-
if (handles.size === 0)
|
|
118685
|
-
byChatroom.delete(handle.chatroomId);
|
|
118686
|
-
}
|
|
118687
|
-
async function abortEnhancerSpawnsForChatroom(chatroomId) {
|
|
118688
|
-
const handles = byChatroom.get(chatroomId);
|
|
118689
|
-
if (!handles)
|
|
118690
|
-
return;
|
|
118691
|
-
await Promise.all([...handles].map(async (handle) => {
|
|
118692
|
-
handle.abort();
|
|
118693
|
-
await handle.stopProcess().catch(() => {
|
|
118694
|
-
return;
|
|
118695
|
-
});
|
|
118696
|
-
}));
|
|
118697
|
-
}
|
|
118698
|
-
var byChatroom;
|
|
118699
|
-
var init_enhancer_spawn_registry = __esm(() => {
|
|
118700
|
-
byChatroom = new Map;
|
|
118701
|
-
});
|
|
118702
|
-
|
|
118703
|
-
// src/daemon/entry/enhancer/job-outcome-subscription.ts
|
|
118704
|
-
function subscribeToEnhancerJobOutcome(args2) {
|
|
118705
|
-
let currentState = null;
|
|
118706
|
-
let resolveOutcome = null;
|
|
118707
|
-
let rejectOutcome = null;
|
|
118708
|
-
let stopped = false;
|
|
118709
|
-
const outcome = new Promise((resolve5, reject) => {
|
|
118710
|
-
resolveOutcome = resolve5;
|
|
118711
|
-
rejectOutcome = reject;
|
|
118712
|
-
});
|
|
118713
|
-
const unsub = args2.wsClient.onUpdate(api.web.enhancer.index.getJobOutcome, {
|
|
118714
|
-
sessionId: args2.sessionId,
|
|
118715
|
-
chatroomId: args2.chatroomId,
|
|
118716
|
-
jobId: args2.jobId
|
|
118717
|
-
}, (state) => {
|
|
118718
|
-
if (stopped)
|
|
118719
|
-
return;
|
|
118720
|
-
if (!state) {
|
|
118721
|
-
rejectOutcome?.(new Error("Enhancer job not found"));
|
|
118722
|
-
resolveOutcome = null;
|
|
118723
|
-
rejectOutcome = null;
|
|
118724
|
-
return;
|
|
118725
|
-
}
|
|
118726
|
-
currentState = state;
|
|
118727
|
-
if (state.status === "complete" || state.status === "failed" || state.status === "cancelled") {
|
|
118728
|
-
resolveOutcome?.(state);
|
|
118729
|
-
resolveOutcome = null;
|
|
118730
|
-
rejectOutcome = null;
|
|
118731
|
-
}
|
|
118732
|
-
}, (error51) => {
|
|
118733
|
-
if (stopped)
|
|
118734
|
-
return;
|
|
118735
|
-
rejectOutcome?.(error51);
|
|
118736
|
-
resolveOutcome = null;
|
|
118737
|
-
rejectOutcome = null;
|
|
118738
|
-
});
|
|
118739
|
-
return {
|
|
118740
|
-
outcome,
|
|
118741
|
-
getCurrentState: () => currentState,
|
|
118742
|
-
stop: () => {
|
|
118743
|
-
if (stopped)
|
|
118744
|
-
return;
|
|
118745
|
-
stopped = true;
|
|
118746
|
-
unsub();
|
|
118747
|
-
resolveOutcome = null;
|
|
118748
|
-
rejectOutcome = null;
|
|
118749
|
-
}
|
|
118750
|
-
};
|
|
118751
|
-
}
|
|
118752
|
-
var init_job_outcome_subscription = __esm(() => {
|
|
118753
|
-
init_api3();
|
|
118754
|
-
});
|
|
118755
|
-
|
|
118756
|
-
// src/daemon/entry/enhancer/wait-for-enhancer-job.ts
|
|
118757
|
-
async function waitForEnhancerJobResolution(params) {
|
|
118758
|
-
const { sessionId, chatroomId, jobId, wsClient: wsClient2, onFailure, onSalvageComplete, log: log4, signal } = params;
|
|
118759
|
-
const writeLog = (message) => log4?.write(message);
|
|
118760
|
-
let outcome = null;
|
|
118761
|
-
let salvagedText = "";
|
|
118762
|
-
let agentEndTimer = null;
|
|
118763
|
-
let resolveWait = null;
|
|
118764
|
-
const waitPromise = new Promise((resolve5) => {
|
|
118765
|
-
resolveWait = resolve5;
|
|
118766
|
-
});
|
|
118767
|
-
const subscription = subscribeToEnhancerJobOutcome({
|
|
118768
|
-
wsClient: wsClient2,
|
|
118769
|
-
sessionId,
|
|
118770
|
-
chatroomId,
|
|
118771
|
-
jobId
|
|
118772
|
-
});
|
|
118773
|
-
const finish = (resolution) => {
|
|
118774
|
-
if (outcome)
|
|
118775
|
-
return;
|
|
118776
|
-
outcome = resolution;
|
|
118777
|
-
resolveWait?.();
|
|
118778
|
-
resolveWait = null;
|
|
118779
|
-
};
|
|
118780
|
-
const onAbort = () => finish("aborted");
|
|
118781
|
-
if (signal?.aborted)
|
|
118782
|
-
onAbort();
|
|
118783
|
-
else
|
|
118784
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
118785
|
-
const failAfterAgentEnd = () => {
|
|
118786
|
-
writeLog("agent_end: turn ended without complete — failing terminal");
|
|
118787
|
-
onFailure("Agent exited without completing enhancer job", true);
|
|
118788
|
-
finish("failed");
|
|
118789
|
-
};
|
|
118790
|
-
subscription.outcome.then((state) => {
|
|
118791
|
-
if (outcome)
|
|
118792
|
-
return;
|
|
118793
|
-
const resolution = state.status === "complete" ? "complete" : "failed";
|
|
118794
|
-
if (resolution === "complete")
|
|
118795
|
-
writeLog(`completed job=${jobId}`);
|
|
118796
|
-
finish(resolution);
|
|
118797
|
-
}).catch((error51) => {
|
|
118798
|
-
if (outcome)
|
|
118799
|
-
return;
|
|
118800
|
-
writeLog(`enhancer outcome subscription failed: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
118801
|
-
onFailure("Enhancer job outcome subscription failed", false);
|
|
118802
|
-
finish("failed");
|
|
118803
|
-
});
|
|
118804
|
-
params.onAssistantText?.((text) => {
|
|
118805
|
-
salvagedText += text;
|
|
118806
|
-
});
|
|
118807
|
-
params.onAgentEnd?.(() => {
|
|
118808
|
-
if (outcome)
|
|
118809
|
-
return;
|
|
118810
|
-
agentEndTimer = setTimeout(() => {
|
|
118811
|
-
if (outcome)
|
|
118812
|
-
return;
|
|
118813
|
-
const state = subscription.getCurrentState();
|
|
118814
|
-
if (state?.status === "complete") {
|
|
118815
|
-
finish("complete");
|
|
118816
|
-
return;
|
|
118817
|
-
}
|
|
118818
|
-
if (state?.status !== "running") {
|
|
118819
|
-
failAfterAgentEnd();
|
|
118820
|
-
return;
|
|
118821
|
-
}
|
|
118822
|
-
const trimmed = salvagedText.trim();
|
|
118823
|
-
if (!trimmed || !onSalvageComplete) {
|
|
118824
|
-
failAfterAgentEnd();
|
|
118825
|
-
return;
|
|
118826
|
-
}
|
|
118827
|
-
onSalvageComplete(trimmed).catch(() => {
|
|
118828
|
-
failAfterAgentEnd();
|
|
118829
|
-
});
|
|
118830
|
-
}, ENHANCER_AGENT_END_GRACE_MS);
|
|
118831
|
-
});
|
|
118832
|
-
params.onExit(() => {
|
|
118833
|
-
if (outcome)
|
|
118834
|
-
return;
|
|
118835
|
-
onFailure("Agent process exited without completing enhancer job", false);
|
|
118836
|
-
finish("failed");
|
|
118837
|
-
});
|
|
118838
|
-
await waitPromise;
|
|
118839
|
-
if (agentEndTimer)
|
|
118840
|
-
clearTimeout(agentEndTimer);
|
|
118841
|
-
subscription.stop();
|
|
118842
|
-
signal?.removeEventListener("abort", onAbort);
|
|
118843
|
-
return outcome ?? "failed";
|
|
118844
|
-
}
|
|
118845
|
-
var init_wait_for_enhancer_job = __esm(() => {
|
|
118846
|
-
init_job_outcome_subscription();
|
|
118847
|
-
});
|
|
118848
|
-
|
|
118849
|
-
// src/daemon/entry/enhancer-inbound-registry.ts
|
|
118850
|
-
function registerEnhancerInboundHandler(h) {
|
|
119015
|
+
// src/daemon/entry/file-inbound-registry.ts
|
|
119016
|
+
function registerFileInboundHandler(h) {
|
|
118851
119017
|
handler3 = h;
|
|
118852
119018
|
}
|
|
118853
|
-
function
|
|
119019
|
+
function unregisterFileInboundHandler() {
|
|
118854
119020
|
handler3 = undefined;
|
|
118855
119021
|
}
|
|
118856
|
-
async function
|
|
119022
|
+
async function dispatchFileInboundEvent(event) {
|
|
118857
119023
|
if (handler3)
|
|
118858
119024
|
await handler3(event);
|
|
118859
119025
|
}
|
|
118860
119026
|
var handler3;
|
|
118861
119027
|
|
|
118862
|
-
// src/daemon/entry/enhancer/job-subscriber.ts
|
|
118863
|
-
async function processEnhancerJobForSpawn(sessionId, machineId, convexUrl, wsClient2, backend2, agentServices, job, inFlight2, logSink) {
|
|
118864
|
-
if (inFlight2.has(job.jobId))
|
|
118865
|
-
return;
|
|
118866
|
-
if (isChatroomStopScopeActive(job.chatroomId))
|
|
118867
|
-
return;
|
|
118868
|
-
inFlight2.add(job.jobId);
|
|
118869
|
-
let claimed = false;
|
|
118870
|
-
let chatroomId = job.chatroomId;
|
|
118871
|
-
let jobId = job.jobId;
|
|
118872
|
-
let spawnResult = null;
|
|
118873
|
-
let service4 = null;
|
|
118874
|
-
let abortController = null;
|
|
118875
|
-
let spawnHandle = null;
|
|
118876
|
-
let agentEndSeen = false;
|
|
118877
|
-
let resolveAgentEnd;
|
|
118878
|
-
let agentEndPromise = Promise.resolve();
|
|
118879
|
-
let log4 = createEnhancerLogWriter(logSink, {
|
|
118880
|
-
chatroomId: job.chatroomId,
|
|
118881
|
-
harness: "unknown"
|
|
118882
|
-
});
|
|
118883
|
-
try {
|
|
118884
|
-
const claim = await backend2.mutation(api.daemon.enhancer.index.claimForSpawn, {
|
|
118885
|
-
sessionId,
|
|
118886
|
-
jobId: job.jobId,
|
|
118887
|
-
machineId
|
|
118888
|
-
});
|
|
118889
|
-
if (!claim.claimed)
|
|
118890
|
-
return;
|
|
118891
|
-
claimed = true;
|
|
118892
|
-
log4.write(`claimed job=${job.jobId} chatroom=${job.chatroomId}`);
|
|
118893
|
-
const payload = await backend2.query(api.daemon.enhancer.index.getTaskDeliveryForJob, {
|
|
118894
|
-
sessionId,
|
|
118895
|
-
jobId: job.jobId,
|
|
118896
|
-
convexUrl
|
|
118897
|
-
});
|
|
118898
|
-
chatroomId = payload.chatroomId;
|
|
118899
|
-
jobId = payload.jobId;
|
|
118900
|
-
log4 = createEnhancerLogWriter(logSink, {
|
|
118901
|
-
chatroomId: payload.chatroomId,
|
|
118902
|
-
harness: payload.agentHarness,
|
|
118903
|
-
pid: undefined
|
|
118904
|
-
});
|
|
118905
|
-
log4.write(`spawning harness=${payload.agentHarness} model=${payload.model} job=${payload.jobId}`);
|
|
118906
|
-
service4 = agentServices.get(payload.agentHarness) ?? null;
|
|
118907
|
-
if (!service4) {
|
|
118908
|
-
await backend2.mutation(api.web.enhancer.index.recordAttemptFailure, {
|
|
118909
|
-
sessionId,
|
|
118910
|
-
chatroomId: payload.chatroomId,
|
|
118911
|
-
jobId: payload.jobId,
|
|
118912
|
-
error: `Harness ${payload.agentHarness} not available on machine`
|
|
118913
|
-
});
|
|
118914
|
-
return;
|
|
118915
|
-
}
|
|
118916
|
-
const spawned = await service4.spawn({
|
|
118917
|
-
workingDir: payload.workingDir,
|
|
118918
|
-
prompt: createSpawnPrompt(payload.taskDeliveryOutput),
|
|
118919
|
-
systemPrompt: payload.systemPrompt,
|
|
118920
|
-
model: payload.model,
|
|
118921
|
-
context: {
|
|
118922
|
-
machineId,
|
|
118923
|
-
chatroomId: payload.chatroomId,
|
|
118924
|
-
role: ENHANCER_AGENT_ROLE
|
|
118925
|
-
},
|
|
118926
|
-
resolvedConvexUrl: convexUrl
|
|
118927
|
-
});
|
|
118928
|
-
spawnResult = spawned;
|
|
118929
|
-
abortController = new AbortController;
|
|
118930
|
-
spawnHandle = {
|
|
118931
|
-
jobId: payload.jobId,
|
|
118932
|
-
chatroomId: payload.chatroomId,
|
|
118933
|
-
abort: () => abortController?.abort(),
|
|
118934
|
-
stopProcess: async () => {
|
|
118935
|
-
await service4?.stop(spawned.pid);
|
|
118936
|
-
}
|
|
118937
|
-
};
|
|
118938
|
-
registerEnhancerSpawn(spawnHandle);
|
|
118939
|
-
log4 = createEnhancerLogWriter(logSink, {
|
|
118940
|
-
chatroomId: payload.chatroomId,
|
|
118941
|
-
harness: payload.agentHarness,
|
|
118942
|
-
pid: spawned.pid
|
|
118943
|
-
});
|
|
118944
|
-
spawned.onLogLine?.((line) => {
|
|
118945
|
-
log4.write(line);
|
|
118946
|
-
});
|
|
118947
|
-
agentEndPromise = new Promise((resolve5) => {
|
|
118948
|
-
resolveAgentEnd = resolve5;
|
|
118949
|
-
});
|
|
118950
|
-
spawned.onAgentEnd?.(() => {
|
|
118951
|
-
if (agentEndSeen)
|
|
118952
|
-
return;
|
|
118953
|
-
agentEndSeen = true;
|
|
118954
|
-
resolveAgentEnd?.();
|
|
118955
|
-
});
|
|
118956
|
-
await waitForEnhancerJobResolution({
|
|
118957
|
-
sessionId,
|
|
118958
|
-
chatroomId: payload.chatroomId,
|
|
118959
|
-
jobId: payload.jobId,
|
|
118960
|
-
wsClient: wsClient2,
|
|
118961
|
-
log: log4,
|
|
118962
|
-
onAssistantText: spawned.onAssistantText ? (cb) => spawned.onAssistantText?.(cb) : undefined,
|
|
118963
|
-
onAgentEnd: spawned.onAgentEnd ? (cb) => spawned.onAgentEnd?.(cb) : undefined,
|
|
118964
|
-
onExit: (cb) => spawned.onExit(() => cb()),
|
|
118965
|
-
onSalvageComplete: async (content) => {
|
|
118966
|
-
await backend2.mutation(api.web.enhancer.index.complete, {
|
|
118967
|
-
sessionId,
|
|
118968
|
-
chatroomId: payload.chatroomId,
|
|
118969
|
-
jobId: payload.jobId,
|
|
118970
|
-
enhancedContent: content
|
|
118971
|
-
});
|
|
118972
|
-
},
|
|
118973
|
-
onFailure: async (error51, forceTerminal) => {
|
|
118974
|
-
await backend2.mutation(api.web.enhancer.index.recordAttemptFailure, {
|
|
118975
|
-
sessionId,
|
|
118976
|
-
chatroomId: payload.chatroomId,
|
|
118977
|
-
jobId: payload.jobId,
|
|
118978
|
-
error: error51,
|
|
118979
|
-
...forceTerminal ? { forceTerminal: true } : {}
|
|
118980
|
-
});
|
|
118981
|
-
},
|
|
118982
|
-
signal: abortController.signal
|
|
118983
|
-
});
|
|
118984
|
-
if (!abortController.signal.aborted)
|
|
118985
|
-
log4.write(`completed job=${jobId}`);
|
|
118986
|
-
} catch (err) {
|
|
118987
|
-
log4.write(`error: ${err instanceof Error ? err.message : String(err)}`);
|
|
118988
|
-
if (claimed) {
|
|
118989
|
-
await backend2.mutation(api.web.enhancer.index.recordAttemptFailure, {
|
|
118990
|
-
sessionId,
|
|
118991
|
-
chatroomId,
|
|
118992
|
-
jobId,
|
|
118993
|
-
error: err instanceof Error ? err.message : String(err)
|
|
118994
|
-
});
|
|
118995
|
-
}
|
|
118996
|
-
} finally {
|
|
118997
|
-
inFlight2.delete(job.jobId);
|
|
118998
|
-
if (spawnHandle)
|
|
118999
|
-
unregisterEnhancerSpawn(spawnHandle);
|
|
119000
|
-
if (spawnResult && service4) {
|
|
119001
|
-
if (!agentEndSeen)
|
|
119002
|
-
await Promise.race([
|
|
119003
|
-
agentEndPromise,
|
|
119004
|
-
new Promise((resolve5) => setTimeout(resolve5, ENHANCER_AGENT_END_GRACE_MS))
|
|
119005
|
-
]);
|
|
119006
|
-
try {
|
|
119007
|
-
await service4.stop(spawnResult.pid);
|
|
119008
|
-
} catch {}
|
|
119009
|
-
}
|
|
119010
|
-
}
|
|
119011
|
-
}
|
|
119012
|
-
function processEnhancerJobs(sessionId, machineId, convexUrl, wsClient2, backend2, agentServices, jobs, inFlight2, logSink) {
|
|
119013
|
-
for (const job of jobs ?? []) {
|
|
119014
|
-
processEnhancerJobForSpawn(sessionId, machineId, convexUrl, wsClient2, backend2, agentServices, job, inFlight2, logSink);
|
|
119015
|
-
}
|
|
119016
|
-
}
|
|
119017
|
-
async function drainPendingEnhancerJobs(sessionId, machineId, convexUrl, wsClient2, backend2, agentServices, inFlight2, logSink) {
|
|
119018
|
-
const jobs = await backend2.query(api.daemon.enhancer.index.pendingForMachine, {
|
|
119019
|
-
sessionId,
|
|
119020
|
-
machineId
|
|
119021
|
-
});
|
|
119022
|
-
if (!jobs?.length)
|
|
119023
|
-
return;
|
|
119024
|
-
processEnhancerJobs(sessionId, machineId, convexUrl, wsClient2, backend2, agentServices, jobs, inFlight2, logSink);
|
|
119025
|
-
}
|
|
119026
|
-
function startEnhancerJobSubscriber(sessionId, machineId, convexUrl, wsClient2, backend2, agentServices, logSink) {
|
|
119027
|
-
const inFlight2 = new Set;
|
|
119028
|
-
registerEnhancerInboundHandler(async () => {
|
|
119029
|
-
await drainPendingEnhancerJobs(sessionId, machineId, convexUrl, wsClient2, backend2, agentServices, inFlight2, logSink);
|
|
119030
|
-
});
|
|
119031
|
-
setEnhancerDrainHandler(() => drainPendingEnhancerJobs(sessionId, machineId, convexUrl, wsClient2, backend2, agentServices, inFlight2, logSink));
|
|
119032
|
-
return {
|
|
119033
|
-
stop: () => {
|
|
119034
|
-
unregisterEnhancerInboundHandler();
|
|
119035
|
-
clearEnhancerDrainHandlerForTests();
|
|
119036
|
-
},
|
|
119037
|
-
drainPendingEnhancerJobs: () => drainPendingEnhancerJobs(sessionId, machineId, convexUrl, wsClient2, backend2, agentServices, inFlight2, logSink)
|
|
119038
|
-
};
|
|
119039
|
-
}
|
|
119040
|
-
var init_job_subscriber = __esm(() => {
|
|
119041
|
-
init_enhancer_log();
|
|
119042
|
-
init_enhancer_spawn_registry();
|
|
119043
|
-
init_wait_for_enhancer_job();
|
|
119044
|
-
init_api3();
|
|
119045
|
-
init_service_interfaces();
|
|
119046
|
-
});
|
|
119047
|
-
|
|
119048
|
-
// src/daemon/entry/enhancer/start-subscriptions.ts
|
|
119049
|
-
function startEnhancerSubscriptions(sessionId, machineId, convexUrl, wsClient2, backend2, agentServices, logSink) {
|
|
119050
|
-
return startEnhancerJobSubscriber(sessionId, machineId, convexUrl, wsClient2, backend2, agentServices, logSink);
|
|
119051
|
-
}
|
|
119052
|
-
var init_start_subscriptions2 = __esm(() => {
|
|
119053
|
-
init_job_subscriber();
|
|
119054
|
-
});
|
|
119055
|
-
|
|
119056
|
-
// src/daemon/entry/file-inbound-registry.ts
|
|
119057
|
-
function registerFileInboundHandler(h) {
|
|
119058
|
-
handler4 = h;
|
|
119059
|
-
}
|
|
119060
|
-
function unregisterFileInboundHandler() {
|
|
119061
|
-
handler4 = undefined;
|
|
119062
|
-
}
|
|
119063
|
-
async function dispatchFileInboundEvent(event) {
|
|
119064
|
-
if (handler4)
|
|
119065
|
-
await handler4(event);
|
|
119066
|
-
}
|
|
119067
|
-
var handler4;
|
|
119068
|
-
|
|
119069
119028
|
// src/daemon/entry/files/file-content-classifier.ts
|
|
119070
119029
|
function extensionOf(path3) {
|
|
119071
119030
|
const lastDot = path3.lastIndexOf(".");
|
|
@@ -119184,7 +119143,7 @@ var init_assert_registered_working_dir = __esm(() => {
|
|
|
119184
119143
|
|
|
119185
119144
|
// src/infrastructure/services/workspace/workspace-path-security.ts
|
|
119186
119145
|
import { realpath } from "node:fs/promises";
|
|
119187
|
-
import { dirname as
|
|
119146
|
+
import { dirname as dirname12, isAbsolute, relative as relative2, resolve as resolve5, sep } from "node:path";
|
|
119188
119147
|
import { gunzipSync } from "node:zlib";
|
|
119189
119148
|
function validateRelativePathSegments(filePath) {
|
|
119190
119149
|
if (filePath.includes("\x00"))
|
|
@@ -119212,7 +119171,7 @@ function assertContained(workspaceRoot, targetPath) {
|
|
|
119212
119171
|
return { ok: true };
|
|
119213
119172
|
}
|
|
119214
119173
|
async function resolveNonExistentTarget(workspaceRoot, candidate) {
|
|
119215
|
-
let current =
|
|
119174
|
+
let current = dirname12(candidate);
|
|
119216
119175
|
for (;; ) {
|
|
119217
119176
|
try {
|
|
119218
119177
|
const ancestorReal = await realpath(current);
|
|
@@ -119230,7 +119189,7 @@ async function resolveNonExistentTarget(workspaceRoot, candidate) {
|
|
|
119230
119189
|
if (code2 !== "ENOENT") {
|
|
119231
119190
|
return { ok: false, error: "Invalid file path" };
|
|
119232
119191
|
}
|
|
119233
|
-
const parent =
|
|
119192
|
+
const parent = dirname12(current);
|
|
119234
119193
|
if (parent === current) {
|
|
119235
119194
|
return { ok: false, error: "Path escapes workspace" };
|
|
119236
119195
|
}
|
|
@@ -120034,16 +119993,16 @@ var require_ignore = __commonJS((exports, module) => {
|
|
|
120034
119993
|
// src/infrastructure/services/workspace/workspace-ignore.ts
|
|
120035
119994
|
import { promises as fsPromises } from "node:fs";
|
|
120036
119995
|
import { readFile as readFile10 } from "node:fs/promises";
|
|
120037
|
-
import { homedir as
|
|
119996
|
+
import { homedir as homedir10 } from "node:os";
|
|
120038
119997
|
import path3 from "node:path";
|
|
120039
119998
|
function normalizeRelativePath(relativePath) {
|
|
120040
119999
|
return relativePath.replace(/\\/g, "/").replace(/^\.?\//, "").replace(/\/+$/, "");
|
|
120041
120000
|
}
|
|
120042
120001
|
function expandUserPath(filePath) {
|
|
120043
120002
|
if (filePath === "~")
|
|
120044
|
-
return
|
|
120003
|
+
return homedir10();
|
|
120045
120004
|
if (filePath.startsWith("~/"))
|
|
120046
|
-
return path3.join(
|
|
120005
|
+
return path3.join(homedir10(), filePath.slice(2));
|
|
120047
120006
|
return filePath;
|
|
120048
120007
|
}
|
|
120049
120008
|
function readExcludesFileFromGitconfig(content) {
|
|
@@ -120074,11 +120033,11 @@ async function readGitconfigExcludesFilePath(configPath) {
|
|
|
120074
120033
|
return path3.isAbsolute(raw) ? expandUserPath(raw) : path3.resolve(path3.dirname(configPath), raw);
|
|
120075
120034
|
}
|
|
120076
120035
|
async function resolveGitExtraExcludeFilePaths(rootDir) {
|
|
120077
|
-
const globalConfig2 = process.env.GIT_CONFIG_GLOBAL?.length ? process.env.GIT_CONFIG_GLOBAL : path3.join(
|
|
120036
|
+
const globalConfig2 = process.env.GIT_CONFIG_GLOBAL?.length ? process.env.GIT_CONFIG_GLOBAL : path3.join(homedir10(), ".gitconfig");
|
|
120078
120037
|
const localConfig = path3.join(rootDir, ".git", "config");
|
|
120079
120038
|
let excludesFile = await readGitconfigExcludesFilePath(localConfig) ?? await readGitconfigExcludesFilePath(globalConfig2);
|
|
120080
120039
|
if (!excludesFile) {
|
|
120081
|
-
excludesFile = path3.join(process.env.XDG_CONFIG_HOME?.length ? process.env.XDG_CONFIG_HOME : path3.join(
|
|
120040
|
+
excludesFile = path3.join(process.env.XDG_CONFIG_HOME?.length ? process.env.XDG_CONFIG_HOME : path3.join(homedir10(), ".config"), "git", "ignore");
|
|
120082
120041
|
}
|
|
120083
120042
|
const candidates = [excludesFile, path3.join(rootDir, ".git", "info", "exclude")];
|
|
120084
120043
|
const existing = [];
|
|
@@ -121214,9 +121173,9 @@ class NodeFsHandler {
|
|
|
121214
121173
|
if (this.fsw.closed) {
|
|
121215
121174
|
return;
|
|
121216
121175
|
}
|
|
121217
|
-
const
|
|
121176
|
+
const dirname14 = sp.dirname(file2);
|
|
121218
121177
|
const basename4 = sp.basename(file2);
|
|
121219
|
-
const parent = this.fsw._getWatchedDir(
|
|
121178
|
+
const parent = this.fsw._getWatchedDir(dirname14);
|
|
121220
121179
|
let prevStats = stats;
|
|
121221
121180
|
if (parent.has(basename4))
|
|
121222
121181
|
return;
|
|
@@ -121243,7 +121202,7 @@ class NodeFsHandler {
|
|
|
121243
121202
|
prevStats = newStats2;
|
|
121244
121203
|
}
|
|
121245
121204
|
} catch (error51) {
|
|
121246
|
-
this.fsw._remove(
|
|
121205
|
+
this.fsw._remove(dirname14, basename4);
|
|
121247
121206
|
}
|
|
121248
121207
|
} else if (parent.has(basename4)) {
|
|
121249
121208
|
const at = newStats.atimeMs;
|
|
@@ -122632,8 +122591,8 @@ function diffPathIndexes(previous, next4) {
|
|
|
122632
122591
|
// src/infrastructure/services/workspace/workspace-sync-state.ts
|
|
122633
122592
|
import { createHash as createHash7, randomUUID as randomUUID12 } from "node:crypto";
|
|
122634
122593
|
import * as fs11 from "node:fs/promises";
|
|
122635
|
-
import { homedir as
|
|
122636
|
-
import { join as
|
|
122594
|
+
import { homedir as homedir11 } from "node:os";
|
|
122595
|
+
import { join as join27 } from "node:path";
|
|
122637
122596
|
function workspaceKeyFor(workingDir) {
|
|
122638
122597
|
const normalized = normalizeWorkingDirForLookup(workingDir);
|
|
122639
122598
|
return createHash7("sha256").update(normalized).digest("hex").slice(0, 16);
|
|
@@ -122647,10 +122606,10 @@ function buildPathIndex(entries2) {
|
|
|
122647
122606
|
}
|
|
122648
122607
|
function manifestPath(machineId, workingDir) {
|
|
122649
122608
|
const key = workspaceKeyFor(workingDir);
|
|
122650
|
-
return
|
|
122609
|
+
return join27(SYNC_STATE_DIR, machineId, key, "manifest.json");
|
|
122651
122610
|
}
|
|
122652
122611
|
async function ensureDir(filePath) {
|
|
122653
|
-
await fs11.mkdir(
|
|
122612
|
+
await fs11.mkdir(join27(filePath, ".."), { recursive: true, mode: 448 });
|
|
122654
122613
|
}
|
|
122655
122614
|
async function loadWorkspaceSyncManifest(machineId, workingDir) {
|
|
122656
122615
|
try {
|
|
@@ -122710,7 +122669,7 @@ function entriesFromPathIndex(paths) {
|
|
|
122710
122669
|
}
|
|
122711
122670
|
var SYNC_STATE_VERSION = "2", SYNC_STATE_DIR;
|
|
122712
122671
|
var init_workspace_sync_state = __esm(() => {
|
|
122713
|
-
SYNC_STATE_DIR =
|
|
122672
|
+
SYNC_STATE_DIR = join27(homedir11(), ".chatroom", "sync-state");
|
|
122714
122673
|
});
|
|
122715
122674
|
|
|
122716
122675
|
// src/infrastructure/services/workspace/workspace-file-tree-coordinator.ts
|
|
@@ -123088,12 +123047,12 @@ var init_durable_coalescing_state_schema = __esm(() => {
|
|
|
123088
123047
|
});
|
|
123089
123048
|
|
|
123090
123049
|
// src/daemon/infrastructure/outbox/lib/durable-coalescing-state-store.ts
|
|
123091
|
-
import { mkdirSync as
|
|
123092
|
-
import { dirname as
|
|
123093
|
-
import { DatabaseSync as
|
|
123050
|
+
import { mkdirSync as mkdirSync9 } from "node:fs";
|
|
123051
|
+
import { dirname as dirname15 } from "node:path";
|
|
123052
|
+
import { DatabaseSync as DatabaseSync4 } from "node:sqlite";
|
|
123094
123053
|
function openDurableCoalescingStateStore(path8) {
|
|
123095
|
-
|
|
123096
|
-
const db = new
|
|
123054
|
+
mkdirSync9(dirname15(path8), { recursive: true });
|
|
123055
|
+
const db = new DatabaseSync4(path8);
|
|
123097
123056
|
for (const sql of DURABLE_COALESCING_STATE_MIGRATIONS)
|
|
123098
123057
|
db.exec(sql);
|
|
123099
123058
|
db.prepare("UPDATE coalescing_outbox_entries SET status='pending' WHERE status='in_flight'").run();
|
|
@@ -124081,7 +124040,7 @@ var init_file_write_request_priority = __esm(() => {
|
|
|
124081
124040
|
|
|
124082
124041
|
// src/daemon/entry/files/file-write-fulfillment.ts
|
|
124083
124042
|
import { access as access4, mkdir as mkdir10, rename as rename4, rm as rm4, writeFile as writeFile10 } from "node:fs/promises";
|
|
124084
|
-
import { dirname as
|
|
124043
|
+
import { dirname as dirname16 } from "node:path";
|
|
124085
124044
|
function isTerminalFileWriteError(errorMessage) {
|
|
124086
124045
|
const terminalMessages = new Set([
|
|
124087
124046
|
"Invalid file path",
|
|
@@ -124180,7 +124139,7 @@ async function validateWriteOperation(operation, absolutePath) {
|
|
|
124180
124139
|
}
|
|
124181
124140
|
async function writePayloadToDisk(absolutePath, operation, content) {
|
|
124182
124141
|
if (operation === "create") {
|
|
124183
|
-
await mkdir10(
|
|
124142
|
+
await mkdir10(dirname16(absolutePath), { recursive: true });
|
|
124184
124143
|
await writeFile10(absolutePath, content, { flag: "wx" });
|
|
124185
124144
|
return;
|
|
124186
124145
|
}
|
|
@@ -124258,7 +124217,7 @@ async function fulfillOneFileWriteRequest(session2, request2) {
|
|
|
124258
124217
|
});
|
|
124259
124218
|
return;
|
|
124260
124219
|
}
|
|
124261
|
-
await mkdir10(
|
|
124220
|
+
await mkdir10(dirname16(targetResolved.absolutePath), { recursive: true });
|
|
124262
124221
|
await rename4(resolved.absolutePath, targetResolved.absolutePath);
|
|
124263
124222
|
await completeWriteRequest(session2, claimed._id, claimed.revision, { status: "done" });
|
|
124264
124223
|
const elapsed4 = Date.now() - startTime;
|
|
@@ -125333,16 +125292,16 @@ var init_workspace_list_subscription = __esm(() => {
|
|
|
125333
125292
|
|
|
125334
125293
|
// src/daemon/entry/workspace-git-inbound-registry.ts
|
|
125335
125294
|
function registerWorkspaceGitInboundHandler(h) {
|
|
125336
|
-
|
|
125295
|
+
handler4 = h;
|
|
125337
125296
|
}
|
|
125338
125297
|
function unregisterWorkspaceGitInboundHandler() {
|
|
125339
|
-
|
|
125298
|
+
handler4 = undefined;
|
|
125340
125299
|
}
|
|
125341
125300
|
async function dispatchWorkspaceGitInboundEvent(event) {
|
|
125342
|
-
if (
|
|
125343
|
-
await
|
|
125301
|
+
if (handler4)
|
|
125302
|
+
await handler4(event);
|
|
125344
125303
|
}
|
|
125345
|
-
var
|
|
125304
|
+
var handler4;
|
|
125346
125305
|
|
|
125347
125306
|
// src/events/lifecycle/on-daemon-shutdown.ts
|
|
125348
125307
|
var onDaemonShutdownEffect;
|
|
@@ -125360,6 +125319,19 @@ var init_on_daemon_shutdown = __esm(() => {
|
|
|
125360
125319
|
const activeAgents = agentPm.listActive();
|
|
125361
125320
|
if (activeAgents.length > 0) {
|
|
125362
125321
|
console.log(`[${formatTimestamp()}] Stopping ${activeAgents.length} agent(s) locally...`);
|
|
125322
|
+
yield* exports_Effect.promise(async () => {
|
|
125323
|
+
try {
|
|
125324
|
+
const tasksReleased = await session2.backend.mutation(api.daemon.taskStatus.releaseMachineTasks, {
|
|
125325
|
+
sessionId: session2.sessionId,
|
|
125326
|
+
machineId: session2.machineId
|
|
125327
|
+
});
|
|
125328
|
+
if (tasksReleased > 0) {
|
|
125329
|
+
console.log(`[${formatTimestamp()}] Released ${tasksReleased} in-flight task(s) to pending`);
|
|
125330
|
+
}
|
|
125331
|
+
} catch (error51) {
|
|
125332
|
+
console.log(`[${formatTimestamp()}] ⚠️ Failed to release in-flight tasks on shutdown: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
125333
|
+
}
|
|
125334
|
+
});
|
|
125363
125335
|
let totalStopped = 0;
|
|
125364
125336
|
let totalFailed = 0;
|
|
125365
125337
|
yield* exports_Effect.all(activeAgents.map(({ chatroomId, role }) => exports_Effect.promise(() => agentPm.stopAgent({ chatroomId, role, reason: "daemon.shutdown" })).pipe(exports_Effect.tap(() => exports_Effect.sync(() => {
|
|
@@ -125389,7 +125361,6 @@ function createDaemonRuntime(deps) {
|
|
|
125389
125361
|
let workspaceListSubscriptionHandle = null;
|
|
125390
125362
|
let logObserverSubscriptionHandle = null;
|
|
125391
125363
|
let agenticQueryWorkerHandle = null;
|
|
125392
|
-
let enhancerWorkerHandle = null;
|
|
125393
125364
|
let taskInboxHandle = null;
|
|
125394
125365
|
let agentConfigRegistryHandle = null;
|
|
125395
125366
|
const activeSessions = new Map;
|
|
@@ -125430,7 +125401,6 @@ function createDaemonRuntime(deps) {
|
|
|
125430
125401
|
taskInboxHandle?.stop();
|
|
125431
125402
|
logObserverSubscriptionHandle?.stop();
|
|
125432
125403
|
agenticQueryWorkerHandle?.stop();
|
|
125433
|
-
enhancerWorkerHandle?.stop();
|
|
125434
125404
|
};
|
|
125435
125405
|
const shutdown = async () => {
|
|
125436
125406
|
if (isShuttingDown)
|
|
@@ -125548,7 +125518,6 @@ function createDaemonRuntime(deps) {
|
|
|
125548
125518
|
backend: session2.backend,
|
|
125549
125519
|
convexUrl: session2.convexUrl
|
|
125550
125520
|
}, activeSessions, harnesses);
|
|
125551
|
-
enhancerWorkerHandle = startEnhancerSubscriptions(session2.sessionId, session2.machineId, session2.convexUrl, deps.wsClient, session2.backend, session2.agentServices, getActiveLogSink());
|
|
125552
125521
|
console.log(`
|
|
125553
125522
|
Listening for commands...`);
|
|
125554
125523
|
console.log(`Press Ctrl+C to stop
|
|
@@ -125585,7 +125554,6 @@ var init_daemon_runtime = __esm(() => {
|
|
|
125585
125554
|
init_start_subscriptions();
|
|
125586
125555
|
init_command_dispatch();
|
|
125587
125556
|
init_daemon_services();
|
|
125588
|
-
init_start_subscriptions2();
|
|
125589
125557
|
init_file_content_subscription();
|
|
125590
125558
|
init_file_tree_subscription();
|
|
125591
125559
|
init_file_write_subscription();
|
|
@@ -125593,7 +125561,6 @@ var init_daemon_runtime = __esm(() => {
|
|
|
125593
125561
|
init_orphan_tracker();
|
|
125594
125562
|
init_command_run_subscription();
|
|
125595
125563
|
init_log_observer_sync();
|
|
125596
|
-
init_init_daemon();
|
|
125597
125564
|
init_task_inbox_runtime();
|
|
125598
125565
|
init_git_subscription();
|
|
125599
125566
|
init_api3();
|
|
@@ -125636,21 +125603,6 @@ function createCommandRouterDeps() {
|
|
|
125636
125603
|
}
|
|
125637
125604
|
var init_command_bridge = () => {};
|
|
125638
125605
|
|
|
125639
|
-
// src/daemon/domain/usecase/process-enhancer-job.ts
|
|
125640
|
-
async function processEnhancerJobInbound(deps, event) {
|
|
125641
|
-
await deps.dispatchInbound(event);
|
|
125642
|
-
}
|
|
125643
|
-
|
|
125644
|
-
// src/daemon/entry/bridge/enhancer-bridge.ts
|
|
125645
|
-
function createEnhancerRouterDeps() {
|
|
125646
|
-
return {
|
|
125647
|
-
deliverInbound: async (event) => {
|
|
125648
|
-
await processEnhancerJobInbound({ dispatchInbound: dispatchEnhancerInboundEvent }, event);
|
|
125649
|
-
}
|
|
125650
|
-
};
|
|
125651
|
-
}
|
|
125652
|
-
var init_enhancer_bridge = () => {};
|
|
125653
|
-
|
|
125654
125606
|
// src/daemon/domain/usecase/fulfill-file-content-request.ts
|
|
125655
125607
|
async function fulfillFileContentRequest(deps, event) {
|
|
125656
125608
|
await deps.dispatchInbound(event);
|
|
@@ -125720,14 +125672,12 @@ function createDefaultEventRouterDeps() {
|
|
|
125720
125672
|
command: createCommandRouterDeps(),
|
|
125721
125673
|
workspaceGit: createWorkspaceGitRouterDeps(),
|
|
125722
125674
|
file: createFileRouterDeps(),
|
|
125723
|
-
agenticQuery: createAgenticQueryRouterDeps()
|
|
125724
|
-
enhancer: createEnhancerRouterDeps()
|
|
125675
|
+
agenticQuery: createAgenticQueryRouterDeps()
|
|
125725
125676
|
};
|
|
125726
125677
|
}
|
|
125727
125678
|
var init_default_router_deps = __esm(() => {
|
|
125728
125679
|
init_agentic_query_bridge();
|
|
125729
125680
|
init_command_bridge();
|
|
125730
|
-
init_enhancer_bridge();
|
|
125731
125681
|
init_file_bridge();
|
|
125732
125682
|
init_workspace_git_bridge();
|
|
125733
125683
|
});
|
|
@@ -126008,7 +125958,6 @@ async function executeChatroomStopCommand(args2) {
|
|
|
126008
125958
|
args2.apm.markStopIntent(args2.chatroomId, args2.role, "user.stop", undefined, args2.workingDir);
|
|
126009
125959
|
else if (!args2.workingDir) {
|
|
126010
125960
|
args2.apm.markChatroomStopIntent(args2.chatroomId, "user.stop");
|
|
126011
|
-
await abortEnhancerSpawnsForChatroom(args2.chatroomId);
|
|
126012
125961
|
}
|
|
126013
125962
|
const confirmedDeps = args2.apm.getConfirmedStopAdapterDeps();
|
|
126014
125963
|
const targets = await args2.apm.discoverStopTargets(args2.chatroomId);
|
|
@@ -126041,15 +125990,14 @@ async function executeChatroomStopCommand(args2) {
|
|
|
126041
125990
|
}
|
|
126042
125991
|
var init_execute_chatroom_stop_command = __esm(() => {
|
|
126043
125992
|
init_reliability();
|
|
126044
|
-
init_enhancer_spawn_registry();
|
|
126045
125993
|
init_agent_process_service2();
|
|
126046
125994
|
});
|
|
126047
125995
|
|
|
126048
125996
|
// src/daemon/entry/persistence-path.ts
|
|
126049
|
-
import { homedir as
|
|
126050
|
-
import { join as
|
|
125997
|
+
import { homedir as homedir12 } from "node:os";
|
|
125998
|
+
import { join as join28 } from "node:path";
|
|
126051
125999
|
function resolvePersistenceDbPath(machineId) {
|
|
126052
|
-
return
|
|
126000
|
+
return join28(homedir12(), ".chatroom", "daemon", machineId, "events.sqlite");
|
|
126053
126001
|
}
|
|
126054
126002
|
var init_persistence_path = () => {};
|
|
126055
126003
|
|
|
@@ -126067,13 +126015,6 @@ async function handleCommandInbound(deps, event) {
|
|
|
126067
126015
|
}
|
|
126068
126016
|
}
|
|
126069
126017
|
|
|
126070
|
-
// src/daemon/domain/usecase/handle-enhancer-inbound.ts
|
|
126071
|
-
async function handleEnhancerInbound(deps, event) {
|
|
126072
|
-
if (deps.deliverInbound) {
|
|
126073
|
-
await deps.deliverInbound(event);
|
|
126074
|
-
}
|
|
126075
|
-
}
|
|
126076
|
-
|
|
126077
126018
|
// src/daemon/domain/usecase/handle-file-inbound.ts
|
|
126078
126019
|
async function handleFileInbound(deps, event) {
|
|
126079
126020
|
if (deps.deliverInbound) {
|
|
@@ -126109,9 +126050,6 @@ async function routeInboundEvent(deps, event) {
|
|
|
126109
126050
|
case "agentic-query.prompt":
|
|
126110
126051
|
await handleAgenticQueryInbound(deps.agenticQuery, event);
|
|
126111
126052
|
break;
|
|
126112
|
-
case "enhancer.job-assigned":
|
|
126113
|
-
await handleEnhancerInbound(deps.enhancer, event);
|
|
126114
|
-
break;
|
|
126115
126053
|
default:
|
|
126116
126054
|
}
|
|
126117
126055
|
}
|
|
@@ -126219,80 +126157,6 @@ var init_command_run = __esm(() => {
|
|
|
126219
126157
|
init_api3();
|
|
126220
126158
|
});
|
|
126221
126159
|
|
|
126222
|
-
// src/daemon/infrastructure/convex/subscribers/enhancer-job.ts
|
|
126223
|
-
function startEnhancerJobSubscriber2(deps, onEvent) {
|
|
126224
|
-
const seen = new Set;
|
|
126225
|
-
const watchers = new Map;
|
|
126226
|
-
let stopped = false;
|
|
126227
|
-
let refreshInFlight = false;
|
|
126228
|
-
const onPendingJobs = (jobs) => {
|
|
126229
|
-
if (!jobs?.length)
|
|
126230
|
-
return;
|
|
126231
|
-
for (const job of jobs) {
|
|
126232
|
-
if (job == null || typeof job !== "object" || !("jobId" in job))
|
|
126233
|
-
continue;
|
|
126234
|
-
if (seen.has(job.jobId))
|
|
126235
|
-
continue;
|
|
126236
|
-
seen.add(job.jobId);
|
|
126237
|
-
onEvent({ type: "enhancer.job-assigned", jobId: job.jobId });
|
|
126238
|
-
}
|
|
126239
|
-
};
|
|
126240
|
-
const onError3 = (err) => {
|
|
126241
|
-
console.warn(`[daemon] enhancer-job subscriber error: ${err instanceof Error ? err.message : String(err)}`);
|
|
126242
|
-
};
|
|
126243
|
-
const watchChatroom = (chatroomId) => {
|
|
126244
|
-
if (watchers.has(chatroomId) || stopped)
|
|
126245
|
-
return;
|
|
126246
|
-
const unsub = deps.wsClient.onUpdate(api.daemon.enhancer.index.pendingForChatroom, {
|
|
126247
|
-
sessionId: deps.sessionId,
|
|
126248
|
-
machineId: deps.machineId,
|
|
126249
|
-
chatroomId
|
|
126250
|
-
}, onPendingJobs, onError3);
|
|
126251
|
-
watchers.set(chatroomId, unsub);
|
|
126252
|
-
};
|
|
126253
|
-
const refreshChatrooms = async () => {
|
|
126254
|
-
if (refreshInFlight)
|
|
126255
|
-
return;
|
|
126256
|
-
refreshInFlight = true;
|
|
126257
|
-
try {
|
|
126258
|
-
const workspaces = await deps.wsClient.query(api.workspaces.listWorkspacesForMachine, {
|
|
126259
|
-
sessionId: deps.sessionId,
|
|
126260
|
-
machineId: deps.machineId
|
|
126261
|
-
});
|
|
126262
|
-
if (stopped)
|
|
126263
|
-
return;
|
|
126264
|
-
const roomIds = [
|
|
126265
|
-
...new Set((workspaces ?? []).map((ws) => ws.chatroomId))
|
|
126266
|
-
];
|
|
126267
|
-
for (const [roomId, unsub] of watchers) {
|
|
126268
|
-
if (!roomIds.includes(roomId)) {
|
|
126269
|
-
unsub();
|
|
126270
|
-
watchers.delete(roomId);
|
|
126271
|
-
}
|
|
126272
|
-
}
|
|
126273
|
-
for (const roomId of roomIds)
|
|
126274
|
-
watchChatroom(roomId);
|
|
126275
|
-
} catch (error51) {
|
|
126276
|
-
console.warn(`[daemon] enhancer-job room refresh failed: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
126277
|
-
} finally {
|
|
126278
|
-
refreshInFlight = false;
|
|
126279
|
-
}
|
|
126280
|
-
};
|
|
126281
|
-
refreshChatrooms();
|
|
126282
|
-
return {
|
|
126283
|
-
async stop() {
|
|
126284
|
-
stopped = true;
|
|
126285
|
-
for (const unsub of watchers.values())
|
|
126286
|
-
unsub();
|
|
126287
|
-
watchers.clear();
|
|
126288
|
-
},
|
|
126289
|
-
refreshChatrooms
|
|
126290
|
-
};
|
|
126291
|
-
}
|
|
126292
|
-
var init_enhancer_job = __esm(() => {
|
|
126293
|
-
init_api3();
|
|
126294
|
-
});
|
|
126295
|
-
|
|
126296
126160
|
// src/daemon/infrastructure/convex/subscribers/pending-file-request-dedup.ts
|
|
126297
126161
|
function pendingConvexId(req) {
|
|
126298
126162
|
if (req._id == null)
|
|
@@ -126609,7 +126473,6 @@ function startAllSubscribers(deps) {
|
|
|
126609
126473
|
const onEvent = (event) => {
|
|
126610
126474
|
routeInboundEvent(deps.router, event);
|
|
126611
126475
|
};
|
|
126612
|
-
const enhancerJob = startEnhancerJobSubscriber2(deps, onEvent);
|
|
126613
126476
|
const gitRequest = startGitRequestSubscriber(deps, onEvent);
|
|
126614
126477
|
const machineCommands = startMachineCommandInboxSubscriber(deps, async (claimed) => {
|
|
126615
126478
|
if (claimed.type === "agent.stop") {
|
|
@@ -126640,8 +126503,7 @@ function startAllSubscribers(deps) {
|
|
|
126640
126503
|
fileContent.stop(),
|
|
126641
126504
|
fileWrite.stop(),
|
|
126642
126505
|
agenticQuerySession.stop(),
|
|
126643
|
-
agenticQueryPrompt.stop()
|
|
126644
|
-
enhancerJob.stop()
|
|
126506
|
+
agenticQueryPrompt.stop()
|
|
126645
126507
|
]);
|
|
126646
126508
|
}
|
|
126647
126509
|
};
|
|
@@ -126651,7 +126513,6 @@ var init_subscriber_registry = __esm(() => {
|
|
|
126651
126513
|
init_agentic_query_prompt();
|
|
126652
126514
|
init_agentic_query_session();
|
|
126653
126515
|
init_command_run();
|
|
126654
|
-
init_enhancer_job();
|
|
126655
126516
|
init_file_content_request();
|
|
126656
126517
|
init_file_tree_release_request();
|
|
126657
126518
|
init_file_tree_request();
|
|
@@ -126700,12 +126561,12 @@ var init_schema = __esm(() => {
|
|
|
126700
126561
|
});
|
|
126701
126562
|
|
|
126702
126563
|
// src/daemon/infrastructure/persistence/open-database.ts
|
|
126703
|
-
import { mkdirSync as
|
|
126704
|
-
import { dirname as
|
|
126705
|
-
import { DatabaseSync as
|
|
126564
|
+
import { mkdirSync as mkdirSync10 } from "node:fs";
|
|
126565
|
+
import { dirname as dirname17 } from "node:path";
|
|
126566
|
+
import { DatabaseSync as DatabaseSync5 } from "node:sqlite";
|
|
126706
126567
|
function openDatabase(dbPath) {
|
|
126707
|
-
|
|
126708
|
-
const db = new
|
|
126568
|
+
mkdirSync10(dirname17(dbPath), { recursive: true });
|
|
126569
|
+
const db = new DatabaseSync5(dbPath);
|
|
126709
126570
|
for (const sql of MIGRATIONS2) {
|
|
126710
126571
|
db.exec(sql);
|
|
126711
126572
|
}
|
|
@@ -134200,19 +134061,19 @@ function routeRequest(req, res, deps) {
|
|
|
134200
134061
|
|
|
134201
134062
|
// src/daemon/local-web/server/serve-static.ts
|
|
134202
134063
|
import { existsSync as existsSync10, readFileSync as readFileSync11 } from "node:fs";
|
|
134203
|
-
import { dirname as
|
|
134064
|
+
import { dirname as dirname18, join as join29 } from "node:path";
|
|
134204
134065
|
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
134205
134066
|
function clientDistCandidates(here) {
|
|
134206
134067
|
return [
|
|
134207
|
-
|
|
134208
|
-
|
|
134209
|
-
|
|
134068
|
+
join29(here, "client/build"),
|
|
134069
|
+
join29(here, "../client/build"),
|
|
134070
|
+
join29(here, "../src/daemon/local-web/client/build")
|
|
134210
134071
|
];
|
|
134211
134072
|
}
|
|
134212
|
-
function resolveClientDistDir(here =
|
|
134073
|
+
function resolveClientDistDir(here = dirname18(fileURLToPath7(import.meta.url))) {
|
|
134213
134074
|
const candidates = clientDistCandidates(here);
|
|
134214
134075
|
for (const dir of candidates) {
|
|
134215
|
-
if (existsSync10(
|
|
134076
|
+
if (existsSync10(join29(dir, "index.html")))
|
|
134216
134077
|
return dir;
|
|
134217
134078
|
}
|
|
134218
134079
|
return candidates[0];
|
|
@@ -134225,7 +134086,7 @@ function tryServeStatic(req, res, distDir) {
|
|
|
134225
134086
|
return false;
|
|
134226
134087
|
}
|
|
134227
134088
|
const safePath = pathname === "/" ? "/index.html" : pathname;
|
|
134228
|
-
const filePath =
|
|
134089
|
+
const filePath = join29(distDir, safePath);
|
|
134229
134090
|
if (!filePath.startsWith(distDir)) {
|
|
134230
134091
|
res.writeHead(403);
|
|
134231
134092
|
res.end();
|
|
@@ -134242,7 +134103,7 @@ function tryServeStatic(req, res, distDir) {
|
|
|
134242
134103
|
}
|
|
134243
134104
|
return true;
|
|
134244
134105
|
}
|
|
134245
|
-
const indexPath =
|
|
134106
|
+
const indexPath = join29(distDir, "index.html");
|
|
134246
134107
|
if (existsSync10(indexPath)) {
|
|
134247
134108
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
134248
134109
|
if (req.method === "HEAD") {
|
|
@@ -134291,6 +134152,14 @@ function normalizeError(err) {
|
|
|
134291
134152
|
details: err.flatten()
|
|
134292
134153
|
};
|
|
134293
134154
|
}
|
|
134155
|
+
if (err instanceof ConvexError) {
|
|
134156
|
+
const data = err.data;
|
|
134157
|
+
return {
|
|
134158
|
+
code: data.code ?? "internal_error",
|
|
134159
|
+
message: data.message ?? err.message,
|
|
134160
|
+
details: err.data
|
|
134161
|
+
};
|
|
134162
|
+
}
|
|
134294
134163
|
if (err instanceof Error) {
|
|
134295
134164
|
const code2 = "code" in err && typeof err.code === "string" ? err.code : "internal_error";
|
|
134296
134165
|
if (code2 === "not_found" || code2 === "validation_error" || code2 === "unauthorized") {
|
|
@@ -134301,6 +134170,7 @@ function normalizeError(err) {
|
|
|
134301
134170
|
return { code: "internal_error", message: "Unknown error" };
|
|
134302
134171
|
}
|
|
134303
134172
|
var init_normalize_error = __esm(() => {
|
|
134173
|
+
init_values();
|
|
134304
134174
|
init_zod();
|
|
134305
134175
|
});
|
|
134306
134176
|
|
|
@@ -134431,6 +134301,16 @@ function extractAck(args2) {
|
|
|
134431
134301
|
}
|
|
134432
134302
|
return { payload: args2[0], ack: undefined };
|
|
134433
134303
|
}
|
|
134304
|
+
async function resolveDebugStatePayload(deps, payload) {
|
|
134305
|
+
if (!deps.debugState)
|
|
134306
|
+
throw new Error("daemon debug state is not configured");
|
|
134307
|
+
const { chatroomId } = debugStateInputSchema.parse(payload ?? {});
|
|
134308
|
+
const data = await deps.debugState(chatroomId);
|
|
134309
|
+
if (data && typeof data === "object" && deps.cliGateway) {
|
|
134310
|
+
data.cliGateway = deps.cliGateway.debugState();
|
|
134311
|
+
}
|
|
134312
|
+
return data;
|
|
134313
|
+
}
|
|
134434
134314
|
function registerSocketHandlers(io2, deps) {
|
|
134435
134315
|
const logHistory = deps.logRepo ? createLogHistoryUseCase({ reader: deps.logRepo }) : undefined;
|
|
134436
134316
|
const eventStreamHistory = deps.logRepo ? createEventStreamHistoryUseCase({ reader: deps.logRepo }) : undefined;
|
|
@@ -134450,13 +134330,22 @@ function registerSocketHandlers(io2, deps) {
|
|
|
134450
134330
|
callAck(ack, { ok: false, error: normalizeError(err) });
|
|
134451
134331
|
}
|
|
134452
134332
|
});
|
|
134333
|
+
socket.on("cli.handoff", async (...args2) => {
|
|
134334
|
+
const { payload, ack } = extractAck(args2);
|
|
134335
|
+
try {
|
|
134336
|
+
if (!deps.cliGateway)
|
|
134337
|
+
throw new Error("CLI gateway is not configured");
|
|
134338
|
+
const data = await deps.cliGateway.handoff(payload);
|
|
134339
|
+
callAck(ack, { ok: true, data });
|
|
134340
|
+
} catch (err) {
|
|
134341
|
+
callAck(ack, { ok: false, error: normalizeError(err) });
|
|
134342
|
+
}
|
|
134343
|
+
});
|
|
134453
134344
|
socket.on("daemon.debug.state", async (...args2) => {
|
|
134454
134345
|
const { payload, ack } = extractAck(args2);
|
|
134455
134346
|
try {
|
|
134456
|
-
|
|
134457
|
-
|
|
134458
|
-
const { chatroomId } = debugStateInputSchema.parse(payload ?? {});
|
|
134459
|
-
callAck(ack, { ok: true, data: await deps.debugState(chatroomId) });
|
|
134347
|
+
const data = await resolveDebugStatePayload(deps, payload);
|
|
134348
|
+
callAck(ack, { ok: true, data });
|
|
134460
134349
|
} catch (err) {
|
|
134461
134350
|
callAck(ack, { ok: false, error: normalizeError(err) });
|
|
134462
134351
|
}
|
|
@@ -134640,7 +134529,8 @@ async function startLocalWebServer(config4, deps = {}) {
|
|
|
134640
134529
|
eventStreamHub: deps.eventStreamHub,
|
|
134641
134530
|
backend: deps.backend,
|
|
134642
134531
|
sessionId: deps.sessionId,
|
|
134643
|
-
debugState: deps.debugState
|
|
134532
|
+
debugState: deps.debugState,
|
|
134533
|
+
cliGateway: deps.cliGateway
|
|
134644
134534
|
});
|
|
134645
134535
|
return {
|
|
134646
134536
|
port: boundPort,
|
|
@@ -134696,6 +134586,80 @@ function createLogStreamHub() {
|
|
|
134696
134586
|
};
|
|
134697
134587
|
}
|
|
134698
134588
|
|
|
134589
|
+
// src/daemon/services/cli-gateway-service/index.ts
|
|
134590
|
+
function createCliGatewayService(deps) {
|
|
134591
|
+
const logs2 = [];
|
|
134592
|
+
const writeLog = (message) => {
|
|
134593
|
+
logs2.push({ timestamp: Date.now(), message });
|
|
134594
|
+
if (logs2.length > 100)
|
|
134595
|
+
logs2.shift();
|
|
134596
|
+
(deps.log ?? console.log)(`[CliGateway:${message}]`);
|
|
134597
|
+
};
|
|
134598
|
+
return {
|
|
134599
|
+
handoff: async (args2) => {
|
|
134600
|
+
writeLog(`request handoff chatroom=${args2.chatroomId} role=${args2.senderRole}`);
|
|
134601
|
+
const taskIdsBeforeCommit = getActiveTaskIdsForRole(deps, args2);
|
|
134602
|
+
const result = await commitHandoffMutation(deps, args2, writeLog);
|
|
134603
|
+
writeLog(`backend result success=${result.success}`);
|
|
134604
|
+
if (result.success) {
|
|
134605
|
+
await syncTaskServiceAfterHandoff(deps, args2, result, taskIdsBeforeCommit, writeLog);
|
|
134606
|
+
}
|
|
134607
|
+
return result;
|
|
134608
|
+
},
|
|
134609
|
+
debugState: () => ({ port: deps.port, logs: [...logs2] })
|
|
134610
|
+
};
|
|
134611
|
+
}
|
|
134612
|
+
function getActiveTaskIdsForRole(deps, args2) {
|
|
134613
|
+
return deps.taskService.listTasksForRole?.(args2.chatroomId, args2.senderRole).filter((task) => task.status === "acknowledged" || task.status === "in_progress").map((task) => task.taskId) ?? [];
|
|
134614
|
+
}
|
|
134615
|
+
async function commitHandoffMutation(deps, args2, writeLog) {
|
|
134616
|
+
try {
|
|
134617
|
+
return await deps.backend.mutation(api.messages.handoff, args2);
|
|
134618
|
+
} catch (error51) {
|
|
134619
|
+
writeLog(`backend failure=${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
134620
|
+
throw error51;
|
|
134621
|
+
}
|
|
134622
|
+
}
|
|
134623
|
+
async function syncTaskServiceAfterHandoff(deps, args2, result, taskIdsBeforeCommit, writeLog) {
|
|
134624
|
+
try {
|
|
134625
|
+
const nextTask = await adoptNextHandoffTask(deps, args2, result);
|
|
134626
|
+
await deps.taskService.recordHandoffOutcome({
|
|
134627
|
+
chatroomId: args2.chatroomId,
|
|
134628
|
+
role: args2.senderRole,
|
|
134629
|
+
targetRole: args2.targetRole,
|
|
134630
|
+
nextTask,
|
|
134631
|
+
taskIds: taskIdsBeforeCommit
|
|
134632
|
+
});
|
|
134633
|
+
writeLog(`task-service updated chatroom=${args2.chatroomId} role=${args2.senderRole}` + (nextTask ? ` adopted=${nextTask.taskId}` : ""));
|
|
134634
|
+
} catch (error51) {
|
|
134635
|
+
writeLog(`post-commit sync failure chatroom=${args2.chatroomId} error=${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
134636
|
+
await recordFallbackHandoffOutcome(deps, args2, writeLog);
|
|
134637
|
+
}
|
|
134638
|
+
}
|
|
134639
|
+
async function adoptNextHandoffTask(deps, args2, result) {
|
|
134640
|
+
if (!result.newTaskId || args2.targetRole.toLowerCase() === "user")
|
|
134641
|
+
return;
|
|
134642
|
+
return await deps.taskService.loadAssignedTaskForAction({
|
|
134643
|
+
chatroomId: args2.chatroomId,
|
|
134644
|
+
role: args2.targetRole,
|
|
134645
|
+
taskId: result.newTaskId
|
|
134646
|
+
}) ?? undefined;
|
|
134647
|
+
}
|
|
134648
|
+
async function recordFallbackHandoffOutcome(deps, args2, writeLog) {
|
|
134649
|
+
try {
|
|
134650
|
+
await deps.taskService.recordHandoffOutcome({
|
|
134651
|
+
chatroomId: args2.chatroomId,
|
|
134652
|
+
role: args2.senderRole,
|
|
134653
|
+
targetRole: args2.targetRole
|
|
134654
|
+
});
|
|
134655
|
+
} catch (cleanupError) {
|
|
134656
|
+
writeLog(`post-commit cleanup failure chatroom=${args2.chatroomId} error=${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`);
|
|
134657
|
+
}
|
|
134658
|
+
}
|
|
134659
|
+
var init_cli_gateway_service = __esm(() => {
|
|
134660
|
+
init_api3();
|
|
134661
|
+
});
|
|
134662
|
+
|
|
134699
134663
|
// src/daemon/entry/start-daemon.ts
|
|
134700
134664
|
async function startDaemon() {
|
|
134701
134665
|
let resolveBoundPort;
|
|
@@ -134730,6 +134694,11 @@ async function startDaemon() {
|
|
|
134730
134694
|
logEvent: init2.logEvent
|
|
134731
134695
|
});
|
|
134732
134696
|
const localWebPort = resolveLocalWebPort();
|
|
134697
|
+
const cliGateway = createCliGatewayService({
|
|
134698
|
+
backend: init2.backend,
|
|
134699
|
+
port: localWebPort,
|
|
134700
|
+
taskService: init2.taskService
|
|
134701
|
+
});
|
|
134733
134702
|
const debugState = async (chatroomId) => {
|
|
134734
134703
|
const persisted = await loadDaemonState(init2.machineId);
|
|
134735
134704
|
const persistedAgents = Object.fromEntries(Object.entries(persisted?.agents ?? {}).filter(([key]) => key.startsWith(`${chatroomId}/`)));
|
|
@@ -134787,7 +134756,8 @@ async function startDaemon() {
|
|
|
134787
134756
|
eventStreamHub,
|
|
134788
134757
|
backend: init2.backend,
|
|
134789
134758
|
sessionId: init2.sessionId,
|
|
134790
|
-
debugState
|
|
134759
|
+
debugState,
|
|
134760
|
+
cliGateway
|
|
134791
134761
|
});
|
|
134792
134762
|
resolveBoundPort(localWeb.port);
|
|
134793
134763
|
const subscribers = startAllSubscribers({
|
|
@@ -134848,6 +134818,7 @@ var init_start_daemon = __esm(() => {
|
|
|
134848
134818
|
init_log_repository();
|
|
134849
134819
|
init_socket3();
|
|
134850
134820
|
init_create_local_web_server();
|
|
134821
|
+
init_cli_gateway_service();
|
|
134851
134822
|
});
|
|
134852
134823
|
|
|
134853
134824
|
// src/commands/machine/daemon-start/index.ts
|
|
@@ -135657,10 +135628,10 @@ teamCommand.command("set").description("Set the team preset for a chatroom").req
|
|
|
135657
135628
|
const { setTeam: setTeam2 } = await Promise.resolve().then(() => (init_team(), exports_team));
|
|
135658
135629
|
await setTeam2(options.chatroomId, options.team);
|
|
135659
135630
|
});
|
|
135660
|
-
handoffCommandGroup.command("view-template").description("Print
|
|
135631
|
+
handoffCommandGroup.command("view-template").description("Print a handoff message template; omit --next-role to inspect a generic architect or UI/UX engineer template").option("--team-id <teamId>", "Team id (solo, duo); defaults to duo").action(async function(options) {
|
|
135661
135632
|
const parentOpts = this.parent?.opts() ?? {};
|
|
135662
|
-
if (!parentOpts.role
|
|
135663
|
-
console.error(
|
|
135633
|
+
if (!parentOpts.role) {
|
|
135634
|
+
console.error(`error: required option '--role <role>' not specified`);
|
|
135664
135635
|
process.exit(1);
|
|
135665
135636
|
}
|
|
135666
135637
|
const { printHandoffViewTemplate: printHandoffViewTemplate2 } = await Promise.resolve().then(() => (init_view_template3(), exports_view_template));
|
|
@@ -136104,4 +136075,4 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
|
136104
136075
|
});
|
|
136105
136076
|
program2.parse();
|
|
136106
136077
|
|
|
136107
|
-
//# debugId=
|
|
136078
|
+
//# debugId=318DFD58C705B11264756E2164756E21
|