@spencer-kit/coder-studio 0.4.6 → 0.4.8

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.
@@ -625,7 +625,15 @@ var init_definition = __esm({
625
625
  id: "claude",
626
626
  displayName: "Claude Code",
627
627
  badge: "Claude",
628
+ kind: "built_in",
628
629
  capability: "full",
630
+ capabilities: [
631
+ { key: "interactive_session", supported: true, label: "Interactive session" },
632
+ { key: "supervisor_eval", supported: true, label: "Supervisor evaluation" },
633
+ { key: "idle_detection", supported: true, label: "Idle detection" },
634
+ { key: "context_attach", supported: false, label: "Context attach" },
635
+ { key: "review", supported: false, label: "Review" }
636
+ ],
629
637
  install: claudeInstallMetadata,
630
638
  // ===== Command construction =====
631
639
  buildCommand(config, ctx) {
@@ -795,7 +803,15 @@ var init_definition2 = __esm({
795
803
  id: "codex",
796
804
  displayName: "Codex",
797
805
  badge: "Codex",
806
+ kind: "built_in",
798
807
  capability: "full",
808
+ capabilities: [
809
+ { key: "interactive_session", supported: true, label: "Interactive session" },
810
+ { key: "supervisor_eval", supported: true, label: "Supervisor evaluation" },
811
+ { key: "idle_detection", supported: true, label: "Idle detection" },
812
+ { key: "context_attach", supported: false, label: "Context attach" },
813
+ { key: "review", supported: false, label: "Review" }
814
+ ],
799
815
  install: codexInstallMetadata,
800
816
  // ===== Command construction =====
801
817
  buildCommand(config, ctx) {
@@ -828,7 +844,78 @@ var init_definition2 = __esm({
828
844
  }
829
845
  });
830
846
 
847
+ // packages/providers/src/presets.ts
848
+ function cloneCapabilities(capabilities) {
849
+ return capabilities.map((capability) => ({ ...capability }));
850
+ }
851
+ var defaultCapabilities, providerPresets;
852
+ var init_presets = __esm({
853
+ "packages/providers/src/presets.ts"() {
854
+ "use strict";
855
+ defaultCapabilities = [
856
+ { key: "interactive_session", supported: true, label: "Interactive session" },
857
+ { key: "context_attach", supported: true, label: "Context attach" },
858
+ { key: "review", supported: true, label: "Review" }
859
+ ];
860
+ providerPresets = [
861
+ {
862
+ id: "gemini-cli",
863
+ displayName: "Gemini CLI",
864
+ kind: "preset",
865
+ description: "Preset metadata for launching Google's Gemini CLI through the custom provider flow.",
866
+ command: "gemini",
867
+ args: [],
868
+ env: {},
869
+ cwdMode: "workspace_root",
870
+ sessionMode: "interactive",
871
+ startupPrompt: "Follow the workspace instructions and explain important tradeoffs.",
872
+ capabilities: cloneCapabilities(defaultCapabilities),
873
+ requiredCommands: ["gemini"]
874
+ },
875
+ {
876
+ id: "aider",
877
+ displayName: "Aider",
878
+ kind: "preset",
879
+ description: "Preset metadata for launching Aider as a workspace-root interactive coding agent.",
880
+ command: "aider",
881
+ args: [],
882
+ env: {},
883
+ cwdMode: "workspace_root",
884
+ sessionMode: "interactive",
885
+ startupPrompt: "Review the current workspace state before making edits.",
886
+ capabilities: cloneCapabilities(defaultCapabilities),
887
+ requiredCommands: ["aider"]
888
+ },
889
+ {
890
+ id: "opencode",
891
+ displayName: "OpenCode",
892
+ kind: "preset",
893
+ description: "Preset metadata for launching OpenCode from the workspace root.",
894
+ command: "opencode",
895
+ args: [],
896
+ env: {},
897
+ cwdMode: "workspace_root",
898
+ sessionMode: "interactive",
899
+ startupPrompt: "Use the repository instructions and verify changes before finishing.",
900
+ capabilities: cloneCapabilities(defaultCapabilities),
901
+ requiredCommands: ["opencode"]
902
+ }
903
+ ];
904
+ }
905
+ });
906
+
831
907
  // packages/providers/src/registry.ts
908
+ function toProviderListItem(provider) {
909
+ return {
910
+ id: provider.id,
911
+ displayName: provider.displayName,
912
+ badge: provider.badge,
913
+ kind: provider.kind,
914
+ capability: provider.capability,
915
+ capabilities: provider.capabilities.map((capability) => ({ ...capability })),
916
+ requiredCommands: [...provider.requiredCommands]
917
+ };
918
+ }
832
919
  var providerRegistry;
833
920
  var init_registry = __esm({
834
921
  "packages/providers/src/registry.ts"() {
@@ -848,6 +935,7 @@ var init_src = __esm({
848
935
  init_config_schema2();
849
936
  init_definition2();
850
937
  init_stdout_heuristics();
938
+ init_presets();
851
939
  init_registry();
852
940
  }
853
941
  });
@@ -1690,7 +1778,7 @@ import { mkdir as mkdir3, mkdtemp, rm as rm3, writeFile as writeFile2 } from "fs
1690
1778
  import os2 from "os";
1691
1779
  import path7 from "path";
1692
1780
  async function runGit(cwd, args, options = {}) {
1693
- return new Promise((resolve6, reject) => {
1781
+ return new Promise((resolve8, reject) => {
1694
1782
  const gitArgs = [
1695
1783
  ...options.config?.flatMap(([key, value]) => ["-c", `${key}=${value}`]) ?? [],
1696
1784
  ...args
@@ -1717,7 +1805,7 @@ async function runGit(cwd, args, options = {}) {
1717
1805
  if (err) {
1718
1806
  reject(new GitError(err.message, stderr));
1719
1807
  } else {
1720
- resolve6({ stdout, stderr });
1808
+ resolve8({ stdout, stderr });
1721
1809
  }
1722
1810
  }
1723
1811
  );
@@ -3598,12 +3686,12 @@ var init_auto_fetch = __esm({
3598
3686
  }
3599
3687
  acquireWorkspaceOperation(workspaceId) {
3600
3688
  const state = this.getOrCreateState(workspaceId);
3601
- return new Promise((resolve6) => {
3689
+ return new Promise((resolve8) => {
3602
3690
  const grant = () => {
3603
3691
  state.inFlight = true;
3604
3692
  state.nextFetchAt = void 0;
3605
3693
  let released = false;
3606
- resolve6(() => {
3694
+ resolve8(() => {
3607
3695
  if (released) {
3608
3696
  return;
3609
3697
  }
@@ -4606,7 +4694,7 @@ var init_manager = __esm({
4606
4694
  // packages/server/src/provider-runtime/command-runner.ts
4607
4695
  import { spawn as spawn2 } from "node:child_process";
4608
4696
  async function runCommandAsString(file, args, options) {
4609
- return new Promise((resolve6, reject) => {
4697
+ return new Promise((resolve8, reject) => {
4610
4698
  const child = spawn2(file, args, {
4611
4699
  cwd: options?.cwd,
4612
4700
  env: options?.env,
@@ -4633,7 +4721,7 @@ async function runCommandAsString(file, args, options) {
4633
4721
  const stdout = Buffer.concat(stdoutChunks).toString("utf8");
4634
4722
  const stderr = Buffer.concat(stderrChunks).toString("utf8");
4635
4723
  if (code === 0) {
4636
- resolve6({ stdout, stderr });
4724
+ resolve8({ stdout, stderr });
4637
4725
  return;
4638
4726
  }
4639
4727
  reject(
@@ -5433,6 +5521,66 @@ var init_tool_root = __esm({
5433
5521
  }
5434
5522
  });
5435
5523
 
5524
+ // packages/server/src/provider-runtime/custom-provider.ts
5525
+ import { z as z4 } from "zod";
5526
+ function deriveProviderCapability(capabilities) {
5527
+ const interactive = capabilities.find((capability) => capability.key === "interactive_session");
5528
+ if (!interactive?.supported) {
5529
+ return "unsupported";
5530
+ }
5531
+ const allSupported = capabilities.length > 0 && capabilities.every((capability) => capability.supported);
5532
+ return allSupported ? "full" : "limited";
5533
+ }
5534
+ function buildCustomProviderDefinition(config) {
5535
+ const command = config.command.trim();
5536
+ const requiredCommand = command.split(/\s+/)[0] ?? command;
5537
+ return {
5538
+ id: config.id,
5539
+ displayName: config.displayName,
5540
+ badge: "Custom",
5541
+ kind: "custom",
5542
+ capability: deriveProviderCapability(config.capabilities),
5543
+ capabilities: config.capabilities.map((capability) => ({ ...capability })),
5544
+ install: {
5545
+ prerequisites: [],
5546
+ manualGuideKeys: [],
5547
+ docUrls: {
5548
+ provider: "",
5549
+ prerequisites: {}
5550
+ },
5551
+ strategies: {}
5552
+ },
5553
+ buildCommand(_providerConfig, ctx) {
5554
+ return {
5555
+ argv: [command, ...config.args],
5556
+ env: {
5557
+ ...config.env,
5558
+ CODER_STUDIO_SESSION_ID: ctx.sessionId
5559
+ },
5560
+ cwd: ctx.workspacePath
5561
+ };
5562
+ },
5563
+ configSchema: CUSTOM_PROVIDER_CONFIG_SCHEMA,
5564
+ defaultConfig: {},
5565
+ requiredCommands: requiredCommand ? [requiredCommand] : []
5566
+ };
5567
+ }
5568
+ function upsertProviderDefinition(registry, provider) {
5569
+ const next = registry.filter((item) => item.id !== provider.id);
5570
+ next.push(provider);
5571
+ return next;
5572
+ }
5573
+ function removeProviderDefinition(registry, providerId) {
5574
+ return registry.filter((item) => item.id !== providerId);
5575
+ }
5576
+ var CUSTOM_PROVIDER_CONFIG_SCHEMA;
5577
+ var init_custom_provider = __esm({
5578
+ "packages/server/src/provider-runtime/custom-provider.ts"() {
5579
+ "use strict";
5580
+ CUSTOM_PROVIDER_CONFIG_SCHEMA = z4.object({}).passthrough();
5581
+ }
5582
+ });
5583
+
5436
5584
  // packages/server/src/provider-runtime/e2e-provider-mock.ts
5437
5585
  import { chmodSync, existsSync as existsSync5, mkdirSync as mkdirSync6, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "node:fs";
5438
5586
  import { dirname as dirname5, join as join8 } from "node:path";
@@ -5675,9 +5823,24 @@ var init_install_manager2 = __esm({
5675
5823
  deps;
5676
5824
  constructor(providers, deps = {}) {
5677
5825
  this.deps = deps;
5826
+ this.setProviders(providers);
5827
+ }
5828
+ setProviders(providers) {
5829
+ const nextIds = new Set(providers.map((provider) => provider.id));
5830
+ this.providers.clear();
5678
5831
  for (const provider of providers) {
5679
5832
  this.providers.set(provider.id, provider);
5680
5833
  }
5834
+ for (const providerId of this.activeJobIdsByProviderId.keys()) {
5835
+ if (!nextIds.has(providerId)) {
5836
+ this.activeJobIdsByProviderId.delete(providerId);
5837
+ }
5838
+ }
5839
+ for (const providerId of this.inFlightStartsByProviderId.keys()) {
5840
+ if (!nextIds.has(providerId)) {
5841
+ this.inFlightStartsByProviderId.delete(providerId);
5842
+ }
5843
+ }
5681
5844
  }
5682
5845
  async start(providerId) {
5683
5846
  const activeJob = this.getActiveJob(providerId);
@@ -6147,7 +6310,7 @@ var init_update = __esm({
6147
6310
  });
6148
6311
 
6149
6312
  // packages/core/src/protocol/messages.ts
6150
- import { z as z4 } from "zod";
6313
+ import { z as z5 } from "zod";
6151
6314
  var TERMINAL_BINARY_PROTOCOL_VERSION, TERMINAL_BINARY_HEADER_SIZE, TerminalBinaryFrameType, RECOVERY_REASONS, TERMINAL_INPUT_ACTIVITIES, encodeTerminalBinaryFrame, TERMINAL_BINARY_OUTPUT_VERSION, encodeTerminalOutputFrame, CommandMessage, ResultMessage, EventMessage, SubscribeMessage, UnsubscribeMessage, ResyncMessage, ClientMessage, ServerMessage;
6152
6315
  var init_messages = __esm({
6153
6316
  "packages/core/src/protocol/messages.ts"() {
@@ -6210,49 +6373,49 @@ var init_messages = __esm({
6210
6373
  frame.set(payload, TERMINAL_BINARY_HEADER_SIZE + topicBytes.length);
6211
6374
  return frame;
6212
6375
  };
6213
- CommandMessage = z4.object({
6214
- kind: z4.literal("command"),
6215
- id: z4.string().uuid(),
6216
- op: z4.string(),
6217
- args: z4.unknown()
6376
+ CommandMessage = z5.object({
6377
+ kind: z5.literal("command"),
6378
+ id: z5.string().uuid(),
6379
+ op: z5.string(),
6380
+ args: z5.unknown()
6218
6381
  });
6219
- ResultMessage = z4.object({
6220
- kind: z4.literal("result"),
6221
- id: z4.string().uuid(),
6222
- ok: z4.boolean(),
6223
- data: z4.unknown().optional(),
6224
- error: z4.object({
6225
- code: z4.string(),
6226
- message: z4.string(),
6227
- details: z4.unknown().optional()
6382
+ ResultMessage = z5.object({
6383
+ kind: z5.literal("result"),
6384
+ id: z5.string().uuid(),
6385
+ ok: z5.boolean(),
6386
+ data: z5.unknown().optional(),
6387
+ error: z5.object({
6388
+ code: z5.string(),
6389
+ message: z5.string(),
6390
+ details: z5.unknown().optional()
6228
6391
  }).optional()
6229
6392
  });
6230
- EventMessage = z4.object({
6231
- kind: z4.literal("event"),
6232
- topic: z4.string(),
6233
- seq: z4.number().int().nonnegative(),
6234
- timestamp: z4.number().int().positive(),
6235
- data: z4.unknown()
6393
+ EventMessage = z5.object({
6394
+ kind: z5.literal("event"),
6395
+ topic: z5.string(),
6396
+ seq: z5.number().int().nonnegative(),
6397
+ timestamp: z5.number().int().positive(),
6398
+ data: z5.unknown()
6236
6399
  });
6237
- SubscribeMessage = z4.object({
6238
- kind: z4.literal("subscribe"),
6239
- topics: z4.array(z4.string())
6400
+ SubscribeMessage = z5.object({
6401
+ kind: z5.literal("subscribe"),
6402
+ topics: z5.array(z5.string())
6240
6403
  });
6241
- UnsubscribeMessage = z4.object({
6242
- kind: z4.literal("unsubscribe"),
6243
- topics: z4.array(z4.string())
6404
+ UnsubscribeMessage = z5.object({
6405
+ kind: z5.literal("unsubscribe"),
6406
+ topics: z5.array(z5.string())
6244
6407
  });
6245
- ResyncMessage = z4.object({
6246
- kind: z4.literal("resync"),
6247
- lastSeen: z4.record(z4.string(), z4.number())
6408
+ ResyncMessage = z5.object({
6409
+ kind: z5.literal("resync"),
6410
+ lastSeen: z5.record(z5.string(), z5.number())
6248
6411
  });
6249
- ClientMessage = z4.discriminatedUnion("kind", [
6412
+ ClientMessage = z5.discriminatedUnion("kind", [
6250
6413
  CommandMessage,
6251
6414
  SubscribeMessage,
6252
6415
  UnsubscribeMessage,
6253
6416
  ResyncMessage
6254
6417
  ]);
6255
- ServerMessage = z4.discriminatedUnion("kind", [ResultMessage, EventMessage]);
6418
+ ServerMessage = z5.discriminatedUnion("kind", [ResultMessage, EventMessage]);
6256
6419
  }
6257
6420
  });
6258
6421
 
@@ -6325,7 +6488,7 @@ var init_src3 = __esm({
6325
6488
  });
6326
6489
 
6327
6490
  // packages/server/src/provider-config.ts
6328
- import { z as z5 } from "zod";
6491
+ import { z as z6 } from "zod";
6329
6492
  function isSupportedProviderId(providerId) {
6330
6493
  return supportedProviderIds.has(providerId);
6331
6494
  }
@@ -6345,17 +6508,17 @@ var init_provider_config = __esm({
6345
6508
  "use strict";
6346
6509
  SUPPORTED_PROVIDER_IDS = ["claude", "codex"];
6347
6510
  supportedProviderIds = new Set(SUPPORTED_PROVIDER_IDS);
6348
- ProviderLaunchConfigInputSchema = z5.object({
6349
- additionalArgs: z5.array(z5.string()).optional(),
6350
- envVars: z5.record(z5.string(), z5.string()).optional()
6511
+ ProviderLaunchConfigInputSchema = z6.object({
6512
+ additionalArgs: z6.array(z6.string()).optional(),
6513
+ envVars: z6.record(z6.string(), z6.string()).optional()
6351
6514
  }).strict();
6352
- ProviderSettingsSchema = z5.object({
6515
+ ProviderSettingsSchema = z6.object({
6353
6516
  claude: ProviderLaunchConfigInputSchema.optional(),
6354
6517
  codex: ProviderLaunchConfigInputSchema.optional()
6355
6518
  }).strict();
6356
- ProviderLaunchConfigSchema = z5.object({
6357
- additionalArgs: z5.array(z5.string()).default([]),
6358
- envVars: z5.record(z5.string(), z5.string()).optional()
6519
+ ProviderLaunchConfigSchema = z6.object({
6520
+ additionalArgs: z6.array(z6.string()).default([]),
6521
+ envVars: z6.record(z6.string(), z6.string()).optional()
6359
6522
  });
6360
6523
  }
6361
6524
  });
@@ -6851,6 +7014,9 @@ var init_manager3 = __esm({
6851
7014
  comparators = /* @__PURE__ */ new Map();
6852
7015
  detectorUnsubscribes = /* @__PURE__ */ new Map();
6853
7016
  logger;
7017
+ setProviderRegistry(providerRegistry2) {
7018
+ this.deps.providerRegistry = providerRegistry2;
7019
+ }
6854
7020
  /**
6855
7021
  * Create a new session with provider
6856
7022
  */
@@ -7815,15 +7981,104 @@ var init_auth_session_repo = __esm({
7815
7981
  }
7816
7982
  });
7817
7983
 
7818
- // packages/server/src/storage/repositories/provider-config-repo.ts
7984
+ // packages/server/src/storage/repositories/custom-provider-repo.ts
7819
7985
  function isRecord5(value) {
7820
7986
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
7821
7987
  }
7822
- function normalizeProviderConfigFile(value) {
7988
+ function normalizeConfig(config) {
7989
+ return {
7990
+ ...config,
7991
+ args: [...config.args],
7992
+ env: { ...config.env },
7993
+ capabilities: config.capabilities.map((capability) => ({ ...capability }))
7994
+ };
7995
+ }
7996
+ function normalizeFileConfigs(value) {
7823
7997
  if (isRecord5(value) && value.version === 1 && isRecord5(value.providers)) {
7824
- return value.providers;
7998
+ return Object.fromEntries(
7999
+ Object.entries(value.providers).map(([id, config]) => [
8000
+ id,
8001
+ normalizeConfig(config)
8002
+ ])
8003
+ );
7825
8004
  }
7826
8005
  if (isRecord5(value)) {
8006
+ return Object.fromEntries(
8007
+ Object.entries(value).map(([id, config]) => [
8008
+ id,
8009
+ normalizeConfig(config)
8010
+ ])
8011
+ );
8012
+ }
8013
+ return {};
8014
+ }
8015
+ var CustomProviderRepo;
8016
+ var init_custom_provider_repo = __esm({
8017
+ "packages/server/src/storage/repositories/custom-provider-repo.ts"() {
8018
+ "use strict";
8019
+ init_json_file_store();
8020
+ CustomProviderRepo = class {
8021
+ filePath;
8022
+ constructor(input) {
8023
+ this.filePath = input.filePath;
8024
+ }
8025
+ list() {
8026
+ return Object.values(this.loadFileConfigs()).sort(
8027
+ (left, right) => right.updatedAt - left.updatedAt || left.id.localeCompare(right.id)
8028
+ );
8029
+ }
8030
+ get(id) {
8031
+ return this.loadFileConfigs()[id];
8032
+ }
8033
+ set(config) {
8034
+ const existing = this.get(config.id);
8035
+ const createdAt = existing?.createdAt ?? config.createdAt;
8036
+ const normalized = normalizeConfig({
8037
+ ...config,
8038
+ createdAt
8039
+ });
8040
+ const next = this.loadFileConfigs();
8041
+ next[normalized.id] = normalized;
8042
+ this.saveFileConfigs(next);
8043
+ return next[normalized.id];
8044
+ }
8045
+ delete(id) {
8046
+ const next = this.loadFileConfigs();
8047
+ if (!Object.prototype.hasOwnProperty.call(next, id)) {
8048
+ return;
8049
+ }
8050
+ delete next[id];
8051
+ this.saveFileConfigs(next);
8052
+ }
8053
+ loadFileConfigs() {
8054
+ const parsed = readJsonFile(
8055
+ this.filePath
8056
+ );
8057
+ if (parsed !== void 0) {
8058
+ return normalizeFileConfigs(parsed);
8059
+ }
8060
+ return {};
8061
+ }
8062
+ saveFileConfigs(configs) {
8063
+ const payload = {
8064
+ version: 1,
8065
+ providers: configs
8066
+ };
8067
+ writeJsonFileAtomic(this.filePath, payload);
8068
+ }
8069
+ };
8070
+ }
8071
+ });
8072
+
8073
+ // packages/server/src/storage/repositories/provider-config-repo.ts
8074
+ function isRecord6(value) {
8075
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
8076
+ }
8077
+ function normalizeProviderConfigFile(value) {
8078
+ if (isRecord6(value) && value.version === 1 && isRecord6(value.providers)) {
8079
+ return value.providers;
8080
+ }
8081
+ if (isRecord6(value)) {
7827
8082
  return value;
7828
8083
  }
7829
8084
  return {};
@@ -7896,15 +8151,159 @@ var init_provider_config_repo = __esm({
7896
8151
  }
7897
8152
  });
7898
8153
 
8154
+ // packages/server/src/workspace/workspace-state.ts
8155
+ import { join as join9 } from "node:path";
8156
+ function resolveWorkspaceStateFilePath(workspacePath, fileName) {
8157
+ return join9(workspacePath, WORKSPACE_STATE_DIR, fileName);
8158
+ }
8159
+ var WORKSPACE_STATE_DIR, AGENT_INSTRUCTIONS_RELATIVE_PATH, SESSION_METADATA_FILE_NAME, SESSION_METADATA_RELATIVE_PATH;
8160
+ var init_workspace_state = __esm({
8161
+ "packages/server/src/workspace/workspace-state.ts"() {
8162
+ "use strict";
8163
+ WORKSPACE_STATE_DIR = ".coder-studio";
8164
+ AGENT_INSTRUCTIONS_RELATIVE_PATH = `${WORKSPACE_STATE_DIR}/AGENTS.md`;
8165
+ SESSION_METADATA_FILE_NAME = "session-metadata.json";
8166
+ SESSION_METADATA_RELATIVE_PATH = `${WORKSPACE_STATE_DIR}/${SESSION_METADATA_FILE_NAME}`;
8167
+ }
8168
+ });
8169
+
8170
+ // packages/server/src/storage/repositories/session-metadata-repo.ts
8171
+ function isRecord7(value) {
8172
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
8173
+ }
8174
+ function normalizeRun(run) {
8175
+ return {
8176
+ ...run
8177
+ };
8178
+ }
8179
+ function normalizeMetadata(metadata) {
8180
+ return {
8181
+ sessionId: metadata.sessionId,
8182
+ workspaceId: metadata.workspaceId,
8183
+ providerId: metadata.providerId,
8184
+ objective: metadata.objective ?? void 0,
8185
+ baselineGitHead: metadata.baselineGitHead ?? void 0,
8186
+ baselineCapturedAt: metadata.baselineCapturedAt ?? void 0,
8187
+ verificationRuns: metadata.verificationRuns.map(normalizeRun)
8188
+ };
8189
+ }
8190
+ function normalizeFileMetadata(value) {
8191
+ if (isRecord7(value) && value.version === 1 && isRecord7(value.metadata)) {
8192
+ return Object.fromEntries(
8193
+ Object.entries(value.metadata).map(([sessionId, metadata]) => [
8194
+ sessionId,
8195
+ normalizeMetadata(metadata)
8196
+ ])
8197
+ );
8198
+ }
8199
+ if (isRecord7(value)) {
8200
+ return Object.fromEntries(
8201
+ Object.entries(value).map(([sessionId, metadata]) => [
8202
+ sessionId,
8203
+ normalizeMetadata(metadata)
8204
+ ])
8205
+ );
8206
+ }
8207
+ return {};
8208
+ }
8209
+ var SessionMetadataRepo;
8210
+ var init_session_metadata_repo = __esm({
8211
+ "packages/server/src/storage/repositories/session-metadata-repo.ts"() {
8212
+ "use strict";
8213
+ init_workspace_state();
8214
+ init_json_file_store();
8215
+ SessionMetadataRepo = class {
8216
+ workspaceRepo;
8217
+ constructor(input) {
8218
+ this.workspaceRepo = input.workspaceRepo;
8219
+ }
8220
+ upsert(metadata) {
8221
+ const normalized = normalizeMetadata(metadata);
8222
+ const workspace = this.workspaceRepo.findById(normalized.workspaceId);
8223
+ if (!workspace) {
8224
+ throw new Error(`Workspace not found for session metadata: ${normalized.workspaceId}`);
8225
+ }
8226
+ const existing = this.findSessionLocation(normalized.sessionId);
8227
+ if (existing && existing.workspace.id !== workspace.id) {
8228
+ delete existing.fileMetadata[normalized.sessionId];
8229
+ this.saveWorkspaceFileMetadata(existing.workspace.path, existing.fileMetadata);
8230
+ }
8231
+ const next = existing && existing.workspace.id === workspace.id ? existing.fileMetadata : this.loadWorkspaceFileMetadata(workspace.path);
8232
+ next[normalized.sessionId] = normalized;
8233
+ this.saveWorkspaceFileMetadata(workspace.path, next);
8234
+ return next[normalized.sessionId];
8235
+ }
8236
+ get(sessionId) {
8237
+ return this.findSessionLocation(sessionId)?.fileMetadata[sessionId];
8238
+ }
8239
+ addVerificationRun(sessionId, run) {
8240
+ const existing = this.findSessionLocation(sessionId);
8241
+ if (!existing) {
8242
+ throw new Error(`Session metadata not found: ${sessionId}`);
8243
+ }
8244
+ existing.fileMetadata[sessionId] = normalizeMetadata({
8245
+ ...existing.fileMetadata[sessionId],
8246
+ verificationRuns: [...existing.fileMetadata[sessionId].verificationRuns, normalizeRun(run)]
8247
+ });
8248
+ this.saveWorkspaceFileMetadata(existing.workspace.path, existing.fileMetadata);
8249
+ return existing.fileMetadata[sessionId];
8250
+ }
8251
+ delete(sessionId) {
8252
+ this.deleteFromAnyWorkspace(sessionId);
8253
+ }
8254
+ findSessionLocation(sessionId) {
8255
+ for (const workspace of this.workspaceRepo.list()) {
8256
+ const fileMetadata = this.loadWorkspaceFileMetadata(workspace.path);
8257
+ if (Object.prototype.hasOwnProperty.call(fileMetadata, sessionId)) {
8258
+ return {
8259
+ workspace,
8260
+ fileMetadata
8261
+ };
8262
+ }
8263
+ }
8264
+ return void 0;
8265
+ }
8266
+ deleteFromAnyWorkspace(sessionId) {
8267
+ const existing = this.findSessionLocation(sessionId);
8268
+ if (!existing) {
8269
+ return false;
8270
+ }
8271
+ delete existing.fileMetadata[sessionId];
8272
+ this.saveWorkspaceFileMetadata(existing.workspace.path, existing.fileMetadata);
8273
+ return true;
8274
+ }
8275
+ loadWorkspaceFileMetadata(workspacePath) {
8276
+ const parsed = readJsonFile(
8277
+ resolveWorkspaceStateFilePath(workspacePath, SESSION_METADATA_FILE_NAME)
8278
+ );
8279
+ if (parsed !== void 0) {
8280
+ return normalizeFileMetadata(parsed);
8281
+ }
8282
+ return {};
8283
+ }
8284
+ saveWorkspaceFileMetadata(workspacePath, metadata) {
8285
+ const payload = {
8286
+ version: 1,
8287
+ metadata
8288
+ };
8289
+ writeJsonFileAtomic(
8290
+ resolveWorkspaceStateFilePath(workspacePath, SESSION_METADATA_FILE_NAME),
8291
+ payload
8292
+ );
8293
+ }
8294
+ };
8295
+ }
8296
+ });
8297
+
7899
8298
  // packages/server/src/storage/repositories/settings-repo.ts
7900
- function isRecord6(value) {
8299
+ function isRecord8(value) {
7901
8300
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
7902
8301
  }
7903
8302
  function normalizeSettingsFile(value) {
7904
- if (isRecord6(value) && value.version === 1 && isRecord6(value.settings)) {
8303
+ if (isRecord8(value) && value.version === 1 && isRecord8(value.settings)) {
7905
8304
  return { ...value.settings };
7906
8305
  }
7907
- if (isRecord6(value)) {
8306
+ if (isRecord8(value)) {
7908
8307
  return { ...value };
7909
8308
  }
7910
8309
  return {};
@@ -8055,11 +8454,11 @@ var init_supervisor_repo = __esm({
8055
8454
  });
8056
8455
 
8057
8456
  // packages/server/src/storage/repositories/terminal-repo.ts
8058
- function isRecord7(value) {
8457
+ function isRecord9(value) {
8059
8458
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
8060
8459
  }
8061
8460
  function isTerminal(value) {
8062
- if (!isRecord7(value)) {
8461
+ if (!isRecord9(value)) {
8063
8462
  return false;
8064
8463
  }
8065
8464
  return typeof value.id === "string" && typeof value.workspaceId === "string" && (value.kind === "agent" || value.kind === "shell") && typeof value.cwd === "string" && Array.isArray(value.argv) && typeof value.cols === "number" && typeof value.rows === "number" && typeof value.alive === "boolean" && typeof value.createdAt === "number";
@@ -8071,7 +8470,7 @@ function normalizeTerminal(value) {
8071
8470
  };
8072
8471
  }
8073
8472
  function normalizeTerminalFile(value) {
8074
- if (isRecord7(value) && value.version === 1 && isRecord7(value.terminals)) {
8473
+ if (isRecord9(value) && value.version === 1 && isRecord9(value.terminals)) {
8075
8474
  const normalized = {};
8076
8475
  for (const entry of Object.values(value.terminals)) {
8077
8476
  if (isTerminal(entry)) {
@@ -8089,7 +8488,7 @@ function normalizeTerminalFile(value) {
8089
8488
  }
8090
8489
  return normalized;
8091
8490
  }
8092
- if (isRecord7(value)) {
8491
+ if (isRecord9(value)) {
8093
8492
  const normalized = {};
8094
8493
  for (const [terminalId, entry] of Object.entries(value)) {
8095
8494
  if (isTerminal(entry)) {
@@ -8255,12 +8654,12 @@ var init_terminal_repo = __esm({
8255
8654
  });
8256
8655
 
8257
8656
  // packages/server/src/storage/repositories/update-state-repo.ts
8258
- function isRecord8(value) {
8657
+ function isRecord10(value) {
8259
8658
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
8260
8659
  }
8261
8660
  function normalizeUpdateState(value, currentVersion) {
8262
8661
  const defaults = createDefaultUpdateState(currentVersion);
8263
- if (!isRecord8(value)) {
8662
+ if (!isRecord10(value)) {
8264
8663
  return defaults;
8265
8664
  }
8266
8665
  return {
@@ -8323,17 +8722,17 @@ var init_update_state_repo = __esm({
8323
8722
  });
8324
8723
 
8325
8724
  // packages/server/src/storage/repositories/workspace-repo.ts
8326
- function isRecord9(value) {
8725
+ function isRecord11(value) {
8327
8726
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
8328
8727
  }
8329
8728
  function isWorkspace(value) {
8330
- if (!isRecord9(value)) {
8729
+ if (!isRecord11(value)) {
8331
8730
  return false;
8332
8731
  }
8333
- return typeof value.id === "string" && typeof value.path === "string" && (value.targetRuntime === "native" || value.targetRuntime === "wsl") && typeof value.openedAt === "number" && typeof value.lastActiveAt === "number" && isRecord9(value.uiState);
8732
+ return typeof value.id === "string" && typeof value.path === "string" && (value.targetRuntime === "native" || value.targetRuntime === "wsl") && typeof value.openedAt === "number" && typeof value.lastActiveAt === "number" && isRecord11(value.uiState);
8334
8733
  }
8335
8734
  function normalizeWorkspaceFile(value) {
8336
- if (isRecord9(value) && value.version === 1 && isRecord9(value.workspaces)) {
8735
+ if (isRecord11(value) && value.version === 1 && isRecord11(value.workspaces)) {
8337
8736
  const normalized = {};
8338
8737
  for (const entry of Object.values(value.workspaces)) {
8339
8738
  if (isWorkspace(entry)) {
@@ -8351,7 +8750,7 @@ function normalizeWorkspaceFile(value) {
8351
8750
  }
8352
8751
  return normalized;
8353
8752
  }
8354
- if (isRecord9(value)) {
8753
+ if (isRecord11(value)) {
8355
8754
  const normalized = {};
8356
8755
  for (const [workspaceId, entry] of Object.entries(value)) {
8357
8756
  if (isWorkspace(entry)) {
@@ -8596,13 +8995,13 @@ function ensureNodePtySpawnHelperExecutable(deps = {}) {
8596
8995
  return;
8597
8996
  }
8598
8997
  const arch = deps.arch ?? process.arch;
8599
- const resolve6 = deps.resolve ?? ((id) => require4.resolve(id));
8998
+ const resolve8 = deps.resolve ?? ((id) => require4.resolve(id));
8600
8999
  const fileExists = deps.existsSync ?? existsSync6;
8601
- const stat11 = deps.statSync ?? statSync;
9000
+ const stat12 = deps.statSync ?? statSync;
8602
9001
  const chmod = deps.chmodSync ?? chmodSync2;
8603
9002
  let packageJsonPath;
8604
9003
  try {
8605
- packageJsonPath = resolve6(NODE_PTY_PKG);
9004
+ packageJsonPath = resolve8(NODE_PTY_PKG);
8606
9005
  } catch {
8607
9006
  return;
8608
9007
  }
@@ -8616,7 +9015,7 @@ function ensureNodePtySpawnHelperExecutable(deps = {}) {
8616
9015
  if (!fileExists(helperPath)) {
8617
9016
  return;
8618
9017
  }
8619
- const currentMode = stat11(helperPath).mode;
9018
+ const currentMode = stat12(helperPath).mode;
8620
9019
  const executableMode = currentMode | 73;
8621
9020
  if (executableMode === currentMode) {
8622
9021
  return;
@@ -8667,7 +9066,7 @@ async function escalateKillWithPolling(pid, signal, options) {
8667
9066
  const startTime = Date.now();
8668
9067
  const deadline = startTime + timeoutMs;
8669
9068
  while (Date.now() < deadline) {
8670
- await new Promise((resolve6) => setTimeout(resolve6, pollIntervalMs));
9069
+ await new Promise((resolve8) => setTimeout(resolve8, pollIntervalMs));
8671
9070
  if (!isProcessAlive(pid)) {
8672
9071
  return true;
8673
9072
  }
@@ -9031,7 +9430,7 @@ async function runCommand(command, timeoutMs, options = {}) {
9031
9430
  if (options.signal?.aborted) {
9032
9431
  throw createSupervisorEvalAbortedError();
9033
9432
  }
9034
- return await new Promise((resolve6, reject) => {
9433
+ return await new Promise((resolve8, reject) => {
9035
9434
  const child = spawn3(command.argv[0], command.argv.slice(1), {
9036
9435
  cwd: command.cwd,
9037
9436
  detached: process.platform !== "win32",
@@ -9061,7 +9460,7 @@ async function runCommand(command, timeoutMs, options = {}) {
9061
9460
  }
9062
9461
  settled = true;
9063
9462
  cleanup();
9064
- resolve6(value);
9463
+ resolve8(value);
9065
9464
  };
9066
9465
  const terminate = (error) => {
9067
9466
  if (terminationError) {
@@ -9889,12 +10288,12 @@ var init_scheduler = __esm({
9889
10288
 
9890
10289
  // packages/server/src/supervisor/manager.ts
9891
10290
  function createDeferredCompletion() {
9892
- let resolve6 = () => {
10291
+ let resolve8 = () => {
9893
10292
  };
9894
10293
  const promise = new Promise((innerResolve) => {
9895
- resolve6 = innerResolve;
10294
+ resolve8 = innerResolve;
9896
10295
  });
9897
- return { promise, resolve: resolve6 };
10296
+ return { promise, resolve: resolve8 };
9898
10297
  }
9899
10298
  function generateSupervisorId() {
9900
10299
  return `sup_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
@@ -10015,6 +10414,9 @@ var init_manager4 = __esm({
10015
10414
  logger;
10016
10415
  config;
10017
10416
  lifecycleUnsubscribe = null;
10417
+ setProviderRegistry(providerRegistry2) {
10418
+ this.deps.providerRegistry = providerRegistry2;
10419
+ }
10018
10420
  start() {
10019
10421
  this.lifecycleUnsubscribe?.();
10020
10422
  this.lifecycleUnsubscribe = this.deps.eventBus.on(
@@ -11249,10 +11651,10 @@ var init_manager4 = __esm({
11249
11651
  if (signal?.aborted) {
11250
11652
  throw { code: "supervisor_eval_aborted", message: "Supervisor evaluator aborted" };
11251
11653
  }
11252
- await new Promise((resolve6, reject) => {
11654
+ await new Promise((resolve8, reject) => {
11253
11655
  const timer = setTimeout(() => {
11254
11656
  signal?.removeEventListener("abort", onAbort);
11255
- resolve6();
11657
+ resolve8();
11256
11658
  }, delayMs);
11257
11659
  timer.unref?.();
11258
11660
  const onAbort = () => {
@@ -11284,30 +11686,30 @@ __export(target_store_exports, {
11284
11686
  saveTargetMeta: () => saveTargetMeta
11285
11687
  });
11286
11688
  import { mkdir as mkdir4, mkdtemp as mkdtemp2, readdir as readdir2, readFile as readFile3, rename, rm as rm6, writeFile as writeFile4 } from "node:fs/promises";
11287
- import { dirname as dirname6, join as join9 } from "node:path";
11689
+ import { dirname as dirname6, join as join10 } from "node:path";
11288
11690
  function targetDir(workspacePath, targetId) {
11289
- return join9(workspacePath, ".coder-studio", "supervisor", "targets", targetId);
11691
+ return join10(workspacePath, ".coder-studio", "supervisor", "targets", targetId);
11290
11692
  }
11291
11693
  function metaPath(workspacePath, targetId) {
11292
- return join9(targetDir(workspacePath, targetId), "meta.json");
11694
+ return join10(targetDir(workspacePath, targetId), "meta.json");
11293
11695
  }
11294
11696
  function memoryPath(workspacePath, targetId) {
11295
- return join9(targetDir(workspacePath, targetId), "memory.json");
11697
+ return join10(targetDir(workspacePath, targetId), "memory.json");
11296
11698
  }
11297
11699
  function cyclesPath(workspacePath, targetId) {
11298
- return join9(targetDir(workspacePath, targetId), "cycles.jsonl");
11700
+ return join10(targetDir(workspacePath, targetId), "cycles.jsonl");
11299
11701
  }
11300
11702
  function targetsRoot(workspacePath) {
11301
- return join9(workspacePath, ".coder-studio", "supervisor", "targets");
11703
+ return join10(workspacePath, ".coder-studio", "supervisor", "targets");
11302
11704
  }
11303
11705
  function metaFilePath(dirPath) {
11304
- return join9(dirPath, "meta.json");
11706
+ return join10(dirPath, "meta.json");
11305
11707
  }
11306
11708
  function memoryFilePath(dirPath) {
11307
- return join9(dirPath, "memory.json");
11709
+ return join10(dirPath, "memory.json");
11308
11710
  }
11309
11711
  function cyclesFilePath(dirPath) {
11310
- return join9(dirPath, "cycles.jsonl");
11712
+ return join10(dirPath, "cycles.jsonl");
11311
11713
  }
11312
11714
  function hasCode2(error, code) {
11313
11715
  return Boolean(
@@ -11326,7 +11728,7 @@ function errorMessage(error, fallback) {
11326
11728
  }
11327
11729
  return fallback;
11328
11730
  }
11329
- function isRecord10(value) {
11731
+ function isRecord12(value) {
11330
11732
  return Boolean(value) && typeof value === "object";
11331
11733
  }
11332
11734
  function readNonEmptyString(value) {
@@ -11370,7 +11772,7 @@ function fallbackAcceptanceCriteria(title) {
11370
11772
  return [`${title} is complete`];
11371
11773
  }
11372
11774
  function normalizeItem(value, fallbackKind) {
11373
- if (!isRecord10(value)) {
11775
+ if (!isRecord12(value)) {
11374
11776
  return null;
11375
11777
  }
11376
11778
  const id = readNonEmptyString(value.id);
@@ -11401,7 +11803,7 @@ function normalizeLegacyPlanItems(plan) {
11401
11803
  }
11402
11804
  return plan.flatMap((value) => {
11403
11805
  const item = normalizeItem(
11404
- isRecord10(value) ? {
11806
+ isRecord12(value) ? {
11405
11807
  id: value.id,
11406
11808
  kind: "stage",
11407
11809
  title: value.title,
@@ -11425,7 +11827,7 @@ function resolveActiveItemId(items, candidate) {
11425
11827
  return items.find((item) => item.status === "in_progress")?.id ?? items.find((item) => item.status === "pending")?.id ?? items[0]?.id;
11426
11828
  }
11427
11829
  function normalizeTargetMemory(raw, targetId) {
11428
- if (!isRecord10(raw)) {
11830
+ if (!isRecord12(raw)) {
11429
11831
  return buildTargetMemory(targetId, 0);
11430
11832
  }
11431
11833
  const updatedAt = readTimestamp(raw.updatedAt, 0);
@@ -11452,7 +11854,7 @@ function normalizeTargetMemory(raw, targetId) {
11452
11854
  };
11453
11855
  }
11454
11856
  function normalizePersistedSupervisor(raw, fallback) {
11455
- if (!isRecord10(raw)) {
11857
+ if (!isRecord12(raw)) {
11456
11858
  return void 0;
11457
11859
  }
11458
11860
  const id = readNonEmptyString(raw.id) ?? fallback.targetId;
@@ -11488,7 +11890,7 @@ function normalizePersistedSupervisor(raw, fallback) {
11488
11890
  };
11489
11891
  }
11490
11892
  function normalizeTargetMeta(raw, fallbackTargetId) {
11491
- if (!isRecord10(raw)) {
11893
+ if (!isRecord12(raw)) {
11492
11894
  const targetId2 = fallbackTargetId ?? "";
11493
11895
  return {
11494
11896
  targetId: targetId2,
@@ -11609,7 +12011,7 @@ async function resetTargetFiles(workspacePath, input) {
11609
12011
  const parentDir = dirname6(dir);
11610
12012
  const backupDir = `${dir}.backup-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
11611
12013
  await mkdir4(parentDir, { recursive: true });
11612
- const stagingDir = await mkdtemp2(join9(parentDir, `${input.targetId}.reset-`));
12014
+ const stagingDir = await mkdtemp2(join10(parentDir, `${input.targetId}.reset-`));
11613
12015
  let backupCreated = false;
11614
12016
  let promoted = false;
11615
12017
  let restored = false;
@@ -12066,8 +12468,8 @@ var init_terminal_snapshot_buffer = __esm({
12066
12468
  if (this.pendingWriteCount === 0) {
12067
12469
  return Promise.resolve();
12068
12470
  }
12069
- return new Promise((resolve6) => {
12070
- this.drainResolvers.push(resolve6);
12471
+ return new Promise((resolve8) => {
12472
+ this.drainResolvers.push(resolve8);
12071
12473
  });
12072
12474
  }
12073
12475
  resolveDrainIfIdle() {
@@ -12076,8 +12478,8 @@ var init_terminal_snapshot_buffer = __esm({
12076
12478
  }
12077
12479
  const resolvers = this.drainResolvers;
12078
12480
  this.drainResolvers = [];
12079
- for (const resolve6 of resolvers) {
12080
- resolve6();
12481
+ for (const resolve8 of resolvers) {
12482
+ resolve8();
12081
12483
  }
12082
12484
  }
12083
12485
  requireTerminal() {
@@ -12231,6 +12633,13 @@ var init_manager5 = __esm({
12231
12633
  ...derivedColorFgBg ? { COLORFGBG: derivedColorFgBg } : {},
12232
12634
  ...spec.env
12233
12635
  };
12636
+ delete terminalEnv.COLORFGBG;
12637
+ if (derivedColorFgBg) {
12638
+ terminalEnv.COLORFGBG = derivedColorFgBg;
12639
+ }
12640
+ if (spec.env?.COLORFGBG) {
12641
+ terminalEnv.COLORFGBG = spec.env.COLORFGBG;
12642
+ }
12234
12643
  let pty;
12235
12644
  try {
12236
12645
  pty = this.deps.ptyHost.spawn(spec.argv, {
@@ -12431,10 +12840,10 @@ var init_manager5 = __esm({
12431
12840
  }
12432
12841
  return existing.promise;
12433
12842
  }
12434
- let resolve6 = () => {
12843
+ let resolve8 = () => {
12435
12844
  };
12436
12845
  const promise = new Promise((innerResolve) => {
12437
- resolve6 = innerResolve;
12846
+ resolve8 = innerResolve;
12438
12847
  });
12439
12848
  let markKillCompleted = () => {
12440
12849
  };
@@ -12447,7 +12856,7 @@ var init_manager5 = __esm({
12447
12856
  markKillCompleted,
12448
12857
  finalized: false,
12449
12858
  promise,
12450
- resolve: resolve6
12859
+ resolve: resolve8
12451
12860
  });
12452
12861
  void terminal.pty.kill(signal).finally(() => {
12453
12862
  const waiter = this.explicitCloseWaiters.get(terminalId);
@@ -12630,7 +13039,7 @@ var init_update_service = __esm({
12630
13039
  "packages/server/src/update/update-service.ts"() {
12631
13040
  "use strict";
12632
13041
  init_src3();
12633
- UpdateService = class {
13042
+ UpdateService = class _UpdateService {
12634
13043
  constructor(deps) {
12635
13044
  this.deps = deps;
12636
13045
  this.now = deps.now ?? Date.now;
@@ -12652,12 +13061,14 @@ var init_update_service = __esm({
12652
13061
  this.spawnDetachedWorkerImpl = deps.spawnDetachedWorker;
12653
13062
  }
12654
13063
  deps;
13064
+ static CHECK_TIMEOUT_MS = 15e3;
12655
13065
  now;
12656
13066
  runtime;
12657
13067
  updateWorkerLogFilePath;
12658
13068
  runLatestVersionLookup;
12659
13069
  spawnDetachedWorkerImpl;
12660
13070
  scheduleTimer = null;
13071
+ inFlightCheck = null;
12661
13072
  start() {
12662
13073
  this.reconcileOnStartup();
12663
13074
  this.reloadScheduleFromSettings();
@@ -12688,10 +13099,8 @@ var init_update_service = __esm({
12688
13099
  this.scheduleTimer.unref?.();
12689
13100
  }
12690
13101
  getStateView() {
12691
- return {
12692
- ...this.deps.updateStateRepo.get(),
12693
- ...this.getSupportInfo()
12694
- };
13102
+ const persisted = this.deps.updateStateRepo.get();
13103
+ return this.composeStateView(persisted);
12695
13104
  }
12696
13105
  getPrepareInstallState() {
12697
13106
  const state = this.getStateView();
@@ -12708,36 +13117,15 @@ var init_update_service = __esm({
12708
13117
  if (current.updateStatus === "installing" || current.updateStatus === "restarting") {
12709
13118
  throw createBusyError("Update installation is already in progress");
12710
13119
  }
12711
- if (current.updateStatus === "checking") {
13120
+ if (this.inFlightCheck) {
12712
13121
  throw createBusyError("Update check is already in progress");
12713
13122
  }
12714
- this.persistAndBroadcast({
12715
- updateStatus: "checking",
12716
- finishedAt: null,
12717
- errorSummary: null
12718
- });
13123
+ this.inFlightCheck = this.runCheckForUpdates();
13124
+ this.broadcastStateChange();
12719
13125
  try {
12720
- const latestVersion = await this.runLatestVersionLookup(this.runtime.packageName);
12721
- const availability = compareVersions(latestVersion, this.runtime.currentVersion) > 0 ? "update_available" : "up_to_date";
12722
- return this.persistAndBroadcast({
12723
- currentVersion: this.runtime.currentVersion,
12724
- latestVersion,
12725
- availability,
12726
- updateStatus: "idle",
12727
- lastCheckedAt: this.now(),
12728
- errorSummary: null,
12729
- requiresManualStep: false,
12730
- manualCommand: null
12731
- });
12732
- } catch (error) {
12733
- const message = error instanceof Error ? error.message : String(error);
12734
- return this.persistAndBroadcast({
12735
- currentVersion: this.runtime.currentVersion,
12736
- availability: "check_failed",
12737
- updateStatus: "idle",
12738
- lastCheckedAt: this.now(),
12739
- errorSummary: message
12740
- });
13126
+ return await this.inFlightCheck;
13127
+ } finally {
13128
+ this.inFlightCheck = null;
12741
13129
  }
12742
13130
  }
12743
13131
  prepareInstall() {
@@ -12752,6 +13140,9 @@ var init_update_service = __esm({
12752
13140
  if (state.updateStatus === "installing" || state.updateStatus === "restarting") {
12753
13141
  throw createBusyError("Update installation is already in progress");
12754
13142
  }
13143
+ if (this.inFlightCheck) {
13144
+ throw createBusyError("Update check is already in progress");
13145
+ }
12755
13146
  const targetVersion = input.targetVersion ?? state.latestVersion;
12756
13147
  if (!targetVersion) {
12757
13148
  throw createValidationError("update_no_target", "No target version is available");
@@ -12826,6 +13217,15 @@ var init_update_service = __esm({
12826
13217
  errorSummary: null
12827
13218
  });
12828
13219
  }
13220
+ if (current.updateStatus === "checking") {
13221
+ return this.persistAndBroadcast({
13222
+ currentVersion: this.runtime.currentVersion,
13223
+ availability: "check_failed",
13224
+ updateStatus: "failed",
13225
+ finishedAt: this.now(),
13226
+ errorSummary: "Update check did not complete before the service restarted"
13227
+ });
13228
+ }
12829
13229
  if (current.updateStatus === "installing" || current.updateStatus === "restarting") {
12830
13230
  return this.persistAndBroadcast({
12831
13231
  currentVersion: this.runtime.currentVersion,
@@ -12876,18 +13276,6 @@ var init_update_service = __esm({
12876
13276
  hasActiveWork: runningTerminalCount > 0 || runningSessionCount > 0 || runningSupervisorCount > 0
12877
13277
  };
12878
13278
  }
12879
- persistAndBroadcast(patch) {
12880
- const snapshot = this.deps.updateStateRepo.update((current) => ({
12881
- ...patch,
12882
- currentVersion: patch.currentVersion ?? current.currentVersion
12883
- }));
12884
- const view = {
12885
- ...snapshot,
12886
- ...this.getSupportInfo()
12887
- };
12888
- this.deps.broadcaster.broadcast("update.state.changed", view);
12889
- return view;
12890
- }
12891
13279
  buildManualCommand(targetVersion) {
12892
13280
  return [
12893
13281
  `${this.runtime.npmCommand ?? "npm"} install -g ${this.runtime.packageName}@${targetVersion}`,
@@ -12917,32 +13305,109 @@ var init_update_service = __esm({
12917
13305
  });
12918
13306
  child.unref();
12919
13307
  }
12920
- };
12921
- }
12922
- });
12923
-
12924
- // packages/server/src/workspace/validator.ts
12925
- import { constants } from "fs";
12926
- import { access, stat as stat7 } from "fs/promises";
12927
- async function validatePath(path14) {
12928
- try {
12929
- const stats = await stat7(path14);
12930
- if (!stats.isDirectory()) {
12931
- return { valid: false, error: "Path is not a directory" };
12932
- }
12933
- await access(path14, constants.R_OK);
12934
- await access(path14, constants.W_OK);
12935
- return { valid: true };
12936
- } catch (error) {
12937
- if (error.code === "ENOENT") {
12938
- return { valid: false, error: "Path does not exist" };
12939
- }
12940
- if (error.code === "EACCES") {
12941
- return { valid: false, error: "Permission denied" };
12942
- }
12943
- return { valid: false, error: `Validation failed: ${error.message}` };
12944
- }
12945
- }
13308
+ composeStateView(snapshot, options) {
13309
+ if (options?.includeInFlightCheck !== false && this.inFlightCheck) {
13310
+ return {
13311
+ ...snapshot,
13312
+ ...this.getSupportInfo(),
13313
+ updateStatus: "checking",
13314
+ errorSummary: null
13315
+ };
13316
+ }
13317
+ return {
13318
+ ...snapshot,
13319
+ ...this.getSupportInfo()
13320
+ };
13321
+ }
13322
+ broadcastStateChange() {
13323
+ this.deps.broadcaster.broadcast("update.state.changed", this.getStateView());
13324
+ }
13325
+ async runCheckForUpdates() {
13326
+ try {
13327
+ const latestVersion = await this.withCheckTimeout(
13328
+ this.runLatestVersionLookup(this.runtime.packageName)
13329
+ );
13330
+ const availability = compareVersions(latestVersion, this.runtime.currentVersion) > 0 ? "update_available" : "up_to_date";
13331
+ return this.persistAndBroadcast(
13332
+ {
13333
+ currentVersion: this.runtime.currentVersion,
13334
+ latestVersion,
13335
+ availability,
13336
+ updateStatus: "idle",
13337
+ lastCheckedAt: this.now(),
13338
+ errorSummary: null,
13339
+ requiresManualStep: false,
13340
+ manualCommand: null
13341
+ },
13342
+ false
13343
+ );
13344
+ } catch (error) {
13345
+ const message = error instanceof Error ? error.message : String(error);
13346
+ return this.persistAndBroadcast(
13347
+ {
13348
+ currentVersion: this.runtime.currentVersion,
13349
+ availability: "check_failed",
13350
+ updateStatus: "idle",
13351
+ lastCheckedAt: this.now(),
13352
+ errorSummary: message
13353
+ },
13354
+ false
13355
+ );
13356
+ }
13357
+ }
13358
+ async withCheckTimeout(promise) {
13359
+ let timeoutHandle = null;
13360
+ try {
13361
+ return await Promise.race([
13362
+ promise,
13363
+ new Promise((_, reject) => {
13364
+ timeoutHandle = setTimeout(() => {
13365
+ reject(new Error(`Update check timed out after ${_UpdateService.CHECK_TIMEOUT_MS}ms`));
13366
+ }, _UpdateService.CHECK_TIMEOUT_MS);
13367
+ timeoutHandle.unref?.();
13368
+ })
13369
+ ]);
13370
+ } finally {
13371
+ if (timeoutHandle) {
13372
+ clearTimeout(timeoutHandle);
13373
+ }
13374
+ }
13375
+ }
13376
+ persistAndBroadcast(patch, includeInFlightCheck = true) {
13377
+ const snapshot = this.deps.updateStateRepo.update((current) => ({
13378
+ ...patch,
13379
+ currentVersion: patch.currentVersion ?? current.currentVersion
13380
+ }));
13381
+ const view = this.composeStateView(snapshot, { includeInFlightCheck });
13382
+ this.deps.broadcaster.broadcast("update.state.changed", view);
13383
+ return view;
13384
+ }
13385
+ };
13386
+ }
13387
+ });
13388
+
13389
+ // packages/server/src/workspace/validator.ts
13390
+ import { constants } from "fs";
13391
+ import { access, stat as stat7 } from "fs/promises";
13392
+ async function validatePath(path14) {
13393
+ try {
13394
+ const stats = await stat7(path14);
13395
+ if (!stats.isDirectory()) {
13396
+ return { valid: false, error: "Path is not a directory" };
13397
+ }
13398
+ await access(path14, constants.R_OK);
13399
+ await access(path14, constants.W_OK);
13400
+ return { valid: true };
13401
+ } catch (error) {
13402
+ if (error.code === "ENOENT") {
13403
+ return { valid: false, error: "Path does not exist" };
13404
+ }
13405
+ if (error.code === "EACCES") {
13406
+ return { valid: false, error: "Permission denied" };
13407
+ }
13408
+ return { valid: false, error: `Validation failed: ${error.message}` };
13409
+ }
13410
+ }
12946
13411
  var WorkspaceValidator;
12947
13412
  var init_validator = __esm({
12948
13413
  "packages/server/src/workspace/validator.ts"() {
@@ -12961,7 +13426,7 @@ var init_validator = __esm({
12961
13426
  // packages/server/src/fs/gitignore.ts
12962
13427
  import { existsSync as existsSync7, readFileSync as readFileSync6 } from "fs";
12963
13428
  import ignore from "ignore";
12964
- import { join as join10, relative as relative2 } from "path";
13429
+ import { join as join11, relative as relative2 } from "path";
12965
13430
  function normalizePath(path14) {
12966
13431
  return path14.replace(/\\/g, "/");
12967
13432
  }
@@ -12984,7 +13449,7 @@ function isIgnoredByGitignore(ig, path14) {
12984
13449
  return ig.ignores(path14) || ig.ignores(`${path14}/`);
12985
13450
  }
12986
13451
  function createGitignoreFilter(rootPath, dirPath) {
12987
- const gitignorePath = join10(rootPath, ".gitignore");
13452
+ const gitignorePath = join11(rootPath, ".gitignore");
12988
13453
  if (!existsSync7(gitignorePath)) {
12989
13454
  return (name) => !isDefaultTreeIgnored(name);
12990
13455
  }
@@ -12994,7 +13459,7 @@ function createGitignoreFilter(rootPath, dirPath) {
12994
13459
  if (isAlwaysTreeIgnored(name)) {
12995
13460
  return false;
12996
13461
  }
12997
- const relativePath = relativeToRoot(rootPath, join10(dirPath, name));
13462
+ const relativePath = relativeToRoot(rootPath, join11(dirPath, name));
12998
13463
  return !isIgnoredByGitignore(ig, relativePath);
12999
13464
  };
13000
13465
  }
@@ -13667,7 +14132,7 @@ var init_fencing = __esm({
13667
14132
  // packages/server/src/commands/terminal.ts
13668
14133
  import { stat as stat8 } from "node:fs/promises";
13669
14134
  import { basename, isAbsolute as isAbsolute2 } from "node:path";
13670
- import { z as z6 } from "zod";
14135
+ import { z as z7 } from "zod";
13671
14136
  function decodeTerminalInput(args) {
13672
14137
  if ("bytes" in args) {
13673
14138
  return Buffer.from(args.bytes, "base64");
@@ -13739,29 +14204,29 @@ var init_terminal = __esm({
13739
14204
  init_src3();
13740
14205
  init_file_io();
13741
14206
  init_dispatch();
13742
- TerminalInputActivitySchema = z6.enum(TERMINAL_INPUT_ACTIVITIES).optional();
13743
- TerminalInputSchema = z6.union([
13744
- z6.object({
13745
- terminalId: z6.string(),
13746
- bytes: z6.string(),
14207
+ TerminalInputActivitySchema = z7.enum(TERMINAL_INPUT_ACTIVITIES).optional();
14208
+ TerminalInputSchema = z7.union([
14209
+ z7.object({
14210
+ terminalId: z7.string(),
14211
+ bytes: z7.string(),
13747
14212
  activity: TerminalInputActivitySchema,
13748
- submittedText: z6.string().optional()
14213
+ submittedText: z7.string().optional()
13749
14214
  }),
13750
- z6.object({
13751
- terminalId: z6.string(),
13752
- transport: z6.literal("binary"),
13753
- streamId: z6.number().int().nonnegative(),
13754
- size: z6.number().int().nonnegative(),
14215
+ z7.object({
14216
+ terminalId: z7.string(),
14217
+ transport: z7.literal("binary"),
14218
+ streamId: z7.number().int().nonnegative(),
14219
+ size: z7.number().int().nonnegative(),
13755
14220
  activity: TerminalInputActivitySchema,
13756
- submittedText: z6.string().optional()
14221
+ submittedText: z7.string().optional()
13757
14222
  })
13758
14223
  ]);
13759
14224
  pendingTerminalInput = /* @__PURE__ */ new Map();
13760
14225
  nextOutboundBinaryStreamId = 0;
13761
14226
  registerCommand(
13762
14227
  "terminal.list",
13763
- z6.object({
13764
- workspaceId: z6.string()
14228
+ z7.object({
14229
+ workspaceId: z7.string()
13765
14230
  }),
13766
14231
  async (args, ctx) => {
13767
14232
  return ctx.terminalMgr.getAll().map((terminal) => terminal.toDTO()).filter((terminal) => terminal.workspaceId === args.workspaceId);
@@ -13769,12 +14234,12 @@ var init_terminal = __esm({
13769
14234
  );
13770
14235
  registerCommand(
13771
14236
  "terminal.create",
13772
- z6.object({
13773
- workspaceId: z6.string(),
13774
- cols: z6.number().int().positive().optional(),
13775
- rows: z6.number().int().positive().optional(),
13776
- cwdPath: z6.string().optional(),
13777
- themeBackground: z6.string().regex(/^#[0-9a-fA-F]{3,8}$/).optional()
14237
+ z7.object({
14238
+ workspaceId: z7.string(),
14239
+ cols: z7.number().int().positive().optional(),
14240
+ rows: z7.number().int().positive().optional(),
14241
+ cwdPath: z7.string().optional(),
14242
+ themeBackground: z7.string().regex(/^#[0-9a-fA-F]{3,8}$/).optional()
13778
14243
  }),
13779
14244
  async (args, ctx) => {
13780
14245
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -13820,9 +14285,9 @@ var init_terminal = __esm({
13820
14285
  );
13821
14286
  registerCommand(
13822
14287
  "terminal.replay",
13823
- z6.object({
13824
- terminalId: z6.string(),
13825
- lastSeq: z6.number().int().nonnegative().optional()
14288
+ z7.object({
14289
+ terminalId: z7.string(),
14290
+ lastSeq: z7.number().int().nonnegative().optional()
13826
14291
  }),
13827
14292
  async (args, ctx, clientId) => {
13828
14293
  const replay = ctx.terminalMgr.replay(args.terminalId, args.lastSeq ?? 0);
@@ -13847,8 +14312,8 @@ var init_terminal = __esm({
13847
14312
  );
13848
14313
  registerCommand(
13849
14314
  "terminal.snapshot",
13850
- z6.object({
13851
- terminalId: z6.string()
14315
+ z7.object({
14316
+ terminalId: z7.string()
13852
14317
  }),
13853
14318
  async (args, ctx, clientId) => {
13854
14319
  const snapshot = await ctx.terminalMgr.snapshot(args.terminalId);
@@ -13876,8 +14341,8 @@ var init_terminal = __esm({
13876
14341
  );
13877
14342
  registerCommand(
13878
14343
  "terminal.close",
13879
- z6.object({
13880
- terminalId: z6.string()
14344
+ z7.object({
14345
+ terminalId: z7.string()
13881
14346
  }),
13882
14347
  async (args, ctx) => {
13883
14348
  await ctx.terminalMgr.close(args.terminalId);
@@ -13899,10 +14364,10 @@ var init_terminal = __esm({
13899
14364
  });
13900
14365
  registerCommand(
13901
14366
  "terminal.resize",
13902
- z6.object({
13903
- terminalId: z6.string(),
13904
- cols: z6.number().int().positive(),
13905
- rows: z6.number().int().positive()
14367
+ z7.object({
14368
+ terminalId: z7.string(),
14369
+ cols: z7.number().int().positive(),
14370
+ rows: z7.number().int().positive()
13906
14371
  }),
13907
14372
  async (args, ctx) => {
13908
14373
  const sessionId = ctx.sessionMgr.findSessionIdByTerminal(args.terminalId);
@@ -14525,7 +14990,7 @@ var init_hub = __esm({
14525
14990
  }
14526
14991
  }
14527
14992
  awaitBinaryPayload(clientId) {
14528
- return new Promise((resolve6, reject) => {
14993
+ return new Promise((resolve8, reject) => {
14529
14994
  const timer = setTimeout(() => {
14530
14995
  const waiters = this.pendingBinaryWaiters.get(clientId);
14531
14996
  if (!waiters) return;
@@ -14537,7 +15002,7 @@ var init_hub = __esm({
14537
15002
  }
14538
15003
  reject(new Error("Timeout waiting for terminal input binary payload"));
14539
15004
  }, BINARY_PAYLOAD_TIMEOUT_MS);
14540
- const waiter = { resolve: resolve6, reject, timer };
15005
+ const waiter = { resolve: resolve8, reject, timer };
14541
15006
  const queue = this.pendingBinaryWaiters.get(clientId);
14542
15007
  if (queue) {
14543
15008
  queue.push(waiter);
@@ -14841,20 +15306,232 @@ var init_hub = __esm({
14841
15306
  }
14842
15307
  });
14843
15308
 
15309
+ // packages/server/src/workspace/intelligence.ts
15310
+ import { access as access2, lstat as lstat2, readFile as readFile4, stat as stat9 } from "node:fs/promises";
15311
+ import { join as join12, resolve as resolve4 } from "node:path";
15312
+ async function inspectWorkspaceIntelligence(input) {
15313
+ const [packageManager, manifest, git, docsExistence, agentsExists, frameworks] = await Promise.all([
15314
+ detectPackageManager(input.rootPath),
15315
+ readPackageJson(input.rootPath),
15316
+ detectGitState(input.rootPath),
15317
+ detectDocs(input.rootPath),
15318
+ pathExists(join12(input.rootPath, AGENT_INSTRUCTIONS_RELATIVE_PATH)),
15319
+ detectFrameworks(input.rootPath)
15320
+ ]);
15321
+ const scripts = extractScripts(manifest);
15322
+ return {
15323
+ workspaceId: input.workspaceId,
15324
+ rootPath: input.rootPath,
15325
+ git,
15326
+ packageManager,
15327
+ frameworks,
15328
+ scripts,
15329
+ recommendedCommands: buildRecommendedCommands(packageManager, scripts),
15330
+ docs: docsExistence,
15331
+ agentInstructions: {
15332
+ exists: agentsExists,
15333
+ path: AGENT_INSTRUCTIONS_RELATIVE_PATH
15334
+ }
15335
+ };
15336
+ }
15337
+ async function detectPackageManager(rootPath) {
15338
+ for (const candidate of packageManagerCandidates) {
15339
+ if (await pathExists(join12(rootPath, candidate.file))) {
15340
+ return candidate.manager;
15341
+ }
15342
+ }
15343
+ if (await pathExists(join12(rootPath, "package.json"))) {
15344
+ return "npm";
15345
+ }
15346
+ return void 0;
15347
+ }
15348
+ async function readPackageJson(rootPath) {
15349
+ const packageJsonPath = join12(rootPath, "package.json");
15350
+ if (!await pathExists(packageJsonPath)) {
15351
+ return null;
15352
+ }
15353
+ try {
15354
+ const raw = await readFile4(packageJsonPath, "utf8");
15355
+ const parsed = JSON.parse(raw);
15356
+ return parsed && typeof parsed === "object" ? parsed : null;
15357
+ } catch {
15358
+ return null;
15359
+ }
15360
+ }
15361
+ function extractScripts(manifest) {
15362
+ const scripts = manifest?.scripts ?? {};
15363
+ return {
15364
+ dev: normalizeScript(scripts.dev),
15365
+ test: normalizeScript(scripts.test),
15366
+ build: normalizeScript(scripts.build),
15367
+ lint: normalizeScript(scripts.lint)
15368
+ };
15369
+ }
15370
+ function normalizeScript(value) {
15371
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
15372
+ }
15373
+ function buildRecommendedCommands(packageManager, scripts) {
15374
+ if (!packageManager) {
15375
+ return [];
15376
+ }
15377
+ return packageScriptKeys.flatMap((key) => {
15378
+ if (!scripts[key]) {
15379
+ return [];
15380
+ }
15381
+ return [
15382
+ {
15383
+ key,
15384
+ command: buildPackageCommand(packageManager, key),
15385
+ source: "package_json"
15386
+ }
15387
+ ];
15388
+ });
15389
+ }
15390
+ function buildPackageCommand(packageManager, scriptName) {
15391
+ switch (packageManager) {
15392
+ case "pnpm":
15393
+ return `pnpm ${scriptName}`;
15394
+ case "yarn":
15395
+ return `yarn ${scriptName}`;
15396
+ case "bun":
15397
+ return `bun run ${scriptName}`;
15398
+ case "npm":
15399
+ default:
15400
+ return `npm run ${scriptName}`;
15401
+ }
15402
+ }
15403
+ async function detectFrameworks(rootPath) {
15404
+ const manifest = await readPackageJson(rootPath);
15405
+ const deps = {
15406
+ ...manifest?.dependencies ?? {},
15407
+ ...manifest?.devDependencies ?? {}
15408
+ };
15409
+ const frameworks = /* @__PURE__ */ new Set();
15410
+ if ("next" in deps) {
15411
+ frameworks.add("Next.js");
15412
+ }
15413
+ if ("react" in deps) {
15414
+ frameworks.add("React");
15415
+ }
15416
+ if ("vite" in deps || await hasAnyPath(rootPath, viteConfigFiles)) {
15417
+ frameworks.add("Vite");
15418
+ }
15419
+ if (manifest) {
15420
+ frameworks.add("Node");
15421
+ }
15422
+ if (await hasAnyPath(rootPath, ["pnpm-workspace.yaml", "turbo.json", "nx.json"])) {
15423
+ frameworks.add("Monorepo");
15424
+ }
15425
+ return frameworkOrder.filter((framework) => frameworks.has(framework));
15426
+ }
15427
+ async function detectGitState(rootPath) {
15428
+ const gitPath = join12(rootPath, ".git");
15429
+ let stats;
15430
+ try {
15431
+ stats = await lstat2(gitPath);
15432
+ } catch {
15433
+ return { isRepo: false };
15434
+ }
15435
+ const gitDir = stats.isDirectory() ? gitPath : stats.isFile() ? await resolveGitDirFromFile(rootPath, gitPath) : null;
15436
+ if (!gitDir) {
15437
+ return { isRepo: false };
15438
+ }
15439
+ const branch = await readGitBranch(gitDir);
15440
+ return branch ? { isRepo: true, branch } : { isRepo: true };
15441
+ }
15442
+ async function resolveGitDirFromFile(rootPath, gitFilePath) {
15443
+ try {
15444
+ const raw = await readFile4(gitFilePath, "utf8");
15445
+ const match = raw.match(/^gitdir:\s*(.+)\s*$/m);
15446
+ if (!match) {
15447
+ return null;
15448
+ }
15449
+ const gitDirPath = match[1];
15450
+ if (!gitDirPath) {
15451
+ return null;
15452
+ }
15453
+ return resolve4(rootPath, gitDirPath);
15454
+ } catch {
15455
+ return null;
15456
+ }
15457
+ }
15458
+ async function readGitBranch(gitDir) {
15459
+ try {
15460
+ const head = await readFile4(join12(gitDir, "HEAD"), "utf8");
15461
+ const refMatch = head.match(/^ref:\s*refs\/heads\/(.+)\s*$/);
15462
+ return refMatch?.[1];
15463
+ } catch {
15464
+ return void 0;
15465
+ }
15466
+ }
15467
+ async function detectDocs(rootPath) {
15468
+ const docs = [];
15469
+ if (await pathExists(join12(rootPath, "README.md"))) {
15470
+ docs.push({ path: "README.md", kind: "readme" });
15471
+ }
15472
+ if (await pathExists(join12(rootPath, "docs"))) {
15473
+ try {
15474
+ const docsStats = await stat9(join12(rootPath, "docs"));
15475
+ if (docsStats.isDirectory()) {
15476
+ docs.push({ path: "docs", kind: "docs" });
15477
+ }
15478
+ } catch {
15479
+ }
15480
+ }
15481
+ return docs;
15482
+ }
15483
+ async function hasAnyPath(rootPath, relativePaths) {
15484
+ for (const relativePath of relativePaths) {
15485
+ if (await pathExists(join12(rootPath, relativePath))) {
15486
+ return true;
15487
+ }
15488
+ }
15489
+ return false;
15490
+ }
15491
+ async function pathExists(path14) {
15492
+ try {
15493
+ await access2(path14);
15494
+ return true;
15495
+ } catch {
15496
+ return false;
15497
+ }
15498
+ }
15499
+ var frameworkOrder, packageManagerCandidates, packageScriptKeys, viteConfigFiles;
15500
+ var init_intelligence = __esm({
15501
+ "packages/server/src/workspace/intelligence.ts"() {
15502
+ "use strict";
15503
+ init_workspace_state();
15504
+ frameworkOrder = ["Next.js", "React", "Vite", "Node", "Monorepo"];
15505
+ packageManagerCandidates = [
15506
+ { file: "pnpm-lock.yaml", manager: "pnpm" },
15507
+ { file: "yarn.lock", manager: "yarn" },
15508
+ { file: "bun.lockb", manager: "bun" },
15509
+ { file: "package-lock.json", manager: "npm" }
15510
+ ];
15511
+ packageScriptKeys = ["dev", "test", "build", "lint"];
15512
+ viteConfigFiles = [
15513
+ "vite.config.ts",
15514
+ "vite.config.js",
15515
+ "vite.config.mjs",
15516
+ "vite.config.cjs"
15517
+ ];
15518
+ }
15519
+ });
15520
+
14844
15521
  // packages/server/src/commands/workspace.ts
14845
15522
  import { readdir as readdir3, realpath as realpath3 } from "node:fs/promises";
14846
15523
  import { homedir as homedir2 } from "node:os";
14847
- import { isAbsolute as isAbsolute3, join as join11, resolve as resolve4 } from "node:path";
14848
- import { z as z7 } from "zod";
15524
+ import { isAbsolute as isAbsolute3, join as join13, resolve as resolve5 } from "node:path";
15525
+ import { z as z8 } from "zod";
14849
15526
  function resolveBrowsePath(path14) {
14850
15527
  const home = homedir2();
14851
15528
  if (!path14 || path14 === "~") {
14852
15529
  return home;
14853
15530
  }
14854
15531
  if (path14.startsWith("~/")) {
14855
- return join11(home, path14.slice(2));
15532
+ return join13(home, path14.slice(2));
14856
15533
  }
14857
- return isAbsolute3(path14) ? path14 : resolve4(home, path14);
15534
+ return isAbsolute3(path14) ? path14 : resolve5(home, path14);
14858
15535
  }
14859
15536
  async function buildRootPaths(currentPath) {
14860
15537
  const roots = /* @__PURE__ */ new Set(["/"]);
@@ -14873,25 +15550,26 @@ async function buildRootPaths(currentPath) {
14873
15550
  var init_workspace = __esm({
14874
15551
  "packages/server/src/commands/workspace.ts"() {
14875
15552
  "use strict";
15553
+ init_intelligence();
14876
15554
  init_dispatch();
14877
- registerCommand("workspace.list", z7.object({}), async (_args, ctx) => {
15555
+ registerCommand("workspace.list", z8.object({}), async (_args, ctx) => {
14878
15556
  return ctx.workspaceMgr.list();
14879
15557
  });
14880
15558
  registerCommand(
14881
15559
  "workspace.browse",
14882
- z7.object({
14883
- path: z7.string().optional()
15560
+ z8.object({
15561
+ path: z8.string().optional()
14884
15562
  }),
14885
15563
  async (args) => {
14886
15564
  const basePath = resolveBrowsePath(args.path);
14887
15565
  const entries = await readdir3(basePath, { withFileTypes: true });
14888
15566
  const directories = entries.filter((entry) => entry.isDirectory()).map((entry) => ({
14889
15567
  name: entry.name,
14890
- path: join11(basePath, entry.name)
15568
+ path: join13(basePath, entry.name)
14891
15569
  })).sort((a, b) => a.name.localeCompare(b.name));
14892
15570
  return {
14893
15571
  currentPath: basePath,
14894
- parentPath: basePath !== "/" ? join11(basePath, "..") : null,
15572
+ parentPath: basePath !== "/" ? join13(basePath, "..") : null,
14895
15573
  directories,
14896
15574
  rootPaths: await buildRootPaths(basePath)
14897
15575
  };
@@ -14899,8 +15577,8 @@ var init_workspace = __esm({
14899
15577
  );
14900
15578
  registerCommand(
14901
15579
  "workspace.open",
14902
- z7.object({
14903
- path: z7.string()
15580
+ z8.object({
15581
+ path: z8.string()
14904
15582
  }),
14905
15583
  async (args, ctx) => {
14906
15584
  return ctx.workspaceMgr.open({
@@ -14908,10 +15586,26 @@ var init_workspace = __esm({
14908
15586
  });
14909
15587
  }
14910
15588
  );
15589
+ registerCommand(
15590
+ "workspace.intelligence",
15591
+ z8.object({
15592
+ workspaceId: z8.string()
15593
+ }),
15594
+ async (args, ctx) => {
15595
+ const workspace = ctx.workspaceMgr.get(args.workspaceId);
15596
+ if (!workspace) {
15597
+ throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
15598
+ }
15599
+ return inspectWorkspaceIntelligence({
15600
+ workspaceId: workspace.id,
15601
+ rootPath: workspace.path
15602
+ });
15603
+ }
15604
+ );
14911
15605
  registerCommand(
14912
15606
  "workspace.close",
14913
- z7.object({
14914
- id: z7.string()
15607
+ z8.object({
15608
+ id: z8.string()
14915
15609
  }),
14916
15610
  async (args, ctx) => {
14917
15611
  await ctx.workspaceMgr.close(args.id);
@@ -14919,27 +15613,27 @@ var init_workspace = __esm({
14919
15613
  );
14920
15614
  registerCommand(
14921
15615
  "workspace.uiState.set",
14922
- z7.object({
14923
- workspaceId: z7.string(),
14924
- uiState: z7.object({
14925
- leftPanelWidth: z7.number(),
14926
- bottomPanelHeight: z7.number(),
14927
- focusMode: z7.boolean(),
14928
- activeSessionId: z7.string().optional(),
14929
- fileTreeExpandedDirs: z7.array(z7.string()).optional(),
14930
- paneLayout: z7.object({
14931
- id: z7.string(),
14932
- type: z7.enum(["leaf", "split"]),
14933
- sessionId: z7.string().optional(),
14934
- direction: z7.enum(["horizontal", "vertical"]).optional(),
14935
- children: z7.lazy(
14936
- () => z7.array(
14937
- z7.object({
14938
- id: z7.string(),
14939
- type: z7.enum(["leaf", "split"]),
14940
- sessionId: z7.string().optional(),
14941
- direction: z7.enum(["horizontal", "vertical"]).optional(),
14942
- children: z7.any().optional()
15616
+ z8.object({
15617
+ workspaceId: z8.string(),
15618
+ uiState: z8.object({
15619
+ leftPanelWidth: z8.number(),
15620
+ bottomPanelHeight: z8.number(),
15621
+ focusMode: z8.boolean(),
15622
+ activeSessionId: z8.string().optional(),
15623
+ fileTreeExpandedDirs: z8.array(z8.string()).optional(),
15624
+ paneLayout: z8.object({
15625
+ id: z8.string(),
15626
+ type: z8.enum(["leaf", "split"]),
15627
+ sessionId: z8.string().optional(),
15628
+ direction: z8.enum(["horizontal", "vertical"]).optional(),
15629
+ children: z8.lazy(
15630
+ () => z8.array(
15631
+ z8.object({
15632
+ id: z8.string(),
15633
+ type: z8.enum(["leaf", "split"]),
15634
+ sessionId: z8.string().optional(),
15635
+ direction: z8.enum(["horizontal", "vertical"]).optional(),
15636
+ children: z8.any().optional()
14943
15637
  })
14944
15638
  )
14945
15639
  ).optional()
@@ -14959,7 +15653,7 @@ var init_workspace = __esm({
14959
15653
  });
14960
15654
 
14961
15655
  // packages/server/src/commands/workspace-activity.ts
14962
- import { z as z8 } from "zod";
15656
+ import { z as z9 } from "zod";
14963
15657
  function parseWorkspaceLastViewedTarget(value) {
14964
15658
  try {
14965
15659
  const parsed = JSON.parse(value);
@@ -14975,15 +15669,15 @@ var init_workspace_activity = __esm({
14975
15669
  "use strict";
14976
15670
  init_dispatch();
14977
15671
  WORKSPACE_LAST_VIEWED_TARGET_KEY = "workspace.lastViewedTarget";
14978
- workspaceLastViewedTargetSchema = z8.object({
14979
- workspaceId: z8.string(),
14980
- sessionId: z8.string().optional(),
14981
- updatedAt: z8.number()
15672
+ workspaceLastViewedTargetSchema = z9.object({
15673
+ workspaceId: z9.string(),
15674
+ sessionId: z9.string().optional(),
15675
+ updatedAt: z9.number()
14982
15676
  });
14983
15677
  registerCommand(
14984
15678
  "workspace.activate",
14985
- z8.object({
14986
- workspaceId: z8.string()
15679
+ z9.object({
15680
+ workspaceId: z9.string()
14987
15681
  }),
14988
15682
  async (args, ctx, clientId) => {
14989
15683
  if (!clientId) {
@@ -14993,14 +15687,14 @@ var init_workspace_activity = __esm({
14993
15687
  return {};
14994
15688
  }
14995
15689
  );
14996
- registerCommand("workspace.deactivate", z8.object({}), async (_args, ctx, clientId) => {
15690
+ registerCommand("workspace.deactivate", z9.object({}), async (_args, ctx, clientId) => {
14997
15691
  if (!clientId) {
14998
15692
  return {};
14999
15693
  }
15000
15694
  ctx.autoFetch.unregisterViewer(clientId);
15001
15695
  return {};
15002
15696
  });
15003
- registerCommand("workspace.lastViewedTarget.get", z8.object({}), async (_args, ctx) => {
15697
+ registerCommand("workspace.lastViewedTarget.get", z9.object({}), async (_args, ctx) => {
15004
15698
  const value = ctx.settingsRepo.get(WORKSPACE_LAST_VIEWED_TARGET_KEY);
15005
15699
  if (value === void 0) {
15006
15700
  return null;
@@ -15009,9 +15703,9 @@ var init_workspace_activity = __esm({
15009
15703
  });
15010
15704
  registerCommand(
15011
15705
  "workspace.lastViewedTarget.set",
15012
- z8.object({
15013
- workspaceId: z8.string(),
15014
- sessionId: z8.string().optional()
15706
+ z9.object({
15707
+ workspaceId: z9.string(),
15708
+ sessionId: z9.string().optional()
15015
15709
  }),
15016
15710
  async (args, ctx) => {
15017
15711
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -15035,14 +15729,14 @@ var init_workspace_activity = __esm({
15035
15729
  });
15036
15730
 
15037
15731
  // packages/server/src/commands/activation.ts
15038
- import { z as z9 } from "zod";
15732
+ import { z as z10 } from "zod";
15039
15733
  var init_activation2 = __esm({
15040
15734
  "packages/server/src/commands/activation.ts"() {
15041
15735
  "use strict";
15042
15736
  init_dispatch();
15043
15737
  registerCommand(
15044
15738
  "activation.claim",
15045
- z9.object({ clientInstanceId: z9.string().min(1) }),
15739
+ z10.object({ clientInstanceId: z10.string().min(1) }),
15046
15740
  async (args, ctx, clientId) => {
15047
15741
  if (!clientId) {
15048
15742
  throw {
@@ -15066,7 +15760,7 @@ var init_activation2 = __esm({
15066
15760
  );
15067
15761
  registerCommand(
15068
15762
  "activation.release",
15069
- z9.object({ clientInstanceId: z9.string(), generation: z9.number().int().positive() }),
15763
+ z10.object({ clientInstanceId: z10.string(), generation: z10.number().int().positive() }),
15070
15764
  async (args, ctx, clientId) => {
15071
15765
  const lease = ctx.activationMgr.getLease();
15072
15766
  if (!clientId || !lease || lease.wsClientId !== clientId) {
@@ -15080,34 +15774,34 @@ var init_activation2 = __esm({
15080
15774
  });
15081
15775
 
15082
15776
  // packages/server/src/commands/connection.ts
15083
- import { z as z10 } from "zod";
15777
+ import { z as z11 } from "zod";
15084
15778
  var init_connection = __esm({
15085
15779
  "packages/server/src/commands/connection.ts"() {
15086
15780
  "use strict";
15087
15781
  init_dispatch();
15088
- registerCommand("connection.probe", z10.object({}).default({}), async () => {
15782
+ registerCommand("connection.probe", z11.object({}).default({}), async () => {
15089
15783
  return { ok: true };
15090
15784
  });
15091
15785
  }
15092
15786
  });
15093
15787
 
15094
15788
  // packages/server/src/commands/recovery.ts
15095
- import { z as z11 } from "zod";
15789
+ import { z as z12 } from "zod";
15096
15790
  var RecoveryReasonSchema;
15097
15791
  var init_recovery = __esm({
15098
15792
  "packages/server/src/commands/recovery.ts"() {
15099
15793
  "use strict";
15100
15794
  init_src3();
15101
15795
  init_dispatch();
15102
- RecoveryReasonSchema = z11.enum(RECOVERY_REASONS);
15796
+ RecoveryReasonSchema = z12.enum(RECOVERY_REASONS);
15103
15797
  registerCommand(
15104
15798
  "recovery.reconcile",
15105
- z11.object({
15799
+ z12.object({
15106
15800
  reason: RecoveryReasonSchema,
15107
- terminals: z11.array(
15108
- z11.object({
15109
- terminalId: z11.string(),
15110
- renderedSeq: z11.number().int().nonnegative()
15801
+ terminals: z12.array(
15802
+ z12.object({
15803
+ terminalId: z12.string(),
15804
+ renderedSeq: z12.number().int().nonnegative()
15111
15805
  })
15112
15806
  )
15113
15807
  }),
@@ -15353,15 +16047,33 @@ var init_pane_layout = __esm({
15353
16047
  });
15354
16048
 
15355
16049
  // packages/server/src/commands/session.ts
15356
- import { z as z12 } from "zod";
16050
+ import { readFile as readFile5 } from "node:fs/promises";
16051
+ import { join as join14, resolve as resolve6 } from "node:path";
16052
+ import { z as z13 } from "zod";
15357
16053
  function delay(ms) {
15358
- return new Promise((resolve6) => {
15359
- setTimeout(resolve6, ms);
16054
+ return new Promise((resolve8) => {
16055
+ setTimeout(resolve8, ms);
15360
16056
  });
15361
16057
  }
15362
16058
  function getProviderFromRegistry(providerId, registry) {
15363
16059
  return registry.find((provider) => provider.id === providerId);
15364
16060
  }
16061
+ async function tryReadGitHead(workspacePath) {
16062
+ try {
16063
+ const gitEntryPath = join14(workspacePath, ".git");
16064
+ const gitEntry = await readFile5(gitEntryPath, "utf8").catch(() => null);
16065
+ let gitDir = gitEntryPath;
16066
+ if (gitEntry && gitEntry.startsWith("gitdir:")) {
16067
+ const relativeGitDir = gitEntry.slice("gitdir:".length).trim();
16068
+ gitDir = resolve6(workspacePath, relativeGitDir);
16069
+ }
16070
+ const head = await readFile5(join14(gitDir, "HEAD"), "utf8");
16071
+ const trimmed = head.trim();
16072
+ return trimmed.length > 0 && !trimmed.startsWith("ref:") ? trimmed : void 0;
16073
+ } catch {
16074
+ return void 0;
16075
+ }
16076
+ }
15365
16077
  var SESSION_CLOSE_POLL_INTERVAL_MS, SESSION_CLOSE_TIMEOUT_MS;
15366
16078
  var init_session2 = __esm({
15367
16079
  "packages/server/src/commands/session.ts"() {
@@ -15373,8 +16085,8 @@ var init_session2 = __esm({
15373
16085
  SESSION_CLOSE_TIMEOUT_MS = 5e3;
15374
16086
  registerCommand(
15375
16087
  "session.list",
15376
- z12.object({
15377
- workspaceId: z12.string()
16088
+ z13.object({
16089
+ workspaceId: z13.string()
15378
16090
  }),
15379
16091
  async (args, ctx) => {
15380
16092
  return ctx.sessionMgr.getForWorkspace(args.workspaceId);
@@ -15382,11 +16094,11 @@ var init_session2 = __esm({
15382
16094
  );
15383
16095
  registerCommand(
15384
16096
  "session.create",
15385
- z12.object({
15386
- workspaceId: z12.string(),
15387
- providerId: z12.string(),
15388
- draft: z12.string().optional(),
15389
- themeBackground: z12.string().regex(/^#[0-9a-fA-F]{3,8}$/).optional()
16097
+ z13.object({
16098
+ workspaceId: z13.string(),
16099
+ providerId: z13.string(),
16100
+ draft: z13.string().optional(),
16101
+ themeBackground: z13.string().regex(/^#[0-9a-fA-F]{3,8}$/).optional()
15390
16102
  }),
15391
16103
  async (args, ctx) => {
15392
16104
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -15409,7 +16121,7 @@ var init_session2 = __esm({
15409
16121
  }
15410
16122
  };
15411
16123
  }
15412
- return ctx.sessionMgr.create({
16124
+ const session = await ctx.sessionMgr.create({
15413
16125
  workspaceId: args.workspaceId,
15414
16126
  workspacePath: workspace.path,
15415
16127
  providerId: args.providerId,
@@ -15417,12 +16129,22 @@ var init_session2 = __esm({
15417
16129
  draft: args.draft,
15418
16130
  themeBackground: args.themeBackground
15419
16131
  });
16132
+ ctx.sessionMetadataRepo?.upsert({
16133
+ sessionId: session.id,
16134
+ workspaceId: args.workspaceId,
16135
+ providerId: args.providerId,
16136
+ objective: args.draft?.trim() || void 0,
16137
+ baselineGitHead: await tryReadGitHead(workspace.path),
16138
+ baselineCapturedAt: Date.now(),
16139
+ verificationRuns: []
16140
+ });
16141
+ return session;
15420
16142
  }
15421
16143
  );
15422
16144
  registerCommand(
15423
16145
  "session.stop",
15424
- z12.object({
15425
- sessionId: z12.string()
16146
+ z13.object({
16147
+ sessionId: z13.string()
15426
16148
  }),
15427
16149
  async (args, ctx) => {
15428
16150
  await ctx.sessionMgr.stop(args.sessionId);
@@ -15430,8 +16152,8 @@ var init_session2 = __esm({
15430
16152
  );
15431
16153
  registerCommand(
15432
16154
  "session.remove",
15433
- z12.object({
15434
- sessionId: z12.string()
16155
+ z13.object({
16156
+ sessionId: z13.string()
15435
16157
  }),
15436
16158
  async (args, ctx) => {
15437
16159
  const session = ctx.sessionMgr.get(args.sessionId);
@@ -15442,13 +16164,14 @@ var init_session2 = __esm({
15442
16164
  throw { code: "invalid_state", message: `Cannot remove session in state: ${session.state}` };
15443
16165
  }
15444
16166
  ctx.sessionMgr.delete(args.sessionId);
16167
+ ctx.sessionMetadataRepo?.delete(args.sessionId);
15445
16168
  }
15446
16169
  );
15447
16170
  registerCommand(
15448
16171
  "session.close",
15449
- z12.object({
15450
- sessionId: z12.string(),
15451
- paneDisposition: z12.enum(["draft", "remove"]).default("draft")
16172
+ z13.object({
16173
+ sessionId: z13.string(),
16174
+ paneDisposition: z13.enum(["draft", "remove"]).default("draft")
15452
16175
  }),
15453
16176
  async (args, ctx) => {
15454
16177
  let session = ctx.sessionMgr.get(args.sessionId);
@@ -15504,46 +16227,487 @@ var init_session2 = __esm({
15504
16227
  };
15505
16228
  ctx.workspaceMgr.updateUiState(session.workspaceId, nextUiState);
15506
16229
  ctx.sessionMgr.delete(args.sessionId);
16230
+ ctx.sessionMetadataRepo?.delete(args.sessionId);
15507
16231
  }
15508
16232
  );
15509
16233
  }
15510
16234
  });
15511
16235
 
15512
- // packages/server/src/fs/content-search.ts
15513
- import { spawn as spawn5 } from "child_process";
15514
- import { existsSync as existsSync8 } from "fs";
15515
- import { readdir as readdir4, readFile as readFile4, stat as stat9 } from "fs/promises";
15516
- import { basename as basename2, join as join12, relative as relative3 } from "path";
15517
- import { createInterface } from "readline";
15518
- async function searchFileContents(rootPath, options) {
15519
- const query = options.query.trim();
15520
- if (!query) {
15521
- return {
15522
- files: [],
15523
- totalMatchCount: 0,
15524
- hasMoreFiles: false,
15525
- truncatedMatchFileCount: 0
16236
+ // packages/server/src/commands/session-metadata.ts
16237
+ import { randomUUID as randomUUID6 } from "node:crypto";
16238
+ import { z as z14 } from "zod";
16239
+ function requireSessionMetadataRepo(ctx) {
16240
+ if (!ctx.sessionMetadataRepo) {
16241
+ throw {
16242
+ code: "session_metadata_unavailable",
16243
+ message: "Session metadata repository is not configured"
15526
16244
  };
15527
16245
  }
15528
- const result = await searchWithRipgrep(rootPath, query, options.maxFiles).catch(
15529
- async (error) => {
15530
- if (error.code === "ENOENT") {
15531
- return searchWithNode(rootPath, query, options.maxFiles);
15532
- }
15533
- throw error;
15534
- }
15535
- );
15536
- return finalizeResults(result, options.maxFiles, options.maxMatchesPerFile);
15537
16246
  }
15538
- async function searchWithRipgrep(rootPath, query, maxFiles) {
15539
- const hasGitignore = existsSync8(join12(rootPath, ".gitignore"));
15540
- const args = [
15541
- "--json",
15542
- "--line-number",
15543
- "--column",
15544
- "--fixed-strings",
15545
- "--sort",
15546
- "path",
16247
+ var init_session_metadata = __esm({
16248
+ "packages/server/src/commands/session-metadata.ts"() {
16249
+ "use strict";
16250
+ init_dispatch();
16251
+ registerCommand(
16252
+ "session.metadata.get",
16253
+ z14.object({
16254
+ sessionId: z14.string()
16255
+ }),
16256
+ async (args, ctx) => {
16257
+ requireSessionMetadataRepo(ctx);
16258
+ const metadata = ctx.sessionMetadataRepo.get(args.sessionId);
16259
+ if (!metadata) {
16260
+ throw {
16261
+ code: "session_metadata_not_found",
16262
+ message: `Session metadata not found: ${args.sessionId}`
16263
+ };
16264
+ }
16265
+ return metadata;
16266
+ }
16267
+ );
16268
+ registerCommand(
16269
+ "session.verification.add",
16270
+ z14.object({
16271
+ sessionId: z14.string(),
16272
+ command: z14.string().trim().min(1),
16273
+ status: z14.enum(["passed", "failed", "unknown"]),
16274
+ exitCode: z14.number().int().optional(),
16275
+ summary: z14.string().optional()
16276
+ }),
16277
+ async (args, ctx) => {
16278
+ requireSessionMetadataRepo(ctx);
16279
+ return ctx.sessionMetadataRepo.addVerificationRun(args.sessionId, {
16280
+ id: randomUUID6(),
16281
+ command: args.command,
16282
+ status: args.status,
16283
+ exitCode: args.exitCode,
16284
+ summary: args.summary?.trim() || void 0,
16285
+ createdAt: Date.now()
16286
+ });
16287
+ }
16288
+ );
16289
+ }
16290
+ });
16291
+
16292
+ // packages/server/src/git/diff.ts
16293
+ import { mkdtemp as mkdtemp3, readFile as readFile6, rm as rm7 } from "fs/promises";
16294
+ import os3 from "os";
16295
+ import path11 from "path";
16296
+ async function isTrackedPath(cwd, filePath) {
16297
+ try {
16298
+ await runGit(cwd, ["ls-files", "--error-unmatch", "--", filePath]);
16299
+ return true;
16300
+ } catch {
16301
+ return false;
16302
+ }
16303
+ }
16304
+ async function getUntrackedFileDiff(cwd, filePath) {
16305
+ const tempDir = await mkdtemp3(path11.join(os3.tmpdir(), "coder-studio-git-diff-"));
16306
+ const tempIndex = path11.join(tempDir, "index");
16307
+ try {
16308
+ try {
16309
+ await runGit(cwd, ["read-tree", "HEAD"], {
16310
+ env: { GIT_INDEX_FILE: tempIndex }
16311
+ });
16312
+ } catch (error) {
16313
+ if (!(error instanceof GitError)) {
16314
+ throw error;
16315
+ }
16316
+ await runGit(cwd, ["read-tree", "--empty"], {
16317
+ env: { GIT_INDEX_FILE: tempIndex }
16318
+ });
16319
+ }
16320
+ await runGit(cwd, ["add", "-N", "--", filePath], {
16321
+ env: { GIT_INDEX_FILE: tempIndex }
16322
+ });
16323
+ const result = await runGit(cwd, ["diff", "--", filePath], {
16324
+ env: { GIT_INDEX_FILE: tempIndex }
16325
+ });
16326
+ return result.stdout;
16327
+ } finally {
16328
+ await rm7(tempDir, { recursive: true, force: true });
16329
+ }
16330
+ }
16331
+ async function pathExists2(cwd, filePath) {
16332
+ try {
16333
+ await readFile6(resolveSafe(cwd, filePath));
16334
+ return true;
16335
+ } catch {
16336
+ return false;
16337
+ }
16338
+ }
16339
+ async function readTextAtRevision(cwd, revision, filePath) {
16340
+ if (revision === "WORKTREE") {
16341
+ return readFile6(resolveSafe(cwd, filePath), "utf-8");
16342
+ }
16343
+ try {
16344
+ const gitSpec = revision === "INDEX" ? `:${filePath}` : `${revision}:${filePath}`;
16345
+ const result = await runGit(cwd, ["show", gitSpec]);
16346
+ return result.stdout;
16347
+ } catch {
16348
+ return "";
16349
+ }
16350
+ }
16351
+ async function deriveFileDiffStatus(cwd, filePath, staged) {
16352
+ const tracked = await isTrackedPath(cwd, filePath);
16353
+ const existsOnDisk = await pathExists2(cwd, filePath);
16354
+ if (!staged && !tracked) {
16355
+ return "added";
16356
+ }
16357
+ if (staged) {
16358
+ try {
16359
+ await runGit(cwd, ["cat-file", "-e", `HEAD:${filePath}`]);
16360
+ return existsOnDisk ? "modified" : "deleted";
16361
+ } catch {
16362
+ return "added";
16363
+ }
16364
+ }
16365
+ return existsOnDisk ? "modified" : "deleted";
16366
+ }
16367
+ async function buildTextDiffResult(cwd, filePath, staged, diff) {
16368
+ const status = await deriveFileDiffStatus(cwd, filePath, staged);
16369
+ if (status === "added") {
16370
+ return {
16371
+ diff,
16372
+ renderAs: "text",
16373
+ status,
16374
+ originalContent: "",
16375
+ modifiedContent: await readTextAtRevision(cwd, staged ? "INDEX" : "WORKTREE", filePath)
16376
+ };
16377
+ }
16378
+ if (status === "deleted") {
16379
+ return {
16380
+ diff,
16381
+ renderAs: "text",
16382
+ status,
16383
+ originalContent: await readTextAtRevision(cwd, staged ? "HEAD" : "INDEX", filePath),
16384
+ modifiedContent: ""
16385
+ };
16386
+ }
16387
+ return {
16388
+ diff,
16389
+ renderAs: "text",
16390
+ status,
16391
+ originalContent: await readTextAtRevision(cwd, staged ? "HEAD" : "INDEX", filePath),
16392
+ modifiedContent: await readTextAtRevision(cwd, staged ? "INDEX" : "WORKTREE", filePath)
16393
+ };
16394
+ }
16395
+ async function getFileDiff(cwd, path14, staged = false) {
16396
+ const imageType = getImageTypeInfo(path14);
16397
+ if (!staged && !await isTrackedPath(cwd, path14)) {
16398
+ const diff = await getUntrackedFileDiff(cwd, path14);
16399
+ if (imageType) {
16400
+ return {
16401
+ diff,
16402
+ renderAs: "image",
16403
+ status: "added",
16404
+ originalRevision: "HEAD",
16405
+ modifiedRevision: "WORKTREE"
16406
+ };
16407
+ }
16408
+ return buildTextDiffResult(cwd, path14, staged, diff);
16409
+ }
16410
+ const args = staged ? ["diff", "--staged", "--", path14] : ["diff", "--", path14];
16411
+ const result = await runGit(cwd, args);
16412
+ if (imageType && /Binary files .* differ/.test(result.stdout)) {
16413
+ return {
16414
+ diff: result.stdout,
16415
+ renderAs: "image",
16416
+ status: await deriveFileDiffStatus(cwd, path14, staged),
16417
+ originalRevision: staged ? "HEAD" : "INDEX",
16418
+ modifiedRevision: staged ? "INDEX" : "WORKTREE"
16419
+ };
16420
+ }
16421
+ return buildTextDiffResult(cwd, path14, staged, result.stdout);
16422
+ }
16423
+ var init_diff = __esm({
16424
+ "packages/server/src/git/diff.ts"() {
16425
+ "use strict";
16426
+ init_file_io();
16427
+ init_image();
16428
+ init_cli();
16429
+ }
16430
+ });
16431
+
16432
+ // packages/server/src/session-review/review.ts
16433
+ function isWorkspaceStatePath(path14) {
16434
+ return path14 === WORKSPACE_STATE_DIR || path14.startsWith(`${WORKSPACE_STATE_DIR}/`);
16435
+ }
16436
+ function requireSessionMetadata(metadataRepo, sessionId) {
16437
+ const metadata = metadataRepo.get(sessionId);
16438
+ if (!metadata) {
16439
+ throw {
16440
+ code: "session_metadata_not_found",
16441
+ message: `Session metadata not found: ${sessionId}`
16442
+ };
16443
+ }
16444
+ return metadata;
16445
+ }
16446
+ async function isGitRepository(workspacePath) {
16447
+ try {
16448
+ await runGit(workspacePath, ["rev-parse", "--git-dir"]);
16449
+ return true;
16450
+ } catch (error) {
16451
+ if (error instanceof GitError) {
16452
+ return false;
16453
+ }
16454
+ throw error;
16455
+ }
16456
+ }
16457
+ function compareGitChanges(a, b) {
16458
+ const pathCompare = a.path.localeCompare(b.path);
16459
+ if (pathCompare !== 0) {
16460
+ return pathCompare;
16461
+ }
16462
+ return (a.oldPath ?? "").localeCompare(b.oldPath ?? "");
16463
+ }
16464
+ function mapGitStatus(code) {
16465
+ switch (code[0]) {
16466
+ case "A":
16467
+ return "added";
16468
+ case "D":
16469
+ return "deleted";
16470
+ case "M":
16471
+ default:
16472
+ return "modified";
16473
+ }
16474
+ }
16475
+ async function listTrackedChangesSinceBaseline(workspacePath, baselineGitHead) {
16476
+ const { stdout } = await runGit(workspacePath, [
16477
+ "diff",
16478
+ "--name-status",
16479
+ "--find-renames",
16480
+ baselineGitHead,
16481
+ "--"
16482
+ ]);
16483
+ const changes = stdout.split("\n").map((line) => line.trim()).filter((line) => line.length > 0).map((line) => {
16484
+ const parts = line.split(" ");
16485
+ const statusCode = parts[0] ?? "M";
16486
+ if (statusCode.startsWith("R")) {
16487
+ const oldPath = parts[1];
16488
+ const path15 = parts[2];
16489
+ if (!oldPath || !path15) {
16490
+ return null;
16491
+ }
16492
+ return {
16493
+ oldPath,
16494
+ path: path15,
16495
+ status: "renamed"
16496
+ };
16497
+ }
16498
+ const path14 = parts[1];
16499
+ if (!path14) {
16500
+ return null;
16501
+ }
16502
+ return {
16503
+ path: path14,
16504
+ status: mapGitStatus(statusCode)
16505
+ };
16506
+ });
16507
+ return changes.filter((change) => change !== null).filter((change) => !isWorkspaceStatePath(change.path)).sort(compareGitChanges);
16508
+ }
16509
+ async function listUntrackedChanges(workspacePath) {
16510
+ const { stdout } = await runGit(workspacePath, ["ls-files", "--others", "--exclude-standard"]);
16511
+ return stdout.split("\n").map((line) => line.trim()).filter((line) => line.length > 0).map((path14) => ({
16512
+ path: path14,
16513
+ status: "untracked"
16514
+ })).filter((change) => !isWorkspaceStatePath(change.path)).sort(compareGitChanges);
16515
+ }
16516
+ async function isUntrackedPath(workspacePath, filePath) {
16517
+ const { stdout } = await runGit(workspacePath, [
16518
+ "ls-files",
16519
+ "--others",
16520
+ "--exclude-standard",
16521
+ "--",
16522
+ filePath
16523
+ ]);
16524
+ return stdout.trim().length > 0;
16525
+ }
16526
+ async function buildSessionReviewSummary(input) {
16527
+ const metadata = requireSessionMetadata(input.metadataRepo, input.sessionId);
16528
+ if (!metadata.baselineGitHead) {
16529
+ return {
16530
+ sessionId: metadata.sessionId,
16531
+ workspaceId: metadata.workspaceId,
16532
+ baselineGitHead: metadata.baselineGitHead,
16533
+ changedFiles: [],
16534
+ verificationRuns: metadata.verificationRuns,
16535
+ warnings: [MISSING_BASELINE_WARNING]
16536
+ };
16537
+ }
16538
+ if (!await isGitRepository(input.workspacePath)) {
16539
+ return {
16540
+ sessionId: metadata.sessionId,
16541
+ workspaceId: metadata.workspaceId,
16542
+ baselineGitHead: metadata.baselineGitHead,
16543
+ changedFiles: [],
16544
+ verificationRuns: metadata.verificationRuns,
16545
+ warnings: [NOT_GIT_REPO_WARNING]
16546
+ };
16547
+ }
16548
+ const trackedChanges = await listTrackedChangesSinceBaseline(
16549
+ input.workspacePath,
16550
+ metadata.baselineGitHead
16551
+ );
16552
+ const trackedPaths = new Set(trackedChanges.map((change) => change.path));
16553
+ const untrackedChanges = (await listUntrackedChanges(input.workspacePath)).filter(
16554
+ (change) => !trackedPaths.has(change.path)
16555
+ );
16556
+ return {
16557
+ sessionId: metadata.sessionId,
16558
+ workspaceId: metadata.workspaceId,
16559
+ baselineGitHead: metadata.baselineGitHead,
16560
+ changedFiles: [...trackedChanges, ...untrackedChanges],
16561
+ verificationRuns: metadata.verificationRuns,
16562
+ warnings: []
16563
+ };
16564
+ }
16565
+ async function getSessionReviewDiff(input) {
16566
+ const metadata = requireSessionMetadata(input.metadataRepo, input.sessionId);
16567
+ if (!metadata.baselineGitHead) {
16568
+ return "";
16569
+ }
16570
+ if (!await isGitRepository(input.workspacePath)) {
16571
+ return "";
16572
+ }
16573
+ if (await isUntrackedPath(input.workspacePath, input.path)) {
16574
+ return (await getFileDiff(input.workspacePath, input.path)).diff;
16575
+ }
16576
+ const { stdout } = await runGit(input.workspacePath, [
16577
+ "diff",
16578
+ metadata.baselineGitHead,
16579
+ "--",
16580
+ input.path
16581
+ ]);
16582
+ return stdout;
16583
+ }
16584
+ var MISSING_BASELINE_WARNING, NOT_GIT_REPO_WARNING;
16585
+ var init_review = __esm({
16586
+ "packages/server/src/session-review/review.ts"() {
16587
+ "use strict";
16588
+ init_cli();
16589
+ init_diff();
16590
+ init_workspace_state();
16591
+ MISSING_BASELINE_WARNING = {
16592
+ code: "missing_baseline",
16593
+ message: "Session baseline is missing."
16594
+ };
16595
+ NOT_GIT_REPO_WARNING = {
16596
+ code: "not_git_repo",
16597
+ message: "Workspace is not a Git repository."
16598
+ };
16599
+ }
16600
+ });
16601
+
16602
+ // packages/server/src/commands/session-review.ts
16603
+ import { z as z15 } from "zod";
16604
+ function requireSessionMetadataRepo2(ctx) {
16605
+ if (!ctx.sessionMetadataRepo) {
16606
+ throw {
16607
+ code: "session_metadata_unavailable",
16608
+ message: "Session metadata repository is not configured"
16609
+ };
16610
+ }
16611
+ }
16612
+ function requireWorkspace(ctx, workspaceId) {
16613
+ const workspace = ctx.workspaceMgr.get(workspaceId);
16614
+ if (!workspace) {
16615
+ throw { code: "workspace_not_found", message: `Workspace not found: ${workspaceId}` };
16616
+ }
16617
+ return workspace;
16618
+ }
16619
+ var init_session_review = __esm({
16620
+ "packages/server/src/commands/session-review.ts"() {
16621
+ "use strict";
16622
+ init_review();
16623
+ init_dispatch();
16624
+ registerCommand(
16625
+ "sessionReview.summary",
16626
+ z15.object({
16627
+ sessionId: z15.string()
16628
+ }),
16629
+ async (args, ctx) => {
16630
+ requireSessionMetadataRepo2(ctx);
16631
+ const metadata = ctx.sessionMetadataRepo.get(args.sessionId);
16632
+ if (!metadata) {
16633
+ throw {
16634
+ code: "session_metadata_not_found",
16635
+ message: `Session metadata not found: ${args.sessionId}`
16636
+ };
16637
+ }
16638
+ const workspace = requireWorkspace(ctx, metadata.workspaceId);
16639
+ return buildSessionReviewSummary({
16640
+ sessionId: args.sessionId,
16641
+ workspacePath: workspace.path,
16642
+ metadataRepo: ctx.sessionMetadataRepo
16643
+ });
16644
+ }
16645
+ );
16646
+ registerCommand(
16647
+ "sessionReview.diff",
16648
+ z15.object({
16649
+ sessionId: z15.string(),
16650
+ path: z15.string().trim().min(1)
16651
+ }),
16652
+ async (args, ctx) => {
16653
+ requireSessionMetadataRepo2(ctx);
16654
+ const metadata = ctx.sessionMetadataRepo.get(args.sessionId);
16655
+ if (!metadata) {
16656
+ throw {
16657
+ code: "session_metadata_not_found",
16658
+ message: `Session metadata not found: ${args.sessionId}`
16659
+ };
16660
+ }
16661
+ const workspace = requireWorkspace(ctx, metadata.workspaceId);
16662
+ return {
16663
+ path: args.path,
16664
+ diff: await getSessionReviewDiff({
16665
+ sessionId: args.sessionId,
16666
+ workspacePath: workspace.path,
16667
+ metadataRepo: ctx.sessionMetadataRepo,
16668
+ path: args.path
16669
+ })
16670
+ };
16671
+ }
16672
+ );
16673
+ }
16674
+ });
16675
+
16676
+ // packages/server/src/fs/content-search.ts
16677
+ import { spawn as spawn5 } from "child_process";
16678
+ import { existsSync as existsSync8 } from "fs";
16679
+ import { readdir as readdir4, readFile as readFile7, stat as stat10 } from "fs/promises";
16680
+ import { basename as basename2, join as join15, relative as relative3 } from "path";
16681
+ import { createInterface } from "readline";
16682
+ async function searchFileContents(rootPath, options) {
16683
+ const query = options.query.trim();
16684
+ if (!query) {
16685
+ return {
16686
+ files: [],
16687
+ totalMatchCount: 0,
16688
+ hasMoreFiles: false,
16689
+ truncatedMatchFileCount: 0
16690
+ };
16691
+ }
16692
+ const result = await searchWithRipgrep(rootPath, query, options.maxFiles).catch(
16693
+ async (error) => {
16694
+ if (error.code === "ENOENT") {
16695
+ return searchWithNode(rootPath, query, options.maxFiles);
16696
+ }
16697
+ throw error;
16698
+ }
16699
+ );
16700
+ return finalizeResults(result, options.maxFiles, options.maxMatchesPerFile);
16701
+ }
16702
+ async function searchWithRipgrep(rootPath, query, maxFiles) {
16703
+ const hasGitignore = existsSync8(join15(rootPath, ".gitignore"));
16704
+ const args = [
16705
+ "--json",
16706
+ "--line-number",
16707
+ "--column",
16708
+ "--fixed-strings",
16709
+ "--sort",
16710
+ "path",
15547
16711
  "--with-filename",
15548
16712
  "--glob",
15549
16713
  "!**/.git/**",
@@ -15555,7 +16719,7 @@ async function searchWithRipgrep(rootPath, query, maxFiles) {
15555
16719
  args.push("--no-require-git");
15556
16720
  }
15557
16721
  args.push(query, ".");
15558
- return new Promise((resolve6, reject) => {
16722
+ return new Promise((resolve8, reject) => {
15559
16723
  const child = spawn5("rg", args, { cwd: rootPath, stdio: ["ignore", "pipe", "pipe"] });
15560
16724
  const stdout = createInterface({ input: child.stdout });
15561
16725
  const files = /* @__PURE__ */ new Map();
@@ -15574,7 +16738,7 @@ async function searchWithRipgrep(rootPath, query, maxFiles) {
15574
16738
  if (!rawPath) {
15575
16739
  return;
15576
16740
  }
15577
- const relativePath = normalizeRelativePath(relative3(rootPath, join12(rootPath, rawPath)));
16741
+ const relativePath = normalizeRelativePath(relative3(rootPath, join15(rootPath, rawPath)));
15578
16742
  const preview = (event.data?.lines?.text ?? "").replace(/\r?\n$/, "");
15579
16743
  const lineNumber = event.data?.line_number ?? 1;
15580
16744
  const submatches = event.data?.submatches ?? [];
@@ -15604,7 +16768,7 @@ async function searchWithRipgrep(rootPath, query, maxFiles) {
15604
16768
  child.on("close", (code) => {
15605
16769
  void stdout.close();
15606
16770
  if (code === 0 || code === 1) {
15607
- resolve6({
16771
+ resolve8({
15608
16772
  files: sortAccumulators(files),
15609
16773
  totalMatchCount,
15610
16774
  hasMoreFiles
@@ -15627,7 +16791,7 @@ async function searchWithNode(rootPath, query, maxFiles) {
15627
16791
  const filteredEntries = entries.filter((entry) => filter(entry.name));
15628
16792
  filteredEntries.sort((a, b) => a.name.localeCompare(b.name));
15629
16793
  for (const entry of filteredEntries) {
15630
- const fullPath = join12(dirPath, entry.name);
16794
+ const fullPath = join15(dirPath, entry.name);
15631
16795
  if (entry.isDirectory()) {
15632
16796
  await walk(fullPath);
15633
16797
  continue;
@@ -15635,11 +16799,11 @@ async function searchWithNode(rootPath, query, maxFiles) {
15635
16799
  if (!entry.isFile()) {
15636
16800
  continue;
15637
16801
  }
15638
- const fileStat = await stat9(fullPath);
16802
+ const fileStat = await stat10(fullPath);
15639
16803
  if (fileStat.size > FALLBACK_MAX_FILE_BYTES) {
15640
16804
  continue;
15641
16805
  }
15642
- const buffer = await readFile4(fullPath);
16806
+ const buffer = await readFile7(fullPath);
15643
16807
  if (isBinaryFile(buffer)) {
15644
16808
  continue;
15645
16809
  }
@@ -15750,10 +16914,10 @@ var init_content_search = __esm({
15750
16914
  });
15751
16915
 
15752
16916
  // packages/server/src/fs/tree.ts
15753
- import { readdir as readdir5, stat as stat10 } from "fs/promises";
15754
- import { join as join13, relative as relative4 } from "path";
16917
+ import { readdir as readdir5, stat as stat11 } from "fs/promises";
16918
+ import { join as join16, relative as relative4 } from "path";
15755
16919
  async function readTree(rootPath, subdir) {
15756
- const targetPath = subdir ? join13(rootPath, subdir) : rootPath;
16920
+ const targetPath = subdir ? join16(rootPath, subdir) : rootPath;
15757
16921
  const filter = createTreeVisibilityFilter();
15758
16922
  const entries = await readdir5(targetPath, { withFileTypes: true });
15759
16923
  const nodes = [];
@@ -15761,7 +16925,7 @@ async function readTree(rootPath, subdir) {
15761
16925
  if (!filter(entry.name)) {
15762
16926
  continue;
15763
16927
  }
15764
- const fullPath = join13(targetPath, entry.name);
16928
+ const fullPath = join16(targetPath, entry.name);
15765
16929
  const relPath = relative4(rootPath, fullPath);
15766
16930
  if (entry.isDirectory()) {
15767
16931
  nodes.push({
@@ -15772,7 +16936,7 @@ async function readTree(rootPath, subdir) {
15772
16936
  // Not loaded yet - client will request on expand
15773
16937
  });
15774
16938
  } else if (entry.isFile()) {
15775
- const stats = await stat10(fullPath);
16939
+ const stats = await stat11(fullPath);
15776
16940
  nodes.push({
15777
16941
  name: entry.name,
15778
16942
  path: relPath,
@@ -15805,7 +16969,7 @@ async function searchFiles(rootPath, query, limit = 10) {
15805
16969
  const filteredEntries = entries.filter((entry) => filter(entry.name));
15806
16970
  filteredEntries.sort((a, b) => a.name.localeCompare(b.name));
15807
16971
  for (const entry of filteredEntries) {
15808
- const fullPath = join13(dirPath, entry.name);
16972
+ const fullPath = join16(dirPath, entry.name);
15809
16973
  const relPath = relative4(rootPath, fullPath);
15810
16974
  if (entry.isDirectory()) {
15811
16975
  await walk(fullPath);
@@ -15841,7 +17005,7 @@ async function searchFiles(rootPath, query, limit = 10) {
15841
17005
  }
15842
17006
  return a.path.toLowerCase().localeCompare(b.path.toLowerCase());
15843
17007
  }).slice(0, limit)) {
15844
- const stats = await stat10(match.fullPath);
17008
+ const stats = await stat11(match.fullPath);
15845
17009
  files.push({
15846
17010
  name: match.name,
15847
17011
  path: match.path,
@@ -15921,7 +17085,7 @@ var init_tree = __esm({
15921
17085
  });
15922
17086
 
15923
17087
  // packages/server/src/commands/file.ts
15924
- import { z as z13 } from "zod";
17088
+ import { z as z16 } from "zod";
15925
17089
  var init_file = __esm({
15926
17090
  "packages/server/src/commands/file.ts"() {
15927
17091
  "use strict";
@@ -15931,9 +17095,9 @@ var init_file = __esm({
15931
17095
  init_dispatch();
15932
17096
  registerCommand(
15933
17097
  "file.readTree",
15934
- z13.object({
15935
- workspaceId: z13.string(),
15936
- subPath: z13.string().optional()
17098
+ z16.object({
17099
+ workspaceId: z16.string(),
17100
+ subPath: z16.string().optional()
15937
17101
  }),
15938
17102
  async (args, ctx) => {
15939
17103
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -15945,10 +17109,10 @@ var init_file = __esm({
15945
17109
  );
15946
17110
  registerCommand(
15947
17111
  "file.search",
15948
- z13.object({
15949
- workspaceId: z13.string(),
15950
- query: z13.string(),
15951
- limit: z13.number().int().positive().max(50).optional()
17112
+ z16.object({
17113
+ workspaceId: z16.string(),
17114
+ query: z16.string(),
17115
+ limit: z16.number().int().positive().max(50).optional()
15952
17116
  }),
15953
17117
  async (args, ctx) => {
15954
17118
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -15960,11 +17124,11 @@ var init_file = __esm({
15960
17124
  );
15961
17125
  registerCommand(
15962
17126
  "file.searchContent",
15963
- z13.object({
15964
- workspaceId: z13.string(),
15965
- query: z13.string(),
15966
- maxFiles: z13.number().int().positive().max(100),
15967
- maxMatchesPerFile: z13.number().int().positive().max(100)
17127
+ z16.object({
17128
+ workspaceId: z16.string(),
17129
+ query: z16.string(),
17130
+ maxFiles: z16.number().int().positive().max(100),
17131
+ maxMatchesPerFile: z16.number().int().positive().max(100)
15968
17132
  }),
15969
17133
  async (args, ctx) => {
15970
17134
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -15980,9 +17144,9 @@ var init_file = __esm({
15980
17144
  );
15981
17145
  registerCommand(
15982
17146
  "file.read",
15983
- z13.object({
15984
- workspaceId: z13.string(),
15985
- path: z13.string()
17147
+ z16.object({
17148
+ workspaceId: z16.string(),
17149
+ path: z16.string()
15986
17150
  }),
15987
17151
  async (args, ctx) => {
15988
17152
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -15994,9 +17158,9 @@ var init_file = __esm({
15994
17158
  );
15995
17159
  registerCommand(
15996
17160
  "file.create",
15997
- z13.object({
15998
- workspaceId: z13.string(),
15999
- path: z13.string()
17161
+ z16.object({
17162
+ workspaceId: z16.string(),
17163
+ path: z16.string()
16000
17164
  }),
16001
17165
  async (args, ctx) => {
16002
17166
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -16014,9 +17178,9 @@ var init_file = __esm({
16014
17178
  );
16015
17179
  registerCommand(
16016
17180
  "file.mkdir",
16017
- z13.object({
16018
- workspaceId: z13.string(),
16019
- path: z13.string()
17181
+ z16.object({
17182
+ workspaceId: z16.string(),
17183
+ path: z16.string()
16020
17184
  }),
16021
17185
  async (args, ctx) => {
16022
17186
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -16034,9 +17198,9 @@ var init_file = __esm({
16034
17198
  );
16035
17199
  registerCommand(
16036
17200
  "file.delete",
16037
- z13.object({
16038
- workspaceId: z13.string(),
16039
- path: z13.string()
17201
+ z16.object({
17202
+ workspaceId: z16.string(),
17203
+ path: z16.string()
16040
17204
  }),
16041
17205
  async (args, ctx) => {
16042
17206
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -16054,10 +17218,10 @@ var init_file = __esm({
16054
17218
  );
16055
17219
  registerCommand(
16056
17220
  "file.rename",
16057
- z13.object({
16058
- workspaceId: z13.string(),
16059
- fromPath: z13.string(),
16060
- toPath: z13.string()
17221
+ z16.object({
17222
+ workspaceId: z16.string(),
17223
+ fromPath: z16.string(),
17224
+ toPath: z16.string()
16061
17225
  }),
16062
17226
  async (args, ctx) => {
16063
17227
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -16075,167 +17239,27 @@ var init_file = __esm({
16075
17239
  );
16076
17240
  registerCommand(
16077
17241
  "file.write",
16078
- z13.object({
16079
- workspaceId: z13.string(),
16080
- path: z13.string(),
16081
- content: z13.string(),
16082
- baseHash: z13.string().optional()
17242
+ z16.object({
17243
+ workspaceId: z16.string(),
17244
+ path: z16.string(),
17245
+ content: z16.string(),
17246
+ baseHash: z16.string().optional()
16083
17247
  // For conflict detection
16084
17248
  }),
16085
- async (args, ctx) => {
16086
- const workspace = ctx.workspaceMgr.get(args.workspaceId);
16087
- if (!workspace) {
16088
- throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
16089
- }
16090
- const result = await writeFile(workspace.path, args.path, args.content, args.baseHash);
16091
- ctx.eventBus.emit({
16092
- type: "fs.dirty",
16093
- workspaceId: args.workspaceId,
16094
- reason: "file_content"
16095
- });
16096
- return result;
16097
- }
16098
- );
16099
- }
16100
- });
16101
-
16102
- // packages/server/src/git/diff.ts
16103
- import { mkdtemp as mkdtemp3, readFile as readFile5, rm as rm7 } from "fs/promises";
16104
- import os3 from "os";
16105
- import path11 from "path";
16106
- async function isTrackedPath(cwd, filePath) {
16107
- try {
16108
- await runGit(cwd, ["ls-files", "--error-unmatch", "--", filePath]);
16109
- return true;
16110
- } catch {
16111
- return false;
16112
- }
16113
- }
16114
- async function getUntrackedFileDiff(cwd, filePath) {
16115
- const tempDir = await mkdtemp3(path11.join(os3.tmpdir(), "coder-studio-git-diff-"));
16116
- const tempIndex = path11.join(tempDir, "index");
16117
- try {
16118
- try {
16119
- await runGit(cwd, ["read-tree", "HEAD"], {
16120
- env: { GIT_INDEX_FILE: tempIndex }
16121
- });
16122
- } catch (error) {
16123
- if (!(error instanceof GitError)) {
16124
- throw error;
16125
- }
16126
- await runGit(cwd, ["read-tree", "--empty"], {
16127
- env: { GIT_INDEX_FILE: tempIndex }
16128
- });
16129
- }
16130
- await runGit(cwd, ["add", "-N", "--", filePath], {
16131
- env: { GIT_INDEX_FILE: tempIndex }
16132
- });
16133
- const result = await runGit(cwd, ["diff", "--", filePath], {
16134
- env: { GIT_INDEX_FILE: tempIndex }
16135
- });
16136
- return result.stdout;
16137
- } finally {
16138
- await rm7(tempDir, { recursive: true, force: true });
16139
- }
16140
- }
16141
- async function pathExists(cwd, filePath) {
16142
- try {
16143
- await readFile5(resolveSafe(cwd, filePath));
16144
- return true;
16145
- } catch {
16146
- return false;
16147
- }
16148
- }
16149
- async function readTextAtRevision(cwd, revision, filePath) {
16150
- if (revision === "WORKTREE") {
16151
- return readFile5(resolveSafe(cwd, filePath), "utf-8");
16152
- }
16153
- try {
16154
- const gitSpec = revision === "INDEX" ? `:${filePath}` : `${revision}:${filePath}`;
16155
- const result = await runGit(cwd, ["show", gitSpec]);
16156
- return result.stdout;
16157
- } catch {
16158
- return "";
16159
- }
16160
- }
16161
- async function deriveFileDiffStatus(cwd, filePath, staged) {
16162
- const tracked = await isTrackedPath(cwd, filePath);
16163
- const existsOnDisk = await pathExists(cwd, filePath);
16164
- if (!staged && !tracked) {
16165
- return "added";
16166
- }
16167
- if (staged) {
16168
- try {
16169
- await runGit(cwd, ["cat-file", "-e", `HEAD:${filePath}`]);
16170
- return existsOnDisk ? "modified" : "deleted";
16171
- } catch {
16172
- return "added";
16173
- }
16174
- }
16175
- return existsOnDisk ? "modified" : "deleted";
16176
- }
16177
- async function buildTextDiffResult(cwd, filePath, staged, diff) {
16178
- const status = await deriveFileDiffStatus(cwd, filePath, staged);
16179
- if (status === "added") {
16180
- return {
16181
- diff,
16182
- renderAs: "text",
16183
- status,
16184
- originalContent: "",
16185
- modifiedContent: await readTextAtRevision(cwd, staged ? "INDEX" : "WORKTREE", filePath)
16186
- };
16187
- }
16188
- if (status === "deleted") {
16189
- return {
16190
- diff,
16191
- renderAs: "text",
16192
- status,
16193
- originalContent: await readTextAtRevision(cwd, staged ? "HEAD" : "INDEX", filePath),
16194
- modifiedContent: ""
16195
- };
16196
- }
16197
- return {
16198
- diff,
16199
- renderAs: "text",
16200
- status,
16201
- originalContent: await readTextAtRevision(cwd, staged ? "HEAD" : "INDEX", filePath),
16202
- modifiedContent: await readTextAtRevision(cwd, staged ? "INDEX" : "WORKTREE", filePath)
16203
- };
16204
- }
16205
- async function getFileDiff(cwd, path14, staged = false) {
16206
- const imageType = getImageTypeInfo(path14);
16207
- if (!staged && !await isTrackedPath(cwd, path14)) {
16208
- const diff = await getUntrackedFileDiff(cwd, path14);
16209
- if (imageType) {
16210
- return {
16211
- diff,
16212
- renderAs: "image",
16213
- status: "added",
16214
- originalRevision: "HEAD",
16215
- modifiedRevision: "WORKTREE"
16216
- };
16217
- }
16218
- return buildTextDiffResult(cwd, path14, staged, diff);
16219
- }
16220
- const args = staged ? ["diff", "--staged", "--", path14] : ["diff", "--", path14];
16221
- const result = await runGit(cwd, args);
16222
- if (imageType && /Binary files .* differ/.test(result.stdout)) {
16223
- return {
16224
- diff: result.stdout,
16225
- renderAs: "image",
16226
- status: await deriveFileDiffStatus(cwd, path14, staged),
16227
- originalRevision: staged ? "HEAD" : "INDEX",
16228
- modifiedRevision: staged ? "INDEX" : "WORKTREE"
16229
- };
16230
- }
16231
- return buildTextDiffResult(cwd, path14, staged, result.stdout);
16232
- }
16233
- var init_diff = __esm({
16234
- "packages/server/src/git/diff.ts"() {
16235
- "use strict";
16236
- init_file_io();
16237
- init_image();
16238
- init_cli();
17249
+ async (args, ctx) => {
17250
+ const workspace = ctx.workspaceMgr.get(args.workspaceId);
17251
+ if (!workspace) {
17252
+ throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
17253
+ }
17254
+ const result = await writeFile(workspace.path, args.path, args.content, args.baseHash);
17255
+ ctx.eventBus.emit({
17256
+ type: "fs.dirty",
17257
+ workspaceId: args.workspaceId,
17258
+ reason: "file_content"
17259
+ });
17260
+ return result;
17261
+ }
17262
+ );
16239
17263
  }
16240
17264
  });
16241
17265
 
@@ -16256,7 +17280,7 @@ var init_git_events = __esm({
16256
17280
  });
16257
17281
 
16258
17282
  // packages/server/src/commands/git.ts
16259
- import { z as z14 } from "zod";
17283
+ import { z as z17 } from "zod";
16260
17284
  async function runGitNetworkOperation(ctx, workspaceId, op) {
16261
17285
  if (!ctx.autoFetch?.runExclusive) {
16262
17286
  return op();
@@ -16271,16 +17295,16 @@ var init_git2 = __esm({
16271
17295
  init_diff();
16272
17296
  init_dispatch();
16273
17297
  init_git_events();
16274
- gitHttpAuthSchema = z14.object({
16275
- username: z14.string(),
16276
- password: z14.string()
17298
+ gitHttpAuthSchema = z17.object({
17299
+ username: z17.string(),
17300
+ password: z17.string()
16277
17301
  });
16278
- gitCommitRevisionSchema = z14.string().regex(/^[0-9a-fA-F]{7,64}$/, "Invalid git commit revision");
17302
+ gitCommitRevisionSchema = z17.string().regex(/^[0-9a-fA-F]{7,64}$/, "Invalid git commit revision");
16279
17303
  GIT_BACKGROUND_FETCH_TIMEOUT_MS = 30 * 1e3;
16280
17304
  registerCommand(
16281
17305
  "git.status",
16282
- z14.object({
16283
- workspaceId: z14.string()
17306
+ z17.object({
17307
+ workspaceId: z17.string()
16284
17308
  }),
16285
17309
  async (args, ctx) => {
16286
17310
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -16292,9 +17316,9 @@ var init_git2 = __esm({
16292
17316
  );
16293
17317
  registerCommand(
16294
17318
  "git.stage",
16295
- z14.object({
16296
- workspaceId: z14.string(),
16297
- paths: z14.array(z14.string())
17319
+ z17.object({
17320
+ workspaceId: z17.string(),
17321
+ paths: z17.array(z17.string())
16298
17322
  }),
16299
17323
  async (args, ctx) => {
16300
17324
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -16308,10 +17332,10 @@ var init_git2 = __esm({
16308
17332
  );
16309
17333
  registerCommand(
16310
17334
  "git.diff",
16311
- z14.object({
16312
- workspaceId: z14.string(),
16313
- path: z14.string(),
16314
- staged: z14.boolean().optional()
17335
+ z17.object({
17336
+ workspaceId: z17.string(),
17337
+ path: z17.string(),
17338
+ staged: z17.boolean().optional()
16315
17339
  }),
16316
17340
  async (args, ctx) => {
16317
17341
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -16323,9 +17347,9 @@ var init_git2 = __esm({
16323
17347
  );
16324
17348
  registerCommand(
16325
17349
  "git.log",
16326
- z14.object({
16327
- workspaceId: z14.string(),
16328
- limit: z14.number().int().min(1).max(50).optional()
17350
+ z17.object({
17351
+ workspaceId: z17.string(),
17352
+ limit: z17.number().int().min(1).max(50).optional()
16329
17353
  }),
16330
17354
  async (args, ctx) => {
16331
17355
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -16339,8 +17363,8 @@ var init_git2 = __esm({
16339
17363
  );
16340
17364
  registerCommand(
16341
17365
  "git.show",
16342
- z14.object({
16343
- workspaceId: z14.string(),
17366
+ z17.object({
17367
+ workspaceId: z17.string(),
16344
17368
  sha: gitCommitRevisionSchema
16345
17369
  }),
16346
17370
  async (args, ctx) => {
@@ -16355,9 +17379,9 @@ var init_git2 = __esm({
16355
17379
  );
16356
17380
  registerCommand(
16357
17381
  "git.unstage",
16358
- z14.object({
16359
- workspaceId: z14.string(),
16360
- paths: z14.array(z14.string())
17382
+ z17.object({
17383
+ workspaceId: z17.string(),
17384
+ paths: z17.array(z17.string())
16361
17385
  }),
16362
17386
  async (args, ctx) => {
16363
17387
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -16371,9 +17395,9 @@ var init_git2 = __esm({
16371
17395
  );
16372
17396
  registerCommand(
16373
17397
  "git.discard",
16374
- z14.object({
16375
- workspaceId: z14.string(),
16376
- paths: z14.array(z14.string())
17398
+ z17.object({
17399
+ workspaceId: z17.string(),
17400
+ paths: z17.array(z17.string())
16377
17401
  }),
16378
17402
  async (args, ctx) => {
16379
17403
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -16389,9 +17413,9 @@ var init_git2 = __esm({
16389
17413
  );
16390
17414
  registerCommand(
16391
17415
  "git.commit",
16392
- z14.object({
16393
- workspaceId: z14.string(),
16394
- message: z14.string()
17416
+ z17.object({
17417
+ workspaceId: z17.string(),
17418
+ message: z17.string()
16395
17419
  }),
16396
17420
  async (args, ctx) => {
16397
17421
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -16408,11 +17432,11 @@ var init_git2 = __esm({
16408
17432
  );
16409
17433
  registerCommand(
16410
17434
  "git.push",
16411
- z14.object({
16412
- workspaceId: z14.string(),
16413
- remote: z14.string().optional(),
16414
- branch: z14.string().optional(),
16415
- force: z14.boolean().optional(),
17435
+ z17.object({
17436
+ workspaceId: z17.string(),
17437
+ remote: z17.string().optional(),
17438
+ branch: z17.string().optional(),
17439
+ force: z17.boolean().optional(),
16416
17440
  auth: gitHttpAuthSchema.optional()
16417
17441
  }),
16418
17442
  async (args, ctx) => {
@@ -16438,128 +17462,737 @@ var init_git2 = __esm({
16438
17462
  }
16439
17463
  );
16440
17464
  registerCommand(
16441
- "git.pull",
16442
- z14.object({
16443
- workspaceId: z14.string(),
16444
- remote: z14.string().optional(),
16445
- branch: z14.string().optional(),
16446
- auth: gitHttpAuthSchema.optional()
17465
+ "git.pull",
17466
+ z17.object({
17467
+ workspaceId: z17.string(),
17468
+ remote: z17.string().optional(),
17469
+ branch: z17.string().optional(),
17470
+ auth: gitHttpAuthSchema.optional()
17471
+ }),
17472
+ async (args, ctx) => {
17473
+ const workspace = ctx.workspaceMgr.get(args.workspaceId);
17474
+ if (!workspace) {
17475
+ throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
17476
+ }
17477
+ const result = await runGitNetworkOperation(
17478
+ ctx,
17479
+ args.workspaceId,
17480
+ () => runGitPull(workspace.path, {
17481
+ remote: args.remote,
17482
+ branch: args.branch,
17483
+ auth: args.auth
17484
+ })
17485
+ );
17486
+ ctx.workspaceMgr.recordFetch(args.workspaceId);
17487
+ emitGitStateChanged(ctx, args.workspaceId, {
17488
+ treeChanged: true,
17489
+ branchChanged: true,
17490
+ worktreeChanged: true
17491
+ });
17492
+ return result;
17493
+ }
17494
+ );
17495
+ registerCommand(
17496
+ "git.fetch",
17497
+ z17.object({
17498
+ workspaceId: z17.string(),
17499
+ remote: z17.string().optional(),
17500
+ prune: z17.boolean().optional(),
17501
+ auth: gitHttpAuthSchema.optional(),
17502
+ background: z17.boolean().optional()
17503
+ }),
17504
+ async (args, ctx, clientId) => {
17505
+ const workspace = ctx.workspaceMgr.get(args.workspaceId);
17506
+ if (!workspace) {
17507
+ throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
17508
+ }
17509
+ try {
17510
+ const isInternalBackgroundFetch = args.background === true && !clientId;
17511
+ const runFetch = () => runGitFetch(workspace.path, {
17512
+ remote: args.remote,
17513
+ prune: args.prune,
17514
+ auth: args.auth,
17515
+ timeoutMs: args.background ? GIT_BACKGROUND_FETCH_TIMEOUT_MS : void 0
17516
+ });
17517
+ const result = isInternalBackgroundFetch ? await runFetch() : await runGitNetworkOperation(ctx, args.workspaceId, runFetch);
17518
+ ctx.workspaceMgr.recordFetch(args.workspaceId);
17519
+ emitGitStateChanged(ctx, args.workspaceId, { branchChanged: true });
17520
+ return result;
17521
+ } catch (err) {
17522
+ if (args.background && err instanceof GitAuthError) {
17523
+ return { success: false, message: err.message, updatedRefs: [] };
17524
+ }
17525
+ throw err;
17526
+ }
17527
+ }
17528
+ );
17529
+ registerCommand(
17530
+ "git.checkout",
17531
+ z17.object({
17532
+ workspaceId: z17.string(),
17533
+ ref: z17.string(),
17534
+ createBranch: z17.boolean().optional()
17535
+ }),
17536
+ async (args, ctx) => {
17537
+ const workspace = ctx.workspaceMgr.get(args.workspaceId);
17538
+ if (!workspace) {
17539
+ throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
17540
+ }
17541
+ const result = await runGitCheckout(workspace.path, args.ref, {
17542
+ createBranch: args.createBranch
17543
+ });
17544
+ if (result.success) {
17545
+ emitGitStateChanged(ctx, args.workspaceId, {
17546
+ treeChanged: true,
17547
+ branchChanged: true,
17548
+ worktreeChanged: true
17549
+ });
17550
+ }
17551
+ return result;
17552
+ }
17553
+ );
17554
+ registerCommand(
17555
+ "git.branch",
17556
+ z17.object({
17557
+ workspaceId: z17.string(),
17558
+ name: z17.string(),
17559
+ startPoint: z17.string().optional()
17560
+ }),
17561
+ async (args, ctx) => {
17562
+ const workspace = ctx.workspaceMgr.get(args.workspaceId);
17563
+ if (!workspace) {
17564
+ throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
17565
+ }
17566
+ const result = await runGitCreateBranch(workspace.path, args.name, {
17567
+ startPoint: args.startPoint
17568
+ });
17569
+ emitGitStateChanged(ctx, args.workspaceId, {
17570
+ branchChanged: true,
17571
+ worktreeChanged: true
17572
+ });
17573
+ return result;
17574
+ }
17575
+ );
17576
+ registerCommand(
17577
+ "git.branches",
17578
+ z17.object({
17579
+ workspaceId: z17.string()
17580
+ }),
17581
+ async (args, ctx) => {
17582
+ const workspace = ctx.workspaceMgr.get(args.workspaceId);
17583
+ if (!workspace) {
17584
+ throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
17585
+ }
17586
+ return runGitListBranches(workspace.path);
17587
+ }
17588
+ );
17589
+ }
17590
+ });
17591
+
17592
+ // packages/server/src/agent-instructions/generator.ts
17593
+ function buildAgentInstructionsMarkdown(summary) {
17594
+ const lines = ["# Agent Instructions", ""];
17595
+ pushSection(lines, "Project Overview", buildProjectOverview(summary));
17596
+ pushSection(lines, "Development Commands", buildDevelopmentCommands(summary));
17597
+ pushSection(lines, "Working Rules", [...WORKING_RULES.map((rule) => `- ${rule}`)]);
17598
+ pushSection(
17599
+ lines,
17600
+ "Review Expectations",
17601
+ REVIEW_EXPECTATIONS.map((rule) => `- ${rule}`)
17602
+ );
17603
+ pushSection(
17604
+ lines,
17605
+ "Provider Notes",
17606
+ PROVIDER_NOTES.map((note) => `- ${note}`)
17607
+ );
17608
+ return lines.join("\n");
17609
+ }
17610
+ function buildProjectOverview(summary) {
17611
+ const lines = [];
17612
+ if (summary.git.isRepo) {
17613
+ if (summary.git.branch) {
17614
+ lines.push(`- Git branch: ${summary.git.branch}`);
17615
+ } else {
17616
+ lines.push("- Git repository: yes");
17617
+ }
17618
+ } else {
17619
+ lines.push("- Git repository: no");
17620
+ }
17621
+ if (summary.packageManager) {
17622
+ lines.push(`- Package manager: ${summary.packageManager}`);
17623
+ }
17624
+ if (summary.frameworks.length > 0) {
17625
+ lines.push(`- Frameworks: ${summary.frameworks.join(", ")}`);
17626
+ }
17627
+ if (summary.docs.length > 0) {
17628
+ lines.push(`- Docs: ${summary.docs.map((doc) => doc.path).join(", ")}`);
17629
+ }
17630
+ lines.push(
17631
+ `- ${summary.agentInstructions.path}: ${summary.agentInstructions.exists ? "exists" : "missing"}`
17632
+ );
17633
+ return lines;
17634
+ }
17635
+ function buildDevelopmentCommands(summary) {
17636
+ const lines = [];
17637
+ const commandLabels = {
17638
+ dev: "Dev",
17639
+ test: "Test",
17640
+ build: "Build",
17641
+ lint: "Lint"
17642
+ };
17643
+ for (const key of ["dev", "test", "build", "lint"]) {
17644
+ const command = summary.recommendedCommands.find((item) => item.key === key)?.command;
17645
+ if (!command) {
17646
+ continue;
17647
+ }
17648
+ lines.push(`- ${commandLabels[key]}: \`${command}\``);
17649
+ }
17650
+ return lines;
17651
+ }
17652
+ function pushSection(lines, heading, body) {
17653
+ lines.push(`## ${heading}`, "");
17654
+ lines.push(...body);
17655
+ lines.push("");
17656
+ }
17657
+ var WORKING_RULES, REVIEW_EXPECTATIONS, PROVIDER_NOTES;
17658
+ var init_generator = __esm({
17659
+ "packages/server/src/agent-instructions/generator.ts"() {
17660
+ "use strict";
17661
+ WORKING_RULES = [
17662
+ "Keep changes focused on the requested task.",
17663
+ "Do not revert user changes unless explicitly asked.",
17664
+ "Prefer the project's existing patterns.",
17665
+ "Run the relevant verification command before reporting completion."
17666
+ ];
17667
+ REVIEW_EXPECTATIONS = [
17668
+ "Summarize changed files.",
17669
+ "Report verification commands and results.",
17670
+ "Call out risks, skipped tests, and assumptions."
17671
+ ];
17672
+ PROVIDER_NOTES = [
17673
+ "Claude Code: use the project rules above.",
17674
+ "Codex: use the project rules above."
17675
+ ];
17676
+ }
17677
+ });
17678
+
17679
+ // packages/server/src/agent-instructions/health.ts
17680
+ function evaluateAgentInstructionsMarkdown(content) {
17681
+ if (!content.trim()) {
17682
+ return {
17683
+ path: AGENT_INSTRUCTIONS_RELATIVE_PATH,
17684
+ exists: false,
17685
+ status: "missing",
17686
+ checks: {
17687
+ projectOverview: false,
17688
+ developmentCommands: false,
17689
+ workingRules: false,
17690
+ reviewExpectations: false,
17691
+ safetyRules: false,
17692
+ providerNotes: false
17693
+ },
17694
+ issues: [
17695
+ {
17696
+ code: "missing_document",
17697
+ message: `${AGENT_INSTRUCTIONS_RELATIVE_PATH} is missing`
17698
+ }
17699
+ ]
17700
+ };
17701
+ }
17702
+ const sections = indexSections(content);
17703
+ const projectOverview = sections.has("Project Overview");
17704
+ const developmentCommands = hasAnyBullet(sections.get("Development Commands"));
17705
+ const workingRulesSection = sections.get("Working Rules");
17706
+ const reviewExpectationsSection = sections.get("Review Expectations");
17707
+ const providerNotesSection = sections.get("Provider Notes");
17708
+ const workingRules = hasAnyBullet(workingRulesSection);
17709
+ const reviewExpectations = hasAnyBullet(reviewExpectationsSection) && REQUIRED_REVIEW_EXPECTATIONS.every(
17710
+ (rule) => reviewExpectationsSection?.some((line) => line.includes(rule))
17711
+ );
17712
+ const providerNotes = hasAnyBullet(providerNotesSection) && PROVIDER_NOTE_MARKERS.some(
17713
+ (marker) => providerNotesSection?.some((line) => line.includes(marker))
17714
+ );
17715
+ const safetyRules = REQUIRED_WORKING_RULES.every(
17716
+ (rule) => workingRulesSection?.some((line) => line.includes(rule))
17717
+ );
17718
+ const issues = [];
17719
+ if (!projectOverview) {
17720
+ issues.push({
17721
+ code: "missing_project_overview",
17722
+ message: "Project Overview section is missing"
17723
+ });
17724
+ }
17725
+ if (!developmentCommands) {
17726
+ issues.push({
17727
+ code: "missing_development_commands",
17728
+ message: "Development Commands section is missing"
17729
+ });
17730
+ }
17731
+ if (!workingRules) {
17732
+ issues.push({
17733
+ code: "missing_working_rules",
17734
+ message: "Working Rules section is missing"
17735
+ });
17736
+ }
17737
+ if (!reviewExpectations) {
17738
+ issues.push({
17739
+ code: "missing_review_expectations",
17740
+ message: "Review Expectations section is missing"
17741
+ });
17742
+ }
17743
+ if (!safetyRules) {
17744
+ issues.push({
17745
+ code: "missing_safety_rules",
17746
+ message: "Working rules do not include the required safety rules"
17747
+ });
17748
+ }
17749
+ if (!providerNotes) {
17750
+ issues.push({
17751
+ code: "missing_provider_notes",
17752
+ message: "Provider Notes section is missing"
17753
+ });
17754
+ }
17755
+ const status = issues.length === 0 ? "healthy" : "warning";
17756
+ return {
17757
+ path: AGENT_INSTRUCTIONS_RELATIVE_PATH,
17758
+ exists: true,
17759
+ status,
17760
+ checks: {
17761
+ projectOverview,
17762
+ developmentCommands,
17763
+ workingRules,
17764
+ reviewExpectations,
17765
+ safetyRules,
17766
+ providerNotes
17767
+ },
17768
+ issues
17769
+ };
17770
+ }
17771
+ function indexSections(content) {
17772
+ const sections = /* @__PURE__ */ new Map();
17773
+ const lines = content.split(/\r?\n/);
17774
+ let currentHeading = null;
17775
+ for (const line of lines) {
17776
+ const heading = line.match(/^##\s+(.+?)\s*$/)?.[1];
17777
+ if (heading) {
17778
+ currentHeading = heading;
17779
+ if (!sections.has(heading)) {
17780
+ sections.set(heading, []);
17781
+ }
17782
+ continue;
17783
+ }
17784
+ if (currentHeading) {
17785
+ sections.get(currentHeading)?.push(line);
17786
+ }
17787
+ }
17788
+ return sections;
17789
+ }
17790
+ function hasAnyBullet(lines) {
17791
+ return Boolean(lines?.some((line) => line.trimStart().startsWith("- ")));
17792
+ }
17793
+ var REQUIRED_WORKING_RULES, REQUIRED_REVIEW_EXPECTATIONS, PROVIDER_NOTE_MARKERS;
17794
+ var init_health = __esm({
17795
+ "packages/server/src/agent-instructions/health.ts"() {
17796
+ "use strict";
17797
+ init_workspace_state();
17798
+ REQUIRED_WORKING_RULES = [
17799
+ "Keep changes focused on the requested task.",
17800
+ "Do not revert user changes unless explicitly asked.",
17801
+ "Prefer the project's existing patterns.",
17802
+ "Run the relevant verification command before reporting completion."
17803
+ ];
17804
+ REQUIRED_REVIEW_EXPECTATIONS = [
17805
+ "Summarize changed files.",
17806
+ "Report verification commands and results.",
17807
+ "Call out risks, skipped tests, and assumptions."
17808
+ ];
17809
+ PROVIDER_NOTE_MARKERS = ["Claude Code:", "Codex:"];
17810
+ }
17811
+ });
17812
+
17813
+ // packages/server/src/commands/agent-instructions.ts
17814
+ import { z as z18 } from "zod";
17815
+ async function readAgentInstructionsDocument(workspaceId, rootPath) {
17816
+ const path14 = AGENT_INSTRUCTIONS_RELATIVE_PATH;
17817
+ try {
17818
+ const result = await readFile(workspaceId, rootPath, path14);
17819
+ if (result.kind !== "text") {
17820
+ return {
17821
+ path: path14,
17822
+ exists: true,
17823
+ content: ""
17824
+ };
17825
+ }
17826
+ return {
17827
+ path: path14,
17828
+ exists: true,
17829
+ content: result.content,
17830
+ baseHash: result.baseHash
17831
+ };
17832
+ } catch {
17833
+ return {
17834
+ path: path14,
17835
+ exists: false,
17836
+ content: ""
17837
+ };
17838
+ }
17839
+ }
17840
+ var init_agent_instructions = __esm({
17841
+ "packages/server/src/commands/agent-instructions.ts"() {
17842
+ "use strict";
17843
+ init_generator();
17844
+ init_health();
17845
+ init_file_io();
17846
+ init_intelligence();
17847
+ init_workspace_state();
17848
+ init_dispatch();
17849
+ registerCommand(
17850
+ "agentInstructions.read",
17851
+ z18.object({
17852
+ workspaceId: z18.string()
17853
+ }),
17854
+ async (args, ctx) => {
17855
+ const workspace = ctx.workspaceMgr.get(args.workspaceId);
17856
+ if (!workspace) {
17857
+ throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
17858
+ }
17859
+ return readAgentInstructionsDocument(workspace.id, workspace.path);
17860
+ }
17861
+ );
17862
+ registerCommand(
17863
+ "agentInstructions.generate",
17864
+ z18.object({
17865
+ workspaceId: z18.string()
17866
+ }),
17867
+ async (args, ctx) => {
17868
+ const workspace = ctx.workspaceMgr.get(args.workspaceId);
17869
+ if (!workspace) {
17870
+ throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
17871
+ }
17872
+ const summary = await inspectWorkspaceIntelligence({
17873
+ workspaceId: workspace.id,
17874
+ rootPath: workspace.path
17875
+ });
17876
+ return {
17877
+ path: AGENT_INSTRUCTIONS_RELATIVE_PATH,
17878
+ exists: false,
17879
+ content: buildAgentInstructionsMarkdown(summary)
17880
+ };
17881
+ }
17882
+ );
17883
+ registerCommand(
17884
+ "agentInstructions.write",
17885
+ z18.object({
17886
+ workspaceId: z18.string(),
17887
+ content: z18.string(),
17888
+ overwrite: z18.boolean().optional(),
17889
+ baseHash: z18.string().optional()
16447
17890
  }),
16448
17891
  async (args, ctx) => {
16449
17892
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
16450
17893
  if (!workspace) {
16451
17894
  throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
16452
17895
  }
16453
- const result = await runGitNetworkOperation(
16454
- ctx,
16455
- args.workspaceId,
16456
- () => runGitPull(workspace.path, {
16457
- remote: args.remote,
16458
- branch: args.branch,
16459
- auth: args.auth
16460
- })
17896
+ const existing = await readAgentInstructionsDocument(workspace.id, workspace.path);
17897
+ if (existing.exists && !args.overwrite) {
17898
+ throw {
17899
+ code: "agent_instructions_exists",
17900
+ message: `${AGENT_INSTRUCTIONS_RELATIVE_PATH} already exists`
17901
+ };
17902
+ }
17903
+ const result = await writeFile(
17904
+ workspace.path,
17905
+ AGENT_INSTRUCTIONS_RELATIVE_PATH,
17906
+ args.content,
17907
+ args.baseHash
16461
17908
  );
16462
- ctx.workspaceMgr.recordFetch(args.workspaceId);
16463
- emitGitStateChanged(ctx, args.workspaceId, {
16464
- treeChanged: true,
16465
- branchChanged: true,
16466
- worktreeChanged: true
17909
+ ctx.eventBus.emit({
17910
+ type: "fs.dirty",
17911
+ workspaceId: args.workspaceId,
17912
+ reason: "file_content"
16467
17913
  });
16468
- return result;
17914
+ return {
17915
+ path: AGENT_INSTRUCTIONS_RELATIVE_PATH,
17916
+ exists: true,
17917
+ content: args.content,
17918
+ baseHash: result.newHash
17919
+ };
16469
17920
  }
16470
17921
  );
16471
17922
  registerCommand(
16472
- "git.fetch",
16473
- z14.object({
16474
- workspaceId: z14.string(),
16475
- remote: z14.string().optional(),
16476
- prune: z14.boolean().optional(),
16477
- auth: gitHttpAuthSchema.optional(),
16478
- background: z14.boolean().optional()
17923
+ "agentInstructions.health",
17924
+ z18.object({
17925
+ workspaceId: z18.string()
16479
17926
  }),
16480
- async (args, ctx, clientId) => {
17927
+ async (args, ctx) => {
16481
17928
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
16482
17929
  if (!workspace) {
16483
17930
  throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
16484
17931
  }
16485
- try {
16486
- const isInternalBackgroundFetch = args.background === true && !clientId;
16487
- const runFetch = () => runGitFetch(workspace.path, {
16488
- remote: args.remote,
16489
- prune: args.prune,
16490
- auth: args.auth,
16491
- timeoutMs: args.background ? GIT_BACKGROUND_FETCH_TIMEOUT_MS : void 0
16492
- });
16493
- const result = isInternalBackgroundFetch ? await runFetch() : await runGitNetworkOperation(ctx, args.workspaceId, runFetch);
16494
- ctx.workspaceMgr.recordFetch(args.workspaceId);
16495
- emitGitStateChanged(ctx, args.workspaceId, { branchChanged: true });
16496
- return result;
16497
- } catch (err) {
16498
- if (args.background && err instanceof GitAuthError) {
16499
- return { success: false, message: err.message, updatedRefs: [] };
16500
- }
16501
- throw err;
16502
- }
17932
+ const document = await readAgentInstructionsDocument(workspace.id, workspace.path);
17933
+ return evaluateAgentInstructionsMarkdown(document.content);
16503
17934
  }
16504
17935
  );
17936
+ }
17937
+ });
17938
+
17939
+ // packages/server/src/agent-context/context-package.ts
17940
+ import { randomUUID as randomUUID7 } from "node:crypto";
17941
+ import { readFile as readFile8 } from "node:fs/promises";
17942
+ function resolveOptions(options) {
17943
+ return {
17944
+ createId: options?.createId ?? randomUUID7,
17945
+ now: options?.now ?? Date.now
17946
+ };
17947
+ }
17948
+ function formatSource(source) {
17949
+ const parts = [`workspace=${source.workspaceId}`];
17950
+ if (source.sessionId) {
17951
+ parts.push(`session=${source.sessionId}`);
17952
+ }
17953
+ if (source.path) {
17954
+ parts.push(`path=${source.path}`);
17955
+ }
17956
+ if (source.terminalId) {
17957
+ parts.push(`terminal=${source.terminalId}`);
17958
+ }
17959
+ return parts.join(" ");
17960
+ }
17961
+ function wrapContext(title, source, body) {
17962
+ return `Context: ${title}
17963
+ Source: ${formatSource(source)}
17964
+
17965
+ ${body}`;
17966
+ }
17967
+ function createContextPackage(kind, title, source, body, options) {
17968
+ const resolved = resolveOptions(options);
17969
+ return {
17970
+ id: resolved.createId(),
17971
+ kind,
17972
+ title,
17973
+ body: wrapContext(title, source, body),
17974
+ source,
17975
+ createdAt: resolved.now()
17976
+ };
17977
+ }
17978
+ function requireSessionMetadata2(metadataRepo, sessionId) {
17979
+ const metadata = metadataRepo.get(sessionId);
17980
+ if (!metadata) {
17981
+ throw {
17982
+ code: "session_metadata_not_found",
17983
+ message: `Session metadata not found: ${sessionId}`
17984
+ };
17985
+ }
17986
+ return metadata;
17987
+ }
17988
+ function buildProjectSummaryBody(summary) {
17989
+ const lines = [
17990
+ `Git: ${summary.git.isRepo ? "repository detected" : "no repository detected"}`,
17991
+ `Package manager: ${summary.packageManager ?? "unknown"}`,
17992
+ `Frameworks: ${summary.frameworks.length > 0 ? summary.frameworks.join(", ") : "none"}`
17993
+ ];
17994
+ if (summary.recommendedCommands.length > 0) {
17995
+ lines.push("Recommended commands:");
17996
+ for (const command of summary.recommendedCommands) {
17997
+ lines.push(`- ${command.key}: ${command.command}`);
17998
+ }
17999
+ } else {
18000
+ lines.push("Recommended commands: none");
18001
+ }
18002
+ if (summary.docs.length > 0) {
18003
+ lines.push("Docs:");
18004
+ for (const doc of summary.docs) {
18005
+ lines.push(`- ${doc.path}`);
18006
+ }
18007
+ } else {
18008
+ lines.push("Docs: none");
18009
+ }
18010
+ lines.push(
18011
+ `Agent instructions: ${summary.agentInstructions.path} ${summary.agentInstructions.exists ? "present" : "missing"}`
18012
+ );
18013
+ return lines.join("\n");
18014
+ }
18015
+ async function buildFileContextPackage(input, options) {
18016
+ const content = await readFile8(resolveSafe(input.workspacePath, input.path), "utf8");
18017
+ return createContextPackage(
18018
+ "file",
18019
+ `File: ${input.path}`,
18020
+ {
18021
+ workspaceId: input.workspaceId,
18022
+ path: input.path
18023
+ },
18024
+ content,
18025
+ options
18026
+ );
18027
+ }
18028
+ async function buildDiffContextPackage(input, options) {
18029
+ const metadata = requireSessionMetadata2(input.metadataRepo, input.sessionId);
18030
+ const diff = await getSessionReviewDiff({
18031
+ sessionId: input.sessionId,
18032
+ workspacePath: input.workspacePath,
18033
+ metadataRepo: input.metadataRepo,
18034
+ path: input.path
18035
+ });
18036
+ return createContextPackage(
18037
+ "git_diff",
18038
+ `Git Diff: ${input.path}`,
18039
+ {
18040
+ workspaceId: metadata.workspaceId,
18041
+ sessionId: input.sessionId,
18042
+ path: input.path
18043
+ },
18044
+ diff,
18045
+ options
18046
+ );
18047
+ }
18048
+ async function buildProjectSummaryContextPackage(input, options) {
18049
+ const summary = await inspectWorkspaceIntelligence({
18050
+ workspaceId: input.workspaceId,
18051
+ rootPath: input.workspacePath
18052
+ });
18053
+ return createContextPackage(
18054
+ "project_summary",
18055
+ "Project Summary",
18056
+ {
18057
+ workspaceId: input.workspaceId
18058
+ },
18059
+ buildProjectSummaryBody(summary),
18060
+ options
18061
+ );
18062
+ }
18063
+ async function buildSessionReviewContextPackage(input, options) {
18064
+ const metadata = requireSessionMetadata2(input.metadataRepo, input.sessionId);
18065
+ const summary = await buildSessionReviewSummary({
18066
+ sessionId: input.sessionId,
18067
+ workspacePath: input.workspacePath,
18068
+ metadataRepo: input.metadataRepo
18069
+ });
18070
+ const lines = [
18071
+ `Baseline: ${summary.baselineGitHead ?? "missing"}`,
18072
+ "Changed files:",
18073
+ ...summary.changedFiles.length > 0 ? summary.changedFiles.map((change) => `- ${change.status ?? "modified"}: ${change.path}`) : ["- none"],
18074
+ "Verification runs:",
18075
+ ...summary.verificationRuns.length > 0 ? summary.verificationRuns.map((run) => `- ${run.status}: ${run.command}`) : ["- none"]
18076
+ ];
18077
+ if (summary.warnings.length > 0) {
18078
+ lines.push("Warnings:");
18079
+ for (const warning of summary.warnings) {
18080
+ lines.push(`- ${warning.code}: ${warning.message}`);
18081
+ }
18082
+ }
18083
+ return createContextPackage(
18084
+ "session_review",
18085
+ `Session Review: ${summary.sessionId}`,
18086
+ {
18087
+ workspaceId: metadata.workspaceId,
18088
+ sessionId: input.sessionId
18089
+ },
18090
+ lines.join("\n"),
18091
+ options
18092
+ );
18093
+ }
18094
+ var init_context_package = __esm({
18095
+ "packages/server/src/agent-context/context-package.ts"() {
18096
+ "use strict";
18097
+ init_file_io();
18098
+ init_review();
18099
+ init_intelligence();
18100
+ }
18101
+ });
18102
+
18103
+ // packages/server/src/commands/agent-context.ts
18104
+ import { z as z19 } from "zod";
18105
+ function requireWorkspace2(ctx, workspaceId) {
18106
+ const workspace = ctx.workspaceMgr.get(workspaceId);
18107
+ if (!workspace) {
18108
+ throw { code: "workspace_not_found", message: `Workspace not found: ${workspaceId}` };
18109
+ }
18110
+ return workspace;
18111
+ }
18112
+ function requireSessionMetadataRepo3(ctx) {
18113
+ if (!ctx.sessionMetadataRepo) {
18114
+ throw {
18115
+ code: "session_metadata_unavailable",
18116
+ message: "Session metadata repository is not configured"
18117
+ };
18118
+ }
18119
+ }
18120
+ function getSessionWorkspace(ctx, sessionId) {
18121
+ const metadata = ctx.sessionMetadataRepo.get(sessionId);
18122
+ if (!metadata) {
18123
+ throw {
18124
+ code: "session_metadata_not_found",
18125
+ message: `Session metadata not found: ${sessionId}`
18126
+ };
18127
+ }
18128
+ return {
18129
+ metadata,
18130
+ workspace: requireWorkspace2(ctx, metadata.workspaceId)
18131
+ };
18132
+ }
18133
+ var init_agent_context = __esm({
18134
+ "packages/server/src/commands/agent-context.ts"() {
18135
+ "use strict";
18136
+ init_context_package();
18137
+ init_dispatch();
16505
18138
  registerCommand(
16506
- "git.checkout",
16507
- z14.object({
16508
- workspaceId: z14.string(),
16509
- ref: z14.string(),
16510
- createBranch: z14.boolean().optional()
18139
+ "agentContext.fromFile",
18140
+ z19.object({
18141
+ workspaceId: z19.string(),
18142
+ path: z19.string().trim().min(1)
16511
18143
  }),
16512
18144
  async (args, ctx) => {
16513
- const workspace = ctx.workspaceMgr.get(args.workspaceId);
16514
- if (!workspace) {
16515
- throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
16516
- }
16517
- const result = await runGitCheckout(workspace.path, args.ref, {
16518
- createBranch: args.createBranch
18145
+ const workspace = requireWorkspace2(ctx, args.workspaceId);
18146
+ return buildFileContextPackage({
18147
+ workspaceId: workspace.id,
18148
+ workspacePath: workspace.path,
18149
+ path: args.path
16519
18150
  });
16520
- if (result.success) {
16521
- emitGitStateChanged(ctx, args.workspaceId, {
16522
- treeChanged: true,
16523
- branchChanged: true,
16524
- worktreeChanged: true
16525
- });
16526
- }
16527
- return result;
16528
18151
  }
16529
18152
  );
16530
18153
  registerCommand(
16531
- "git.branch",
16532
- z14.object({
16533
- workspaceId: z14.string(),
16534
- name: z14.string(),
16535
- startPoint: z14.string().optional()
18154
+ "agentContext.fromDiff",
18155
+ z19.object({
18156
+ sessionId: z19.string(),
18157
+ path: z19.string().trim().min(1)
16536
18158
  }),
16537
18159
  async (args, ctx) => {
16538
- const workspace = ctx.workspaceMgr.get(args.workspaceId);
16539
- if (!workspace) {
16540
- throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
16541
- }
16542
- const result = await runGitCreateBranch(workspace.path, args.name, {
16543
- startPoint: args.startPoint
18160
+ requireSessionMetadataRepo3(ctx);
18161
+ const { workspace } = getSessionWorkspace(ctx, args.sessionId);
18162
+ return buildDiffContextPackage({
18163
+ sessionId: args.sessionId,
18164
+ path: args.path,
18165
+ workspacePath: workspace.path,
18166
+ metadataRepo: ctx.sessionMetadataRepo
16544
18167
  });
16545
- emitGitStateChanged(ctx, args.workspaceId, {
16546
- branchChanged: true,
16547
- worktreeChanged: true
18168
+ }
18169
+ );
18170
+ registerCommand(
18171
+ "agentContext.fromProjectSummary",
18172
+ z19.object({
18173
+ workspaceId: z19.string()
18174
+ }),
18175
+ async (args, ctx) => {
18176
+ const workspace = requireWorkspace2(ctx, args.workspaceId);
18177
+ return buildProjectSummaryContextPackage({
18178
+ workspaceId: workspace.id,
18179
+ workspacePath: workspace.path
16548
18180
  });
16549
- return result;
16550
18181
  }
16551
18182
  );
16552
18183
  registerCommand(
16553
- "git.branches",
16554
- z14.object({
16555
- workspaceId: z14.string()
18184
+ "agentContext.fromSessionReview",
18185
+ z19.object({
18186
+ sessionId: z19.string()
16556
18187
  }),
16557
18188
  async (args, ctx) => {
16558
- const workspace = ctx.workspaceMgr.get(args.workspaceId);
16559
- if (!workspace) {
16560
- throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
16561
- }
16562
- return runGitListBranches(workspace.path);
18189
+ requireSessionMetadataRepo3(ctx);
18190
+ const { workspace } = getSessionWorkspace(ctx, args.sessionId);
18191
+ return buildSessionReviewContextPackage({
18192
+ sessionId: args.sessionId,
18193
+ workspacePath: workspace.path,
18194
+ metadataRepo: ctx.sessionMetadataRepo
18195
+ });
16563
18196
  }
16564
18197
  );
16565
18198
  }
@@ -16568,25 +18201,25 @@ var init_git2 = __esm({
16568
18201
  // packages/server/src/config/config-io.ts
16569
18202
  import { existsSync as existsSync9, mkdirSync as mkdirSync7, readFileSync as readFileSync7, renameSync as renameSync2, writeFileSync as writeFileSync5 } from "node:fs";
16570
18203
  import { homedir as homedir3 } from "node:os";
16571
- import { basename as basename3, dirname as dirname7, join as join14 } from "node:path";
18204
+ import { basename as basename3, dirname as dirname7, join as join17 } from "node:path";
16572
18205
  function resolveConfigPath(configType) {
16573
18206
  if (configType === "codex") {
16574
18207
  const testHome = process.env.CODER_STUDIO_CODEX_HOME;
16575
18208
  if (testHome && testHome.trim()) {
16576
- return join14(testHome, "config.toml");
18209
+ return join17(testHome, "config.toml");
16577
18210
  }
16578
18211
  const codexHome = process.env.CODEX_HOME;
16579
18212
  if (codexHome && codexHome.trim()) {
16580
- return join14(codexHome, "config.toml");
18213
+ return join17(codexHome, "config.toml");
16581
18214
  }
16582
- return join14(homedir3(), ".codex", "config.toml");
18215
+ return join17(homedir3(), ".codex", "config.toml");
16583
18216
  }
16584
18217
  if (configType === "claude") {
16585
18218
  const testHome = process.env.CODER_STUDIO_CLAUDE_HOME;
16586
18219
  if (testHome && testHome.trim()) {
16587
- return join14(testHome, "settings.json");
18220
+ return join17(testHome, "settings.json");
16588
18221
  }
16589
- return join14(homedir3(), ".claude", "settings.json");
18222
+ return join17(homedir3(), ".claude", "settings.json");
16590
18223
  }
16591
18224
  throw new Error(`Unknown config type: ${configType}`);
16592
18225
  }
@@ -16631,7 +18264,7 @@ function createBackup(filePath) {
16631
18264
  const base = basename3(filePath, `.${ext}`);
16632
18265
  const dir = dirname7(filePath);
16633
18266
  const ts = formatTimestamp(/* @__PURE__ */ new Date());
16634
- const backupPath = join14(dir, `${base}.bak.${ts}.${ext}`);
18267
+ const backupPath = join17(dir, `${base}.bak.${ts}.${ext}`);
16635
18268
  writeFileSync5(backupPath, original, "utf-8");
16636
18269
  return backupPath;
16637
18270
  }
@@ -16646,7 +18279,7 @@ var init_config_io = __esm({
16646
18279
  });
16647
18280
 
16648
18281
  // packages/server/src/commands/settings.ts
16649
- import { z as z15 } from "zod";
18282
+ import { z as z20 } from "zod";
16650
18283
  function flattenSettings(obj, prefix = "") {
16651
18284
  const result = {};
16652
18285
  for (const [key, value] of Object.entries(obj)) {
@@ -16697,13 +18330,13 @@ var init_settings2 = __esm({
16697
18330
  init_provider_config();
16698
18331
  init_settings();
16699
18332
  init_dispatch();
16700
- PersonalizationOverridesSchema = z15.object({
16701
- backgroundAssetId: z15.string().min(1).nullable().optional(),
16702
- backgroundDimness: z15.number().int().min(0).max(100).optional(),
16703
- backgroundBlur: z15.number().int().min(0).max(40).optional(),
16704
- glassEnabled: z15.boolean().optional(),
16705
- glassIntensity: z15.number().int().min(0).max(100).optional(),
16706
- surfaceOpacity: z15.number().int().min(0).max(100).optional()
18333
+ PersonalizationOverridesSchema = z20.object({
18334
+ backgroundAssetId: z20.string().min(1).nullable().optional(),
18335
+ backgroundDimness: z20.number().int().min(0).max(100).optional(),
18336
+ backgroundBlur: z20.number().int().min(0).max(40).optional(),
18337
+ glassEnabled: z20.boolean().optional(),
18338
+ glassIntensity: z20.number().int().min(0).max(100).optional(),
18339
+ surfaceOpacity: z20.number().int().min(0).max(100).optional()
16707
18340
  });
16708
18341
  PERSONALIZATION_OVERRIDE_BRANCHES = ["desktop", "mobile"];
16709
18342
  PERSONALIZATION_OVERRIDE_FIELDS = [
@@ -16714,59 +18347,59 @@ var init_settings2 = __esm({
16714
18347
  "glassIntensity",
16715
18348
  "surfaceOpacity"
16716
18349
  ];
16717
- SettingsSchema = z15.object({
16718
- defaultProviderId: z15.string().optional(),
16719
- notifications: z15.object({
16720
- enabled: z15.boolean().optional(),
16721
- soundEnabled: z15.boolean().optional(),
18350
+ SettingsSchema = z20.object({
18351
+ defaultProviderId: z20.string().optional(),
18352
+ notifications: z20.object({
18353
+ enabled: z20.boolean().optional(),
18354
+ soundEnabled: z20.boolean().optional(),
16722
18355
  // Legacy field — accepted for backward compat with older clients but
16723
18356
  // no longer surfaced in the UI. The web client now picks the channel
16724
18357
  // automatically based on workspace focus + page visibility.
16725
- onlyWhenBackgrounded: z15.boolean().optional()
18358
+ onlyWhenBackgrounded: z20.boolean().optional()
16726
18359
  }).optional(),
16727
- supervisor: z15.object({
16728
- evaluationTimeoutSec: z15.number().int().min(1).max(MAX_SUPERVISOR_EVALUATION_TIMEOUT_SEC).default(DEFAULT_SUPERVISOR_EVALUATION_TIMEOUT_SEC).optional(),
16729
- retryEnabled: z15.boolean().optional(),
16730
- retryMaxCount: z15.number().int().min(0).max(MAX_SUPERVISOR_RETRY_MAX_COUNT).optional(),
16731
- retryDelaySec: z15.number().int().min(1).max(MAX_SUPERVISOR_RETRY_DELAY_SEC).optional(),
16732
- retryOnTimeout: z15.boolean().optional(),
16733
- retryOnEvaluatorError: z15.boolean().optional()
18360
+ supervisor: z20.object({
18361
+ evaluationTimeoutSec: z20.number().int().min(1).max(MAX_SUPERVISOR_EVALUATION_TIMEOUT_SEC).default(DEFAULT_SUPERVISOR_EVALUATION_TIMEOUT_SEC).optional(),
18362
+ retryEnabled: z20.boolean().optional(),
18363
+ retryMaxCount: z20.number().int().min(0).max(MAX_SUPERVISOR_RETRY_MAX_COUNT).optional(),
18364
+ retryDelaySec: z20.number().int().min(1).max(MAX_SUPERVISOR_RETRY_DELAY_SEC).optional(),
18365
+ retryOnTimeout: z20.boolean().optional(),
18366
+ retryOnEvaluatorError: z20.boolean().optional()
16734
18367
  }).optional(),
16735
- appearance: z15.object({
16736
- theme: z15.enum(["dark", "light"]).optional(),
16737
- themeId: z15.string().optional(),
16738
- terminalRenderer: z15.enum(["standard", "compatibility"]).optional(),
16739
- terminalCopyOnSelect: z15.boolean().optional(),
16740
- terminalFontSize: z15.number().int().min(10).max(18).optional(),
16741
- desktopTerminalFontSize: z15.number().int().min(10).max(18).optional(),
16742
- mobileTerminalFontSize: z15.number().int().min(10).max(18).optional(),
16743
- locale: z15.enum(["zh", "en"]).optional(),
16744
- personalization: z15.object({
16745
- version: z15.literal(1).optional(),
16746
- common: z15.object({
16747
- backgroundMode: z15.enum(["none", "image"]).optional(),
16748
- backgroundAssetId: z15.string().min(1).nullable().optional(),
16749
- backgroundFit: z15.enum(["cover", "contain"]).optional(),
16750
- backgroundDimness: z15.number().int().min(0).max(100).optional(),
16751
- backgroundBlur: z15.number().int().min(0).max(40).optional(),
16752
- glassEnabled: z15.boolean().optional(),
16753
- glassIntensity: z15.number().int().min(0).max(100).optional(),
16754
- surfaceOpacity: z15.number().int().min(0).max(100).optional()
18368
+ appearance: z20.object({
18369
+ theme: z20.enum(["dark", "light"]).optional(),
18370
+ themeId: z20.string().optional(),
18371
+ terminalRenderer: z20.enum(["standard", "compatibility"]).optional(),
18372
+ terminalCopyOnSelect: z20.boolean().optional(),
18373
+ terminalFontSize: z20.number().int().min(10).max(18).optional(),
18374
+ desktopTerminalFontSize: z20.number().int().min(10).max(18).optional(),
18375
+ mobileTerminalFontSize: z20.number().int().min(10).max(18).optional(),
18376
+ locale: z20.enum(["zh", "en"]).optional(),
18377
+ personalization: z20.object({
18378
+ version: z20.literal(1).optional(),
18379
+ common: z20.object({
18380
+ backgroundMode: z20.enum(["none", "image"]).optional(),
18381
+ backgroundAssetId: z20.string().min(1).nullable().optional(),
18382
+ backgroundFit: z20.enum(["cover", "contain"]).optional(),
18383
+ backgroundDimness: z20.number().int().min(0).max(100).optional(),
18384
+ backgroundBlur: z20.number().int().min(0).max(40).optional(),
18385
+ glassEnabled: z20.boolean().optional(),
18386
+ glassIntensity: z20.number().int().min(0).max(100).optional(),
18387
+ surfaceOpacity: z20.number().int().min(0).max(100).optional()
16755
18388
  }).optional(),
16756
18389
  desktop: PersonalizationOverridesSchema.optional(),
16757
18390
  mobile: PersonalizationOverridesSchema.optional()
16758
18391
  }).optional()
16759
18392
  }).optional(),
16760
- lsp: z15.object({
16761
- mode: z15.enum(["auto", "off"]).optional()
18393
+ lsp: z20.object({
18394
+ mode: z20.enum(["auto", "off"]).optional()
16762
18395
  }).optional(),
16763
- updates: z15.object({
16764
- autoCheckEnabled: z15.boolean().optional(),
16765
- checkIntervalSec: z15.number().int().refine(isUpdateCheckIntervalSec).optional()
18396
+ updates: z20.object({
18397
+ autoCheckEnabled: z20.boolean().optional(),
18398
+ checkIntervalSec: z20.number().int().refine(isUpdateCheckIntervalSec).optional()
16766
18399
  }).optional(),
16767
18400
  providers: ProviderSettingsSchema.optional()
16768
18401
  });
16769
- registerCommand("settings.get", z15.object({}), async (_args, ctx) => {
18402
+ registerCommand("settings.get", z20.object({}), async (_args, ctx) => {
16770
18403
  const settings = {};
16771
18404
  for (const [key, value] of Object.entries(ctx.settingsRepo.getAll())) {
16772
18405
  if (key.startsWith("providers.")) {
@@ -16818,7 +18451,7 @@ var init_settings2 = __esm({
16818
18451
  });
16819
18452
  registerCommand(
16820
18453
  "settings.update",
16821
- z15.object({
18454
+ z20.object({
16822
18455
  settings: SettingsSchema
16823
18456
  }),
16824
18457
  async (args, ctx) => {
@@ -16851,10 +18484,10 @@ var init_settings2 = __esm({
16851
18484
  );
16852
18485
  registerCommand(
16853
18486
  "settings.previewCommand",
16854
- z15.object({
16855
- providerId: z15.string(),
18487
+ z20.object({
18488
+ providerId: z20.string(),
16856
18489
  config: ProviderLaunchConfigInputSchema,
16857
- workspacePath: z15.string().optional()
18490
+ workspacePath: z20.string().optional()
16858
18491
  }),
16859
18492
  async (args, ctx) => {
16860
18493
  const provider = ctx.providerRegistry.find((item) => item.id === args.providerId);
@@ -16875,8 +18508,8 @@ var init_settings2 = __esm({
16875
18508
  );
16876
18509
  registerCommand(
16877
18510
  "settings.readConfigFile",
16878
- z15.object({
16879
- configType: z15.enum(["codex", "claude"])
18511
+ z20.object({
18512
+ configType: z20.enum(["codex", "claude"])
16880
18513
  }),
16881
18514
  async (args) => {
16882
18515
  const result = readConfigFile(args.configType);
@@ -16885,9 +18518,9 @@ var init_settings2 = __esm({
16885
18518
  );
16886
18519
  registerCommand(
16887
18520
  "settings.writeConfigFile",
16888
- z15.object({
16889
- configType: z15.enum(["codex", "claude"]),
16890
- content: z15.string()
18521
+ z20.object({
18522
+ configType: z20.enum(["codex", "claude"]),
18523
+ content: z20.string()
16891
18524
  }),
16892
18525
  async (args) => {
16893
18526
  const result = writeConfigFile(args.configType, args.content);
@@ -16898,7 +18531,7 @@ var init_settings2 = __esm({
16898
18531
  });
16899
18532
 
16900
18533
  // packages/server/src/commands/diagnostics.ts
16901
- import { z as z16 } from "zod";
18534
+ import { z as z21 } from "zod";
16902
18535
  function isLoopbackHost(host) {
16903
18536
  return host === void 0 || host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "0.0.0.0";
16904
18537
  }
@@ -17268,11 +18901,11 @@ var init_diagnostics2 = __esm({
17268
18901
  init_runtime_status();
17269
18902
  init_validator();
17270
18903
  init_dispatch();
17271
- DiagnosticsRequestSchema = z16.object({
17272
- context: z16.enum(["workspace_open", "session_start", "mobile_continue", "manual_check"]),
17273
- workspaceId: z16.string().optional(),
17274
- workspacePath: z16.string().optional(),
17275
- providerId: z16.string().optional()
18904
+ DiagnosticsRequestSchema = z21.object({
18905
+ context: z21.enum(["workspace_open", "session_start", "mobile_continue", "manual_check"]),
18906
+ workspaceId: z21.string().optional(),
18907
+ workspacePath: z21.string().optional(),
18908
+ providerId: z21.string().optional()
17276
18909
  });
17277
18910
  registerCommand("diagnostics.get", DiagnosticsRequestSchema, async (args, ctx) => {
17278
18911
  return buildDiagnostics(args, ctx);
@@ -17284,19 +18917,23 @@ var init_diagnostics2 = __esm({
17284
18917
  });
17285
18918
 
17286
18919
  // packages/server/src/commands/provider.ts
17287
- import { z as z17 } from "zod";
18920
+ import { z as z22 } from "zod";
17288
18921
  var init_provider = __esm({
17289
18922
  "packages/server/src/commands/provider.ts"() {
17290
18923
  "use strict";
18924
+ init_src();
17291
18925
  init_runtime_status();
17292
18926
  init_dispatch();
17293
- registerCommand("provider.runtimeStatus", z17.object({}), async (_args, ctx) => {
18927
+ registerCommand("provider.list", z22.object({}), async (_args, ctx) => {
18928
+ return ctx.providerRegistry.map((provider) => toProviderListItem(provider));
18929
+ });
18930
+ registerCommand("provider.runtimeStatus", z22.object({}), async (_args, ctx) => {
17294
18931
  return buildProviderRuntimeStatus(ctx.providerRegistry, ctx.providerRuntimeDeps);
17295
18932
  });
17296
18933
  registerCommand(
17297
18934
  "provider.install.start",
17298
- z17.object({
17299
- providerId: z17.string()
18935
+ z22.object({
18936
+ providerId: z22.string()
17300
18937
  }),
17301
18938
  async (args, ctx) => {
17302
18939
  if (!ctx.providerInstallMgr) {
@@ -17310,8 +18947,8 @@ var init_provider = __esm({
17310
18947
  );
17311
18948
  registerCommand(
17312
18949
  "provider.install.get",
17313
- z17.object({
17314
- jobId: z17.string()
18950
+ z22.object({
18951
+ jobId: z22.string()
17315
18952
  }),
17316
18953
  async (args, ctx) => {
17317
18954
  if (!ctx.providerInstallMgr) {
@@ -17333,45 +18970,147 @@ var init_provider = __esm({
17333
18970
  }
17334
18971
  });
17335
18972
 
18973
+ // packages/server/src/commands/custom-provider.ts
18974
+ import { z as z23 } from "zod";
18975
+ function requireCustomProviderSupport(ctx) {
18976
+ if (!ctx.customProviderRepo || !ctx.setProviderRegistry) {
18977
+ throw {
18978
+ code: "custom_provider_unavailable",
18979
+ message: "Custom provider runtime is not configured"
18980
+ };
18981
+ }
18982
+ }
18983
+ function materializeConfig(input, previous) {
18984
+ const now = Date.now();
18985
+ return {
18986
+ ...input,
18987
+ startupPrompt: input.startupPrompt?.trim() || void 0,
18988
+ createdAt: previous?.createdAt ?? now,
18989
+ updatedAt: now
18990
+ };
18991
+ }
18992
+ var CapabilitySchema, BaseCustomProviderInputSchema;
18993
+ var init_custom_provider2 = __esm({
18994
+ "packages/server/src/commands/custom-provider.ts"() {
18995
+ "use strict";
18996
+ init_src();
18997
+ init_custom_provider();
18998
+ init_dispatch();
18999
+ CapabilitySchema = z23.object({
19000
+ key: z23.enum([
19001
+ "interactive_session",
19002
+ "supervisor_eval",
19003
+ "idle_detection",
19004
+ "context_attach",
19005
+ "review"
19006
+ ]),
19007
+ supported: z23.boolean(),
19008
+ label: z23.string().min(1)
19009
+ });
19010
+ BaseCustomProviderInputSchema = z23.object({
19011
+ id: z23.string().trim().min(1).regex(/^[a-z0-9][a-z0-9-_]*$/),
19012
+ displayName: z23.string().trim().min(1),
19013
+ command: z23.string().trim().min(1),
19014
+ args: z23.array(z23.string()),
19015
+ env: z23.record(z23.string(), z23.string()),
19016
+ cwdMode: z23.literal("workspace_root"),
19017
+ sessionMode: z23.literal("interactive"),
19018
+ startupPrompt: z23.string().optional(),
19019
+ capabilities: z23.array(CapabilitySchema).min(1)
19020
+ });
19021
+ registerCommand("customProvider.list", z23.object({}), async (_args, ctx) => {
19022
+ requireCustomProviderSupport(ctx);
19023
+ return ctx.customProviderRepo.list().map((config) => toProviderListItem(buildCustomProviderDefinition(config)));
19024
+ });
19025
+ registerCommand("customProvider.create", BaseCustomProviderInputSchema, async (args, ctx) => {
19026
+ requireCustomProviderSupport(ctx);
19027
+ if (ctx.providerRegistry.some((provider) => provider.id === args.id)) {
19028
+ throw {
19029
+ code: "custom_provider_exists",
19030
+ message: `Provider already exists: ${args.id}`
19031
+ };
19032
+ }
19033
+ const config = materializeConfig(args);
19034
+ const saved = ctx.customProviderRepo.set(config);
19035
+ const definition = buildCustomProviderDefinition(saved);
19036
+ ctx.setProviderRegistry(upsertProviderDefinition(ctx.providerRegistry, definition));
19037
+ return toProviderListItem(definition);
19038
+ });
19039
+ registerCommand("customProvider.update", BaseCustomProviderInputSchema, async (args, ctx) => {
19040
+ requireCustomProviderSupport(ctx);
19041
+ const existing = ctx.customProviderRepo.get(args.id);
19042
+ if (!existing) {
19043
+ throw {
19044
+ code: "custom_provider_not_found",
19045
+ message: `Custom provider not found: ${args.id}`
19046
+ };
19047
+ }
19048
+ const saved = ctx.customProviderRepo.set(materializeConfig(args, existing));
19049
+ const definition = buildCustomProviderDefinition(saved);
19050
+ ctx.setProviderRegistry(upsertProviderDefinition(ctx.providerRegistry, definition));
19051
+ return toProviderListItem(definition);
19052
+ });
19053
+ registerCommand(
19054
+ "customProvider.delete",
19055
+ z23.object({
19056
+ id: z23.string().trim().min(1)
19057
+ }),
19058
+ async (args, ctx) => {
19059
+ requireCustomProviderSupport(ctx);
19060
+ const existing = ctx.customProviderRepo.get(args.id);
19061
+ if (!existing) {
19062
+ throw {
19063
+ code: "custom_provider_not_found",
19064
+ message: `Custom provider not found: ${args.id}`
19065
+ };
19066
+ }
19067
+ ctx.customProviderRepo.delete(args.id);
19068
+ ctx.setProviderRegistry(removeProviderDefinition(ctx.providerRegistry, args.id));
19069
+ return { deleted: true, id: args.id };
19070
+ }
19071
+ );
19072
+ }
19073
+ });
19074
+
17336
19075
  // packages/server/src/commands/supervisor.ts
17337
- import { z as z18 } from "zod";
19076
+ import { z as z24 } from "zod";
17338
19077
  var supervisorObjectiveSchema, createSupervisorSchema, updateSupervisorSchema, sessionIdSchema, workspaceIdSchema, supervisorIdSchema, restoreSupervisorSchema;
17339
19078
  var init_supervisor2 = __esm({
17340
19079
  "packages/server/src/commands/supervisor.ts"() {
17341
19080
  "use strict";
17342
19081
  init_dispatch();
17343
- supervisorObjectiveSchema = z18.string().trim().min(1).max(4e3);
17344
- createSupervisorSchema = z18.object({
17345
- sessionId: z18.string(),
17346
- workspaceId: z18.string(),
19082
+ supervisorObjectiveSchema = z24.string().trim().min(1).max(4e3);
19083
+ createSupervisorSchema = z24.object({
19084
+ sessionId: z24.string(),
19085
+ workspaceId: z24.string(),
17347
19086
  objective: supervisorObjectiveSchema,
17348
- evaluatorProviderId: z18.string(),
17349
- evaluatorModel: z18.string().trim().min(1).max(200).optional(),
17350
- maxSupervisionCount: z18.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional(),
17351
- scheduledAt: z18.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional()
19087
+ evaluatorProviderId: z24.string(),
19088
+ evaluatorModel: z24.string().trim().min(1).max(200).optional(),
19089
+ maxSupervisionCount: z24.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional(),
19090
+ scheduledAt: z24.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional()
17352
19091
  }).strict();
17353
- updateSupervisorSchema = z18.object({
17354
- id: z18.string(),
19092
+ updateSupervisorSchema = z24.object({
19093
+ id: z24.string(),
17355
19094
  objective: supervisorObjectiveSchema.optional(),
17356
- evaluatorProviderId: z18.string().optional(),
17357
- evaluatorModel: z18.string().trim().min(1).max(200).nullable().optional(),
17358
- maxSupervisionCount: z18.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional(),
17359
- scheduledAt: z18.number().int().min(0).max(Number.MAX_SAFE_INTEGER).nullable().optional()
19095
+ evaluatorProviderId: z24.string().optional(),
19096
+ evaluatorModel: z24.string().trim().min(1).max(200).nullable().optional(),
19097
+ maxSupervisionCount: z24.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional(),
19098
+ scheduledAt: z24.number().int().min(0).max(Number.MAX_SAFE_INTEGER).nullable().optional()
17360
19099
  }).strict().refine(
17361
19100
  (input) => input.objective !== void 0 || input.evaluatorProviderId !== void 0 || input.evaluatorModel !== void 0 || input.maxSupervisionCount !== void 0 || input.scheduledAt !== void 0,
17362
19101
  "at least one supervisor field is required"
17363
19102
  );
17364
- sessionIdSchema = z18.object({ sessionId: z18.string() });
17365
- workspaceIdSchema = z18.object({ workspaceId: z18.string() });
17366
- supervisorIdSchema = z18.object({ id: z18.string() });
17367
- restoreSupervisorSchema = z18.object({
17368
- sessionId: z18.string(),
17369
- workspaceId: z18.string(),
17370
- sourceTargetId: z18.string(),
17371
- evaluatorProviderId: z18.string(),
17372
- evaluatorModel: z18.string().trim().min(1).max(200).optional(),
17373
- maxSupervisionCount: z18.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional(),
17374
- scheduledAt: z18.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional()
19103
+ sessionIdSchema = z24.object({ sessionId: z24.string() });
19104
+ workspaceIdSchema = z24.object({ workspaceId: z24.string() });
19105
+ supervisorIdSchema = z24.object({ id: z24.string() });
19106
+ restoreSupervisorSchema = z24.object({
19107
+ sessionId: z24.string(),
19108
+ workspaceId: z24.string(),
19109
+ sourceTargetId: z24.string(),
19110
+ evaluatorProviderId: z24.string(),
19111
+ evaluatorModel: z24.string().trim().min(1).max(200).optional(),
19112
+ maxSupervisionCount: z24.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional(),
19113
+ scheduledAt: z24.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional()
17375
19114
  }).strict();
17376
19115
  registerCommand("supervisor.create", createSupervisorSchema, async (args, ctx) => {
17377
19116
  return {
@@ -17573,7 +19312,7 @@ var init_worktree = __esm({
17573
19312
 
17574
19313
  // packages/server/src/commands/worktree.ts
17575
19314
  import path13 from "node:path";
17576
- import { z as z19 } from "zod";
19315
+ import { z as z25 } from "zod";
17577
19316
  async function findRelatedWorkspaceIds(ctx, workspacePath) {
17578
19317
  const targetCommonDir = await getGitCommonDirPath(workspacePath);
17579
19318
  const relatedWorkspaceIds = await Promise.all(
@@ -17606,7 +19345,7 @@ var init_worktree2 = __esm({
17606
19345
  init_worktree();
17607
19346
  init_dispatch();
17608
19347
  init_git_events();
17609
- registerCommand("worktree.list", z19.object({ workspaceId: z19.string() }), async (args, ctx) => {
19348
+ registerCommand("worktree.list", z25.object({ workspaceId: z25.string() }), async (args, ctx) => {
17610
19349
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
17611
19350
  if (!workspace) {
17612
19351
  throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
@@ -17615,7 +19354,7 @@ var init_worktree2 = __esm({
17615
19354
  });
17616
19355
  registerCommand(
17617
19356
  "worktree.status",
17618
- z19.object({ workspaceId: z19.string(), worktreePath: z19.string() }),
19357
+ z25.object({ workspaceId: z25.string(), worktreePath: z25.string() }),
17619
19358
  async (args, ctx) => {
17620
19359
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
17621
19360
  if (!workspace) {
@@ -17627,10 +19366,10 @@ var init_worktree2 = __esm({
17627
19366
  );
17628
19367
  registerCommand(
17629
19368
  "worktree.diff",
17630
- z19.object({
17631
- workspaceId: z19.string(),
17632
- worktreePath: z19.string(),
17633
- staged: z19.boolean().optional().default(false)
19369
+ z25.object({
19370
+ workspaceId: z25.string(),
19371
+ worktreePath: z25.string(),
19372
+ staged: z25.boolean().optional().default(false)
17634
19373
  }),
17635
19374
  async (args, ctx) => {
17636
19375
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -17643,7 +19382,7 @@ var init_worktree2 = __esm({
17643
19382
  );
17644
19383
  registerCommand(
17645
19384
  "worktree.tree",
17646
- z19.object({ workspaceId: z19.string(), worktreePath: z19.string() }),
19385
+ z25.object({ workspaceId: z25.string(), worktreePath: z25.string() }),
17647
19386
  async (args, ctx) => {
17648
19387
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
17649
19388
  if (!workspace) {
@@ -17655,10 +19394,10 @@ var init_worktree2 = __esm({
17655
19394
  );
17656
19395
  registerCommand(
17657
19396
  "worktree.create",
17658
- z19.object({
17659
- workspaceId: z19.string(),
17660
- branch: z19.string(),
17661
- path: z19.string()
19397
+ z25.object({
19398
+ workspaceId: z25.string(),
19399
+ branch: z25.string(),
19400
+ path: z25.string()
17662
19401
  }),
17663
19402
  async (args, ctx) => {
17664
19403
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -17673,10 +19412,10 @@ var init_worktree2 = __esm({
17673
19412
  );
17674
19413
  registerCommand(
17675
19414
  "worktree.remove",
17676
- z19.object({
17677
- workspaceId: z19.string(),
17678
- worktreePath: z19.string(),
17679
- force: z19.boolean().optional().default(false)
19415
+ z25.object({
19416
+ workspaceId: z25.string(),
19417
+ worktreePath: z25.string(),
19418
+ force: z25.boolean().optional().default(false)
17680
19419
  }),
17681
19420
  async (args, ctx) => {
17682
19421
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -17700,7 +19439,7 @@ var init_worktree2 = __esm({
17700
19439
  });
17701
19440
 
17702
19441
  // packages/server/src/commands/fencing.ts
17703
- import { z as z20 } from "zod";
19442
+ import { z as z26 } from "zod";
17704
19443
  function createMockFencingRequest() {
17705
19444
  return {
17706
19445
  ip: "127.0.0.1",
@@ -17713,9 +19452,9 @@ var init_fencing2 = __esm({
17713
19452
  init_dispatch();
17714
19453
  registerCommand(
17715
19454
  "fencing.request",
17716
- z20.object({
17717
- workspaceId: z20.string(),
17718
- tabId: z20.string()
19455
+ z26.object({
19456
+ workspaceId: z26.string(),
19457
+ tabId: z26.string()
17719
19458
  }),
17720
19459
  async (args, ctx, clientId) => {
17721
19460
  return ctx.fencingMgr.requestControl(
@@ -17728,7 +19467,7 @@ var init_fencing2 = __esm({
17728
19467
  );
17729
19468
  registerCommand(
17730
19469
  "fencing.heartbeat",
17731
- z20.object({ workspaceId: z20.string() }),
19470
+ z26.object({ workspaceId: z26.string() }),
17732
19471
  async (args, ctx, clientId) => {
17733
19472
  const success = ctx.fencingMgr.heartbeat(args.workspaceId, clientId);
17734
19473
  return { success };
@@ -17736,13 +19475,13 @@ var init_fencing2 = __esm({
17736
19475
  );
17737
19476
  registerCommand(
17738
19477
  "fencing.release",
17739
- z20.object({ workspaceId: z20.string() }),
19478
+ z26.object({ workspaceId: z26.string() }),
17740
19479
  async (args, ctx, clientId) => {
17741
19480
  ctx.fencingMgr.release(args.workspaceId, clientId);
17742
19481
  return {};
17743
19482
  }
17744
19483
  );
17745
- registerCommand("fencing.status", z20.object({ workspaceId: z20.string() }), async (args, ctx) => {
19484
+ registerCommand("fencing.status", z26.object({ workspaceId: z26.string() }), async (args, ctx) => {
17746
19485
  const controller = ctx.fencingMgr.getController(args.workspaceId);
17747
19486
  const isUnresponsive = ctx.fencingMgr.isControllerUnresponsive(args.workspaceId);
17748
19487
  return {
@@ -17753,9 +19492,9 @@ var init_fencing2 = __esm({
17753
19492
  });
17754
19493
  registerCommand(
17755
19494
  "fencing.takeover",
17756
- z20.object({
17757
- workspaceId: z20.string(),
17758
- tabId: z20.string()
19495
+ z26.object({
19496
+ workspaceId: z26.string(),
19497
+ tabId: z26.string()
17759
19498
  }),
17760
19499
  async (args, ctx, clientId) => {
17761
19500
  return ctx.fencingMgr.forceTakeover(
@@ -17793,7 +19532,7 @@ var init_runtime_status2 = __esm({
17793
19532
  });
17794
19533
 
17795
19534
  // packages/server/src/commands/lsp.ts
17796
- import { z as z21 } from "zod";
19535
+ import { z as z27 } from "zod";
17797
19536
  var init_lsp2 = __esm({
17798
19537
  "packages/server/src/commands/lsp.ts"() {
17799
19538
  "use strict";
@@ -17801,16 +19540,16 @@ var init_lsp2 = __esm({
17801
19540
  init_dispatch();
17802
19541
  registerCommand(
17803
19542
  "lsp.ensureSession",
17804
- z21.object({
17805
- workspaceId: z21.string(),
17806
- path: z21.string()
19543
+ z27.object({
19544
+ workspaceId: z27.string(),
19545
+ path: z27.string()
17807
19546
  }),
17808
19547
  async (args, ctx) => ctx.lspMgr.ensureSession(args)
17809
19548
  );
17810
19549
  registerCommand(
17811
19550
  "lsp.setMode",
17812
- z21.object({
17813
- mode: z21.enum(["auto", "off"])
19551
+ z27.object({
19552
+ mode: z27.enum(["auto", "off"])
17814
19553
  }),
17815
19554
  async (args, ctx) => {
17816
19555
  await ctx.lspMgr.setRuntimeMode(args.mode);
@@ -17819,8 +19558,8 @@ var init_lsp2 = __esm({
17819
19558
  );
17820
19559
  registerCommand(
17821
19560
  "lsp.runtimeStatus",
17822
- z21.object({
17823
- workspaceId: z21.string()
19561
+ z27.object({
19562
+ workspaceId: z27.string()
17824
19563
  }),
17825
19564
  async (args, ctx) => {
17826
19565
  if (!ctx.lspToolMgr) {
@@ -17844,9 +19583,9 @@ var init_lsp2 = __esm({
17844
19583
  );
17845
19584
  registerCommand(
17846
19585
  "lsp.install.start",
17847
- z21.object({
17848
- workspaceId: z21.string(),
17849
- serverKind: z21.enum(["typescript", "python", "go", "rust"])
19586
+ z27.object({
19587
+ workspaceId: z27.string(),
19588
+ serverKind: z27.enum(["typescript", "python", "go", "rust"])
17850
19589
  }),
17851
19590
  async (args, ctx) => {
17852
19591
  if (!ctx.lspToolInstallMgr) {
@@ -17870,8 +19609,8 @@ var init_lsp2 = __esm({
17870
19609
  );
17871
19610
  registerCommand(
17872
19611
  "lsp.install.get",
17873
- z21.object({
17874
- jobId: z21.string()
19612
+ z27.object({
19613
+ jobId: z27.string()
17875
19614
  }),
17876
19615
  async (args, ctx) => {
17877
19616
  if (!ctx.lspToolInstallMgr) {
@@ -17892,86 +19631,86 @@ var init_lsp2 = __esm({
17892
19631
  );
17893
19632
  registerCommand(
17894
19633
  "lsp.openDocument",
17895
- z21.object({
17896
- workspaceId: z21.string(),
17897
- path: z21.string(),
17898
- languageId: z21.string(),
17899
- text: z21.string()
19634
+ z27.object({
19635
+ workspaceId: z27.string(),
19636
+ path: z27.string(),
19637
+ languageId: z27.string(),
19638
+ text: z27.string()
17900
19639
  }),
17901
19640
  async (args, ctx) => ctx.lspMgr.openDocument(args)
17902
19641
  );
17903
19642
  registerCommand(
17904
19643
  "lsp.changeDocument",
17905
- z21.object({
17906
- workspaceId: z21.string(),
17907
- path: z21.string(),
17908
- text: z21.string()
19644
+ z27.object({
19645
+ workspaceId: z27.string(),
19646
+ path: z27.string(),
19647
+ text: z27.string()
17909
19648
  }),
17910
19649
  async (args, ctx) => ctx.lspMgr.changeDocument(args)
17911
19650
  );
17912
19651
  registerCommand(
17913
19652
  "lsp.closeDocument",
17914
- z21.object({
17915
- workspaceId: z21.string(),
17916
- path: z21.string()
19653
+ z27.object({
19654
+ workspaceId: z27.string(),
19655
+ path: z27.string()
17917
19656
  }),
17918
19657
  async (args, ctx) => ctx.lspMgr.closeDocument(args)
17919
19658
  );
17920
19659
  registerCommand(
17921
19660
  "lsp.definition",
17922
- z21.object({
17923
- workspaceId: z21.string(),
17924
- path: z21.string(),
17925
- line: z21.number().int().positive(),
17926
- column: z21.number().int().positive()
19661
+ z27.object({
19662
+ workspaceId: z27.string(),
19663
+ path: z27.string(),
19664
+ line: z27.number().int().positive(),
19665
+ column: z27.number().int().positive()
17927
19666
  }),
17928
19667
  async (args, ctx) => ctx.lspMgr.definition(args)
17929
19668
  );
17930
19669
  registerCommand(
17931
19670
  "lsp.declaration",
17932
- z21.object({
17933
- workspaceId: z21.string(),
17934
- path: z21.string(),
17935
- line: z21.number().int().positive(),
17936
- column: z21.number().int().positive()
19671
+ z27.object({
19672
+ workspaceId: z27.string(),
19673
+ path: z27.string(),
19674
+ line: z27.number().int().positive(),
19675
+ column: z27.number().int().positive()
17937
19676
  }),
17938
19677
  async (args, ctx) => ctx.lspMgr.declaration(args)
17939
19678
  );
17940
19679
  registerCommand(
17941
19680
  "lsp.typeDefinition",
17942
- z21.object({
17943
- workspaceId: z21.string(),
17944
- path: z21.string(),
17945
- line: z21.number().int().positive(),
17946
- column: z21.number().int().positive()
19681
+ z27.object({
19682
+ workspaceId: z27.string(),
19683
+ path: z27.string(),
19684
+ line: z27.number().int().positive(),
19685
+ column: z27.number().int().positive()
17947
19686
  }),
17948
19687
  async (args, ctx) => ctx.lspMgr.typeDefinition(args)
17949
19688
  );
17950
19689
  registerCommand(
17951
19690
  "lsp.references",
17952
- z21.object({
17953
- workspaceId: z21.string(),
17954
- path: z21.string(),
17955
- line: z21.number().int().positive(),
17956
- column: z21.number().int().positive()
19691
+ z27.object({
19692
+ workspaceId: z27.string(),
19693
+ path: z27.string(),
19694
+ line: z27.number().int().positive(),
19695
+ column: z27.number().int().positive()
17957
19696
  }),
17958
19697
  async (args, ctx) => ctx.lspMgr.references(args)
17959
19698
  );
17960
19699
  registerCommand(
17961
19700
  "lsp.hover",
17962
- z21.object({
17963
- workspaceId: z21.string(),
17964
- path: z21.string(),
17965
- line: z21.number().int().positive(),
17966
- column: z21.number().int().positive()
19701
+ z27.object({
19702
+ workspaceId: z27.string(),
19703
+ path: z27.string(),
19704
+ line: z27.number().int().positive(),
19705
+ column: z27.number().int().positive()
17967
19706
  }),
17968
19707
  async (args, ctx) => ctx.lspMgr.hover(args)
17969
19708
  );
17970
19709
  registerCommand(
17971
19710
  "lsp.documentSymbols",
17972
- z21.object({
17973
- workspaceId: z21.string(),
17974
- path: z21.string()
19711
+ z27.object({
19712
+ workspaceId: z27.string(),
19713
+ path: z27.string()
17975
19714
  }),
17976
19715
  async (args, ctx) => ctx.lspMgr.documentSymbols(args)
17977
19716
  );
@@ -17979,12 +19718,12 @@ var init_lsp2 = __esm({
17979
19718
  });
17980
19719
 
17981
19720
  // packages/server/src/commands/updates.ts
17982
- import { z as z22 } from "zod";
19721
+ import { z as z28 } from "zod";
17983
19722
  var init_updates = __esm({
17984
19723
  "packages/server/src/commands/updates.ts"() {
17985
19724
  "use strict";
17986
19725
  init_dispatch();
17987
- registerCommand("updates.getState", z22.object({}).default({}), async (_args, ctx) => {
19726
+ registerCommand("updates.getState", z28.object({}).default({}), async (_args, ctx) => {
17988
19727
  if (!ctx.updateService) {
17989
19728
  throw {
17990
19729
  code: "update_unavailable",
@@ -17993,7 +19732,7 @@ var init_updates = __esm({
17993
19732
  }
17994
19733
  return ctx.updateService.getStateView();
17995
19734
  });
17996
- registerCommand("updates.check", z22.object({}).default({}), async (_args, ctx) => {
19735
+ registerCommand("updates.check", z28.object({}).default({}), async (_args, ctx) => {
17997
19736
  if (!ctx.updateService) {
17998
19737
  throw {
17999
19738
  code: "update_unavailable",
@@ -18002,7 +19741,7 @@ var init_updates = __esm({
18002
19741
  }
18003
19742
  return await ctx.updateService.checkForUpdates({ manual: true });
18004
19743
  });
18005
- registerCommand("updates.prepareInstall", z22.object({}).default({}), async (_args, ctx) => {
19744
+ registerCommand("updates.prepareInstall", z28.object({}).default({}), async (_args, ctx) => {
18006
19745
  if (!ctx.updateService) {
18007
19746
  throw {
18008
19747
  code: "update_unavailable",
@@ -18013,9 +19752,9 @@ var init_updates = __esm({
18013
19752
  });
18014
19753
  registerCommand(
18015
19754
  "updates.startInstall",
18016
- z22.object({
18017
- targetVersion: z22.string().optional(),
18018
- force: z22.boolean().optional()
19755
+ z28.object({
19756
+ targetVersion: z28.string().optional(),
19757
+ force: z28.boolean().optional()
18019
19758
  }),
18020
19759
  async (args, ctx) => {
18021
19760
  if (!ctx.updateService) {
@@ -18040,12 +19779,17 @@ var init_commands = __esm({
18040
19779
  init_connection();
18041
19780
  init_recovery();
18042
19781
  init_session2();
19782
+ init_session_metadata();
19783
+ init_session_review();
18043
19784
  init_terminal();
18044
19785
  init_file();
18045
19786
  init_git2();
19787
+ init_agent_instructions();
19788
+ init_agent_context();
18046
19789
  init_settings2();
18047
19790
  init_diagnostics2();
18048
19791
  init_provider();
19792
+ init_custom_provider2();
18049
19793
  init_supervisor2();
18050
19794
  init_worktree2();
18051
19795
  init_fencing2();
@@ -18057,12 +19801,12 @@ var init_commands = __esm({
18057
19801
  // packages/server/src/server.ts
18058
19802
  import { mkdtempSync, rmSync as rmSync2 } from "node:fs";
18059
19803
  import { tmpdir } from "node:os";
18060
- import { join as join15 } from "node:path";
19804
+ import { join as join18 } from "node:path";
18061
19805
  async function createServer(configOverrides) {
18062
19806
  const config = parseServerConfig(configOverrides);
18063
19807
  const configuredStateDir = resolveConfiguredStateDir(config);
18064
19808
  const shouldCleanupStateRoot = configuredStateDir === IN_MEMORY_STATE_DIR;
18065
- const stateRoot = shouldCleanupStateRoot ? mkdtempSync(join15(tmpdir(), "coder-studio-state-")) : configuredStateDir;
19809
+ const stateRoot = shouldCleanupStateRoot ? mkdtempSync(join18(tmpdir(), "coder-studio-state-")) : configuredStateDir;
18066
19810
  ensureStateDir(config);
18067
19811
  const eventBus = new EventBus();
18068
19812
  const activationMgr = new ActivationManager();
@@ -18072,10 +19816,10 @@ async function createServer(configOverrides) {
18072
19816
  let commandContext;
18073
19817
  let lspMgr = null;
18074
19818
  const terminalRepo = new TerminalRepo({
18075
- filePath: join15(stateRoot, "state", "terminals.json")
19819
+ filePath: join18(stateRoot, "state", "terminals.json")
18076
19820
  });
18077
19821
  const sessionRepo = new SessionRepo({
18078
- filePath: join15(stateRoot, "state", "sessions.json")
19822
+ filePath: join18(stateRoot, "state", "sessions.json")
18079
19823
  });
18080
19824
  const terminalMgr = new TerminalManager({
18081
19825
  ptyHost: createPtyHost(),
@@ -18083,10 +19827,10 @@ async function createServer(configOverrides) {
18083
19827
  db: terminalRepo
18084
19828
  });
18085
19829
  const settingsRepo = new SettingsRepo({
18086
- filePath: join15(stateRoot, "state", "settings.json")
19830
+ filePath: join18(stateRoot, "state", "settings.json")
18087
19831
  });
18088
19832
  const updateStateRepo = new UpdateStateRepo({
18089
- filePath: join15(stateRoot, "state", "update-state.json"),
19833
+ filePath: join18(stateRoot, "state", "update-state.json"),
18090
19834
  currentVersion: config.appVersion ?? "0.0.0"
18091
19835
  });
18092
19836
  const autoFetch = new AutoFetchScheduler({
@@ -18119,17 +19863,27 @@ async function createServer(configOverrides) {
18119
19863
  }
18120
19864
  });
18121
19865
  const providerConfigRepo = new ProviderConfigRepo({
18122
- filePath: join15(stateRoot, "state", "provider-configs.json")
19866
+ filePath: join18(stateRoot, "state", "provider-configs.json")
19867
+ });
19868
+ const customProviderRepo = new CustomProviderRepo({
19869
+ filePath: join18(stateRoot, "state", "custom-providers.json")
18123
19870
  });
18124
19871
  const workspaceRepo = new WorkspaceRepo({
18125
- filePath: join15(stateRoot, "state", "workspaces.json")
19872
+ filePath: join18(stateRoot, "state", "workspaces.json")
19873
+ });
19874
+ const sessionMetadataRepo = new SessionMetadataRepo({
19875
+ workspaceRepo
18126
19876
  });
19877
+ let activeProviderRegistry = [
19878
+ ...providerRegistry,
19879
+ ...customProviderRepo.list().map((config2) => buildCustomProviderDefinition(config2))
19880
+ ];
18127
19881
  const sessionMgr = new SessionManager({
18128
19882
  terminalMgr,
18129
19883
  eventBus,
18130
19884
  db: sessionRepo,
18131
19885
  broadcaster: wsHub,
18132
- providerRegistry,
19886
+ providerRegistry: activeProviderRegistry,
18133
19887
  providerConfigRepo
18134
19888
  });
18135
19889
  let supervisorMgr;
@@ -18140,13 +19894,15 @@ async function createServer(configOverrides) {
18140
19894
  broadcaster: wsHub,
18141
19895
  autoFetch,
18142
19896
  teardown: async (workspaceId) => {
19897
+ const persistedSessions = sessionRepo.findByWorkspaceId(workspaceId);
18143
19898
  await lspMgr?.disposeWorkspace(workspaceId);
18144
19899
  await supervisorMgr?.deleteForWorkspace(workspaceId);
18145
19900
  await sessionMgr.stopForWorkspace(workspaceId);
18146
19901
  await terminalMgr.closeForWorkspace(workspaceId);
18147
19902
  sessionMgr.deleteEndedForWorkspace(workspaceId);
18148
- for (const session of sessionRepo.findByWorkspaceId(workspaceId)) {
19903
+ for (const session of persistedSessions) {
18149
19904
  sessionRepo.delete(session.id);
19905
+ sessionMetadataRepo.delete(session.id);
18150
19906
  }
18151
19907
  for (const terminal of terminalRepo.listByWorkspace(workspaceId)) {
18152
19908
  terminalRepo.delete(terminal.id);
@@ -18157,13 +19913,13 @@ async function createServer(configOverrides) {
18157
19913
  )
18158
19914
  });
18159
19915
  const authSessionRepo = new AuthSessionRepo({
18160
- filePath: join15(stateRoot, "state", "auth-sessions.json")
19916
+ filePath: join18(stateRoot, "state", "auth-sessions.json")
18161
19917
  });
18162
19918
  const authLoginBlockRepo = new AuthLoginBlockRepo({
18163
- filePath: join15(stateRoot, "state", "auth-login-blocks.json")
19919
+ filePath: join18(stateRoot, "state", "auth-login-blocks.json")
18164
19920
  });
18165
19921
  const appearanceAssetRepo = new AppearanceAssetRepo({
18166
- filePath: join15(stateRoot, "state", "appearance-assets.json")
19922
+ filePath: join18(stateRoot, "state", "appearance-assets.json")
18167
19923
  });
18168
19924
  const app = await buildFastifyApp({
18169
19925
  wsHub,
@@ -18214,7 +19970,7 @@ async function createServer(configOverrides) {
18214
19970
  terminalMgr,
18215
19971
  workspaceMgr,
18216
19972
  sessionMgr,
18217
- providerRegistry,
19973
+ providerRegistry: activeProviderRegistry,
18218
19974
  providerConfigRepo,
18219
19975
  settingsRepo,
18220
19976
  supervisorRepo,
@@ -18227,7 +19983,7 @@ async function createServer(configOverrides) {
18227
19983
  const providerRuntimeDeps = providerMockOverrides ? {
18228
19984
  commandExists: providerMockOverrides.commandExists
18229
19985
  } : {};
18230
- const providerInstallMgr = new ProviderInstallManager(providerRegistry, {
19986
+ const providerInstallMgr = new ProviderInstallManager(activeProviderRegistry, {
18231
19987
  ...providerRuntimeDeps,
18232
19988
  runCommand: providerMockOverrides?.runCommand ?? runCommandAsString
18233
19989
  });
@@ -18239,7 +19995,7 @@ async function createServer(configOverrides) {
18239
19995
  ...config.update,
18240
19996
  currentVersion: config.appVersion ?? "0.0.0"
18241
19997
  },
18242
- updateWorkerLogFilePath: join15(stateRoot, "logs", "update-worker.log"),
19998
+ updateWorkerLogFilePath: join18(stateRoot, "logs", "update-worker.log"),
18243
19999
  countRunningTerminals: () => terminalMgr.getAll().filter((terminal) => terminal.alive).length,
18244
20000
  countRunningSessions: () => sessionMgr.getAll().filter((session) => session.state === "starting" || session.state === "running").length,
18245
20001
  countActiveSupervisors: () => supervisorMgr?.countActive() ?? 0
@@ -18253,7 +20009,7 @@ async function createServer(configOverrides) {
18253
20009
  broadcaster: wsHub,
18254
20010
  settingsRepo,
18255
20011
  providerConfigRepo,
18256
- providerRegistry,
20012
+ providerRegistry: activeProviderRegistry,
18257
20013
  fencingMgr,
18258
20014
  supervisorMgr,
18259
20015
  autoFetch,
@@ -18264,7 +20020,16 @@ async function createServer(configOverrides) {
18264
20020
  lspMgr,
18265
20021
  lspToolMgr,
18266
20022
  lspToolInstallMgr,
18267
- updateService
20023
+ updateService,
20024
+ customProviderRepo,
20025
+ sessionMetadataRepo,
20026
+ setProviderRegistry: (providers) => {
20027
+ activeProviderRegistry = providers;
20028
+ commandContext.providerRegistry = providers;
20029
+ providerInstallMgr.setProviders(providers);
20030
+ sessionMgr.setProviderRegistry(providers);
20031
+ supervisorMgr?.setProviderRegistry(providers);
20032
+ }
18268
20033
  };
18269
20034
  wsHub.setCommandContext(commandContext);
18270
20035
  await app.listen({
@@ -18348,13 +20113,16 @@ var init_server = __esm({
18348
20113
  init_manifest_store();
18349
20114
  init_tool_root();
18350
20115
  init_command_runner();
20116
+ init_custom_provider();
18351
20117
  init_e2e_provider_mock();
18352
20118
  init_install_manager2();
18353
20119
  init_manager3();
18354
20120
  init_appearance_asset_repo();
18355
20121
  init_auth_login_block_repo();
18356
20122
  init_auth_session_repo();
20123
+ init_custom_provider_repo();
18357
20124
  init_provider_config_repo();
20125
+ init_session_metadata_repo();
18358
20126
  init_session_repo();
18359
20127
  init_settings_repo();
18360
20128
  init_supervisor_repo();
@@ -18397,7 +20165,9 @@ var init_storage = __esm({
18397
20165
  "use strict";
18398
20166
  init_auth_login_block_repo();
18399
20167
  init_auth_session_repo();
20168
+ init_custom_provider_repo();
18400
20169
  init_provider_config_repo();
20170
+ init_session_metadata_repo();
18401
20171
  init_session_repo();
18402
20172
  init_settings_repo();
18403
20173
  init_supervisor_repo();
@@ -18425,10 +20195,12 @@ __export(src_exports, {
18425
20195
  ActiveTerminal: () => ActiveTerminal,
18426
20196
  AuthLoginBlockRepo: () => AuthLoginBlockRepo,
18427
20197
  AuthSessionRepo: () => AuthSessionRepo,
20198
+ CustomProviderRepo: () => CustomProviderRepo,
18428
20199
  EventBus: () => EventBus,
18429
20200
  NodePtyHost: () => NodePtyHost,
18430
20201
  ProviderConfigRepo: () => ProviderConfigRepo,
18431
20202
  RingBuffer: () => RingBuffer,
20203
+ SessionMetadataRepo: () => SessionMetadataRepo,
18432
20204
  SessionRepo: () => SessionRepo,
18433
20205
  SettingsRepo: () => SettingsRepo,
18434
20206
  SupervisorRepo: () => SupervisorRepo,
@@ -18470,9 +20242,9 @@ import { fileURLToPath as fileURLToPath4 } from "url";
18470
20242
  init_state_paths();
18471
20243
  import { existsSync as existsSync10, mkdirSync as mkdirSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "fs";
18472
20244
  import { homedir as homedir4 } from "os";
18473
- import { join as join16 } from "path";
20245
+ import { join as join19 } from "path";
18474
20246
  function getCliConfigPath() {
18475
- return join16(homedir4(), ".coder-studio", "config.json");
20247
+ return join19(homedir4(), ".coder-studio", "config.json");
18476
20248
  }
18477
20249
  function normalizeLegacyDataDir(input) {
18478
20250
  return normalizeLegacyStateDir(input);
@@ -18500,11 +20272,11 @@ function readCliConfig() {
18500
20272
 
18501
20273
  // packages/cli/src/embed.ts
18502
20274
  import { existsSync as existsSync11 } from "fs";
18503
- import { dirname as dirname8, resolve as resolve5 } from "path";
20275
+ import { dirname as dirname8, resolve as resolve7 } from "path";
18504
20276
  import { fileURLToPath as fileURLToPath2 } from "url";
18505
20277
  var __filename = fileURLToPath2(import.meta.url);
18506
20278
  var __dirname = dirname8(__filename);
18507
- var WEB_ASSETS_DIR = resolve5(__dirname, "../web");
20279
+ var WEB_ASSETS_DIR = resolve7(__dirname, "../web");
18508
20280
  function getStaticAssetsDir() {
18509
20281
  return WEB_ASSETS_DIR;
18510
20282
  }
@@ -18568,13 +20340,13 @@ function getCliPackageName(importMetaUrl) {
18568
20340
 
18569
20341
  // packages/cli/src/update-runtime.ts
18570
20342
  import { existsSync as existsSync13 } from "node:fs";
18571
- import { dirname as dirname9, join as join17 } from "node:path";
20343
+ import { dirname as dirname9, join as join20 } from "node:path";
18572
20344
  import { fileURLToPath as fileURLToPath3 } from "node:url";
18573
20345
  function resolveWorkerEntryPath(importMetaUrl) {
18574
20346
  const currentDir = dirname9(fileURLToPath3(importMetaUrl));
18575
20347
  const candidates = [
18576
- join17(currentDir, "update-worker.mjs"),
18577
- join17(currentDir, "../src/update-worker.ts")
20348
+ join20(currentDir, "update-worker.mjs"),
20349
+ join20(currentDir, "../src/update-worker.ts")
18578
20350
  ];
18579
20351
  return candidates.find((candidate) => existsSync13(candidate));
18580
20352
  }