@tiflis-io/tiflis-code-workstation 0.3.3 → 0.3.5

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.
Files changed (2) hide show
  1. package/dist/main.js +229 -39
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -347,6 +347,22 @@ var AGENT_EXECUTION_CONFIG = {
347
347
  ]
348
348
  };
349
349
  var BASE_AGENT_TYPES = ["cursor", "claude", "opencode"];
350
+ function isBaseAgentDisabled(baseType) {
351
+ const env = getEnv();
352
+ switch (baseType) {
353
+ case "cursor":
354
+ return env.HIDE_BASE_CURSOR;
355
+ case "claude":
356
+ return env.HIDE_BASE_CLAUDE;
357
+ case "opencode":
358
+ return env.HIDE_BASE_OPENCODE;
359
+ default:
360
+ return false;
361
+ }
362
+ }
363
+ function getDisabledBaseAgents() {
364
+ return BASE_AGENT_TYPES.filter(isBaseAgentDisabled);
365
+ }
350
366
  function getBaseTypeFromCommand(command) {
351
367
  const commandMap = {
352
368
  claude: "claude",
@@ -357,33 +373,39 @@ function getBaseTypeFromCommand(command) {
357
373
  }
358
374
  function getAvailableAgents() {
359
375
  const agents = /* @__PURE__ */ new Map();
360
- agents.set("cursor", {
361
- name: "cursor",
362
- command: AGENT_COMMANDS.cursor.command,
363
- aliasArgs: [],
364
- aliasEnvVars: {},
365
- baseType: "cursor",
366
- description: AGENT_COMMANDS.cursor.description,
367
- isAlias: false
368
- });
369
- agents.set("claude", {
370
- name: "claude",
371
- command: AGENT_COMMANDS.claude.command,
372
- aliasArgs: [],
373
- aliasEnvVars: {},
374
- baseType: "claude",
375
- description: AGENT_COMMANDS.claude.description,
376
- isAlias: false
377
- });
378
- agents.set("opencode", {
379
- name: "opencode",
380
- command: AGENT_COMMANDS.opencode.command,
381
- aliasArgs: [],
382
- aliasEnvVars: {},
383
- baseType: "opencode",
384
- description: AGENT_COMMANDS.opencode.description,
385
- isAlias: false
386
- });
376
+ if (!isBaseAgentDisabled("cursor")) {
377
+ agents.set("cursor", {
378
+ name: "cursor",
379
+ command: AGENT_COMMANDS.cursor.command,
380
+ aliasArgs: [],
381
+ aliasEnvVars: {},
382
+ baseType: "cursor",
383
+ description: AGENT_COMMANDS.cursor.description,
384
+ isAlias: false
385
+ });
386
+ }
387
+ if (!isBaseAgentDisabled("claude")) {
388
+ agents.set("claude", {
389
+ name: "claude",
390
+ command: AGENT_COMMANDS.claude.command,
391
+ aliasArgs: [],
392
+ aliasEnvVars: {},
393
+ baseType: "claude",
394
+ description: AGENT_COMMANDS.claude.description,
395
+ isAlias: false
396
+ });
397
+ }
398
+ if (!isBaseAgentDisabled("opencode")) {
399
+ agents.set("opencode", {
400
+ name: "opencode",
401
+ command: AGENT_COMMANDS.opencode.command,
402
+ aliasArgs: [],
403
+ aliasEnvVars: {},
404
+ baseType: "opencode",
405
+ description: AGENT_COMMANDS.opencode.description,
406
+ isAlias: false
407
+ });
408
+ }
387
409
  const aliases = getAgentAliases();
388
410
  for (const [name, alias] of aliases) {
389
411
  const baseType = getBaseTypeFromCommand(alias.baseCommand);
@@ -1102,8 +1124,21 @@ var HeartbeatSchema = z2.object({
1102
1124
  var SyncMessageSchema = z2.object({
1103
1125
  type: z2.literal("sync"),
1104
1126
  id: z2.string(),
1105
- device_id: z2.string().optional()
1127
+ device_id: z2.string().optional(),
1128
+ // Injected by tunnel for tunnel connections
1129
+ lightweight: z2.boolean().optional()
1130
+ // If true, excludes message histories (for watchOS)
1131
+ });
1132
+ var HistoryRequestPayloadSchema = z2.object({
1133
+ session_id: z2.string().optional()
1134
+ // If omitted, returns supervisor history
1135
+ });
1136
+ var HistoryRequestSchema = z2.object({
1137
+ type: z2.literal("history.request"),
1138
+ id: z2.string(),
1139
+ device_id: z2.string().optional(),
1106
1140
  // Injected by tunnel for tunnel connections
1141
+ payload: HistoryRequestPayloadSchema.optional()
1107
1142
  });
1108
1143
  var ListSessionsSchema = z2.object({
1109
1144
  type: z2.literal("supervisor.list_sessions"),
@@ -1260,6 +1295,7 @@ var IncomingClientMessageSchema = z2.discriminatedUnion("type", [
1260
1295
  PingSchema,
1261
1296
  HeartbeatSchema,
1262
1297
  SyncMessageSchema,
1298
+ HistoryRequestSchema,
1263
1299
  ListSessionsSchema,
1264
1300
  CreateSessionSchema,
1265
1301
  TerminateSessionSchema,
@@ -7355,10 +7391,11 @@ async function bootstrap() {
7355
7391
  const syncMessage = message;
7356
7392
  const client = clientRegistry.getBySocket(socket) ?? (syncMessage.device_id ? clientRegistry.getByDeviceId(new DeviceId(syncMessage.device_id)) : void 0);
7357
7393
  const subscriptions2 = client ? client.getSubscriptions() : [];
7394
+ const isLightweight = syncMessage.lightweight === true;
7358
7395
  const inMemorySessions = sessionManager.getSessionInfos();
7359
7396
  const persistedAgentSessions = chatHistoryService.getActiveAgentSessions();
7360
7397
  logger.debug(
7361
- { persistedAgentSessions, inMemoryCount: inMemorySessions.length },
7398
+ { persistedAgentSessions, inMemoryCount: inMemorySessions.length, isLightweight },
7362
7399
  "Sync: fetched sessions"
7363
7400
  );
7364
7401
  const inMemorySessionIds = new Set(
@@ -7383,6 +7420,67 @@ async function bootstrap() {
7383
7420
  };
7384
7421
  });
7385
7422
  const sessions2 = [...inMemorySessions, ...restoredAgentSessions];
7423
+ if (isLightweight) {
7424
+ const availableAgentsMap2 = getAvailableAgents();
7425
+ const availableAgents2 = Array.from(availableAgentsMap2.values()).map(
7426
+ (agent) => ({
7427
+ name: agent.name,
7428
+ base_type: agent.baseType,
7429
+ description: agent.description,
7430
+ is_alias: agent.isAlias
7431
+ })
7432
+ );
7433
+ const hiddenBaseTypes2 = getDisabledBaseAgents();
7434
+ const workspacesList2 = await workspaceDiscovery.listWorkspaces();
7435
+ const workspaces2 = await Promise.all(
7436
+ workspacesList2.map(async (ws) => {
7437
+ const projects = await workspaceDiscovery.listProjects(ws.name);
7438
+ return {
7439
+ name: ws.name,
7440
+ projects: projects.map((p) => ({
7441
+ name: p.name,
7442
+ is_git_repo: p.isGitRepo,
7443
+ default_branch: p.defaultBranch
7444
+ }))
7445
+ };
7446
+ })
7447
+ );
7448
+ const executingStates2 = {};
7449
+ for (const session of sessions2) {
7450
+ if (session.session_type === "cursor" || session.session_type === "claude" || session.session_type === "opencode") {
7451
+ executingStates2[session.session_id] = agentSessionManager.isExecuting(
7452
+ session.session_id
7453
+ );
7454
+ }
7455
+ }
7456
+ const supervisorIsExecuting2 = supervisorAgent.isProcessing();
7457
+ logger.info(
7458
+ {
7459
+ totalSessions: sessions2.length,
7460
+ isLightweight: true,
7461
+ availableAgentsCount: availableAgents2.length,
7462
+ workspacesCount: workspaces2.length,
7463
+ supervisorIsExecuting: supervisorIsExecuting2
7464
+ },
7465
+ "Sync: sending lightweight state to client (no histories)"
7466
+ );
7467
+ const syncStateMessage2 = JSON.stringify({
7468
+ type: "sync.state",
7469
+ id: syncMessage.id,
7470
+ payload: {
7471
+ sessions: sessions2,
7472
+ subscriptions: subscriptions2,
7473
+ availableAgents: availableAgents2,
7474
+ hiddenBaseTypes: hiddenBaseTypes2,
7475
+ workspaces: workspaces2,
7476
+ supervisorIsExecuting: supervisorIsExecuting2,
7477
+ executingStates: executingStates2
7478
+ // Omit: supervisorHistory, agentHistories, currentStreamingBlocks
7479
+ }
7480
+ });
7481
+ sendToDevice(socket, syncMessage.device_id, syncStateMessage2);
7482
+ return Promise.resolve();
7483
+ }
7386
7484
  const supervisorHistoryRaw = chatHistoryService.getSupervisorHistory();
7387
7485
  const supervisorHistory = await Promise.all(
7388
7486
  supervisorHistoryRaw.map(async (msg) => ({
@@ -7437,16 +7535,7 @@ async function bootstrap() {
7437
7535
  is_alias: agent.isAlias
7438
7536
  })
7439
7537
  );
7440
- const hiddenBaseTypes = [];
7441
- if (env.HIDE_BASE_CURSOR) {
7442
- hiddenBaseTypes.push("cursor");
7443
- }
7444
- if (env.HIDE_BASE_CLAUDE) {
7445
- hiddenBaseTypes.push("claude");
7446
- }
7447
- if (env.HIDE_BASE_OPENCODE) {
7448
- hiddenBaseTypes.push("opencode");
7449
- }
7538
+ const hiddenBaseTypes = getDisabledBaseAgents();
7450
7539
  const workspacesList = await workspaceDiscovery.listWorkspaces();
7451
7540
  const workspaces = await Promise.all(
7452
7541
  workspacesList.map(async (ws) => {
@@ -8498,6 +8587,107 @@ async function bootstrap() {
8498
8587
  }
8499
8588
  return Promise.resolve();
8500
8589
  },
8590
+ "history.request": async (socket, message) => {
8591
+ const historyRequest = message;
8592
+ const sessionId = historyRequest.payload?.session_id;
8593
+ const isSupervisor = !sessionId;
8594
+ logger.debug(
8595
+ { sessionId, isSupervisor, requestId: historyRequest.id },
8596
+ "History request received"
8597
+ );
8598
+ try {
8599
+ if (isSupervisor) {
8600
+ const supervisorHistoryRaw = chatHistoryService.getSupervisorHistory();
8601
+ const supervisorHistory = await Promise.all(
8602
+ supervisorHistoryRaw.map(async (msg) => ({
8603
+ message_id: msg.id,
8604
+ // Include message ID for audio.request
8605
+ sequence: msg.sequence,
8606
+ role: msg.role,
8607
+ content: msg.content,
8608
+ content_blocks: await chatHistoryService.enrichBlocksWithAudio(
8609
+ msg.contentBlocks,
8610
+ msg.audioOutputPath,
8611
+ msg.audioInputPath,
8612
+ false
8613
+ // Don't include audio in history response
8614
+ ),
8615
+ createdAt: msg.createdAt.toISOString()
8616
+ }))
8617
+ );
8618
+ const isExecuting = supervisorAgent.isProcessing();
8619
+ socket.send(
8620
+ JSON.stringify({
8621
+ type: "history.response",
8622
+ id: historyRequest.id,
8623
+ payload: {
8624
+ session_id: null,
8625
+ // Indicates supervisor
8626
+ history: supervisorHistory,
8627
+ is_executing: isExecuting
8628
+ }
8629
+ })
8630
+ );
8631
+ logger.debug(
8632
+ { messageCount: supervisorHistory.length, isExecuting },
8633
+ "Supervisor history sent"
8634
+ );
8635
+ } else {
8636
+ const history = chatHistoryService.getAgentHistory(sessionId);
8637
+ const enrichedHistory = await Promise.all(
8638
+ history.map(async (msg) => ({
8639
+ sequence: msg.sequence,
8640
+ role: msg.role,
8641
+ content: msg.content,
8642
+ content_blocks: await chatHistoryService.enrichBlocksWithAudio(
8643
+ msg.contentBlocks,
8644
+ msg.audioOutputPath,
8645
+ msg.audioInputPath,
8646
+ false
8647
+ // Don't include audio in history response
8648
+ ),
8649
+ createdAt: msg.createdAt.toISOString()
8650
+ }))
8651
+ );
8652
+ const isExecuting = agentSessionManager.isExecuting(sessionId);
8653
+ let currentStreamingBlocks;
8654
+ if (isExecuting) {
8655
+ const blocks = agentMessageAccumulator.get(sessionId);
8656
+ if (blocks && blocks.length > 0) {
8657
+ currentStreamingBlocks = blocks;
8658
+ }
8659
+ }
8660
+ socket.send(
8661
+ JSON.stringify({
8662
+ type: "history.response",
8663
+ id: historyRequest.id,
8664
+ payload: {
8665
+ session_id: sessionId,
8666
+ history: enrichedHistory,
8667
+ is_executing: isExecuting,
8668
+ current_streaming_blocks: currentStreamingBlocks
8669
+ }
8670
+ })
8671
+ );
8672
+ logger.debug(
8673
+ { sessionId, messageCount: enrichedHistory.length, isExecuting },
8674
+ "Agent session history sent"
8675
+ );
8676
+ }
8677
+ } catch (error) {
8678
+ logger.error({ error, sessionId }, "Failed to get history");
8679
+ socket.send(
8680
+ JSON.stringify({
8681
+ type: "history.response",
8682
+ id: historyRequest.id,
8683
+ payload: {
8684
+ session_id: sessionId ?? null,
8685
+ error: error instanceof Error ? error.message : "Failed to get history"
8686
+ }
8687
+ })
8688
+ );
8689
+ }
8690
+ },
8501
8691
  "audio.request": async (socket, message) => {
8502
8692
  const audioRequest = message;
8503
8693
  const { message_id, type = "output" } = audioRequest.payload;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiflis-io/tiflis-code-workstation",
3
- "version": "0.3.3",
3
+ "version": "0.3.5",
4
4
  "description": "Workstation server for tiflis-code - manages agent sessions and terminal access",
5
5
  "author": "Roman Barinov <rbarinov@gmail.com>",
6
6
  "license": "FSL-1.1-NC",