@phenx-inc/ctlsurf 0.12.1 → 0.13.4

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 (41) hide show
  1. package/LICENSE +22 -0
  2. package/out/headless/index.mjs +33 -36
  3. package/out/headless/index.mjs.map +3 -3
  4. package/out/main/index.js +47 -40
  5. package/out/preload/index.js +1 -0
  6. package/out/renderer/assets/{cssMode-D7r66wvO.js → cssMode-CAEObGNt.js} +3 -3
  7. package/out/renderer/assets/{freemarker2-jSWJIjPG.js → freemarker2-D63hnnDq.js} +1 -1
  8. package/out/renderer/assets/{handlebars-BnFyz5RH.js → handlebars-UYo_IYpi.js} +1 -1
  9. package/out/renderer/assets/{html-Bl5UFavp.js → html-2dvYDi3g.js} +1 -1
  10. package/out/renderer/assets/{htmlMode-D4VByBT6.js → htmlMode-B6fxDDPF.js} +3 -3
  11. package/out/renderer/assets/{index-Cc_TqOCL.css → index-BEekQe3-.css} +232 -8
  12. package/out/renderer/assets/{index-DxhW1emk.js → index-CMb4AqkZ.js} +786 -473
  13. package/out/renderer/assets/{javascript-CMN1OmwG.js → javascript-8RyFDDdk.js} +2 -2
  14. package/out/renderer/assets/{jsonMode-CJ5AYSPV.js → jsonMode-CqspkWCb.js} +3 -3
  15. package/out/renderer/assets/{liquid-BGMIDTEm.js → liquid-DaEnAsYY.js} +1 -1
  16. package/out/renderer/assets/{lspLanguageFeatures-DGifVYB5.js → lspLanguageFeatures-Czkp5sZb.js} +1 -1
  17. package/out/renderer/assets/{mdx-B2Z7R10Q.js → mdx-Q-qSZsFg.js} +1 -1
  18. package/out/renderer/assets/{python-LMDMSSdn.js → python-Sw0S0BJV.js} +1 -1
  19. package/out/renderer/assets/{razor-BZSrziPu.js → razor-C7zQmabz.js} +1 -1
  20. package/out/renderer/assets/{tsMode-DF9m6_3n.js → tsMode-BWdOxk6v.js} +1 -1
  21. package/out/renderer/assets/{typescript-rZeCMf0a.js → typescript-BrdIiKZf.js} +1 -1
  22. package/out/renderer/assets/{xml-fNSZ-7so.js → xml-DbKLNPOq.js} +1 -1
  23. package/out/renderer/assets/{yaml-1wxIuvzh.js → yaml-ehupJBsZ.js} +1 -1
  24. package/out/renderer/index.html +2 -2
  25. package/package.json +2 -2
  26. package/src/main/bridge.ts +3 -2
  27. package/src/main/index.ts +15 -0
  28. package/src/main/orchestrator.ts +1 -1
  29. package/src/main/pty.ts +2 -5
  30. package/src/main/ticketStore.ts +28 -21
  31. package/src/main/timeTracker.ts +4 -1
  32. package/src/main/transcripts.ts +3 -2
  33. package/src/preload/index.ts +2 -0
  34. package/src/renderer/App.tsx +15 -2
  35. package/src/renderer/components/CtlsurfPanel.tsx +169 -35
  36. package/src/renderer/components/SettingsDialog.tsx +13 -0
  37. package/src/renderer/components/SpeakControls.tsx +5 -0
  38. package/src/renderer/components/TerminalPanel.tsx +155 -48
  39. package/src/renderer/components/TicketPanel.tsx +80 -24
  40. package/src/renderer/lib/speech.ts +2 -1
  41. package/src/renderer/styles.css +232 -8
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright © 2026 Phenx, Inc. All rights reserved.
2
+
3
+ This software, including its source code, design, and documentation
4
+ (the "Software"), is the confidential and proprietary property of
5
+ Phenx, Inc. ("Phenx").
6
+
7
+ No license or right to use, copy, modify, merge, publish, distribute,
8
+ sublicense, sell, reverse engineer, decompile, or create derivative works
9
+ of the Software, in whole or in part, is granted except under a separate
10
+ written agreement signed by Phenx. Unauthorized use, reproduction, or
11
+ distribution is strictly prohibited and may result in civil and criminal
12
+ penalties.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL
17
+ PHENX BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY ARISING FROM OR
18
+ IN CONNECTION WITH THE SOFTWARE OR ITS USE.
19
+
20
+ Third-party components distributed with the Software are licensed under
21
+ their own terms by their respective authors; those licenses continue to
22
+ apply to those components.
@@ -5471,7 +5471,7 @@ var require_package = __commonJS({
5471
5471
  "package.json"(exports, module) {
5472
5472
  module.exports = {
5473
5473
  name: "@phenx-inc/ctlsurf",
5474
- version: "0.12.1",
5474
+ version: "0.13.4",
5475
5475
  description: "Agent-agnostic terminal and desktop app for ctlsurf \u2014 run Claude Code, Codex, or any coding agent with live session logging and remote control",
5476
5476
  main: "out/main/index.js",
5477
5477
  bin: {
@@ -5509,7 +5509,7 @@ var require_package = __commonJS({
5509
5509
  "node-pty",
5510
5510
  "xterm"
5511
5511
  ],
5512
- license: "MIT",
5512
+ license: "SEE LICENSE IN LICENSE",
5513
5513
  engines: {
5514
5514
  node: ">=18"
5515
5515
  },
@@ -5578,10 +5578,7 @@ var PtyManager = class {
5578
5578
  constructor(agent, cwd) {
5579
5579
  const shell = agent.command;
5580
5580
  const args = agent.args || [];
5581
- try {
5582
- console.log(`[pty] Spawning: ${shell} ${args.join(" ")} in ${cwd}`);
5583
- } catch {
5584
- }
5581
+ log(`[pty] Spawning: ${shell} ${args.join(" ")} in ${cwd}`);
5585
5582
  this.process = pty.spawn(shell, args, {
5586
5583
  name: "xterm-256color",
5587
5584
  cwd,
@@ -5847,7 +5844,7 @@ var ConversationBridge = class {
5847
5844
  this.inputBuffer = "";
5848
5845
  this.terminalCapture.reset();
5849
5846
  this.sessionActive = true;
5850
- console.log("[bridge] Session started");
5847
+ log("[bridge] Session started");
5851
5848
  }
5852
5849
  feedOutput(data) {
5853
5850
  if (!this.sessionActive || !this.loggingEnabled) return;
@@ -5927,7 +5924,7 @@ var ConversationBridge = class {
5927
5924
  this.sessionActive = false;
5928
5925
  this.inputBuffer = "";
5929
5926
  this.outputBuffer = "";
5930
- console.log("[bridge] Session ended");
5927
+ log("[bridge] Session ended");
5931
5928
  }
5932
5929
  };
5933
5930
  var DEFAULT_COLS = 80;
@@ -6141,7 +6138,7 @@ var TranscriptTailer = class {
6141
6138
  this.sinceMs = Date.now();
6142
6139
  this.files.clear();
6143
6140
  this.pollTimer = setInterval(() => this.poll(), POLL_INTERVAL_MS);
6144
- console.log(`[transcripts] Tailing ${this.agentId} transcripts for ${this.cwd}`);
6141
+ log(`[transcripts] Tailing ${this.agentId} transcripts for ${this.cwd}`);
6145
6142
  }
6146
6143
  stop() {
6147
6144
  if (!this.pollTimer) return;
@@ -6149,7 +6146,7 @@ var TranscriptTailer = class {
6149
6146
  this.pollTimer = null;
6150
6147
  this.poll();
6151
6148
  this.files.clear();
6152
- console.log("[transcripts] Stopped");
6149
+ log("[transcripts] Stopped");
6153
6150
  }
6154
6151
  poll() {
6155
6152
  try {
@@ -6952,10 +6949,7 @@ function isSameLocalDay(a, b) {
6952
6949
  return da.getFullYear() === db.getFullYear() && da.getMonth() === db.getMonth() && da.getDate() === db.getDate();
6953
6950
  }
6954
6951
  function log2(...args) {
6955
- try {
6956
- console.log("[time-tracker]", ...args);
6957
- } catch {
6958
- }
6952
+ log("[time-tracker]", ...args);
6959
6953
  }
6960
6954
  function findPageByTitle(pages, title) {
6961
6955
  for (const p of pages) {
@@ -7244,10 +7238,7 @@ var COLUMNS2 = [
7244
7238
  { name: "Created", type: "date" }
7245
7239
  ];
7246
7240
  function log3(...args) {
7247
- try {
7248
- console.log("[ticket-store]", ...args);
7249
- } catch {
7250
- }
7241
+ log("[ticket-store]", ...args);
7251
7242
  }
7252
7243
  function findPageByTitle2(pages, title) {
7253
7244
  for (const p of pages) {
@@ -7261,7 +7252,10 @@ function findPageByTitle2(pages, title) {
7261
7252
  }
7262
7253
  var TicketStore = class {
7263
7254
  api;
7264
- blockCache = /* @__PURE__ */ new Map();
7255
+ // Per-cwd cache of the resolved Tickets datastore: the block (the datastore
7256
+ // element) and the Agent Datastore page it lives on. Both ids are handed to
7257
+ // the coding agent so it can read/update tickets via the ctlsurf MCP tools.
7258
+ dsCache = /* @__PURE__ */ new Map();
7265
7259
  constructor(api) {
7266
7260
  this.api = api;
7267
7261
  }
@@ -7270,11 +7264,11 @@ var TicketStore = class {
7270
7264
  const title = input.title?.trim();
7271
7265
  if (!title) return { ok: false, error: "Title is required" };
7272
7266
  try {
7273
- const blockId = await this.ensureDatastore(cwd, true);
7274
- if (!blockId) {
7267
+ const ds = await this.ensureDatastore(cwd, true);
7268
+ if (!ds) {
7275
7269
  return { ok: false, error: "No ctlsurf project found for this folder" };
7276
7270
  }
7277
- await this.api.addRow(blockId, {
7271
+ await this.api.addRow(ds.blockId, {
7278
7272
  Title: title,
7279
7273
  Description: input.description?.trim() || "",
7280
7274
  Status: input.status || "Open",
@@ -7293,9 +7287,9 @@ var TicketStore = class {
7293
7287
  const title = input.title?.trim();
7294
7288
  if (!title) return { ok: false, error: "Title is required" };
7295
7289
  try {
7296
- const blockId = await this.ensureDatastore(cwd, false);
7297
- if (!blockId) return { ok: false, error: "No Tickets datastore for this project" };
7298
- await this.api.updateRow(blockId, rowId, {
7290
+ const ds = await this.ensureDatastore(cwd, false);
7291
+ if (!ds) return { ok: false, error: "No Tickets datastore for this project" };
7292
+ await this.api.updateRow(ds.blockId, rowId, {
7299
7293
  Title: title,
7300
7294
  Description: input.description?.trim() || "",
7301
7295
  Status: input.status || "Open",
@@ -7312,9 +7306,9 @@ var TicketStore = class {
7312
7306
  * datastore — an unconfigured project simply has no tickets yet. */
7313
7307
  async listTickets(cwd) {
7314
7308
  try {
7315
- const blockId = await this.ensureDatastore(cwd, false);
7316
- if (!blockId) return { ok: true, tickets: [] };
7317
- const res = await this.api.queryRows(blockId, { orderBy: "Created", order: "desc", limit: 200 });
7309
+ const ds = await this.ensureDatastore(cwd, false);
7310
+ if (!ds) return { ok: true, tickets: [] };
7311
+ const res = await this.api.queryRows(ds.blockId, { orderBy: "Created", order: "desc", limit: 200 });
7318
7312
  const tickets = (res?.rows || []).map((r) => ({
7319
7313
  id: r.id,
7320
7314
  title: String(r.data?.Title ?? ""),
@@ -7323,14 +7317,14 @@ var TicketStore = class {
7323
7317
  priority: String(r.data?.Priority ?? "Med"),
7324
7318
  created: r.data?.Created ?? r.created_at ?? null
7325
7319
  }));
7326
- return { ok: true, tickets };
7320
+ return { ok: true, tickets, blockId: ds.blockId, pageId: ds.pageId };
7327
7321
  } catch (err) {
7328
7322
  log3(`listTickets failed for ${cwd}: ${err?.message || err}`);
7329
7323
  return { ok: false, tickets: [], error: err?.message || String(err) };
7330
7324
  }
7331
7325
  }
7332
7326
  async ensureDatastore(cwd, create) {
7333
- const cached = this.blockCache.get(cwd);
7327
+ const cached = this.dsCache.get(cwd);
7334
7328
  if (cached) return cached;
7335
7329
  let folder = null;
7336
7330
  try {
@@ -7342,11 +7336,13 @@ var TicketStore = class {
7342
7336
  const folderDetail = await this.api.getFolder(folder.id);
7343
7337
  const agentPage = findPageByTitle2(folderDetail?.pages || [], AGENT_DATASTORE_PAGE_TITLE2);
7344
7338
  if (!agentPage?.id) return null;
7345
- const blockId = await this.findOrAdoptBlock(agentPage.id);
7339
+ const pageId = agentPage.id;
7340
+ const blockId = await this.findOrAdoptBlock(pageId);
7346
7341
  if (blockId) {
7347
7342
  await this.ensureColumns(blockId);
7348
- this.blockCache.set(cwd, blockId);
7349
- return blockId;
7343
+ const ds = { blockId, pageId };
7344
+ this.dsCache.set(cwd, ds);
7345
+ return ds;
7350
7346
  }
7351
7347
  if (!create) return null;
7352
7348
  const columns = COLUMNS2.map((c, i) => ({
@@ -7355,15 +7351,16 @@ var TicketStore = class {
7355
7351
  type: c.type,
7356
7352
  ...c.options ? { options: c.options } : {}
7357
7353
  }));
7358
- const created = await this.api.createBlock(agentPage.id, {
7354
+ const created = await this.api.createBlock(pageId, {
7359
7355
  type: "datastore",
7360
7356
  title: DATASTORE_TITLE2,
7361
7357
  props: { columns, system_key: SYSTEM_KEY2 }
7362
7358
  });
7363
7359
  if (created?.id) {
7364
7360
  log3(`Created "${DATASTORE_TITLE2}" datastore on Agent Datastore page for ${cwd}`);
7365
- this.blockCache.set(cwd, created.id);
7366
- return created.id;
7361
+ const ds = { blockId: created.id, pageId };
7362
+ this.dsCache.set(cwd, ds);
7363
+ return ds;
7367
7364
  }
7368
7365
  return null;
7369
7366
  }