@spencer-kit/coder-studio 0.4.7 → 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.
package/dist/esm/bin.mjs CHANGED
@@ -647,7 +647,15 @@ var init_definition = __esm({
647
647
  id: "claude",
648
648
  displayName: "Claude Code",
649
649
  badge: "Claude",
650
+ kind: "built_in",
650
651
  capability: "full",
652
+ capabilities: [
653
+ { key: "interactive_session", supported: true, label: "Interactive session" },
654
+ { key: "supervisor_eval", supported: true, label: "Supervisor evaluation" },
655
+ { key: "idle_detection", supported: true, label: "Idle detection" },
656
+ { key: "context_attach", supported: false, label: "Context attach" },
657
+ { key: "review", supported: false, label: "Review" }
658
+ ],
651
659
  install: claudeInstallMetadata,
652
660
  // ===== Command construction =====
653
661
  buildCommand(config, ctx) {
@@ -817,7 +825,15 @@ var init_definition2 = __esm({
817
825
  id: "codex",
818
826
  displayName: "Codex",
819
827
  badge: "Codex",
828
+ kind: "built_in",
820
829
  capability: "full",
830
+ capabilities: [
831
+ { key: "interactive_session", supported: true, label: "Interactive session" },
832
+ { key: "supervisor_eval", supported: true, label: "Supervisor evaluation" },
833
+ { key: "idle_detection", supported: true, label: "Idle detection" },
834
+ { key: "context_attach", supported: false, label: "Context attach" },
835
+ { key: "review", supported: false, label: "Review" }
836
+ ],
821
837
  install: codexInstallMetadata,
822
838
  // ===== Command construction =====
823
839
  buildCommand(config, ctx) {
@@ -850,7 +866,78 @@ var init_definition2 = __esm({
850
866
  }
851
867
  });
852
868
 
869
+ // packages/providers/src/presets.ts
870
+ function cloneCapabilities(capabilities) {
871
+ return capabilities.map((capability) => ({ ...capability }));
872
+ }
873
+ var defaultCapabilities, providerPresets;
874
+ var init_presets = __esm({
875
+ "packages/providers/src/presets.ts"() {
876
+ "use strict";
877
+ defaultCapabilities = [
878
+ { key: "interactive_session", supported: true, label: "Interactive session" },
879
+ { key: "context_attach", supported: true, label: "Context attach" },
880
+ { key: "review", supported: true, label: "Review" }
881
+ ];
882
+ providerPresets = [
883
+ {
884
+ id: "gemini-cli",
885
+ displayName: "Gemini CLI",
886
+ kind: "preset",
887
+ description: "Preset metadata for launching Google's Gemini CLI through the custom provider flow.",
888
+ command: "gemini",
889
+ args: [],
890
+ env: {},
891
+ cwdMode: "workspace_root",
892
+ sessionMode: "interactive",
893
+ startupPrompt: "Follow the workspace instructions and explain important tradeoffs.",
894
+ capabilities: cloneCapabilities(defaultCapabilities),
895
+ requiredCommands: ["gemini"]
896
+ },
897
+ {
898
+ id: "aider",
899
+ displayName: "Aider",
900
+ kind: "preset",
901
+ description: "Preset metadata for launching Aider as a workspace-root interactive coding agent.",
902
+ command: "aider",
903
+ args: [],
904
+ env: {},
905
+ cwdMode: "workspace_root",
906
+ sessionMode: "interactive",
907
+ startupPrompt: "Review the current workspace state before making edits.",
908
+ capabilities: cloneCapabilities(defaultCapabilities),
909
+ requiredCommands: ["aider"]
910
+ },
911
+ {
912
+ id: "opencode",
913
+ displayName: "OpenCode",
914
+ kind: "preset",
915
+ description: "Preset metadata for launching OpenCode from the workspace root.",
916
+ command: "opencode",
917
+ args: [],
918
+ env: {},
919
+ cwdMode: "workspace_root",
920
+ sessionMode: "interactive",
921
+ startupPrompt: "Use the repository instructions and verify changes before finishing.",
922
+ capabilities: cloneCapabilities(defaultCapabilities),
923
+ requiredCommands: ["opencode"]
924
+ }
925
+ ];
926
+ }
927
+ });
928
+
853
929
  // packages/providers/src/registry.ts
930
+ function toProviderListItem(provider) {
931
+ return {
932
+ id: provider.id,
933
+ displayName: provider.displayName,
934
+ badge: provider.badge,
935
+ kind: provider.kind,
936
+ capability: provider.capability,
937
+ capabilities: provider.capabilities.map((capability) => ({ ...capability })),
938
+ requiredCommands: [...provider.requiredCommands]
939
+ };
940
+ }
854
941
  var providerRegistry;
855
942
  var init_registry = __esm({
856
943
  "packages/providers/src/registry.ts"() {
@@ -870,6 +957,7 @@ var init_src = __esm({
870
957
  init_config_schema2();
871
958
  init_definition2();
872
959
  init_stdout_heuristics();
960
+ init_presets();
873
961
  init_registry();
874
962
  }
875
963
  });
@@ -1712,7 +1800,7 @@ import { mkdir as mkdir3, mkdtemp, rm as rm3, writeFile as writeFile2 } from "fs
1712
1800
  import os2 from "os";
1713
1801
  import path7 from "path";
1714
1802
  async function runGit(cwd, args, options = {}) {
1715
- return new Promise((resolve6, reject) => {
1803
+ return new Promise((resolve8, reject) => {
1716
1804
  const gitArgs = [
1717
1805
  ...options.config?.flatMap(([key, value]) => ["-c", `${key}=${value}`]) ?? [],
1718
1806
  ...args
@@ -1739,7 +1827,7 @@ async function runGit(cwd, args, options = {}) {
1739
1827
  if (err) {
1740
1828
  reject(new GitError(err.message, stderr));
1741
1829
  } else {
1742
- resolve6({ stdout, stderr });
1830
+ resolve8({ stdout, stderr });
1743
1831
  }
1744
1832
  }
1745
1833
  );
@@ -3620,12 +3708,12 @@ var init_auto_fetch = __esm({
3620
3708
  }
3621
3709
  acquireWorkspaceOperation(workspaceId) {
3622
3710
  const state = this.getOrCreateState(workspaceId);
3623
- return new Promise((resolve6) => {
3711
+ return new Promise((resolve8) => {
3624
3712
  const grant = () => {
3625
3713
  state.inFlight = true;
3626
3714
  state.nextFetchAt = void 0;
3627
3715
  let released = false;
3628
- resolve6(() => {
3716
+ resolve8(() => {
3629
3717
  if (released) {
3630
3718
  return;
3631
3719
  }
@@ -4628,7 +4716,7 @@ var init_manager = __esm({
4628
4716
  // packages/server/src/provider-runtime/command-runner.ts
4629
4717
  import { spawn as spawn2 } from "node:child_process";
4630
4718
  async function runCommandAsString(file, args, options) {
4631
- return new Promise((resolve6, reject) => {
4719
+ return new Promise((resolve8, reject) => {
4632
4720
  const child = spawn2(file, args, {
4633
4721
  cwd: options?.cwd,
4634
4722
  env: options?.env,
@@ -4655,7 +4743,7 @@ async function runCommandAsString(file, args, options) {
4655
4743
  const stdout = Buffer.concat(stdoutChunks).toString("utf8");
4656
4744
  const stderr = Buffer.concat(stderrChunks).toString("utf8");
4657
4745
  if (code === 0) {
4658
- resolve6({ stdout, stderr });
4746
+ resolve8({ stdout, stderr });
4659
4747
  return;
4660
4748
  }
4661
4749
  reject(
@@ -5455,6 +5543,66 @@ var init_tool_root = __esm({
5455
5543
  }
5456
5544
  });
5457
5545
 
5546
+ // packages/server/src/provider-runtime/custom-provider.ts
5547
+ import { z as z4 } from "zod";
5548
+ function deriveProviderCapability(capabilities) {
5549
+ const interactive = capabilities.find((capability) => capability.key === "interactive_session");
5550
+ if (!interactive?.supported) {
5551
+ return "unsupported";
5552
+ }
5553
+ const allSupported = capabilities.length > 0 && capabilities.every((capability) => capability.supported);
5554
+ return allSupported ? "full" : "limited";
5555
+ }
5556
+ function buildCustomProviderDefinition(config) {
5557
+ const command = config.command.trim();
5558
+ const requiredCommand = command.split(/\s+/)[0] ?? command;
5559
+ return {
5560
+ id: config.id,
5561
+ displayName: config.displayName,
5562
+ badge: "Custom",
5563
+ kind: "custom",
5564
+ capability: deriveProviderCapability(config.capabilities),
5565
+ capabilities: config.capabilities.map((capability) => ({ ...capability })),
5566
+ install: {
5567
+ prerequisites: [],
5568
+ manualGuideKeys: [],
5569
+ docUrls: {
5570
+ provider: "",
5571
+ prerequisites: {}
5572
+ },
5573
+ strategies: {}
5574
+ },
5575
+ buildCommand(_providerConfig, ctx) {
5576
+ return {
5577
+ argv: [command, ...config.args],
5578
+ env: {
5579
+ ...config.env,
5580
+ CODER_STUDIO_SESSION_ID: ctx.sessionId
5581
+ },
5582
+ cwd: ctx.workspacePath
5583
+ };
5584
+ },
5585
+ configSchema: CUSTOM_PROVIDER_CONFIG_SCHEMA,
5586
+ defaultConfig: {},
5587
+ requiredCommands: requiredCommand ? [requiredCommand] : []
5588
+ };
5589
+ }
5590
+ function upsertProviderDefinition(registry, provider) {
5591
+ const next = registry.filter((item) => item.id !== provider.id);
5592
+ next.push(provider);
5593
+ return next;
5594
+ }
5595
+ function removeProviderDefinition(registry, providerId) {
5596
+ return registry.filter((item) => item.id !== providerId);
5597
+ }
5598
+ var CUSTOM_PROVIDER_CONFIG_SCHEMA;
5599
+ var init_custom_provider = __esm({
5600
+ "packages/server/src/provider-runtime/custom-provider.ts"() {
5601
+ "use strict";
5602
+ CUSTOM_PROVIDER_CONFIG_SCHEMA = z4.object({}).passthrough();
5603
+ }
5604
+ });
5605
+
5458
5606
  // packages/server/src/provider-runtime/e2e-provider-mock.ts
5459
5607
  import { chmodSync, existsSync as existsSync5, mkdirSync as mkdirSync6, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "node:fs";
5460
5608
  import { dirname as dirname5, join as join8 } from "node:path";
@@ -5697,9 +5845,24 @@ var init_install_manager2 = __esm({
5697
5845
  deps;
5698
5846
  constructor(providers, deps = {}) {
5699
5847
  this.deps = deps;
5848
+ this.setProviders(providers);
5849
+ }
5850
+ setProviders(providers) {
5851
+ const nextIds = new Set(providers.map((provider) => provider.id));
5852
+ this.providers.clear();
5700
5853
  for (const provider of providers) {
5701
5854
  this.providers.set(provider.id, provider);
5702
5855
  }
5856
+ for (const providerId of this.activeJobIdsByProviderId.keys()) {
5857
+ if (!nextIds.has(providerId)) {
5858
+ this.activeJobIdsByProviderId.delete(providerId);
5859
+ }
5860
+ }
5861
+ for (const providerId of this.inFlightStartsByProviderId.keys()) {
5862
+ if (!nextIds.has(providerId)) {
5863
+ this.inFlightStartsByProviderId.delete(providerId);
5864
+ }
5865
+ }
5703
5866
  }
5704
5867
  async start(providerId) {
5705
5868
  const activeJob = this.getActiveJob(providerId);
@@ -6169,7 +6332,7 @@ var init_update = __esm({
6169
6332
  });
6170
6333
 
6171
6334
  // packages/core/src/protocol/messages.ts
6172
- import { z as z4 } from "zod";
6335
+ import { z as z5 } from "zod";
6173
6336
  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;
6174
6337
  var init_messages = __esm({
6175
6338
  "packages/core/src/protocol/messages.ts"() {
@@ -6232,49 +6395,49 @@ var init_messages = __esm({
6232
6395
  frame.set(payload, TERMINAL_BINARY_HEADER_SIZE + topicBytes.length);
6233
6396
  return frame;
6234
6397
  };
6235
- CommandMessage = z4.object({
6236
- kind: z4.literal("command"),
6237
- id: z4.string().uuid(),
6238
- op: z4.string(),
6239
- args: z4.unknown()
6398
+ CommandMessage = z5.object({
6399
+ kind: z5.literal("command"),
6400
+ id: z5.string().uuid(),
6401
+ op: z5.string(),
6402
+ args: z5.unknown()
6240
6403
  });
6241
- ResultMessage = z4.object({
6242
- kind: z4.literal("result"),
6243
- id: z4.string().uuid(),
6244
- ok: z4.boolean(),
6245
- data: z4.unknown().optional(),
6246
- error: z4.object({
6247
- code: z4.string(),
6248
- message: z4.string(),
6249
- details: z4.unknown().optional()
6404
+ ResultMessage = z5.object({
6405
+ kind: z5.literal("result"),
6406
+ id: z5.string().uuid(),
6407
+ ok: z5.boolean(),
6408
+ data: z5.unknown().optional(),
6409
+ error: z5.object({
6410
+ code: z5.string(),
6411
+ message: z5.string(),
6412
+ details: z5.unknown().optional()
6250
6413
  }).optional()
6251
6414
  });
6252
- EventMessage = z4.object({
6253
- kind: z4.literal("event"),
6254
- topic: z4.string(),
6255
- seq: z4.number().int().nonnegative(),
6256
- timestamp: z4.number().int().positive(),
6257
- data: z4.unknown()
6415
+ EventMessage = z5.object({
6416
+ kind: z5.literal("event"),
6417
+ topic: z5.string(),
6418
+ seq: z5.number().int().nonnegative(),
6419
+ timestamp: z5.number().int().positive(),
6420
+ data: z5.unknown()
6258
6421
  });
6259
- SubscribeMessage = z4.object({
6260
- kind: z4.literal("subscribe"),
6261
- topics: z4.array(z4.string())
6422
+ SubscribeMessage = z5.object({
6423
+ kind: z5.literal("subscribe"),
6424
+ topics: z5.array(z5.string())
6262
6425
  });
6263
- UnsubscribeMessage = z4.object({
6264
- kind: z4.literal("unsubscribe"),
6265
- topics: z4.array(z4.string())
6426
+ UnsubscribeMessage = z5.object({
6427
+ kind: z5.literal("unsubscribe"),
6428
+ topics: z5.array(z5.string())
6266
6429
  });
6267
- ResyncMessage = z4.object({
6268
- kind: z4.literal("resync"),
6269
- lastSeen: z4.record(z4.string(), z4.number())
6430
+ ResyncMessage = z5.object({
6431
+ kind: z5.literal("resync"),
6432
+ lastSeen: z5.record(z5.string(), z5.number())
6270
6433
  });
6271
- ClientMessage = z4.discriminatedUnion("kind", [
6434
+ ClientMessage = z5.discriminatedUnion("kind", [
6272
6435
  CommandMessage,
6273
6436
  SubscribeMessage,
6274
6437
  UnsubscribeMessage,
6275
6438
  ResyncMessage
6276
6439
  ]);
6277
- ServerMessage = z4.discriminatedUnion("kind", [ResultMessage, EventMessage]);
6440
+ ServerMessage = z5.discriminatedUnion("kind", [ResultMessage, EventMessage]);
6278
6441
  }
6279
6442
  });
6280
6443
 
@@ -6347,7 +6510,7 @@ var init_src3 = __esm({
6347
6510
  });
6348
6511
 
6349
6512
  // packages/server/src/provider-config.ts
6350
- import { z as z5 } from "zod";
6513
+ import { z as z6 } from "zod";
6351
6514
  function isSupportedProviderId(providerId) {
6352
6515
  return supportedProviderIds.has(providerId);
6353
6516
  }
@@ -6367,17 +6530,17 @@ var init_provider_config = __esm({
6367
6530
  "use strict";
6368
6531
  SUPPORTED_PROVIDER_IDS = ["claude", "codex"];
6369
6532
  supportedProviderIds = new Set(SUPPORTED_PROVIDER_IDS);
6370
- ProviderLaunchConfigInputSchema = z5.object({
6371
- additionalArgs: z5.array(z5.string()).optional(),
6372
- envVars: z5.record(z5.string(), z5.string()).optional()
6533
+ ProviderLaunchConfigInputSchema = z6.object({
6534
+ additionalArgs: z6.array(z6.string()).optional(),
6535
+ envVars: z6.record(z6.string(), z6.string()).optional()
6373
6536
  }).strict();
6374
- ProviderSettingsSchema = z5.object({
6537
+ ProviderSettingsSchema = z6.object({
6375
6538
  claude: ProviderLaunchConfigInputSchema.optional(),
6376
6539
  codex: ProviderLaunchConfigInputSchema.optional()
6377
6540
  }).strict();
6378
- ProviderLaunchConfigSchema = z5.object({
6379
- additionalArgs: z5.array(z5.string()).default([]),
6380
- envVars: z5.record(z5.string(), z5.string()).optional()
6541
+ ProviderLaunchConfigSchema = z6.object({
6542
+ additionalArgs: z6.array(z6.string()).default([]),
6543
+ envVars: z6.record(z6.string(), z6.string()).optional()
6381
6544
  });
6382
6545
  }
6383
6546
  });
@@ -6873,6 +7036,9 @@ var init_manager3 = __esm({
6873
7036
  comparators = /* @__PURE__ */ new Map();
6874
7037
  detectorUnsubscribes = /* @__PURE__ */ new Map();
6875
7038
  logger;
7039
+ setProviderRegistry(providerRegistry2) {
7040
+ this.deps.providerRegistry = providerRegistry2;
7041
+ }
6876
7042
  /**
6877
7043
  * Create a new session with provider
6878
7044
  */
@@ -7837,15 +8003,104 @@ var init_auth_session_repo = __esm({
7837
8003
  }
7838
8004
  });
7839
8005
 
7840
- // packages/server/src/storage/repositories/provider-config-repo.ts
8006
+ // packages/server/src/storage/repositories/custom-provider-repo.ts
7841
8007
  function isRecord5(value) {
7842
8008
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
7843
8009
  }
7844
- function normalizeProviderConfigFile(value) {
8010
+ function normalizeConfig(config) {
8011
+ return {
8012
+ ...config,
8013
+ args: [...config.args],
8014
+ env: { ...config.env },
8015
+ capabilities: config.capabilities.map((capability) => ({ ...capability }))
8016
+ };
8017
+ }
8018
+ function normalizeFileConfigs(value) {
7845
8019
  if (isRecord5(value) && value.version === 1 && isRecord5(value.providers)) {
7846
- return value.providers;
8020
+ return Object.fromEntries(
8021
+ Object.entries(value.providers).map(([id, config]) => [
8022
+ id,
8023
+ normalizeConfig(config)
8024
+ ])
8025
+ );
7847
8026
  }
7848
8027
  if (isRecord5(value)) {
8028
+ return Object.fromEntries(
8029
+ Object.entries(value).map(([id, config]) => [
8030
+ id,
8031
+ normalizeConfig(config)
8032
+ ])
8033
+ );
8034
+ }
8035
+ return {};
8036
+ }
8037
+ var CustomProviderRepo;
8038
+ var init_custom_provider_repo = __esm({
8039
+ "packages/server/src/storage/repositories/custom-provider-repo.ts"() {
8040
+ "use strict";
8041
+ init_json_file_store();
8042
+ CustomProviderRepo = class {
8043
+ filePath;
8044
+ constructor(input2) {
8045
+ this.filePath = input2.filePath;
8046
+ }
8047
+ list() {
8048
+ return Object.values(this.loadFileConfigs()).sort(
8049
+ (left, right) => right.updatedAt - left.updatedAt || left.id.localeCompare(right.id)
8050
+ );
8051
+ }
8052
+ get(id) {
8053
+ return this.loadFileConfigs()[id];
8054
+ }
8055
+ set(config) {
8056
+ const existing = this.get(config.id);
8057
+ const createdAt = existing?.createdAt ?? config.createdAt;
8058
+ const normalized = normalizeConfig({
8059
+ ...config,
8060
+ createdAt
8061
+ });
8062
+ const next = this.loadFileConfigs();
8063
+ next[normalized.id] = normalized;
8064
+ this.saveFileConfigs(next);
8065
+ return next[normalized.id];
8066
+ }
8067
+ delete(id) {
8068
+ const next = this.loadFileConfigs();
8069
+ if (!Object.prototype.hasOwnProperty.call(next, id)) {
8070
+ return;
8071
+ }
8072
+ delete next[id];
8073
+ this.saveFileConfigs(next);
8074
+ }
8075
+ loadFileConfigs() {
8076
+ const parsed = readJsonFile(
8077
+ this.filePath
8078
+ );
8079
+ if (parsed !== void 0) {
8080
+ return normalizeFileConfigs(parsed);
8081
+ }
8082
+ return {};
8083
+ }
8084
+ saveFileConfigs(configs) {
8085
+ const payload = {
8086
+ version: 1,
8087
+ providers: configs
8088
+ };
8089
+ writeJsonFileAtomic(this.filePath, payload);
8090
+ }
8091
+ };
8092
+ }
8093
+ });
8094
+
8095
+ // packages/server/src/storage/repositories/provider-config-repo.ts
8096
+ function isRecord6(value) {
8097
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
8098
+ }
8099
+ function normalizeProviderConfigFile(value) {
8100
+ if (isRecord6(value) && value.version === 1 && isRecord6(value.providers)) {
8101
+ return value.providers;
8102
+ }
8103
+ if (isRecord6(value)) {
7849
8104
  return value;
7850
8105
  }
7851
8106
  return {};
@@ -7918,15 +8173,159 @@ var init_provider_config_repo = __esm({
7918
8173
  }
7919
8174
  });
7920
8175
 
8176
+ // packages/server/src/workspace/workspace-state.ts
8177
+ import { join as join9 } from "node:path";
8178
+ function resolveWorkspaceStateFilePath(workspacePath, fileName) {
8179
+ return join9(workspacePath, WORKSPACE_STATE_DIR, fileName);
8180
+ }
8181
+ var WORKSPACE_STATE_DIR, AGENT_INSTRUCTIONS_RELATIVE_PATH, SESSION_METADATA_FILE_NAME, SESSION_METADATA_RELATIVE_PATH;
8182
+ var init_workspace_state = __esm({
8183
+ "packages/server/src/workspace/workspace-state.ts"() {
8184
+ "use strict";
8185
+ WORKSPACE_STATE_DIR = ".coder-studio";
8186
+ AGENT_INSTRUCTIONS_RELATIVE_PATH = `${WORKSPACE_STATE_DIR}/AGENTS.md`;
8187
+ SESSION_METADATA_FILE_NAME = "session-metadata.json";
8188
+ SESSION_METADATA_RELATIVE_PATH = `${WORKSPACE_STATE_DIR}/${SESSION_METADATA_FILE_NAME}`;
8189
+ }
8190
+ });
8191
+
8192
+ // packages/server/src/storage/repositories/session-metadata-repo.ts
8193
+ function isRecord7(value) {
8194
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
8195
+ }
8196
+ function normalizeRun(run) {
8197
+ return {
8198
+ ...run
8199
+ };
8200
+ }
8201
+ function normalizeMetadata(metadata) {
8202
+ return {
8203
+ sessionId: metadata.sessionId,
8204
+ workspaceId: metadata.workspaceId,
8205
+ providerId: metadata.providerId,
8206
+ objective: metadata.objective ?? void 0,
8207
+ baselineGitHead: metadata.baselineGitHead ?? void 0,
8208
+ baselineCapturedAt: metadata.baselineCapturedAt ?? void 0,
8209
+ verificationRuns: metadata.verificationRuns.map(normalizeRun)
8210
+ };
8211
+ }
8212
+ function normalizeFileMetadata(value) {
8213
+ if (isRecord7(value) && value.version === 1 && isRecord7(value.metadata)) {
8214
+ return Object.fromEntries(
8215
+ Object.entries(value.metadata).map(([sessionId, metadata]) => [
8216
+ sessionId,
8217
+ normalizeMetadata(metadata)
8218
+ ])
8219
+ );
8220
+ }
8221
+ if (isRecord7(value)) {
8222
+ return Object.fromEntries(
8223
+ Object.entries(value).map(([sessionId, metadata]) => [
8224
+ sessionId,
8225
+ normalizeMetadata(metadata)
8226
+ ])
8227
+ );
8228
+ }
8229
+ return {};
8230
+ }
8231
+ var SessionMetadataRepo;
8232
+ var init_session_metadata_repo = __esm({
8233
+ "packages/server/src/storage/repositories/session-metadata-repo.ts"() {
8234
+ "use strict";
8235
+ init_workspace_state();
8236
+ init_json_file_store();
8237
+ SessionMetadataRepo = class {
8238
+ workspaceRepo;
8239
+ constructor(input2) {
8240
+ this.workspaceRepo = input2.workspaceRepo;
8241
+ }
8242
+ upsert(metadata) {
8243
+ const normalized = normalizeMetadata(metadata);
8244
+ const workspace = this.workspaceRepo.findById(normalized.workspaceId);
8245
+ if (!workspace) {
8246
+ throw new Error(`Workspace not found for session metadata: ${normalized.workspaceId}`);
8247
+ }
8248
+ const existing = this.findSessionLocation(normalized.sessionId);
8249
+ if (existing && existing.workspace.id !== workspace.id) {
8250
+ delete existing.fileMetadata[normalized.sessionId];
8251
+ this.saveWorkspaceFileMetadata(existing.workspace.path, existing.fileMetadata);
8252
+ }
8253
+ const next = existing && existing.workspace.id === workspace.id ? existing.fileMetadata : this.loadWorkspaceFileMetadata(workspace.path);
8254
+ next[normalized.sessionId] = normalized;
8255
+ this.saveWorkspaceFileMetadata(workspace.path, next);
8256
+ return next[normalized.sessionId];
8257
+ }
8258
+ get(sessionId) {
8259
+ return this.findSessionLocation(sessionId)?.fileMetadata[sessionId];
8260
+ }
8261
+ addVerificationRun(sessionId, run) {
8262
+ const existing = this.findSessionLocation(sessionId);
8263
+ if (!existing) {
8264
+ throw new Error(`Session metadata not found: ${sessionId}`);
8265
+ }
8266
+ existing.fileMetadata[sessionId] = normalizeMetadata({
8267
+ ...existing.fileMetadata[sessionId],
8268
+ verificationRuns: [...existing.fileMetadata[sessionId].verificationRuns, normalizeRun(run)]
8269
+ });
8270
+ this.saveWorkspaceFileMetadata(existing.workspace.path, existing.fileMetadata);
8271
+ return existing.fileMetadata[sessionId];
8272
+ }
8273
+ delete(sessionId) {
8274
+ this.deleteFromAnyWorkspace(sessionId);
8275
+ }
8276
+ findSessionLocation(sessionId) {
8277
+ for (const workspace of this.workspaceRepo.list()) {
8278
+ const fileMetadata = this.loadWorkspaceFileMetadata(workspace.path);
8279
+ if (Object.prototype.hasOwnProperty.call(fileMetadata, sessionId)) {
8280
+ return {
8281
+ workspace,
8282
+ fileMetadata
8283
+ };
8284
+ }
8285
+ }
8286
+ return void 0;
8287
+ }
8288
+ deleteFromAnyWorkspace(sessionId) {
8289
+ const existing = this.findSessionLocation(sessionId);
8290
+ if (!existing) {
8291
+ return false;
8292
+ }
8293
+ delete existing.fileMetadata[sessionId];
8294
+ this.saveWorkspaceFileMetadata(existing.workspace.path, existing.fileMetadata);
8295
+ return true;
8296
+ }
8297
+ loadWorkspaceFileMetadata(workspacePath) {
8298
+ const parsed = readJsonFile(
8299
+ resolveWorkspaceStateFilePath(workspacePath, SESSION_METADATA_FILE_NAME)
8300
+ );
8301
+ if (parsed !== void 0) {
8302
+ return normalizeFileMetadata(parsed);
8303
+ }
8304
+ return {};
8305
+ }
8306
+ saveWorkspaceFileMetadata(workspacePath, metadata) {
8307
+ const payload = {
8308
+ version: 1,
8309
+ metadata
8310
+ };
8311
+ writeJsonFileAtomic(
8312
+ resolveWorkspaceStateFilePath(workspacePath, SESSION_METADATA_FILE_NAME),
8313
+ payload
8314
+ );
8315
+ }
8316
+ };
8317
+ }
8318
+ });
8319
+
7921
8320
  // packages/server/src/storage/repositories/settings-repo.ts
7922
- function isRecord6(value) {
8321
+ function isRecord8(value) {
7923
8322
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
7924
8323
  }
7925
8324
  function normalizeSettingsFile(value) {
7926
- if (isRecord6(value) && value.version === 1 && isRecord6(value.settings)) {
8325
+ if (isRecord8(value) && value.version === 1 && isRecord8(value.settings)) {
7927
8326
  return { ...value.settings };
7928
8327
  }
7929
- if (isRecord6(value)) {
8328
+ if (isRecord8(value)) {
7930
8329
  return { ...value };
7931
8330
  }
7932
8331
  return {};
@@ -8077,11 +8476,11 @@ var init_supervisor_repo = __esm({
8077
8476
  });
8078
8477
 
8079
8478
  // packages/server/src/storage/repositories/terminal-repo.ts
8080
- function isRecord7(value) {
8479
+ function isRecord9(value) {
8081
8480
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
8082
8481
  }
8083
8482
  function isTerminal(value) {
8084
- if (!isRecord7(value)) {
8483
+ if (!isRecord9(value)) {
8085
8484
  return false;
8086
8485
  }
8087
8486
  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";
@@ -8093,7 +8492,7 @@ function normalizeTerminal(value) {
8093
8492
  };
8094
8493
  }
8095
8494
  function normalizeTerminalFile(value) {
8096
- if (isRecord7(value) && value.version === 1 && isRecord7(value.terminals)) {
8495
+ if (isRecord9(value) && value.version === 1 && isRecord9(value.terminals)) {
8097
8496
  const normalized = {};
8098
8497
  for (const entry of Object.values(value.terminals)) {
8099
8498
  if (isTerminal(entry)) {
@@ -8111,7 +8510,7 @@ function normalizeTerminalFile(value) {
8111
8510
  }
8112
8511
  return normalized;
8113
8512
  }
8114
- if (isRecord7(value)) {
8513
+ if (isRecord9(value)) {
8115
8514
  const normalized = {};
8116
8515
  for (const [terminalId, entry] of Object.entries(value)) {
8117
8516
  if (isTerminal(entry)) {
@@ -8277,12 +8676,12 @@ var init_terminal_repo = __esm({
8277
8676
  });
8278
8677
 
8279
8678
  // packages/server/src/storage/repositories/update-state-repo.ts
8280
- function isRecord8(value) {
8679
+ function isRecord10(value) {
8281
8680
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
8282
8681
  }
8283
8682
  function normalizeUpdateState(value, currentVersion) {
8284
8683
  const defaults = createDefaultUpdateState(currentVersion);
8285
- if (!isRecord8(value)) {
8684
+ if (!isRecord10(value)) {
8286
8685
  return defaults;
8287
8686
  }
8288
8687
  return {
@@ -8345,17 +8744,17 @@ var init_update_state_repo = __esm({
8345
8744
  });
8346
8745
 
8347
8746
  // packages/server/src/storage/repositories/workspace-repo.ts
8348
- function isRecord9(value) {
8747
+ function isRecord11(value) {
8349
8748
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
8350
8749
  }
8351
8750
  function isWorkspace(value) {
8352
- if (!isRecord9(value)) {
8751
+ if (!isRecord11(value)) {
8353
8752
  return false;
8354
8753
  }
8355
- 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);
8754
+ 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);
8356
8755
  }
8357
8756
  function normalizeWorkspaceFile(value) {
8358
- if (isRecord9(value) && value.version === 1 && isRecord9(value.workspaces)) {
8757
+ if (isRecord11(value) && value.version === 1 && isRecord11(value.workspaces)) {
8359
8758
  const normalized = {};
8360
8759
  for (const entry of Object.values(value.workspaces)) {
8361
8760
  if (isWorkspace(entry)) {
@@ -8373,7 +8772,7 @@ function normalizeWorkspaceFile(value) {
8373
8772
  }
8374
8773
  return normalized;
8375
8774
  }
8376
- if (isRecord9(value)) {
8775
+ if (isRecord11(value)) {
8377
8776
  const normalized = {};
8378
8777
  for (const [workspaceId, entry] of Object.entries(value)) {
8379
8778
  if (isWorkspace(entry)) {
@@ -8618,13 +9017,13 @@ function ensureNodePtySpawnHelperExecutable(deps = {}) {
8618
9017
  return;
8619
9018
  }
8620
9019
  const arch = deps.arch ?? process.arch;
8621
- const resolve6 = deps.resolve ?? ((id) => require4.resolve(id));
9020
+ const resolve8 = deps.resolve ?? ((id) => require4.resolve(id));
8622
9021
  const fileExists = deps.existsSync ?? existsSync6;
8623
- const stat11 = deps.statSync ?? statSync;
9022
+ const stat12 = deps.statSync ?? statSync;
8624
9023
  const chmod = deps.chmodSync ?? chmodSync2;
8625
9024
  let packageJsonPath;
8626
9025
  try {
8627
- packageJsonPath = resolve6(NODE_PTY_PKG);
9026
+ packageJsonPath = resolve8(NODE_PTY_PKG);
8628
9027
  } catch {
8629
9028
  return;
8630
9029
  }
@@ -8638,7 +9037,7 @@ function ensureNodePtySpawnHelperExecutable(deps = {}) {
8638
9037
  if (!fileExists(helperPath)) {
8639
9038
  return;
8640
9039
  }
8641
- const currentMode = stat11(helperPath).mode;
9040
+ const currentMode = stat12(helperPath).mode;
8642
9041
  const executableMode = currentMode | 73;
8643
9042
  if (executableMode === currentMode) {
8644
9043
  return;
@@ -8689,7 +9088,7 @@ async function escalateKillWithPolling(pid, signal, options) {
8689
9088
  const startTime = Date.now();
8690
9089
  const deadline = startTime + timeoutMs;
8691
9090
  while (Date.now() < deadline) {
8692
- await new Promise((resolve6) => setTimeout(resolve6, pollIntervalMs));
9091
+ await new Promise((resolve8) => setTimeout(resolve8, pollIntervalMs));
8693
9092
  if (!isProcessAlive(pid)) {
8694
9093
  return true;
8695
9094
  }
@@ -9053,7 +9452,7 @@ async function runCommand(command, timeoutMs, options = {}) {
9053
9452
  if (options.signal?.aborted) {
9054
9453
  throw createSupervisorEvalAbortedError();
9055
9454
  }
9056
- return await new Promise((resolve6, reject) => {
9455
+ return await new Promise((resolve8, reject) => {
9057
9456
  const child = spawn3(command.argv[0], command.argv.slice(1), {
9058
9457
  cwd: command.cwd,
9059
9458
  detached: process.platform !== "win32",
@@ -9083,7 +9482,7 @@ async function runCommand(command, timeoutMs, options = {}) {
9083
9482
  }
9084
9483
  settled = true;
9085
9484
  cleanup();
9086
- resolve6(value);
9485
+ resolve8(value);
9087
9486
  };
9088
9487
  const terminate = (error) => {
9089
9488
  if (terminationError) {
@@ -9911,12 +10310,12 @@ var init_scheduler = __esm({
9911
10310
 
9912
10311
  // packages/server/src/supervisor/manager.ts
9913
10312
  function createDeferredCompletion() {
9914
- let resolve6 = () => {
10313
+ let resolve8 = () => {
9915
10314
  };
9916
10315
  const promise = new Promise((innerResolve) => {
9917
- resolve6 = innerResolve;
10316
+ resolve8 = innerResolve;
9918
10317
  });
9919
- return { promise, resolve: resolve6 };
10318
+ return { promise, resolve: resolve8 };
9920
10319
  }
9921
10320
  function generateSupervisorId() {
9922
10321
  return `sup_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
@@ -10037,6 +10436,9 @@ var init_manager4 = __esm({
10037
10436
  logger;
10038
10437
  config;
10039
10438
  lifecycleUnsubscribe = null;
10439
+ setProviderRegistry(providerRegistry2) {
10440
+ this.deps.providerRegistry = providerRegistry2;
10441
+ }
10040
10442
  start() {
10041
10443
  this.lifecycleUnsubscribe?.();
10042
10444
  this.lifecycleUnsubscribe = this.deps.eventBus.on(
@@ -11271,10 +11673,10 @@ var init_manager4 = __esm({
11271
11673
  if (signal?.aborted) {
11272
11674
  throw { code: "supervisor_eval_aborted", message: "Supervisor evaluator aborted" };
11273
11675
  }
11274
- await new Promise((resolve6, reject) => {
11676
+ await new Promise((resolve8, reject) => {
11275
11677
  const timer = setTimeout(() => {
11276
11678
  signal?.removeEventListener("abort", onAbort);
11277
- resolve6();
11679
+ resolve8();
11278
11680
  }, delayMs);
11279
11681
  timer.unref?.();
11280
11682
  const onAbort = () => {
@@ -11306,30 +11708,30 @@ __export(target_store_exports, {
11306
11708
  saveTargetMeta: () => saveTargetMeta
11307
11709
  });
11308
11710
  import { mkdir as mkdir4, mkdtemp as mkdtemp2, readdir as readdir2, readFile as readFile3, rename, rm as rm6, writeFile as writeFile4 } from "node:fs/promises";
11309
- import { dirname as dirname6, join as join9 } from "node:path";
11711
+ import { dirname as dirname6, join as join10 } from "node:path";
11310
11712
  function targetDir(workspacePath, targetId) {
11311
- return join9(workspacePath, ".coder-studio", "supervisor", "targets", targetId);
11713
+ return join10(workspacePath, ".coder-studio", "supervisor", "targets", targetId);
11312
11714
  }
11313
11715
  function metaPath(workspacePath, targetId) {
11314
- return join9(targetDir(workspacePath, targetId), "meta.json");
11716
+ return join10(targetDir(workspacePath, targetId), "meta.json");
11315
11717
  }
11316
11718
  function memoryPath(workspacePath, targetId) {
11317
- return join9(targetDir(workspacePath, targetId), "memory.json");
11719
+ return join10(targetDir(workspacePath, targetId), "memory.json");
11318
11720
  }
11319
11721
  function cyclesPath(workspacePath, targetId) {
11320
- return join9(targetDir(workspacePath, targetId), "cycles.jsonl");
11722
+ return join10(targetDir(workspacePath, targetId), "cycles.jsonl");
11321
11723
  }
11322
11724
  function targetsRoot(workspacePath) {
11323
- return join9(workspacePath, ".coder-studio", "supervisor", "targets");
11725
+ return join10(workspacePath, ".coder-studio", "supervisor", "targets");
11324
11726
  }
11325
11727
  function metaFilePath(dirPath) {
11326
- return join9(dirPath, "meta.json");
11728
+ return join10(dirPath, "meta.json");
11327
11729
  }
11328
11730
  function memoryFilePath(dirPath) {
11329
- return join9(dirPath, "memory.json");
11731
+ return join10(dirPath, "memory.json");
11330
11732
  }
11331
11733
  function cyclesFilePath(dirPath) {
11332
- return join9(dirPath, "cycles.jsonl");
11734
+ return join10(dirPath, "cycles.jsonl");
11333
11735
  }
11334
11736
  function hasCode2(error, code) {
11335
11737
  return Boolean(
@@ -11348,7 +11750,7 @@ function errorMessage(error, fallback) {
11348
11750
  }
11349
11751
  return fallback;
11350
11752
  }
11351
- function isRecord10(value) {
11753
+ function isRecord12(value) {
11352
11754
  return Boolean(value) && typeof value === "object";
11353
11755
  }
11354
11756
  function readNonEmptyString(value) {
@@ -11392,7 +11794,7 @@ function fallbackAcceptanceCriteria(title) {
11392
11794
  return [`${title} is complete`];
11393
11795
  }
11394
11796
  function normalizeItem(value, fallbackKind) {
11395
- if (!isRecord10(value)) {
11797
+ if (!isRecord12(value)) {
11396
11798
  return null;
11397
11799
  }
11398
11800
  const id = readNonEmptyString(value.id);
@@ -11423,7 +11825,7 @@ function normalizeLegacyPlanItems(plan) {
11423
11825
  }
11424
11826
  return plan.flatMap((value) => {
11425
11827
  const item = normalizeItem(
11426
- isRecord10(value) ? {
11828
+ isRecord12(value) ? {
11427
11829
  id: value.id,
11428
11830
  kind: "stage",
11429
11831
  title: value.title,
@@ -11447,7 +11849,7 @@ function resolveActiveItemId(items, candidate) {
11447
11849
  return items.find((item) => item.status === "in_progress")?.id ?? items.find((item) => item.status === "pending")?.id ?? items[0]?.id;
11448
11850
  }
11449
11851
  function normalizeTargetMemory(raw, targetId) {
11450
- if (!isRecord10(raw)) {
11852
+ if (!isRecord12(raw)) {
11451
11853
  return buildTargetMemory(targetId, 0);
11452
11854
  }
11453
11855
  const updatedAt = readTimestamp(raw.updatedAt, 0);
@@ -11474,7 +11876,7 @@ function normalizeTargetMemory(raw, targetId) {
11474
11876
  };
11475
11877
  }
11476
11878
  function normalizePersistedSupervisor(raw, fallback) {
11477
- if (!isRecord10(raw)) {
11879
+ if (!isRecord12(raw)) {
11478
11880
  return void 0;
11479
11881
  }
11480
11882
  const id = readNonEmptyString(raw.id) ?? fallback.targetId;
@@ -11510,7 +11912,7 @@ function normalizePersistedSupervisor(raw, fallback) {
11510
11912
  };
11511
11913
  }
11512
11914
  function normalizeTargetMeta(raw, fallbackTargetId) {
11513
- if (!isRecord10(raw)) {
11915
+ if (!isRecord12(raw)) {
11514
11916
  const targetId2 = fallbackTargetId ?? "";
11515
11917
  return {
11516
11918
  targetId: targetId2,
@@ -11631,7 +12033,7 @@ async function resetTargetFiles(workspacePath, input2) {
11631
12033
  const parentDir = dirname6(dir);
11632
12034
  const backupDir = `${dir}.backup-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
11633
12035
  await mkdir4(parentDir, { recursive: true });
11634
- const stagingDir = await mkdtemp2(join9(parentDir, `${input2.targetId}.reset-`));
12036
+ const stagingDir = await mkdtemp2(join10(parentDir, `${input2.targetId}.reset-`));
11635
12037
  let backupCreated = false;
11636
12038
  let promoted = false;
11637
12039
  let restored = false;
@@ -12088,8 +12490,8 @@ var init_terminal_snapshot_buffer = __esm({
12088
12490
  if (this.pendingWriteCount === 0) {
12089
12491
  return Promise.resolve();
12090
12492
  }
12091
- return new Promise((resolve6) => {
12092
- this.drainResolvers.push(resolve6);
12493
+ return new Promise((resolve8) => {
12494
+ this.drainResolvers.push(resolve8);
12093
12495
  });
12094
12496
  }
12095
12497
  resolveDrainIfIdle() {
@@ -12098,8 +12500,8 @@ var init_terminal_snapshot_buffer = __esm({
12098
12500
  }
12099
12501
  const resolvers = this.drainResolvers;
12100
12502
  this.drainResolvers = [];
12101
- for (const resolve6 of resolvers) {
12102
- resolve6();
12503
+ for (const resolve8 of resolvers) {
12504
+ resolve8();
12103
12505
  }
12104
12506
  }
12105
12507
  requireTerminal() {
@@ -12460,10 +12862,10 @@ var init_manager5 = __esm({
12460
12862
  }
12461
12863
  return existing.promise;
12462
12864
  }
12463
- let resolve6 = () => {
12865
+ let resolve8 = () => {
12464
12866
  };
12465
12867
  const promise = new Promise((innerResolve) => {
12466
- resolve6 = innerResolve;
12868
+ resolve8 = innerResolve;
12467
12869
  });
12468
12870
  let markKillCompleted = () => {
12469
12871
  };
@@ -12476,7 +12878,7 @@ var init_manager5 = __esm({
12476
12878
  markKillCompleted,
12477
12879
  finalized: false,
12478
12880
  promise,
12479
- resolve: resolve6
12881
+ resolve: resolve8
12480
12882
  });
12481
12883
  void terminal.pty.kill(signal).finally(() => {
12482
12884
  const waiter = this.explicitCloseWaiters.get(terminalId);
@@ -13046,7 +13448,7 @@ var init_validator = __esm({
13046
13448
  // packages/server/src/fs/gitignore.ts
13047
13449
  import { existsSync as existsSync7, readFileSync as readFileSync6 } from "fs";
13048
13450
  import ignore from "ignore";
13049
- import { join as join10, relative as relative2 } from "path";
13451
+ import { join as join11, relative as relative2 } from "path";
13050
13452
  function normalizePath(path14) {
13051
13453
  return path14.replace(/\\/g, "/");
13052
13454
  }
@@ -13069,7 +13471,7 @@ function isIgnoredByGitignore(ig, path14) {
13069
13471
  return ig.ignores(path14) || ig.ignores(`${path14}/`);
13070
13472
  }
13071
13473
  function createGitignoreFilter(rootPath, dirPath) {
13072
- const gitignorePath = join10(rootPath, ".gitignore");
13474
+ const gitignorePath = join11(rootPath, ".gitignore");
13073
13475
  if (!existsSync7(gitignorePath)) {
13074
13476
  return (name) => !isDefaultTreeIgnored(name);
13075
13477
  }
@@ -13079,7 +13481,7 @@ function createGitignoreFilter(rootPath, dirPath) {
13079
13481
  if (isAlwaysTreeIgnored(name)) {
13080
13482
  return false;
13081
13483
  }
13082
- const relativePath = relativeToRoot(rootPath, join10(dirPath, name));
13484
+ const relativePath = relativeToRoot(rootPath, join11(dirPath, name));
13083
13485
  return !isIgnoredByGitignore(ig, relativePath);
13084
13486
  };
13085
13487
  }
@@ -13752,7 +14154,7 @@ var init_fencing = __esm({
13752
14154
  // packages/server/src/commands/terminal.ts
13753
14155
  import { stat as stat8 } from "node:fs/promises";
13754
14156
  import { basename, isAbsolute as isAbsolute2 } from "node:path";
13755
- import { z as z6 } from "zod";
14157
+ import { z as z7 } from "zod";
13756
14158
  function decodeTerminalInput(args) {
13757
14159
  if ("bytes" in args) {
13758
14160
  return Buffer.from(args.bytes, "base64");
@@ -13824,29 +14226,29 @@ var init_terminal = __esm({
13824
14226
  init_src3();
13825
14227
  init_file_io();
13826
14228
  init_dispatch();
13827
- TerminalInputActivitySchema = z6.enum(TERMINAL_INPUT_ACTIVITIES).optional();
13828
- TerminalInputSchema = z6.union([
13829
- z6.object({
13830
- terminalId: z6.string(),
13831
- bytes: z6.string(),
14229
+ TerminalInputActivitySchema = z7.enum(TERMINAL_INPUT_ACTIVITIES).optional();
14230
+ TerminalInputSchema = z7.union([
14231
+ z7.object({
14232
+ terminalId: z7.string(),
14233
+ bytes: z7.string(),
13832
14234
  activity: TerminalInputActivitySchema,
13833
- submittedText: z6.string().optional()
14235
+ submittedText: z7.string().optional()
13834
14236
  }),
13835
- z6.object({
13836
- terminalId: z6.string(),
13837
- transport: z6.literal("binary"),
13838
- streamId: z6.number().int().nonnegative(),
13839
- size: z6.number().int().nonnegative(),
14237
+ z7.object({
14238
+ terminalId: z7.string(),
14239
+ transport: z7.literal("binary"),
14240
+ streamId: z7.number().int().nonnegative(),
14241
+ size: z7.number().int().nonnegative(),
13840
14242
  activity: TerminalInputActivitySchema,
13841
- submittedText: z6.string().optional()
14243
+ submittedText: z7.string().optional()
13842
14244
  })
13843
14245
  ]);
13844
14246
  pendingTerminalInput = /* @__PURE__ */ new Map();
13845
14247
  nextOutboundBinaryStreamId = 0;
13846
14248
  registerCommand(
13847
14249
  "terminal.list",
13848
- z6.object({
13849
- workspaceId: z6.string()
14250
+ z7.object({
14251
+ workspaceId: z7.string()
13850
14252
  }),
13851
14253
  async (args, ctx) => {
13852
14254
  return ctx.terminalMgr.getAll().map((terminal) => terminal.toDTO()).filter((terminal) => terminal.workspaceId === args.workspaceId);
@@ -13854,12 +14256,12 @@ var init_terminal = __esm({
13854
14256
  );
13855
14257
  registerCommand(
13856
14258
  "terminal.create",
13857
- z6.object({
13858
- workspaceId: z6.string(),
13859
- cols: z6.number().int().positive().optional(),
13860
- rows: z6.number().int().positive().optional(),
13861
- cwdPath: z6.string().optional(),
13862
- themeBackground: z6.string().regex(/^#[0-9a-fA-F]{3,8}$/).optional()
14259
+ z7.object({
14260
+ workspaceId: z7.string(),
14261
+ cols: z7.number().int().positive().optional(),
14262
+ rows: z7.number().int().positive().optional(),
14263
+ cwdPath: z7.string().optional(),
14264
+ themeBackground: z7.string().regex(/^#[0-9a-fA-F]{3,8}$/).optional()
13863
14265
  }),
13864
14266
  async (args, ctx) => {
13865
14267
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -13905,9 +14307,9 @@ var init_terminal = __esm({
13905
14307
  );
13906
14308
  registerCommand(
13907
14309
  "terminal.replay",
13908
- z6.object({
13909
- terminalId: z6.string(),
13910
- lastSeq: z6.number().int().nonnegative().optional()
14310
+ z7.object({
14311
+ terminalId: z7.string(),
14312
+ lastSeq: z7.number().int().nonnegative().optional()
13911
14313
  }),
13912
14314
  async (args, ctx, clientId) => {
13913
14315
  const replay = ctx.terminalMgr.replay(args.terminalId, args.lastSeq ?? 0);
@@ -13932,8 +14334,8 @@ var init_terminal = __esm({
13932
14334
  );
13933
14335
  registerCommand(
13934
14336
  "terminal.snapshot",
13935
- z6.object({
13936
- terminalId: z6.string()
14337
+ z7.object({
14338
+ terminalId: z7.string()
13937
14339
  }),
13938
14340
  async (args, ctx, clientId) => {
13939
14341
  const snapshot = await ctx.terminalMgr.snapshot(args.terminalId);
@@ -13961,8 +14363,8 @@ var init_terminal = __esm({
13961
14363
  );
13962
14364
  registerCommand(
13963
14365
  "terminal.close",
13964
- z6.object({
13965
- terminalId: z6.string()
14366
+ z7.object({
14367
+ terminalId: z7.string()
13966
14368
  }),
13967
14369
  async (args, ctx) => {
13968
14370
  await ctx.terminalMgr.close(args.terminalId);
@@ -13984,10 +14386,10 @@ var init_terminal = __esm({
13984
14386
  });
13985
14387
  registerCommand(
13986
14388
  "terminal.resize",
13987
- z6.object({
13988
- terminalId: z6.string(),
13989
- cols: z6.number().int().positive(),
13990
- rows: z6.number().int().positive()
14389
+ z7.object({
14390
+ terminalId: z7.string(),
14391
+ cols: z7.number().int().positive(),
14392
+ rows: z7.number().int().positive()
13991
14393
  }),
13992
14394
  async (args, ctx) => {
13993
14395
  const sessionId = ctx.sessionMgr.findSessionIdByTerminal(args.terminalId);
@@ -14610,7 +15012,7 @@ var init_hub = __esm({
14610
15012
  }
14611
15013
  }
14612
15014
  awaitBinaryPayload(clientId) {
14613
- return new Promise((resolve6, reject) => {
15015
+ return new Promise((resolve8, reject) => {
14614
15016
  const timer = setTimeout(() => {
14615
15017
  const waiters = this.pendingBinaryWaiters.get(clientId);
14616
15018
  if (!waiters) return;
@@ -14622,7 +15024,7 @@ var init_hub = __esm({
14622
15024
  }
14623
15025
  reject(new Error("Timeout waiting for terminal input binary payload"));
14624
15026
  }, BINARY_PAYLOAD_TIMEOUT_MS);
14625
- const waiter = { resolve: resolve6, reject, timer };
15027
+ const waiter = { resolve: resolve8, reject, timer };
14626
15028
  const queue = this.pendingBinaryWaiters.get(clientId);
14627
15029
  if (queue) {
14628
15030
  queue.push(waiter);
@@ -14926,57 +15328,270 @@ var init_hub = __esm({
14926
15328
  }
14927
15329
  });
14928
15330
 
14929
- // packages/server/src/commands/workspace.ts
14930
- import { readdir as readdir3, realpath as realpath3 } from "node:fs/promises";
14931
- import { homedir as homedir2 } from "node:os";
14932
- import { isAbsolute as isAbsolute3, join as join11, resolve as resolve4 } from "node:path";
14933
- import { z as z7 } from "zod";
14934
- function resolveBrowsePath(path14) {
14935
- const home = homedir2();
14936
- if (!path14 || path14 === "~") {
14937
- return home;
15331
+ // packages/server/src/workspace/intelligence.ts
15332
+ import { access as access2, lstat as lstat2, readFile as readFile4, stat as stat9 } from "node:fs/promises";
15333
+ import { join as join12, resolve as resolve4 } from "node:path";
15334
+ async function inspectWorkspaceIntelligence(input2) {
15335
+ const [packageManager, manifest, git, docsExistence, agentsExists, frameworks] = await Promise.all([
15336
+ detectPackageManager(input2.rootPath),
15337
+ readPackageJson(input2.rootPath),
15338
+ detectGitState(input2.rootPath),
15339
+ detectDocs(input2.rootPath),
15340
+ pathExists(join12(input2.rootPath, AGENT_INSTRUCTIONS_RELATIVE_PATH)),
15341
+ detectFrameworks(input2.rootPath)
15342
+ ]);
15343
+ const scripts = extractScripts(manifest);
15344
+ return {
15345
+ workspaceId: input2.workspaceId,
15346
+ rootPath: input2.rootPath,
15347
+ git,
15348
+ packageManager,
15349
+ frameworks,
15350
+ scripts,
15351
+ recommendedCommands: buildRecommendedCommands(packageManager, scripts),
15352
+ docs: docsExistence,
15353
+ agentInstructions: {
15354
+ exists: agentsExists,
15355
+ path: AGENT_INSTRUCTIONS_RELATIVE_PATH
15356
+ }
15357
+ };
15358
+ }
15359
+ async function detectPackageManager(rootPath) {
15360
+ for (const candidate of packageManagerCandidates) {
15361
+ if (await pathExists(join12(rootPath, candidate.file))) {
15362
+ return candidate.manager;
15363
+ }
14938
15364
  }
14939
- if (path14.startsWith("~/")) {
14940
- return join11(home, path14.slice(2));
15365
+ if (await pathExists(join12(rootPath, "package.json"))) {
15366
+ return "npm";
14941
15367
  }
14942
- return isAbsolute3(path14) ? path14 : resolve4(home, path14);
15368
+ return void 0;
14943
15369
  }
14944
- async function buildRootPaths(currentPath) {
14945
- const roots = /* @__PURE__ */ new Set(["/"]);
14946
- const home = homedir2();
14947
- roots.add(home);
15370
+ async function readPackageJson(rootPath) {
15371
+ const packageJsonPath = join12(rootPath, "package.json");
15372
+ if (!await pathExists(packageJsonPath)) {
15373
+ return null;
15374
+ }
14948
15375
  try {
14949
- roots.add(await realpath3(home));
15376
+ const raw = await readFile4(packageJsonPath, "utf8");
15377
+ const parsed = JSON.parse(raw);
15378
+ return parsed && typeof parsed === "object" ? parsed : null;
14950
15379
  } catch {
15380
+ return null;
14951
15381
  }
14952
- const currentSegments = currentPath.split("/").filter(Boolean);
14953
- if (currentSegments.length > 0) {
14954
- roots.add(`/${currentSegments[0]}`);
15382
+ }
15383
+ function extractScripts(manifest) {
15384
+ const scripts = manifest?.scripts ?? {};
15385
+ return {
15386
+ dev: normalizeScript(scripts.dev),
15387
+ test: normalizeScript(scripts.test),
15388
+ build: normalizeScript(scripts.build),
15389
+ lint: normalizeScript(scripts.lint)
15390
+ };
15391
+ }
15392
+ function normalizeScript(value) {
15393
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
15394
+ }
15395
+ function buildRecommendedCommands(packageManager, scripts) {
15396
+ if (!packageManager) {
15397
+ return [];
14955
15398
  }
14956
- return Array.from(roots);
15399
+ return packageScriptKeys.flatMap((key) => {
15400
+ if (!scripts[key]) {
15401
+ return [];
15402
+ }
15403
+ return [
15404
+ {
15405
+ key,
15406
+ command: buildPackageCommand(packageManager, key),
15407
+ source: "package_json"
15408
+ }
15409
+ ];
15410
+ });
14957
15411
  }
14958
- var init_workspace = __esm({
14959
- "packages/server/src/commands/workspace.ts"() {
14960
- "use strict";
14961
- init_dispatch();
14962
- registerCommand("workspace.list", z7.object({}), async (_args, ctx) => {
14963
- return ctx.workspaceMgr.list();
14964
- });
14965
- registerCommand(
14966
- "workspace.browse",
14967
- z7.object({
14968
- path: z7.string().optional()
14969
- }),
14970
- async (args) => {
14971
- const basePath = resolveBrowsePath(args.path);
14972
- const entries = await readdir3(basePath, { withFileTypes: true });
14973
- const directories = entries.filter((entry) => entry.isDirectory()).map((entry) => ({
15412
+ function buildPackageCommand(packageManager, scriptName) {
15413
+ switch (packageManager) {
15414
+ case "pnpm":
15415
+ return `pnpm ${scriptName}`;
15416
+ case "yarn":
15417
+ return `yarn ${scriptName}`;
15418
+ case "bun":
15419
+ return `bun run ${scriptName}`;
15420
+ case "npm":
15421
+ default:
15422
+ return `npm run ${scriptName}`;
15423
+ }
15424
+ }
15425
+ async function detectFrameworks(rootPath) {
15426
+ const manifest = await readPackageJson(rootPath);
15427
+ const deps = {
15428
+ ...manifest?.dependencies ?? {},
15429
+ ...manifest?.devDependencies ?? {}
15430
+ };
15431
+ const frameworks = /* @__PURE__ */ new Set();
15432
+ if ("next" in deps) {
15433
+ frameworks.add("Next.js");
15434
+ }
15435
+ if ("react" in deps) {
15436
+ frameworks.add("React");
15437
+ }
15438
+ if ("vite" in deps || await hasAnyPath(rootPath, viteConfigFiles)) {
15439
+ frameworks.add("Vite");
15440
+ }
15441
+ if (manifest) {
15442
+ frameworks.add("Node");
15443
+ }
15444
+ if (await hasAnyPath(rootPath, ["pnpm-workspace.yaml", "turbo.json", "nx.json"])) {
15445
+ frameworks.add("Monorepo");
15446
+ }
15447
+ return frameworkOrder.filter((framework) => frameworks.has(framework));
15448
+ }
15449
+ async function detectGitState(rootPath) {
15450
+ const gitPath = join12(rootPath, ".git");
15451
+ let stats;
15452
+ try {
15453
+ stats = await lstat2(gitPath);
15454
+ } catch {
15455
+ return { isRepo: false };
15456
+ }
15457
+ const gitDir = stats.isDirectory() ? gitPath : stats.isFile() ? await resolveGitDirFromFile(rootPath, gitPath) : null;
15458
+ if (!gitDir) {
15459
+ return { isRepo: false };
15460
+ }
15461
+ const branch = await readGitBranch(gitDir);
15462
+ return branch ? { isRepo: true, branch } : { isRepo: true };
15463
+ }
15464
+ async function resolveGitDirFromFile(rootPath, gitFilePath) {
15465
+ try {
15466
+ const raw = await readFile4(gitFilePath, "utf8");
15467
+ const match = raw.match(/^gitdir:\s*(.+)\s*$/m);
15468
+ if (!match) {
15469
+ return null;
15470
+ }
15471
+ const gitDirPath = match[1];
15472
+ if (!gitDirPath) {
15473
+ return null;
15474
+ }
15475
+ return resolve4(rootPath, gitDirPath);
15476
+ } catch {
15477
+ return null;
15478
+ }
15479
+ }
15480
+ async function readGitBranch(gitDir) {
15481
+ try {
15482
+ const head = await readFile4(join12(gitDir, "HEAD"), "utf8");
15483
+ const refMatch = head.match(/^ref:\s*refs\/heads\/(.+)\s*$/);
15484
+ return refMatch?.[1];
15485
+ } catch {
15486
+ return void 0;
15487
+ }
15488
+ }
15489
+ async function detectDocs(rootPath) {
15490
+ const docs = [];
15491
+ if (await pathExists(join12(rootPath, "README.md"))) {
15492
+ docs.push({ path: "README.md", kind: "readme" });
15493
+ }
15494
+ if (await pathExists(join12(rootPath, "docs"))) {
15495
+ try {
15496
+ const docsStats = await stat9(join12(rootPath, "docs"));
15497
+ if (docsStats.isDirectory()) {
15498
+ docs.push({ path: "docs", kind: "docs" });
15499
+ }
15500
+ } catch {
15501
+ }
15502
+ }
15503
+ return docs;
15504
+ }
15505
+ async function hasAnyPath(rootPath, relativePaths) {
15506
+ for (const relativePath of relativePaths) {
15507
+ if (await pathExists(join12(rootPath, relativePath))) {
15508
+ return true;
15509
+ }
15510
+ }
15511
+ return false;
15512
+ }
15513
+ async function pathExists(path14) {
15514
+ try {
15515
+ await access2(path14);
15516
+ return true;
15517
+ } catch {
15518
+ return false;
15519
+ }
15520
+ }
15521
+ var frameworkOrder, packageManagerCandidates, packageScriptKeys, viteConfigFiles;
15522
+ var init_intelligence = __esm({
15523
+ "packages/server/src/workspace/intelligence.ts"() {
15524
+ "use strict";
15525
+ init_workspace_state();
15526
+ frameworkOrder = ["Next.js", "React", "Vite", "Node", "Monorepo"];
15527
+ packageManagerCandidates = [
15528
+ { file: "pnpm-lock.yaml", manager: "pnpm" },
15529
+ { file: "yarn.lock", manager: "yarn" },
15530
+ { file: "bun.lockb", manager: "bun" },
15531
+ { file: "package-lock.json", manager: "npm" }
15532
+ ];
15533
+ packageScriptKeys = ["dev", "test", "build", "lint"];
15534
+ viteConfigFiles = [
15535
+ "vite.config.ts",
15536
+ "vite.config.js",
15537
+ "vite.config.mjs",
15538
+ "vite.config.cjs"
15539
+ ];
15540
+ }
15541
+ });
15542
+
15543
+ // packages/server/src/commands/workspace.ts
15544
+ import { readdir as readdir3, realpath as realpath3 } from "node:fs/promises";
15545
+ import { homedir as homedir2 } from "node:os";
15546
+ import { isAbsolute as isAbsolute3, join as join13, resolve as resolve5 } from "node:path";
15547
+ import { z as z8 } from "zod";
15548
+ function resolveBrowsePath(path14) {
15549
+ const home = homedir2();
15550
+ if (!path14 || path14 === "~") {
15551
+ return home;
15552
+ }
15553
+ if (path14.startsWith("~/")) {
15554
+ return join13(home, path14.slice(2));
15555
+ }
15556
+ return isAbsolute3(path14) ? path14 : resolve5(home, path14);
15557
+ }
15558
+ async function buildRootPaths(currentPath) {
15559
+ const roots = /* @__PURE__ */ new Set(["/"]);
15560
+ const home = homedir2();
15561
+ roots.add(home);
15562
+ try {
15563
+ roots.add(await realpath3(home));
15564
+ } catch {
15565
+ }
15566
+ const currentSegments = currentPath.split("/").filter(Boolean);
15567
+ if (currentSegments.length > 0) {
15568
+ roots.add(`/${currentSegments[0]}`);
15569
+ }
15570
+ return Array.from(roots);
15571
+ }
15572
+ var init_workspace = __esm({
15573
+ "packages/server/src/commands/workspace.ts"() {
15574
+ "use strict";
15575
+ init_intelligence();
15576
+ init_dispatch();
15577
+ registerCommand("workspace.list", z8.object({}), async (_args, ctx) => {
15578
+ return ctx.workspaceMgr.list();
15579
+ });
15580
+ registerCommand(
15581
+ "workspace.browse",
15582
+ z8.object({
15583
+ path: z8.string().optional()
15584
+ }),
15585
+ async (args) => {
15586
+ const basePath = resolveBrowsePath(args.path);
15587
+ const entries = await readdir3(basePath, { withFileTypes: true });
15588
+ const directories = entries.filter((entry) => entry.isDirectory()).map((entry) => ({
14974
15589
  name: entry.name,
14975
- path: join11(basePath, entry.name)
15590
+ path: join13(basePath, entry.name)
14976
15591
  })).sort((a, b) => a.name.localeCompare(b.name));
14977
15592
  return {
14978
15593
  currentPath: basePath,
14979
- parentPath: basePath !== "/" ? join11(basePath, "..") : null,
15594
+ parentPath: basePath !== "/" ? join13(basePath, "..") : null,
14980
15595
  directories,
14981
15596
  rootPaths: await buildRootPaths(basePath)
14982
15597
  };
@@ -14984,8 +15599,8 @@ var init_workspace = __esm({
14984
15599
  );
14985
15600
  registerCommand(
14986
15601
  "workspace.open",
14987
- z7.object({
14988
- path: z7.string()
15602
+ z8.object({
15603
+ path: z8.string()
14989
15604
  }),
14990
15605
  async (args, ctx) => {
14991
15606
  return ctx.workspaceMgr.open({
@@ -14993,10 +15608,26 @@ var init_workspace = __esm({
14993
15608
  });
14994
15609
  }
14995
15610
  );
15611
+ registerCommand(
15612
+ "workspace.intelligence",
15613
+ z8.object({
15614
+ workspaceId: z8.string()
15615
+ }),
15616
+ async (args, ctx) => {
15617
+ const workspace = ctx.workspaceMgr.get(args.workspaceId);
15618
+ if (!workspace) {
15619
+ throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
15620
+ }
15621
+ return inspectWorkspaceIntelligence({
15622
+ workspaceId: workspace.id,
15623
+ rootPath: workspace.path
15624
+ });
15625
+ }
15626
+ );
14996
15627
  registerCommand(
14997
15628
  "workspace.close",
14998
- z7.object({
14999
- id: z7.string()
15629
+ z8.object({
15630
+ id: z8.string()
15000
15631
  }),
15001
15632
  async (args, ctx) => {
15002
15633
  await ctx.workspaceMgr.close(args.id);
@@ -15004,27 +15635,27 @@ var init_workspace = __esm({
15004
15635
  );
15005
15636
  registerCommand(
15006
15637
  "workspace.uiState.set",
15007
- z7.object({
15008
- workspaceId: z7.string(),
15009
- uiState: z7.object({
15010
- leftPanelWidth: z7.number(),
15011
- bottomPanelHeight: z7.number(),
15012
- focusMode: z7.boolean(),
15013
- activeSessionId: z7.string().optional(),
15014
- fileTreeExpandedDirs: z7.array(z7.string()).optional(),
15015
- paneLayout: z7.object({
15016
- id: z7.string(),
15017
- type: z7.enum(["leaf", "split"]),
15018
- sessionId: z7.string().optional(),
15019
- direction: z7.enum(["horizontal", "vertical"]).optional(),
15020
- children: z7.lazy(
15021
- () => z7.array(
15022
- z7.object({
15023
- id: z7.string(),
15024
- type: z7.enum(["leaf", "split"]),
15025
- sessionId: z7.string().optional(),
15026
- direction: z7.enum(["horizontal", "vertical"]).optional(),
15027
- children: z7.any().optional()
15638
+ z8.object({
15639
+ workspaceId: z8.string(),
15640
+ uiState: z8.object({
15641
+ leftPanelWidth: z8.number(),
15642
+ bottomPanelHeight: z8.number(),
15643
+ focusMode: z8.boolean(),
15644
+ activeSessionId: z8.string().optional(),
15645
+ fileTreeExpandedDirs: z8.array(z8.string()).optional(),
15646
+ paneLayout: z8.object({
15647
+ id: z8.string(),
15648
+ type: z8.enum(["leaf", "split"]),
15649
+ sessionId: z8.string().optional(),
15650
+ direction: z8.enum(["horizontal", "vertical"]).optional(),
15651
+ children: z8.lazy(
15652
+ () => z8.array(
15653
+ z8.object({
15654
+ id: z8.string(),
15655
+ type: z8.enum(["leaf", "split"]),
15656
+ sessionId: z8.string().optional(),
15657
+ direction: z8.enum(["horizontal", "vertical"]).optional(),
15658
+ children: z8.any().optional()
15028
15659
  })
15029
15660
  )
15030
15661
  ).optional()
@@ -15044,7 +15675,7 @@ var init_workspace = __esm({
15044
15675
  });
15045
15676
 
15046
15677
  // packages/server/src/commands/workspace-activity.ts
15047
- import { z as z8 } from "zod";
15678
+ import { z as z9 } from "zod";
15048
15679
  function parseWorkspaceLastViewedTarget(value) {
15049
15680
  try {
15050
15681
  const parsed = JSON.parse(value);
@@ -15060,15 +15691,15 @@ var init_workspace_activity = __esm({
15060
15691
  "use strict";
15061
15692
  init_dispatch();
15062
15693
  WORKSPACE_LAST_VIEWED_TARGET_KEY = "workspace.lastViewedTarget";
15063
- workspaceLastViewedTargetSchema = z8.object({
15064
- workspaceId: z8.string(),
15065
- sessionId: z8.string().optional(),
15066
- updatedAt: z8.number()
15694
+ workspaceLastViewedTargetSchema = z9.object({
15695
+ workspaceId: z9.string(),
15696
+ sessionId: z9.string().optional(),
15697
+ updatedAt: z9.number()
15067
15698
  });
15068
15699
  registerCommand(
15069
15700
  "workspace.activate",
15070
- z8.object({
15071
- workspaceId: z8.string()
15701
+ z9.object({
15702
+ workspaceId: z9.string()
15072
15703
  }),
15073
15704
  async (args, ctx, clientId) => {
15074
15705
  if (!clientId) {
@@ -15078,14 +15709,14 @@ var init_workspace_activity = __esm({
15078
15709
  return {};
15079
15710
  }
15080
15711
  );
15081
- registerCommand("workspace.deactivate", z8.object({}), async (_args, ctx, clientId) => {
15712
+ registerCommand("workspace.deactivate", z9.object({}), async (_args, ctx, clientId) => {
15082
15713
  if (!clientId) {
15083
15714
  return {};
15084
15715
  }
15085
15716
  ctx.autoFetch.unregisterViewer(clientId);
15086
15717
  return {};
15087
15718
  });
15088
- registerCommand("workspace.lastViewedTarget.get", z8.object({}), async (_args, ctx) => {
15719
+ registerCommand("workspace.lastViewedTarget.get", z9.object({}), async (_args, ctx) => {
15089
15720
  const value = ctx.settingsRepo.get(WORKSPACE_LAST_VIEWED_TARGET_KEY);
15090
15721
  if (value === void 0) {
15091
15722
  return null;
@@ -15094,9 +15725,9 @@ var init_workspace_activity = __esm({
15094
15725
  });
15095
15726
  registerCommand(
15096
15727
  "workspace.lastViewedTarget.set",
15097
- z8.object({
15098
- workspaceId: z8.string(),
15099
- sessionId: z8.string().optional()
15728
+ z9.object({
15729
+ workspaceId: z9.string(),
15730
+ sessionId: z9.string().optional()
15100
15731
  }),
15101
15732
  async (args, ctx) => {
15102
15733
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -15120,14 +15751,14 @@ var init_workspace_activity = __esm({
15120
15751
  });
15121
15752
 
15122
15753
  // packages/server/src/commands/activation.ts
15123
- import { z as z9 } from "zod";
15754
+ import { z as z10 } from "zod";
15124
15755
  var init_activation2 = __esm({
15125
15756
  "packages/server/src/commands/activation.ts"() {
15126
15757
  "use strict";
15127
15758
  init_dispatch();
15128
15759
  registerCommand(
15129
15760
  "activation.claim",
15130
- z9.object({ clientInstanceId: z9.string().min(1) }),
15761
+ z10.object({ clientInstanceId: z10.string().min(1) }),
15131
15762
  async (args, ctx, clientId) => {
15132
15763
  if (!clientId) {
15133
15764
  throw {
@@ -15151,7 +15782,7 @@ var init_activation2 = __esm({
15151
15782
  );
15152
15783
  registerCommand(
15153
15784
  "activation.release",
15154
- z9.object({ clientInstanceId: z9.string(), generation: z9.number().int().positive() }),
15785
+ z10.object({ clientInstanceId: z10.string(), generation: z10.number().int().positive() }),
15155
15786
  async (args, ctx, clientId) => {
15156
15787
  const lease = ctx.activationMgr.getLease();
15157
15788
  if (!clientId || !lease || lease.wsClientId !== clientId) {
@@ -15165,34 +15796,34 @@ var init_activation2 = __esm({
15165
15796
  });
15166
15797
 
15167
15798
  // packages/server/src/commands/connection.ts
15168
- import { z as z10 } from "zod";
15799
+ import { z as z11 } from "zod";
15169
15800
  var init_connection = __esm({
15170
15801
  "packages/server/src/commands/connection.ts"() {
15171
15802
  "use strict";
15172
15803
  init_dispatch();
15173
- registerCommand("connection.probe", z10.object({}).default({}), async () => {
15804
+ registerCommand("connection.probe", z11.object({}).default({}), async () => {
15174
15805
  return { ok: true };
15175
15806
  });
15176
15807
  }
15177
15808
  });
15178
15809
 
15179
15810
  // packages/server/src/commands/recovery.ts
15180
- import { z as z11 } from "zod";
15811
+ import { z as z12 } from "zod";
15181
15812
  var RecoveryReasonSchema;
15182
15813
  var init_recovery = __esm({
15183
15814
  "packages/server/src/commands/recovery.ts"() {
15184
15815
  "use strict";
15185
15816
  init_src3();
15186
15817
  init_dispatch();
15187
- RecoveryReasonSchema = z11.enum(RECOVERY_REASONS);
15818
+ RecoveryReasonSchema = z12.enum(RECOVERY_REASONS);
15188
15819
  registerCommand(
15189
15820
  "recovery.reconcile",
15190
- z11.object({
15821
+ z12.object({
15191
15822
  reason: RecoveryReasonSchema,
15192
- terminals: z11.array(
15193
- z11.object({
15194
- terminalId: z11.string(),
15195
- renderedSeq: z11.number().int().nonnegative()
15823
+ terminals: z12.array(
15824
+ z12.object({
15825
+ terminalId: z12.string(),
15826
+ renderedSeq: z12.number().int().nonnegative()
15196
15827
  })
15197
15828
  )
15198
15829
  }),
@@ -15438,15 +16069,33 @@ var init_pane_layout = __esm({
15438
16069
  });
15439
16070
 
15440
16071
  // packages/server/src/commands/session.ts
15441
- import { z as z12 } from "zod";
16072
+ import { readFile as readFile5 } from "node:fs/promises";
16073
+ import { join as join14, resolve as resolve6 } from "node:path";
16074
+ import { z as z13 } from "zod";
15442
16075
  function delay(ms) {
15443
- return new Promise((resolve6) => {
15444
- setTimeout(resolve6, ms);
16076
+ return new Promise((resolve8) => {
16077
+ setTimeout(resolve8, ms);
15445
16078
  });
15446
16079
  }
15447
16080
  function getProviderFromRegistry(providerId, registry) {
15448
16081
  return registry.find((provider) => provider.id === providerId);
15449
16082
  }
16083
+ async function tryReadGitHead(workspacePath) {
16084
+ try {
16085
+ const gitEntryPath = join14(workspacePath, ".git");
16086
+ const gitEntry = await readFile5(gitEntryPath, "utf8").catch(() => null);
16087
+ let gitDir = gitEntryPath;
16088
+ if (gitEntry && gitEntry.startsWith("gitdir:")) {
16089
+ const relativeGitDir = gitEntry.slice("gitdir:".length).trim();
16090
+ gitDir = resolve6(workspacePath, relativeGitDir);
16091
+ }
16092
+ const head = await readFile5(join14(gitDir, "HEAD"), "utf8");
16093
+ const trimmed = head.trim();
16094
+ return trimmed.length > 0 && !trimmed.startsWith("ref:") ? trimmed : void 0;
16095
+ } catch {
16096
+ return void 0;
16097
+ }
16098
+ }
15450
16099
  var SESSION_CLOSE_POLL_INTERVAL_MS, SESSION_CLOSE_TIMEOUT_MS;
15451
16100
  var init_session2 = __esm({
15452
16101
  "packages/server/src/commands/session.ts"() {
@@ -15458,8 +16107,8 @@ var init_session2 = __esm({
15458
16107
  SESSION_CLOSE_TIMEOUT_MS = 5e3;
15459
16108
  registerCommand(
15460
16109
  "session.list",
15461
- z12.object({
15462
- workspaceId: z12.string()
16110
+ z13.object({
16111
+ workspaceId: z13.string()
15463
16112
  }),
15464
16113
  async (args, ctx) => {
15465
16114
  return ctx.sessionMgr.getForWorkspace(args.workspaceId);
@@ -15467,11 +16116,11 @@ var init_session2 = __esm({
15467
16116
  );
15468
16117
  registerCommand(
15469
16118
  "session.create",
15470
- z12.object({
15471
- workspaceId: z12.string(),
15472
- providerId: z12.string(),
15473
- draft: z12.string().optional(),
15474
- themeBackground: z12.string().regex(/^#[0-9a-fA-F]{3,8}$/).optional()
16119
+ z13.object({
16120
+ workspaceId: z13.string(),
16121
+ providerId: z13.string(),
16122
+ draft: z13.string().optional(),
16123
+ themeBackground: z13.string().regex(/^#[0-9a-fA-F]{3,8}$/).optional()
15475
16124
  }),
15476
16125
  async (args, ctx) => {
15477
16126
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -15494,7 +16143,7 @@ var init_session2 = __esm({
15494
16143
  }
15495
16144
  };
15496
16145
  }
15497
- return ctx.sessionMgr.create({
16146
+ const session = await ctx.sessionMgr.create({
15498
16147
  workspaceId: args.workspaceId,
15499
16148
  workspacePath: workspace.path,
15500
16149
  providerId: args.providerId,
@@ -15502,12 +16151,22 @@ var init_session2 = __esm({
15502
16151
  draft: args.draft,
15503
16152
  themeBackground: args.themeBackground
15504
16153
  });
16154
+ ctx.sessionMetadataRepo?.upsert({
16155
+ sessionId: session.id,
16156
+ workspaceId: args.workspaceId,
16157
+ providerId: args.providerId,
16158
+ objective: args.draft?.trim() || void 0,
16159
+ baselineGitHead: await tryReadGitHead(workspace.path),
16160
+ baselineCapturedAt: Date.now(),
16161
+ verificationRuns: []
16162
+ });
16163
+ return session;
15505
16164
  }
15506
16165
  );
15507
16166
  registerCommand(
15508
16167
  "session.stop",
15509
- z12.object({
15510
- sessionId: z12.string()
16168
+ z13.object({
16169
+ sessionId: z13.string()
15511
16170
  }),
15512
16171
  async (args, ctx) => {
15513
16172
  await ctx.sessionMgr.stop(args.sessionId);
@@ -15515,8 +16174,8 @@ var init_session2 = __esm({
15515
16174
  );
15516
16175
  registerCommand(
15517
16176
  "session.remove",
15518
- z12.object({
15519
- sessionId: z12.string()
16177
+ z13.object({
16178
+ sessionId: z13.string()
15520
16179
  }),
15521
16180
  async (args, ctx) => {
15522
16181
  const session = ctx.sessionMgr.get(args.sessionId);
@@ -15527,13 +16186,14 @@ var init_session2 = __esm({
15527
16186
  throw { code: "invalid_state", message: `Cannot remove session in state: ${session.state}` };
15528
16187
  }
15529
16188
  ctx.sessionMgr.delete(args.sessionId);
16189
+ ctx.sessionMetadataRepo?.delete(args.sessionId);
15530
16190
  }
15531
16191
  );
15532
16192
  registerCommand(
15533
16193
  "session.close",
15534
- z12.object({
15535
- sessionId: z12.string(),
15536
- paneDisposition: z12.enum(["draft", "remove"]).default("draft")
16194
+ z13.object({
16195
+ sessionId: z13.string(),
16196
+ paneDisposition: z13.enum(["draft", "remove"]).default("draft")
15537
16197
  }),
15538
16198
  async (args, ctx) => {
15539
16199
  let session = ctx.sessionMgr.get(args.sessionId);
@@ -15589,112 +16249,553 @@ var init_session2 = __esm({
15589
16249
  };
15590
16250
  ctx.workspaceMgr.updateUiState(session.workspaceId, nextUiState);
15591
16251
  ctx.sessionMgr.delete(args.sessionId);
16252
+ ctx.sessionMetadataRepo?.delete(args.sessionId);
15592
16253
  }
15593
16254
  );
15594
16255
  }
15595
16256
  });
15596
16257
 
15597
- // packages/server/src/fs/content-search.ts
15598
- import { spawn as spawn5 } from "child_process";
15599
- import { existsSync as existsSync8 } from "fs";
15600
- import { readdir as readdir4, readFile as readFile4, stat as stat9 } from "fs/promises";
15601
- import { basename as basename2, join as join12, relative as relative3 } from "path";
15602
- import { createInterface } from "readline";
15603
- async function searchFileContents(rootPath, options) {
15604
- const query = options.query.trim();
15605
- if (!query) {
15606
- return {
15607
- files: [],
15608
- totalMatchCount: 0,
15609
- hasMoreFiles: false,
15610
- truncatedMatchFileCount: 0
16258
+ // packages/server/src/commands/session-metadata.ts
16259
+ import { randomUUID as randomUUID6 } from "node:crypto";
16260
+ import { z as z14 } from "zod";
16261
+ function requireSessionMetadataRepo(ctx) {
16262
+ if (!ctx.sessionMetadataRepo) {
16263
+ throw {
16264
+ code: "session_metadata_unavailable",
16265
+ message: "Session metadata repository is not configured"
15611
16266
  };
15612
16267
  }
15613
- const result = await searchWithRipgrep(rootPath, query, options.maxFiles).catch(
15614
- async (error) => {
15615
- if (error.code === "ENOENT") {
15616
- return searchWithNode(rootPath, query, options.maxFiles);
15617
- }
15618
- throw error;
15619
- }
15620
- );
15621
- return finalizeResults(result, options.maxFiles, options.maxMatchesPerFile);
15622
16268
  }
15623
- async function searchWithRipgrep(rootPath, query, maxFiles) {
15624
- const hasGitignore = existsSync8(join12(rootPath, ".gitignore"));
15625
- const args = [
15626
- "--json",
15627
- "--line-number",
15628
- "--column",
15629
- "--fixed-strings",
15630
- "--sort",
15631
- "path",
15632
- "--with-filename",
15633
- "--glob",
15634
- "!**/.git/**",
15635
- "--glob",
15636
- "!**/node_modules/**"
15637
- ];
15638
- if (hasGitignore) {
15639
- args.push("--hidden");
15640
- args.push("--no-require-git");
15641
- }
15642
- args.push(query, ".");
15643
- return new Promise((resolve6, reject) => {
15644
- const child = spawn5("rg", args, { cwd: rootPath, stdio: ["ignore", "pipe", "pipe"] });
15645
- const stdout = createInterface({ input: child.stdout });
15646
- const files = /* @__PURE__ */ new Map();
15647
- let totalMatchCount = 0;
15648
- let hasMoreFiles = false;
15649
- let stderr = "";
15650
- stdout.on("line", (line) => {
15651
- if (!line.trim()) {
15652
- return;
15653
- }
15654
- const event = JSON.parse(line);
15655
- if (event.type !== "match") {
15656
- return;
15657
- }
15658
- const rawPath = event.data?.path?.text;
15659
- if (!rawPath) {
15660
- return;
15661
- }
15662
- const relativePath = normalizeRelativePath(relative3(rootPath, join12(rootPath, rawPath)));
15663
- const preview = (event.data?.lines?.text ?? "").replace(/\r?\n$/, "");
15664
- const lineNumber = event.data?.line_number ?? 1;
15665
- const submatches = event.data?.submatches ?? [];
15666
- totalMatchCount += submatches.length;
15667
- if (!files.has(relativePath) && files.size >= maxFiles) {
15668
- hasMoreFiles = true;
15669
- return;
16269
+ var init_session_metadata = __esm({
16270
+ "packages/server/src/commands/session-metadata.ts"() {
16271
+ "use strict";
16272
+ init_dispatch();
16273
+ registerCommand(
16274
+ "session.metadata.get",
16275
+ z14.object({
16276
+ sessionId: z14.string()
16277
+ }),
16278
+ async (args, ctx) => {
16279
+ requireSessionMetadataRepo(ctx);
16280
+ const metadata = ctx.sessionMetadataRepo.get(args.sessionId);
16281
+ if (!metadata) {
16282
+ throw {
16283
+ code: "session_metadata_not_found",
16284
+ message: `Session metadata not found: ${args.sessionId}`
16285
+ };
16286
+ }
16287
+ return metadata;
15670
16288
  }
15671
- for (const submatch of submatches) {
15672
- pushMatch(files, relativePath, {
15673
- line: lineNumber,
15674
- column: byteOffsetToColumn(preview, submatch.start),
15675
- endColumn: byteOffsetToColumn(preview, submatch.end),
15676
- preview,
15677
- previewColumnStart: byteOffsetToColumn(preview, submatch.start),
15678
- previewColumnEnd: byteOffsetToColumn(preview, submatch.end)
16289
+ );
16290
+ registerCommand(
16291
+ "session.verification.add",
16292
+ z14.object({
16293
+ sessionId: z14.string(),
16294
+ command: z14.string().trim().min(1),
16295
+ status: z14.enum(["passed", "failed", "unknown"]),
16296
+ exitCode: z14.number().int().optional(),
16297
+ summary: z14.string().optional()
16298
+ }),
16299
+ async (args, ctx) => {
16300
+ requireSessionMetadataRepo(ctx);
16301
+ return ctx.sessionMetadataRepo.addVerificationRun(args.sessionId, {
16302
+ id: randomUUID6(),
16303
+ command: args.command,
16304
+ status: args.status,
16305
+ exitCode: args.exitCode,
16306
+ summary: args.summary?.trim() || void 0,
16307
+ createdAt: Date.now()
15679
16308
  });
15680
16309
  }
15681
- });
15682
- child.stderr.on("data", (chunk) => {
15683
- stderr += chunk.toString();
15684
- });
15685
- child.on("error", (error) => {
15686
- void stdout.close();
15687
- reject(error);
15688
- });
15689
- child.on("close", (code) => {
15690
- void stdout.close();
15691
- if (code === 0 || code === 1) {
15692
- resolve6({
15693
- files: sortAccumulators(files),
15694
- totalMatchCount,
15695
- hasMoreFiles
15696
- });
15697
- return;
16310
+ );
16311
+ }
16312
+ });
16313
+
16314
+ // packages/server/src/git/diff.ts
16315
+ import { mkdtemp as mkdtemp3, readFile as readFile6, rm as rm7 } from "fs/promises";
16316
+ import os3 from "os";
16317
+ import path11 from "path";
16318
+ async function isTrackedPath(cwd, filePath) {
16319
+ try {
16320
+ await runGit(cwd, ["ls-files", "--error-unmatch", "--", filePath]);
16321
+ return true;
16322
+ } catch {
16323
+ return false;
16324
+ }
16325
+ }
16326
+ async function getUntrackedFileDiff(cwd, filePath) {
16327
+ const tempDir = await mkdtemp3(path11.join(os3.tmpdir(), "coder-studio-git-diff-"));
16328
+ const tempIndex = path11.join(tempDir, "index");
16329
+ try {
16330
+ try {
16331
+ await runGit(cwd, ["read-tree", "HEAD"], {
16332
+ env: { GIT_INDEX_FILE: tempIndex }
16333
+ });
16334
+ } catch (error) {
16335
+ if (!(error instanceof GitError)) {
16336
+ throw error;
16337
+ }
16338
+ await runGit(cwd, ["read-tree", "--empty"], {
16339
+ env: { GIT_INDEX_FILE: tempIndex }
16340
+ });
16341
+ }
16342
+ await runGit(cwd, ["add", "-N", "--", filePath], {
16343
+ env: { GIT_INDEX_FILE: tempIndex }
16344
+ });
16345
+ const result = await runGit(cwd, ["diff", "--", filePath], {
16346
+ env: { GIT_INDEX_FILE: tempIndex }
16347
+ });
16348
+ return result.stdout;
16349
+ } finally {
16350
+ await rm7(tempDir, { recursive: true, force: true });
16351
+ }
16352
+ }
16353
+ async function pathExists2(cwd, filePath) {
16354
+ try {
16355
+ await readFile6(resolveSafe(cwd, filePath));
16356
+ return true;
16357
+ } catch {
16358
+ return false;
16359
+ }
16360
+ }
16361
+ async function readTextAtRevision(cwd, revision, filePath) {
16362
+ if (revision === "WORKTREE") {
16363
+ return readFile6(resolveSafe(cwd, filePath), "utf-8");
16364
+ }
16365
+ try {
16366
+ const gitSpec = revision === "INDEX" ? `:${filePath}` : `${revision}:${filePath}`;
16367
+ const result = await runGit(cwd, ["show", gitSpec]);
16368
+ return result.stdout;
16369
+ } catch {
16370
+ return "";
16371
+ }
16372
+ }
16373
+ async function deriveFileDiffStatus(cwd, filePath, staged) {
16374
+ const tracked = await isTrackedPath(cwd, filePath);
16375
+ const existsOnDisk = await pathExists2(cwd, filePath);
16376
+ if (!staged && !tracked) {
16377
+ return "added";
16378
+ }
16379
+ if (staged) {
16380
+ try {
16381
+ await runGit(cwd, ["cat-file", "-e", `HEAD:${filePath}`]);
16382
+ return existsOnDisk ? "modified" : "deleted";
16383
+ } catch {
16384
+ return "added";
16385
+ }
16386
+ }
16387
+ return existsOnDisk ? "modified" : "deleted";
16388
+ }
16389
+ async function buildTextDiffResult(cwd, filePath, staged, diff) {
16390
+ const status = await deriveFileDiffStatus(cwd, filePath, staged);
16391
+ if (status === "added") {
16392
+ return {
16393
+ diff,
16394
+ renderAs: "text",
16395
+ status,
16396
+ originalContent: "",
16397
+ modifiedContent: await readTextAtRevision(cwd, staged ? "INDEX" : "WORKTREE", filePath)
16398
+ };
16399
+ }
16400
+ if (status === "deleted") {
16401
+ return {
16402
+ diff,
16403
+ renderAs: "text",
16404
+ status,
16405
+ originalContent: await readTextAtRevision(cwd, staged ? "HEAD" : "INDEX", filePath),
16406
+ modifiedContent: ""
16407
+ };
16408
+ }
16409
+ return {
16410
+ diff,
16411
+ renderAs: "text",
16412
+ status,
16413
+ originalContent: await readTextAtRevision(cwd, staged ? "HEAD" : "INDEX", filePath),
16414
+ modifiedContent: await readTextAtRevision(cwd, staged ? "INDEX" : "WORKTREE", filePath)
16415
+ };
16416
+ }
16417
+ async function getFileDiff(cwd, path14, staged = false) {
16418
+ const imageType = getImageTypeInfo(path14);
16419
+ if (!staged && !await isTrackedPath(cwd, path14)) {
16420
+ const diff = await getUntrackedFileDiff(cwd, path14);
16421
+ if (imageType) {
16422
+ return {
16423
+ diff,
16424
+ renderAs: "image",
16425
+ status: "added",
16426
+ originalRevision: "HEAD",
16427
+ modifiedRevision: "WORKTREE"
16428
+ };
16429
+ }
16430
+ return buildTextDiffResult(cwd, path14, staged, diff);
16431
+ }
16432
+ const args = staged ? ["diff", "--staged", "--", path14] : ["diff", "--", path14];
16433
+ const result = await runGit(cwd, args);
16434
+ if (imageType && /Binary files .* differ/.test(result.stdout)) {
16435
+ return {
16436
+ diff: result.stdout,
16437
+ renderAs: "image",
16438
+ status: await deriveFileDiffStatus(cwd, path14, staged),
16439
+ originalRevision: staged ? "HEAD" : "INDEX",
16440
+ modifiedRevision: staged ? "INDEX" : "WORKTREE"
16441
+ };
16442
+ }
16443
+ return buildTextDiffResult(cwd, path14, staged, result.stdout);
16444
+ }
16445
+ var init_diff = __esm({
16446
+ "packages/server/src/git/diff.ts"() {
16447
+ "use strict";
16448
+ init_file_io();
16449
+ init_image();
16450
+ init_cli();
16451
+ }
16452
+ });
16453
+
16454
+ // packages/server/src/session-review/review.ts
16455
+ function isWorkspaceStatePath(path14) {
16456
+ return path14 === WORKSPACE_STATE_DIR || path14.startsWith(`${WORKSPACE_STATE_DIR}/`);
16457
+ }
16458
+ function requireSessionMetadata(metadataRepo, sessionId) {
16459
+ const metadata = metadataRepo.get(sessionId);
16460
+ if (!metadata) {
16461
+ throw {
16462
+ code: "session_metadata_not_found",
16463
+ message: `Session metadata not found: ${sessionId}`
16464
+ };
16465
+ }
16466
+ return metadata;
16467
+ }
16468
+ async function isGitRepository(workspacePath) {
16469
+ try {
16470
+ await runGit(workspacePath, ["rev-parse", "--git-dir"]);
16471
+ return true;
16472
+ } catch (error) {
16473
+ if (error instanceof GitError) {
16474
+ return false;
16475
+ }
16476
+ throw error;
16477
+ }
16478
+ }
16479
+ function compareGitChanges(a, b) {
16480
+ const pathCompare = a.path.localeCompare(b.path);
16481
+ if (pathCompare !== 0) {
16482
+ return pathCompare;
16483
+ }
16484
+ return (a.oldPath ?? "").localeCompare(b.oldPath ?? "");
16485
+ }
16486
+ function mapGitStatus(code) {
16487
+ switch (code[0]) {
16488
+ case "A":
16489
+ return "added";
16490
+ case "D":
16491
+ return "deleted";
16492
+ case "M":
16493
+ default:
16494
+ return "modified";
16495
+ }
16496
+ }
16497
+ async function listTrackedChangesSinceBaseline(workspacePath, baselineGitHead) {
16498
+ const { stdout } = await runGit(workspacePath, [
16499
+ "diff",
16500
+ "--name-status",
16501
+ "--find-renames",
16502
+ baselineGitHead,
16503
+ "--"
16504
+ ]);
16505
+ const changes = stdout.split("\n").map((line) => line.trim()).filter((line) => line.length > 0).map((line) => {
16506
+ const parts = line.split(" ");
16507
+ const statusCode = parts[0] ?? "M";
16508
+ if (statusCode.startsWith("R")) {
16509
+ const oldPath = parts[1];
16510
+ const path15 = parts[2];
16511
+ if (!oldPath || !path15) {
16512
+ return null;
16513
+ }
16514
+ return {
16515
+ oldPath,
16516
+ path: path15,
16517
+ status: "renamed"
16518
+ };
16519
+ }
16520
+ const path14 = parts[1];
16521
+ if (!path14) {
16522
+ return null;
16523
+ }
16524
+ return {
16525
+ path: path14,
16526
+ status: mapGitStatus(statusCode)
16527
+ };
16528
+ });
16529
+ return changes.filter((change) => change !== null).filter((change) => !isWorkspaceStatePath(change.path)).sort(compareGitChanges);
16530
+ }
16531
+ async function listUntrackedChanges(workspacePath) {
16532
+ const { stdout } = await runGit(workspacePath, ["ls-files", "--others", "--exclude-standard"]);
16533
+ return stdout.split("\n").map((line) => line.trim()).filter((line) => line.length > 0).map((path14) => ({
16534
+ path: path14,
16535
+ status: "untracked"
16536
+ })).filter((change) => !isWorkspaceStatePath(change.path)).sort(compareGitChanges);
16537
+ }
16538
+ async function isUntrackedPath(workspacePath, filePath) {
16539
+ const { stdout } = await runGit(workspacePath, [
16540
+ "ls-files",
16541
+ "--others",
16542
+ "--exclude-standard",
16543
+ "--",
16544
+ filePath
16545
+ ]);
16546
+ return stdout.trim().length > 0;
16547
+ }
16548
+ async function buildSessionReviewSummary(input2) {
16549
+ const metadata = requireSessionMetadata(input2.metadataRepo, input2.sessionId);
16550
+ if (!metadata.baselineGitHead) {
16551
+ return {
16552
+ sessionId: metadata.sessionId,
16553
+ workspaceId: metadata.workspaceId,
16554
+ baselineGitHead: metadata.baselineGitHead,
16555
+ changedFiles: [],
16556
+ verificationRuns: metadata.verificationRuns,
16557
+ warnings: [MISSING_BASELINE_WARNING]
16558
+ };
16559
+ }
16560
+ if (!await isGitRepository(input2.workspacePath)) {
16561
+ return {
16562
+ sessionId: metadata.sessionId,
16563
+ workspaceId: metadata.workspaceId,
16564
+ baselineGitHead: metadata.baselineGitHead,
16565
+ changedFiles: [],
16566
+ verificationRuns: metadata.verificationRuns,
16567
+ warnings: [NOT_GIT_REPO_WARNING]
16568
+ };
16569
+ }
16570
+ const trackedChanges = await listTrackedChangesSinceBaseline(
16571
+ input2.workspacePath,
16572
+ metadata.baselineGitHead
16573
+ );
16574
+ const trackedPaths = new Set(trackedChanges.map((change) => change.path));
16575
+ const untrackedChanges = (await listUntrackedChanges(input2.workspacePath)).filter(
16576
+ (change) => !trackedPaths.has(change.path)
16577
+ );
16578
+ return {
16579
+ sessionId: metadata.sessionId,
16580
+ workspaceId: metadata.workspaceId,
16581
+ baselineGitHead: metadata.baselineGitHead,
16582
+ changedFiles: [...trackedChanges, ...untrackedChanges],
16583
+ verificationRuns: metadata.verificationRuns,
16584
+ warnings: []
16585
+ };
16586
+ }
16587
+ async function getSessionReviewDiff(input2) {
16588
+ const metadata = requireSessionMetadata(input2.metadataRepo, input2.sessionId);
16589
+ if (!metadata.baselineGitHead) {
16590
+ return "";
16591
+ }
16592
+ if (!await isGitRepository(input2.workspacePath)) {
16593
+ return "";
16594
+ }
16595
+ if (await isUntrackedPath(input2.workspacePath, input2.path)) {
16596
+ return (await getFileDiff(input2.workspacePath, input2.path)).diff;
16597
+ }
16598
+ const { stdout } = await runGit(input2.workspacePath, [
16599
+ "diff",
16600
+ metadata.baselineGitHead,
16601
+ "--",
16602
+ input2.path
16603
+ ]);
16604
+ return stdout;
16605
+ }
16606
+ var MISSING_BASELINE_WARNING, NOT_GIT_REPO_WARNING;
16607
+ var init_review = __esm({
16608
+ "packages/server/src/session-review/review.ts"() {
16609
+ "use strict";
16610
+ init_cli();
16611
+ init_diff();
16612
+ init_workspace_state();
16613
+ MISSING_BASELINE_WARNING = {
16614
+ code: "missing_baseline",
16615
+ message: "Session baseline is missing."
16616
+ };
16617
+ NOT_GIT_REPO_WARNING = {
16618
+ code: "not_git_repo",
16619
+ message: "Workspace is not a Git repository."
16620
+ };
16621
+ }
16622
+ });
16623
+
16624
+ // packages/server/src/commands/session-review.ts
16625
+ import { z as z15 } from "zod";
16626
+ function requireSessionMetadataRepo2(ctx) {
16627
+ if (!ctx.sessionMetadataRepo) {
16628
+ throw {
16629
+ code: "session_metadata_unavailable",
16630
+ message: "Session metadata repository is not configured"
16631
+ };
16632
+ }
16633
+ }
16634
+ function requireWorkspace(ctx, workspaceId) {
16635
+ const workspace = ctx.workspaceMgr.get(workspaceId);
16636
+ if (!workspace) {
16637
+ throw { code: "workspace_not_found", message: `Workspace not found: ${workspaceId}` };
16638
+ }
16639
+ return workspace;
16640
+ }
16641
+ var init_session_review = __esm({
16642
+ "packages/server/src/commands/session-review.ts"() {
16643
+ "use strict";
16644
+ init_review();
16645
+ init_dispatch();
16646
+ registerCommand(
16647
+ "sessionReview.summary",
16648
+ z15.object({
16649
+ sessionId: z15.string()
16650
+ }),
16651
+ async (args, ctx) => {
16652
+ requireSessionMetadataRepo2(ctx);
16653
+ const metadata = ctx.sessionMetadataRepo.get(args.sessionId);
16654
+ if (!metadata) {
16655
+ throw {
16656
+ code: "session_metadata_not_found",
16657
+ message: `Session metadata not found: ${args.sessionId}`
16658
+ };
16659
+ }
16660
+ const workspace = requireWorkspace(ctx, metadata.workspaceId);
16661
+ return buildSessionReviewSummary({
16662
+ sessionId: args.sessionId,
16663
+ workspacePath: workspace.path,
16664
+ metadataRepo: ctx.sessionMetadataRepo
16665
+ });
16666
+ }
16667
+ );
16668
+ registerCommand(
16669
+ "sessionReview.diff",
16670
+ z15.object({
16671
+ sessionId: z15.string(),
16672
+ path: z15.string().trim().min(1)
16673
+ }),
16674
+ async (args, ctx) => {
16675
+ requireSessionMetadataRepo2(ctx);
16676
+ const metadata = ctx.sessionMetadataRepo.get(args.sessionId);
16677
+ if (!metadata) {
16678
+ throw {
16679
+ code: "session_metadata_not_found",
16680
+ message: `Session metadata not found: ${args.sessionId}`
16681
+ };
16682
+ }
16683
+ const workspace = requireWorkspace(ctx, metadata.workspaceId);
16684
+ return {
16685
+ path: args.path,
16686
+ diff: await getSessionReviewDiff({
16687
+ sessionId: args.sessionId,
16688
+ workspacePath: workspace.path,
16689
+ metadataRepo: ctx.sessionMetadataRepo,
16690
+ path: args.path
16691
+ })
16692
+ };
16693
+ }
16694
+ );
16695
+ }
16696
+ });
16697
+
16698
+ // packages/server/src/fs/content-search.ts
16699
+ import { spawn as spawn5 } from "child_process";
16700
+ import { existsSync as existsSync8 } from "fs";
16701
+ import { readdir as readdir4, readFile as readFile7, stat as stat10 } from "fs/promises";
16702
+ import { basename as basename2, join as join15, relative as relative3 } from "path";
16703
+ import { createInterface } from "readline";
16704
+ async function searchFileContents(rootPath, options) {
16705
+ const query = options.query.trim();
16706
+ if (!query) {
16707
+ return {
16708
+ files: [],
16709
+ totalMatchCount: 0,
16710
+ hasMoreFiles: false,
16711
+ truncatedMatchFileCount: 0
16712
+ };
16713
+ }
16714
+ const result = await searchWithRipgrep(rootPath, query, options.maxFiles).catch(
16715
+ async (error) => {
16716
+ if (error.code === "ENOENT") {
16717
+ return searchWithNode(rootPath, query, options.maxFiles);
16718
+ }
16719
+ throw error;
16720
+ }
16721
+ );
16722
+ return finalizeResults(result, options.maxFiles, options.maxMatchesPerFile);
16723
+ }
16724
+ async function searchWithRipgrep(rootPath, query, maxFiles) {
16725
+ const hasGitignore = existsSync8(join15(rootPath, ".gitignore"));
16726
+ const args = [
16727
+ "--json",
16728
+ "--line-number",
16729
+ "--column",
16730
+ "--fixed-strings",
16731
+ "--sort",
16732
+ "path",
16733
+ "--with-filename",
16734
+ "--glob",
16735
+ "!**/.git/**",
16736
+ "--glob",
16737
+ "!**/node_modules/**"
16738
+ ];
16739
+ if (hasGitignore) {
16740
+ args.push("--hidden");
16741
+ args.push("--no-require-git");
16742
+ }
16743
+ args.push(query, ".");
16744
+ return new Promise((resolve8, reject) => {
16745
+ const child = spawn5("rg", args, { cwd: rootPath, stdio: ["ignore", "pipe", "pipe"] });
16746
+ const stdout = createInterface({ input: child.stdout });
16747
+ const files = /* @__PURE__ */ new Map();
16748
+ let totalMatchCount = 0;
16749
+ let hasMoreFiles = false;
16750
+ let stderr = "";
16751
+ stdout.on("line", (line) => {
16752
+ if (!line.trim()) {
16753
+ return;
16754
+ }
16755
+ const event = JSON.parse(line);
16756
+ if (event.type !== "match") {
16757
+ return;
16758
+ }
16759
+ const rawPath = event.data?.path?.text;
16760
+ if (!rawPath) {
16761
+ return;
16762
+ }
16763
+ const relativePath = normalizeRelativePath(relative3(rootPath, join15(rootPath, rawPath)));
16764
+ const preview = (event.data?.lines?.text ?? "").replace(/\r?\n$/, "");
16765
+ const lineNumber = event.data?.line_number ?? 1;
16766
+ const submatches = event.data?.submatches ?? [];
16767
+ totalMatchCount += submatches.length;
16768
+ if (!files.has(relativePath) && files.size >= maxFiles) {
16769
+ hasMoreFiles = true;
16770
+ return;
16771
+ }
16772
+ for (const submatch of submatches) {
16773
+ pushMatch(files, relativePath, {
16774
+ line: lineNumber,
16775
+ column: byteOffsetToColumn(preview, submatch.start),
16776
+ endColumn: byteOffsetToColumn(preview, submatch.end),
16777
+ preview,
16778
+ previewColumnStart: byteOffsetToColumn(preview, submatch.start),
16779
+ previewColumnEnd: byteOffsetToColumn(preview, submatch.end)
16780
+ });
16781
+ }
16782
+ });
16783
+ child.stderr.on("data", (chunk) => {
16784
+ stderr += chunk.toString();
16785
+ });
16786
+ child.on("error", (error) => {
16787
+ void stdout.close();
16788
+ reject(error);
16789
+ });
16790
+ child.on("close", (code) => {
16791
+ void stdout.close();
16792
+ if (code === 0 || code === 1) {
16793
+ resolve8({
16794
+ files: sortAccumulators(files),
16795
+ totalMatchCount,
16796
+ hasMoreFiles
16797
+ });
16798
+ return;
15698
16799
  }
15699
16800
  reject(
15700
16801
  Object.assign(new Error(stderr || `rg exited with code ${code ?? "unknown"}`), { code })
@@ -15712,7 +16813,7 @@ async function searchWithNode(rootPath, query, maxFiles) {
15712
16813
  const filteredEntries = entries.filter((entry) => filter(entry.name));
15713
16814
  filteredEntries.sort((a, b) => a.name.localeCompare(b.name));
15714
16815
  for (const entry of filteredEntries) {
15715
- const fullPath = join12(dirPath, entry.name);
16816
+ const fullPath = join15(dirPath, entry.name);
15716
16817
  if (entry.isDirectory()) {
15717
16818
  await walk(fullPath);
15718
16819
  continue;
@@ -15720,11 +16821,11 @@ async function searchWithNode(rootPath, query, maxFiles) {
15720
16821
  if (!entry.isFile()) {
15721
16822
  continue;
15722
16823
  }
15723
- const fileStat = await stat9(fullPath);
16824
+ const fileStat = await stat10(fullPath);
15724
16825
  if (fileStat.size > FALLBACK_MAX_FILE_BYTES) {
15725
16826
  continue;
15726
16827
  }
15727
- const buffer = await readFile4(fullPath);
16828
+ const buffer = await readFile7(fullPath);
15728
16829
  if (isBinaryFile(buffer)) {
15729
16830
  continue;
15730
16831
  }
@@ -15835,10 +16936,10 @@ var init_content_search = __esm({
15835
16936
  });
15836
16937
 
15837
16938
  // packages/server/src/fs/tree.ts
15838
- import { readdir as readdir5, stat as stat10 } from "fs/promises";
15839
- import { join as join13, relative as relative4 } from "path";
16939
+ import { readdir as readdir5, stat as stat11 } from "fs/promises";
16940
+ import { join as join16, relative as relative4 } from "path";
15840
16941
  async function readTree(rootPath, subdir) {
15841
- const targetPath = subdir ? join13(rootPath, subdir) : rootPath;
16942
+ const targetPath = subdir ? join16(rootPath, subdir) : rootPath;
15842
16943
  const filter = createTreeVisibilityFilter();
15843
16944
  const entries = await readdir5(targetPath, { withFileTypes: true });
15844
16945
  const nodes = [];
@@ -15846,7 +16947,7 @@ async function readTree(rootPath, subdir) {
15846
16947
  if (!filter(entry.name)) {
15847
16948
  continue;
15848
16949
  }
15849
- const fullPath = join13(targetPath, entry.name);
16950
+ const fullPath = join16(targetPath, entry.name);
15850
16951
  const relPath = relative4(rootPath, fullPath);
15851
16952
  if (entry.isDirectory()) {
15852
16953
  nodes.push({
@@ -15857,7 +16958,7 @@ async function readTree(rootPath, subdir) {
15857
16958
  // Not loaded yet - client will request on expand
15858
16959
  });
15859
16960
  } else if (entry.isFile()) {
15860
- const stats = await stat10(fullPath);
16961
+ const stats = await stat11(fullPath);
15861
16962
  nodes.push({
15862
16963
  name: entry.name,
15863
16964
  path: relPath,
@@ -15890,7 +16991,7 @@ async function searchFiles(rootPath, query, limit = 10) {
15890
16991
  const filteredEntries = entries.filter((entry) => filter(entry.name));
15891
16992
  filteredEntries.sort((a, b) => a.name.localeCompare(b.name));
15892
16993
  for (const entry of filteredEntries) {
15893
- const fullPath = join13(dirPath, entry.name);
16994
+ const fullPath = join16(dirPath, entry.name);
15894
16995
  const relPath = relative4(rootPath, fullPath);
15895
16996
  if (entry.isDirectory()) {
15896
16997
  await walk(fullPath);
@@ -15926,7 +17027,7 @@ async function searchFiles(rootPath, query, limit = 10) {
15926
17027
  }
15927
17028
  return a.path.toLowerCase().localeCompare(b.path.toLowerCase());
15928
17029
  }).slice(0, limit)) {
15929
- const stats = await stat10(match.fullPath);
17030
+ const stats = await stat11(match.fullPath);
15930
17031
  files.push({
15931
17032
  name: match.name,
15932
17033
  path: match.path,
@@ -16006,7 +17107,7 @@ var init_tree = __esm({
16006
17107
  });
16007
17108
 
16008
17109
  // packages/server/src/commands/file.ts
16009
- import { z as z13 } from "zod";
17110
+ import { z as z16 } from "zod";
16010
17111
  var init_file = __esm({
16011
17112
  "packages/server/src/commands/file.ts"() {
16012
17113
  "use strict";
@@ -16016,9 +17117,9 @@ var init_file = __esm({
16016
17117
  init_dispatch();
16017
17118
  registerCommand(
16018
17119
  "file.readTree",
16019
- z13.object({
16020
- workspaceId: z13.string(),
16021
- subPath: z13.string().optional()
17120
+ z16.object({
17121
+ workspaceId: z16.string(),
17122
+ subPath: z16.string().optional()
16022
17123
  }),
16023
17124
  async (args, ctx) => {
16024
17125
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -16030,10 +17131,10 @@ var init_file = __esm({
16030
17131
  );
16031
17132
  registerCommand(
16032
17133
  "file.search",
16033
- z13.object({
16034
- workspaceId: z13.string(),
16035
- query: z13.string(),
16036
- limit: z13.number().int().positive().max(50).optional()
17134
+ z16.object({
17135
+ workspaceId: z16.string(),
17136
+ query: z16.string(),
17137
+ limit: z16.number().int().positive().max(50).optional()
16037
17138
  }),
16038
17139
  async (args, ctx) => {
16039
17140
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -16045,11 +17146,11 @@ var init_file = __esm({
16045
17146
  );
16046
17147
  registerCommand(
16047
17148
  "file.searchContent",
16048
- z13.object({
16049
- workspaceId: z13.string(),
16050
- query: z13.string(),
16051
- maxFiles: z13.number().int().positive().max(100),
16052
- maxMatchesPerFile: z13.number().int().positive().max(100)
17149
+ z16.object({
17150
+ workspaceId: z16.string(),
17151
+ query: z16.string(),
17152
+ maxFiles: z16.number().int().positive().max(100),
17153
+ maxMatchesPerFile: z16.number().int().positive().max(100)
16053
17154
  }),
16054
17155
  async (args, ctx) => {
16055
17156
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -16065,9 +17166,9 @@ var init_file = __esm({
16065
17166
  );
16066
17167
  registerCommand(
16067
17168
  "file.read",
16068
- z13.object({
16069
- workspaceId: z13.string(),
16070
- path: z13.string()
17169
+ z16.object({
17170
+ workspaceId: z16.string(),
17171
+ path: z16.string()
16071
17172
  }),
16072
17173
  async (args, ctx) => {
16073
17174
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -16079,9 +17180,9 @@ var init_file = __esm({
16079
17180
  );
16080
17181
  registerCommand(
16081
17182
  "file.create",
16082
- z13.object({
16083
- workspaceId: z13.string(),
16084
- path: z13.string()
17183
+ z16.object({
17184
+ workspaceId: z16.string(),
17185
+ path: z16.string()
16085
17186
  }),
16086
17187
  async (args, ctx) => {
16087
17188
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -16099,9 +17200,9 @@ var init_file = __esm({
16099
17200
  );
16100
17201
  registerCommand(
16101
17202
  "file.mkdir",
16102
- z13.object({
16103
- workspaceId: z13.string(),
16104
- path: z13.string()
17203
+ z16.object({
17204
+ workspaceId: z16.string(),
17205
+ path: z16.string()
16105
17206
  }),
16106
17207
  async (args, ctx) => {
16107
17208
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -16119,9 +17220,9 @@ var init_file = __esm({
16119
17220
  );
16120
17221
  registerCommand(
16121
17222
  "file.delete",
16122
- z13.object({
16123
- workspaceId: z13.string(),
16124
- path: z13.string()
17223
+ z16.object({
17224
+ workspaceId: z16.string(),
17225
+ path: z16.string()
16125
17226
  }),
16126
17227
  async (args, ctx) => {
16127
17228
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -16139,10 +17240,10 @@ var init_file = __esm({
16139
17240
  );
16140
17241
  registerCommand(
16141
17242
  "file.rename",
16142
- z13.object({
16143
- workspaceId: z13.string(),
16144
- fromPath: z13.string(),
16145
- toPath: z13.string()
17243
+ z16.object({
17244
+ workspaceId: z16.string(),
17245
+ fromPath: z16.string(),
17246
+ toPath: z16.string()
16146
17247
  }),
16147
17248
  async (args, ctx) => {
16148
17249
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -16160,167 +17261,27 @@ var init_file = __esm({
16160
17261
  );
16161
17262
  registerCommand(
16162
17263
  "file.write",
16163
- z13.object({
16164
- workspaceId: z13.string(),
16165
- path: z13.string(),
16166
- content: z13.string(),
16167
- baseHash: z13.string().optional()
17264
+ z16.object({
17265
+ workspaceId: z16.string(),
17266
+ path: z16.string(),
17267
+ content: z16.string(),
17268
+ baseHash: z16.string().optional()
16168
17269
  // For conflict detection
16169
17270
  }),
16170
- async (args, ctx) => {
16171
- const workspace = ctx.workspaceMgr.get(args.workspaceId);
16172
- if (!workspace) {
16173
- throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
16174
- }
16175
- const result = await writeFile(workspace.path, args.path, args.content, args.baseHash);
16176
- ctx.eventBus.emit({
16177
- type: "fs.dirty",
16178
- workspaceId: args.workspaceId,
16179
- reason: "file_content"
16180
- });
16181
- return result;
16182
- }
16183
- );
16184
- }
16185
- });
16186
-
16187
- // packages/server/src/git/diff.ts
16188
- import { mkdtemp as mkdtemp3, readFile as readFile5, rm as rm7 } from "fs/promises";
16189
- import os3 from "os";
16190
- import path11 from "path";
16191
- async function isTrackedPath(cwd, filePath) {
16192
- try {
16193
- await runGit(cwd, ["ls-files", "--error-unmatch", "--", filePath]);
16194
- return true;
16195
- } catch {
16196
- return false;
16197
- }
16198
- }
16199
- async function getUntrackedFileDiff(cwd, filePath) {
16200
- const tempDir = await mkdtemp3(path11.join(os3.tmpdir(), "coder-studio-git-diff-"));
16201
- const tempIndex = path11.join(tempDir, "index");
16202
- try {
16203
- try {
16204
- await runGit(cwd, ["read-tree", "HEAD"], {
16205
- env: { GIT_INDEX_FILE: tempIndex }
16206
- });
16207
- } catch (error) {
16208
- if (!(error instanceof GitError)) {
16209
- throw error;
16210
- }
16211
- await runGit(cwd, ["read-tree", "--empty"], {
16212
- env: { GIT_INDEX_FILE: tempIndex }
16213
- });
16214
- }
16215
- await runGit(cwd, ["add", "-N", "--", filePath], {
16216
- env: { GIT_INDEX_FILE: tempIndex }
16217
- });
16218
- const result = await runGit(cwd, ["diff", "--", filePath], {
16219
- env: { GIT_INDEX_FILE: tempIndex }
16220
- });
16221
- return result.stdout;
16222
- } finally {
16223
- await rm7(tempDir, { recursive: true, force: true });
16224
- }
16225
- }
16226
- async function pathExists(cwd, filePath) {
16227
- try {
16228
- await readFile5(resolveSafe(cwd, filePath));
16229
- return true;
16230
- } catch {
16231
- return false;
16232
- }
16233
- }
16234
- async function readTextAtRevision(cwd, revision, filePath) {
16235
- if (revision === "WORKTREE") {
16236
- return readFile5(resolveSafe(cwd, filePath), "utf-8");
16237
- }
16238
- try {
16239
- const gitSpec = revision === "INDEX" ? `:${filePath}` : `${revision}:${filePath}`;
16240
- const result = await runGit(cwd, ["show", gitSpec]);
16241
- return result.stdout;
16242
- } catch {
16243
- return "";
16244
- }
16245
- }
16246
- async function deriveFileDiffStatus(cwd, filePath, staged) {
16247
- const tracked = await isTrackedPath(cwd, filePath);
16248
- const existsOnDisk = await pathExists(cwd, filePath);
16249
- if (!staged && !tracked) {
16250
- return "added";
16251
- }
16252
- if (staged) {
16253
- try {
16254
- await runGit(cwd, ["cat-file", "-e", `HEAD:${filePath}`]);
16255
- return existsOnDisk ? "modified" : "deleted";
16256
- } catch {
16257
- return "added";
16258
- }
16259
- }
16260
- return existsOnDisk ? "modified" : "deleted";
16261
- }
16262
- async function buildTextDiffResult(cwd, filePath, staged, diff) {
16263
- const status = await deriveFileDiffStatus(cwd, filePath, staged);
16264
- if (status === "added") {
16265
- return {
16266
- diff,
16267
- renderAs: "text",
16268
- status,
16269
- originalContent: "",
16270
- modifiedContent: await readTextAtRevision(cwd, staged ? "INDEX" : "WORKTREE", filePath)
16271
- };
16272
- }
16273
- if (status === "deleted") {
16274
- return {
16275
- diff,
16276
- renderAs: "text",
16277
- status,
16278
- originalContent: await readTextAtRevision(cwd, staged ? "HEAD" : "INDEX", filePath),
16279
- modifiedContent: ""
16280
- };
16281
- }
16282
- return {
16283
- diff,
16284
- renderAs: "text",
16285
- status,
16286
- originalContent: await readTextAtRevision(cwd, staged ? "HEAD" : "INDEX", filePath),
16287
- modifiedContent: await readTextAtRevision(cwd, staged ? "INDEX" : "WORKTREE", filePath)
16288
- };
16289
- }
16290
- async function getFileDiff(cwd, path14, staged = false) {
16291
- const imageType = getImageTypeInfo(path14);
16292
- if (!staged && !await isTrackedPath(cwd, path14)) {
16293
- const diff = await getUntrackedFileDiff(cwd, path14);
16294
- if (imageType) {
16295
- return {
16296
- diff,
16297
- renderAs: "image",
16298
- status: "added",
16299
- originalRevision: "HEAD",
16300
- modifiedRevision: "WORKTREE"
16301
- };
16302
- }
16303
- return buildTextDiffResult(cwd, path14, staged, diff);
16304
- }
16305
- const args = staged ? ["diff", "--staged", "--", path14] : ["diff", "--", path14];
16306
- const result = await runGit(cwd, args);
16307
- if (imageType && /Binary files .* differ/.test(result.stdout)) {
16308
- return {
16309
- diff: result.stdout,
16310
- renderAs: "image",
16311
- status: await deriveFileDiffStatus(cwd, path14, staged),
16312
- originalRevision: staged ? "HEAD" : "INDEX",
16313
- modifiedRevision: staged ? "INDEX" : "WORKTREE"
16314
- };
16315
- }
16316
- return buildTextDiffResult(cwd, path14, staged, result.stdout);
16317
- }
16318
- var init_diff = __esm({
16319
- "packages/server/src/git/diff.ts"() {
16320
- "use strict";
16321
- init_file_io();
16322
- init_image();
16323
- init_cli();
17271
+ async (args, ctx) => {
17272
+ const workspace = ctx.workspaceMgr.get(args.workspaceId);
17273
+ if (!workspace) {
17274
+ throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
17275
+ }
17276
+ const result = await writeFile(workspace.path, args.path, args.content, args.baseHash);
17277
+ ctx.eventBus.emit({
17278
+ type: "fs.dirty",
17279
+ workspaceId: args.workspaceId,
17280
+ reason: "file_content"
17281
+ });
17282
+ return result;
17283
+ }
17284
+ );
16324
17285
  }
16325
17286
  });
16326
17287
 
@@ -16341,7 +17302,7 @@ var init_git_events = __esm({
16341
17302
  });
16342
17303
 
16343
17304
  // packages/server/src/commands/git.ts
16344
- import { z as z14 } from "zod";
17305
+ import { z as z17 } from "zod";
16345
17306
  async function runGitNetworkOperation(ctx, workspaceId, op) {
16346
17307
  if (!ctx.autoFetch?.runExclusive) {
16347
17308
  return op();
@@ -16356,16 +17317,16 @@ var init_git2 = __esm({
16356
17317
  init_diff();
16357
17318
  init_dispatch();
16358
17319
  init_git_events();
16359
- gitHttpAuthSchema = z14.object({
16360
- username: z14.string(),
16361
- password: z14.string()
17320
+ gitHttpAuthSchema = z17.object({
17321
+ username: z17.string(),
17322
+ password: z17.string()
16362
17323
  });
16363
- gitCommitRevisionSchema = z14.string().regex(/^[0-9a-fA-F]{7,64}$/, "Invalid git commit revision");
17324
+ gitCommitRevisionSchema = z17.string().regex(/^[0-9a-fA-F]{7,64}$/, "Invalid git commit revision");
16364
17325
  GIT_BACKGROUND_FETCH_TIMEOUT_MS = 30 * 1e3;
16365
17326
  registerCommand(
16366
17327
  "git.status",
16367
- z14.object({
16368
- workspaceId: z14.string()
17328
+ z17.object({
17329
+ workspaceId: z17.string()
16369
17330
  }),
16370
17331
  async (args, ctx) => {
16371
17332
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -16377,9 +17338,9 @@ var init_git2 = __esm({
16377
17338
  );
16378
17339
  registerCommand(
16379
17340
  "git.stage",
16380
- z14.object({
16381
- workspaceId: z14.string(),
16382
- paths: z14.array(z14.string())
17341
+ z17.object({
17342
+ workspaceId: z17.string(),
17343
+ paths: z17.array(z17.string())
16383
17344
  }),
16384
17345
  async (args, ctx) => {
16385
17346
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -16393,10 +17354,10 @@ var init_git2 = __esm({
16393
17354
  );
16394
17355
  registerCommand(
16395
17356
  "git.diff",
16396
- z14.object({
16397
- workspaceId: z14.string(),
16398
- path: z14.string(),
16399
- staged: z14.boolean().optional()
17357
+ z17.object({
17358
+ workspaceId: z17.string(),
17359
+ path: z17.string(),
17360
+ staged: z17.boolean().optional()
16400
17361
  }),
16401
17362
  async (args, ctx) => {
16402
17363
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -16408,9 +17369,9 @@ var init_git2 = __esm({
16408
17369
  );
16409
17370
  registerCommand(
16410
17371
  "git.log",
16411
- z14.object({
16412
- workspaceId: z14.string(),
16413
- limit: z14.number().int().min(1).max(50).optional()
17372
+ z17.object({
17373
+ workspaceId: z17.string(),
17374
+ limit: z17.number().int().min(1).max(50).optional()
16414
17375
  }),
16415
17376
  async (args, ctx) => {
16416
17377
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -16424,8 +17385,8 @@ var init_git2 = __esm({
16424
17385
  );
16425
17386
  registerCommand(
16426
17387
  "git.show",
16427
- z14.object({
16428
- workspaceId: z14.string(),
17388
+ z17.object({
17389
+ workspaceId: z17.string(),
16429
17390
  sha: gitCommitRevisionSchema
16430
17391
  }),
16431
17392
  async (args, ctx) => {
@@ -16440,9 +17401,9 @@ var init_git2 = __esm({
16440
17401
  );
16441
17402
  registerCommand(
16442
17403
  "git.unstage",
16443
- z14.object({
16444
- workspaceId: z14.string(),
16445
- paths: z14.array(z14.string())
17404
+ z17.object({
17405
+ workspaceId: z17.string(),
17406
+ paths: z17.array(z17.string())
16446
17407
  }),
16447
17408
  async (args, ctx) => {
16448
17409
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -16456,9 +17417,9 @@ var init_git2 = __esm({
16456
17417
  );
16457
17418
  registerCommand(
16458
17419
  "git.discard",
16459
- z14.object({
16460
- workspaceId: z14.string(),
16461
- paths: z14.array(z14.string())
17420
+ z17.object({
17421
+ workspaceId: z17.string(),
17422
+ paths: z17.array(z17.string())
16462
17423
  }),
16463
17424
  async (args, ctx) => {
16464
17425
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -16474,9 +17435,9 @@ var init_git2 = __esm({
16474
17435
  );
16475
17436
  registerCommand(
16476
17437
  "git.commit",
16477
- z14.object({
16478
- workspaceId: z14.string(),
16479
- message: z14.string()
17438
+ z17.object({
17439
+ workspaceId: z17.string(),
17440
+ message: z17.string()
16480
17441
  }),
16481
17442
  async (args, ctx) => {
16482
17443
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -16493,11 +17454,11 @@ var init_git2 = __esm({
16493
17454
  );
16494
17455
  registerCommand(
16495
17456
  "git.push",
16496
- z14.object({
16497
- workspaceId: z14.string(),
16498
- remote: z14.string().optional(),
16499
- branch: z14.string().optional(),
16500
- force: z14.boolean().optional(),
17457
+ z17.object({
17458
+ workspaceId: z17.string(),
17459
+ remote: z17.string().optional(),
17460
+ branch: z17.string().optional(),
17461
+ force: z17.boolean().optional(),
16501
17462
  auth: gitHttpAuthSchema.optional()
16502
17463
  }),
16503
17464
  async (args, ctx) => {
@@ -16523,128 +17484,737 @@ var init_git2 = __esm({
16523
17484
  }
16524
17485
  );
16525
17486
  registerCommand(
16526
- "git.pull",
16527
- z14.object({
16528
- workspaceId: z14.string(),
16529
- remote: z14.string().optional(),
16530
- branch: z14.string().optional(),
16531
- auth: gitHttpAuthSchema.optional()
17487
+ "git.pull",
17488
+ z17.object({
17489
+ workspaceId: z17.string(),
17490
+ remote: z17.string().optional(),
17491
+ branch: z17.string().optional(),
17492
+ auth: gitHttpAuthSchema.optional()
17493
+ }),
17494
+ async (args, ctx) => {
17495
+ const workspace = ctx.workspaceMgr.get(args.workspaceId);
17496
+ if (!workspace) {
17497
+ throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
17498
+ }
17499
+ const result = await runGitNetworkOperation(
17500
+ ctx,
17501
+ args.workspaceId,
17502
+ () => runGitPull(workspace.path, {
17503
+ remote: args.remote,
17504
+ branch: args.branch,
17505
+ auth: args.auth
17506
+ })
17507
+ );
17508
+ ctx.workspaceMgr.recordFetch(args.workspaceId);
17509
+ emitGitStateChanged(ctx, args.workspaceId, {
17510
+ treeChanged: true,
17511
+ branchChanged: true,
17512
+ worktreeChanged: true
17513
+ });
17514
+ return result;
17515
+ }
17516
+ );
17517
+ registerCommand(
17518
+ "git.fetch",
17519
+ z17.object({
17520
+ workspaceId: z17.string(),
17521
+ remote: z17.string().optional(),
17522
+ prune: z17.boolean().optional(),
17523
+ auth: gitHttpAuthSchema.optional(),
17524
+ background: z17.boolean().optional()
17525
+ }),
17526
+ async (args, ctx, clientId) => {
17527
+ const workspace = ctx.workspaceMgr.get(args.workspaceId);
17528
+ if (!workspace) {
17529
+ throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
17530
+ }
17531
+ try {
17532
+ const isInternalBackgroundFetch = args.background === true && !clientId;
17533
+ const runFetch = () => runGitFetch(workspace.path, {
17534
+ remote: args.remote,
17535
+ prune: args.prune,
17536
+ auth: args.auth,
17537
+ timeoutMs: args.background ? GIT_BACKGROUND_FETCH_TIMEOUT_MS : void 0
17538
+ });
17539
+ const result = isInternalBackgroundFetch ? await runFetch() : await runGitNetworkOperation(ctx, args.workspaceId, runFetch);
17540
+ ctx.workspaceMgr.recordFetch(args.workspaceId);
17541
+ emitGitStateChanged(ctx, args.workspaceId, { branchChanged: true });
17542
+ return result;
17543
+ } catch (err) {
17544
+ if (args.background && err instanceof GitAuthError) {
17545
+ return { success: false, message: err.message, updatedRefs: [] };
17546
+ }
17547
+ throw err;
17548
+ }
17549
+ }
17550
+ );
17551
+ registerCommand(
17552
+ "git.checkout",
17553
+ z17.object({
17554
+ workspaceId: z17.string(),
17555
+ ref: z17.string(),
17556
+ createBranch: z17.boolean().optional()
17557
+ }),
17558
+ async (args, ctx) => {
17559
+ const workspace = ctx.workspaceMgr.get(args.workspaceId);
17560
+ if (!workspace) {
17561
+ throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
17562
+ }
17563
+ const result = await runGitCheckout(workspace.path, args.ref, {
17564
+ createBranch: args.createBranch
17565
+ });
17566
+ if (result.success) {
17567
+ emitGitStateChanged(ctx, args.workspaceId, {
17568
+ treeChanged: true,
17569
+ branchChanged: true,
17570
+ worktreeChanged: true
17571
+ });
17572
+ }
17573
+ return result;
17574
+ }
17575
+ );
17576
+ registerCommand(
17577
+ "git.branch",
17578
+ z17.object({
17579
+ workspaceId: z17.string(),
17580
+ name: z17.string(),
17581
+ startPoint: z17.string().optional()
17582
+ }),
17583
+ async (args, ctx) => {
17584
+ const workspace = ctx.workspaceMgr.get(args.workspaceId);
17585
+ if (!workspace) {
17586
+ throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
17587
+ }
17588
+ const result = await runGitCreateBranch(workspace.path, args.name, {
17589
+ startPoint: args.startPoint
17590
+ });
17591
+ emitGitStateChanged(ctx, args.workspaceId, {
17592
+ branchChanged: true,
17593
+ worktreeChanged: true
17594
+ });
17595
+ return result;
17596
+ }
17597
+ );
17598
+ registerCommand(
17599
+ "git.branches",
17600
+ z17.object({
17601
+ workspaceId: z17.string()
17602
+ }),
17603
+ async (args, ctx) => {
17604
+ const workspace = ctx.workspaceMgr.get(args.workspaceId);
17605
+ if (!workspace) {
17606
+ throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
17607
+ }
17608
+ return runGitListBranches(workspace.path);
17609
+ }
17610
+ );
17611
+ }
17612
+ });
17613
+
17614
+ // packages/server/src/agent-instructions/generator.ts
17615
+ function buildAgentInstructionsMarkdown(summary) {
17616
+ const lines = ["# Agent Instructions", ""];
17617
+ pushSection(lines, "Project Overview", buildProjectOverview(summary));
17618
+ pushSection(lines, "Development Commands", buildDevelopmentCommands(summary));
17619
+ pushSection(lines, "Working Rules", [...WORKING_RULES.map((rule) => `- ${rule}`)]);
17620
+ pushSection(
17621
+ lines,
17622
+ "Review Expectations",
17623
+ REVIEW_EXPECTATIONS.map((rule) => `- ${rule}`)
17624
+ );
17625
+ pushSection(
17626
+ lines,
17627
+ "Provider Notes",
17628
+ PROVIDER_NOTES.map((note) => `- ${note}`)
17629
+ );
17630
+ return lines.join("\n");
17631
+ }
17632
+ function buildProjectOverview(summary) {
17633
+ const lines = [];
17634
+ if (summary.git.isRepo) {
17635
+ if (summary.git.branch) {
17636
+ lines.push(`- Git branch: ${summary.git.branch}`);
17637
+ } else {
17638
+ lines.push("- Git repository: yes");
17639
+ }
17640
+ } else {
17641
+ lines.push("- Git repository: no");
17642
+ }
17643
+ if (summary.packageManager) {
17644
+ lines.push(`- Package manager: ${summary.packageManager}`);
17645
+ }
17646
+ if (summary.frameworks.length > 0) {
17647
+ lines.push(`- Frameworks: ${summary.frameworks.join(", ")}`);
17648
+ }
17649
+ if (summary.docs.length > 0) {
17650
+ lines.push(`- Docs: ${summary.docs.map((doc) => doc.path).join(", ")}`);
17651
+ }
17652
+ lines.push(
17653
+ `- ${summary.agentInstructions.path}: ${summary.agentInstructions.exists ? "exists" : "missing"}`
17654
+ );
17655
+ return lines;
17656
+ }
17657
+ function buildDevelopmentCommands(summary) {
17658
+ const lines = [];
17659
+ const commandLabels = {
17660
+ dev: "Dev",
17661
+ test: "Test",
17662
+ build: "Build",
17663
+ lint: "Lint"
17664
+ };
17665
+ for (const key of ["dev", "test", "build", "lint"]) {
17666
+ const command = summary.recommendedCommands.find((item) => item.key === key)?.command;
17667
+ if (!command) {
17668
+ continue;
17669
+ }
17670
+ lines.push(`- ${commandLabels[key]}: \`${command}\``);
17671
+ }
17672
+ return lines;
17673
+ }
17674
+ function pushSection(lines, heading, body) {
17675
+ lines.push(`## ${heading}`, "");
17676
+ lines.push(...body);
17677
+ lines.push("");
17678
+ }
17679
+ var WORKING_RULES, REVIEW_EXPECTATIONS, PROVIDER_NOTES;
17680
+ var init_generator = __esm({
17681
+ "packages/server/src/agent-instructions/generator.ts"() {
17682
+ "use strict";
17683
+ WORKING_RULES = [
17684
+ "Keep changes focused on the requested task.",
17685
+ "Do not revert user changes unless explicitly asked.",
17686
+ "Prefer the project's existing patterns.",
17687
+ "Run the relevant verification command before reporting completion."
17688
+ ];
17689
+ REVIEW_EXPECTATIONS = [
17690
+ "Summarize changed files.",
17691
+ "Report verification commands and results.",
17692
+ "Call out risks, skipped tests, and assumptions."
17693
+ ];
17694
+ PROVIDER_NOTES = [
17695
+ "Claude Code: use the project rules above.",
17696
+ "Codex: use the project rules above."
17697
+ ];
17698
+ }
17699
+ });
17700
+
17701
+ // packages/server/src/agent-instructions/health.ts
17702
+ function evaluateAgentInstructionsMarkdown(content) {
17703
+ if (!content.trim()) {
17704
+ return {
17705
+ path: AGENT_INSTRUCTIONS_RELATIVE_PATH,
17706
+ exists: false,
17707
+ status: "missing",
17708
+ checks: {
17709
+ projectOverview: false,
17710
+ developmentCommands: false,
17711
+ workingRules: false,
17712
+ reviewExpectations: false,
17713
+ safetyRules: false,
17714
+ providerNotes: false
17715
+ },
17716
+ issues: [
17717
+ {
17718
+ code: "missing_document",
17719
+ message: `${AGENT_INSTRUCTIONS_RELATIVE_PATH} is missing`
17720
+ }
17721
+ ]
17722
+ };
17723
+ }
17724
+ const sections = indexSections(content);
17725
+ const projectOverview = sections.has("Project Overview");
17726
+ const developmentCommands = hasAnyBullet(sections.get("Development Commands"));
17727
+ const workingRulesSection = sections.get("Working Rules");
17728
+ const reviewExpectationsSection = sections.get("Review Expectations");
17729
+ const providerNotesSection = sections.get("Provider Notes");
17730
+ const workingRules = hasAnyBullet(workingRulesSection);
17731
+ const reviewExpectations = hasAnyBullet(reviewExpectationsSection) && REQUIRED_REVIEW_EXPECTATIONS.every(
17732
+ (rule) => reviewExpectationsSection?.some((line) => line.includes(rule))
17733
+ );
17734
+ const providerNotes = hasAnyBullet(providerNotesSection) && PROVIDER_NOTE_MARKERS.some(
17735
+ (marker) => providerNotesSection?.some((line) => line.includes(marker))
17736
+ );
17737
+ const safetyRules = REQUIRED_WORKING_RULES.every(
17738
+ (rule) => workingRulesSection?.some((line) => line.includes(rule))
17739
+ );
17740
+ const issues = [];
17741
+ if (!projectOverview) {
17742
+ issues.push({
17743
+ code: "missing_project_overview",
17744
+ message: "Project Overview section is missing"
17745
+ });
17746
+ }
17747
+ if (!developmentCommands) {
17748
+ issues.push({
17749
+ code: "missing_development_commands",
17750
+ message: "Development Commands section is missing"
17751
+ });
17752
+ }
17753
+ if (!workingRules) {
17754
+ issues.push({
17755
+ code: "missing_working_rules",
17756
+ message: "Working Rules section is missing"
17757
+ });
17758
+ }
17759
+ if (!reviewExpectations) {
17760
+ issues.push({
17761
+ code: "missing_review_expectations",
17762
+ message: "Review Expectations section is missing"
17763
+ });
17764
+ }
17765
+ if (!safetyRules) {
17766
+ issues.push({
17767
+ code: "missing_safety_rules",
17768
+ message: "Working rules do not include the required safety rules"
17769
+ });
17770
+ }
17771
+ if (!providerNotes) {
17772
+ issues.push({
17773
+ code: "missing_provider_notes",
17774
+ message: "Provider Notes section is missing"
17775
+ });
17776
+ }
17777
+ const status = issues.length === 0 ? "healthy" : "warning";
17778
+ return {
17779
+ path: AGENT_INSTRUCTIONS_RELATIVE_PATH,
17780
+ exists: true,
17781
+ status,
17782
+ checks: {
17783
+ projectOverview,
17784
+ developmentCommands,
17785
+ workingRules,
17786
+ reviewExpectations,
17787
+ safetyRules,
17788
+ providerNotes
17789
+ },
17790
+ issues
17791
+ };
17792
+ }
17793
+ function indexSections(content) {
17794
+ const sections = /* @__PURE__ */ new Map();
17795
+ const lines = content.split(/\r?\n/);
17796
+ let currentHeading = null;
17797
+ for (const line of lines) {
17798
+ const heading = line.match(/^##\s+(.+?)\s*$/)?.[1];
17799
+ if (heading) {
17800
+ currentHeading = heading;
17801
+ if (!sections.has(heading)) {
17802
+ sections.set(heading, []);
17803
+ }
17804
+ continue;
17805
+ }
17806
+ if (currentHeading) {
17807
+ sections.get(currentHeading)?.push(line);
17808
+ }
17809
+ }
17810
+ return sections;
17811
+ }
17812
+ function hasAnyBullet(lines) {
17813
+ return Boolean(lines?.some((line) => line.trimStart().startsWith("- ")));
17814
+ }
17815
+ var REQUIRED_WORKING_RULES, REQUIRED_REVIEW_EXPECTATIONS, PROVIDER_NOTE_MARKERS;
17816
+ var init_health = __esm({
17817
+ "packages/server/src/agent-instructions/health.ts"() {
17818
+ "use strict";
17819
+ init_workspace_state();
17820
+ REQUIRED_WORKING_RULES = [
17821
+ "Keep changes focused on the requested task.",
17822
+ "Do not revert user changes unless explicitly asked.",
17823
+ "Prefer the project's existing patterns.",
17824
+ "Run the relevant verification command before reporting completion."
17825
+ ];
17826
+ REQUIRED_REVIEW_EXPECTATIONS = [
17827
+ "Summarize changed files.",
17828
+ "Report verification commands and results.",
17829
+ "Call out risks, skipped tests, and assumptions."
17830
+ ];
17831
+ PROVIDER_NOTE_MARKERS = ["Claude Code:", "Codex:"];
17832
+ }
17833
+ });
17834
+
17835
+ // packages/server/src/commands/agent-instructions.ts
17836
+ import { z as z18 } from "zod";
17837
+ async function readAgentInstructionsDocument(workspaceId, rootPath) {
17838
+ const path14 = AGENT_INSTRUCTIONS_RELATIVE_PATH;
17839
+ try {
17840
+ const result = await readFile(workspaceId, rootPath, path14);
17841
+ if (result.kind !== "text") {
17842
+ return {
17843
+ path: path14,
17844
+ exists: true,
17845
+ content: ""
17846
+ };
17847
+ }
17848
+ return {
17849
+ path: path14,
17850
+ exists: true,
17851
+ content: result.content,
17852
+ baseHash: result.baseHash
17853
+ };
17854
+ } catch {
17855
+ return {
17856
+ path: path14,
17857
+ exists: false,
17858
+ content: ""
17859
+ };
17860
+ }
17861
+ }
17862
+ var init_agent_instructions = __esm({
17863
+ "packages/server/src/commands/agent-instructions.ts"() {
17864
+ "use strict";
17865
+ init_generator();
17866
+ init_health();
17867
+ init_file_io();
17868
+ init_intelligence();
17869
+ init_workspace_state();
17870
+ init_dispatch();
17871
+ registerCommand(
17872
+ "agentInstructions.read",
17873
+ z18.object({
17874
+ workspaceId: z18.string()
17875
+ }),
17876
+ async (args, ctx) => {
17877
+ const workspace = ctx.workspaceMgr.get(args.workspaceId);
17878
+ if (!workspace) {
17879
+ throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
17880
+ }
17881
+ return readAgentInstructionsDocument(workspace.id, workspace.path);
17882
+ }
17883
+ );
17884
+ registerCommand(
17885
+ "agentInstructions.generate",
17886
+ z18.object({
17887
+ workspaceId: z18.string()
17888
+ }),
17889
+ async (args, ctx) => {
17890
+ const workspace = ctx.workspaceMgr.get(args.workspaceId);
17891
+ if (!workspace) {
17892
+ throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
17893
+ }
17894
+ const summary = await inspectWorkspaceIntelligence({
17895
+ workspaceId: workspace.id,
17896
+ rootPath: workspace.path
17897
+ });
17898
+ return {
17899
+ path: AGENT_INSTRUCTIONS_RELATIVE_PATH,
17900
+ exists: false,
17901
+ content: buildAgentInstructionsMarkdown(summary)
17902
+ };
17903
+ }
17904
+ );
17905
+ registerCommand(
17906
+ "agentInstructions.write",
17907
+ z18.object({
17908
+ workspaceId: z18.string(),
17909
+ content: z18.string(),
17910
+ overwrite: z18.boolean().optional(),
17911
+ baseHash: z18.string().optional()
16532
17912
  }),
16533
17913
  async (args, ctx) => {
16534
17914
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
16535
17915
  if (!workspace) {
16536
17916
  throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
16537
17917
  }
16538
- const result = await runGitNetworkOperation(
16539
- ctx,
16540
- args.workspaceId,
16541
- () => runGitPull(workspace.path, {
16542
- remote: args.remote,
16543
- branch: args.branch,
16544
- auth: args.auth
16545
- })
17918
+ const existing = await readAgentInstructionsDocument(workspace.id, workspace.path);
17919
+ if (existing.exists && !args.overwrite) {
17920
+ throw {
17921
+ code: "agent_instructions_exists",
17922
+ message: `${AGENT_INSTRUCTIONS_RELATIVE_PATH} already exists`
17923
+ };
17924
+ }
17925
+ const result = await writeFile(
17926
+ workspace.path,
17927
+ AGENT_INSTRUCTIONS_RELATIVE_PATH,
17928
+ args.content,
17929
+ args.baseHash
16546
17930
  );
16547
- ctx.workspaceMgr.recordFetch(args.workspaceId);
16548
- emitGitStateChanged(ctx, args.workspaceId, {
16549
- treeChanged: true,
16550
- branchChanged: true,
16551
- worktreeChanged: true
17931
+ ctx.eventBus.emit({
17932
+ type: "fs.dirty",
17933
+ workspaceId: args.workspaceId,
17934
+ reason: "file_content"
16552
17935
  });
16553
- return result;
17936
+ return {
17937
+ path: AGENT_INSTRUCTIONS_RELATIVE_PATH,
17938
+ exists: true,
17939
+ content: args.content,
17940
+ baseHash: result.newHash
17941
+ };
16554
17942
  }
16555
17943
  );
16556
17944
  registerCommand(
16557
- "git.fetch",
16558
- z14.object({
16559
- workspaceId: z14.string(),
16560
- remote: z14.string().optional(),
16561
- prune: z14.boolean().optional(),
16562
- auth: gitHttpAuthSchema.optional(),
16563
- background: z14.boolean().optional()
17945
+ "agentInstructions.health",
17946
+ z18.object({
17947
+ workspaceId: z18.string()
16564
17948
  }),
16565
- async (args, ctx, clientId) => {
17949
+ async (args, ctx) => {
16566
17950
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
16567
17951
  if (!workspace) {
16568
17952
  throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
16569
17953
  }
16570
- try {
16571
- const isInternalBackgroundFetch = args.background === true && !clientId;
16572
- const runFetch = () => runGitFetch(workspace.path, {
16573
- remote: args.remote,
16574
- prune: args.prune,
16575
- auth: args.auth,
16576
- timeoutMs: args.background ? GIT_BACKGROUND_FETCH_TIMEOUT_MS : void 0
16577
- });
16578
- const result = isInternalBackgroundFetch ? await runFetch() : await runGitNetworkOperation(ctx, args.workspaceId, runFetch);
16579
- ctx.workspaceMgr.recordFetch(args.workspaceId);
16580
- emitGitStateChanged(ctx, args.workspaceId, { branchChanged: true });
16581
- return result;
16582
- } catch (err) {
16583
- if (args.background && err instanceof GitAuthError) {
16584
- return { success: false, message: err.message, updatedRefs: [] };
16585
- }
16586
- throw err;
16587
- }
17954
+ const document = await readAgentInstructionsDocument(workspace.id, workspace.path);
17955
+ return evaluateAgentInstructionsMarkdown(document.content);
16588
17956
  }
16589
17957
  );
17958
+ }
17959
+ });
17960
+
17961
+ // packages/server/src/agent-context/context-package.ts
17962
+ import { randomUUID as randomUUID7 } from "node:crypto";
17963
+ import { readFile as readFile8 } from "node:fs/promises";
17964
+ function resolveOptions(options) {
17965
+ return {
17966
+ createId: options?.createId ?? randomUUID7,
17967
+ now: options?.now ?? Date.now
17968
+ };
17969
+ }
17970
+ function formatSource(source) {
17971
+ const parts = [`workspace=${source.workspaceId}`];
17972
+ if (source.sessionId) {
17973
+ parts.push(`session=${source.sessionId}`);
17974
+ }
17975
+ if (source.path) {
17976
+ parts.push(`path=${source.path}`);
17977
+ }
17978
+ if (source.terminalId) {
17979
+ parts.push(`terminal=${source.terminalId}`);
17980
+ }
17981
+ return parts.join(" ");
17982
+ }
17983
+ function wrapContext(title, source, body) {
17984
+ return `Context: ${title}
17985
+ Source: ${formatSource(source)}
17986
+
17987
+ ${body}`;
17988
+ }
17989
+ function createContextPackage(kind, title, source, body, options) {
17990
+ const resolved = resolveOptions(options);
17991
+ return {
17992
+ id: resolved.createId(),
17993
+ kind,
17994
+ title,
17995
+ body: wrapContext(title, source, body),
17996
+ source,
17997
+ createdAt: resolved.now()
17998
+ };
17999
+ }
18000
+ function requireSessionMetadata2(metadataRepo, sessionId) {
18001
+ const metadata = metadataRepo.get(sessionId);
18002
+ if (!metadata) {
18003
+ throw {
18004
+ code: "session_metadata_not_found",
18005
+ message: `Session metadata not found: ${sessionId}`
18006
+ };
18007
+ }
18008
+ return metadata;
18009
+ }
18010
+ function buildProjectSummaryBody(summary) {
18011
+ const lines = [
18012
+ `Git: ${summary.git.isRepo ? "repository detected" : "no repository detected"}`,
18013
+ `Package manager: ${summary.packageManager ?? "unknown"}`,
18014
+ `Frameworks: ${summary.frameworks.length > 0 ? summary.frameworks.join(", ") : "none"}`
18015
+ ];
18016
+ if (summary.recommendedCommands.length > 0) {
18017
+ lines.push("Recommended commands:");
18018
+ for (const command of summary.recommendedCommands) {
18019
+ lines.push(`- ${command.key}: ${command.command}`);
18020
+ }
18021
+ } else {
18022
+ lines.push("Recommended commands: none");
18023
+ }
18024
+ if (summary.docs.length > 0) {
18025
+ lines.push("Docs:");
18026
+ for (const doc of summary.docs) {
18027
+ lines.push(`- ${doc.path}`);
18028
+ }
18029
+ } else {
18030
+ lines.push("Docs: none");
18031
+ }
18032
+ lines.push(
18033
+ `Agent instructions: ${summary.agentInstructions.path} ${summary.agentInstructions.exists ? "present" : "missing"}`
18034
+ );
18035
+ return lines.join("\n");
18036
+ }
18037
+ async function buildFileContextPackage(input2, options) {
18038
+ const content = await readFile8(resolveSafe(input2.workspacePath, input2.path), "utf8");
18039
+ return createContextPackage(
18040
+ "file",
18041
+ `File: ${input2.path}`,
18042
+ {
18043
+ workspaceId: input2.workspaceId,
18044
+ path: input2.path
18045
+ },
18046
+ content,
18047
+ options
18048
+ );
18049
+ }
18050
+ async function buildDiffContextPackage(input2, options) {
18051
+ const metadata = requireSessionMetadata2(input2.metadataRepo, input2.sessionId);
18052
+ const diff = await getSessionReviewDiff({
18053
+ sessionId: input2.sessionId,
18054
+ workspacePath: input2.workspacePath,
18055
+ metadataRepo: input2.metadataRepo,
18056
+ path: input2.path
18057
+ });
18058
+ return createContextPackage(
18059
+ "git_diff",
18060
+ `Git Diff: ${input2.path}`,
18061
+ {
18062
+ workspaceId: metadata.workspaceId,
18063
+ sessionId: input2.sessionId,
18064
+ path: input2.path
18065
+ },
18066
+ diff,
18067
+ options
18068
+ );
18069
+ }
18070
+ async function buildProjectSummaryContextPackage(input2, options) {
18071
+ const summary = await inspectWorkspaceIntelligence({
18072
+ workspaceId: input2.workspaceId,
18073
+ rootPath: input2.workspacePath
18074
+ });
18075
+ return createContextPackage(
18076
+ "project_summary",
18077
+ "Project Summary",
18078
+ {
18079
+ workspaceId: input2.workspaceId
18080
+ },
18081
+ buildProjectSummaryBody(summary),
18082
+ options
18083
+ );
18084
+ }
18085
+ async function buildSessionReviewContextPackage(input2, options) {
18086
+ const metadata = requireSessionMetadata2(input2.metadataRepo, input2.sessionId);
18087
+ const summary = await buildSessionReviewSummary({
18088
+ sessionId: input2.sessionId,
18089
+ workspacePath: input2.workspacePath,
18090
+ metadataRepo: input2.metadataRepo
18091
+ });
18092
+ const lines = [
18093
+ `Baseline: ${summary.baselineGitHead ?? "missing"}`,
18094
+ "Changed files:",
18095
+ ...summary.changedFiles.length > 0 ? summary.changedFiles.map((change) => `- ${change.status ?? "modified"}: ${change.path}`) : ["- none"],
18096
+ "Verification runs:",
18097
+ ...summary.verificationRuns.length > 0 ? summary.verificationRuns.map((run) => `- ${run.status}: ${run.command}`) : ["- none"]
18098
+ ];
18099
+ if (summary.warnings.length > 0) {
18100
+ lines.push("Warnings:");
18101
+ for (const warning of summary.warnings) {
18102
+ lines.push(`- ${warning.code}: ${warning.message}`);
18103
+ }
18104
+ }
18105
+ return createContextPackage(
18106
+ "session_review",
18107
+ `Session Review: ${summary.sessionId}`,
18108
+ {
18109
+ workspaceId: metadata.workspaceId,
18110
+ sessionId: input2.sessionId
18111
+ },
18112
+ lines.join("\n"),
18113
+ options
18114
+ );
18115
+ }
18116
+ var init_context_package = __esm({
18117
+ "packages/server/src/agent-context/context-package.ts"() {
18118
+ "use strict";
18119
+ init_file_io();
18120
+ init_review();
18121
+ init_intelligence();
18122
+ }
18123
+ });
18124
+
18125
+ // packages/server/src/commands/agent-context.ts
18126
+ import { z as z19 } from "zod";
18127
+ function requireWorkspace2(ctx, workspaceId) {
18128
+ const workspace = ctx.workspaceMgr.get(workspaceId);
18129
+ if (!workspace) {
18130
+ throw { code: "workspace_not_found", message: `Workspace not found: ${workspaceId}` };
18131
+ }
18132
+ return workspace;
18133
+ }
18134
+ function requireSessionMetadataRepo3(ctx) {
18135
+ if (!ctx.sessionMetadataRepo) {
18136
+ throw {
18137
+ code: "session_metadata_unavailable",
18138
+ message: "Session metadata repository is not configured"
18139
+ };
18140
+ }
18141
+ }
18142
+ function getSessionWorkspace(ctx, sessionId) {
18143
+ const metadata = ctx.sessionMetadataRepo.get(sessionId);
18144
+ if (!metadata) {
18145
+ throw {
18146
+ code: "session_metadata_not_found",
18147
+ message: `Session metadata not found: ${sessionId}`
18148
+ };
18149
+ }
18150
+ return {
18151
+ metadata,
18152
+ workspace: requireWorkspace2(ctx, metadata.workspaceId)
18153
+ };
18154
+ }
18155
+ var init_agent_context = __esm({
18156
+ "packages/server/src/commands/agent-context.ts"() {
18157
+ "use strict";
18158
+ init_context_package();
18159
+ init_dispatch();
16590
18160
  registerCommand(
16591
- "git.checkout",
16592
- z14.object({
16593
- workspaceId: z14.string(),
16594
- ref: z14.string(),
16595
- createBranch: z14.boolean().optional()
18161
+ "agentContext.fromFile",
18162
+ z19.object({
18163
+ workspaceId: z19.string(),
18164
+ path: z19.string().trim().min(1)
16596
18165
  }),
16597
18166
  async (args, ctx) => {
16598
- const workspace = ctx.workspaceMgr.get(args.workspaceId);
16599
- if (!workspace) {
16600
- throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
16601
- }
16602
- const result = await runGitCheckout(workspace.path, args.ref, {
16603
- createBranch: args.createBranch
18167
+ const workspace = requireWorkspace2(ctx, args.workspaceId);
18168
+ return buildFileContextPackage({
18169
+ workspaceId: workspace.id,
18170
+ workspacePath: workspace.path,
18171
+ path: args.path
16604
18172
  });
16605
- if (result.success) {
16606
- emitGitStateChanged(ctx, args.workspaceId, {
16607
- treeChanged: true,
16608
- branchChanged: true,
16609
- worktreeChanged: true
16610
- });
16611
- }
16612
- return result;
16613
18173
  }
16614
18174
  );
16615
18175
  registerCommand(
16616
- "git.branch",
16617
- z14.object({
16618
- workspaceId: z14.string(),
16619
- name: z14.string(),
16620
- startPoint: z14.string().optional()
18176
+ "agentContext.fromDiff",
18177
+ z19.object({
18178
+ sessionId: z19.string(),
18179
+ path: z19.string().trim().min(1)
16621
18180
  }),
16622
18181
  async (args, ctx) => {
16623
- const workspace = ctx.workspaceMgr.get(args.workspaceId);
16624
- if (!workspace) {
16625
- throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
16626
- }
16627
- const result = await runGitCreateBranch(workspace.path, args.name, {
16628
- startPoint: args.startPoint
18182
+ requireSessionMetadataRepo3(ctx);
18183
+ const { workspace } = getSessionWorkspace(ctx, args.sessionId);
18184
+ return buildDiffContextPackage({
18185
+ sessionId: args.sessionId,
18186
+ path: args.path,
18187
+ workspacePath: workspace.path,
18188
+ metadataRepo: ctx.sessionMetadataRepo
16629
18189
  });
16630
- emitGitStateChanged(ctx, args.workspaceId, {
16631
- branchChanged: true,
16632
- worktreeChanged: true
18190
+ }
18191
+ );
18192
+ registerCommand(
18193
+ "agentContext.fromProjectSummary",
18194
+ z19.object({
18195
+ workspaceId: z19.string()
18196
+ }),
18197
+ async (args, ctx) => {
18198
+ const workspace = requireWorkspace2(ctx, args.workspaceId);
18199
+ return buildProjectSummaryContextPackage({
18200
+ workspaceId: workspace.id,
18201
+ workspacePath: workspace.path
16633
18202
  });
16634
- return result;
16635
18203
  }
16636
18204
  );
16637
18205
  registerCommand(
16638
- "git.branches",
16639
- z14.object({
16640
- workspaceId: z14.string()
18206
+ "agentContext.fromSessionReview",
18207
+ z19.object({
18208
+ sessionId: z19.string()
16641
18209
  }),
16642
18210
  async (args, ctx) => {
16643
- const workspace = ctx.workspaceMgr.get(args.workspaceId);
16644
- if (!workspace) {
16645
- throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
16646
- }
16647
- return runGitListBranches(workspace.path);
18211
+ requireSessionMetadataRepo3(ctx);
18212
+ const { workspace } = getSessionWorkspace(ctx, args.sessionId);
18213
+ return buildSessionReviewContextPackage({
18214
+ sessionId: args.sessionId,
18215
+ workspacePath: workspace.path,
18216
+ metadataRepo: ctx.sessionMetadataRepo
18217
+ });
16648
18218
  }
16649
18219
  );
16650
18220
  }
@@ -16653,25 +18223,25 @@ var init_git2 = __esm({
16653
18223
  // packages/server/src/config/config-io.ts
16654
18224
  import { existsSync as existsSync9, mkdirSync as mkdirSync7, readFileSync as readFileSync7, renameSync as renameSync2, writeFileSync as writeFileSync5 } from "node:fs";
16655
18225
  import { homedir as homedir3 } from "node:os";
16656
- import { basename as basename3, dirname as dirname7, join as join14 } from "node:path";
18226
+ import { basename as basename3, dirname as dirname7, join as join17 } from "node:path";
16657
18227
  function resolveConfigPath(configType) {
16658
18228
  if (configType === "codex") {
16659
18229
  const testHome = process.env.CODER_STUDIO_CODEX_HOME;
16660
18230
  if (testHome && testHome.trim()) {
16661
- return join14(testHome, "config.toml");
18231
+ return join17(testHome, "config.toml");
16662
18232
  }
16663
18233
  const codexHome = process.env.CODEX_HOME;
16664
18234
  if (codexHome && codexHome.trim()) {
16665
- return join14(codexHome, "config.toml");
18235
+ return join17(codexHome, "config.toml");
16666
18236
  }
16667
- return join14(homedir3(), ".codex", "config.toml");
18237
+ return join17(homedir3(), ".codex", "config.toml");
16668
18238
  }
16669
18239
  if (configType === "claude") {
16670
18240
  const testHome = process.env.CODER_STUDIO_CLAUDE_HOME;
16671
18241
  if (testHome && testHome.trim()) {
16672
- return join14(testHome, "settings.json");
18242
+ return join17(testHome, "settings.json");
16673
18243
  }
16674
- return join14(homedir3(), ".claude", "settings.json");
18244
+ return join17(homedir3(), ".claude", "settings.json");
16675
18245
  }
16676
18246
  throw new Error(`Unknown config type: ${configType}`);
16677
18247
  }
@@ -16716,7 +18286,7 @@ function createBackup(filePath) {
16716
18286
  const base = basename3(filePath, `.${ext}`);
16717
18287
  const dir = dirname7(filePath);
16718
18288
  const ts = formatTimestamp(/* @__PURE__ */ new Date());
16719
- const backupPath = join14(dir, `${base}.bak.${ts}.${ext}`);
18289
+ const backupPath = join17(dir, `${base}.bak.${ts}.${ext}`);
16720
18290
  writeFileSync5(backupPath, original, "utf-8");
16721
18291
  return backupPath;
16722
18292
  }
@@ -16731,7 +18301,7 @@ var init_config_io = __esm({
16731
18301
  });
16732
18302
 
16733
18303
  // packages/server/src/commands/settings.ts
16734
- import { z as z15 } from "zod";
18304
+ import { z as z20 } from "zod";
16735
18305
  function flattenSettings(obj, prefix = "") {
16736
18306
  const result = {};
16737
18307
  for (const [key, value] of Object.entries(obj)) {
@@ -16782,13 +18352,13 @@ var init_settings2 = __esm({
16782
18352
  init_provider_config();
16783
18353
  init_settings();
16784
18354
  init_dispatch();
16785
- PersonalizationOverridesSchema = z15.object({
16786
- backgroundAssetId: z15.string().min(1).nullable().optional(),
16787
- backgroundDimness: z15.number().int().min(0).max(100).optional(),
16788
- backgroundBlur: z15.number().int().min(0).max(40).optional(),
16789
- glassEnabled: z15.boolean().optional(),
16790
- glassIntensity: z15.number().int().min(0).max(100).optional(),
16791
- surfaceOpacity: z15.number().int().min(0).max(100).optional()
18355
+ PersonalizationOverridesSchema = z20.object({
18356
+ backgroundAssetId: z20.string().min(1).nullable().optional(),
18357
+ backgroundDimness: z20.number().int().min(0).max(100).optional(),
18358
+ backgroundBlur: z20.number().int().min(0).max(40).optional(),
18359
+ glassEnabled: z20.boolean().optional(),
18360
+ glassIntensity: z20.number().int().min(0).max(100).optional(),
18361
+ surfaceOpacity: z20.number().int().min(0).max(100).optional()
16792
18362
  });
16793
18363
  PERSONALIZATION_OVERRIDE_BRANCHES = ["desktop", "mobile"];
16794
18364
  PERSONALIZATION_OVERRIDE_FIELDS = [
@@ -16799,59 +18369,59 @@ var init_settings2 = __esm({
16799
18369
  "glassIntensity",
16800
18370
  "surfaceOpacity"
16801
18371
  ];
16802
- SettingsSchema = z15.object({
16803
- defaultProviderId: z15.string().optional(),
16804
- notifications: z15.object({
16805
- enabled: z15.boolean().optional(),
16806
- soundEnabled: z15.boolean().optional(),
18372
+ SettingsSchema = z20.object({
18373
+ defaultProviderId: z20.string().optional(),
18374
+ notifications: z20.object({
18375
+ enabled: z20.boolean().optional(),
18376
+ soundEnabled: z20.boolean().optional(),
16807
18377
  // Legacy field — accepted for backward compat with older clients but
16808
18378
  // no longer surfaced in the UI. The web client now picks the channel
16809
18379
  // automatically based on workspace focus + page visibility.
16810
- onlyWhenBackgrounded: z15.boolean().optional()
18380
+ onlyWhenBackgrounded: z20.boolean().optional()
16811
18381
  }).optional(),
16812
- supervisor: z15.object({
16813
- evaluationTimeoutSec: z15.number().int().min(1).max(MAX_SUPERVISOR_EVALUATION_TIMEOUT_SEC).default(DEFAULT_SUPERVISOR_EVALUATION_TIMEOUT_SEC).optional(),
16814
- retryEnabled: z15.boolean().optional(),
16815
- retryMaxCount: z15.number().int().min(0).max(MAX_SUPERVISOR_RETRY_MAX_COUNT).optional(),
16816
- retryDelaySec: z15.number().int().min(1).max(MAX_SUPERVISOR_RETRY_DELAY_SEC).optional(),
16817
- retryOnTimeout: z15.boolean().optional(),
16818
- retryOnEvaluatorError: z15.boolean().optional()
18382
+ supervisor: z20.object({
18383
+ evaluationTimeoutSec: z20.number().int().min(1).max(MAX_SUPERVISOR_EVALUATION_TIMEOUT_SEC).default(DEFAULT_SUPERVISOR_EVALUATION_TIMEOUT_SEC).optional(),
18384
+ retryEnabled: z20.boolean().optional(),
18385
+ retryMaxCount: z20.number().int().min(0).max(MAX_SUPERVISOR_RETRY_MAX_COUNT).optional(),
18386
+ retryDelaySec: z20.number().int().min(1).max(MAX_SUPERVISOR_RETRY_DELAY_SEC).optional(),
18387
+ retryOnTimeout: z20.boolean().optional(),
18388
+ retryOnEvaluatorError: z20.boolean().optional()
16819
18389
  }).optional(),
16820
- appearance: z15.object({
16821
- theme: z15.enum(["dark", "light"]).optional(),
16822
- themeId: z15.string().optional(),
16823
- terminalRenderer: z15.enum(["standard", "compatibility"]).optional(),
16824
- terminalCopyOnSelect: z15.boolean().optional(),
16825
- terminalFontSize: z15.number().int().min(10).max(18).optional(),
16826
- desktopTerminalFontSize: z15.number().int().min(10).max(18).optional(),
16827
- mobileTerminalFontSize: z15.number().int().min(10).max(18).optional(),
16828
- locale: z15.enum(["zh", "en"]).optional(),
16829
- personalization: z15.object({
16830
- version: z15.literal(1).optional(),
16831
- common: z15.object({
16832
- backgroundMode: z15.enum(["none", "image"]).optional(),
16833
- backgroundAssetId: z15.string().min(1).nullable().optional(),
16834
- backgroundFit: z15.enum(["cover", "contain"]).optional(),
16835
- backgroundDimness: z15.number().int().min(0).max(100).optional(),
16836
- backgroundBlur: z15.number().int().min(0).max(40).optional(),
16837
- glassEnabled: z15.boolean().optional(),
16838
- glassIntensity: z15.number().int().min(0).max(100).optional(),
16839
- surfaceOpacity: z15.number().int().min(0).max(100).optional()
18390
+ appearance: z20.object({
18391
+ theme: z20.enum(["dark", "light"]).optional(),
18392
+ themeId: z20.string().optional(),
18393
+ terminalRenderer: z20.enum(["standard", "compatibility"]).optional(),
18394
+ terminalCopyOnSelect: z20.boolean().optional(),
18395
+ terminalFontSize: z20.number().int().min(10).max(18).optional(),
18396
+ desktopTerminalFontSize: z20.number().int().min(10).max(18).optional(),
18397
+ mobileTerminalFontSize: z20.number().int().min(10).max(18).optional(),
18398
+ locale: z20.enum(["zh", "en"]).optional(),
18399
+ personalization: z20.object({
18400
+ version: z20.literal(1).optional(),
18401
+ common: z20.object({
18402
+ backgroundMode: z20.enum(["none", "image"]).optional(),
18403
+ backgroundAssetId: z20.string().min(1).nullable().optional(),
18404
+ backgroundFit: z20.enum(["cover", "contain"]).optional(),
18405
+ backgroundDimness: z20.number().int().min(0).max(100).optional(),
18406
+ backgroundBlur: z20.number().int().min(0).max(40).optional(),
18407
+ glassEnabled: z20.boolean().optional(),
18408
+ glassIntensity: z20.number().int().min(0).max(100).optional(),
18409
+ surfaceOpacity: z20.number().int().min(0).max(100).optional()
16840
18410
  }).optional(),
16841
18411
  desktop: PersonalizationOverridesSchema.optional(),
16842
18412
  mobile: PersonalizationOverridesSchema.optional()
16843
18413
  }).optional()
16844
18414
  }).optional(),
16845
- lsp: z15.object({
16846
- mode: z15.enum(["auto", "off"]).optional()
18415
+ lsp: z20.object({
18416
+ mode: z20.enum(["auto", "off"]).optional()
16847
18417
  }).optional(),
16848
- updates: z15.object({
16849
- autoCheckEnabled: z15.boolean().optional(),
16850
- checkIntervalSec: z15.number().int().refine(isUpdateCheckIntervalSec).optional()
18418
+ updates: z20.object({
18419
+ autoCheckEnabled: z20.boolean().optional(),
18420
+ checkIntervalSec: z20.number().int().refine(isUpdateCheckIntervalSec).optional()
16851
18421
  }).optional(),
16852
18422
  providers: ProviderSettingsSchema.optional()
16853
18423
  });
16854
- registerCommand("settings.get", z15.object({}), async (_args, ctx) => {
18424
+ registerCommand("settings.get", z20.object({}), async (_args, ctx) => {
16855
18425
  const settings = {};
16856
18426
  for (const [key, value] of Object.entries(ctx.settingsRepo.getAll())) {
16857
18427
  if (key.startsWith("providers.")) {
@@ -16903,7 +18473,7 @@ var init_settings2 = __esm({
16903
18473
  });
16904
18474
  registerCommand(
16905
18475
  "settings.update",
16906
- z15.object({
18476
+ z20.object({
16907
18477
  settings: SettingsSchema
16908
18478
  }),
16909
18479
  async (args, ctx) => {
@@ -16936,10 +18506,10 @@ var init_settings2 = __esm({
16936
18506
  );
16937
18507
  registerCommand(
16938
18508
  "settings.previewCommand",
16939
- z15.object({
16940
- providerId: z15.string(),
18509
+ z20.object({
18510
+ providerId: z20.string(),
16941
18511
  config: ProviderLaunchConfigInputSchema,
16942
- workspacePath: z15.string().optional()
18512
+ workspacePath: z20.string().optional()
16943
18513
  }),
16944
18514
  async (args, ctx) => {
16945
18515
  const provider = ctx.providerRegistry.find((item) => item.id === args.providerId);
@@ -16960,8 +18530,8 @@ var init_settings2 = __esm({
16960
18530
  );
16961
18531
  registerCommand(
16962
18532
  "settings.readConfigFile",
16963
- z15.object({
16964
- configType: z15.enum(["codex", "claude"])
18533
+ z20.object({
18534
+ configType: z20.enum(["codex", "claude"])
16965
18535
  }),
16966
18536
  async (args) => {
16967
18537
  const result = readConfigFile(args.configType);
@@ -16970,9 +18540,9 @@ var init_settings2 = __esm({
16970
18540
  );
16971
18541
  registerCommand(
16972
18542
  "settings.writeConfigFile",
16973
- z15.object({
16974
- configType: z15.enum(["codex", "claude"]),
16975
- content: z15.string()
18543
+ z20.object({
18544
+ configType: z20.enum(["codex", "claude"]),
18545
+ content: z20.string()
16976
18546
  }),
16977
18547
  async (args) => {
16978
18548
  const result = writeConfigFile(args.configType, args.content);
@@ -16983,7 +18553,7 @@ var init_settings2 = __esm({
16983
18553
  });
16984
18554
 
16985
18555
  // packages/server/src/commands/diagnostics.ts
16986
- import { z as z16 } from "zod";
18556
+ import { z as z21 } from "zod";
16987
18557
  function isLoopbackHost(host) {
16988
18558
  return host === void 0 || host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "0.0.0.0";
16989
18559
  }
@@ -17353,11 +18923,11 @@ var init_diagnostics2 = __esm({
17353
18923
  init_runtime_status();
17354
18924
  init_validator();
17355
18925
  init_dispatch();
17356
- DiagnosticsRequestSchema = z16.object({
17357
- context: z16.enum(["workspace_open", "session_start", "mobile_continue", "manual_check"]),
17358
- workspaceId: z16.string().optional(),
17359
- workspacePath: z16.string().optional(),
17360
- providerId: z16.string().optional()
18926
+ DiagnosticsRequestSchema = z21.object({
18927
+ context: z21.enum(["workspace_open", "session_start", "mobile_continue", "manual_check"]),
18928
+ workspaceId: z21.string().optional(),
18929
+ workspacePath: z21.string().optional(),
18930
+ providerId: z21.string().optional()
17361
18931
  });
17362
18932
  registerCommand("diagnostics.get", DiagnosticsRequestSchema, async (args, ctx) => {
17363
18933
  return buildDiagnostics(args, ctx);
@@ -17369,19 +18939,23 @@ var init_diagnostics2 = __esm({
17369
18939
  });
17370
18940
 
17371
18941
  // packages/server/src/commands/provider.ts
17372
- import { z as z17 } from "zod";
18942
+ import { z as z22 } from "zod";
17373
18943
  var init_provider = __esm({
17374
18944
  "packages/server/src/commands/provider.ts"() {
17375
18945
  "use strict";
18946
+ init_src();
17376
18947
  init_runtime_status();
17377
18948
  init_dispatch();
17378
- registerCommand("provider.runtimeStatus", z17.object({}), async (_args, ctx) => {
18949
+ registerCommand("provider.list", z22.object({}), async (_args, ctx) => {
18950
+ return ctx.providerRegistry.map((provider) => toProviderListItem(provider));
18951
+ });
18952
+ registerCommand("provider.runtimeStatus", z22.object({}), async (_args, ctx) => {
17379
18953
  return buildProviderRuntimeStatus(ctx.providerRegistry, ctx.providerRuntimeDeps);
17380
18954
  });
17381
18955
  registerCommand(
17382
18956
  "provider.install.start",
17383
- z17.object({
17384
- providerId: z17.string()
18957
+ z22.object({
18958
+ providerId: z22.string()
17385
18959
  }),
17386
18960
  async (args, ctx) => {
17387
18961
  if (!ctx.providerInstallMgr) {
@@ -17395,8 +18969,8 @@ var init_provider = __esm({
17395
18969
  );
17396
18970
  registerCommand(
17397
18971
  "provider.install.get",
17398
- z17.object({
17399
- jobId: z17.string()
18972
+ z22.object({
18973
+ jobId: z22.string()
17400
18974
  }),
17401
18975
  async (args, ctx) => {
17402
18976
  if (!ctx.providerInstallMgr) {
@@ -17418,45 +18992,147 @@ var init_provider = __esm({
17418
18992
  }
17419
18993
  });
17420
18994
 
18995
+ // packages/server/src/commands/custom-provider.ts
18996
+ import { z as z23 } from "zod";
18997
+ function requireCustomProviderSupport(ctx) {
18998
+ if (!ctx.customProviderRepo || !ctx.setProviderRegistry) {
18999
+ throw {
19000
+ code: "custom_provider_unavailable",
19001
+ message: "Custom provider runtime is not configured"
19002
+ };
19003
+ }
19004
+ }
19005
+ function materializeConfig(input2, previous) {
19006
+ const now = Date.now();
19007
+ return {
19008
+ ...input2,
19009
+ startupPrompt: input2.startupPrompt?.trim() || void 0,
19010
+ createdAt: previous?.createdAt ?? now,
19011
+ updatedAt: now
19012
+ };
19013
+ }
19014
+ var CapabilitySchema, BaseCustomProviderInputSchema;
19015
+ var init_custom_provider2 = __esm({
19016
+ "packages/server/src/commands/custom-provider.ts"() {
19017
+ "use strict";
19018
+ init_src();
19019
+ init_custom_provider();
19020
+ init_dispatch();
19021
+ CapabilitySchema = z23.object({
19022
+ key: z23.enum([
19023
+ "interactive_session",
19024
+ "supervisor_eval",
19025
+ "idle_detection",
19026
+ "context_attach",
19027
+ "review"
19028
+ ]),
19029
+ supported: z23.boolean(),
19030
+ label: z23.string().min(1)
19031
+ });
19032
+ BaseCustomProviderInputSchema = z23.object({
19033
+ id: z23.string().trim().min(1).regex(/^[a-z0-9][a-z0-9-_]*$/),
19034
+ displayName: z23.string().trim().min(1),
19035
+ command: z23.string().trim().min(1),
19036
+ args: z23.array(z23.string()),
19037
+ env: z23.record(z23.string(), z23.string()),
19038
+ cwdMode: z23.literal("workspace_root"),
19039
+ sessionMode: z23.literal("interactive"),
19040
+ startupPrompt: z23.string().optional(),
19041
+ capabilities: z23.array(CapabilitySchema).min(1)
19042
+ });
19043
+ registerCommand("customProvider.list", z23.object({}), async (_args, ctx) => {
19044
+ requireCustomProviderSupport(ctx);
19045
+ return ctx.customProviderRepo.list().map((config) => toProviderListItem(buildCustomProviderDefinition(config)));
19046
+ });
19047
+ registerCommand("customProvider.create", BaseCustomProviderInputSchema, async (args, ctx) => {
19048
+ requireCustomProviderSupport(ctx);
19049
+ if (ctx.providerRegistry.some((provider) => provider.id === args.id)) {
19050
+ throw {
19051
+ code: "custom_provider_exists",
19052
+ message: `Provider already exists: ${args.id}`
19053
+ };
19054
+ }
19055
+ const config = materializeConfig(args);
19056
+ const saved = ctx.customProviderRepo.set(config);
19057
+ const definition = buildCustomProviderDefinition(saved);
19058
+ ctx.setProviderRegistry(upsertProviderDefinition(ctx.providerRegistry, definition));
19059
+ return toProviderListItem(definition);
19060
+ });
19061
+ registerCommand("customProvider.update", BaseCustomProviderInputSchema, async (args, ctx) => {
19062
+ requireCustomProviderSupport(ctx);
19063
+ const existing = ctx.customProviderRepo.get(args.id);
19064
+ if (!existing) {
19065
+ throw {
19066
+ code: "custom_provider_not_found",
19067
+ message: `Custom provider not found: ${args.id}`
19068
+ };
19069
+ }
19070
+ const saved = ctx.customProviderRepo.set(materializeConfig(args, existing));
19071
+ const definition = buildCustomProviderDefinition(saved);
19072
+ ctx.setProviderRegistry(upsertProviderDefinition(ctx.providerRegistry, definition));
19073
+ return toProviderListItem(definition);
19074
+ });
19075
+ registerCommand(
19076
+ "customProvider.delete",
19077
+ z23.object({
19078
+ id: z23.string().trim().min(1)
19079
+ }),
19080
+ async (args, ctx) => {
19081
+ requireCustomProviderSupport(ctx);
19082
+ const existing = ctx.customProviderRepo.get(args.id);
19083
+ if (!existing) {
19084
+ throw {
19085
+ code: "custom_provider_not_found",
19086
+ message: `Custom provider not found: ${args.id}`
19087
+ };
19088
+ }
19089
+ ctx.customProviderRepo.delete(args.id);
19090
+ ctx.setProviderRegistry(removeProviderDefinition(ctx.providerRegistry, args.id));
19091
+ return { deleted: true, id: args.id };
19092
+ }
19093
+ );
19094
+ }
19095
+ });
19096
+
17421
19097
  // packages/server/src/commands/supervisor.ts
17422
- import { z as z18 } from "zod";
19098
+ import { z as z24 } from "zod";
17423
19099
  var supervisorObjectiveSchema, createSupervisorSchema, updateSupervisorSchema, sessionIdSchema, workspaceIdSchema, supervisorIdSchema, restoreSupervisorSchema;
17424
19100
  var init_supervisor2 = __esm({
17425
19101
  "packages/server/src/commands/supervisor.ts"() {
17426
19102
  "use strict";
17427
19103
  init_dispatch();
17428
- supervisorObjectiveSchema = z18.string().trim().min(1).max(4e3);
17429
- createSupervisorSchema = z18.object({
17430
- sessionId: z18.string(),
17431
- workspaceId: z18.string(),
19104
+ supervisorObjectiveSchema = z24.string().trim().min(1).max(4e3);
19105
+ createSupervisorSchema = z24.object({
19106
+ sessionId: z24.string(),
19107
+ workspaceId: z24.string(),
17432
19108
  objective: supervisorObjectiveSchema,
17433
- evaluatorProviderId: z18.string(),
17434
- evaluatorModel: z18.string().trim().min(1).max(200).optional(),
17435
- maxSupervisionCount: z18.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional(),
17436
- scheduledAt: z18.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional()
19109
+ evaluatorProviderId: z24.string(),
19110
+ evaluatorModel: z24.string().trim().min(1).max(200).optional(),
19111
+ maxSupervisionCount: z24.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional(),
19112
+ scheduledAt: z24.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional()
17437
19113
  }).strict();
17438
- updateSupervisorSchema = z18.object({
17439
- id: z18.string(),
19114
+ updateSupervisorSchema = z24.object({
19115
+ id: z24.string(),
17440
19116
  objective: supervisorObjectiveSchema.optional(),
17441
- evaluatorProviderId: z18.string().optional(),
17442
- evaluatorModel: z18.string().trim().min(1).max(200).nullable().optional(),
17443
- maxSupervisionCount: z18.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional(),
17444
- scheduledAt: z18.number().int().min(0).max(Number.MAX_SAFE_INTEGER).nullable().optional()
19117
+ evaluatorProviderId: z24.string().optional(),
19118
+ evaluatorModel: z24.string().trim().min(1).max(200).nullable().optional(),
19119
+ maxSupervisionCount: z24.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional(),
19120
+ scheduledAt: z24.number().int().min(0).max(Number.MAX_SAFE_INTEGER).nullable().optional()
17445
19121
  }).strict().refine(
17446
19122
  (input2) => input2.objective !== void 0 || input2.evaluatorProviderId !== void 0 || input2.evaluatorModel !== void 0 || input2.maxSupervisionCount !== void 0 || input2.scheduledAt !== void 0,
17447
19123
  "at least one supervisor field is required"
17448
19124
  );
17449
- sessionIdSchema = z18.object({ sessionId: z18.string() });
17450
- workspaceIdSchema = z18.object({ workspaceId: z18.string() });
17451
- supervisorIdSchema = z18.object({ id: z18.string() });
17452
- restoreSupervisorSchema = z18.object({
17453
- sessionId: z18.string(),
17454
- workspaceId: z18.string(),
17455
- sourceTargetId: z18.string(),
17456
- evaluatorProviderId: z18.string(),
17457
- evaluatorModel: z18.string().trim().min(1).max(200).optional(),
17458
- maxSupervisionCount: z18.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional(),
17459
- scheduledAt: z18.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional()
19125
+ sessionIdSchema = z24.object({ sessionId: z24.string() });
19126
+ workspaceIdSchema = z24.object({ workspaceId: z24.string() });
19127
+ supervisorIdSchema = z24.object({ id: z24.string() });
19128
+ restoreSupervisorSchema = z24.object({
19129
+ sessionId: z24.string(),
19130
+ workspaceId: z24.string(),
19131
+ sourceTargetId: z24.string(),
19132
+ evaluatorProviderId: z24.string(),
19133
+ evaluatorModel: z24.string().trim().min(1).max(200).optional(),
19134
+ maxSupervisionCount: z24.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional(),
19135
+ scheduledAt: z24.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional()
17460
19136
  }).strict();
17461
19137
  registerCommand("supervisor.create", createSupervisorSchema, async (args, ctx) => {
17462
19138
  return {
@@ -17658,7 +19334,7 @@ var init_worktree = __esm({
17658
19334
 
17659
19335
  // packages/server/src/commands/worktree.ts
17660
19336
  import path13 from "node:path";
17661
- import { z as z19 } from "zod";
19337
+ import { z as z25 } from "zod";
17662
19338
  async function findRelatedWorkspaceIds(ctx, workspacePath) {
17663
19339
  const targetCommonDir = await getGitCommonDirPath(workspacePath);
17664
19340
  const relatedWorkspaceIds = await Promise.all(
@@ -17691,7 +19367,7 @@ var init_worktree2 = __esm({
17691
19367
  init_worktree();
17692
19368
  init_dispatch();
17693
19369
  init_git_events();
17694
- registerCommand("worktree.list", z19.object({ workspaceId: z19.string() }), async (args, ctx) => {
19370
+ registerCommand("worktree.list", z25.object({ workspaceId: z25.string() }), async (args, ctx) => {
17695
19371
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
17696
19372
  if (!workspace) {
17697
19373
  throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
@@ -17700,7 +19376,7 @@ var init_worktree2 = __esm({
17700
19376
  });
17701
19377
  registerCommand(
17702
19378
  "worktree.status",
17703
- z19.object({ workspaceId: z19.string(), worktreePath: z19.string() }),
19379
+ z25.object({ workspaceId: z25.string(), worktreePath: z25.string() }),
17704
19380
  async (args, ctx) => {
17705
19381
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
17706
19382
  if (!workspace) {
@@ -17712,10 +19388,10 @@ var init_worktree2 = __esm({
17712
19388
  );
17713
19389
  registerCommand(
17714
19390
  "worktree.diff",
17715
- z19.object({
17716
- workspaceId: z19.string(),
17717
- worktreePath: z19.string(),
17718
- staged: z19.boolean().optional().default(false)
19391
+ z25.object({
19392
+ workspaceId: z25.string(),
19393
+ worktreePath: z25.string(),
19394
+ staged: z25.boolean().optional().default(false)
17719
19395
  }),
17720
19396
  async (args, ctx) => {
17721
19397
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -17728,7 +19404,7 @@ var init_worktree2 = __esm({
17728
19404
  );
17729
19405
  registerCommand(
17730
19406
  "worktree.tree",
17731
- z19.object({ workspaceId: z19.string(), worktreePath: z19.string() }),
19407
+ z25.object({ workspaceId: z25.string(), worktreePath: z25.string() }),
17732
19408
  async (args, ctx) => {
17733
19409
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
17734
19410
  if (!workspace) {
@@ -17740,10 +19416,10 @@ var init_worktree2 = __esm({
17740
19416
  );
17741
19417
  registerCommand(
17742
19418
  "worktree.create",
17743
- z19.object({
17744
- workspaceId: z19.string(),
17745
- branch: z19.string(),
17746
- path: z19.string()
19419
+ z25.object({
19420
+ workspaceId: z25.string(),
19421
+ branch: z25.string(),
19422
+ path: z25.string()
17747
19423
  }),
17748
19424
  async (args, ctx) => {
17749
19425
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -17758,10 +19434,10 @@ var init_worktree2 = __esm({
17758
19434
  );
17759
19435
  registerCommand(
17760
19436
  "worktree.remove",
17761
- z19.object({
17762
- workspaceId: z19.string(),
17763
- worktreePath: z19.string(),
17764
- force: z19.boolean().optional().default(false)
19437
+ z25.object({
19438
+ workspaceId: z25.string(),
19439
+ worktreePath: z25.string(),
19440
+ force: z25.boolean().optional().default(false)
17765
19441
  }),
17766
19442
  async (args, ctx) => {
17767
19443
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -17785,7 +19461,7 @@ var init_worktree2 = __esm({
17785
19461
  });
17786
19462
 
17787
19463
  // packages/server/src/commands/fencing.ts
17788
- import { z as z20 } from "zod";
19464
+ import { z as z26 } from "zod";
17789
19465
  function createMockFencingRequest() {
17790
19466
  return {
17791
19467
  ip: "127.0.0.1",
@@ -17798,9 +19474,9 @@ var init_fencing2 = __esm({
17798
19474
  init_dispatch();
17799
19475
  registerCommand(
17800
19476
  "fencing.request",
17801
- z20.object({
17802
- workspaceId: z20.string(),
17803
- tabId: z20.string()
19477
+ z26.object({
19478
+ workspaceId: z26.string(),
19479
+ tabId: z26.string()
17804
19480
  }),
17805
19481
  async (args, ctx, clientId) => {
17806
19482
  return ctx.fencingMgr.requestControl(
@@ -17813,7 +19489,7 @@ var init_fencing2 = __esm({
17813
19489
  );
17814
19490
  registerCommand(
17815
19491
  "fencing.heartbeat",
17816
- z20.object({ workspaceId: z20.string() }),
19492
+ z26.object({ workspaceId: z26.string() }),
17817
19493
  async (args, ctx, clientId) => {
17818
19494
  const success = ctx.fencingMgr.heartbeat(args.workspaceId, clientId);
17819
19495
  return { success };
@@ -17821,13 +19497,13 @@ var init_fencing2 = __esm({
17821
19497
  );
17822
19498
  registerCommand(
17823
19499
  "fencing.release",
17824
- z20.object({ workspaceId: z20.string() }),
19500
+ z26.object({ workspaceId: z26.string() }),
17825
19501
  async (args, ctx, clientId) => {
17826
19502
  ctx.fencingMgr.release(args.workspaceId, clientId);
17827
19503
  return {};
17828
19504
  }
17829
19505
  );
17830
- registerCommand("fencing.status", z20.object({ workspaceId: z20.string() }), async (args, ctx) => {
19506
+ registerCommand("fencing.status", z26.object({ workspaceId: z26.string() }), async (args, ctx) => {
17831
19507
  const controller = ctx.fencingMgr.getController(args.workspaceId);
17832
19508
  const isUnresponsive = ctx.fencingMgr.isControllerUnresponsive(args.workspaceId);
17833
19509
  return {
@@ -17838,9 +19514,9 @@ var init_fencing2 = __esm({
17838
19514
  });
17839
19515
  registerCommand(
17840
19516
  "fencing.takeover",
17841
- z20.object({
17842
- workspaceId: z20.string(),
17843
- tabId: z20.string()
19517
+ z26.object({
19518
+ workspaceId: z26.string(),
19519
+ tabId: z26.string()
17844
19520
  }),
17845
19521
  async (args, ctx, clientId) => {
17846
19522
  return ctx.fencingMgr.forceTakeover(
@@ -17878,7 +19554,7 @@ var init_runtime_status2 = __esm({
17878
19554
  });
17879
19555
 
17880
19556
  // packages/server/src/commands/lsp.ts
17881
- import { z as z21 } from "zod";
19557
+ import { z as z27 } from "zod";
17882
19558
  var init_lsp2 = __esm({
17883
19559
  "packages/server/src/commands/lsp.ts"() {
17884
19560
  "use strict";
@@ -17886,16 +19562,16 @@ var init_lsp2 = __esm({
17886
19562
  init_dispatch();
17887
19563
  registerCommand(
17888
19564
  "lsp.ensureSession",
17889
- z21.object({
17890
- workspaceId: z21.string(),
17891
- path: z21.string()
19565
+ z27.object({
19566
+ workspaceId: z27.string(),
19567
+ path: z27.string()
17892
19568
  }),
17893
19569
  async (args, ctx) => ctx.lspMgr.ensureSession(args)
17894
19570
  );
17895
19571
  registerCommand(
17896
19572
  "lsp.setMode",
17897
- z21.object({
17898
- mode: z21.enum(["auto", "off"])
19573
+ z27.object({
19574
+ mode: z27.enum(["auto", "off"])
17899
19575
  }),
17900
19576
  async (args, ctx) => {
17901
19577
  await ctx.lspMgr.setRuntimeMode(args.mode);
@@ -17904,8 +19580,8 @@ var init_lsp2 = __esm({
17904
19580
  );
17905
19581
  registerCommand(
17906
19582
  "lsp.runtimeStatus",
17907
- z21.object({
17908
- workspaceId: z21.string()
19583
+ z27.object({
19584
+ workspaceId: z27.string()
17909
19585
  }),
17910
19586
  async (args, ctx) => {
17911
19587
  if (!ctx.lspToolMgr) {
@@ -17929,9 +19605,9 @@ var init_lsp2 = __esm({
17929
19605
  );
17930
19606
  registerCommand(
17931
19607
  "lsp.install.start",
17932
- z21.object({
17933
- workspaceId: z21.string(),
17934
- serverKind: z21.enum(["typescript", "python", "go", "rust"])
19608
+ z27.object({
19609
+ workspaceId: z27.string(),
19610
+ serverKind: z27.enum(["typescript", "python", "go", "rust"])
17935
19611
  }),
17936
19612
  async (args, ctx) => {
17937
19613
  if (!ctx.lspToolInstallMgr) {
@@ -17955,8 +19631,8 @@ var init_lsp2 = __esm({
17955
19631
  );
17956
19632
  registerCommand(
17957
19633
  "lsp.install.get",
17958
- z21.object({
17959
- jobId: z21.string()
19634
+ z27.object({
19635
+ jobId: z27.string()
17960
19636
  }),
17961
19637
  async (args, ctx) => {
17962
19638
  if (!ctx.lspToolInstallMgr) {
@@ -17977,86 +19653,86 @@ var init_lsp2 = __esm({
17977
19653
  );
17978
19654
  registerCommand(
17979
19655
  "lsp.openDocument",
17980
- z21.object({
17981
- workspaceId: z21.string(),
17982
- path: z21.string(),
17983
- languageId: z21.string(),
17984
- text: z21.string()
19656
+ z27.object({
19657
+ workspaceId: z27.string(),
19658
+ path: z27.string(),
19659
+ languageId: z27.string(),
19660
+ text: z27.string()
17985
19661
  }),
17986
19662
  async (args, ctx) => ctx.lspMgr.openDocument(args)
17987
19663
  );
17988
19664
  registerCommand(
17989
19665
  "lsp.changeDocument",
17990
- z21.object({
17991
- workspaceId: z21.string(),
17992
- path: z21.string(),
17993
- text: z21.string()
19666
+ z27.object({
19667
+ workspaceId: z27.string(),
19668
+ path: z27.string(),
19669
+ text: z27.string()
17994
19670
  }),
17995
19671
  async (args, ctx) => ctx.lspMgr.changeDocument(args)
17996
19672
  );
17997
19673
  registerCommand(
17998
19674
  "lsp.closeDocument",
17999
- z21.object({
18000
- workspaceId: z21.string(),
18001
- path: z21.string()
19675
+ z27.object({
19676
+ workspaceId: z27.string(),
19677
+ path: z27.string()
18002
19678
  }),
18003
19679
  async (args, ctx) => ctx.lspMgr.closeDocument(args)
18004
19680
  );
18005
19681
  registerCommand(
18006
19682
  "lsp.definition",
18007
- z21.object({
18008
- workspaceId: z21.string(),
18009
- path: z21.string(),
18010
- line: z21.number().int().positive(),
18011
- column: z21.number().int().positive()
19683
+ z27.object({
19684
+ workspaceId: z27.string(),
19685
+ path: z27.string(),
19686
+ line: z27.number().int().positive(),
19687
+ column: z27.number().int().positive()
18012
19688
  }),
18013
19689
  async (args, ctx) => ctx.lspMgr.definition(args)
18014
19690
  );
18015
19691
  registerCommand(
18016
19692
  "lsp.declaration",
18017
- z21.object({
18018
- workspaceId: z21.string(),
18019
- path: z21.string(),
18020
- line: z21.number().int().positive(),
18021
- column: z21.number().int().positive()
19693
+ z27.object({
19694
+ workspaceId: z27.string(),
19695
+ path: z27.string(),
19696
+ line: z27.number().int().positive(),
19697
+ column: z27.number().int().positive()
18022
19698
  }),
18023
19699
  async (args, ctx) => ctx.lspMgr.declaration(args)
18024
19700
  );
18025
19701
  registerCommand(
18026
19702
  "lsp.typeDefinition",
18027
- z21.object({
18028
- workspaceId: z21.string(),
18029
- path: z21.string(),
18030
- line: z21.number().int().positive(),
18031
- column: z21.number().int().positive()
19703
+ z27.object({
19704
+ workspaceId: z27.string(),
19705
+ path: z27.string(),
19706
+ line: z27.number().int().positive(),
19707
+ column: z27.number().int().positive()
18032
19708
  }),
18033
19709
  async (args, ctx) => ctx.lspMgr.typeDefinition(args)
18034
19710
  );
18035
19711
  registerCommand(
18036
19712
  "lsp.references",
18037
- z21.object({
18038
- workspaceId: z21.string(),
18039
- path: z21.string(),
18040
- line: z21.number().int().positive(),
18041
- column: z21.number().int().positive()
19713
+ z27.object({
19714
+ workspaceId: z27.string(),
19715
+ path: z27.string(),
19716
+ line: z27.number().int().positive(),
19717
+ column: z27.number().int().positive()
18042
19718
  }),
18043
19719
  async (args, ctx) => ctx.lspMgr.references(args)
18044
19720
  );
18045
19721
  registerCommand(
18046
19722
  "lsp.hover",
18047
- z21.object({
18048
- workspaceId: z21.string(),
18049
- path: z21.string(),
18050
- line: z21.number().int().positive(),
18051
- column: z21.number().int().positive()
19723
+ z27.object({
19724
+ workspaceId: z27.string(),
19725
+ path: z27.string(),
19726
+ line: z27.number().int().positive(),
19727
+ column: z27.number().int().positive()
18052
19728
  }),
18053
19729
  async (args, ctx) => ctx.lspMgr.hover(args)
18054
19730
  );
18055
19731
  registerCommand(
18056
19732
  "lsp.documentSymbols",
18057
- z21.object({
18058
- workspaceId: z21.string(),
18059
- path: z21.string()
19733
+ z27.object({
19734
+ workspaceId: z27.string(),
19735
+ path: z27.string()
18060
19736
  }),
18061
19737
  async (args, ctx) => ctx.lspMgr.documentSymbols(args)
18062
19738
  );
@@ -18064,12 +19740,12 @@ var init_lsp2 = __esm({
18064
19740
  });
18065
19741
 
18066
19742
  // packages/server/src/commands/updates.ts
18067
- import { z as z22 } from "zod";
19743
+ import { z as z28 } from "zod";
18068
19744
  var init_updates = __esm({
18069
19745
  "packages/server/src/commands/updates.ts"() {
18070
19746
  "use strict";
18071
19747
  init_dispatch();
18072
- registerCommand("updates.getState", z22.object({}).default({}), async (_args, ctx) => {
19748
+ registerCommand("updates.getState", z28.object({}).default({}), async (_args, ctx) => {
18073
19749
  if (!ctx.updateService) {
18074
19750
  throw {
18075
19751
  code: "update_unavailable",
@@ -18078,7 +19754,7 @@ var init_updates = __esm({
18078
19754
  }
18079
19755
  return ctx.updateService.getStateView();
18080
19756
  });
18081
- registerCommand("updates.check", z22.object({}).default({}), async (_args, ctx) => {
19757
+ registerCommand("updates.check", z28.object({}).default({}), async (_args, ctx) => {
18082
19758
  if (!ctx.updateService) {
18083
19759
  throw {
18084
19760
  code: "update_unavailable",
@@ -18087,7 +19763,7 @@ var init_updates = __esm({
18087
19763
  }
18088
19764
  return await ctx.updateService.checkForUpdates({ manual: true });
18089
19765
  });
18090
- registerCommand("updates.prepareInstall", z22.object({}).default({}), async (_args, ctx) => {
19766
+ registerCommand("updates.prepareInstall", z28.object({}).default({}), async (_args, ctx) => {
18091
19767
  if (!ctx.updateService) {
18092
19768
  throw {
18093
19769
  code: "update_unavailable",
@@ -18098,9 +19774,9 @@ var init_updates = __esm({
18098
19774
  });
18099
19775
  registerCommand(
18100
19776
  "updates.startInstall",
18101
- z22.object({
18102
- targetVersion: z22.string().optional(),
18103
- force: z22.boolean().optional()
19777
+ z28.object({
19778
+ targetVersion: z28.string().optional(),
19779
+ force: z28.boolean().optional()
18104
19780
  }),
18105
19781
  async (args, ctx) => {
18106
19782
  if (!ctx.updateService) {
@@ -18125,12 +19801,17 @@ var init_commands = __esm({
18125
19801
  init_connection();
18126
19802
  init_recovery();
18127
19803
  init_session2();
19804
+ init_session_metadata();
19805
+ init_session_review();
18128
19806
  init_terminal();
18129
19807
  init_file();
18130
19808
  init_git2();
19809
+ init_agent_instructions();
19810
+ init_agent_context();
18131
19811
  init_settings2();
18132
19812
  init_diagnostics2();
18133
19813
  init_provider();
19814
+ init_custom_provider2();
18134
19815
  init_supervisor2();
18135
19816
  init_worktree2();
18136
19817
  init_fencing2();
@@ -18142,12 +19823,12 @@ var init_commands = __esm({
18142
19823
  // packages/server/src/server.ts
18143
19824
  import { mkdtempSync, rmSync as rmSync2 } from "node:fs";
18144
19825
  import { tmpdir } from "node:os";
18145
- import { join as join15 } from "node:path";
19826
+ import { join as join18 } from "node:path";
18146
19827
  async function createServer(configOverrides) {
18147
19828
  const config = parseServerConfig(configOverrides);
18148
19829
  const configuredStateDir = resolveConfiguredStateDir(config);
18149
19830
  const shouldCleanupStateRoot = configuredStateDir === IN_MEMORY_STATE_DIR;
18150
- const stateRoot = shouldCleanupStateRoot ? mkdtempSync(join15(tmpdir(), "coder-studio-state-")) : configuredStateDir;
19831
+ const stateRoot = shouldCleanupStateRoot ? mkdtempSync(join18(tmpdir(), "coder-studio-state-")) : configuredStateDir;
18151
19832
  ensureStateDir(config);
18152
19833
  const eventBus = new EventBus();
18153
19834
  const activationMgr = new ActivationManager();
@@ -18157,10 +19838,10 @@ async function createServer(configOverrides) {
18157
19838
  let commandContext;
18158
19839
  let lspMgr = null;
18159
19840
  const terminalRepo = new TerminalRepo({
18160
- filePath: join15(stateRoot, "state", "terminals.json")
19841
+ filePath: join18(stateRoot, "state", "terminals.json")
18161
19842
  });
18162
19843
  const sessionRepo = new SessionRepo({
18163
- filePath: join15(stateRoot, "state", "sessions.json")
19844
+ filePath: join18(stateRoot, "state", "sessions.json")
18164
19845
  });
18165
19846
  const terminalMgr = new TerminalManager({
18166
19847
  ptyHost: createPtyHost(),
@@ -18168,10 +19849,10 @@ async function createServer(configOverrides) {
18168
19849
  db: terminalRepo
18169
19850
  });
18170
19851
  const settingsRepo = new SettingsRepo({
18171
- filePath: join15(stateRoot, "state", "settings.json")
19852
+ filePath: join18(stateRoot, "state", "settings.json")
18172
19853
  });
18173
19854
  const updateStateRepo = new UpdateStateRepo({
18174
- filePath: join15(stateRoot, "state", "update-state.json"),
19855
+ filePath: join18(stateRoot, "state", "update-state.json"),
18175
19856
  currentVersion: config.appVersion ?? "0.0.0"
18176
19857
  });
18177
19858
  const autoFetch = new AutoFetchScheduler({
@@ -18204,17 +19885,27 @@ async function createServer(configOverrides) {
18204
19885
  }
18205
19886
  });
18206
19887
  const providerConfigRepo = new ProviderConfigRepo({
18207
- filePath: join15(stateRoot, "state", "provider-configs.json")
19888
+ filePath: join18(stateRoot, "state", "provider-configs.json")
19889
+ });
19890
+ const customProviderRepo = new CustomProviderRepo({
19891
+ filePath: join18(stateRoot, "state", "custom-providers.json")
18208
19892
  });
18209
19893
  const workspaceRepo = new WorkspaceRepo({
18210
- filePath: join15(stateRoot, "state", "workspaces.json")
19894
+ filePath: join18(stateRoot, "state", "workspaces.json")
19895
+ });
19896
+ const sessionMetadataRepo = new SessionMetadataRepo({
19897
+ workspaceRepo
18211
19898
  });
19899
+ let activeProviderRegistry = [
19900
+ ...providerRegistry,
19901
+ ...customProviderRepo.list().map((config2) => buildCustomProviderDefinition(config2))
19902
+ ];
18212
19903
  const sessionMgr = new SessionManager({
18213
19904
  terminalMgr,
18214
19905
  eventBus,
18215
19906
  db: sessionRepo,
18216
19907
  broadcaster: wsHub,
18217
- providerRegistry,
19908
+ providerRegistry: activeProviderRegistry,
18218
19909
  providerConfigRepo
18219
19910
  });
18220
19911
  let supervisorMgr;
@@ -18225,13 +19916,15 @@ async function createServer(configOverrides) {
18225
19916
  broadcaster: wsHub,
18226
19917
  autoFetch,
18227
19918
  teardown: async (workspaceId) => {
19919
+ const persistedSessions = sessionRepo.findByWorkspaceId(workspaceId);
18228
19920
  await lspMgr?.disposeWorkspace(workspaceId);
18229
19921
  await supervisorMgr?.deleteForWorkspace(workspaceId);
18230
19922
  await sessionMgr.stopForWorkspace(workspaceId);
18231
19923
  await terminalMgr.closeForWorkspace(workspaceId);
18232
19924
  sessionMgr.deleteEndedForWorkspace(workspaceId);
18233
- for (const session of sessionRepo.findByWorkspaceId(workspaceId)) {
19925
+ for (const session of persistedSessions) {
18234
19926
  sessionRepo.delete(session.id);
19927
+ sessionMetadataRepo.delete(session.id);
18235
19928
  }
18236
19929
  for (const terminal of terminalRepo.listByWorkspace(workspaceId)) {
18237
19930
  terminalRepo.delete(terminal.id);
@@ -18242,13 +19935,13 @@ async function createServer(configOverrides) {
18242
19935
  )
18243
19936
  });
18244
19937
  const authSessionRepo = new AuthSessionRepo({
18245
- filePath: join15(stateRoot, "state", "auth-sessions.json")
19938
+ filePath: join18(stateRoot, "state", "auth-sessions.json")
18246
19939
  });
18247
19940
  const authLoginBlockRepo = new AuthLoginBlockRepo({
18248
- filePath: join15(stateRoot, "state", "auth-login-blocks.json")
19941
+ filePath: join18(stateRoot, "state", "auth-login-blocks.json")
18249
19942
  });
18250
19943
  const appearanceAssetRepo = new AppearanceAssetRepo({
18251
- filePath: join15(stateRoot, "state", "appearance-assets.json")
19944
+ filePath: join18(stateRoot, "state", "appearance-assets.json")
18252
19945
  });
18253
19946
  const app = await buildFastifyApp({
18254
19947
  wsHub,
@@ -18299,7 +19992,7 @@ async function createServer(configOverrides) {
18299
19992
  terminalMgr,
18300
19993
  workspaceMgr,
18301
19994
  sessionMgr,
18302
- providerRegistry,
19995
+ providerRegistry: activeProviderRegistry,
18303
19996
  providerConfigRepo,
18304
19997
  settingsRepo,
18305
19998
  supervisorRepo,
@@ -18312,7 +20005,7 @@ async function createServer(configOverrides) {
18312
20005
  const providerRuntimeDeps = providerMockOverrides ? {
18313
20006
  commandExists: providerMockOverrides.commandExists
18314
20007
  } : {};
18315
- const providerInstallMgr = new ProviderInstallManager(providerRegistry, {
20008
+ const providerInstallMgr = new ProviderInstallManager(activeProviderRegistry, {
18316
20009
  ...providerRuntimeDeps,
18317
20010
  runCommand: providerMockOverrides?.runCommand ?? runCommandAsString
18318
20011
  });
@@ -18324,7 +20017,7 @@ async function createServer(configOverrides) {
18324
20017
  ...config.update,
18325
20018
  currentVersion: config.appVersion ?? "0.0.0"
18326
20019
  },
18327
- updateWorkerLogFilePath: join15(stateRoot, "logs", "update-worker.log"),
20020
+ updateWorkerLogFilePath: join18(stateRoot, "logs", "update-worker.log"),
18328
20021
  countRunningTerminals: () => terminalMgr.getAll().filter((terminal) => terminal.alive).length,
18329
20022
  countRunningSessions: () => sessionMgr.getAll().filter((session) => session.state === "starting" || session.state === "running").length,
18330
20023
  countActiveSupervisors: () => supervisorMgr?.countActive() ?? 0
@@ -18338,7 +20031,7 @@ async function createServer(configOverrides) {
18338
20031
  broadcaster: wsHub,
18339
20032
  settingsRepo,
18340
20033
  providerConfigRepo,
18341
- providerRegistry,
20034
+ providerRegistry: activeProviderRegistry,
18342
20035
  fencingMgr,
18343
20036
  supervisorMgr,
18344
20037
  autoFetch,
@@ -18349,7 +20042,16 @@ async function createServer(configOverrides) {
18349
20042
  lspMgr,
18350
20043
  lspToolMgr,
18351
20044
  lspToolInstallMgr,
18352
- updateService
20045
+ updateService,
20046
+ customProviderRepo,
20047
+ sessionMetadataRepo,
20048
+ setProviderRegistry: (providers) => {
20049
+ activeProviderRegistry = providers;
20050
+ commandContext.providerRegistry = providers;
20051
+ providerInstallMgr.setProviders(providers);
20052
+ sessionMgr.setProviderRegistry(providers);
20053
+ supervisorMgr?.setProviderRegistry(providers);
20054
+ }
18353
20055
  };
18354
20056
  wsHub.setCommandContext(commandContext);
18355
20057
  await app.listen({
@@ -18433,13 +20135,16 @@ var init_server = __esm({
18433
20135
  init_manifest_store();
18434
20136
  init_tool_root();
18435
20137
  init_command_runner();
20138
+ init_custom_provider();
18436
20139
  init_e2e_provider_mock();
18437
20140
  init_install_manager2();
18438
20141
  init_manager3();
18439
20142
  init_appearance_asset_repo();
18440
20143
  init_auth_login_block_repo();
18441
20144
  init_auth_session_repo();
20145
+ init_custom_provider_repo();
18442
20146
  init_provider_config_repo();
20147
+ init_session_metadata_repo();
18443
20148
  init_session_repo();
18444
20149
  init_settings_repo();
18445
20150
  init_supervisor_repo();
@@ -18482,7 +20187,9 @@ var init_storage = __esm({
18482
20187
  "use strict";
18483
20188
  init_auth_login_block_repo();
18484
20189
  init_auth_session_repo();
20190
+ init_custom_provider_repo();
18485
20191
  init_provider_config_repo();
20192
+ init_session_metadata_repo();
18486
20193
  init_session_repo();
18487
20194
  init_settings_repo();
18488
20195
  init_supervisor_repo();
@@ -18510,10 +20217,12 @@ __export(src_exports, {
18510
20217
  ActiveTerminal: () => ActiveTerminal,
18511
20218
  AuthLoginBlockRepo: () => AuthLoginBlockRepo,
18512
20219
  AuthSessionRepo: () => AuthSessionRepo,
20220
+ CustomProviderRepo: () => CustomProviderRepo,
18513
20221
  EventBus: () => EventBus,
18514
20222
  NodePtyHost: () => NodePtyHost,
18515
20223
  ProviderConfigRepo: () => ProviderConfigRepo,
18516
20224
  RingBuffer: () => RingBuffer,
20225
+ SessionMetadataRepo: () => SessionMetadataRepo,
18517
20226
  SessionRepo: () => SessionRepo,
18518
20227
  SettingsRepo: () => SettingsRepo,
18519
20228
  SupervisorRepo: () => SupervisorRepo,
@@ -18548,20 +20257,20 @@ var init_src4 = __esm({
18548
20257
 
18549
20258
  // packages/cli/src/cli.ts
18550
20259
  import { existsSync as existsSync15 } from "fs";
18551
- import { dirname as dirname10, join as join20 } from "path";
20260
+ import { dirname as dirname10, join as join23 } from "path";
18552
20261
  import { fileURLToPath as fileURLToPath5 } from "url";
18553
20262
 
18554
20263
  // packages/cli/src/auth-control.ts
18555
20264
  await init_src4();
18556
- import { join as join17 } from "node:path";
20265
+ import { join as join20 } from "node:path";
18557
20266
 
18558
20267
  // packages/cli/src/config-store.ts
18559
20268
  init_state_paths();
18560
20269
  import { existsSync as existsSync10, mkdirSync as mkdirSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "fs";
18561
20270
  import { homedir as homedir4 } from "os";
18562
- import { join as join16 } from "path";
20271
+ import { join as join19 } from "path";
18563
20272
  function getCliConfigPath() {
18564
- return join16(homedir4(), ".coder-studio", "config.json");
20273
+ return join19(homedir4(), ".coder-studio", "config.json");
18565
20274
  }
18566
20275
  function normalizeLegacyDataDir(input2) {
18567
20276
  return normalizeLegacyStateDir(input2);
@@ -18588,7 +20297,7 @@ function readCliConfig() {
18588
20297
  }
18589
20298
  function writeCliConfig(config) {
18590
20299
  const path14 = getCliConfigPath();
18591
- const dir = join16(homedir4(), ".coder-studio");
20300
+ const dir = join19(homedir4(), ".coder-studio");
18592
20301
  const normalizedConfig = {
18593
20302
  ...config.host !== void 0 ? { host: config.host } : {},
18594
20303
  ...config.port !== void 0 && config.port > 0 ? { port: config.port } : {},
@@ -18610,7 +20319,7 @@ function resolveStateDir() {
18610
20319
  }
18611
20320
  async function listAuthBlocks(now = Date.now()) {
18612
20321
  const repo = new AuthLoginBlockRepo({
18613
- filePath: join17(resolveStateDir(), "state", "auth-login-blocks.json")
20322
+ filePath: join20(resolveStateDir(), "state", "auth-login-blocks.json")
18614
20323
  });
18615
20324
  return repo.listActiveBlocks(now).map((record) => ({
18616
20325
  ip: record.ip,
@@ -18622,7 +20331,7 @@ async function listAuthBlocks(now = Date.now()) {
18622
20331
  }
18623
20332
  async function clearAuthBlockByIp(ip) {
18624
20333
  const repo = new AuthLoginBlockRepo({
18625
- filePath: join17(resolveStateDir(), "state", "auth-login-blocks.json")
20334
+ filePath: join20(resolveStateDir(), "state", "auth-login-blocks.json")
18626
20335
  });
18627
20336
  return repo.delete(ip);
18628
20337
  }
@@ -18641,7 +20350,7 @@ function getOpenCommand(url) {
18641
20350
  }
18642
20351
  async function openBrowser(url) {
18643
20352
  const { command, args } = getOpenCommand(url);
18644
- await new Promise((resolve6, reject) => {
20353
+ await new Promise((resolve8, reject) => {
18645
20354
  const child = spawn6(command, args, {
18646
20355
  detached: true,
18647
20356
  stdio: "ignore",
@@ -18650,7 +20359,7 @@ async function openBrowser(url) {
18650
20359
  child.once("error", reject);
18651
20360
  child.once("spawn", () => {
18652
20361
  child.unref();
18653
- resolve6();
20362
+ resolve8();
18654
20363
  });
18655
20364
  });
18656
20365
  }
@@ -18983,7 +20692,7 @@ function parseArgs(argv) {
18983
20692
  init_runtime();
18984
20693
  import { mkdirSync as mkdirSync9 } from "fs";
18985
20694
  import { homedir as homedir5 } from "os";
18986
- import { join as join18 } from "path";
20695
+ import { join as join21 } from "path";
18987
20696
  var MANAGED_SERVER_NAME = "coder-studio-server";
18988
20697
  var PM2_RESTART_DELAY_MS = 2e3;
18989
20698
  var PM2_MIN_UPTIME = "5s";
@@ -19023,29 +20732,29 @@ async function loadPm2() {
19023
20732
  }
19024
20733
  var connectPm2 = async () => {
19025
20734
  const pm2 = await loadPm2();
19026
- return new Promise((resolve6, reject) => {
20735
+ return new Promise((resolve8, reject) => {
19027
20736
  pm2.connect((error) => {
19028
20737
  if (error) {
19029
20738
  reject(error);
19030
20739
  return;
19031
20740
  }
19032
- resolve6();
20741
+ resolve8();
19033
20742
  });
19034
20743
  });
19035
20744
  };
19036
- var sleep = async (ms) => new Promise((resolve6) => {
19037
- setTimeout(resolve6, ms);
20745
+ var sleep = async (ms) => new Promise((resolve8) => {
20746
+ setTimeout(resolve8, ms);
19038
20747
  });
19039
20748
  var disconnectPm2 = async () => {
19040
20749
  const pm2 = await loadPm2();
19041
- await new Promise((resolve6) => {
20750
+ await new Promise((resolve8) => {
19042
20751
  let settled = false;
19043
20752
  const finish = () => {
19044
20753
  if (settled) {
19045
20754
  return;
19046
20755
  }
19047
20756
  settled = true;
19048
- resolve6();
20757
+ resolve8();
19049
20758
  };
19050
20759
  const timer = setTimeout(finish, PM2_DISCONNECT_WAIT_MS);
19051
20760
  try {
@@ -19059,29 +20768,29 @@ var disconnectPm2 = async () => {
19059
20768
  }
19060
20769
  });
19061
20770
  };
19062
- var describeManagedServer = async (pm2) => new Promise((resolve6, reject) => {
20771
+ var describeManagedServer = async (pm2) => new Promise((resolve8, reject) => {
19063
20772
  pm2.describe(MANAGED_SERVER_NAME, (error, result) => {
19064
20773
  if (error) {
19065
20774
  reject(error);
19066
20775
  return;
19067
20776
  }
19068
- resolve6(result ?? []);
20777
+ resolve8(result ?? []);
19069
20778
  });
19070
20779
  });
19071
- var removeManagedServer = async (pm2) => new Promise((resolve6, reject) => {
20780
+ var removeManagedServer = async (pm2) => new Promise((resolve8, reject) => {
19072
20781
  pm2.delete(MANAGED_SERVER_NAME, (error) => {
19073
20782
  if (error) {
19074
20783
  reject(error);
19075
20784
  return;
19076
20785
  }
19077
- resolve6();
20786
+ resolve8();
19078
20787
  });
19079
20788
  });
19080
20789
  var killPm2Daemon = async () => {
19081
20790
  const pm2 = await loadPm2();
19082
- return new Promise((resolve6) => {
20791
+ return new Promise((resolve8) => {
19083
20792
  pm2.kill(() => {
19084
- resolve6();
20793
+ resolve8();
19085
20794
  });
19086
20795
  });
19087
20796
  };
@@ -19204,11 +20913,11 @@ var deleteManagedServerInSession = async (pm2, {
19204
20913
  return true;
19205
20914
  };
19206
20915
  var ensureLogDirectory = () => {
19207
- mkdirSync9(join18(homedir5(), ".coder-studio", "logs"), { recursive: true });
20916
+ mkdirSync9(join21(homedir5(), ".coder-studio", "logs"), { recursive: true });
19208
20917
  };
19209
20918
  var getLogPaths = () => ({
19210
- outFile: join18(homedir5(), ".coder-studio", "logs", "server.out.log"),
19211
- errFile: join18(homedir5(), ".coder-studio", "logs", "server.err.log")
20919
+ outFile: join21(homedir5(), ".coder-studio", "logs", "server.out.log"),
20920
+ errFile: join21(homedir5(), ".coder-studio", "logs", "server.err.log")
19212
20921
  });
19213
20922
  var captureStartupLogOffsets = () => {
19214
20923
  const { outFile, errFile } = getLogPaths();
@@ -19257,7 +20966,7 @@ var startManagedServer = async ({
19257
20966
  ensureLogDirectory();
19258
20967
  const { outFile, errFile } = getLogPaths();
19259
20968
  const logOffsets = captureStartupLogOffsets();
19260
- await new Promise((resolve6, reject) => {
20969
+ await new Promise((resolve8, reject) => {
19261
20970
  pm2.start(
19262
20971
  {
19263
20972
  name: MANAGED_SERVER_NAME,
@@ -19280,7 +20989,7 @@ var startManagedServer = async ({
19280
20989
  reject(error);
19281
20990
  return;
19282
20991
  }
19283
- resolve6();
20992
+ resolve8();
19284
20993
  }
19285
20994
  );
19286
20995
  });
@@ -19397,11 +21106,11 @@ import { fileURLToPath as fileURLToPath4 } from "url";
19397
21106
 
19398
21107
  // packages/cli/src/embed.ts
19399
21108
  import { existsSync as existsSync13 } from "fs";
19400
- import { dirname as dirname8, resolve as resolve5 } from "path";
21109
+ import { dirname as dirname8, resolve as resolve7 } from "path";
19401
21110
  import { fileURLToPath as fileURLToPath2 } from "url";
19402
21111
  var __filename = fileURLToPath2(import.meta.url);
19403
21112
  var __dirname = dirname8(__filename);
19404
- var WEB_ASSETS_DIR = resolve5(__dirname, "../web");
21113
+ var WEB_ASSETS_DIR = resolve7(__dirname, "../web");
19405
21114
  function getStaticAssetsDir() {
19406
21115
  return WEB_ASSETS_DIR;
19407
21116
  }
@@ -19411,13 +21120,13 @@ function hasWebAssets() {
19411
21120
 
19412
21121
  // packages/cli/src/update-runtime.ts
19413
21122
  import { existsSync as existsSync14 } from "node:fs";
19414
- import { dirname as dirname9, join as join19 } from "node:path";
21123
+ import { dirname as dirname9, join as join22 } from "node:path";
19415
21124
  import { fileURLToPath as fileURLToPath3 } from "node:url";
19416
21125
  function resolveWorkerEntryPath(importMetaUrl) {
19417
21126
  const currentDir = dirname9(fileURLToPath3(importMetaUrl));
19418
21127
  const candidates = [
19419
- join19(currentDir, "update-worker.mjs"),
19420
- join19(currentDir, "../src/update-worker.ts")
21128
+ join22(currentDir, "update-worker.mjs"),
21129
+ join22(currentDir, "../src/update-worker.ts")
19421
21130
  ];
19422
21131
  return candidates.find((candidate) => existsSync14(candidate));
19423
21132
  }
@@ -19646,9 +21355,9 @@ function resolveManagedScriptPath() {
19646
21355
  const currentFile = fileURLToPath5(import.meta.url);
19647
21356
  const currentDir = dirname10(currentFile);
19648
21357
  const candidates = [
19649
- join20(currentDir, "server-runner.js"),
19650
- join20(currentDir, "server-runner.mjs"),
19651
- join20(currentDir, "../src/server-runner.ts")
21358
+ join23(currentDir, "server-runner.js"),
21359
+ join23(currentDir, "server-runner.mjs"),
21360
+ join23(currentDir, "../src/server-runner.ts")
19652
21361
  ];
19653
21362
  const scriptPath = candidates.find((candidate) => existsSync15(candidate));
19654
21363
  if (!scriptPath) {