comisai 1.0.15 → 1.0.17

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 (124) hide show
  1. package/node_modules/@comis/agent/dist/bootstrap/types.d.ts +1 -1
  2. package/node_modules/@comis/agent/dist/bridge/pi-event-bridge.js +12 -11
  3. package/node_modules/@comis/agent/dist/context-engine/constants.d.ts +11 -0
  4. package/node_modules/@comis/agent/dist/context-engine/constants.js +11 -0
  5. package/node_modules/@comis/agent/dist/context-engine/index.d.ts +1 -1
  6. package/node_modules/@comis/agent/dist/context-engine/index.js +1 -1
  7. package/node_modules/@comis/agent/dist/context-engine/llm-compaction.js +32 -18
  8. package/node_modules/@comis/agent/dist/executor/cache-break-diff-writer.d.ts +2 -0
  9. package/node_modules/@comis/agent/dist/executor/cache-break-diff-writer.js +36 -0
  10. package/node_modules/@comis/agent/dist/executor/executor-post-execution.d.ts +12 -0
  11. package/node_modules/@comis/agent/dist/executor/executor-post-execution.js +117 -27
  12. package/node_modules/@comis/agent/dist/executor/executor-prompt-runner.d.ts +1 -0
  13. package/node_modules/@comis/agent/dist/executor/executor-prompt-runner.js +16 -4
  14. package/node_modules/@comis/agent/dist/executor/executor-stream-setup.js +17 -1
  15. package/node_modules/@comis/agent/dist/executor/executor-tool-assembly.js +27 -1
  16. package/node_modules/@comis/agent/dist/executor/session-snapshot-cleanup.js +3 -1
  17. package/node_modules/@comis/agent/dist/executor/stream-wrappers/index.d.ts +2 -0
  18. package/node_modules/@comis/agent/dist/executor/stream-wrappers/index.js +2 -0
  19. package/node_modules/@comis/agent/dist/executor/stream-wrappers/request-body-injector.d.ts +9 -0
  20. package/node_modules/@comis/agent/dist/executor/stream-wrappers/request-body-injector.js +65 -3
  21. package/node_modules/@comis/agent/dist/executor/stream-wrappers/stub-filter-injector.d.ts +28 -0
  22. package/node_modules/@comis/agent/dist/executor/stream-wrappers/stub-filter-injector.js +63 -0
  23. package/node_modules/@comis/agent/dist/executor/tool-deferral.d.ts +18 -1
  24. package/node_modules/@comis/agent/dist/executor/tool-deferral.js +275 -133
  25. package/node_modules/@comis/agent/dist/executor/ttl-guard.d.ts +6 -0
  26. package/node_modules/@comis/agent/dist/executor/ttl-guard.js +8 -0
  27. package/node_modules/@comis/agent/package.json +1 -1
  28. package/node_modules/@comis/channels/dist/shared/typing-controller.d.ts +7 -0
  29. package/node_modules/@comis/channels/dist/shared/typing-controller.js +33 -0
  30. package/node_modules/@comis/channels/package.json +1 -1
  31. package/node_modules/@comis/cli/dist/commands/daemon.js +116 -28
  32. package/node_modules/@comis/cli/dist/wizard/non-interactive.js +1 -0
  33. package/node_modules/@comis/cli/dist/wizard/steps/01-detect-existing.js +4 -0
  34. package/node_modules/@comis/cli/dist/wizard/steps/07-gateway.js +9 -0
  35. package/node_modules/@comis/cli/dist/wizard/steps/10-write-config.js +2 -0
  36. package/node_modules/@comis/cli/dist/wizard/steps/12-finish.js +5 -2
  37. package/node_modules/@comis/cli/dist/wizard/types.d.ts +1 -0
  38. package/node_modules/@comis/cli/package.json +1 -1
  39. package/node_modules/@comis/core/dist/config/schema-agent.d.ts +10 -0
  40. package/node_modules/@comis/core/dist/config/schema-agent.js +8 -0
  41. package/node_modules/@comis/core/dist/config/schema-gateway.d.ts +17 -2
  42. package/node_modules/@comis/core/dist/config/schema-gateway.js +11 -0
  43. package/node_modules/@comis/core/dist/config/schema-skills.d.ts +16 -2
  44. package/node_modules/@comis/core/dist/config/schema-skills.js +9 -2
  45. package/node_modules/@comis/core/dist/config/schema.d.ts +66 -60
  46. package/node_modules/@comis/core/package.json +1 -1
  47. package/node_modules/@comis/daemon/dist/wiring/setup-gateway.js +34 -6
  48. package/node_modules/@comis/daemon/package.json +1 -1
  49. package/node_modules/@comis/gateway/package.json +1 -1
  50. package/node_modules/@comis/infra/package.json +1 -1
  51. package/node_modules/@comis/memory/package.json +1 -1
  52. package/node_modules/@comis/scheduler/package.json +1 -1
  53. package/node_modules/@comis/shared/package.json +1 -1
  54. package/node_modules/@comis/skills/dist/builtin/platform/gateway-tool.d.ts +1 -1
  55. package/node_modules/@comis/skills/package.json +1 -1
  56. package/node_modules/@comis/web/dist/android-chrome-192x192.png +0 -0
  57. package/node_modules/@comis/web/dist/android-chrome-512x512.png +0 -0
  58. package/node_modules/@comis/web/dist/apple-touch-icon.png +0 -0
  59. package/node_modules/@comis/web/dist/assets/agent-detail-BG9MGWWj.js +615 -0
  60. package/node_modules/@comis/web/dist/assets/agent-editor-C26Q_xCs.js +2173 -0
  61. package/node_modules/@comis/web/dist/assets/agent-list-LHCJ4rw2.js +504 -0
  62. package/node_modules/@comis/web/dist/assets/approvals-q9VH_IKr.js +54 -0
  63. package/node_modules/@comis/web/dist/assets/billing-view-CtYvBqTE.js +375 -0
  64. package/node_modules/@comis/web/dist/assets/channel-detail-CaInesJM.js +681 -0
  65. package/node_modules/@comis/web/dist/assets/channel-list-B8dj3O9a.js +323 -0
  66. package/node_modules/@comis/web/dist/assets/chat-console-CNmzl0JW.js +943 -0
  67. package/node_modules/@comis/web/dist/assets/config-editor-DX4ITw6y.js +1374 -0
  68. package/node_modules/@comis/web/dist/assets/context-dag-browser-BwiaF5tf.js +393 -0
  69. package/node_modules/@comis/web/dist/assets/context-engine-BZ5Am6hA.js +393 -0
  70. package/node_modules/@comis/web/dist/assets/delivery-view-OfBZof-m.js +392 -0
  71. package/node_modules/@comis/web/dist/assets/diagnostics-view-YFwCxgr2.js +231 -0
  72. package/node_modules/@comis/web/dist/assets/directive-DoeGSK_T.js +1 -0
  73. package/node_modules/@comis/web/dist/assets/extract-variables-BM5qyK-s.js +149 -0
  74. package/node_modules/@comis/web/dist/assets/ic-array-editor-B7m6x7-S.js +118 -0
  75. package/node_modules/@comis/web/dist/assets/ic-breadcrumb-CUMpp3BL.js +75 -0
  76. package/node_modules/@comis/web/dist/assets/ic-budget-segment-bar-BtJ6x5mN.js +64 -0
  77. package/node_modules/@comis/web/dist/assets/ic-chat-message-CFyDJd0z.js +352 -0
  78. package/node_modules/@comis/web/dist/assets/ic-confirm-dialog-CCDbB04e.js +110 -0
  79. package/node_modules/@comis/web/dist/assets/ic-connection-dot-CnT1b8xr.js +54 -0
  80. package/node_modules/@comis/web/dist/assets/ic-data-table-CKUNTxHw.js +277 -0
  81. package/node_modules/@comis/web/dist/assets/ic-delivery-row-GP5Fkygs.js +67 -0
  82. package/node_modules/@comis/web/dist/assets/ic-detail-panel-BF83r-if.js +116 -0
  83. package/node_modules/@comis/web/dist/assets/ic-empty-state-60l2ePhd.js +52 -0
  84. package/node_modules/@comis/web/dist/assets/ic-graph-canvas-C8FuSMe1.js +359 -0
  85. package/node_modules/@comis/web/dist/assets/ic-icon-xeGTVhVG.js +33 -0
  86. package/node_modules/@comis/web/dist/assets/ic-layer-waterfall-COvEYMg5.js +69 -0
  87. package/node_modules/@comis/web/dist/assets/ic-relative-time-3FqpjeAI.js +12 -0
  88. package/node_modules/@comis/web/dist/assets/ic-search-input-CSOxY9g7.js +92 -0
  89. package/node_modules/@comis/web/dist/assets/ic-select-Ce-Raudx.js +127 -0
  90. package/node_modules/@comis/web/dist/assets/ic-tabs-B7QtM_v8.js +95 -0
  91. package/node_modules/@comis/web/dist/assets/ic-tag-CPPUnDLF.js +33 -0
  92. package/node_modules/@comis/web/dist/assets/ic-time-range-picker-CypCT68y.js +93 -0
  93. package/node_modules/@comis/web/dist/assets/ic-tool-call-7MaXSsCW.js +146 -0
  94. package/node_modules/@comis/web/dist/assets/index-CEcM1R_C.js +2830 -0
  95. package/node_modules/@comis/web/dist/assets/index-CIJFuItj.css +1 -0
  96. package/node_modules/@comis/web/dist/assets/mcp-management-BNZPnpDn.js +582 -0
  97. package/node_modules/@comis/web/dist/assets/media-config-BBvTYxOX.js +314 -0
  98. package/node_modules/@comis/web/dist/assets/media-test-BkK3RCRK.js +496 -0
  99. package/node_modules/@comis/web/dist/assets/memory-inspector-1hDGCGat.js +1139 -0
  100. package/node_modules/@comis/web/dist/assets/message-center-CXefwsUu.js +785 -0
  101. package/node_modules/@comis/web/dist/assets/models-C1qcU_j3.js +894 -0
  102. package/node_modules/@comis/web/dist/assets/observability-types-D7jUtSde.js +1 -0
  103. package/node_modules/@comis/web/dist/assets/observe-view-C0VBhX4C.js +814 -0
  104. package/node_modules/@comis/web/dist/assets/pipeline-builder-DcUUIrm0.js +1496 -0
  105. package/node_modules/@comis/web/dist/assets/pipeline-history-DkfOQ6SW.js +317 -0
  106. package/node_modules/@comis/web/dist/assets/pipeline-history-detail-hyHgD0ai.js +287 -0
  107. package/node_modules/@comis/web/dist/assets/pipeline-list-BPW8hV-q.js +518 -0
  108. package/node_modules/@comis/web/dist/assets/pipeline-monitor-Bip16T7e.js +972 -0
  109. package/node_modules/@comis/web/dist/assets/scheduler-BGgwKd06.js +1182 -0
  110. package/node_modules/@comis/web/dist/assets/security-D15st4xx.js +1224 -0
  111. package/node_modules/@comis/web/dist/assets/session-detail-SGEYNJ0M.js +632 -0
  112. package/node_modules/@comis/web/dist/assets/session-key-parser-DPORMVyU.js +1 -0
  113. package/node_modules/@comis/web/dist/assets/session-list-6ybUTxbY.js +231 -0
  114. package/node_modules/@comis/web/dist/assets/setup-wizard-nT0tz9QP.js +853 -0
  115. package/node_modules/@comis/web/dist/assets/skills-D8yVfSUy.js +1051 -0
  116. package/node_modules/@comis/web/dist/assets/subagents-HHXMeHYo.js +193 -0
  117. package/node_modules/@comis/web/dist/assets/workspace-manager-BQlr10iH.js +785 -0
  118. package/node_modules/@comis/web/dist/comis-logo.png +0 -0
  119. package/node_modules/@comis/web/dist/favicon-16x16.png +0 -0
  120. package/node_modules/@comis/web/dist/favicon-32x32.png +0 -0
  121. package/node_modules/@comis/web/dist/favicon.ico +0 -0
  122. package/node_modules/@comis/web/dist/index.html +17 -0
  123. package/node_modules/@comis/web/package.json +29 -0
  124. package/package.json +15 -13
@@ -12,7 +12,9 @@
12
12
  import { execFile, spawn } from "node:child_process";
13
13
  import { existsSync, readFileSync, writeFileSync, unlinkSync, mkdirSync, openSync } from "node:fs";
14
14
  import * as os from "node:os";
15
+ import { createInterface } from "node:readline";
15
16
  import { promisify } from "node:util";
17
+ import chalk from "chalk";
16
18
  import { safePath } from "@comis/core";
17
19
  import { withClient } from "../client/rpc-client.js";
18
20
  import { success, error, info, warn } from "../output/format.js";
@@ -23,6 +25,63 @@ const PID_FILE = safePath(COMIS_DIR, "daemon.pid");
23
25
  const LOG_FILE = safePath(COMIS_DIR, "daemon.log");
24
26
  /** Max time to wait for daemon gateway to become ready (ms). */
25
27
  const READY_TIMEOUT_MS = 15_000;
28
+ // ---------- Log formatting ----------
29
+ const PINO_LEVELS = {
30
+ 10: { label: "TRACE", color: chalk.gray },
31
+ 20: { label: "DEBUG", color: chalk.gray },
32
+ 30: { label: "INFO", color: chalk.cyan },
33
+ 40: { label: "WARN", color: chalk.yellow },
34
+ 50: { label: "ERROR", color: chalk.red },
35
+ 60: { label: "FATAL", color: chalk.bgRed.white },
36
+ };
37
+ const PINO_META_KEYS = new Set([
38
+ "level", "time", "pid", "hostname", "name", "msg", "module",
39
+ "levelValue", "instanceId",
40
+ ]);
41
+ function formatPinoLine(line) {
42
+ const trimmed = line.trim();
43
+ if (!trimmed.startsWith("{"))
44
+ return line;
45
+ let record;
46
+ try {
47
+ record = JSON.parse(trimmed);
48
+ }
49
+ catch {
50
+ return line;
51
+ }
52
+ if (typeof record["level"] !== "number" && typeof record["level"] !== "string")
53
+ return line;
54
+ const levelNum = typeof record["level"] === "number"
55
+ ? record["level"]
56
+ : ({ trace: 10, debug: 20, info: 30, warn: 40, error: 50, fatal: 60 }[record["level"]] ?? 30);
57
+ const levelInfo = PINO_LEVELS[levelNum] ?? { label: String(record["level"]), color: chalk.white };
58
+ const time = record["time"]
59
+ ? new Date(record["time"]).toLocaleTimeString()
60
+ : "";
61
+ const mod = record["module"] ? `[${record["module"]}]` : "";
62
+ const msg = record["msg"] ?? "";
63
+ const extra = {};
64
+ for (const [k, v] of Object.entries(record)) {
65
+ if (!PINO_META_KEYS.has(k))
66
+ extra[k] = v;
67
+ }
68
+ const extraStr = Object.keys(extra).length > 0
69
+ ? chalk.gray(` ${JSON.stringify(extra)}`)
70
+ : "";
71
+ return `${chalk.dim(time)} ${levelInfo.color(levelInfo.label.padEnd(5))} ${chalk.blue(mod)} ${msg}${extraStr}`;
72
+ }
73
+ function formatLogOutput(raw) {
74
+ return raw
75
+ .split("\n")
76
+ .map((line) => (line.trim() ? formatPinoLine(line) : line))
77
+ .join("\n");
78
+ }
79
+ function pipeFormatted(child) {
80
+ if (!child.stdout)
81
+ return;
82
+ const rl = createInterface({ input: child.stdout });
83
+ rl.on("line", (line) => console.log(formatPinoLine(line)));
84
+ }
26
85
  /** Interval between readiness polls (ms). */
27
86
  const READY_POLL_MS = 500;
28
87
  /**
@@ -533,40 +592,48 @@ async function handleDaemonLogs(options) {
533
592
  }
534
593
  }
535
594
  async function streamSystemdLogs(scope, options) {
536
- const jArgs = ["--unit=comis", "--no-pager", `-n${options.lines}`];
595
+ const jArgs = ["--unit=comis", "--no-pager", `-n${options.lines}`, "--output=cat"];
537
596
  if (scope === "systemd-user")
538
597
  jArgs.push("--user");
539
598
  if (options.follow)
540
599
  jArgs.push("--follow");
541
600
  if (options.follow) {
542
- const child = spawn("journalctl", jArgs, { stdio: "inherit" });
543
- child.on("error", (err) => {
544
- error(`Failed to read logs: ${err.message}`);
545
- process.exit(1);
546
- });
601
+ if (options.raw) {
602
+ const child = spawn("journalctl", jArgs, { stdio: "inherit" });
603
+ child.on("error", (err) => {
604
+ error(`Failed to read logs: ${err.message}`);
605
+ process.exit(1);
606
+ });
607
+ }
608
+ else {
609
+ const child = spawn("journalctl", jArgs, { stdio: ["ignore", "pipe", "inherit"] });
610
+ child.on("error", (err) => {
611
+ error(`Failed to read logs: ${err.message}`);
612
+ process.exit(1);
613
+ });
614
+ pipeFormatted(child);
615
+ }
547
616
  return;
548
617
  }
549
- // Try journalctl directly first (works when user is in systemd-journal group),
550
- // then fall back to sudo for system-scope journals.
551
- try {
552
- const { stdout } = await exec("journalctl", jArgs, { timeout: 10_000 });
618
+ const printOutput = (stdout) => {
553
619
  if (stdout.trim()) {
554
- console.log(stdout);
620
+ console.log(options.raw ? stdout : formatLogOutput(stdout));
555
621
  }
556
622
  else {
557
623
  info("No logs found");
558
624
  }
625
+ };
626
+ // Try journalctl directly first (works when user is in systemd-journal group),
627
+ // then fall back to sudo for system-scope journals.
628
+ try {
629
+ const { stdout } = await exec("journalctl", jArgs, { timeout: 10_000 });
630
+ printOutput(stdout);
559
631
  }
560
632
  catch {
561
633
  // eslint-disable-next-line no-restricted-syntax -- CLI bootstrap before SecretManager
562
634
  if (scope === "systemd" && process.getuid?.() !== 0) {
563
635
  const { stdout } = await exec("sudo", ["journalctl", ...jArgs], { timeout: 10_000 });
564
- if (stdout.trim()) {
565
- console.log(stdout);
566
- }
567
- else {
568
- info("No logs found");
569
- }
636
+ printOutput(stdout);
570
637
  }
571
638
  else {
572
639
  throw new Error("Failed to read journal logs");
@@ -577,11 +644,21 @@ function streamPm2Logs(options) {
577
644
  const args = ["logs", "comis", "--lines", options.lines];
578
645
  if (!options.follow)
579
646
  args.push("--nostream");
580
- const child = spawn("pm2", args, { stdio: "inherit" });
581
- child.on("error", (err) => {
582
- error(`Failed to read logs: ${err.message}`);
583
- process.exit(1);
584
- });
647
+ if (options.raw) {
648
+ const child = spawn("pm2", args, { stdio: "inherit" });
649
+ child.on("error", (err) => {
650
+ error(`Failed to read logs: ${err.message}`);
651
+ process.exit(1);
652
+ });
653
+ }
654
+ else {
655
+ const child = spawn("pm2", args, { stdio: ["ignore", "pipe", "inherit"] });
656
+ child.on("error", (err) => {
657
+ error(`Failed to read logs: ${err.message}`);
658
+ process.exit(1);
659
+ });
660
+ pipeFormatted(child);
661
+ }
585
662
  }
586
663
  async function streamDirectLogs(options) {
587
664
  // eslint-disable-next-line no-restricted-syntax -- CLI bootstrap before SecretManager
@@ -594,16 +671,26 @@ async function streamDirectLogs(options) {
594
671
  const args = ["-n", options.lines, logPath];
595
672
  if (options.follow) {
596
673
  args.unshift("-f");
597
- const child = spawn("tail", args, { stdio: "inherit" });
598
- child.on("error", (err) => {
599
- error(`Failed to read logs: ${err.message}`);
600
- process.exit(1);
601
- });
674
+ if (options.raw) {
675
+ const child = spawn("tail", args, { stdio: "inherit" });
676
+ child.on("error", (err) => {
677
+ error(`Failed to read logs: ${err.message}`);
678
+ process.exit(1);
679
+ });
680
+ }
681
+ else {
682
+ const child = spawn("tail", args, { stdio: ["ignore", "pipe", "inherit"] });
683
+ child.on("error", (err) => {
684
+ error(`Failed to read logs: ${err.message}`);
685
+ process.exit(1);
686
+ });
687
+ pipeFormatted(child);
688
+ }
602
689
  return;
603
690
  }
604
691
  const { stdout } = await exec("tail", args, { timeout: 5_000 });
605
692
  if (stdout.trim()) {
606
- console.log(stdout);
693
+ console.log(options.raw ? stdout : formatLogOutput(stdout));
607
694
  }
608
695
  else {
609
696
  info("No logs found");
@@ -634,5 +721,6 @@ export function registerDaemonCommand(program) {
634
721
  .description("Show daemon logs")
635
722
  .option("-f, --follow", "Follow log output")
636
723
  .option("-n, --lines <n>", "Number of lines to show", "50")
724
+ .option("--raw", "Show raw JSON output without formatting")
637
725
  .action(handleDaemonLogs);
638
726
  }
@@ -230,6 +230,7 @@ export function buildNonInteractiveState(opts) {
230
230
  authMethod: gatewayAuth,
231
231
  ...(gatewayToken !== undefined && { token: gatewayToken }),
232
232
  ...(gatewayPassword !== undefined && { password: gatewayPassword }),
233
+ webEnabled: true,
233
234
  };
234
235
  // Data directory
235
236
  const dataDir = opts.dataDir ?? safePath(homedir(), ".comis", "data");
@@ -68,12 +68,16 @@ function extractStateFromConfig(raw, envRecord = {}) {
68
68
  bindMode = "custom";
69
69
  customIp = host;
70
70
  }
71
+ // Recover gateway.web.enabled (default true) when reloading existing config
72
+ const webRaw = gatewayRaw["web"];
73
+ const webEnabled = webRaw && typeof webRaw["enabled"] === "boolean" ? webRaw["enabled"] : true;
71
74
  if (port !== undefined) {
72
75
  gateway = {
73
76
  port,
74
77
  bindMode,
75
78
  ...(customIp !== undefined && { customIp }),
76
79
  authMethod: "token",
80
+ webEnabled,
77
81
  };
78
82
  }
79
83
  }
@@ -91,6 +91,14 @@ export const gatewayStep = {
91
91
  },
92
92
  });
93
93
  }
94
+ // 5b. Web dashboard prompt
95
+ const webEnabled = await prompter.confirm({
96
+ message: "Enable web dashboard? (served at /app/ on the gateway port)",
97
+ initialValue: state.gateway?.webEnabled ?? true,
98
+ });
99
+ if (webEnabled && bindMode === "loopback") {
100
+ prompter.log.info("Dashboard will bind to 127.0.0.1 only. For remote access, SSH-tunnel: `ssh -L 4766:localhost:4766 user@host`.");
101
+ }
94
102
  // 6. Build config and update state
95
103
  const config = {
96
104
  port,
@@ -99,6 +107,7 @@ export const gatewayStep = {
99
107
  authMethod: authMethod,
100
108
  ...(token !== undefined && { token }),
101
109
  ...(password !== undefined && { password }),
110
+ webEnabled,
102
111
  };
103
112
  return updateState(state, { gateway: config });
104
113
  },
@@ -96,6 +96,8 @@ function buildConfigObject(state) {
96
96
  else if (state.gateway.authMethod === "password") {
97
97
  gatewayConfig.password = "${COMIS_GATEWAY_PASSWORD}";
98
98
  }
99
+ // Web dashboard -- default true; wizard always sets this explicitly
100
+ gatewayConfig.web = { enabled: state.gateway.webEnabled };
99
101
  config.gateway = gatewayConfig;
100
102
  }
101
103
  // Channels section
@@ -54,6 +54,9 @@ function buildGatewayInfo(state) {
54
54
  host = "127.0.0.1";
55
55
  }
56
56
  const wsLine = ` WebSocket: ${brand(`ws://${host}:${state.gateway.port}/ws`)}`;
57
+ const dashboardLine = state.gateway.webEnabled
58
+ ? ` Dashboard: ${brand(`http://${host}:${state.gateway.port}/app/`)}`
59
+ : undefined;
57
60
  let authLine;
58
61
  if (state.gateway.authMethod === "password") {
59
62
  authLine = " Auth: Password auth (in ~/.comis/.env)";
@@ -64,8 +67,8 @@ function buildGatewayInfo(state) {
64
67
  : "see file";
65
68
  authLine = ` Token: ${tokenPreview} (in ~/.comis/.env)`;
66
69
  }
67
- const webLine = ` Web App: ${brand(`http://${host}:${state.gateway.port}`)}`;
68
- return `${wsLine}\n${webLine}\n${authLine}`;
70
+ const lines = [wsLine, dashboardLine, authLine].filter((l) => l !== undefined);
71
+ return lines.join("\n");
69
72
  }
70
73
  // ---------- Step Implementation ----------
71
74
  export const finishStep = {
@@ -65,6 +65,7 @@ export type GatewayConfig = {
65
65
  authMethod: "token" | "password";
66
66
  token?: string;
67
67
  password?: string;
68
+ webEnabled: boolean;
68
69
  };
69
70
  /** Auth method for providers that support both API keys and OAuth tokens. */
70
71
  export type AuthMethod = "apikey" | "oauth";
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@comis/cli",
3
3
  "private": true,
4
- "version": "1.0.15",
4
+ "version": "1.0.17",
5
5
  "author": "Moshe Anconina",
6
6
  "license": "Apache-2.0",
7
7
  "description": "Command-line interface for the Comis AI agent platform",
@@ -737,6 +737,10 @@ export declare const AgentConfigSchema: z.ZodObject<{
737
737
  "multi-zone": "multi-zone";
738
738
  single: "single";
739
739
  }>>;
740
+ /** Advanced cache optimization options for interactive sessions. */
741
+ advancedCacheOptimization: z.ZodDefault<z.ZodObject<{
742
+ enableRecentZonePromotion: z.ZodDefault<z.ZodBoolean>;
743
+ }, z.core.$strip>>;
740
744
  /** Gemini explicit cache configuration (CachedContent lifecycle). */
741
745
  geminiCache: z.ZodDefault<z.ZodObject<{
742
746
  enabled: z.ZodDefault<z.ZodBoolean>;
@@ -1102,6 +1106,9 @@ export declare const PerAgentConfigSchema: z.ZodObject<{
1102
1106
  "multi-zone": "multi-zone";
1103
1107
  single: "single";
1104
1108
  }>>;
1109
+ advancedCacheOptimization: z.ZodDefault<z.ZodObject<{
1110
+ enableRecentZonePromotion: z.ZodDefault<z.ZodBoolean>;
1111
+ }, z.core.$strip>>;
1105
1112
  geminiCache: z.ZodDefault<z.ZodObject<{
1106
1113
  enabled: z.ZodDefault<z.ZodBoolean>;
1107
1114
  maxActiveCaches: z.ZodDefault<z.ZodNumber>;
@@ -1773,6 +1780,9 @@ export declare const AgentsMapSchema: z.ZodRecord<z.ZodString, z.ZodObject<{
1773
1780
  "multi-zone": "multi-zone";
1774
1781
  single: "single";
1775
1782
  }>>;
1783
+ advancedCacheOptimization: z.ZodDefault<z.ZodObject<{
1784
+ enableRecentZonePromotion: z.ZodDefault<z.ZodBoolean>;
1785
+ }, z.core.$strip>>;
1776
1786
  geminiCache: z.ZodDefault<z.ZodObject<{
1777
1787
  enabled: z.ZodDefault<z.ZodBoolean>;
1778
1788
  maxActiveCaches: z.ZodDefault<z.ZodNumber>;
@@ -574,6 +574,14 @@ export const AgentConfigSchema = z.strictObject({
574
574
  * 'auto' resolves to 'single' for direct Anthropic and 'multi-zone' for Bedrock/Vertex.
575
575
  * 'multi-zone' places breakpoints across system, tools, and messages. */
576
576
  cacheBreakpointStrategy: z.enum(["auto", "multi-zone", "single"]).default("single"),
577
+ /** Advanced cache optimization options for interactive sessions. */
578
+ advancedCacheOptimization: z.object({
579
+ /** When true, the recent-zone message breakpoint may be promoted from
580
+ * "short" (5m) to "long" (1h) TTL when observed inter-turn gaps
581
+ * consistently exceed 5 minutes. Prevents repeated cache rewrite costs
582
+ * in slow-cadence channels like Telegram. Default: true. */
583
+ enableRecentZonePromotion: z.boolean().default(true),
584
+ }).default(() => ({ enableRecentZonePromotion: true })),
577
585
  /** Gemini explicit cache configuration (CachedContent lifecycle). */
578
586
  geminiCache: GeminiCacheConfigSchema.default(() => GeminiCacheConfigSchema.parse({})),
579
587
  /** When true, only content inside <final> blocks reaches users (streaming + non-streaming). Default: false. */
@@ -29,9 +29,9 @@ export declare const GatewayTokenSchema: z.ZodObject<{
29
29
  /** The secret value (min 32 chars; resolved at runtime if omitted; string or SecretRef) */
30
30
  secret: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
31
31
  source: z.ZodEnum<{
32
+ env: "env";
32
33
  file: "file";
33
34
  exec: "exec";
34
- env: "env";
35
35
  }>;
36
36
  provider: z.ZodString;
37
37
  id: z.ZodString;
@@ -48,6 +48,15 @@ export declare const GatewayRateLimitSchema: z.ZodObject<{
48
48
  /** Maximum requests per window (default: 100) */
49
49
  maxRequests: z.ZodDefault<z.ZodNumber>;
50
50
  }, z.core.$strict>;
51
+ /**
52
+ * Web dashboard configuration. Controls whether the @comis/web SPA is mounted
53
+ * at /app/* alongside the gateway, sharing the same host/port/auth. When
54
+ * disabled, the daemon skips /app/*, /api, SSE, and the `/` -> `/app/` redirect.
55
+ */
56
+ export declare const GatewayWebConfigSchema: z.ZodObject<{
57
+ /** Enable the web dashboard SPA (default: true) */
58
+ enabled: z.ZodDefault<z.ZodBoolean>;
59
+ }, z.core.$strict>;
51
60
  /**
52
61
  * Gateway server configuration schema.
53
62
  *
@@ -79,9 +88,9 @@ export declare const GatewayConfigSchema: z.ZodObject<{
79
88
  /** The secret value (min 32 chars; resolved at runtime if omitted; string or SecretRef) */
80
89
  secret: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
81
90
  source: z.ZodEnum<{
91
+ env: "env";
82
92
  file: "file";
83
93
  exec: "exec";
84
- env: "env";
85
94
  }>;
86
95
  provider: z.ZodString;
87
96
  id: z.ZodString;
@@ -96,6 +105,11 @@ export declare const GatewayConfigSchema: z.ZodObject<{
96
105
  /** Maximum requests per window (default: 100) */
97
106
  maxRequests: z.ZodDefault<z.ZodNumber>;
98
107
  }, z.core.$strict>>;
108
+ /** Web dashboard (mounted at /app/*, shares gateway host/port/auth) */
109
+ web: z.ZodDefault<z.ZodObject<{
110
+ /** Enable the web dashboard SPA (default: true) */
111
+ enabled: z.ZodDefault<z.ZodBoolean>;
112
+ }, z.core.$strict>>;
99
113
  /** Maximum JSON-RPC batch size (default: 50) */
100
114
  maxBatchSize: z.ZodDefault<z.ZodNumber>;
101
115
  /** WebSocket heartbeat interval in milliseconds (default: 30000) */
@@ -122,3 +136,4 @@ export type GatewayConfig = z.infer<typeof GatewayConfigSchema>;
122
136
  export type GatewayTlsConfig = z.infer<typeof GatewayTlsConfigSchema>;
123
137
  export type GatewayToken = z.infer<typeof GatewayTokenSchema>;
124
138
  export type GatewayRateLimit = z.infer<typeof GatewayRateLimitSchema>;
139
+ export type GatewayWebConfig = z.infer<typeof GatewayWebConfigSchema>;
@@ -42,6 +42,15 @@ export const GatewayRateLimitSchema = z.strictObject({
42
42
  /** Maximum requests per window (default: 100) */
43
43
  maxRequests: z.number().int().positive().default(100),
44
44
  });
45
+ /**
46
+ * Web dashboard configuration. Controls whether the @comis/web SPA is mounted
47
+ * at /app/* alongside the gateway, sharing the same host/port/auth. When
48
+ * disabled, the daemon skips /app/*, /api, SSE, and the `/` -> `/app/` redirect.
49
+ */
50
+ export const GatewayWebConfigSchema = z.strictObject({
51
+ /** Enable the web dashboard SPA (default: true) */
52
+ enabled: z.boolean().default(true),
53
+ });
45
54
  /**
46
55
  * Gateway server configuration schema.
47
56
  *
@@ -61,6 +70,8 @@ export const GatewayConfigSchema = z.strictObject({
61
70
  tokens: z.array(GatewayTokenSchema).default([]),
62
71
  /** Rate limiting settings */
63
72
  rateLimit: GatewayRateLimitSchema.default(() => GatewayRateLimitSchema.parse({})),
73
+ /** Web dashboard (mounted at /app/*, shares gateway host/port/auth) */
74
+ web: GatewayWebConfigSchema.default(() => GatewayWebConfigSchema.parse({})),
64
75
  /** Maximum JSON-RPC batch size (default: 50) */
65
76
  maxBatchSize: z.number().int().positive().default(50),
66
77
  /** WebSocket heartbeat interval in milliseconds (default: 30000) */
@@ -23,7 +23,14 @@ export declare const PromptSkillsConfigSchema: z.ZodObject<{
23
23
  * per-deployment without a rebuild.
24
24
  */
25
25
  declare const ToolDiscoverySchema: z.ZodObject<{
26
- /** Minimum BM25 score to consider a match (BM25-only mode). Default 0.8. */
26
+ /** Minimum BM25 score as FRACTION OF TOP MATCH (0..1). Default 0.8.
27
+ * As of 2026-04-23, BM25 scores are normalized to [0, 1] before this floor
28
+ * applies, matching the semantics of minHybridScore. A value of 0.8 means
29
+ * "return only tools scoring >= 80% of the top match". Values > 1.0 fail
30
+ * validation at config load (stale raw-score overrides would produce zero
31
+ * matches under the new normalized semantics; fail-fast surfaces the
32
+ * error immediately per AGENTS.md §3.4). See design §5.6:
33
+ * .planning/design/discover-tools-bm25-fallback-fix.md */
27
34
  minBm25Score: z.ZodDefault<z.ZodNumber>;
28
35
  /** Minimum combined score (0..1 normalized) for hybrid mode. Default 0.35. */
29
36
  minHybridScore: z.ZodDefault<z.ZodNumber>;
@@ -115,7 +122,14 @@ export declare const SkillsConfigSchema: z.ZodObject<{
115
122
  }, z.core.$strict>>;
116
123
  /** discover_tools score-floor thresholds (BM25 + hybrid). */
117
124
  toolDiscovery: z.ZodDefault<z.ZodObject<{
118
- /** Minimum BM25 score to consider a match (BM25-only mode). Default 0.8. */
125
+ /** Minimum BM25 score as FRACTION OF TOP MATCH (0..1). Default 0.8.
126
+ * As of 2026-04-23, BM25 scores are normalized to [0, 1] before this floor
127
+ * applies, matching the semantics of minHybridScore. A value of 0.8 means
128
+ * "return only tools scoring >= 80% of the top match". Values > 1.0 fail
129
+ * validation at config load (stale raw-score overrides would produce zero
130
+ * matches under the new normalized semantics; fail-fast surfaces the
131
+ * error immediately per AGENTS.md §3.4). See design §5.6:
132
+ * .planning/design/discover-tools-bm25-fallback-fix.md */
119
133
  minBm25Score: z.ZodDefault<z.ZodNumber>;
120
134
  /** Minimum combined score (0..1 normalized) for hybrid mode. Default 0.35. */
121
135
  minHybridScore: z.ZodDefault<z.ZodNumber>;
@@ -93,8 +93,15 @@ const ExecSandboxSchema = z.strictObject({
93
93
  * per-deployment without a rebuild.
94
94
  */
95
95
  const ToolDiscoverySchema = z.strictObject({
96
- /** Minimum BM25 score to consider a match (BM25-only mode). Default 0.8. */
97
- minBm25Score: z.number().min(0).default(0.8),
96
+ /** Minimum BM25 score as FRACTION OF TOP MATCH (0..1). Default 0.8.
97
+ * As of 2026-04-23, BM25 scores are normalized to [0, 1] before this floor
98
+ * applies, matching the semantics of minHybridScore. A value of 0.8 means
99
+ * "return only tools scoring >= 80% of the top match". Values > 1.0 fail
100
+ * validation at config load (stale raw-score overrides would produce zero
101
+ * matches under the new normalized semantics; fail-fast surfaces the
102
+ * error immediately per AGENTS.md §3.4). See design §5.6:
103
+ * .planning/design/discover-tools-bm25-fallback-fix.md */
104
+ minBm25Score: z.number().min(0).max(1).default(0.8),
98
105
  /** Minimum combined score (0..1 normalized) for hybrid mode. Default 0.35. */
99
106
  minHybridScore: z.number().min(0).max(1).default(0.35),
100
107
  });