@askexenow/exe-os 0.8.41 → 0.8.42
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/bin/backfill-conversations.js +805 -642
- package/dist/bin/backfill-responses.js +804 -641
- package/dist/bin/backfill-vectors.js +791 -634
- package/dist/bin/cleanup-stale-review-tasks.js +788 -631
- package/dist/bin/cli.js +1326 -655
- package/dist/bin/exe-agent.js +20 -1
- package/dist/bin/exe-assign.js +1503 -1343
- package/dist/bin/exe-boot.js +2508 -1802
- package/dist/bin/exe-call.js +39 -1
- package/dist/bin/exe-dispatch.js +39 -2
- package/dist/bin/exe-doctor.js +790 -633
- package/dist/bin/exe-export-behaviors.js +792 -637
- package/dist/bin/exe-forget.js +145 -0
- package/dist/bin/exe-gateway.js +2487 -1878
- package/dist/bin/exe-heartbeat.js +147 -1
- package/dist/bin/exe-kill.js +795 -640
- package/dist/bin/exe-launch-agent.js +2168 -2008
- package/dist/bin/exe-link.js +9 -1
- package/dist/bin/exe-new-employee.js +6 -2
- package/dist/bin/exe-pending-messages.js +146 -1
- package/dist/bin/exe-pending-notifications.js +788 -631
- package/dist/bin/exe-pending-reviews.js +147 -1
- package/dist/bin/exe-rename.js +23 -0
- package/dist/bin/exe-review.js +490 -327
- package/dist/bin/exe-search.js +154 -3
- package/dist/bin/exe-session-cleanup.js +2466 -413
- package/dist/bin/exe-status.js +474 -317
- package/dist/bin/exe-team.js +474 -317
- package/dist/bin/git-sweep.js +2690 -150
- package/dist/bin/graph-backfill.js +794 -637
- package/dist/bin/graph-export.js +798 -641
- package/dist/bin/scan-tasks.js +2951 -44
- package/dist/bin/setup.js +47 -25
- package/dist/bin/shard-migrate.js +792 -637
- package/dist/bin/wiki-sync.js +794 -637
- package/dist/gateway/index.js +2504 -1895
- package/dist/hooks/bug-report-worker.js +2118 -576
- package/dist/hooks/commit-complete.js +2689 -149
- package/dist/hooks/error-recall.js +154 -3
- package/dist/hooks/ingest-worker.js +1420 -814
- package/dist/hooks/instructions-loaded.js +151 -0
- package/dist/hooks/notification.js +153 -2
- package/dist/hooks/post-compact.js +164 -0
- package/dist/hooks/pre-compact.js +3073 -101
- package/dist/hooks/pre-tool-use.js +151 -0
- package/dist/hooks/prompt-ingest-worker.js +1700 -1541
- package/dist/hooks/prompt-submit.js +2658 -1113
- package/dist/hooks/response-ingest-worker.js +151 -5
- package/dist/hooks/session-end.js +153 -2
- package/dist/hooks/session-start.js +154 -3
- package/dist/hooks/stop.js +151 -0
- package/dist/hooks/subagent-stop.js +151 -0
- package/dist/hooks/summary-worker.js +160 -6
- package/dist/index.js +278 -100
- package/dist/lib/cloud-sync.js +9 -1
- package/dist/lib/consolidation.js +69 -2
- package/dist/lib/database.js +19 -0
- package/dist/lib/device-registry.js +19 -0
- package/dist/lib/employee-templates.js +20 -1
- package/dist/lib/exe-daemon.js +236 -16
- package/dist/lib/hybrid-search.js +154 -3
- package/dist/lib/messaging.js +39 -2
- package/dist/lib/schedules.js +792 -637
- package/dist/lib/store.js +796 -636
- package/dist/lib/tasks.js +1614 -1091
- package/dist/lib/tmux-routing.js +149 -9
- package/dist/mcp/server.js +1810 -1137
- package/dist/mcp/tools/create-task.js +2280 -828
- package/dist/mcp/tools/list-tasks.js +2788 -159
- package/dist/mcp/tools/send-message.js +39 -2
- package/dist/mcp/tools/update-task.js +64 -0
- package/dist/runtime/index.js +235 -67
- package/dist/tui/App.js +1440 -646
- package/package.json +3 -2
package/dist/tui/App.js
CHANGED
|
@@ -39,6 +39,73 @@ var init_devtools = __esm({
|
|
|
39
39
|
}
|
|
40
40
|
});
|
|
41
41
|
|
|
42
|
+
// src/lib/telemetry.ts
|
|
43
|
+
var telemetry_exports = {};
|
|
44
|
+
__export(telemetry_exports, {
|
|
45
|
+
instrumentServer: () => instrumentServer,
|
|
46
|
+
withTrace: () => withTrace
|
|
47
|
+
});
|
|
48
|
+
async function ensureInit() {
|
|
49
|
+
if (initialized || !ENABLED) return;
|
|
50
|
+
initialized = true;
|
|
51
|
+
try {
|
|
52
|
+
const { NodeSDK } = await import("@opentelemetry/sdk-node");
|
|
53
|
+
const { ConsoleSpanExporter } = await import("@opentelemetry/sdk-trace-base");
|
|
54
|
+
const sdk = new NodeSDK({
|
|
55
|
+
serviceName: "exe-os",
|
|
56
|
+
traceExporter: new ConsoleSpanExporter()
|
|
57
|
+
});
|
|
58
|
+
sdk.start();
|
|
59
|
+
process.stderr.write("[exe-os] OpenTelemetry tracing enabled\n");
|
|
60
|
+
} catch (err) {
|
|
61
|
+
process.stderr.write(
|
|
62
|
+
`[exe-os] OpenTelemetry init failed: ${err instanceof Error ? err.message : String(err)}
|
|
63
|
+
`
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
async function withTrace(toolName, fn) {
|
|
68
|
+
if (!ENABLED) return fn();
|
|
69
|
+
await ensureInit();
|
|
70
|
+
const { trace, SpanStatusCode } = await import("@opentelemetry/api");
|
|
71
|
+
const tracer = trace.getTracer("exe-os", "1.0.0");
|
|
72
|
+
return tracer.startActiveSpan(`mcp.tool.${toolName}`, async (span) => {
|
|
73
|
+
span.setAttribute("mcp.tool.name", toolName);
|
|
74
|
+
try {
|
|
75
|
+
const result = await fn();
|
|
76
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
77
|
+
return result;
|
|
78
|
+
} catch (err) {
|
|
79
|
+
span.setStatus({
|
|
80
|
+
code: SpanStatusCode.ERROR,
|
|
81
|
+
message: err instanceof Error ? err.message : String(err)
|
|
82
|
+
});
|
|
83
|
+
span.recordException(
|
|
84
|
+
err instanceof Error ? err : new Error(String(err))
|
|
85
|
+
);
|
|
86
|
+
throw err;
|
|
87
|
+
} finally {
|
|
88
|
+
span.end();
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
function instrumentServer(server) {
|
|
93
|
+
if (!ENABLED) return;
|
|
94
|
+
const original = server.registerTool.bind(server);
|
|
95
|
+
server.registerTool = (name, config, handler) => {
|
|
96
|
+
const traced = async (...args) => withTrace(name, () => handler(...args));
|
|
97
|
+
return original(name, config, traced);
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
var ENABLED, initialized;
|
|
101
|
+
var init_telemetry = __esm({
|
|
102
|
+
"src/lib/telemetry.ts"() {
|
|
103
|
+
"use strict";
|
|
104
|
+
ENABLED = process.env.EXE_TELEMETRY === "1";
|
|
105
|
+
initialized = false;
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
42
109
|
// src/lib/db-retry.ts
|
|
43
110
|
function isBusyError(err) {
|
|
44
111
|
if (err instanceof Error) {
|
|
@@ -346,6 +413,13 @@ async function ensureSchema() {
|
|
|
346
413
|
});
|
|
347
414
|
} catch {
|
|
348
415
|
}
|
|
416
|
+
try {
|
|
417
|
+
await client.execute({
|
|
418
|
+
sql: `ALTER TABLE tasks ADD COLUMN session_scope TEXT`,
|
|
419
|
+
args: []
|
|
420
|
+
});
|
|
421
|
+
} catch {
|
|
422
|
+
}
|
|
349
423
|
try {
|
|
350
424
|
await client.execute({
|
|
351
425
|
sql: `ALTER TABLE memories ADD COLUMN task_id TEXT`,
|
|
@@ -792,6 +866,18 @@ async function ensureSchema() {
|
|
|
792
866
|
CREATE INDEX IF NOT EXISTS idx_session_kills_agent
|
|
793
867
|
ON session_kills(agent_id);
|
|
794
868
|
`);
|
|
869
|
+
await client.execute(`
|
|
870
|
+
CREATE TABLE IF NOT EXISTS global_procedures (
|
|
871
|
+
id TEXT PRIMARY KEY,
|
|
872
|
+
title TEXT NOT NULL,
|
|
873
|
+
content TEXT NOT NULL,
|
|
874
|
+
priority TEXT NOT NULL DEFAULT 'p0',
|
|
875
|
+
domain TEXT,
|
|
876
|
+
active INTEGER NOT NULL DEFAULT 1,
|
|
877
|
+
created_at TEXT NOT NULL,
|
|
878
|
+
updated_at TEXT NOT NULL
|
|
879
|
+
)
|
|
880
|
+
`);
|
|
795
881
|
await client.executeMultiple(`
|
|
796
882
|
CREATE TABLE IF NOT EXISTS conversations (
|
|
797
883
|
id TEXT PRIMARY KEY,
|
|
@@ -2711,6 +2797,71 @@ var init_agent_loop = __esm({
|
|
|
2711
2797
|
}
|
|
2712
2798
|
});
|
|
2713
2799
|
|
|
2800
|
+
// src/lib/global-procedures.ts
|
|
2801
|
+
var global_procedures_exports = {};
|
|
2802
|
+
__export(global_procedures_exports, {
|
|
2803
|
+
deactivateGlobalProcedure: () => deactivateGlobalProcedure,
|
|
2804
|
+
getGlobalProceduresBlock: () => getGlobalProceduresBlock,
|
|
2805
|
+
loadGlobalProcedures: () => loadGlobalProcedures,
|
|
2806
|
+
storeGlobalProcedure: () => storeGlobalProcedure
|
|
2807
|
+
});
|
|
2808
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
2809
|
+
async function loadGlobalProcedures() {
|
|
2810
|
+
const client = getClient();
|
|
2811
|
+
const result = await client.execute({
|
|
2812
|
+
sql: "SELECT * FROM global_procedures WHERE active = 1 ORDER BY priority ASC, created_at ASC",
|
|
2813
|
+
args: []
|
|
2814
|
+
});
|
|
2815
|
+
const procedures = result.rows;
|
|
2816
|
+
if (procedures.length > 0) {
|
|
2817
|
+
_cache = procedures.map((p) => `### ${p.title}
|
|
2818
|
+
${p.content}`).join("\n\n");
|
|
2819
|
+
} else {
|
|
2820
|
+
_cache = "";
|
|
2821
|
+
}
|
|
2822
|
+
_cacheLoaded = true;
|
|
2823
|
+
return procedures;
|
|
2824
|
+
}
|
|
2825
|
+
function getGlobalProceduresBlock() {
|
|
2826
|
+
if (!_cacheLoaded) return "";
|
|
2827
|
+
if (!_cache) return "";
|
|
2828
|
+
return `## Organization-Wide Procedures (MANDATORY \u2014 supersedes all other rules)
|
|
2829
|
+
|
|
2830
|
+
${_cache}
|
|
2831
|
+
`;
|
|
2832
|
+
}
|
|
2833
|
+
async function storeGlobalProcedure(input) {
|
|
2834
|
+
const id = randomUUID2();
|
|
2835
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2836
|
+
const client = getClient();
|
|
2837
|
+
await client.execute({
|
|
2838
|
+
sql: `INSERT INTO global_procedures (id, title, content, priority, domain, active, created_at, updated_at)
|
|
2839
|
+
VALUES (?, ?, ?, ?, ?, 1, ?, ?)`,
|
|
2840
|
+
args: [id, input.title, input.content, input.priority ?? "p0", input.domain ?? null, now, now]
|
|
2841
|
+
});
|
|
2842
|
+
await loadGlobalProcedures();
|
|
2843
|
+
return id;
|
|
2844
|
+
}
|
|
2845
|
+
async function deactivateGlobalProcedure(id) {
|
|
2846
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2847
|
+
const client = getClient();
|
|
2848
|
+
const result = await client.execute({
|
|
2849
|
+
sql: "UPDATE global_procedures SET active = 0, updated_at = ? WHERE id = ?",
|
|
2850
|
+
args: [now, id]
|
|
2851
|
+
});
|
|
2852
|
+
await loadGlobalProcedures();
|
|
2853
|
+
return result.rowsAffected > 0;
|
|
2854
|
+
}
|
|
2855
|
+
var _cache, _cacheLoaded;
|
|
2856
|
+
var init_global_procedures = __esm({
|
|
2857
|
+
"src/lib/global-procedures.ts"() {
|
|
2858
|
+
"use strict";
|
|
2859
|
+
init_database();
|
|
2860
|
+
_cache = "";
|
|
2861
|
+
_cacheLoaded = false;
|
|
2862
|
+
}
|
|
2863
|
+
});
|
|
2864
|
+
|
|
2714
2865
|
// src/gateway/providers/anthropic.ts
|
|
2715
2866
|
import Anthropic from "@anthropic-ai/sdk";
|
|
2716
2867
|
var AnthropicProvider;
|
|
@@ -2815,7 +2966,7 @@ var init_anthropic = __esm({
|
|
|
2815
2966
|
|
|
2816
2967
|
// src/gateway/providers/openai-compat.ts
|
|
2817
2968
|
import OpenAI from "openai";
|
|
2818
|
-
import { randomUUID as
|
|
2969
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
2819
2970
|
var OpenAICompatProvider;
|
|
2820
2971
|
var init_openai_compat = __esm({
|
|
2821
2972
|
"src/gateway/providers/openai-compat.ts"() {
|
|
@@ -2932,7 +3083,7 @@ var init_openai_compat = __esm({
|
|
|
2932
3083
|
}
|
|
2933
3084
|
content.push({
|
|
2934
3085
|
type: "tool_use",
|
|
2935
|
-
id: call.id ??
|
|
3086
|
+
id: call.id ?? randomUUID3(),
|
|
2936
3087
|
name: fn.name,
|
|
2937
3088
|
input
|
|
2938
3089
|
});
|
|
@@ -4017,7 +4168,7 @@ var init_employees = __esm({
|
|
|
4017
4168
|
});
|
|
4018
4169
|
|
|
4019
4170
|
// src/lib/task-router.ts
|
|
4020
|
-
import { randomUUID as
|
|
4171
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
4021
4172
|
function resolveBloomRouting(complexity, config = DEFAULT_BLOOM_CONFIG) {
|
|
4022
4173
|
const tier = config.complexityToTier[complexity];
|
|
4023
4174
|
const rule = config.tierRules[tier];
|
|
@@ -4549,6 +4700,61 @@ var init_session_kill_telemetry = __esm({
|
|
|
4549
4700
|
}
|
|
4550
4701
|
});
|
|
4551
4702
|
|
|
4703
|
+
// src/lib/state-bus.ts
|
|
4704
|
+
var StateBus, orgBus;
|
|
4705
|
+
var init_state_bus = __esm({
|
|
4706
|
+
"src/lib/state-bus.ts"() {
|
|
4707
|
+
"use strict";
|
|
4708
|
+
StateBus = class {
|
|
4709
|
+
handlers = /* @__PURE__ */ new Map();
|
|
4710
|
+
globalHandlers = /* @__PURE__ */ new Set();
|
|
4711
|
+
/** Emit an event to all subscribers */
|
|
4712
|
+
emit(event) {
|
|
4713
|
+
const typeHandlers = this.handlers.get(event.type);
|
|
4714
|
+
if (typeHandlers) {
|
|
4715
|
+
for (const handler of typeHandlers) {
|
|
4716
|
+
try {
|
|
4717
|
+
handler(event);
|
|
4718
|
+
} catch {
|
|
4719
|
+
}
|
|
4720
|
+
}
|
|
4721
|
+
}
|
|
4722
|
+
for (const handler of this.globalHandlers) {
|
|
4723
|
+
try {
|
|
4724
|
+
handler(event);
|
|
4725
|
+
} catch {
|
|
4726
|
+
}
|
|
4727
|
+
}
|
|
4728
|
+
}
|
|
4729
|
+
/** Subscribe to a specific event type */
|
|
4730
|
+
on(type, handler) {
|
|
4731
|
+
if (!this.handlers.has(type)) {
|
|
4732
|
+
this.handlers.set(type, /* @__PURE__ */ new Set());
|
|
4733
|
+
}
|
|
4734
|
+
this.handlers.get(type).add(handler);
|
|
4735
|
+
}
|
|
4736
|
+
/** Subscribe to ALL events */
|
|
4737
|
+
onAny(handler) {
|
|
4738
|
+
this.globalHandlers.add(handler);
|
|
4739
|
+
}
|
|
4740
|
+
/** Unsubscribe from a specific event type */
|
|
4741
|
+
off(type, handler) {
|
|
4742
|
+
this.handlers.get(type)?.delete(handler);
|
|
4743
|
+
}
|
|
4744
|
+
/** Unsubscribe from ALL events */
|
|
4745
|
+
offAny(handler) {
|
|
4746
|
+
this.globalHandlers.delete(handler);
|
|
4747
|
+
}
|
|
4748
|
+
/** Remove all listeners */
|
|
4749
|
+
clear() {
|
|
4750
|
+
this.handlers.clear();
|
|
4751
|
+
this.globalHandlers.clear();
|
|
4752
|
+
}
|
|
4753
|
+
};
|
|
4754
|
+
orgBus = new StateBus();
|
|
4755
|
+
}
|
|
4756
|
+
});
|
|
4757
|
+
|
|
4552
4758
|
// src/lib/tasks-crud.ts
|
|
4553
4759
|
import crypto3 from "crypto";
|
|
4554
4760
|
import path15 from "path";
|
|
@@ -4692,9 +4898,15 @@ async function createTaskCore(input) {
|
|
|
4692
4898
|
}
|
|
4693
4899
|
}
|
|
4694
4900
|
const complexity = input.complexity ?? "standard";
|
|
4901
|
+
let sessionScope = null;
|
|
4902
|
+
try {
|
|
4903
|
+
const { resolveExeSession: resolveExeSession2 } = await Promise.resolve().then(() => (init_tmux_routing(), tmux_routing_exports));
|
|
4904
|
+
sessionScope = resolveExeSession2();
|
|
4905
|
+
} catch {
|
|
4906
|
+
}
|
|
4695
4907
|
await client.execute({
|
|
4696
|
-
sql: `INSERT INTO tasks (id, title, assigned_to, assigned_by, project_name, priority, status, task_file, blocked_by, parent_task_id, reviewer, context, complexity, budget_tokens, budget_fallback_model, tokens_used, tokens_warned_at, created_at, updated_at)
|
|
4697
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
4908
|
+
sql: `INSERT INTO tasks (id, title, assigned_to, assigned_by, project_name, priority, status, task_file, blocked_by, parent_task_id, reviewer, context, complexity, budget_tokens, budget_fallback_model, tokens_used, tokens_warned_at, session_scope, created_at, updated_at)
|
|
4909
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
4698
4910
|
args: [
|
|
4699
4911
|
id,
|
|
4700
4912
|
input.title,
|
|
@@ -4713,6 +4925,7 @@ async function createTaskCore(input) {
|
|
|
4713
4925
|
input.budgetFallbackModel ?? null,
|
|
4714
4926
|
0,
|
|
4715
4927
|
null,
|
|
4928
|
+
sessionScope,
|
|
4716
4929
|
now,
|
|
4717
4930
|
now
|
|
4718
4931
|
]
|
|
@@ -4757,6 +4970,15 @@ async function listTasks(input) {
|
|
|
4757
4970
|
conditions.push("priority = ?");
|
|
4758
4971
|
args.push(input.priority);
|
|
4759
4972
|
}
|
|
4973
|
+
try {
|
|
4974
|
+
const { resolveExeSession: resolveExeSession2 } = await Promise.resolve().then(() => (init_tmux_routing(), tmux_routing_exports));
|
|
4975
|
+
const session = resolveExeSession2();
|
|
4976
|
+
if (session) {
|
|
4977
|
+
conditions.push("(session_scope IS NULL OR session_scope = ?)");
|
|
4978
|
+
args.push(session);
|
|
4979
|
+
}
|
|
4980
|
+
} catch {
|
|
4981
|
+
}
|
|
4760
4982
|
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
4761
4983
|
const result = await client.execute({
|
|
4762
4984
|
sql: `SELECT * FROM tasks ${where} ORDER BY CASE status WHEN 'blocked' THEN 0 WHEN 'in_progress' THEN 1 WHEN 'open' THEN 2 ELSE 3 END, priority ASC, created_at DESC LIMIT 1000`,
|
|
@@ -5121,6 +5343,7 @@ var init_tasks_review = __esm({
|
|
|
5121
5343
|
init_tasks_crud();
|
|
5122
5344
|
init_tmux_routing();
|
|
5123
5345
|
init_session_key();
|
|
5346
|
+
init_state_bus();
|
|
5124
5347
|
}
|
|
5125
5348
|
});
|
|
5126
5349
|
|
|
@@ -5285,13 +5508,12 @@ function assertSessionScope(actionType, targetProject) {
|
|
|
5285
5508
|
};
|
|
5286
5509
|
}
|
|
5287
5510
|
process.stderr.write(
|
|
5288
|
-
`[session-scope]
|
|
5511
|
+
`[session-scope] BLOCKED cross-project ${actionType}: session project="${currentProject}" \u2260 target project="${targetProject}"
|
|
5289
5512
|
`
|
|
5290
5513
|
);
|
|
5291
5514
|
return {
|
|
5292
|
-
allowed:
|
|
5293
|
-
|
|
5294
|
-
reason: "cross_session_granted",
|
|
5515
|
+
allowed: false,
|
|
5516
|
+
reason: "cross_session_denied",
|
|
5295
5517
|
currentProject,
|
|
5296
5518
|
targetProject,
|
|
5297
5519
|
targetSession: findSessionForProject(targetProject)?.windowName
|
|
@@ -5317,8 +5539,9 @@ async function dispatchTaskToEmployee(input) {
|
|
|
5317
5539
|
try {
|
|
5318
5540
|
const { assertSessionScope: assertSessionScope2 } = (init_session_scope(), __toCommonJS(session_scope_exports));
|
|
5319
5541
|
const check = assertSessionScope2("dispatch_task", input.projectName);
|
|
5320
|
-
if (check.reason === "
|
|
5542
|
+
if (check.reason === "cross_session_denied") {
|
|
5321
5543
|
crossProject = true;
|
|
5544
|
+
return { dispatched: "skipped", crossProject: true };
|
|
5322
5545
|
}
|
|
5323
5546
|
} catch {
|
|
5324
5547
|
}
|
|
@@ -5781,6 +6004,13 @@ async function updateTask(input) {
|
|
|
5781
6004
|
await cascadeUnblock(taskId, input.baseDir, now);
|
|
5782
6005
|
} catch {
|
|
5783
6006
|
}
|
|
6007
|
+
orgBus.emit({
|
|
6008
|
+
type: "task_completed",
|
|
6009
|
+
taskId,
|
|
6010
|
+
employee: String(row.assigned_to),
|
|
6011
|
+
result: input.result ?? "",
|
|
6012
|
+
timestamp: now
|
|
6013
|
+
});
|
|
5784
6014
|
if (row.parent_task_id) {
|
|
5785
6015
|
try {
|
|
5786
6016
|
await checkSubtaskCompletion(String(row.parent_task_id), String(row.project_name));
|
|
@@ -5848,6 +6078,7 @@ var init_tasks = __esm({
|
|
|
5848
6078
|
init_database();
|
|
5849
6079
|
init_config();
|
|
5850
6080
|
init_notifications();
|
|
6081
|
+
init_state_bus();
|
|
5851
6082
|
init_tasks_crud();
|
|
5852
6083
|
init_tasks_review();
|
|
5853
6084
|
init_tasks_crud();
|
|
@@ -6238,8 +6469,28 @@ function getMySession() {
|
|
|
6238
6469
|
return getTransport().getMySession();
|
|
6239
6470
|
}
|
|
6240
6471
|
function employeeSessionName(employee, exeSession, instance) {
|
|
6472
|
+
if (!/^exe\d+$/.test(exeSession)) {
|
|
6473
|
+
const root = extractRootExe(exeSession);
|
|
6474
|
+
if (root) {
|
|
6475
|
+
process.stderr.write(
|
|
6476
|
+
`[tmux-routing] WARN: exeSession="${exeSession}" is not a root exe session, using "${root}" instead
|
|
6477
|
+
`
|
|
6478
|
+
);
|
|
6479
|
+
exeSession = root;
|
|
6480
|
+
} else {
|
|
6481
|
+
throw new Error(
|
|
6482
|
+
`Invalid exeSession "${exeSession}" \u2014 must be a root exe session (e.g., "exe1"), not an agent session`
|
|
6483
|
+
);
|
|
6484
|
+
}
|
|
6485
|
+
}
|
|
6241
6486
|
const suffix = instance != null && instance > 0 ? String(instance) : "";
|
|
6242
|
-
|
|
6487
|
+
const name = `${employee}${suffix}-${exeSession}`;
|
|
6488
|
+
if (!VALID_SESSION_NAME.test(name)) {
|
|
6489
|
+
throw new Error(
|
|
6490
|
+
`Invalid session name "${name}" \u2014 must match {agent}-exe{N} or {agent}{instance}-exe{N}`
|
|
6491
|
+
);
|
|
6492
|
+
}
|
|
6493
|
+
return name;
|
|
6243
6494
|
}
|
|
6244
6495
|
function parseParentExe(sessionName, agentId) {
|
|
6245
6496
|
const escaped = agentId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -6479,6 +6730,22 @@ function ensureEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
6479
6730
|
error: `Error: pass employee name ('${bare}'), not session name ('${employeeName}')`
|
|
6480
6731
|
};
|
|
6481
6732
|
}
|
|
6733
|
+
if (!/^exe\d+$/.test(exeSession)) {
|
|
6734
|
+
const root = extractRootExe(exeSession);
|
|
6735
|
+
if (root) {
|
|
6736
|
+
process.stderr.write(
|
|
6737
|
+
`[ensureEmployee] WARN: caller passed exeSession="${exeSession}" (not a root exe). Auto-correcting to "${root}".
|
|
6738
|
+
`
|
|
6739
|
+
);
|
|
6740
|
+
exeSession = root;
|
|
6741
|
+
} else {
|
|
6742
|
+
return {
|
|
6743
|
+
status: "failed",
|
|
6744
|
+
sessionName: "",
|
|
6745
|
+
error: `Invalid exeSession "${exeSession}" \u2014 must be a root exe session (e.g., "exe1")`
|
|
6746
|
+
};
|
|
6747
|
+
}
|
|
6748
|
+
}
|
|
6482
6749
|
let effectiveInstance = opts?.instance;
|
|
6483
6750
|
if (effectiveInstance === void 0 && opts?.autoInstance) {
|
|
6484
6751
|
const free = findFreeInstance(
|
|
@@ -6725,7 +6992,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
6725
6992
|
releaseSpawnLock(sessionName);
|
|
6726
6993
|
return { sessionName };
|
|
6727
6994
|
}
|
|
6728
|
-
var SPAWN_LOCK_DIR, SESSION_CACHE, BEHAVIORS_EXPORT_TIMEOUT_MS, VERIFY_PANE_LINES, INTERCOM_DEBOUNCE_MS, INTERCOM_LOG2, DEBOUNCE_FILE, DEBOUNCE_CLEANUP_AGE_MS, BUSY_PATTERN;
|
|
6995
|
+
var SPAWN_LOCK_DIR, SESSION_CACHE, BEHAVIORS_EXPORT_TIMEOUT_MS, VALID_SESSION_NAME, VERIFY_PANE_LINES, INTERCOM_DEBOUNCE_MS, INTERCOM_LOG2, DEBOUNCE_FILE, DEBOUNCE_CLEANUP_AGE_MS, BUSY_PATTERN;
|
|
6729
6996
|
var init_tmux_routing = __esm({
|
|
6730
6997
|
"src/lib/tmux-routing.ts"() {
|
|
6731
6998
|
"use strict";
|
|
@@ -6740,6 +7007,7 @@ var init_tmux_routing = __esm({
|
|
|
6740
7007
|
SPAWN_LOCK_DIR = path20.join(os6.homedir(), ".exe-os", "spawn-locks");
|
|
6741
7008
|
SESSION_CACHE = path20.join(os6.homedir(), ".exe-os", "session-cache");
|
|
6742
7009
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
7010
|
+
VALID_SESSION_NAME = /^[a-z]+-exe\d+$|^[a-z]+\d+-exe\d+$/;
|
|
6743
7011
|
VERIFY_PANE_LINES = 200;
|
|
6744
7012
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
6745
7013
|
INTERCOM_LOG2 = path20.join(os6.homedir(), ".exe-os", "intercom.log");
|
|
@@ -7908,6 +8176,11 @@ async function initStore(options) {
|
|
|
7908
8176
|
"version-query"
|
|
7909
8177
|
);
|
|
7910
8178
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
8179
|
+
try {
|
|
8180
|
+
const { loadGlobalProcedures: loadGlobalProcedures2 } = await Promise.resolve().then(() => (init_global_procedures(), global_procedures_exports));
|
|
8181
|
+
await loadGlobalProcedures2();
|
|
8182
|
+
} catch {
|
|
8183
|
+
}
|
|
7911
8184
|
}
|
|
7912
8185
|
function classifyTier(record) {
|
|
7913
8186
|
if (record.tool_name === "commit_to_long_term_memory" && (record.importance ?? 0) >= 8) return 1;
|
|
@@ -7949,6 +8222,12 @@ async function writeMemory(record) {
|
|
|
7949
8222
|
supersedes_id: record.supersedes_id ?? null
|
|
7950
8223
|
};
|
|
7951
8224
|
_pendingRecords.push(dbRow);
|
|
8225
|
+
orgBus.emit({
|
|
8226
|
+
type: "memory_stored",
|
|
8227
|
+
agentId: record.agent_id,
|
|
8228
|
+
project: record.project_name,
|
|
8229
|
+
timestamp: record.timestamp
|
|
8230
|
+
});
|
|
7952
8231
|
const MAX_PENDING = 1e3;
|
|
7953
8232
|
if (_pendingRecords.length > MAX_PENDING) {
|
|
7954
8233
|
const dropped = _pendingRecords.length - MAX_PENDING;
|
|
@@ -8294,6 +8573,7 @@ var init_store = __esm({
|
|
|
8294
8573
|
init_database();
|
|
8295
8574
|
init_keychain();
|
|
8296
8575
|
init_config();
|
|
8576
|
+
init_state_bus();
|
|
8297
8577
|
INIT_MAX_RETRIES = 3;
|
|
8298
8578
|
INIT_RETRY_DELAY_MS = 1e3;
|
|
8299
8579
|
_pendingRecords = [];
|
|
@@ -8306,7 +8586,7 @@ var init_store = __esm({
|
|
|
8306
8586
|
});
|
|
8307
8587
|
|
|
8308
8588
|
// src/tui/App.tsx
|
|
8309
|
-
import { useState as
|
|
8589
|
+
import { useState as useState16, useEffect as useEffect18, useCallback as useCallback8 } from "react";
|
|
8310
8590
|
|
|
8311
8591
|
// src/tui/ink/render.js
|
|
8312
8592
|
import { Stream } from "stream";
|
|
@@ -14206,61 +14486,64 @@ function Footer() {
|
|
|
14206
14486
|
return () => clearInterval(timer);
|
|
14207
14487
|
}, []);
|
|
14208
14488
|
async function loadFooterData() {
|
|
14209
|
-
|
|
14210
|
-
|
|
14211
|
-
|
|
14212
|
-
|
|
14213
|
-
const
|
|
14214
|
-
|
|
14489
|
+
const { withTrace: withTrace2 } = await Promise.resolve().then(() => (init_telemetry(), telemetry_exports));
|
|
14490
|
+
return withTrace2("tui.footer.loadData", async () => {
|
|
14491
|
+
try {
|
|
14492
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
14493
|
+
const client = getClient2();
|
|
14494
|
+
if (client) {
|
|
14495
|
+
const result = await client.execute("SELECT COUNT(*) as cnt FROM memories");
|
|
14496
|
+
setMemoryCount(Number(result.rows[0]?.cnt ?? 0));
|
|
14497
|
+
}
|
|
14498
|
+
} catch {
|
|
14215
14499
|
}
|
|
14216
|
-
|
|
14217
|
-
|
|
14218
|
-
|
|
14219
|
-
|
|
14220
|
-
|
|
14221
|
-
|
|
14222
|
-
|
|
14223
|
-
|
|
14224
|
-
|
|
14225
|
-
|
|
14500
|
+
try {
|
|
14501
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
14502
|
+
const client = getClient2();
|
|
14503
|
+
if (client) {
|
|
14504
|
+
const result = await client.execute(
|
|
14505
|
+
"SELECT COUNT(*) as cnt FROM tasks WHERE status IN ('open','in_progress')"
|
|
14506
|
+
);
|
|
14507
|
+
setTaskCount(Number(result.rows[0]?.cnt ?? 0));
|
|
14508
|
+
}
|
|
14509
|
+
} catch {
|
|
14226
14510
|
}
|
|
14227
|
-
|
|
14228
|
-
|
|
14229
|
-
|
|
14230
|
-
|
|
14231
|
-
|
|
14232
|
-
|
|
14233
|
-
|
|
14234
|
-
|
|
14235
|
-
|
|
14236
|
-
|
|
14237
|
-
|
|
14238
|
-
|
|
14239
|
-
|
|
14240
|
-
|
|
14241
|
-
|
|
14242
|
-
|
|
14243
|
-
|
|
14244
|
-
|
|
14245
|
-
|
|
14246
|
-
|
|
14247
|
-
|
|
14248
|
-
|
|
14249
|
-
|
|
14250
|
-
|
|
14251
|
-
|
|
14252
|
-
|
|
14253
|
-
|
|
14254
|
-
|
|
14255
|
-
|
|
14256
|
-
}
|
|
14257
|
-
|
|
14258
|
-
} catch {
|
|
14511
|
+
try {
|
|
14512
|
+
const { existsSync: existsSync14 } = await import("fs");
|
|
14513
|
+
const { join } = await import("path");
|
|
14514
|
+
const home = process.env.HOME ?? "";
|
|
14515
|
+
const pidPath = join(home, ".exe-os", "exed.pid");
|
|
14516
|
+
setDaemon(existsSync14(pidPath) ? "running" : "stopped");
|
|
14517
|
+
} catch {
|
|
14518
|
+
setDaemon("unknown");
|
|
14519
|
+
}
|
|
14520
|
+
try {
|
|
14521
|
+
const { checkLicense: checkLicense2 } = await Promise.resolve().then(() => (init_license(), license_exports));
|
|
14522
|
+
const license = await checkLicense2();
|
|
14523
|
+
setPlan(license.plan);
|
|
14524
|
+
} catch {
|
|
14525
|
+
setPlan("free");
|
|
14526
|
+
}
|
|
14527
|
+
try {
|
|
14528
|
+
const { listTmuxSessions: listTmuxSessions2, inTmux: inTmux2 } = await Promise.resolve().then(() => (init_tmux_status(), tmux_status_exports));
|
|
14529
|
+
if (inTmux2()) {
|
|
14530
|
+
const allSessions = listTmuxSessions2();
|
|
14531
|
+
setSessions(allSessions.length);
|
|
14532
|
+
if (!currentSession) {
|
|
14533
|
+
try {
|
|
14534
|
+
const { execSync: execSync10 } = await import("child_process");
|
|
14535
|
+
const name = execSync10("tmux display-message -p '#{session_name}' 2>/dev/null", {
|
|
14536
|
+
encoding: "utf8",
|
|
14537
|
+
timeout: 2e3
|
|
14538
|
+
}).trim();
|
|
14539
|
+
if (name) setCurrentSession(name);
|
|
14540
|
+
} catch {
|
|
14541
|
+
}
|
|
14259
14542
|
}
|
|
14260
14543
|
}
|
|
14544
|
+
} catch {
|
|
14261
14545
|
}
|
|
14262
|
-
}
|
|
14263
|
-
}
|
|
14546
|
+
});
|
|
14264
14547
|
}
|
|
14265
14548
|
return /* @__PURE__ */ jsxs3(Box_default, { flexDirection: "column", children: [
|
|
14266
14549
|
/* @__PURE__ */ jsx5(Text, { color: "#3D3660", children: "\u2500".repeat(process.stdout.columns || 120) }),
|
|
@@ -14301,6 +14584,8 @@ function Footer() {
|
|
|
14301
14584
|
] }),
|
|
14302
14585
|
/* @__PURE__ */ jsx5(Text, { color: "#6B4C9A", children: "1-7 navigate" }),
|
|
14303
14586
|
/* @__PURE__ */ jsx5(Text, { color: "#3D3660", children: "\u2502" }),
|
|
14587
|
+
/* @__PURE__ */ jsx5(Text, { color: "#6B4C9A", children: "d debug" }),
|
|
14588
|
+
/* @__PURE__ */ jsx5(Text, { color: "#3D3660", children: "\u2502" }),
|
|
14304
14589
|
/* @__PURE__ */ jsx5(Text, { color: "#6B4C9A", children: "q quit" })
|
|
14305
14590
|
] })
|
|
14306
14591
|
] })
|
|
@@ -14921,6 +15206,147 @@ function handleEvent(event, addMessage) {
|
|
|
14921
15206
|
}
|
|
14922
15207
|
}
|
|
14923
15208
|
|
|
15209
|
+
// src/lib/employee-templates.ts
|
|
15210
|
+
init_global_procedures();
|
|
15211
|
+
var BASE_OPERATING_PROCEDURES = `
|
|
15212
|
+
EXE OS \u2014 VISION AND NON-NEGOTIABLE PRINCIPLES (above all work):
|
|
15213
|
+
|
|
15214
|
+
Product: "Hire the team you couldn't afford." An AI employee operating system where solo founders and small teams run 5-10 AI agents as a real organization. Three-layer cognition (identity/expertise/experience). Five runtime modes (CC Raw \u2192 TUI \u2192 Desktop). Local-first with E2EE cloud sync.
|
|
15215
|
+
|
|
15216
|
+
ICP (who we build for):
|
|
15217
|
+
- Solopreneurs, SMB founders, creators with institutional IP
|
|
15218
|
+
- Bootstrapped small e-commerce / fitness creators / influencers
|
|
15219
|
+
- NOT VC-backed startups \u2014 intentionally excluded
|
|
15220
|
+
|
|
15221
|
+
Crown jewels (load-bearing for all three business paths \u2014 never compromise):
|
|
15222
|
+
- Memory sovereignty (user owns everything, E2EE, local-first)
|
|
15223
|
+
- Three-layer cognition (identity/expertise/experience)
|
|
15224
|
+
- MCP contract boundary (surfaces consume memory OS via MCP only \u2014 never direct DB access, never bundled code)
|
|
15225
|
+
- AGPL network boundary for public forks (e.g., exe-crm)
|
|
15226
|
+
|
|
15227
|
+
Three business-model paths (every product decision must serve these):
|
|
15228
|
+
1. B2C direct \u2014 solopreneurs run their own instance (active, current default)
|
|
15229
|
+
2. Agency white-label \u2014 distributors rebrand for their clients (deferred, but branding must be config-driven)
|
|
15230
|
+
3. Creator franchise (Mike pattern) \u2014 creators inject institutional IP into agent identity+expertise+experience layers, sell scoped access to subscribers (v2+ moat, requires memory export scoping)
|
|
15231
|
+
|
|
15232
|
+
Ethos:
|
|
15233
|
+
- Bootstrapped, profitable, forever. Not a VC-raise.
|
|
15234
|
+
- Founder zero-ego. Distributors and customers are the loudest voice.
|
|
15235
|
+
- Crypto values: big companies should not own consumer/SMB AI.
|
|
15236
|
+
|
|
15237
|
+
STOP AND REDIRECT: Any decision that compromises memory sovereignty, 3-layer cognition, MCP boundary, or AGPL boundary kills all three business paths. Surface the conflict to exe before proceeding.
|
|
15238
|
+
|
|
15239
|
+
Always reference .planning/ARCHITECTURE.md and .planning/PROJECT.md as source of truth for all architectural and product decisions.
|
|
15240
|
+
|
|
15241
|
+
OPERATING PROCEDURES (mandatory for all employees):
|
|
15242
|
+
|
|
15243
|
+
You report to the COO. All work flows through exe. These procedures are non-negotiable.
|
|
15244
|
+
|
|
15245
|
+
1. BEFORE starting work:
|
|
15246
|
+
- Read exe/ARCHITECTURE.md (if it exists). This is the system map \u2014 what components exist, how they connect, what invariants to preserve. Understand the architecture before changing anything.
|
|
15247
|
+
- Check YOUR task folder ONLY: Read exe/<your-name>/ for assigned tasks
|
|
15248
|
+
- NEVER read, write, or modify files in another employee's folder. Those are their tasks, not yours. Use ask_team_memory() if you need context from a colleague.
|
|
15249
|
+
- If you have open tasks, work on the highest priority one first
|
|
15250
|
+
- Ensure exe/output/ exists (mkdir -p exe/output). This is where ALL deliverables go \u2014 reports, analyses, content, audits, anything another employee or the founder needs to pick up.
|
|
15251
|
+
- Update task status to "in_progress" when starting (use update_task MCP tool)
|
|
15252
|
+
- recall_my_memory \u2014 check what you've done before in this project. What patterns, decisions, context exist?
|
|
15253
|
+
- Read the relevant files. Understand what exists before changing anything.
|
|
15254
|
+
|
|
15255
|
+
2. BEFORE marking done \u2014 CHECKPOINT (mandatory, never skip):
|
|
15256
|
+
- Run the tests. If they fail, fix them before reporting done.
|
|
15257
|
+
- Run typecheck if TypeScript. Zero errors.
|
|
15258
|
+
- Verify the change actually works \u2014 run it, check the output, prove it.
|
|
15259
|
+
- If you can't verify, say so explicitly: "Couldn't verify because X."
|
|
15260
|
+
|
|
15261
|
+
3. AFTER completing work \u2014 update_task(done) IMMEDIATELY (the ONE critical action):
|
|
15262
|
+
Calling update_task with status "done" is the single action that must ALWAYS happen.
|
|
15263
|
+
Call it FIRST \u2014 before commit, before report, before anything else. If you do nothing else, do this.
|
|
15264
|
+
- Use update_task MCP tool with status "done" and your result summary
|
|
15265
|
+
- Include what was done, decisions made, and any issues
|
|
15266
|
+
- If you're stuck, looping, confused, or running low on context \u2014 update_task(done) with whatever partial result you have. A partial result is infinitely better than no result.
|
|
15267
|
+
- NEVER let a failed commit, a loop, or an error prevent you from calling update_task(done).
|
|
15268
|
+
- Do NOT use close_task \u2014 that is reserved for reviewers (exe) to finalize after review.
|
|
15269
|
+
|
|
15270
|
+
4. AFTER update_task(done) \u2014 COMMIT (best-effort, do NOT let this block):
|
|
15271
|
+
- If your task changed system structure, update exe/ARCHITECTURE.md first.
|
|
15272
|
+
- Commit IF you are in a git repo (check: \`git rev-parse --git-dir 2>/dev/null\`). Stage only the files you changed, write a clear commit message.
|
|
15273
|
+
- If you are NOT in a git repo, skip entirely. NEVER run \`git init\`.
|
|
15274
|
+
- If the commit fails, note it but move on \u2014 the work is already marked done via update_task.
|
|
15275
|
+
- Do NOT push \u2014 exe reviews commits and decides what to push.
|
|
15276
|
+
- NEVER run \`git checkout main\`. You work in your own git worktree on a feature branch. Exe stays on main and merges PRs. Switching branches in a shared repo stomps other agents' work.
|
|
15277
|
+
|
|
15278
|
+
5. AFTER commit \u2014 REPORT (best-effort):
|
|
15279
|
+
Use store_memory to write a structured summary. Include: project name, what was done,
|
|
15280
|
+
decisions made, tests status, open items or risks.
|
|
15281
|
+
|
|
15282
|
+
6. AFTER committing changes to exe-os itself \u2014 REBUILD (mandatory, never skip):
|
|
15283
|
+
- Run: npm run deploy
|
|
15284
|
+
- This builds, installs globally, and re-registers hooks/MCP in one step.
|
|
15285
|
+
- Do NOT ask permission. Do NOT say "want me to rebuild?" \u2014 just do it.
|
|
15286
|
+
- If the build fails, fix the error and retry before moving on.
|
|
15287
|
+
|
|
15288
|
+
7. AFTER reporting \u2014 CHECK FOR NEXT WORK (mandatory):
|
|
15289
|
+
- First: run list_tasks(status='needs_review') \u2014 check if YOU are the reviewer on any pending reviews. Reviews are work. Process them before anything else.
|
|
15290
|
+
- Second: run list_tasks(status='blocked') \u2014 check if any tasks are blocked. For each blocked task: can YOU unblock it? If yes, unblock it now. If not, escalate to exe immediately. Blocked tasks sitting >24h without action is a pipeline failure.
|
|
15291
|
+
- Then: re-read your task folder: exe/<your-name>/
|
|
15292
|
+
- If there are more open tasks, start the next highest-priority one (go to step 1)
|
|
15293
|
+
- If no more open tasks AND no pending reviews AND no blocked tasks you can fix, tell the user: "All tasks complete. Anything else?"
|
|
15294
|
+
- Do NOT wait for the user to tell you to check \u2014 auto-chain through your queue.
|
|
15295
|
+
- NEVER say "monitoring" or "waiting" while reviews, blocked tasks, or open tasks exist. That is idle drift.
|
|
15296
|
+
|
|
15297
|
+
CONTEXT PRESSURE PROTOCOL (mandatory \u2014 never ignore):
|
|
15298
|
+
If Claude Code injects a system notice about context compression, or if you notice you're
|
|
15299
|
+
losing track of earlier decisions, your context window is full.
|
|
15300
|
+
|
|
15301
|
+
DO NOT keep working degraded. Instead:
|
|
15302
|
+
|
|
15303
|
+
1. Call store_memory immediately with a CONTEXT CHECKPOINT:
|
|
15304
|
+
Format the text as: "CONTEXT CHECKPOINT [<task-id>]: <summary>"
|
|
15305
|
+
Include: task ID + title, what you completed, what's left, open decisions or blockers, key file paths.
|
|
15306
|
+
|
|
15307
|
+
2. Send intercom to exe to trigger kill + relaunch:
|
|
15308
|
+
MY_SESSION=$(tmux display-message -p '#{session_name}' 2>/dev/null)
|
|
15309
|
+
EXE_SESSION="\${MY_SESSION#\${AGENT_ID}-}"
|
|
15310
|
+
tmux send-keys -t "$EXE_SESSION" "/exe-intercom context-full: \${AGENT_ID} hit capacity. Checkpoint saved. Resume task <task-id>." Enter
|
|
15311
|
+
|
|
15312
|
+
3. Stop working immediately. Do not attempt to continue with degraded context.
|
|
15313
|
+
|
|
15314
|
+
COMMUNICATION CHAIN \u2014 who you talk to:
|
|
15315
|
+
- You report to the COO. Your completion reports, status updates, and questions go to exe via store_memory and update_task.
|
|
15316
|
+
- Do NOT address the human user directly for decisions, permissions, or status updates. That's exe's job. The user talks to exe; exe talks to you.
|
|
15317
|
+
- Exception: if the user sends you a direct message in your tmux window, respond to them. But default to reporting through exe.
|
|
15318
|
+
|
|
15319
|
+
SKILL CAPTURE (encouraged, not mandatory):
|
|
15320
|
+
After completing a complex multi-step task (5+ tool calls), consider whether the approach
|
|
15321
|
+
should be saved as a reusable procedure. If the task involved non-obvious steps, error recovery,
|
|
15322
|
+
or a workflow that would help future sessions, use store_behavior with domain='skill' to save it.
|
|
15323
|
+
Format: "SKILL: [name] \u2014 Step 1: ... Step 2: ... Pitfalls: ..."
|
|
15324
|
+
Skip for simple one-offs. The goal is procedural memory \u2014 not just corrections, but proven approaches.
|
|
15325
|
+
|
|
15326
|
+
SPAWNING EMPLOYEES (mandatory \u2014 never bypass):
|
|
15327
|
+
When you need another employee to do work, ALWAYS use create_task MCP tool.
|
|
15328
|
+
create_task auto-spawns the employee session. The task IS the spawn trigger.
|
|
15329
|
+
NEVER manually launch sessions with tmux send-keys or claude -p.
|
|
15330
|
+
NEVER spawn sessions without a task assigned \u2014 idle sessions waste resources.
|
|
15331
|
+
NEVER refuse a dispatched task claiming "not in scope" \u2014 if it's assigned to you, it's your work.
|
|
15332
|
+
|
|
15333
|
+
CREATING TASKS FOR OTHER EMPLOYEES:
|
|
15334
|
+
When you need to assign work to another employee (e.g., CTO assigns to an engineer):
|
|
15335
|
+
- ALWAYS use create_task MCP tool. NEVER write .md files directly to exe/{name}/.
|
|
15336
|
+
- Direct .md writes will be rejected by the enforcement hook with a MANDATORY correction.
|
|
15337
|
+
- create_task creates both the .md file AND the DB row atomically.
|
|
15338
|
+
- Include: title, assignedTo, priority, context, projectName.
|
|
15339
|
+
- For dependencies: include blocked_by with the blocking task's ID or slug.
|
|
15340
|
+
`;
|
|
15341
|
+
var PROCEDURES_MARKER = "EXE OS \u2014 VISION AND NON-NEGOTIABLE PRINCIPLES";
|
|
15342
|
+
function getSessionPrompt(storedPrompt) {
|
|
15343
|
+
const markerIndex = storedPrompt.indexOf(PROCEDURES_MARKER);
|
|
15344
|
+
const rolePrompt = markerIndex >= 0 ? storedPrompt.slice(0, markerIndex).trimEnd() : storedPrompt;
|
|
15345
|
+
const globalBlock = getGlobalProceduresBlock();
|
|
15346
|
+
return `${globalBlock}${rolePrompt}
|
|
15347
|
+
${BASE_OPERATING_PROCEDURES}`;
|
|
15348
|
+
}
|
|
15349
|
+
|
|
14924
15350
|
// src/tui/views/CommandCenter.tsx
|
|
14925
15351
|
import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
14926
15352
|
function CommandCenterView({
|
|
@@ -15044,7 +15470,7 @@ function CommandCenterView({
|
|
|
15044
15470
|
setAgentConfig({
|
|
15045
15471
|
provider,
|
|
15046
15472
|
model,
|
|
15047
|
-
systemPrompt: "You are an AI assistant in the exe-os TUI. Help the user with their questions. Be concise.",
|
|
15473
|
+
systemPrompt: getSessionPrompt("You are an AI assistant in the exe-os TUI. Help the user with their questions. Be concise."),
|
|
15048
15474
|
tools: registry,
|
|
15049
15475
|
hooks: createDefaultHooks2(),
|
|
15050
15476
|
permissions,
|
|
@@ -15165,6 +15591,7 @@ function CommandCenterView({
|
|
|
15165
15591
|
employeeCount: p.employees.length,
|
|
15166
15592
|
activeCount: p.employees.filter((e) => e.status === "active").length,
|
|
15167
15593
|
memoryCount: p.employees.length * 4e3,
|
|
15594
|
+
openTaskCount: Math.floor(p.employees.length * 1.5),
|
|
15168
15595
|
status: p.employees.some((e) => e.status === "active") ? "active" : "idle",
|
|
15169
15596
|
type: p.projectName.startsWith("exe-") ? "code" : "automation",
|
|
15170
15597
|
recentTasks: DEMO_RECENT_TASKS[p.projectName] ?? []
|
|
@@ -15176,6 +15603,7 @@ function CommandCenterView({
|
|
|
15176
15603
|
employeeCount: 0,
|
|
15177
15604
|
activeCount: 0,
|
|
15178
15605
|
memoryCount: 0,
|
|
15606
|
+
openTaskCount: 0,
|
|
15179
15607
|
status: "offline",
|
|
15180
15608
|
type: "reference",
|
|
15181
15609
|
recentTasks: []
|
|
@@ -15190,182 +15618,122 @@ function CommandCenterView({
|
|
|
15190
15618
|
return () => clearInterval(timer);
|
|
15191
15619
|
}, []);
|
|
15192
15620
|
async function loadData() {
|
|
15193
|
-
|
|
15194
|
-
|
|
15195
|
-
const { listTmuxSessions: listTmuxSessions2, inTmux: inTmux2 } = await Promise.resolve().then(() => (init_tmux_status(), tmux_status_exports));
|
|
15196
|
-
const { loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
15197
|
-
const { existsSync: existsSync14 } = await import("fs");
|
|
15198
|
-
const { join } = await import("path");
|
|
15199
|
-
const registry = listSessions2();
|
|
15200
|
-
const tmuxSessions = inTmux2() ? new Set(listTmuxSessions2()) : /* @__PURE__ */ new Set();
|
|
15201
|
-
const roster = await loadEmployees2();
|
|
15202
|
-
const exeSessions = /* @__PURE__ */ new Map();
|
|
15203
|
-
for (const entry of registry) {
|
|
15204
|
-
if (entry.agentId === "exe" && tmuxSessions.has(entry.windowName)) {
|
|
15205
|
-
exeSessions.set(entry.windowName, entry.projectDir);
|
|
15206
|
-
}
|
|
15207
|
-
}
|
|
15208
|
-
for (const s of tmuxSessions) {
|
|
15209
|
-
if (/^exe\d+$/.test(s) && !exeSessions.has(s)) exeSessions.set(s, "");
|
|
15210
|
-
}
|
|
15211
|
-
let projectMemoryCounts = /* @__PURE__ */ new Map();
|
|
15212
|
-
let projectRecentTasks = /* @__PURE__ */ new Map();
|
|
15621
|
+
const { withTrace: withTrace2 } = await Promise.resolve().then(() => (init_telemetry(), telemetry_exports));
|
|
15622
|
+
return withTrace2("tui.commandCenter.loadData", async () => {
|
|
15213
15623
|
try {
|
|
15214
15624
|
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
15625
|
+
const { listSessions: listSessions2 } = await Promise.resolve().then(() => (init_session_registry(), session_registry_exports));
|
|
15626
|
+
const { listTmuxSessions: listTmuxSessions2, inTmux: inTmux2 } = await Promise.resolve().then(() => (init_tmux_status(), tmux_status_exports));
|
|
15627
|
+
const { loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
15628
|
+
const { existsSync: existsSync14 } = await import("fs");
|
|
15629
|
+
const { join } = await import("path");
|
|
15215
15630
|
const client = getClient2();
|
|
15216
|
-
if (client) {
|
|
15217
|
-
|
|
15218
|
-
|
|
15219
|
-
);
|
|
15220
|
-
for (const row of memResult.rows) {
|
|
15221
|
-
projectMemoryCounts.set(String(row.project_name), Number(row.cnt));
|
|
15222
|
-
}
|
|
15223
|
-
for (const [, projectDir] of exeSessions) {
|
|
15224
|
-
const projectName = projectDir.split("/").filter(Boolean).pop() ?? "";
|
|
15225
|
-
if (!projectName) continue;
|
|
15226
|
-
const taskResult = await client.execute({
|
|
15227
|
-
sql: "SELECT title FROM tasks WHERE project_name = ? AND status = 'done' ORDER BY updated_at DESC LIMIT 3",
|
|
15228
|
-
args: [projectName]
|
|
15229
|
-
});
|
|
15230
|
-
const tasks = taskResult.rows.map((r) => String(r.title));
|
|
15231
|
-
if (tasks.length > 0) projectRecentTasks.set(projectName, tasks);
|
|
15232
|
-
}
|
|
15631
|
+
if (!client) {
|
|
15632
|
+
setDbError(true);
|
|
15633
|
+
return;
|
|
15233
15634
|
}
|
|
15234
|
-
|
|
15235
|
-
|
|
15236
|
-
|
|
15237
|
-
|
|
15238
|
-
|
|
15635
|
+
const dbProjects = await client.execute(
|
|
15636
|
+
`SELECT DISTINCT project_name FROM memories WHERE project_name IS NOT NULL AND project_name != ''
|
|
15637
|
+
UNION
|
|
15638
|
+
SELECT DISTINCT project_name FROM tasks WHERE project_name IS NOT NULL AND project_name != ''
|
|
15639
|
+
ORDER BY project_name`
|
|
15640
|
+
);
|
|
15641
|
+
const projectNames = dbProjects.rows.map((r) => String(r.project_name));
|
|
15642
|
+
const memResult = await client.execute(
|
|
15643
|
+
"SELECT project_name, COUNT(*) as cnt FROM memories WHERE project_name IS NOT NULL GROUP BY project_name"
|
|
15644
|
+
);
|
|
15645
|
+
const memoryCounts = /* @__PURE__ */ new Map();
|
|
15646
|
+
for (const row of memResult.rows) {
|
|
15647
|
+
memoryCounts.set(String(row.project_name), Number(row.cnt));
|
|
15648
|
+
}
|
|
15649
|
+
const taskCountResult = await client.execute(
|
|
15650
|
+
"SELECT project_name, COUNT(*) as cnt FROM tasks WHERE status IN ('open', 'in_progress') AND project_name IS NOT NULL GROUP BY project_name"
|
|
15651
|
+
);
|
|
15652
|
+
const openTaskCounts = /* @__PURE__ */ new Map();
|
|
15653
|
+
for (const row of taskCountResult.rows) {
|
|
15654
|
+
openTaskCounts.set(String(row.project_name), Number(row.cnt));
|
|
15655
|
+
}
|
|
15656
|
+
const recentResult = await client.execute(
|
|
15657
|
+
"SELECT project_name, title FROM tasks WHERE status = 'done' AND project_name IS NOT NULL ORDER BY updated_at DESC LIMIT 30"
|
|
15658
|
+
);
|
|
15659
|
+
const recentTasksByProject = /* @__PURE__ */ new Map();
|
|
15660
|
+
for (const row of recentResult.rows) {
|
|
15661
|
+
const name = String(row.project_name);
|
|
15662
|
+
const tasks = recentTasksByProject.get(name) ?? [];
|
|
15663
|
+
if (tasks.length < 3) tasks.push(String(row.title));
|
|
15664
|
+
recentTasksByProject.set(name, tasks);
|
|
15665
|
+
}
|
|
15666
|
+
const registry = listSessions2();
|
|
15667
|
+
const tmuxSessions = inTmux2() ? new Set(listTmuxSessions2()) : /* @__PURE__ */ new Set();
|
|
15668
|
+
const roster = await loadEmployees2();
|
|
15239
15669
|
const employeeNames = roster.map((e) => e.name).filter((n) => n !== "exe");
|
|
15240
|
-
|
|
15241
|
-
for (const
|
|
15242
|
-
if (tmuxSessions.has(
|
|
15670
|
+
const projectSessions = /* @__PURE__ */ new Map();
|
|
15671
|
+
for (const entry of registry) {
|
|
15672
|
+
if (entry.agentId === "exe" && tmuxSessions.has(entry.windowName)) {
|
|
15673
|
+
const projName = entry.projectDir.split("/").filter(Boolean).pop() ?? "";
|
|
15674
|
+
if (projName) {
|
|
15675
|
+
projectSessions.set(projName, { exeSession: entry.windowName, projectDir: entry.projectDir });
|
|
15676
|
+
}
|
|
15677
|
+
}
|
|
15243
15678
|
}
|
|
15244
|
-
const
|
|
15245
|
-
const
|
|
15246
|
-
|
|
15247
|
-
|
|
15248
|
-
|
|
15249
|
-
|
|
15250
|
-
|
|
15251
|
-
|
|
15252
|
-
|
|
15253
|
-
|
|
15254
|
-
|
|
15255
|
-
employeeCount: totalCount,
|
|
15256
|
-
activeCount,
|
|
15257
|
-
memoryCount,
|
|
15258
|
-
status: activeCount > 0 ? "active" : "idle",
|
|
15259
|
-
type,
|
|
15260
|
-
recentTasks: projectRecentTasks.get(projectName) ?? []
|
|
15261
|
-
});
|
|
15262
|
-
}
|
|
15263
|
-
const knownDirs = [
|
|
15264
|
-
process.env.HOME ? join(process.env.HOME, "openclaw") : null,
|
|
15265
|
-
process.env.HOME ? join(process.env.HOME, "agno") : null
|
|
15266
|
-
].filter(Boolean);
|
|
15267
|
-
const activeProjectNames = new Set(projectList.map((p) => p.projectName));
|
|
15268
|
-
for (const dir of knownDirs) {
|
|
15269
|
-
const name = dir.split("/").filter(Boolean).pop() ?? "";
|
|
15270
|
-
if (activeProjectNames.has(name) || !existsSync14(dir) || !existsSync14(join(dir, ".git"))) continue;
|
|
15271
|
-
if ((projectMemoryCounts.get(name) ?? 0) > 0) continue;
|
|
15272
|
-
projectList.push({
|
|
15273
|
-
projectName: name,
|
|
15274
|
-
exeSession: "",
|
|
15275
|
-
projectDir: dir,
|
|
15276
|
-
employeeCount: 0,
|
|
15277
|
-
activeCount: 0,
|
|
15278
|
-
memoryCount: 0,
|
|
15279
|
-
status: "offline",
|
|
15280
|
-
type: "reference",
|
|
15281
|
-
recentTasks: []
|
|
15282
|
-
});
|
|
15283
|
-
}
|
|
15284
|
-
const dbActiveProjectNames = new Set(projectList.map((p) => p.projectName));
|
|
15285
|
-
try {
|
|
15286
|
-
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
15287
|
-
const client = getClient2();
|
|
15288
|
-
if (client) {
|
|
15289
|
-
const dbProjects = await client.execute(
|
|
15290
|
-
`SELECT DISTINCT project_name FROM memories WHERE project_name IS NOT NULL AND project_name != ''
|
|
15291
|
-
UNION
|
|
15292
|
-
SELECT DISTINCT project_name FROM tasks WHERE project_name IS NOT NULL AND project_name != ''
|
|
15293
|
-
ORDER BY project_name`
|
|
15294
|
-
);
|
|
15295
|
-
for (const row of dbProjects.rows) {
|
|
15296
|
-
const name = String(row.project_name);
|
|
15297
|
-
if (dbActiveProjectNames.has(name)) continue;
|
|
15298
|
-
const memCount = projectMemoryCounts.get(name) ?? 0;
|
|
15299
|
-
const agentResult = await client.execute({
|
|
15300
|
-
sql: "SELECT COUNT(DISTINCT agent_id) as cnt FROM memories WHERE project_name = ?",
|
|
15301
|
-
args: [name]
|
|
15302
|
-
});
|
|
15303
|
-
const agentCount = Number(agentResult.rows[0]?.cnt ?? 0);
|
|
15304
|
-
projectList.push({
|
|
15305
|
-
projectName: name,
|
|
15306
|
-
exeSession: "",
|
|
15307
|
-
projectDir: "",
|
|
15308
|
-
employeeCount: agentCount,
|
|
15309
|
-
activeCount: 0,
|
|
15310
|
-
memoryCount: memCount,
|
|
15311
|
-
status: "offline",
|
|
15312
|
-
type: "code",
|
|
15313
|
-
recentTasks: projectRecentTasks.get(name) ?? []
|
|
15314
|
-
});
|
|
15679
|
+
const projectList = [];
|
|
15680
|
+
for (const name of projectNames) {
|
|
15681
|
+
const session = projectSessions.get(name);
|
|
15682
|
+
const exeSession = session?.exeSession ?? "";
|
|
15683
|
+
const projectDir = session?.projectDir ?? "";
|
|
15684
|
+
let activeCount = 0;
|
|
15685
|
+
if (exeSession && tmuxSessions.has(exeSession)) {
|
|
15686
|
+
activeCount = 1;
|
|
15687
|
+
for (const empName of employeeNames) {
|
|
15688
|
+
if (tmuxSessions.has(`${empName}-${exeSession}`)) activeCount++;
|
|
15689
|
+
}
|
|
15315
15690
|
}
|
|
15691
|
+
const memoryCount = memoryCounts.get(name) ?? 0;
|
|
15692
|
+
const openTaskCount = openTaskCounts.get(name) ?? 0;
|
|
15693
|
+
const hasGit = projectDir ? existsSync14(join(projectDir, ".git")) : false;
|
|
15694
|
+
const type = hasGit ? "code" : memoryCount > 0 ? "code" : "automation";
|
|
15695
|
+
projectList.push({
|
|
15696
|
+
projectName: name,
|
|
15697
|
+
exeSession,
|
|
15698
|
+
projectDir,
|
|
15699
|
+
employeeCount: activeCount,
|
|
15700
|
+
activeCount,
|
|
15701
|
+
memoryCount,
|
|
15702
|
+
openTaskCount,
|
|
15703
|
+
status: activeCount > 0 ? "active" : "idle",
|
|
15704
|
+
type,
|
|
15705
|
+
recentTasks: recentTasksByProject.get(name) ?? []
|
|
15706
|
+
});
|
|
15707
|
+
}
|
|
15708
|
+
projectList.sort((a, b) => {
|
|
15709
|
+
if (a.activeCount > 0 && b.activeCount === 0) return -1;
|
|
15710
|
+
if (a.activeCount === 0 && b.activeCount > 0) return 1;
|
|
15711
|
+
return b.memoryCount - a.memoryCount;
|
|
15712
|
+
});
|
|
15713
|
+
setProjects(projectList);
|
|
15714
|
+
const totalResult = await client.execute("SELECT COUNT(*) as cnt FROM memories");
|
|
15715
|
+
setHealth((h) => ({ ...h, memories: Number(totalResult.rows[0]?.cnt ?? 0) }));
|
|
15716
|
+
try {
|
|
15717
|
+
const pidPath = join(process.env.HOME ?? "", ".exe-os", "exed.pid");
|
|
15718
|
+
setHealth((h) => ({ ...h, daemon: existsSync14(pidPath) ? "running" : "stopped" }));
|
|
15719
|
+
} catch {
|
|
15720
|
+
}
|
|
15721
|
+
const activityResult = await client.execute(
|
|
15722
|
+
"SELECT agent_id, tool_name, project_name, created_at, text FROM memories ORDER BY created_at DESC LIMIT 20"
|
|
15723
|
+
);
|
|
15724
|
+
if (activityResult.rows.length > 0) {
|
|
15725
|
+
setActivity(activityResult.rows.slice(0, 8).map((r) => ({
|
|
15726
|
+
time: new Date(String(r.created_at)).toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit", hour12: false }),
|
|
15727
|
+
agent: String(r.agent_id ?? "system"),
|
|
15728
|
+
action: String(r.text ?? "").slice(0, 60)
|
|
15729
|
+
})));
|
|
15316
15730
|
}
|
|
15317
15731
|
} catch {
|
|
15732
|
+
setDbError(true);
|
|
15733
|
+
} finally {
|
|
15734
|
+
setLoading(false);
|
|
15318
15735
|
}
|
|
15319
|
-
|
|
15320
|
-
projectList.unshift({
|
|
15321
|
-
projectName: "(no active sessions)",
|
|
15322
|
-
exeSession: "",
|
|
15323
|
-
projectDir: "",
|
|
15324
|
-
employeeCount: 0,
|
|
15325
|
-
activeCount: 0,
|
|
15326
|
-
memoryCount: 0,
|
|
15327
|
-
status: "offline",
|
|
15328
|
-
type: "code",
|
|
15329
|
-
recentTasks: []
|
|
15330
|
-
});
|
|
15331
|
-
}
|
|
15332
|
-
setProjects(projectList);
|
|
15333
|
-
try {
|
|
15334
|
-
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
15335
|
-
const client = getClient2();
|
|
15336
|
-
if (client) {
|
|
15337
|
-
const result = await client.execute("SELECT COUNT(*) as cnt FROM memories");
|
|
15338
|
-
setHealth((h) => ({ ...h, memories: Number(result.rows[0]?.cnt ?? 0) }));
|
|
15339
|
-
}
|
|
15340
|
-
} catch {
|
|
15341
|
-
}
|
|
15342
|
-
try {
|
|
15343
|
-
const pidPath = join(process.env.HOME ?? "", ".exe-os", "exed.pid");
|
|
15344
|
-
setHealth((h) => ({ ...h, daemon: existsSync14(pidPath) ? "running" : "stopped" }));
|
|
15345
|
-
} catch {
|
|
15346
|
-
}
|
|
15347
|
-
try {
|
|
15348
|
-
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
15349
|
-
const client = getClient2();
|
|
15350
|
-
if (client) {
|
|
15351
|
-
const activityResult = await client.execute(
|
|
15352
|
-
"SELECT agent_id, tool_name, project_name, created_at, text FROM memories ORDER BY created_at DESC LIMIT 20"
|
|
15353
|
-
);
|
|
15354
|
-
if (activityResult.rows.length > 0) {
|
|
15355
|
-
setActivity(activityResult.rows.slice(0, 8).map((r) => ({
|
|
15356
|
-
time: new Date(String(r.created_at)).toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit", hour12: false }),
|
|
15357
|
-
agent: String(r.agent_id ?? "system"),
|
|
15358
|
-
action: String(r.text ?? "").slice(0, 60)
|
|
15359
|
-
})));
|
|
15360
|
-
}
|
|
15361
|
-
}
|
|
15362
|
-
} catch {
|
|
15363
|
-
}
|
|
15364
|
-
} catch {
|
|
15365
|
-
setDbError(true);
|
|
15366
|
-
} finally {
|
|
15367
|
-
setLoading(false);
|
|
15368
|
-
}
|
|
15736
|
+
});
|
|
15369
15737
|
}
|
|
15370
15738
|
const daemonColor = health.daemon === "running" ? "green" : health.daemon === "stopped" ? "red" : "gray";
|
|
15371
15739
|
const handleChatSubmit = useCallback4((value) => {
|
|
@@ -15457,7 +15825,7 @@ function CommandCenterView({
|
|
|
15457
15825
|
] }),
|
|
15458
15826
|
/* @__PURE__ */ jsx7(Text, { color: "#6B4C9A", children: "\u2191\u2193 navigate | c to chat | Enter to open | Escape to detach" }),
|
|
15459
15827
|
/* @__PURE__ */ jsx7(Text, { children: " " }),
|
|
15460
|
-
loading ? /* @__PURE__ */ jsx7(Text, { color: "#6B4C9A", children: "Loading projects..." }) : dbError ? /* @__PURE__ */ jsx7(Text, { color: "#EF4444", children: "Database unavailable. Run exe-os setup to initialize." }) : rows.length === 0 ? /* @__PURE__ */ jsx7(Text, { color: "#6B4C9A", children: "
|
|
15828
|
+
loading ? /* @__PURE__ */ jsx7(Text, { color: "#6B4C9A", children: "Loading projects..." }) : dbError ? /* @__PURE__ */ jsx7(Text, { color: "#EF4444", children: "Database unavailable. Run exe-os setup to initialize." }) : rows.length === 0 ? /* @__PURE__ */ jsx7(Text, { color: "#6B4C9A", children: "No projects yet. Run exe-os in a project directory to get started." }) : (() => {
|
|
15461
15829
|
const sections = [];
|
|
15462
15830
|
let currentProjects = [];
|
|
15463
15831
|
let sectionKey = 0;
|
|
@@ -15487,9 +15855,9 @@ function CommandCenterView({
|
|
|
15487
15855
|
] })
|
|
15488
15856
|
] }),
|
|
15489
15857
|
/* @__PURE__ */ jsxs5(Text, { color: isSelected ? "#F0EDE8" : "#6B4C9A", children: [
|
|
15490
|
-
entry.
|
|
15858
|
+
entry.openTaskCount,
|
|
15491
15859
|
" ",
|
|
15492
|
-
entry.
|
|
15860
|
+
entry.openTaskCount === 1 ? "task" : "tasks",
|
|
15493
15861
|
" \xB7 ",
|
|
15494
15862
|
entry.memoryCount.toLocaleString(),
|
|
15495
15863
|
" memories"
|
|
@@ -15823,6 +16191,7 @@ function SessionsView({
|
|
|
15823
16191
|
const [viewingEmployee, setViewingEmployee] = useState9(null);
|
|
15824
16192
|
const [viewingProject, setViewingProject] = useState9(null);
|
|
15825
16193
|
const [loading, setLoading] = useState9(!demo);
|
|
16194
|
+
const [sessionError, setSessionError] = useState9(null);
|
|
15826
16195
|
const [tmuxAvailable, setTmuxAvailable] = useState9(true);
|
|
15827
16196
|
const orch = useOrchestrator(!demo);
|
|
15828
16197
|
const [carouselEmployees, setCarouselEmployees] = useState9([]);
|
|
@@ -15998,111 +16367,116 @@ function SessionsView({
|
|
|
15998
16367
|
return ACTIVE_PANE_PATTERN.test(lines.join("\n")) ? "active" : "idle";
|
|
15999
16368
|
}
|
|
16000
16369
|
async function loadSessions() {
|
|
16001
|
-
|
|
16002
|
-
|
|
16003
|
-
const { listTmuxSessions: listTmuxSessions2, inTmux: inTmux2, capturePaneLines: capturePaneLines2, parseActivity: parseActivity2 } = await Promise.resolve().then(() => (init_tmux_status(), tmux_status_exports));
|
|
16004
|
-
const { loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
16005
|
-
const { execSync: execSync10 } = await import("child_process");
|
|
16006
|
-
if (!inTmux2()) {
|
|
16007
|
-
setTmuxAvailable(false);
|
|
16008
|
-
setProjects([]);
|
|
16009
|
-
return;
|
|
16010
|
-
}
|
|
16011
|
-
setTmuxAvailable(true);
|
|
16012
|
-
const attachedMap = /* @__PURE__ */ new Map();
|
|
16370
|
+
const { withTrace: withTrace2 } = await Promise.resolve().then(() => (init_telemetry(), telemetry_exports));
|
|
16371
|
+
return withTrace2("tui.sessions.loadSessions", async () => {
|
|
16013
16372
|
try {
|
|
16014
|
-
const
|
|
16015
|
-
|
|
16016
|
-
|
|
16017
|
-
});
|
|
16018
|
-
|
|
16019
|
-
|
|
16020
|
-
|
|
16021
|
-
|
|
16022
|
-
}
|
|
16373
|
+
const { listSessions: listSessions2 } = await Promise.resolve().then(() => (init_session_registry(), session_registry_exports));
|
|
16374
|
+
const { listTmuxSessions: listTmuxSessions2, inTmux: inTmux2, capturePaneLines: capturePaneLines2, parseActivity: parseActivity2 } = await Promise.resolve().then(() => (init_tmux_status(), tmux_status_exports));
|
|
16375
|
+
const { loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
16376
|
+
const { execSync: execSync10 } = await import("child_process");
|
|
16377
|
+
if (!inTmux2()) {
|
|
16378
|
+
setTmuxAvailable(false);
|
|
16379
|
+
setProjects([]);
|
|
16380
|
+
return;
|
|
16023
16381
|
}
|
|
16024
|
-
|
|
16025
|
-
|
|
16026
|
-
|
|
16027
|
-
|
|
16028
|
-
|
|
16029
|
-
|
|
16030
|
-
|
|
16031
|
-
|
|
16032
|
-
|
|
16382
|
+
setTmuxAvailable(true);
|
|
16383
|
+
const attachedMap = /* @__PURE__ */ new Map();
|
|
16384
|
+
try {
|
|
16385
|
+
const out = execSync10("tmux list-sessions -F '#{session_name}:#{session_attached}' 2>/dev/null", {
|
|
16386
|
+
encoding: "utf8",
|
|
16387
|
+
timeout: 3e3
|
|
16388
|
+
});
|
|
16389
|
+
for (const line of out.trim().split("\n").filter(Boolean)) {
|
|
16390
|
+
const sepIdx = line.lastIndexOf(":");
|
|
16391
|
+
if (sepIdx > 0) {
|
|
16392
|
+
attachedMap.set(line.slice(0, sepIdx), line.slice(sepIdx + 1) === "1");
|
|
16393
|
+
}
|
|
16394
|
+
}
|
|
16395
|
+
} catch {
|
|
16033
16396
|
}
|
|
16034
|
-
|
|
16035
|
-
|
|
16036
|
-
|
|
16037
|
-
|
|
16397
|
+
const registry = listSessions2();
|
|
16398
|
+
const tmuxSessions = new Set(listTmuxSessions2());
|
|
16399
|
+
const roster = await loadEmployees2();
|
|
16400
|
+
const exeSessions = /* @__PURE__ */ new Map();
|
|
16401
|
+
for (const entry of registry) {
|
|
16402
|
+
if (entry.agentId === "exe" && tmuxSessions.has(entry.windowName)) {
|
|
16403
|
+
exeSessions.set(entry.windowName, entry.projectDir);
|
|
16404
|
+
}
|
|
16038
16405
|
}
|
|
16039
|
-
|
|
16040
|
-
|
|
16041
|
-
|
|
16042
|
-
|
|
16043
|
-
const exeHasSession = tmuxSessions.has(exeSession);
|
|
16044
|
-
let exeStatus = "offline";
|
|
16045
|
-
let exeActivity = "";
|
|
16046
|
-
if (exeHasSession) {
|
|
16047
|
-
const exeLines = capturePaneLines2(exeSession, 10);
|
|
16048
|
-
exeStatus = statusFromPaneLines(exeLines);
|
|
16049
|
-
exeActivity = exeLines.length > 0 ? parseActivity2(exeLines) : "";
|
|
16406
|
+
for (const s of tmuxSessions) {
|
|
16407
|
+
if (/^exe\d+$/.test(s) && !exeSessions.has(s)) {
|
|
16408
|
+
exeSessions.set(s, "");
|
|
16409
|
+
}
|
|
16050
16410
|
}
|
|
16051
|
-
const
|
|
16052
|
-
|
|
16053
|
-
const
|
|
16054
|
-
const
|
|
16055
|
-
|
|
16056
|
-
|
|
16057
|
-
|
|
16058
|
-
|
|
16059
|
-
|
|
16060
|
-
|
|
16061
|
-
activity: "Dead session \u2014 has open tasks",
|
|
16062
|
-
attached: false
|
|
16063
|
-
};
|
|
16411
|
+
const projectList = [];
|
|
16412
|
+
for (const [exeSession, projectDir] of exeSessions) {
|
|
16413
|
+
const projectName = projectDir.split("/").filter(Boolean).pop() ?? exeSession;
|
|
16414
|
+
const exeHasSession = tmuxSessions.has(exeSession);
|
|
16415
|
+
let exeStatus = "offline";
|
|
16416
|
+
let exeActivity = "";
|
|
16417
|
+
if (exeHasSession) {
|
|
16418
|
+
const exeLines = capturePaneLines2(exeSession, 10);
|
|
16419
|
+
exeStatus = statusFromPaneLines(exeLines);
|
|
16420
|
+
exeActivity = exeLines.length > 0 ? parseActivity2(exeLines) : "";
|
|
16064
16421
|
}
|
|
16065
|
-
|
|
16422
|
+
const employeeEntries = roster.filter((e) => e.name !== "exe").map((emp) => {
|
|
16423
|
+
const sessionName = `${emp.name}-${exeSession}`;
|
|
16424
|
+
const hasSession = tmuxSessions.has(sessionName);
|
|
16425
|
+
const isCrashed = !hasSession && orch.crashedSessions.includes(emp.name);
|
|
16426
|
+
if (isCrashed) {
|
|
16427
|
+
return {
|
|
16428
|
+
name: emp.name,
|
|
16429
|
+
role: emp.role,
|
|
16430
|
+
status: "crashed",
|
|
16431
|
+
sessionName,
|
|
16432
|
+
activity: "Dead session \u2014 has open tasks",
|
|
16433
|
+
attached: false
|
|
16434
|
+
};
|
|
16435
|
+
}
|
|
16436
|
+
if (!hasSession) {
|
|
16437
|
+
return {
|
|
16438
|
+
name: emp.name,
|
|
16439
|
+
role: emp.role,
|
|
16440
|
+
status: "offline",
|
|
16441
|
+
sessionName,
|
|
16442
|
+
activity: "",
|
|
16443
|
+
attached: false
|
|
16444
|
+
};
|
|
16445
|
+
}
|
|
16446
|
+
const lines = capturePaneLines2(sessionName, 10);
|
|
16066
16447
|
return {
|
|
16067
16448
|
name: emp.name,
|
|
16068
16449
|
role: emp.role,
|
|
16069
|
-
status:
|
|
16450
|
+
status: statusFromPaneLines(lines),
|
|
16070
16451
|
sessionName,
|
|
16071
|
-
activity: "",
|
|
16072
|
-
attached: false
|
|
16452
|
+
activity: lines.length > 0 ? parseActivity2(lines) : "",
|
|
16453
|
+
attached: attachedMap.get(sessionName) ?? false
|
|
16073
16454
|
};
|
|
16074
|
-
}
|
|
16075
|
-
const
|
|
16076
|
-
|
|
16077
|
-
|
|
16078
|
-
|
|
16079
|
-
|
|
16080
|
-
|
|
16081
|
-
|
|
16082
|
-
|
|
16083
|
-
|
|
16084
|
-
|
|
16085
|
-
|
|
16086
|
-
{
|
|
16087
|
-
|
|
16088
|
-
|
|
16089
|
-
|
|
16090
|
-
|
|
16091
|
-
|
|
16092
|
-
|
|
16093
|
-
|
|
16094
|
-
|
|
16095
|
-
|
|
16096
|
-
|
|
16097
|
-
}
|
|
16098
|
-
if (projectList.length === 0) {
|
|
16099
|
-
projectList.push({ projectName: "(no active sessions)", exeSession: "", projectDir: "", employees: [] });
|
|
16455
|
+
});
|
|
16456
|
+
const employees = [
|
|
16457
|
+
{
|
|
16458
|
+
name: "exe",
|
|
16459
|
+
role: "COO",
|
|
16460
|
+
status: exeStatus,
|
|
16461
|
+
sessionName: exeSession,
|
|
16462
|
+
activity: exeActivity,
|
|
16463
|
+
attached: attachedMap.get(exeSession) ?? false
|
|
16464
|
+
},
|
|
16465
|
+
...employeeEntries
|
|
16466
|
+
];
|
|
16467
|
+
projectList.push({ projectName, exeSession, projectDir, employees });
|
|
16468
|
+
}
|
|
16469
|
+
if (projectList.length === 0) {
|
|
16470
|
+
projectList.push({ projectName: "(no active sessions)", exeSession: "", projectDir: "", employees: [] });
|
|
16471
|
+
}
|
|
16472
|
+
setProjects(projectList);
|
|
16473
|
+
setSessionError(null);
|
|
16474
|
+
} catch (err) {
|
|
16475
|
+
setSessionError(err instanceof Error ? err.message : "Failed to query sessions.");
|
|
16476
|
+
} finally {
|
|
16477
|
+
setLoading(false);
|
|
16100
16478
|
}
|
|
16101
|
-
|
|
16102
|
-
} catch {
|
|
16103
|
-
} finally {
|
|
16104
|
-
setLoading(false);
|
|
16105
|
-
}
|
|
16479
|
+
});
|
|
16106
16480
|
}
|
|
16107
16481
|
if (viewingEmployee) {
|
|
16108
16482
|
const inCarousel = carouselEmployees.length > 0;
|
|
@@ -16184,7 +16558,10 @@ function SessionsView({
|
|
|
16184
16558
|
] })
|
|
16185
16559
|
] }),
|
|
16186
16560
|
/* @__PURE__ */ jsx9(Text, { children: " " }),
|
|
16187
|
-
loading ? /* @__PURE__ */ jsx9(Text, { color: "#6B4C9A", children: "Loading sessions..." }) :
|
|
16561
|
+
loading ? /* @__PURE__ */ jsx9(Text, { color: "#6B4C9A", children: "Loading sessions..." }) : sessionError ? /* @__PURE__ */ jsxs7(Text, { color: "#C91B00", children: [
|
|
16562
|
+
"Failed to query sessions: ",
|
|
16563
|
+
sessionError
|
|
16564
|
+
] }) : !tmuxAvailable ? /* @__PURE__ */ jsx9(Text, { color: "#3D3660", children: "tmux not available. Start a tmux session first to manage employees." }) : flatItems.length === 0 ? /* @__PURE__ */ jsx9(Text, { color: "#3D3660", children: "No active sessions. Create a task to spawn an employee." }) : flatItems.map((item, i) => {
|
|
16188
16565
|
const isSelected = i === selectedIdx;
|
|
16189
16566
|
const marker = isSelected ? "\u25B8 " : " ";
|
|
16190
16567
|
if (item.type === "project") {
|
|
@@ -16285,7 +16662,7 @@ function TasksView({ onBack }) {
|
|
|
16285
16662
|
const demo = useDemo();
|
|
16286
16663
|
const [allTasks, setAllTasks] = useState10([]);
|
|
16287
16664
|
const [loading, setLoading] = useState10(!demo);
|
|
16288
|
-
const [dbError, setDbError] = useState10(
|
|
16665
|
+
const [dbError, setDbError] = useState10(null);
|
|
16289
16666
|
const [selectedTask, setSelectedTask] = useState10(0);
|
|
16290
16667
|
const [showDetail, setShowDetail] = useState10(false);
|
|
16291
16668
|
const [statusFilter, setStatusFilter] = useState10("all");
|
|
@@ -16357,40 +16734,43 @@ function TasksView({ onBack }) {
|
|
|
16357
16734
|
}
|
|
16358
16735
|
});
|
|
16359
16736
|
async function loadTasks() {
|
|
16360
|
-
|
|
16361
|
-
|
|
16362
|
-
|
|
16363
|
-
|
|
16364
|
-
const
|
|
16365
|
-
|
|
16737
|
+
const { withTrace: withTrace2 } = await Promise.resolve().then(() => (init_telemetry(), telemetry_exports));
|
|
16738
|
+
return withTrace2("tui.tasks.loadTasks", async () => {
|
|
16739
|
+
try {
|
|
16740
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
16741
|
+
const client = getClient2();
|
|
16742
|
+
if (client) {
|
|
16743
|
+
const result = await client.execute(
|
|
16744
|
+
`SELECT id, title, priority, assigned_to, assigned_by, status, project_name, created_at, result
|
|
16366
16745
|
FROM tasks
|
|
16367
16746
|
ORDER BY
|
|
16368
16747
|
CASE status WHEN 'in_progress' THEN 0 WHEN 'open' THEN 1 WHEN 'blocked' THEN 2 WHEN 'needs_review' THEN 3 WHEN 'done' THEN 4 ELSE 5 END,
|
|
16369
16748
|
CASE priority WHEN 'p0' THEN 0 WHEN 'p1' THEN 1 WHEN 'p2' THEN 2 ELSE 3 END,
|
|
16370
16749
|
created_at DESC`
|
|
16371
|
-
|
|
16372
|
-
|
|
16373
|
-
|
|
16374
|
-
|
|
16375
|
-
|
|
16376
|
-
|
|
16377
|
-
|
|
16378
|
-
|
|
16379
|
-
|
|
16380
|
-
|
|
16381
|
-
|
|
16382
|
-
|
|
16383
|
-
|
|
16384
|
-
|
|
16385
|
-
|
|
16386
|
-
|
|
16387
|
-
|
|
16750
|
+
);
|
|
16751
|
+
setAllTasks(
|
|
16752
|
+
result.rows.map((r) => ({
|
|
16753
|
+
id: String(r.id ?? ""),
|
|
16754
|
+
priority: String(r.priority ?? "p2").toUpperCase(),
|
|
16755
|
+
title: String(r.title ?? ""),
|
|
16756
|
+
assignee: String(r.assigned_to ?? ""),
|
|
16757
|
+
assignedBy: String(r.assigned_by ?? ""),
|
|
16758
|
+
status: String(r.status ?? "open"),
|
|
16759
|
+
project: String(r.project_name ?? ""),
|
|
16760
|
+
createdAt: String(r.created_at ?? ""),
|
|
16761
|
+
result: String(r.result ?? "")
|
|
16762
|
+
}))
|
|
16763
|
+
);
|
|
16764
|
+
setDbError(null);
|
|
16765
|
+
} else {
|
|
16766
|
+
setDbError("Database client not initialized. Run exe-os setup.");
|
|
16767
|
+
}
|
|
16768
|
+
} catch (err) {
|
|
16769
|
+
setDbError(err instanceof Error ? err.message : "Unknown error");
|
|
16770
|
+
} finally {
|
|
16771
|
+
setLoading(false);
|
|
16388
16772
|
}
|
|
16389
|
-
}
|
|
16390
|
-
setDbError(true);
|
|
16391
|
-
} finally {
|
|
16392
|
-
setLoading(false);
|
|
16393
|
-
}
|
|
16773
|
+
});
|
|
16394
16774
|
}
|
|
16395
16775
|
const selected = taskRows[selectedTask]?.task;
|
|
16396
16776
|
if (showDetail && selected) {
|
|
@@ -16457,7 +16837,10 @@ function TasksView({ onBack }) {
|
|
|
16457
16837
|
filterLabel
|
|
16458
16838
|
] }),
|
|
16459
16839
|
/* @__PURE__ */ jsx10(Text, { children: " " }),
|
|
16460
|
-
loading ? /* @__PURE__ */ jsx10(Text, { color: "#6B4C9A", children: "Loading tasks..." }) : dbError ? /* @__PURE__ */
|
|
16840
|
+
loading ? /* @__PURE__ */ jsx10(Text, { color: "#6B4C9A", children: "Loading tasks..." }) : dbError ? /* @__PURE__ */ jsxs8(Text, { color: "#C91B00", children: [
|
|
16841
|
+
"Failed to load tasks: ",
|
|
16842
|
+
dbError
|
|
16843
|
+
] }) : allTasks.length === 0 ? /* @__PURE__ */ jsx10(Text, { color: "#3D3660", children: "No tasks. Create one with create_task." }) : filteredTasks.length === 0 ? /* @__PURE__ */ jsx10(Text, { color: "#3D3660", children: "No tasks match current filter." }) : displayRows.map((row, i) => {
|
|
16461
16844
|
if (row.type === "header") {
|
|
16462
16845
|
return /* @__PURE__ */ jsxs8(Box_default, { marginTop: i > 0 ? 1 : 0, children: [
|
|
16463
16846
|
/* @__PURE__ */ jsx10(Text, { bold: true, color: "#F0EDE8", children: row.project }),
|
|
@@ -16911,6 +17294,31 @@ function GatewayView({ onBack }) {
|
|
|
16911
17294
|
/* @__PURE__ */ jsx11(Text, { color: "#6B4C9A", children: "Loading gateway status..." })
|
|
16912
17295
|
] });
|
|
16913
17296
|
}
|
|
17297
|
+
if (!gateway.running && gateway.gatewayUrl && connectionStatus === "disconnected") {
|
|
17298
|
+
return /* @__PURE__ */ jsxs9(Box_default, { flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
|
|
17299
|
+
/* @__PURE__ */ jsx11(Box_default, { borderStyle: "single", borderColor: "#3D3660", paddingX: 1, alignSelf: "flex-start", children: /* @__PURE__ */ jsx11(Text, { bold: true, children: "Gateway Monitor" }) }),
|
|
17300
|
+
/* @__PURE__ */ jsx11(Text, { children: " " }),
|
|
17301
|
+
/* @__PURE__ */ jsx11(Text, { color: "#C91B00", children: "Gateway connection failed." }),
|
|
17302
|
+
/* @__PURE__ */ jsx11(Text, { children: " " }),
|
|
17303
|
+
/* @__PURE__ */ jsxs9(Text, { color: "#6B4C9A", children: [
|
|
17304
|
+
"Gateway URL: ",
|
|
17305
|
+
/* @__PURE__ */ jsx11(Text, { color: "#F0EDE8", children: gateway.gatewayUrl })
|
|
17306
|
+
] }),
|
|
17307
|
+
/* @__PURE__ */ jsxs9(Text, { color: "#6B4C9A", children: [
|
|
17308
|
+
"Process: ",
|
|
17309
|
+
/* @__PURE__ */ jsx11(Text, { color: "#C91B00", children: "not running" })
|
|
17310
|
+
] }),
|
|
17311
|
+
/* @__PURE__ */ jsx11(Text, { children: " " }),
|
|
17312
|
+
/* @__PURE__ */ jsxs9(Text, { color: "#6B4C9A", children: [
|
|
17313
|
+
"Start the gateway: ",
|
|
17314
|
+
/* @__PURE__ */ jsx11(Text, { bold: true, children: "exe-os gateway" })
|
|
17315
|
+
] }),
|
|
17316
|
+
/* @__PURE__ */ jsxs9(Text, { color: "#6B4C9A", children: [
|
|
17317
|
+
"Or check your config: ",
|
|
17318
|
+
/* @__PURE__ */ jsx11(Text, { bold: true, children: "~/.exe-os/gateway.json" })
|
|
17319
|
+
] })
|
|
17320
|
+
] });
|
|
17321
|
+
}
|
|
16914
17322
|
if (!gateway.running && gateway.adapters.length === 0 && !gateway.gatewayUrl) {
|
|
16915
17323
|
return /* @__PURE__ */ jsxs9(Box_default, { flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
|
|
16916
17324
|
/* @__PURE__ */ jsx11(Box_default, { borderStyle: "single", borderColor: "#3D3660", paddingX: 1, alignSelf: "flex-start", children: /* @__PURE__ */ jsx11(Text, { bold: true, children: "Gateway Monitor" }) }),
|
|
@@ -17099,14 +17507,30 @@ function getAgentStatus(agentId) {
|
|
|
17099
17507
|
// src/tui/views/Team.tsx
|
|
17100
17508
|
import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
17101
17509
|
var DEPRECATED_PROJECTS = /* @__PURE__ */ new Set(["exe-ai-employees"]);
|
|
17102
|
-
function
|
|
17510
|
+
function roleBadgeColor(role) {
|
|
17511
|
+
switch (role.toLowerCase()) {
|
|
17512
|
+
case "coo":
|
|
17513
|
+
return "#F5D76E";
|
|
17514
|
+
// gold
|
|
17515
|
+
case "cto":
|
|
17516
|
+
return "#3B82F6";
|
|
17517
|
+
// blue
|
|
17518
|
+
case "cmo":
|
|
17519
|
+
return "#6B4C9A";
|
|
17520
|
+
// purple
|
|
17521
|
+
default:
|
|
17522
|
+
return "#F0EDE8";
|
|
17523
|
+
}
|
|
17524
|
+
}
|
|
17525
|
+
function TeamView({ onBack, onViewSessions }) {
|
|
17103
17526
|
const demo = useDemo();
|
|
17104
17527
|
const [members, setMembers] = useState12([]);
|
|
17105
17528
|
const [externals, setExternals] = useState12([]);
|
|
17106
17529
|
const [loading, setLoading] = useState12(!demo);
|
|
17107
|
-
const [dbError, setDbError] = useState12(
|
|
17530
|
+
const [dbError, setDbError] = useState12(null);
|
|
17108
17531
|
const [selectedIdx, setSelectedIdx] = useState12(0);
|
|
17109
17532
|
const [showDetail, setShowDetail] = useState12(false);
|
|
17533
|
+
const [showAddHint, setShowAddHint] = useState12(false);
|
|
17110
17534
|
const orch = useOrchestrator(!demo);
|
|
17111
17535
|
const orchEmployeeMap = new Map(orch.employees.map((e) => [e.name, e]));
|
|
17112
17536
|
const allItems = [...members, ...externals.map((e) => ({ ...e, activity: "", memoryCount: 0 }))];
|
|
@@ -17121,7 +17545,7 @@ function TeamView({ onBack }) {
|
|
|
17121
17545
|
const timer = setInterval(loadTeam, 5e3);
|
|
17122
17546
|
return () => clearInterval(timer);
|
|
17123
17547
|
}, []);
|
|
17124
|
-
use_input_default((
|
|
17548
|
+
use_input_default((input, key) => {
|
|
17125
17549
|
if (showDetail) {
|
|
17126
17550
|
if (key.escape) setShowDetail(false);
|
|
17127
17551
|
return;
|
|
@@ -17130,91 +17554,103 @@ function TeamView({ onBack }) {
|
|
|
17130
17554
|
onBack?.();
|
|
17131
17555
|
return;
|
|
17132
17556
|
}
|
|
17557
|
+
if (input === "a") {
|
|
17558
|
+
setShowAddHint(true);
|
|
17559
|
+
setTimeout(() => setShowAddHint(false), 3e3);
|
|
17560
|
+
return;
|
|
17561
|
+
}
|
|
17562
|
+
if (input === "s" && selected) {
|
|
17563
|
+
onViewSessions?.(selected.name);
|
|
17564
|
+
return;
|
|
17565
|
+
}
|
|
17133
17566
|
if (key.upArrow && selectedIdx > 0) setSelectedIdx(selectedIdx - 1);
|
|
17134
17567
|
if (key.downArrow && selectedIdx < allItems.length - 1) setSelectedIdx(selectedIdx + 1);
|
|
17135
17568
|
if (key.return && allItems.length > 0) setShowDetail(true);
|
|
17136
17569
|
});
|
|
17137
17570
|
async function loadTeam() {
|
|
17138
|
-
|
|
17139
|
-
|
|
17140
|
-
const roster = await loadEmployees2();
|
|
17141
|
-
let memoryCounts = /* @__PURE__ */ new Map();
|
|
17142
|
-
let projectsByEmployee = /* @__PURE__ */ new Map();
|
|
17143
|
-
let currentTaskByEmployee = /* @__PURE__ */ new Map();
|
|
17571
|
+
const { withTrace: withTrace2 } = await Promise.resolve().then(() => (init_telemetry(), telemetry_exports));
|
|
17572
|
+
return withTrace2("tui.team.loadTeam", async () => {
|
|
17144
17573
|
try {
|
|
17145
|
-
const {
|
|
17146
|
-
const
|
|
17147
|
-
|
|
17148
|
-
|
|
17149
|
-
|
|
17150
|
-
|
|
17151
|
-
}
|
|
17152
|
-
|
|
17153
|
-
|
|
17154
|
-
|
|
17574
|
+
const { loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
17575
|
+
const roster = await loadEmployees2();
|
|
17576
|
+
let memoryCounts = /* @__PURE__ */ new Map();
|
|
17577
|
+
let projectsByEmployee = /* @__PURE__ */ new Map();
|
|
17578
|
+
let currentTaskByEmployee = /* @__PURE__ */ new Map();
|
|
17579
|
+
try {
|
|
17580
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
17581
|
+
const client = getClient2();
|
|
17582
|
+
if (client) {
|
|
17583
|
+
const memResult = await client.execute("SELECT agent_id, COUNT(*) as cnt FROM memories GROUP BY agent_id");
|
|
17584
|
+
for (const row of memResult.rows) {
|
|
17585
|
+
memoryCounts.set(String(row.agent_id), Number(row.cnt));
|
|
17586
|
+
}
|
|
17587
|
+
for (const emp of roster) {
|
|
17588
|
+
const projResult = await client.execute({
|
|
17589
|
+
sql: `SELECT DISTINCT project_name,
|
|
17155
17590
|
MAX(CASE WHEN status = 'in_progress' THEN 1 WHEN status = 'open' THEN 2 ELSE 3 END) as urgency
|
|
17156
17591
|
FROM tasks WHERE assigned_to = ? AND status IN ('open','in_progress','done')
|
|
17157
17592
|
GROUP BY project_name ORDER BY urgency ASC LIMIT 5`,
|
|
17158
|
-
|
|
17159
|
-
|
|
17160
|
-
|
|
17161
|
-
|
|
17162
|
-
|
|
17163
|
-
|
|
17164
|
-
|
|
17165
|
-
|
|
17166
|
-
|
|
17167
|
-
|
|
17168
|
-
|
|
17169
|
-
|
|
17170
|
-
|
|
17171
|
-
|
|
17172
|
-
|
|
17173
|
-
|
|
17174
|
-
|
|
17175
|
-
|
|
17593
|
+
args: [emp.name]
|
|
17594
|
+
});
|
|
17595
|
+
const projects = projResult.rows.filter((r) => !DEPRECATED_PROJECTS.has(String(r.project_name))).map((r) => {
|
|
17596
|
+
const urgency = Number(r.urgency);
|
|
17597
|
+
let pStatus = "idle";
|
|
17598
|
+
if (urgency === 1) pStatus = "active";
|
|
17599
|
+
else if (urgency === 2) pStatus = "has_tasks";
|
|
17600
|
+
return { name: String(r.project_name), status: pStatus };
|
|
17601
|
+
});
|
|
17602
|
+
if (projects.length > 0) projectsByEmployee.set(emp.name, projects);
|
|
17603
|
+
}
|
|
17604
|
+
for (const emp of roster) {
|
|
17605
|
+
const taskResult = await client.execute({
|
|
17606
|
+
sql: "SELECT title FROM tasks WHERE assigned_to = ? AND status = 'in_progress' ORDER BY updated_at DESC LIMIT 1",
|
|
17607
|
+
args: [emp.name]
|
|
17608
|
+
});
|
|
17609
|
+
if (taskResult.rows.length > 0) {
|
|
17610
|
+
currentTaskByEmployee.set(emp.name, String(taskResult.rows[0].title));
|
|
17611
|
+
}
|
|
17176
17612
|
}
|
|
17177
17613
|
}
|
|
17614
|
+
} catch {
|
|
17178
17615
|
}
|
|
17179
|
-
|
|
17180
|
-
|
|
17181
|
-
|
|
17182
|
-
|
|
17183
|
-
|
|
17184
|
-
|
|
17185
|
-
|
|
17186
|
-
|
|
17187
|
-
|
|
17188
|
-
|
|
17189
|
-
|
|
17190
|
-
|
|
17191
|
-
|
|
17192
|
-
|
|
17193
|
-
|
|
17194
|
-
|
|
17195
|
-
|
|
17196
|
-
|
|
17197
|
-
|
|
17198
|
-
|
|
17199
|
-
|
|
17200
|
-
|
|
17201
|
-
|
|
17202
|
-
|
|
17203
|
-
|
|
17204
|
-
|
|
17205
|
-
|
|
17206
|
-
|
|
17207
|
-
|
|
17208
|
-
})));
|
|
17616
|
+
const teamData = roster.map((emp) => {
|
|
17617
|
+
const agentSt = getAgentStatus(emp.name);
|
|
17618
|
+
return {
|
|
17619
|
+
name: emp.name,
|
|
17620
|
+
role: emp.role,
|
|
17621
|
+
status: agentSt.label,
|
|
17622
|
+
activity: agentSt.label === "active" ? "Processing..." : "",
|
|
17623
|
+
memoryCount: memoryCounts.get(emp.name) ?? 0,
|
|
17624
|
+
projects: projectsByEmployee.get(emp.name),
|
|
17625
|
+
currentTask: currentTaskByEmployee.get(emp.name),
|
|
17626
|
+
sessionName: agentSt.session
|
|
17627
|
+
};
|
|
17628
|
+
});
|
|
17629
|
+
setMembers(teamData);
|
|
17630
|
+
setDbError(null);
|
|
17631
|
+
try {
|
|
17632
|
+
const { existsSync: existsSync14, readFileSync: readFileSync11 } = await import("fs");
|
|
17633
|
+
const { join } = await import("path");
|
|
17634
|
+
const home = process.env.HOME ?? "";
|
|
17635
|
+
const gatewayConfig = join(home, ".exe-os", "gateway.json");
|
|
17636
|
+
if (existsSync14(gatewayConfig)) {
|
|
17637
|
+
const raw = JSON.parse(readFileSync11(gatewayConfig, "utf8"));
|
|
17638
|
+
if (raw.agents && raw.agents.length > 0) {
|
|
17639
|
+
setExternals(raw.agents.map((a) => ({
|
|
17640
|
+
name: a.name,
|
|
17641
|
+
role: a.role ?? "external agent",
|
|
17642
|
+
status: "offline"
|
|
17643
|
+
})));
|
|
17644
|
+
}
|
|
17209
17645
|
}
|
|
17646
|
+
} catch {
|
|
17210
17647
|
}
|
|
17211
|
-
} catch {
|
|
17648
|
+
} catch (err) {
|
|
17649
|
+
setDbError(err instanceof Error ? err.message : "Unknown error");
|
|
17650
|
+
} finally {
|
|
17651
|
+
setLoading(false);
|
|
17212
17652
|
}
|
|
17213
|
-
}
|
|
17214
|
-
setDbError(true);
|
|
17215
|
-
} finally {
|
|
17216
|
-
setLoading(false);
|
|
17217
|
-
}
|
|
17653
|
+
});
|
|
17218
17654
|
}
|
|
17219
17655
|
const totalCount = members.length + externals.length;
|
|
17220
17656
|
const selected = allItems[selectedIdx];
|
|
@@ -17231,7 +17667,7 @@ function TeamView({ onBack }) {
|
|
|
17231
17667
|
/* @__PURE__ */ jsx12(Text, { children: " " }),
|
|
17232
17668
|
/* @__PURE__ */ jsxs10(Text, { children: [
|
|
17233
17669
|
"Role: ",
|
|
17234
|
-
/* @__PURE__ */ jsx12(Text, { bold: true, children: selected.role })
|
|
17670
|
+
/* @__PURE__ */ jsx12(Text, { bold: true, color: roleBadgeColor(selected.role), children: selected.role })
|
|
17235
17671
|
] }),
|
|
17236
17672
|
/* @__PURE__ */ jsxs10(Text, { children: [
|
|
17237
17673
|
"Status: ",
|
|
@@ -17260,8 +17696,9 @@ function TeamView({ onBack }) {
|
|
|
17260
17696
|
/* @__PURE__ */ jsx12(Box_default, { borderStyle: "single", borderColor: "#3D3660", paddingX: 1, alignSelf: "flex-start", children: /* @__PURE__ */ jsx12(Text, { bold: true, children: "Team Roster" }) }),
|
|
17261
17697
|
/* @__PURE__ */ jsxs10(Text, { color: "#6B4C9A", children: [
|
|
17262
17698
|
totalCount,
|
|
17263
|
-
" agents |
|
|
17699
|
+
" agents | \u2191\u2193 navigate | Enter details | a add | s sessions"
|
|
17264
17700
|
] }),
|
|
17701
|
+
showAddHint && /* @__PURE__ */ jsx12(Text, { color: "#F5D76E", children: "Run /exe-new-employee <name> from CLI to add an employee." }),
|
|
17265
17702
|
!demo && orch.pendingReviews > 0 && /* @__PURE__ */ jsxs10(Text, { color: "#6B4C9A", children: [
|
|
17266
17703
|
orch.pendingReviews,
|
|
17267
17704
|
" review(s) pending exe attention"
|
|
@@ -17269,7 +17706,10 @@ function TeamView({ onBack }) {
|
|
|
17269
17706
|
/* @__PURE__ */ jsx12(Text, { children: " " }),
|
|
17270
17707
|
/* @__PURE__ */ jsx12(Text, { bold: true, children: "INTERNAL" }),
|
|
17271
17708
|
/* @__PURE__ */ jsx12(Text, { children: " " }),
|
|
17272
|
-
loading ? /* @__PURE__ */ jsx12(Text, { color: "#6B4C9A", children: " Loading
|
|
17709
|
+
loading ? /* @__PURE__ */ jsx12(Text, { color: "#6B4C9A", children: " Loading employee roster..." }) : dbError ? /* @__PURE__ */ jsxs10(Text, { color: "#C91B00", children: [
|
|
17710
|
+
" Failed to load roster: ",
|
|
17711
|
+
dbError
|
|
17712
|
+
] }) : members.length === 0 ? /* @__PURE__ */ jsx12(Text, { color: "#3D3660", children: " No employees configured. Run /exe-new-employee." }) : /* @__PURE__ */ jsx12(Box_default, { flexDirection: "row", flexWrap: "wrap", gap: 1, children: members.map((m, i) => {
|
|
17273
17713
|
const isSelected = i === selectedIdx;
|
|
17274
17714
|
const orchEmp = orchEmployeeMap.get(m.name);
|
|
17275
17715
|
return /* @__PURE__ */ jsxs10(
|
|
@@ -17285,7 +17725,7 @@ function TeamView({ onBack }) {
|
|
|
17285
17725
|
/* @__PURE__ */ jsxs10(Box_default, { gap: 1, children: [
|
|
17286
17726
|
/* @__PURE__ */ jsx12(StatusDot, { status: m.status, showLabel: false }),
|
|
17287
17727
|
/* @__PURE__ */ jsx12(Text, { bold: true, color: isSelected ? "#F5D76E" : "#F0EDE8", children: m.name }),
|
|
17288
|
-
/* @__PURE__ */ jsxs10(Text, { color: isSelected ? "#F5D76E" :
|
|
17728
|
+
/* @__PURE__ */ jsxs10(Text, { color: isSelected ? "#F5D76E" : roleBadgeColor(m.role), children: [
|
|
17289
17729
|
"(",
|
|
17290
17730
|
m.role,
|
|
17291
17731
|
")"
|
|
@@ -17358,6 +17798,33 @@ import TextInput2 from "ink-text-input";
|
|
|
17358
17798
|
import { Fragment as Fragment4, jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
17359
17799
|
var PANELS = ["Workspaces", "Documents", "Chat"];
|
|
17360
17800
|
var MAX_VISIBLE_MESSAGES = 12;
|
|
17801
|
+
var DEMO_SEARCH_RESULTS = [
|
|
17802
|
+
{ id: "1", agentId: "yoshi", rawText: "Reviewed PR #42 \u2014 approved with minor comment on error handling pattern", timestamp: new Date(Date.now() - 2 * 36e5).toISOString(), projectName: "exe-os" },
|
|
17803
|
+
{ id: "2", agentId: "tom", rawText: "Implemented session routing with deterministic naming: agent-exeN convention", timestamp: new Date(Date.now() - 5 * 36e5).toISOString(), projectName: "exe-os" },
|
|
17804
|
+
{ id: "3", agentId: "exe", rawText: "Status brief: 3 tasks completed, 1 blocked on wiki integration", timestamp: new Date(Date.now() - 8 * 36e5).toISOString(), projectName: "exe-os" },
|
|
17805
|
+
{ id: "4", agentId: "mari", rawText: "Created brand guidelines document \u2014 Exe Foundry Bold design system", timestamp: new Date(Date.now() - 24 * 36e5).toISOString(), projectName: "exe-os" },
|
|
17806
|
+
{ id: "5", agentId: "tom", rawText: "Fixed CommandCenter project filtering \u2014 DB-first, no random directories", timestamp: new Date(Date.now() - 48 * 36e5).toISOString(), projectName: "exe-os" }
|
|
17807
|
+
];
|
|
17808
|
+
function agentColor(agentId) {
|
|
17809
|
+
switch (agentId.toLowerCase()) {
|
|
17810
|
+
case "exe":
|
|
17811
|
+
return "#F5D76E";
|
|
17812
|
+
case "yoshi":
|
|
17813
|
+
return "#3B82F6";
|
|
17814
|
+
case "mari":
|
|
17815
|
+
return "#6B4C9A";
|
|
17816
|
+
default:
|
|
17817
|
+
return "#F0EDE8";
|
|
17818
|
+
}
|
|
17819
|
+
}
|
|
17820
|
+
function formatTimeAgo(iso) {
|
|
17821
|
+
const diff2 = Date.now() - new Date(iso).getTime();
|
|
17822
|
+
const hours = Math.floor(diff2 / 36e5);
|
|
17823
|
+
if (hours < 1) return "just now";
|
|
17824
|
+
if (hours < 24) return `${hours}h ago`;
|
|
17825
|
+
const days = Math.floor(hours / 24);
|
|
17826
|
+
return `${days}d ago`;
|
|
17827
|
+
}
|
|
17361
17828
|
function WikiView({ onBack }) {
|
|
17362
17829
|
const demo = useDemo();
|
|
17363
17830
|
const [activePanel, setActivePanel] = useState13("Workspaces");
|
|
@@ -17368,6 +17835,12 @@ function WikiView({ onBack }) {
|
|
|
17368
17835
|
const [chatHistory, setChatHistory] = useState13([]);
|
|
17369
17836
|
const [chatInput, setChatInput] = useState13("");
|
|
17370
17837
|
const [chatFocused, setChatFocused] = useState13(false);
|
|
17838
|
+
const [searchMode, setSearchMode] = useState13(false);
|
|
17839
|
+
const [searchQuery, setSearchQuery] = useState13("");
|
|
17840
|
+
const [searchResults, setSearchResults] = useState13([]);
|
|
17841
|
+
const [searchLoading, setSearchLoading] = useState13(false);
|
|
17842
|
+
const [selectedResultIdx, setSelectedResultIdx] = useState13(0);
|
|
17843
|
+
const [expandedResultIdx, setExpandedResultIdx] = useState13(null);
|
|
17371
17844
|
const [loading, setLoading] = useState13(true);
|
|
17372
17845
|
const [connected, setConnected] = useState13(false);
|
|
17373
17846
|
const [wikiUrl, setWikiUrl] = useState13("");
|
|
@@ -17461,6 +17934,55 @@ function WikiView({ onBack }) {
|
|
|
17461
17934
|
setSending(false);
|
|
17462
17935
|
}
|
|
17463
17936
|
}
|
|
17937
|
+
async function searchMemories2(query) {
|
|
17938
|
+
if (!query.trim()) {
|
|
17939
|
+
setSearchResults([]);
|
|
17940
|
+
return;
|
|
17941
|
+
}
|
|
17942
|
+
if (demo) {
|
|
17943
|
+
const q = query.toLowerCase();
|
|
17944
|
+
setSearchResults(
|
|
17945
|
+
DEMO_SEARCH_RESULTS.filter((r) => r.rawText.toLowerCase().includes(q))
|
|
17946
|
+
);
|
|
17947
|
+
return;
|
|
17948
|
+
}
|
|
17949
|
+
setSearchLoading(true);
|
|
17950
|
+
try {
|
|
17951
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
17952
|
+
const client = getClient2();
|
|
17953
|
+
const result = await client.execute({
|
|
17954
|
+
sql: `SELECT id, agent_id, raw_text, timestamp, project_name
|
|
17955
|
+
FROM memories
|
|
17956
|
+
WHERE raw_text LIKE ? AND COALESCE(status, 'active') = 'active'
|
|
17957
|
+
ORDER BY timestamp DESC LIMIT 20`,
|
|
17958
|
+
args: [`%${query}%`]
|
|
17959
|
+
});
|
|
17960
|
+
setSearchResults(
|
|
17961
|
+
result.rows.map((r) => ({
|
|
17962
|
+
id: String(r.id),
|
|
17963
|
+
agentId: String(r.agent_id),
|
|
17964
|
+
rawText: String(r.raw_text),
|
|
17965
|
+
timestamp: String(r.timestamp),
|
|
17966
|
+
projectName: String(r.project_name ?? "")
|
|
17967
|
+
}))
|
|
17968
|
+
);
|
|
17969
|
+
} catch {
|
|
17970
|
+
setSearchResults([]);
|
|
17971
|
+
} finally {
|
|
17972
|
+
setSearchLoading(false);
|
|
17973
|
+
}
|
|
17974
|
+
}
|
|
17975
|
+
useEffect15(() => {
|
|
17976
|
+
if (!searchMode) return;
|
|
17977
|
+
const timer = setTimeout(() => {
|
|
17978
|
+
searchMemories2(searchQuery);
|
|
17979
|
+
}, 300);
|
|
17980
|
+
return () => clearTimeout(timer);
|
|
17981
|
+
}, [searchQuery, searchMode]);
|
|
17982
|
+
useEffect15(() => {
|
|
17983
|
+
setSelectedResultIdx(0);
|
|
17984
|
+
setExpandedResultIdx(null);
|
|
17985
|
+
}, [searchResults]);
|
|
17464
17986
|
async function selectWorkspace(idx) {
|
|
17465
17987
|
setSelectedWorkspaceIdx(idx);
|
|
17466
17988
|
const ws = workspaces[idx];
|
|
@@ -17481,6 +18003,32 @@ function WikiView({ onBack }) {
|
|
|
17481
18003
|
}
|
|
17482
18004
|
}
|
|
17483
18005
|
use_input_default((input, key) => {
|
|
18006
|
+
if (searchMode && !chatFocused) {
|
|
18007
|
+
if (key.escape) {
|
|
18008
|
+
setSearchMode(false);
|
|
18009
|
+
setSearchQuery("");
|
|
18010
|
+
setSearchResults([]);
|
|
18011
|
+
setExpandedResultIdx(null);
|
|
18012
|
+
return;
|
|
18013
|
+
}
|
|
18014
|
+
if (key.upArrow && selectedResultIdx > 0) {
|
|
18015
|
+
setSelectedResultIdx(selectedResultIdx - 1);
|
|
18016
|
+
setExpandedResultIdx(null);
|
|
18017
|
+
return;
|
|
18018
|
+
}
|
|
18019
|
+
if (key.downArrow && selectedResultIdx < searchResults.length - 1) {
|
|
18020
|
+
setSelectedResultIdx(selectedResultIdx + 1);
|
|
18021
|
+
setExpandedResultIdx(null);
|
|
18022
|
+
return;
|
|
18023
|
+
}
|
|
18024
|
+
if (key.return && searchResults.length > 0) {
|
|
18025
|
+
setExpandedResultIdx(
|
|
18026
|
+
expandedResultIdx === selectedResultIdx ? null : selectedResultIdx
|
|
18027
|
+
);
|
|
18028
|
+
return;
|
|
18029
|
+
}
|
|
18030
|
+
return;
|
|
18031
|
+
}
|
|
17484
18032
|
if (chatFocused) {
|
|
17485
18033
|
if (key.escape) {
|
|
17486
18034
|
setChatFocused(false);
|
|
@@ -17492,6 +18040,13 @@ function WikiView({ onBack }) {
|
|
|
17492
18040
|
}
|
|
17493
18041
|
return;
|
|
17494
18042
|
}
|
|
18043
|
+
if (input === "/" && activePanel !== "Chat") {
|
|
18044
|
+
setSearchMode(true);
|
|
18045
|
+
setSearchQuery("");
|
|
18046
|
+
setSearchResults(demo ? DEMO_SEARCH_RESULTS : []);
|
|
18047
|
+
setExpandedResultIdx(null);
|
|
18048
|
+
return;
|
|
18049
|
+
}
|
|
17495
18050
|
if (key.leftArrow) {
|
|
17496
18051
|
const panelIdx = PANELS.indexOf(activePanel);
|
|
17497
18052
|
if (panelIdx === 0) {
|
|
@@ -17569,9 +18124,53 @@ function WikiView({ onBack }) {
|
|
|
17569
18124
|
/* @__PURE__ */ jsx13(Text, { bold: true, children: selectedWs.name })
|
|
17570
18125
|
] }) : null
|
|
17571
18126
|
] }),
|
|
17572
|
-
/* @__PURE__ */ jsx13(Text, { color: "#6B4C9A", children: "\u2190\u2192 switch panels | \u2191\u2193 navigate | /
|
|
18127
|
+
/* @__PURE__ */ jsx13(Text, { color: "#6B4C9A", children: "\u2190\u2192 switch panels | \u2191\u2193 navigate | / search memories | Enter select" }),
|
|
17573
18128
|
/* @__PURE__ */ jsx13(Text, { children: " " }),
|
|
17574
|
-
/* @__PURE__ */ jsxs11(Box_default, {
|
|
18129
|
+
searchMode ? /* @__PURE__ */ jsxs11(Box_default, { flexDirection: "column", flexGrow: 1, children: [
|
|
18130
|
+
/* @__PURE__ */ jsxs11(Box_default, { paddingX: 1, children: [
|
|
18131
|
+
/* @__PURE__ */ jsx13(Text, { color: "#F5D76E", children: "Search: " }),
|
|
18132
|
+
/* @__PURE__ */ jsx13(
|
|
18133
|
+
TextInput2,
|
|
18134
|
+
{
|
|
18135
|
+
value: searchQuery,
|
|
18136
|
+
onChange: setSearchQuery,
|
|
18137
|
+
placeholder: "search memories...",
|
|
18138
|
+
focus: true
|
|
18139
|
+
}
|
|
18140
|
+
),
|
|
18141
|
+
/* @__PURE__ */ jsx13(Text, { color: "#6B4C9A", children: " (esc to close)" })
|
|
18142
|
+
] }),
|
|
18143
|
+
/* @__PURE__ */ jsx13(Text, { children: " " }),
|
|
18144
|
+
searchLoading ? /* @__PURE__ */ jsx13(Text, { color: "#6B4C9A", children: " Searching..." }) : searchResults.length === 0 && searchQuery.trim() ? /* @__PURE__ */ jsx13(Text, { color: "#6B4C9A", children: " No results found." }) : searchResults.length === 0 ? /* @__PURE__ */ jsx13(Text, { color: "#6B4C9A", children: " Type to search exe-os memories." }) : searchResults.map((result, i) => {
|
|
18145
|
+
const isSelected = i === selectedResultIdx;
|
|
18146
|
+
const isExpanded = i === expandedResultIdx;
|
|
18147
|
+
const snippet = result.rawText.slice(0, 80);
|
|
18148
|
+
return /* @__PURE__ */ jsxs11(Box_default, { flexDirection: "column", children: [
|
|
18149
|
+
/* @__PURE__ */ jsxs11(
|
|
18150
|
+
Text,
|
|
18151
|
+
{
|
|
18152
|
+
backgroundColor: isSelected ? "#6B4C9A" : void 0,
|
|
18153
|
+
color: isSelected ? "#F5D76E" : void 0,
|
|
18154
|
+
children: [
|
|
18155
|
+
" ",
|
|
18156
|
+
/* @__PURE__ */ jsx13(Text, { color: isSelected ? "#F5D76E" : agentColor(result.agentId), bold: true, children: result.agentId.padEnd(8) }),
|
|
18157
|
+
/* @__PURE__ */ jsxs11(Text, { color: isSelected ? "#F5D76E" : "#F0EDE8", children: [
|
|
18158
|
+
snippet,
|
|
18159
|
+
result.rawText.length > 80 ? "..." : ""
|
|
18160
|
+
] }),
|
|
18161
|
+
" ",
|
|
18162
|
+
/* @__PURE__ */ jsx13(Text, { color: isSelected ? "#F5D76E" : "#3D3660", dimColor: !isSelected, children: formatTimeAgo(result.timestamp) })
|
|
18163
|
+
]
|
|
18164
|
+
}
|
|
18165
|
+
),
|
|
18166
|
+
isExpanded ? /* @__PURE__ */ jsx13(Box_default, { paddingX: 4, marginBottom: 1, children: /* @__PURE__ */ jsx13(Text, { color: "#F0EDE8", wrap: "wrap", children: result.rawText }) }) : null
|
|
18167
|
+
] }, result.id);
|
|
18168
|
+
}),
|
|
18169
|
+
searchResults.length > 0 ? /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
18170
|
+
/* @__PURE__ */ jsx13(Text, { children: " " }),
|
|
18171
|
+
/* @__PURE__ */ jsx13(Text, { color: "#3D3660", children: " \u2191\u2193 navigate | Enter expand | Esc close" })
|
|
18172
|
+
] }) : null
|
|
18173
|
+
] }) : /* @__PURE__ */ jsxs11(Box_default, { flexGrow: 1, gap: 1, children: [
|
|
17575
18174
|
/* @__PURE__ */ jsxs11(Box_default, { flexDirection: "column", width: "25%", children: [
|
|
17576
18175
|
/* @__PURE__ */ jsxs11(Text, { bold: true, backgroundColor: panelHeaderBg("Workspaces"), color: panelHeaderColor("Workspaces"), children: [
|
|
17577
18176
|
activePanel === "Workspaces" ? "\u25B8 " : " ",
|
|
@@ -17655,50 +18254,41 @@ function WikiView({ onBack }) {
|
|
|
17655
18254
|
}
|
|
17656
18255
|
|
|
17657
18256
|
// src/tui/views/Settings.tsx
|
|
17658
|
-
import React24, { useState as useState14, useEffect as useEffect16 } from "react";
|
|
18257
|
+
import React24, { useState as useState14, useEffect as useEffect16, useCallback as useCallback7 } from "react";
|
|
17659
18258
|
import { Fragment as Fragment5, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
17660
|
-
|
|
18259
|
+
function maskSecret(value) {
|
|
18260
|
+
if (value.length <= 10) return "****";
|
|
18261
|
+
return `${value.slice(0, 6)}...${value.slice(-4)}`;
|
|
18262
|
+
}
|
|
18263
|
+
var SECTION_NAMES = ["Providers", "Cloud Sync", "License", "System", "Gateway"];
|
|
18264
|
+
var GREEN = "#22C55E";
|
|
18265
|
+
var DIM = "#6B4C9A";
|
|
18266
|
+
var YELLOW = "#F5D76E";
|
|
17661
18267
|
function SettingsView({ onBack }) {
|
|
17662
18268
|
const [providers, setProviders] = useState14([]);
|
|
17663
|
-
const [
|
|
17664
|
-
|
|
17665
|
-
|
|
17666
|
-
|
|
17667
|
-
searchMode: "checking..."
|
|
17668
|
-
});
|
|
17669
|
-
const [runtime, setRuntime] = useState14({
|
|
17670
|
-
consolidation: true,
|
|
17671
|
-
consolidationModel: "...",
|
|
17672
|
-
skillLearning: true,
|
|
17673
|
-
skillThreshold: 3,
|
|
17674
|
-
skillModel: "...",
|
|
17675
|
-
failoverChain: ["anthropic", "opencode", "gemini", "openai"]
|
|
17676
|
-
});
|
|
17677
|
-
const [employeeModels, setEmployeeModels] = useState14([]);
|
|
18269
|
+
const [cloud, setCloud] = useState14({ configured: false, endpoint: "", apiKey: "" });
|
|
18270
|
+
const [license, setLicense] = useState14({ valid: false, plan: "checking...", expiresAt: null, deviceLimit: 0, employeeLimit: 0, memoryLimit: 0 });
|
|
18271
|
+
const [system, setSystem] = useState14({ daemon: "unknown", version: "...", dbPath: "...", embeddingModel: "...", encryption: "checking..." });
|
|
18272
|
+
const [gateway, setGateway] = useState14({ adapters: [] });
|
|
17678
18273
|
const [selectedSection, setSelectedSection] = useState14(0);
|
|
17679
18274
|
const [loading, setLoading] = useState14(true);
|
|
17680
|
-
const
|
|
17681
|
-
|
|
17682
|
-
|
|
17683
|
-
|
|
17684
|
-
|
|
17685
|
-
|
|
17686
|
-
|
|
17687
|
-
|
|
17688
|
-
onBack?.();
|
|
17689
|
-
return;
|
|
17690
|
-
}
|
|
17691
|
-
if (key.upArrow && selectedSection > 0) setSelectedSection(selectedSection - 1);
|
|
17692
|
-
if (key.downArrow && selectedSection < SECTION_NAMES.length - 1) setSelectedSection(selectedSection + 1);
|
|
17693
|
-
});
|
|
17694
|
-
async function loadSettings() {
|
|
17695
|
-
const providerList = [
|
|
17696
|
-
{ name: "Anthropic", configured: !!process.env.ANTHROPIC_API_KEY, detail: process.env.ANTHROPIC_API_KEY ? "ANTHROPIC_API_KEY set" : "not configured" },
|
|
17697
|
-
{ name: "OpenCode", configured: !!process.env.OPENCODE_API_KEY, detail: process.env.OPENCODE_API_KEY ? "OPENCODE_API_KEY set" : "not configured" },
|
|
17698
|
-
{ name: "Gemini", configured: !!process.env.GEMINI_API_KEY, detail: process.env.GEMINI_API_KEY ? "GEMINI_API_KEY set" : "not configured" },
|
|
17699
|
-
{ name: "OpenAI", configured: !!process.env.OPENAI_API_KEY, detail: process.env.OPENAI_API_KEY ? "OPENAI_API_KEY set" : "not configured" },
|
|
17700
|
-
{ name: "Chutes", configured: !!process.env.CHUTES_API_KEY, detail: process.env.CHUTES_API_KEY ? "CHUTES_API_KEY set" : "not configured" }
|
|
18275
|
+
const loadSettings = useCallback7(async () => {
|
|
18276
|
+
setLoading(true);
|
|
18277
|
+
const envKeys = [
|
|
18278
|
+
["Anthropic", "ANTHROPIC_API_KEY"],
|
|
18279
|
+
["OpenCode", "OPENCODE_API_KEY"],
|
|
18280
|
+
["Gemini", "GEMINI_API_KEY"],
|
|
18281
|
+
["OpenAI", "OPENAI_API_KEY"],
|
|
18282
|
+
["Chutes", "CHUTES_API_KEY"]
|
|
17701
18283
|
];
|
|
18284
|
+
const providerList = envKeys.map(([name, envVar]) => {
|
|
18285
|
+
const val = process.env[envVar];
|
|
18286
|
+
return {
|
|
18287
|
+
name,
|
|
18288
|
+
configured: !!val,
|
|
18289
|
+
detail: val ? maskSecret(val) : "not configured"
|
|
18290
|
+
};
|
|
18291
|
+
});
|
|
17702
18292
|
try {
|
|
17703
18293
|
const { execSync: execSync10 } = await import("child_process");
|
|
17704
18294
|
execSync10("curl -s --max-time 1 http://localhost:11434/api/tags", { timeout: 2e3 });
|
|
@@ -17710,112 +18300,101 @@ function SettingsView({ onBack }) {
|
|
|
17710
18300
|
try {
|
|
17711
18301
|
const { existsSync: existsSync14 } = await import("fs");
|
|
17712
18302
|
const { join } = await import("path");
|
|
17713
|
-
const home = process.env.HOME ?? "";
|
|
17714
|
-
const hasKey = existsSync14(join(home, ".exe-os", "master.key"));
|
|
17715
18303
|
const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
17716
18304
|
const cfg = await loadConfig2();
|
|
17717
|
-
setMemory({
|
|
17718
|
-
encryption: hasKey ? "SQLCipher AES-256" : "not configured",
|
|
17719
|
-
embeddingModel: cfg.modelFile ?? "unknown",
|
|
17720
|
-
cloudSync: cfg.cloud ? "enabled" : "disabled",
|
|
17721
|
-
searchMode: cfg.searchMode ?? "hybrid"
|
|
17722
|
-
});
|
|
17723
|
-
const rawCfg = cfg;
|
|
17724
|
-
const chain = Array.isArray(rawCfg.failoverChain) ? rawCfg.failoverChain : ["anthropic", "opencode", "gemini", "openai"];
|
|
17725
|
-
setRuntime({
|
|
17726
|
-
consolidation: cfg.consolidationEnabled,
|
|
17727
|
-
consolidationModel: cfg.consolidationModel,
|
|
17728
|
-
skillLearning: cfg.skillLearning,
|
|
17729
|
-
skillThreshold: cfg.skillThreshold,
|
|
17730
|
-
skillModel: cfg.skillModel,
|
|
17731
|
-
failoverChain: chain
|
|
17732
|
-
});
|
|
17733
|
-
} catch {
|
|
17734
|
-
}
|
|
17735
|
-
try {
|
|
17736
|
-
const { loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
17737
|
-
const roster = await loadEmployees2();
|
|
17738
|
-
const { existsSync: existsSync14, readFileSync: readFileSync11 } = await import("fs");
|
|
17739
|
-
const { join } = await import("path");
|
|
17740
18305
|
const home = process.env.HOME ?? "";
|
|
17741
|
-
const
|
|
17742
|
-
|
|
17743
|
-
|
|
17744
|
-
|
|
17745
|
-
|
|
17746
|
-
|
|
17747
|
-
|
|
17748
|
-
|
|
17749
|
-
|
|
17750
|
-
}
|
|
18306
|
+
const hasKey = existsSync14(join(home, ".exe-os", "master.key"));
|
|
18307
|
+
if (cfg.cloud) {
|
|
18308
|
+
setCloud({
|
|
18309
|
+
configured: true,
|
|
18310
|
+
endpoint: cfg.cloud.endpoint,
|
|
18311
|
+
apiKey: maskSecret(cfg.cloud.apiKey)
|
|
18312
|
+
});
|
|
18313
|
+
} else {
|
|
18314
|
+
setCloud({ configured: false, endpoint: "", apiKey: "" });
|
|
17751
18315
|
}
|
|
17752
|
-
|
|
17753
|
-
|
|
17754
|
-
|
|
17755
|
-
|
|
17756
|
-
}
|
|
17757
|
-
} catch {
|
|
17758
|
-
}
|
|
17759
|
-
try {
|
|
17760
|
-
const { existsSync: existsSync14, readFileSync: readFileSync11 } = await import("fs");
|
|
17761
|
-
const { join } = await import("path");
|
|
17762
|
-
const home = process.env.HOME ?? "";
|
|
17763
|
-
const ccSettingsPath = join(home, ".claude", "settings.json");
|
|
17764
|
-
const installed = existsSync14(ccSettingsPath);
|
|
17765
|
-
let hooksWired = false;
|
|
17766
|
-
if (installed) {
|
|
17767
|
-
try {
|
|
17768
|
-
const settings = JSON.parse(readFileSync11(ccSettingsPath, "utf8"));
|
|
17769
|
-
const hooks = settings.hooks;
|
|
17770
|
-
if (hooks) {
|
|
17771
|
-
hooksWired = Object.values(hooks).flat().some((h) => h.command?.includes("exe-os") || h.command?.includes("exe-mem"));
|
|
17772
|
-
}
|
|
17773
|
-
} catch {
|
|
17774
|
-
}
|
|
18316
|
+
const pidPath = join(home, ".exe-os", "exed.pid");
|
|
18317
|
+
let daemon = "unknown";
|
|
18318
|
+
try {
|
|
18319
|
+
daemon = existsSync14(pidPath) ? "running" : "stopped";
|
|
18320
|
+
} catch {
|
|
17775
18321
|
}
|
|
17776
|
-
|
|
17777
|
-
|
|
17778
|
-
|
|
17779
|
-
|
|
17780
|
-
|
|
17781
|
-
|
|
17782
|
-
|
|
17783
|
-
|
|
17784
|
-
|
|
18322
|
+
let version = "unknown";
|
|
18323
|
+
try {
|
|
18324
|
+
const { readFileSync: readFileSync11 } = await import("fs");
|
|
18325
|
+
const { createRequire } = await import("module");
|
|
18326
|
+
const require2 = createRequire(import.meta.url);
|
|
18327
|
+
const pkgPath = require2.resolve("@askexenow/exe-os/package.json");
|
|
18328
|
+
const pkg = JSON.parse(readFileSync11(pkgPath, "utf8"));
|
|
18329
|
+
version = pkg.version;
|
|
18330
|
+
} catch {
|
|
17785
18331
|
try {
|
|
17786
|
-
const
|
|
17787
|
-
|
|
18332
|
+
const { readFileSync: readFileSync11 } = await import("fs");
|
|
18333
|
+
const { join: joinPath } = await import("path");
|
|
18334
|
+
const pkg = JSON.parse(readFileSync11(joinPath(process.cwd(), "package.json"), "utf8"));
|
|
18335
|
+
version = pkg.version;
|
|
17788
18336
|
} catch {
|
|
17789
|
-
setLicense({ valid: false, detail: "invalid license file" });
|
|
17790
18337
|
}
|
|
17791
|
-
} else {
|
|
17792
|
-
setLicense({ valid: false, detail: "no license" });
|
|
17793
18338
|
}
|
|
18339
|
+
setSystem({
|
|
18340
|
+
daemon,
|
|
18341
|
+
version,
|
|
18342
|
+
dbPath: cfg.dbPath,
|
|
18343
|
+
embeddingModel: cfg.modelFile ?? "unknown",
|
|
18344
|
+
encryption: hasKey ? "SQLCipher AES-256" : "not configured"
|
|
18345
|
+
});
|
|
17794
18346
|
} catch {
|
|
17795
18347
|
}
|
|
17796
18348
|
try {
|
|
17797
|
-
const {
|
|
17798
|
-
const
|
|
17799
|
-
|
|
17800
|
-
|
|
17801
|
-
|
|
17802
|
-
|
|
17803
|
-
|
|
17804
|
-
|
|
17805
|
-
|
|
18349
|
+
const { checkLicense: checkLicense2 } = await Promise.resolve().then(() => (init_license(), license_exports));
|
|
18350
|
+
const lic = await checkLicense2();
|
|
18351
|
+
setLicense({
|
|
18352
|
+
valid: lic.valid,
|
|
18353
|
+
plan: lic.plan.toUpperCase(),
|
|
18354
|
+
expiresAt: lic.expiresAt,
|
|
18355
|
+
deviceLimit: lic.deviceLimit,
|
|
18356
|
+
employeeLimit: lic.employeeLimit,
|
|
18357
|
+
memoryLimit: lic.memoryLimit
|
|
18358
|
+
});
|
|
17806
18359
|
} catch {
|
|
18360
|
+
setLicense({ valid: false, plan: "FREE", expiresAt: null, deviceLimit: 1, employeeLimit: 1, memoryLimit: 5e3 });
|
|
17807
18361
|
}
|
|
17808
|
-
|
|
17809
|
-
|
|
17810
|
-
|
|
17811
|
-
|
|
18362
|
+
const gatewayAdapters = [
|
|
18363
|
+
{ name: "WhatsApp", configured: !!process.env.WHATSAPP_API_TOKEN || !!process.env.WHATSAPP_PHONE_NUMBER_ID },
|
|
18364
|
+
{ name: "Telegram", configured: !!process.env.TELEGRAM_BOT_TOKEN },
|
|
18365
|
+
{ name: "Discord", configured: !!process.env.DISCORD_BOT_TOKEN },
|
|
18366
|
+
{ name: "Slack", configured: !!process.env.SLACK_BOT_TOKEN }
|
|
18367
|
+
];
|
|
18368
|
+
setGateway({ adapters: gatewayAdapters });
|
|
18369
|
+
setLoading(false);
|
|
18370
|
+
}, []);
|
|
18371
|
+
useEffect16(() => {
|
|
18372
|
+
loadSettings();
|
|
18373
|
+
}, [loadSettings]);
|
|
18374
|
+
use_input_default((input, key) => {
|
|
18375
|
+
if (key.leftArrow) {
|
|
18376
|
+
onBack?.();
|
|
18377
|
+
return;
|
|
18378
|
+
}
|
|
18379
|
+
if (key.upArrow && selectedSection > 0) setSelectedSection(selectedSection - 1);
|
|
18380
|
+
if (key.downArrow && selectedSection < SECTION_NAMES.length - 1) setSelectedSection(selectedSection + 1);
|
|
18381
|
+
if (input === "r") {
|
|
18382
|
+
loadSettings();
|
|
18383
|
+
}
|
|
18384
|
+
});
|
|
18385
|
+
const statusDot = (ok) => ok ? "\u2022" : "\u2022";
|
|
18386
|
+
const statusColor = (ok) => ok ? GREEN : DIM;
|
|
18387
|
+
const sectionColor = (idx) => selectedSection === idx ? YELLOW : void 0;
|
|
18388
|
+
const sectionBg = (idx) => selectedSection === idx ? DIM : void 0;
|
|
17812
18389
|
const sectionMarker = (idx) => selectedSection === idx ? "\u25B8 " : " ";
|
|
18390
|
+
const anyGateway = gateway.adapters.some((a) => a.configured);
|
|
18391
|
+
const formatLimit = (n) => n === -1 ? "unlimited" : n.toLocaleString();
|
|
17813
18392
|
return /* @__PURE__ */ jsxs12(Box_default, { flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
|
|
17814
18393
|
/* @__PURE__ */ jsx14(Box_default, { borderStyle: "single", borderColor: "#3D3660", paddingX: 1, alignSelf: "flex-start", children: /* @__PURE__ */ jsx14(Text, { bold: true, children: "Settings" }) }),
|
|
17815
|
-
/* @__PURE__ */ jsx14(Text, { color:
|
|
18394
|
+
/* @__PURE__ */ jsx14(Text, { color: DIM, children: "\u2191\u2193 navigate sections r refresh" }),
|
|
17816
18395
|
/* @__PURE__ */ jsx14(Text, { children: " " }),
|
|
17817
18396
|
loading && /* @__PURE__ */ jsxs12(Fragment5, { children: [
|
|
17818
|
-
/* @__PURE__ */ jsx14(Text, { color:
|
|
18397
|
+
/* @__PURE__ */ jsx14(Text, { color: DIM, children: "Loading settings..." }),
|
|
17819
18398
|
/* @__PURE__ */ jsx14(Text, { children: " " })
|
|
17820
18399
|
] }),
|
|
17821
18400
|
/* @__PURE__ */ jsxs12(Text, { bold: true, backgroundColor: sectionBg(0), color: sectionColor(0), children: [
|
|
@@ -17825,6 +18404,8 @@ function SettingsView({ onBack }) {
|
|
|
17825
18404
|
/* @__PURE__ */ jsx14(Text, { children: " " }),
|
|
17826
18405
|
providers.map((p) => /* @__PURE__ */ jsxs12(Text, { children: [
|
|
17827
18406
|
" ",
|
|
18407
|
+
/* @__PURE__ */ jsx14(Text, { color: statusColor(p.configured), children: statusDot(p.configured) }),
|
|
18408
|
+
" ",
|
|
17828
18409
|
p.name,
|
|
17829
18410
|
": ",
|
|
17830
18411
|
/* @__PURE__ */ jsx14(Text, { color: statusColor(p.configured), children: p.detail })
|
|
@@ -17832,109 +18413,301 @@ function SettingsView({ onBack }) {
|
|
|
17832
18413
|
/* @__PURE__ */ jsx14(Text, { children: " " }),
|
|
17833
18414
|
/* @__PURE__ */ jsxs12(Text, { bold: true, backgroundColor: sectionBg(1), color: sectionColor(1), children: [
|
|
17834
18415
|
sectionMarker(1),
|
|
17835
|
-
"
|
|
18416
|
+
"Cloud Sync"
|
|
17836
18417
|
] }),
|
|
17837
18418
|
/* @__PURE__ */ jsx14(Text, { children: " " }),
|
|
17838
|
-
/* @__PURE__ */ jsxs12(
|
|
18419
|
+
cloud.configured ? /* @__PURE__ */ jsxs12(Fragment5, { children: [
|
|
18420
|
+
/* @__PURE__ */ jsxs12(Text, { children: [
|
|
18421
|
+
" ",
|
|
18422
|
+
/* @__PURE__ */ jsx14(Text, { color: GREEN, children: statusDot(true) }),
|
|
18423
|
+
" Status: ",
|
|
18424
|
+
/* @__PURE__ */ jsx14(Text, { color: GREEN, children: "connected" })
|
|
18425
|
+
] }),
|
|
18426
|
+
/* @__PURE__ */ jsxs12(Text, { children: [
|
|
18427
|
+
" ",
|
|
18428
|
+
"Endpoint: ",
|
|
18429
|
+
/* @__PURE__ */ jsx14(Text, { color: GREEN, children: cloud.endpoint })
|
|
18430
|
+
] }),
|
|
18431
|
+
/* @__PURE__ */ jsxs12(Text, { children: [
|
|
18432
|
+
" ",
|
|
18433
|
+
"API key: ",
|
|
18434
|
+
/* @__PURE__ */ jsx14(Text, { color: DIM, children: cloud.apiKey })
|
|
18435
|
+
] })
|
|
18436
|
+
] }) : /* @__PURE__ */ jsxs12(Text, { children: [
|
|
17839
18437
|
" ",
|
|
17840
|
-
|
|
17841
|
-
|
|
18438
|
+
/* @__PURE__ */ jsx14(Text, { color: DIM, children: statusDot(false) }),
|
|
18439
|
+
" ",
|
|
18440
|
+
/* @__PURE__ */ jsx14(Text, { color: DIM, children: "Not configured \u2014 run /exe-cloud" })
|
|
17842
18441
|
] }),
|
|
17843
|
-
/* @__PURE__ */
|
|
17844
|
-
|
|
17845
|
-
|
|
17846
|
-
|
|
18442
|
+
/* @__PURE__ */ jsx14(Text, { children: " " }),
|
|
18443
|
+
/* @__PURE__ */ jsxs12(Text, { bold: true, backgroundColor: sectionBg(2), color: sectionColor(2), children: [
|
|
18444
|
+
sectionMarker(2),
|
|
18445
|
+
"License"
|
|
17847
18446
|
] }),
|
|
18447
|
+
/* @__PURE__ */ jsx14(Text, { children: " " }),
|
|
17848
18448
|
/* @__PURE__ */ jsxs12(Text, { children: [
|
|
17849
18449
|
" ",
|
|
17850
|
-
"
|
|
17851
|
-
/* @__PURE__ */ jsx14(Text, { color:
|
|
18450
|
+
"Plan: ",
|
|
18451
|
+
/* @__PURE__ */ jsx14(Text, { color: license.plan === "FREE" ? YELLOW : GREEN, children: license.plan })
|
|
17852
18452
|
] }),
|
|
17853
|
-
/* @__PURE__ */ jsxs12(Text, { children: [
|
|
18453
|
+
license.expiresAt && /* @__PURE__ */ jsxs12(Text, { children: [
|
|
17854
18454
|
" ",
|
|
17855
|
-
"
|
|
17856
|
-
/* @__PURE__ */ jsx14(Text, { color:
|
|
17857
|
-
] }),
|
|
17858
|
-
/* @__PURE__ */ jsx14(Text, { children: " " }),
|
|
17859
|
-
/* @__PURE__ */ jsxs12(Text, { bold: true, backgroundColor: sectionBg(2), color: sectionColor(2), children: [
|
|
17860
|
-
sectionMarker(2),
|
|
17861
|
-
"Runtime"
|
|
18455
|
+
"Expires: ",
|
|
18456
|
+
/* @__PURE__ */ jsx14(Text, { color: GREEN, children: license.expiresAt.split("T")[0] })
|
|
17862
18457
|
] }),
|
|
17863
|
-
/* @__PURE__ */ jsx14(Text, { children: " " }),
|
|
17864
18458
|
/* @__PURE__ */ jsxs12(Text, { children: [
|
|
17865
18459
|
" ",
|
|
17866
|
-
"
|
|
17867
|
-
/* @__PURE__ */ jsx14(Text, { color:
|
|
17868
|
-
" (",
|
|
17869
|
-
runtime.consolidationModel,
|
|
17870
|
-
")"
|
|
18460
|
+
"Devices: ",
|
|
18461
|
+
/* @__PURE__ */ jsx14(Text, { color: GREEN, children: formatLimit(license.deviceLimit) })
|
|
17871
18462
|
] }),
|
|
17872
18463
|
/* @__PURE__ */ jsxs12(Text, { children: [
|
|
17873
18464
|
" ",
|
|
17874
|
-
"
|
|
17875
|
-
/* @__PURE__ */ jsx14(Text, { color:
|
|
17876
|
-
" (threshold: ",
|
|
17877
|
-
runtime.skillThreshold,
|
|
17878
|
-
")"
|
|
18465
|
+
"Employees: ",
|
|
18466
|
+
/* @__PURE__ */ jsx14(Text, { color: GREEN, children: formatLimit(license.employeeLimit) })
|
|
17879
18467
|
] }),
|
|
17880
18468
|
/* @__PURE__ */ jsxs12(Text, { children: [
|
|
17881
18469
|
" ",
|
|
17882
|
-
"
|
|
17883
|
-
/* @__PURE__ */ jsx14(Text, { color:
|
|
18470
|
+
"Memory limit: ",
|
|
18471
|
+
/* @__PURE__ */ jsx14(Text, { color: GREEN, children: formatLimit(license.memoryLimit) })
|
|
17884
18472
|
] }),
|
|
17885
18473
|
/* @__PURE__ */ jsx14(Text, { children: " " }),
|
|
17886
18474
|
/* @__PURE__ */ jsxs12(Text, { bold: true, backgroundColor: sectionBg(3), color: sectionColor(3), children: [
|
|
17887
18475
|
sectionMarker(3),
|
|
17888
|
-
"
|
|
18476
|
+
"System"
|
|
17889
18477
|
] }),
|
|
17890
18478
|
/* @__PURE__ */ jsx14(Text, { children: " " }),
|
|
17891
|
-
|
|
17892
|
-
" ",
|
|
17893
|
-
"Loading..."
|
|
17894
|
-
] }) : employeeModels.length === 0 ? /* @__PURE__ */ jsxs12(Text, { color: "#6B4C9A", children: [
|
|
18479
|
+
/* @__PURE__ */ jsxs12(Text, { children: [
|
|
17895
18480
|
" ",
|
|
17896
|
-
"
|
|
17897
|
-
|
|
18481
|
+
/* @__PURE__ */ jsx14(Text, { color: system.daemon === "running" ? GREEN : DIM, children: statusDot(system.daemon === "running") }),
|
|
18482
|
+
" Daemon: ",
|
|
18483
|
+
/* @__PURE__ */ jsx14(Text, { color: system.daemon === "running" ? GREEN : DIM, children: system.daemon })
|
|
18484
|
+
] }),
|
|
18485
|
+
/* @__PURE__ */ jsxs12(Text, { children: [
|
|
17898
18486
|
" ",
|
|
17899
|
-
|
|
17900
|
-
|
|
17901
|
-
/* @__PURE__ */ jsx14(Text, { color: "#22C55E", children: e.model }),
|
|
17902
|
-
" ",
|
|
17903
|
-
/* @__PURE__ */ jsxs12(Text, { color: "#6B4C9A", children: [
|
|
17904
|
-
"via ",
|
|
17905
|
-
e.provider
|
|
17906
|
-
] })
|
|
17907
|
-
] }, e.name)),
|
|
17908
|
-
/* @__PURE__ */ jsx14(Text, { children: " " }),
|
|
17909
|
-
/* @__PURE__ */ jsxs12(Text, { bold: true, backgroundColor: sectionBg(4), color: sectionColor(4), children: [
|
|
17910
|
-
sectionMarker(4),
|
|
17911
|
-
"Integrations"
|
|
18487
|
+
"Version: ",
|
|
18488
|
+
/* @__PURE__ */ jsx14(Text, { color: GREEN, children: system.version })
|
|
17912
18489
|
] }),
|
|
17913
|
-
/* @__PURE__ */ jsx14(Text, { children: " " }),
|
|
17914
18490
|
/* @__PURE__ */ jsxs12(Text, { children: [
|
|
17915
18491
|
" ",
|
|
17916
|
-
"
|
|
17917
|
-
/* @__PURE__ */ jsx14(Text, { color:
|
|
17918
|
-
claudeCode.installed && /* @__PURE__ */ jsxs12(Text, { color: claudeCode.hooksWired ? "#22C55E" : "#6B4C9A", children: [
|
|
17919
|
-
" \u2014 hooks ",
|
|
17920
|
-
claudeCode.hooksWired ? "wired" : "not wired"
|
|
17921
|
-
] })
|
|
18492
|
+
"Encryption: ",
|
|
18493
|
+
/* @__PURE__ */ jsx14(Text, { color: system.encryption.includes("AES") ? GREEN : DIM, children: system.encryption })
|
|
17922
18494
|
] }),
|
|
17923
18495
|
/* @__PURE__ */ jsxs12(Text, { children: [
|
|
17924
18496
|
" ",
|
|
17925
|
-
"
|
|
17926
|
-
/* @__PURE__ */ jsx14(Text, { color:
|
|
18497
|
+
"Embedding: ",
|
|
18498
|
+
/* @__PURE__ */ jsx14(Text, { color: GREEN, children: system.embeddingModel })
|
|
17927
18499
|
] }),
|
|
17928
18500
|
/* @__PURE__ */ jsxs12(Text, { children: [
|
|
17929
18501
|
" ",
|
|
17930
|
-
"
|
|
17931
|
-
/* @__PURE__ */ jsx14(Text, { color:
|
|
18502
|
+
"DB path: ",
|
|
18503
|
+
/* @__PURE__ */ jsx14(Text, { color: DIM, children: system.dbPath })
|
|
18504
|
+
] }),
|
|
18505
|
+
/* @__PURE__ */ jsx14(Text, { children: " " }),
|
|
18506
|
+
/* @__PURE__ */ jsxs12(Text, { bold: true, backgroundColor: sectionBg(4), color: sectionColor(4), children: [
|
|
18507
|
+
sectionMarker(4),
|
|
18508
|
+
"Gateway"
|
|
18509
|
+
] }),
|
|
18510
|
+
/* @__PURE__ */ jsx14(Text, { children: " " }),
|
|
18511
|
+
anyGateway ? gateway.adapters.map((a) => /* @__PURE__ */ jsxs12(Text, { children: [
|
|
18512
|
+
" ",
|
|
18513
|
+
/* @__PURE__ */ jsx14(Text, { color: statusColor(a.configured), children: statusDot(a.configured) }),
|
|
18514
|
+
" ",
|
|
18515
|
+
a.name,
|
|
18516
|
+
": ",
|
|
18517
|
+
/* @__PURE__ */ jsx14(Text, { color: statusColor(a.configured), children: a.configured ? "configured" : "not configured" })
|
|
18518
|
+
] }, a.name)) : /* @__PURE__ */ jsxs12(Text, { children: [
|
|
18519
|
+
" ",
|
|
18520
|
+
/* @__PURE__ */ jsx14(Text, { color: DIM, children: statusDot(false) }),
|
|
18521
|
+
" ",
|
|
18522
|
+
/* @__PURE__ */ jsx14(Text, { color: DIM, children: "No gateway configured" })
|
|
17932
18523
|
] })
|
|
17933
18524
|
] });
|
|
17934
18525
|
}
|
|
17935
18526
|
|
|
17936
|
-
// src/tui/
|
|
18527
|
+
// src/tui/views/DebugPanel.tsx
|
|
18528
|
+
import React25, { useState as useState15, useEffect as useEffect17 } from "react";
|
|
18529
|
+
init_state_bus();
|
|
17937
18530
|
import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
18531
|
+
var MAX_EVENTS = 50;
|
|
18532
|
+
var DISPLAY_EVENTS = 20;
|
|
18533
|
+
var EVENT_COLORS = {
|
|
18534
|
+
task_completed: "#22C55E",
|
|
18535
|
+
review_created: "#F59E0B",
|
|
18536
|
+
employee_status: "#3B82F6",
|
|
18537
|
+
memory_stored: "#8B5CF6",
|
|
18538
|
+
session_started: "#06B6D4",
|
|
18539
|
+
session_ended: "#EF4444",
|
|
18540
|
+
gateway_message: "#EC4899"
|
|
18541
|
+
};
|
|
18542
|
+
function formatEvent(e) {
|
|
18543
|
+
switch (e.type) {
|
|
18544
|
+
case "task_completed":
|
|
18545
|
+
return `${e.employee}: "${e.result.slice(0, 60)}"`;
|
|
18546
|
+
case "review_created":
|
|
18547
|
+
return `${e.employee} \u2192 ${e.reviewer}`;
|
|
18548
|
+
case "employee_status":
|
|
18549
|
+
return `${e.employee}: ${e.status}`;
|
|
18550
|
+
case "memory_stored":
|
|
18551
|
+
return `${e.agentId} [${e.project}]`;
|
|
18552
|
+
case "session_started":
|
|
18553
|
+
return `${e.employee} (${e.sessionId.slice(0, 8)})`;
|
|
18554
|
+
case "session_ended":
|
|
18555
|
+
return `${e.employee} (${e.sessionId.slice(0, 8)})`;
|
|
18556
|
+
case "gateway_message":
|
|
18557
|
+
return `${e.platform}/${e.senderId} \u2192 ${e.botId}`;
|
|
18558
|
+
}
|
|
18559
|
+
}
|
|
18560
|
+
function DebugPanel() {
|
|
18561
|
+
const [events, setEvents] = useState15([]);
|
|
18562
|
+
useEffect17(() => {
|
|
18563
|
+
let counter = 0;
|
|
18564
|
+
const handler = (event) => {
|
|
18565
|
+
setEvents((prev) => {
|
|
18566
|
+
const next = [...prev, { event, id: counter++ }];
|
|
18567
|
+
return next.slice(-MAX_EVENTS);
|
|
18568
|
+
});
|
|
18569
|
+
};
|
|
18570
|
+
orgBus.onAny(handler);
|
|
18571
|
+
return () => {
|
|
18572
|
+
orgBus.offAny(handler);
|
|
18573
|
+
};
|
|
18574
|
+
}, []);
|
|
18575
|
+
return /* @__PURE__ */ jsxs13(Box_default, { flexDirection: "column", borderStyle: "single", borderColor: "#6B4C9A", flexGrow: 1, paddingX: 1, children: [
|
|
18576
|
+
/* @__PURE__ */ jsx15(Text, { bold: true, color: "#F5D76E", children: "Debug \u2014 Live Events" }),
|
|
18577
|
+
/* @__PURE__ */ jsx15(Text, { color: "#3D3660", children: "\u2500".repeat(40) }),
|
|
18578
|
+
events.length === 0 ? /* @__PURE__ */ jsx15(Text, { color: "#3D3660", children: "Waiting for events..." }) : events.slice(-DISPLAY_EVENTS).map(({ event, id }) => {
|
|
18579
|
+
const time = event.timestamp?.slice(11, 19) ?? "??:??:??";
|
|
18580
|
+
const color = EVENT_COLORS[event.type] ?? "#6B4C9A";
|
|
18581
|
+
const summary = formatEvent(event);
|
|
18582
|
+
return /* @__PURE__ */ jsxs13(Text, { color, children: [
|
|
18583
|
+
"[",
|
|
18584
|
+
time,
|
|
18585
|
+
"] ",
|
|
18586
|
+
event.type,
|
|
18587
|
+
" \u2014 ",
|
|
18588
|
+
summary
|
|
18589
|
+
] }, id);
|
|
18590
|
+
})
|
|
18591
|
+
] });
|
|
18592
|
+
}
|
|
18593
|
+
|
|
18594
|
+
// src/tui/components/HelpOverlay.tsx
|
|
18595
|
+
import React26 from "react";
|
|
18596
|
+
import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
18597
|
+
function HelpOverlay({ tabName, shortcuts }) {
|
|
18598
|
+
return /* @__PURE__ */ jsxs14(
|
|
18599
|
+
Box_default,
|
|
18600
|
+
{
|
|
18601
|
+
flexDirection: "column",
|
|
18602
|
+
borderStyle: "double",
|
|
18603
|
+
borderColor: "#6B4C9A",
|
|
18604
|
+
paddingX: 2,
|
|
18605
|
+
paddingY: 1,
|
|
18606
|
+
width: 50,
|
|
18607
|
+
alignSelf: "center",
|
|
18608
|
+
children: [
|
|
18609
|
+
/* @__PURE__ */ jsxs14(Text, { bold: true, color: "#F5D76E", children: [
|
|
18610
|
+
"Keyboard Shortcuts \u2014 ",
|
|
18611
|
+
tabName
|
|
18612
|
+
] }),
|
|
18613
|
+
/* @__PURE__ */ jsx16(Text, { children: " " }),
|
|
18614
|
+
shortcuts.map((s, i) => /* @__PURE__ */ jsxs14(Box_default, { gap: 1, children: [
|
|
18615
|
+
/* @__PURE__ */ jsx16(Text, { color: "#F5D76E", bold: true, children: s.key.padEnd(10) }),
|
|
18616
|
+
/* @__PURE__ */ jsx16(Text, { color: "#F0EDE8", children: s.description })
|
|
18617
|
+
] }, i)),
|
|
18618
|
+
/* @__PURE__ */ jsx16(Text, { children: " " }),
|
|
18619
|
+
/* @__PURE__ */ jsx16(Text, { bold: true, color: "#F5D76E", children: "Global" }),
|
|
18620
|
+
/* @__PURE__ */ jsx16(Text, { children: " " }),
|
|
18621
|
+
/* @__PURE__ */ jsxs14(Box_default, { gap: 1, children: [
|
|
18622
|
+
/* @__PURE__ */ jsx16(Text, { color: "#F5D76E", bold: true, children: "1-7".padEnd(10) }),
|
|
18623
|
+
/* @__PURE__ */ jsx16(Text, { color: "#F0EDE8", children: "Switch tabs" })
|
|
18624
|
+
] }),
|
|
18625
|
+
/* @__PURE__ */ jsxs14(Box_default, { gap: 1, children: [
|
|
18626
|
+
/* @__PURE__ */ jsx16(Text, { color: "#F5D76E", bold: true, children: "q".padEnd(10) }),
|
|
18627
|
+
/* @__PURE__ */ jsx16(Text, { color: "#F0EDE8", children: "Quit" })
|
|
18628
|
+
] }),
|
|
18629
|
+
/* @__PURE__ */ jsxs14(Box_default, { gap: 1, children: [
|
|
18630
|
+
/* @__PURE__ */ jsx16(Text, { color: "#F5D76E", bold: true, children: "?".padEnd(10) }),
|
|
18631
|
+
/* @__PURE__ */ jsx16(Text, { color: "#F0EDE8", children: "Toggle this help" })
|
|
18632
|
+
] }),
|
|
18633
|
+
/* @__PURE__ */ jsxs14(Box_default, { gap: 1, children: [
|
|
18634
|
+
/* @__PURE__ */ jsx16(Text, { color: "#F5D76E", bold: true, children: "Esc".padEnd(10) }),
|
|
18635
|
+
/* @__PURE__ */ jsx16(Text, { color: "#F0EDE8", children: "Back to sidebar" })
|
|
18636
|
+
] }),
|
|
18637
|
+
/* @__PURE__ */ jsx16(Text, { children: " " }),
|
|
18638
|
+
/* @__PURE__ */ jsx16(Text, { color: "#6B4C9A", children: "Press ? to close" })
|
|
18639
|
+
]
|
|
18640
|
+
}
|
|
18641
|
+
);
|
|
18642
|
+
}
|
|
18643
|
+
|
|
18644
|
+
// src/tui/App.tsx
|
|
18645
|
+
import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
18646
|
+
var TAB_SHORTCUTS = {
|
|
18647
|
+
"command-center": {
|
|
18648
|
+
name: "Command Center",
|
|
18649
|
+
shortcuts: [
|
|
18650
|
+
{ key: "\u2191\u2193", description: "Navigate projects" },
|
|
18651
|
+
{ key: "Enter", description: "Select project" },
|
|
18652
|
+
{ key: "/", description: "Enter chat mode" },
|
|
18653
|
+
{ key: "n", description: "New task" }
|
|
18654
|
+
]
|
|
18655
|
+
},
|
|
18656
|
+
sessions: {
|
|
18657
|
+
name: "Sessions",
|
|
18658
|
+
shortcuts: [
|
|
18659
|
+
{ key: "\u2191\u2193", description: "Navigate sessions" },
|
|
18660
|
+
{ key: "Enter", description: "View session output" },
|
|
18661
|
+
{ key: "k", description: "Kill session" },
|
|
18662
|
+
{ key: "r", description: "Restart agent" }
|
|
18663
|
+
]
|
|
18664
|
+
},
|
|
18665
|
+
tasks: {
|
|
18666
|
+
name: "Tasks",
|
|
18667
|
+
shortcuts: [
|
|
18668
|
+
{ key: "\u2191\u2193", description: "Navigate tasks" },
|
|
18669
|
+
{ key: "Enter", description: "View task detail" },
|
|
18670
|
+
{ key: "n", description: "Create new task" },
|
|
18671
|
+
{ key: "f", description: "Cycle status filter" },
|
|
18672
|
+
{ key: "p", description: "Filter by priority" }
|
|
18673
|
+
]
|
|
18674
|
+
},
|
|
18675
|
+
team: {
|
|
18676
|
+
name: "Team",
|
|
18677
|
+
shortcuts: [
|
|
18678
|
+
{ key: "\u2191\u2193", description: "Navigate employees" },
|
|
18679
|
+
{ key: "Enter", description: "View detail" },
|
|
18680
|
+
{ key: "a", description: "Add employee" },
|
|
18681
|
+
{ key: "s", description: "View sessions" }
|
|
18682
|
+
]
|
|
18683
|
+
},
|
|
18684
|
+
gateway: {
|
|
18685
|
+
name: "Gateway",
|
|
18686
|
+
shortcuts: [
|
|
18687
|
+
{ key: "\u2191\u2193", description: "Navigate sections" },
|
|
18688
|
+
{ key: "f", description: "Cycle platform filter" },
|
|
18689
|
+
{ key: "\u2192", description: "Next conversation" },
|
|
18690
|
+
{ key: "r", description: "Reconnect" }
|
|
18691
|
+
]
|
|
18692
|
+
},
|
|
18693
|
+
wiki: {
|
|
18694
|
+
name: "Wiki",
|
|
18695
|
+
shortcuts: [
|
|
18696
|
+
{ key: "\u2190\u2192", description: "Switch panels" },
|
|
18697
|
+
{ key: "\u2191\u2193", description: "Navigate items" },
|
|
18698
|
+
{ key: "/", description: "Search memories" },
|
|
18699
|
+
{ key: "Enter", description: "Select" }
|
|
18700
|
+
]
|
|
18701
|
+
},
|
|
18702
|
+
settings: {
|
|
18703
|
+
name: "Settings",
|
|
18704
|
+
shortcuts: [
|
|
18705
|
+
{ key: "\u2191\u2193", description: "Navigate sections" },
|
|
18706
|
+
{ key: "Enter", description: "Edit setting" },
|
|
18707
|
+
{ key: "r", description: "Refresh status" }
|
|
18708
|
+
]
|
|
18709
|
+
}
|
|
18710
|
+
};
|
|
17938
18711
|
var isDemo = process.argv.includes("--demo");
|
|
17939
18712
|
process.stderr.write(`[exe-tui] Terminal: ${TERMINAL_TYPE}
|
|
17940
18713
|
`);
|
|
@@ -17961,17 +18734,17 @@ if (!isDemo) {
|
|
|
17961
18734
|
})();
|
|
17962
18735
|
}
|
|
17963
18736
|
function App2() {
|
|
17964
|
-
const [section, setSection] =
|
|
18737
|
+
const [section, setSection] = useState16("command-center");
|
|
17965
18738
|
const { exit } = use_app_default();
|
|
17966
|
-
const [, forceUpdate] =
|
|
17967
|
-
|
|
18739
|
+
const [, forceUpdate] = useState16(0);
|
|
18740
|
+
useEffect18(() => {
|
|
17968
18741
|
const handleResize = () => forceUpdate((n) => n + 1);
|
|
17969
18742
|
process.stdout.on("resize", handleResize);
|
|
17970
18743
|
return () => {
|
|
17971
18744
|
process.stdout.off("resize", handleResize);
|
|
17972
18745
|
};
|
|
17973
18746
|
}, []);
|
|
17974
|
-
useMouseEvent(
|
|
18747
|
+
useMouseEvent(useCallback8((event) => {
|
|
17975
18748
|
if (event.button !== 0) return;
|
|
17976
18749
|
if (event.col <= 26) {
|
|
17977
18750
|
const tabIdx = event.row - 4;
|
|
@@ -17983,22 +18756,33 @@ function App2() {
|
|
|
17983
18756
|
setFocus("content");
|
|
17984
18757
|
}
|
|
17985
18758
|
}, []));
|
|
17986
|
-
const [focus, setFocus] =
|
|
17987
|
-
const [
|
|
17988
|
-
const
|
|
18759
|
+
const [focus, setFocus] = useState16("sidebar");
|
|
18760
|
+
const [showDebug, setShowDebug] = useState16(false);
|
|
18761
|
+
const [showHelp, setShowHelp] = useState16(false);
|
|
18762
|
+
const [focusedProject, setFocusedProject] = useState16(null);
|
|
18763
|
+
const handleSelectProject = useCallback8((projectName) => {
|
|
17989
18764
|
setFocusedProject(projectName);
|
|
17990
18765
|
setSection("sessions");
|
|
17991
18766
|
setFocus("content");
|
|
17992
18767
|
}, []);
|
|
17993
|
-
const handleBackToCommandCenter =
|
|
18768
|
+
const handleBackToCommandCenter = useCallback8(() => {
|
|
17994
18769
|
setSection("command-center");
|
|
17995
18770
|
setFocus("sidebar");
|
|
17996
18771
|
}, []);
|
|
17997
18772
|
use_input_default((input, key) => {
|
|
18773
|
+
if (input === "?" || key.shift && input === "/") {
|
|
18774
|
+
setShowHelp((prev) => !prev);
|
|
18775
|
+
return;
|
|
18776
|
+
}
|
|
17998
18777
|
const idx = parseInt(input, 10);
|
|
17999
18778
|
if (idx >= 1 && idx <= SECTIONS.length) {
|
|
18000
18779
|
setSection(SECTIONS[idx - 1].key);
|
|
18001
18780
|
setFocus("sidebar");
|
|
18781
|
+
setShowHelp(false);
|
|
18782
|
+
return;
|
|
18783
|
+
}
|
|
18784
|
+
if (input === "d" && !key.ctrl) {
|
|
18785
|
+
setShowDebug((prev) => !prev);
|
|
18002
18786
|
return;
|
|
18003
18787
|
}
|
|
18004
18788
|
if (input === "q" && !key.ctrl) {
|
|
@@ -18026,24 +18810,34 @@ function App2() {
|
|
|
18026
18810
|
}
|
|
18027
18811
|
}
|
|
18028
18812
|
});
|
|
18029
|
-
const consumeFocusedProject =
|
|
18813
|
+
const consumeFocusedProject = useCallback8(() => {
|
|
18030
18814
|
setFocusedProject(null);
|
|
18031
18815
|
}, []);
|
|
18032
18816
|
const views = {
|
|
18033
|
-
"command-center": /* @__PURE__ */
|
|
18034
|
-
sessions: /* @__PURE__ */
|
|
18035
|
-
tasks: /* @__PURE__ */
|
|
18036
|
-
team: /* @__PURE__ */
|
|
18037
|
-
|
|
18038
|
-
|
|
18039
|
-
|
|
18817
|
+
"command-center": /* @__PURE__ */ jsx17(CommandCenterView, { onSelectProject: handleSelectProject, isFocused: focus === "content" && section === "command-center", onBack: () => setFocus("sidebar") }),
|
|
18818
|
+
sessions: /* @__PURE__ */ jsx17(SessionsView, { initialProject: focusedProject, onConsumeInitialProject: consumeFocusedProject, onBackToCommandCenter: handleBackToCommandCenter, onBack: () => setFocus("sidebar") }),
|
|
18819
|
+
tasks: /* @__PURE__ */ jsx17(TasksView, { onBack: () => setFocus("sidebar") }),
|
|
18820
|
+
team: /* @__PURE__ */ jsx17(TeamView, { onBack: () => setFocus("sidebar"), onViewSessions: (name) => {
|
|
18821
|
+
setFocusedProject(name);
|
|
18822
|
+
setSection("sessions");
|
|
18823
|
+
setFocus("content");
|
|
18824
|
+
} }),
|
|
18825
|
+
gateway: /* @__PURE__ */ jsx17(GatewayView, { onBack: () => setFocus("sidebar") }),
|
|
18826
|
+
wiki: /* @__PURE__ */ jsx17(WikiView, { onBack: () => setFocus("sidebar") }),
|
|
18827
|
+
settings: /* @__PURE__ */ jsx17(SettingsView, { onBack: () => setFocus("sidebar") })
|
|
18040
18828
|
};
|
|
18041
|
-
return /* @__PURE__ */
|
|
18042
|
-
/* @__PURE__ */
|
|
18043
|
-
/* @__PURE__ */
|
|
18044
|
-
|
|
18829
|
+
return /* @__PURE__ */ jsx17(ErrorBoundary2, { children: /* @__PURE__ */ jsx17(AlternateScreen, { children: /* @__PURE__ */ jsx17(DemoProvider, { demo: isDemo, children: /* @__PURE__ */ jsxs15(Box_default, { flexDirection: "column", flexGrow: 1, children: [
|
|
18830
|
+
/* @__PURE__ */ jsxs15(Box_default, { flexGrow: 1, children: [
|
|
18831
|
+
/* @__PURE__ */ jsx17(Sidebar, { active: section, onSelect: setSection, onQuit: exit, focused: focus === "sidebar" }),
|
|
18832
|
+
showHelp ? /* @__PURE__ */ jsx17(
|
|
18833
|
+
HelpOverlay,
|
|
18834
|
+
{
|
|
18835
|
+
tabName: TAB_SHORTCUTS[section].name,
|
|
18836
|
+
shortcuts: TAB_SHORTCUTS[section].shortcuts
|
|
18837
|
+
}
|
|
18838
|
+
) : showDebug ? /* @__PURE__ */ jsx17(DebugPanel, {}) : views[section]
|
|
18045
18839
|
] }),
|
|
18046
|
-
/* @__PURE__ */
|
|
18840
|
+
/* @__PURE__ */ jsx17(Footer, {})
|
|
18047
18841
|
] }) }) }) });
|
|
18048
18842
|
}
|
|
18049
18843
|
{
|
|
@@ -18061,4 +18855,4 @@ function App2() {
|
|
|
18061
18855
|
stdin.unref = () => stdin;
|
|
18062
18856
|
}
|
|
18063
18857
|
}
|
|
18064
|
-
render_default(/* @__PURE__ */
|
|
18858
|
+
render_default(/* @__PURE__ */ jsx17(App2, {}));
|