@askexenow/exe-os 0.8.41 → 0.8.43
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 +1345 -660
- package/dist/bin/exe-agent.js +20 -1
- package/dist/bin/exe-assign.js +1503 -1343
- package/dist/bin/exe-boot.js +2518 -1798
- package/dist/bin/exe-call.js +39 -1
- package/dist/bin/exe-cloud.js +15 -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 +2500 -1877
- 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 +28 -2
- package/dist/bin/exe-new-employee.js +25 -3
- 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 +62 -26
- 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 +1439 -815
- 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 +1714 -1537
- package/dist/hooks/prompt-submit.js +2658 -1113
- package/dist/hooks/response-ingest-worker.js +170 -6
- 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 +179 -7
- package/dist/index.js +278 -100
- package/dist/lib/cloud-sync.js +28 -2
- 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/license.js +15 -1
- 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 +1825 -1138
- 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 +1452 -644
- 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,
|
|
@@ -1357,7 +1443,21 @@ function getCacheAgeMs() {
|
|
|
1357
1443
|
}
|
|
1358
1444
|
}
|
|
1359
1445
|
async function checkLicense() {
|
|
1360
|
-
|
|
1446
|
+
let key = loadLicense();
|
|
1447
|
+
if (!key) {
|
|
1448
|
+
try {
|
|
1449
|
+
const configPath = path2.join(EXE_AI_DIR, "config.json");
|
|
1450
|
+
if (existsSync3(configPath)) {
|
|
1451
|
+
const raw = JSON.parse(readFileSync3(configPath, "utf8"));
|
|
1452
|
+
const cloud = raw.cloud;
|
|
1453
|
+
if (cloud?.apiKey) {
|
|
1454
|
+
key = cloud.apiKey;
|
|
1455
|
+
saveLicense(key);
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
} catch {
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1361
1461
|
if (!key) return FREE_LICENSE;
|
|
1362
1462
|
const cached = await getCachedLicense();
|
|
1363
1463
|
if (cached && getCacheAgeMs() < CACHE_MAX_AGE_MS) return cached;
|
|
@@ -2711,6 +2811,71 @@ var init_agent_loop = __esm({
|
|
|
2711
2811
|
}
|
|
2712
2812
|
});
|
|
2713
2813
|
|
|
2814
|
+
// src/lib/global-procedures.ts
|
|
2815
|
+
var global_procedures_exports = {};
|
|
2816
|
+
__export(global_procedures_exports, {
|
|
2817
|
+
deactivateGlobalProcedure: () => deactivateGlobalProcedure,
|
|
2818
|
+
getGlobalProceduresBlock: () => getGlobalProceduresBlock,
|
|
2819
|
+
loadGlobalProcedures: () => loadGlobalProcedures,
|
|
2820
|
+
storeGlobalProcedure: () => storeGlobalProcedure
|
|
2821
|
+
});
|
|
2822
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
2823
|
+
async function loadGlobalProcedures() {
|
|
2824
|
+
const client = getClient();
|
|
2825
|
+
const result = await client.execute({
|
|
2826
|
+
sql: "SELECT * FROM global_procedures WHERE active = 1 ORDER BY priority ASC, created_at ASC",
|
|
2827
|
+
args: []
|
|
2828
|
+
});
|
|
2829
|
+
const procedures = result.rows;
|
|
2830
|
+
if (procedures.length > 0) {
|
|
2831
|
+
_cache = procedures.map((p) => `### ${p.title}
|
|
2832
|
+
${p.content}`).join("\n\n");
|
|
2833
|
+
} else {
|
|
2834
|
+
_cache = "";
|
|
2835
|
+
}
|
|
2836
|
+
_cacheLoaded = true;
|
|
2837
|
+
return procedures;
|
|
2838
|
+
}
|
|
2839
|
+
function getGlobalProceduresBlock() {
|
|
2840
|
+
if (!_cacheLoaded) return "";
|
|
2841
|
+
if (!_cache) return "";
|
|
2842
|
+
return `## Organization-Wide Procedures (MANDATORY \u2014 supersedes all other rules)
|
|
2843
|
+
|
|
2844
|
+
${_cache}
|
|
2845
|
+
`;
|
|
2846
|
+
}
|
|
2847
|
+
async function storeGlobalProcedure(input) {
|
|
2848
|
+
const id = randomUUID2();
|
|
2849
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2850
|
+
const client = getClient();
|
|
2851
|
+
await client.execute({
|
|
2852
|
+
sql: `INSERT INTO global_procedures (id, title, content, priority, domain, active, created_at, updated_at)
|
|
2853
|
+
VALUES (?, ?, ?, ?, ?, 1, ?, ?)`,
|
|
2854
|
+
args: [id, input.title, input.content, input.priority ?? "p0", input.domain ?? null, now, now]
|
|
2855
|
+
});
|
|
2856
|
+
await loadGlobalProcedures();
|
|
2857
|
+
return id;
|
|
2858
|
+
}
|
|
2859
|
+
async function deactivateGlobalProcedure(id) {
|
|
2860
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2861
|
+
const client = getClient();
|
|
2862
|
+
const result = await client.execute({
|
|
2863
|
+
sql: "UPDATE global_procedures SET active = 0, updated_at = ? WHERE id = ?",
|
|
2864
|
+
args: [now, id]
|
|
2865
|
+
});
|
|
2866
|
+
await loadGlobalProcedures();
|
|
2867
|
+
return result.rowsAffected > 0;
|
|
2868
|
+
}
|
|
2869
|
+
var _cache, _cacheLoaded;
|
|
2870
|
+
var init_global_procedures = __esm({
|
|
2871
|
+
"src/lib/global-procedures.ts"() {
|
|
2872
|
+
"use strict";
|
|
2873
|
+
init_database();
|
|
2874
|
+
_cache = "";
|
|
2875
|
+
_cacheLoaded = false;
|
|
2876
|
+
}
|
|
2877
|
+
});
|
|
2878
|
+
|
|
2714
2879
|
// src/gateway/providers/anthropic.ts
|
|
2715
2880
|
import Anthropic from "@anthropic-ai/sdk";
|
|
2716
2881
|
var AnthropicProvider;
|
|
@@ -2815,7 +2980,7 @@ var init_anthropic = __esm({
|
|
|
2815
2980
|
|
|
2816
2981
|
// src/gateway/providers/openai-compat.ts
|
|
2817
2982
|
import OpenAI from "openai";
|
|
2818
|
-
import { randomUUID as
|
|
2983
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
2819
2984
|
var OpenAICompatProvider;
|
|
2820
2985
|
var init_openai_compat = __esm({
|
|
2821
2986
|
"src/gateway/providers/openai-compat.ts"() {
|
|
@@ -2932,7 +3097,7 @@ var init_openai_compat = __esm({
|
|
|
2932
3097
|
}
|
|
2933
3098
|
content.push({
|
|
2934
3099
|
type: "tool_use",
|
|
2935
|
-
id: call.id ??
|
|
3100
|
+
id: call.id ?? randomUUID3(),
|
|
2936
3101
|
name: fn.name,
|
|
2937
3102
|
input
|
|
2938
3103
|
});
|
|
@@ -4017,7 +4182,7 @@ var init_employees = __esm({
|
|
|
4017
4182
|
});
|
|
4018
4183
|
|
|
4019
4184
|
// src/lib/task-router.ts
|
|
4020
|
-
import { randomUUID as
|
|
4185
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
4021
4186
|
function resolveBloomRouting(complexity, config = DEFAULT_BLOOM_CONFIG) {
|
|
4022
4187
|
const tier = config.complexityToTier[complexity];
|
|
4023
4188
|
const rule = config.tierRules[tier];
|
|
@@ -4549,6 +4714,61 @@ var init_session_kill_telemetry = __esm({
|
|
|
4549
4714
|
}
|
|
4550
4715
|
});
|
|
4551
4716
|
|
|
4717
|
+
// src/lib/state-bus.ts
|
|
4718
|
+
var StateBus, orgBus;
|
|
4719
|
+
var init_state_bus = __esm({
|
|
4720
|
+
"src/lib/state-bus.ts"() {
|
|
4721
|
+
"use strict";
|
|
4722
|
+
StateBus = class {
|
|
4723
|
+
handlers = /* @__PURE__ */ new Map();
|
|
4724
|
+
globalHandlers = /* @__PURE__ */ new Set();
|
|
4725
|
+
/** Emit an event to all subscribers */
|
|
4726
|
+
emit(event) {
|
|
4727
|
+
const typeHandlers = this.handlers.get(event.type);
|
|
4728
|
+
if (typeHandlers) {
|
|
4729
|
+
for (const handler of typeHandlers) {
|
|
4730
|
+
try {
|
|
4731
|
+
handler(event);
|
|
4732
|
+
} catch {
|
|
4733
|
+
}
|
|
4734
|
+
}
|
|
4735
|
+
}
|
|
4736
|
+
for (const handler of this.globalHandlers) {
|
|
4737
|
+
try {
|
|
4738
|
+
handler(event);
|
|
4739
|
+
} catch {
|
|
4740
|
+
}
|
|
4741
|
+
}
|
|
4742
|
+
}
|
|
4743
|
+
/** Subscribe to a specific event type */
|
|
4744
|
+
on(type, handler) {
|
|
4745
|
+
if (!this.handlers.has(type)) {
|
|
4746
|
+
this.handlers.set(type, /* @__PURE__ */ new Set());
|
|
4747
|
+
}
|
|
4748
|
+
this.handlers.get(type).add(handler);
|
|
4749
|
+
}
|
|
4750
|
+
/** Subscribe to ALL events */
|
|
4751
|
+
onAny(handler) {
|
|
4752
|
+
this.globalHandlers.add(handler);
|
|
4753
|
+
}
|
|
4754
|
+
/** Unsubscribe from a specific event type */
|
|
4755
|
+
off(type, handler) {
|
|
4756
|
+
this.handlers.get(type)?.delete(handler);
|
|
4757
|
+
}
|
|
4758
|
+
/** Unsubscribe from ALL events */
|
|
4759
|
+
offAny(handler) {
|
|
4760
|
+
this.globalHandlers.delete(handler);
|
|
4761
|
+
}
|
|
4762
|
+
/** Remove all listeners */
|
|
4763
|
+
clear() {
|
|
4764
|
+
this.handlers.clear();
|
|
4765
|
+
this.globalHandlers.clear();
|
|
4766
|
+
}
|
|
4767
|
+
};
|
|
4768
|
+
orgBus = new StateBus();
|
|
4769
|
+
}
|
|
4770
|
+
});
|
|
4771
|
+
|
|
4552
4772
|
// src/lib/tasks-crud.ts
|
|
4553
4773
|
import crypto3 from "crypto";
|
|
4554
4774
|
import path15 from "path";
|
|
@@ -4692,9 +4912,15 @@ async function createTaskCore(input) {
|
|
|
4692
4912
|
}
|
|
4693
4913
|
}
|
|
4694
4914
|
const complexity = input.complexity ?? "standard";
|
|
4915
|
+
let sessionScope = null;
|
|
4916
|
+
try {
|
|
4917
|
+
const { resolveExeSession: resolveExeSession2 } = await Promise.resolve().then(() => (init_tmux_routing(), tmux_routing_exports));
|
|
4918
|
+
sessionScope = resolveExeSession2();
|
|
4919
|
+
} catch {
|
|
4920
|
+
}
|
|
4695
4921
|
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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
4922
|
+
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)
|
|
4923
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
4698
4924
|
args: [
|
|
4699
4925
|
id,
|
|
4700
4926
|
input.title,
|
|
@@ -4713,6 +4939,7 @@ async function createTaskCore(input) {
|
|
|
4713
4939
|
input.budgetFallbackModel ?? null,
|
|
4714
4940
|
0,
|
|
4715
4941
|
null,
|
|
4942
|
+
sessionScope,
|
|
4716
4943
|
now,
|
|
4717
4944
|
now
|
|
4718
4945
|
]
|
|
@@ -4757,6 +4984,15 @@ async function listTasks(input) {
|
|
|
4757
4984
|
conditions.push("priority = ?");
|
|
4758
4985
|
args.push(input.priority);
|
|
4759
4986
|
}
|
|
4987
|
+
try {
|
|
4988
|
+
const { resolveExeSession: resolveExeSession2 } = await Promise.resolve().then(() => (init_tmux_routing(), tmux_routing_exports));
|
|
4989
|
+
const session = resolveExeSession2();
|
|
4990
|
+
if (session) {
|
|
4991
|
+
conditions.push("(session_scope IS NULL OR session_scope = ?)");
|
|
4992
|
+
args.push(session);
|
|
4993
|
+
}
|
|
4994
|
+
} catch {
|
|
4995
|
+
}
|
|
4760
4996
|
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
4761
4997
|
const result = await client.execute({
|
|
4762
4998
|
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 +5357,7 @@ var init_tasks_review = __esm({
|
|
|
5121
5357
|
init_tasks_crud();
|
|
5122
5358
|
init_tmux_routing();
|
|
5123
5359
|
init_session_key();
|
|
5360
|
+
init_state_bus();
|
|
5124
5361
|
}
|
|
5125
5362
|
});
|
|
5126
5363
|
|
|
@@ -5285,13 +5522,12 @@ function assertSessionScope(actionType, targetProject) {
|
|
|
5285
5522
|
};
|
|
5286
5523
|
}
|
|
5287
5524
|
process.stderr.write(
|
|
5288
|
-
`[session-scope]
|
|
5525
|
+
`[session-scope] BLOCKED cross-project ${actionType}: session project="${currentProject}" \u2260 target project="${targetProject}"
|
|
5289
5526
|
`
|
|
5290
5527
|
);
|
|
5291
5528
|
return {
|
|
5292
|
-
allowed:
|
|
5293
|
-
|
|
5294
|
-
reason: "cross_session_granted",
|
|
5529
|
+
allowed: false,
|
|
5530
|
+
reason: "cross_session_denied",
|
|
5295
5531
|
currentProject,
|
|
5296
5532
|
targetProject,
|
|
5297
5533
|
targetSession: findSessionForProject(targetProject)?.windowName
|
|
@@ -5317,8 +5553,9 @@ async function dispatchTaskToEmployee(input) {
|
|
|
5317
5553
|
try {
|
|
5318
5554
|
const { assertSessionScope: assertSessionScope2 } = (init_session_scope(), __toCommonJS(session_scope_exports));
|
|
5319
5555
|
const check = assertSessionScope2("dispatch_task", input.projectName);
|
|
5320
|
-
if (check.reason === "
|
|
5556
|
+
if (check.reason === "cross_session_denied") {
|
|
5321
5557
|
crossProject = true;
|
|
5558
|
+
return { dispatched: "skipped", crossProject: true };
|
|
5322
5559
|
}
|
|
5323
5560
|
} catch {
|
|
5324
5561
|
}
|
|
@@ -5781,6 +6018,13 @@ async function updateTask(input) {
|
|
|
5781
6018
|
await cascadeUnblock(taskId, input.baseDir, now);
|
|
5782
6019
|
} catch {
|
|
5783
6020
|
}
|
|
6021
|
+
orgBus.emit({
|
|
6022
|
+
type: "task_completed",
|
|
6023
|
+
taskId,
|
|
6024
|
+
employee: String(row.assigned_to),
|
|
6025
|
+
result: input.result ?? "",
|
|
6026
|
+
timestamp: now
|
|
6027
|
+
});
|
|
5784
6028
|
if (row.parent_task_id) {
|
|
5785
6029
|
try {
|
|
5786
6030
|
await checkSubtaskCompletion(String(row.parent_task_id), String(row.project_name));
|
|
@@ -5848,6 +6092,7 @@ var init_tasks = __esm({
|
|
|
5848
6092
|
init_database();
|
|
5849
6093
|
init_config();
|
|
5850
6094
|
init_notifications();
|
|
6095
|
+
init_state_bus();
|
|
5851
6096
|
init_tasks_crud();
|
|
5852
6097
|
init_tasks_review();
|
|
5853
6098
|
init_tasks_crud();
|
|
@@ -6238,8 +6483,28 @@ function getMySession() {
|
|
|
6238
6483
|
return getTransport().getMySession();
|
|
6239
6484
|
}
|
|
6240
6485
|
function employeeSessionName(employee, exeSession, instance) {
|
|
6486
|
+
if (!/^exe\d+$/.test(exeSession)) {
|
|
6487
|
+
const root = extractRootExe(exeSession);
|
|
6488
|
+
if (root) {
|
|
6489
|
+
process.stderr.write(
|
|
6490
|
+
`[tmux-routing] WARN: exeSession="${exeSession}" is not a root exe session, using "${root}" instead
|
|
6491
|
+
`
|
|
6492
|
+
);
|
|
6493
|
+
exeSession = root;
|
|
6494
|
+
} else {
|
|
6495
|
+
throw new Error(
|
|
6496
|
+
`Invalid exeSession "${exeSession}" \u2014 must be a root exe session (e.g., "exe1"), not an agent session`
|
|
6497
|
+
);
|
|
6498
|
+
}
|
|
6499
|
+
}
|
|
6241
6500
|
const suffix = instance != null && instance > 0 ? String(instance) : "";
|
|
6242
|
-
|
|
6501
|
+
const name = `${employee}${suffix}-${exeSession}`;
|
|
6502
|
+
if (!VALID_SESSION_NAME.test(name)) {
|
|
6503
|
+
throw new Error(
|
|
6504
|
+
`Invalid session name "${name}" \u2014 must match {agent}-exe{N} or {agent}{instance}-exe{N}`
|
|
6505
|
+
);
|
|
6506
|
+
}
|
|
6507
|
+
return name;
|
|
6243
6508
|
}
|
|
6244
6509
|
function parseParentExe(sessionName, agentId) {
|
|
6245
6510
|
const escaped = agentId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -6479,6 +6744,22 @@ function ensureEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
6479
6744
|
error: `Error: pass employee name ('${bare}'), not session name ('${employeeName}')`
|
|
6480
6745
|
};
|
|
6481
6746
|
}
|
|
6747
|
+
if (!/^exe\d+$/.test(exeSession)) {
|
|
6748
|
+
const root = extractRootExe(exeSession);
|
|
6749
|
+
if (root) {
|
|
6750
|
+
process.stderr.write(
|
|
6751
|
+
`[ensureEmployee] WARN: caller passed exeSession="${exeSession}" (not a root exe). Auto-correcting to "${root}".
|
|
6752
|
+
`
|
|
6753
|
+
);
|
|
6754
|
+
exeSession = root;
|
|
6755
|
+
} else {
|
|
6756
|
+
return {
|
|
6757
|
+
status: "failed",
|
|
6758
|
+
sessionName: "",
|
|
6759
|
+
error: `Invalid exeSession "${exeSession}" \u2014 must be a root exe session (e.g., "exe1")`
|
|
6760
|
+
};
|
|
6761
|
+
}
|
|
6762
|
+
}
|
|
6482
6763
|
let effectiveInstance = opts?.instance;
|
|
6483
6764
|
if (effectiveInstance === void 0 && opts?.autoInstance) {
|
|
6484
6765
|
const free = findFreeInstance(
|
|
@@ -6725,7 +7006,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
6725
7006
|
releaseSpawnLock(sessionName);
|
|
6726
7007
|
return { sessionName };
|
|
6727
7008
|
}
|
|
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;
|
|
7009
|
+
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
7010
|
var init_tmux_routing = __esm({
|
|
6730
7011
|
"src/lib/tmux-routing.ts"() {
|
|
6731
7012
|
"use strict";
|
|
@@ -6740,6 +7021,7 @@ var init_tmux_routing = __esm({
|
|
|
6740
7021
|
SPAWN_LOCK_DIR = path20.join(os6.homedir(), ".exe-os", "spawn-locks");
|
|
6741
7022
|
SESSION_CACHE = path20.join(os6.homedir(), ".exe-os", "session-cache");
|
|
6742
7023
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
7024
|
+
VALID_SESSION_NAME = /^[a-z]+-exe\d+$|^[a-z]+\d+-exe\d+$/;
|
|
6743
7025
|
VERIFY_PANE_LINES = 200;
|
|
6744
7026
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
6745
7027
|
INTERCOM_LOG2 = path20.join(os6.homedir(), ".exe-os", "intercom.log");
|
|
@@ -7908,6 +8190,11 @@ async function initStore(options) {
|
|
|
7908
8190
|
"version-query"
|
|
7909
8191
|
);
|
|
7910
8192
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
8193
|
+
try {
|
|
8194
|
+
const { loadGlobalProcedures: loadGlobalProcedures2 } = await Promise.resolve().then(() => (init_global_procedures(), global_procedures_exports));
|
|
8195
|
+
await loadGlobalProcedures2();
|
|
8196
|
+
} catch {
|
|
8197
|
+
}
|
|
7911
8198
|
}
|
|
7912
8199
|
function classifyTier(record) {
|
|
7913
8200
|
if (record.tool_name === "commit_to_long_term_memory" && (record.importance ?? 0) >= 8) return 1;
|
|
@@ -7949,6 +8236,12 @@ async function writeMemory(record) {
|
|
|
7949
8236
|
supersedes_id: record.supersedes_id ?? null
|
|
7950
8237
|
};
|
|
7951
8238
|
_pendingRecords.push(dbRow);
|
|
8239
|
+
orgBus.emit({
|
|
8240
|
+
type: "memory_stored",
|
|
8241
|
+
agentId: record.agent_id,
|
|
8242
|
+
project: record.project_name,
|
|
8243
|
+
timestamp: record.timestamp
|
|
8244
|
+
});
|
|
7952
8245
|
const MAX_PENDING = 1e3;
|
|
7953
8246
|
if (_pendingRecords.length > MAX_PENDING) {
|
|
7954
8247
|
const dropped = _pendingRecords.length - MAX_PENDING;
|
|
@@ -8294,6 +8587,7 @@ var init_store = __esm({
|
|
|
8294
8587
|
init_database();
|
|
8295
8588
|
init_keychain();
|
|
8296
8589
|
init_config();
|
|
8590
|
+
init_state_bus();
|
|
8297
8591
|
INIT_MAX_RETRIES = 3;
|
|
8298
8592
|
INIT_RETRY_DELAY_MS = 1e3;
|
|
8299
8593
|
_pendingRecords = [];
|
|
@@ -8306,7 +8600,7 @@ var init_store = __esm({
|
|
|
8306
8600
|
});
|
|
8307
8601
|
|
|
8308
8602
|
// src/tui/App.tsx
|
|
8309
|
-
import { useState as
|
|
8603
|
+
import { useState as useState16, useEffect as useEffect18, useCallback as useCallback8 } from "react";
|
|
8310
8604
|
|
|
8311
8605
|
// src/tui/ink/render.js
|
|
8312
8606
|
import { Stream } from "stream";
|
|
@@ -14206,61 +14500,64 @@ function Footer() {
|
|
|
14206
14500
|
return () => clearInterval(timer);
|
|
14207
14501
|
}, []);
|
|
14208
14502
|
async function loadFooterData() {
|
|
14209
|
-
|
|
14210
|
-
|
|
14211
|
-
|
|
14212
|
-
|
|
14213
|
-
const
|
|
14214
|
-
|
|
14503
|
+
const { withTrace: withTrace2 } = await Promise.resolve().then(() => (init_telemetry(), telemetry_exports));
|
|
14504
|
+
return withTrace2("tui.footer.loadData", async () => {
|
|
14505
|
+
try {
|
|
14506
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
14507
|
+
const client = getClient2();
|
|
14508
|
+
if (client) {
|
|
14509
|
+
const result = await client.execute("SELECT COUNT(*) as cnt FROM memories");
|
|
14510
|
+
setMemoryCount(Number(result.rows[0]?.cnt ?? 0));
|
|
14511
|
+
}
|
|
14512
|
+
} catch {
|
|
14215
14513
|
}
|
|
14216
|
-
|
|
14217
|
-
|
|
14218
|
-
|
|
14219
|
-
|
|
14220
|
-
|
|
14221
|
-
|
|
14222
|
-
|
|
14223
|
-
|
|
14224
|
-
|
|
14225
|
-
|
|
14514
|
+
try {
|
|
14515
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
14516
|
+
const client = getClient2();
|
|
14517
|
+
if (client) {
|
|
14518
|
+
const result = await client.execute(
|
|
14519
|
+
"SELECT COUNT(*) as cnt FROM tasks WHERE status IN ('open','in_progress')"
|
|
14520
|
+
);
|
|
14521
|
+
setTaskCount(Number(result.rows[0]?.cnt ?? 0));
|
|
14522
|
+
}
|
|
14523
|
+
} catch {
|
|
14226
14524
|
}
|
|
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 {
|
|
14525
|
+
try {
|
|
14526
|
+
const { existsSync: existsSync14 } = await import("fs");
|
|
14527
|
+
const { join } = await import("path");
|
|
14528
|
+
const home = process.env.HOME ?? "";
|
|
14529
|
+
const pidPath = join(home, ".exe-os", "exed.pid");
|
|
14530
|
+
setDaemon(existsSync14(pidPath) ? "running" : "stopped");
|
|
14531
|
+
} catch {
|
|
14532
|
+
setDaemon("unknown");
|
|
14533
|
+
}
|
|
14534
|
+
try {
|
|
14535
|
+
const { checkLicense: checkLicense2 } = await Promise.resolve().then(() => (init_license(), license_exports));
|
|
14536
|
+
const license = await checkLicense2();
|
|
14537
|
+
setPlan(license.plan);
|
|
14538
|
+
} catch {
|
|
14539
|
+
setPlan("free");
|
|
14540
|
+
}
|
|
14541
|
+
try {
|
|
14542
|
+
const { listTmuxSessions: listTmuxSessions2, inTmux: inTmux2 } = await Promise.resolve().then(() => (init_tmux_status(), tmux_status_exports));
|
|
14543
|
+
if (inTmux2()) {
|
|
14544
|
+
const allSessions = listTmuxSessions2();
|
|
14545
|
+
setSessions(allSessions.length);
|
|
14546
|
+
if (!currentSession) {
|
|
14547
|
+
try {
|
|
14548
|
+
const { execSync: execSync10 } = await import("child_process");
|
|
14549
|
+
const name = execSync10("tmux display-message -p '#{session_name}' 2>/dev/null", {
|
|
14550
|
+
encoding: "utf8",
|
|
14551
|
+
timeout: 2e3
|
|
14552
|
+
}).trim();
|
|
14553
|
+
if (name) setCurrentSession(name);
|
|
14554
|
+
} catch {
|
|
14555
|
+
}
|
|
14259
14556
|
}
|
|
14260
14557
|
}
|
|
14558
|
+
} catch {
|
|
14261
14559
|
}
|
|
14262
|
-
}
|
|
14263
|
-
}
|
|
14560
|
+
});
|
|
14264
14561
|
}
|
|
14265
14562
|
return /* @__PURE__ */ jsxs3(Box_default, { flexDirection: "column", children: [
|
|
14266
14563
|
/* @__PURE__ */ jsx5(Text, { color: "#3D3660", children: "\u2500".repeat(process.stdout.columns || 120) }),
|
|
@@ -14301,6 +14598,8 @@ function Footer() {
|
|
|
14301
14598
|
] }),
|
|
14302
14599
|
/* @__PURE__ */ jsx5(Text, { color: "#6B4C9A", children: "1-7 navigate" }),
|
|
14303
14600
|
/* @__PURE__ */ jsx5(Text, { color: "#3D3660", children: "\u2502" }),
|
|
14601
|
+
/* @__PURE__ */ jsx5(Text, { color: "#6B4C9A", children: "d debug" }),
|
|
14602
|
+
/* @__PURE__ */ jsx5(Text, { color: "#3D3660", children: "\u2502" }),
|
|
14304
14603
|
/* @__PURE__ */ jsx5(Text, { color: "#6B4C9A", children: "q quit" })
|
|
14305
14604
|
] })
|
|
14306
14605
|
] })
|
|
@@ -14921,6 +15220,147 @@ function handleEvent(event, addMessage) {
|
|
|
14921
15220
|
}
|
|
14922
15221
|
}
|
|
14923
15222
|
|
|
15223
|
+
// src/lib/employee-templates.ts
|
|
15224
|
+
init_global_procedures();
|
|
15225
|
+
var BASE_OPERATING_PROCEDURES = `
|
|
15226
|
+
EXE OS \u2014 VISION AND NON-NEGOTIABLE PRINCIPLES (above all work):
|
|
15227
|
+
|
|
15228
|
+
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.
|
|
15229
|
+
|
|
15230
|
+
ICP (who we build for):
|
|
15231
|
+
- Solopreneurs, SMB founders, creators with institutional IP
|
|
15232
|
+
- Bootstrapped small e-commerce / fitness creators / influencers
|
|
15233
|
+
- NOT VC-backed startups \u2014 intentionally excluded
|
|
15234
|
+
|
|
15235
|
+
Crown jewels (load-bearing for all three business paths \u2014 never compromise):
|
|
15236
|
+
- Memory sovereignty (user owns everything, E2EE, local-first)
|
|
15237
|
+
- Three-layer cognition (identity/expertise/experience)
|
|
15238
|
+
- MCP contract boundary (surfaces consume memory OS via MCP only \u2014 never direct DB access, never bundled code)
|
|
15239
|
+
- AGPL network boundary for public forks (e.g., exe-crm)
|
|
15240
|
+
|
|
15241
|
+
Three business-model paths (every product decision must serve these):
|
|
15242
|
+
1. B2C direct \u2014 solopreneurs run their own instance (active, current default)
|
|
15243
|
+
2. Agency white-label \u2014 distributors rebrand for their clients (deferred, but branding must be config-driven)
|
|
15244
|
+
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)
|
|
15245
|
+
|
|
15246
|
+
Ethos:
|
|
15247
|
+
- Bootstrapped, profitable, forever. Not a VC-raise.
|
|
15248
|
+
- Founder zero-ego. Distributors and customers are the loudest voice.
|
|
15249
|
+
- Crypto values: big companies should not own consumer/SMB AI.
|
|
15250
|
+
|
|
15251
|
+
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.
|
|
15252
|
+
|
|
15253
|
+
Always reference .planning/ARCHITECTURE.md and .planning/PROJECT.md as source of truth for all architectural and product decisions.
|
|
15254
|
+
|
|
15255
|
+
OPERATING PROCEDURES (mandatory for all employees):
|
|
15256
|
+
|
|
15257
|
+
You report to the COO. All work flows through exe. These procedures are non-negotiable.
|
|
15258
|
+
|
|
15259
|
+
1. BEFORE starting work:
|
|
15260
|
+
- 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.
|
|
15261
|
+
- Check YOUR task folder ONLY: Read exe/<your-name>/ for assigned tasks
|
|
15262
|
+
- 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.
|
|
15263
|
+
- If you have open tasks, work on the highest priority one first
|
|
15264
|
+
- 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.
|
|
15265
|
+
- Update task status to "in_progress" when starting (use update_task MCP tool)
|
|
15266
|
+
- recall_my_memory \u2014 check what you've done before in this project. What patterns, decisions, context exist?
|
|
15267
|
+
- Read the relevant files. Understand what exists before changing anything.
|
|
15268
|
+
|
|
15269
|
+
2. BEFORE marking done \u2014 CHECKPOINT (mandatory, never skip):
|
|
15270
|
+
- Run the tests. If they fail, fix them before reporting done.
|
|
15271
|
+
- Run typecheck if TypeScript. Zero errors.
|
|
15272
|
+
- Verify the change actually works \u2014 run it, check the output, prove it.
|
|
15273
|
+
- If you can't verify, say so explicitly: "Couldn't verify because X."
|
|
15274
|
+
|
|
15275
|
+
3. AFTER completing work \u2014 update_task(done) IMMEDIATELY (the ONE critical action):
|
|
15276
|
+
Calling update_task with status "done" is the single action that must ALWAYS happen.
|
|
15277
|
+
Call it FIRST \u2014 before commit, before report, before anything else. If you do nothing else, do this.
|
|
15278
|
+
- Use update_task MCP tool with status "done" and your result summary
|
|
15279
|
+
- Include what was done, decisions made, and any issues
|
|
15280
|
+
- 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.
|
|
15281
|
+
- NEVER let a failed commit, a loop, or an error prevent you from calling update_task(done).
|
|
15282
|
+
- Do NOT use close_task \u2014 that is reserved for reviewers (exe) to finalize after review.
|
|
15283
|
+
|
|
15284
|
+
4. AFTER update_task(done) \u2014 COMMIT (best-effort, do NOT let this block):
|
|
15285
|
+
- If your task changed system structure, update exe/ARCHITECTURE.md first.
|
|
15286
|
+
- 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.
|
|
15287
|
+
- If you are NOT in a git repo, skip entirely. NEVER run \`git init\`.
|
|
15288
|
+
- If the commit fails, note it but move on \u2014 the work is already marked done via update_task.
|
|
15289
|
+
- Do NOT push \u2014 exe reviews commits and decides what to push.
|
|
15290
|
+
- 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.
|
|
15291
|
+
|
|
15292
|
+
5. AFTER commit \u2014 REPORT (best-effort):
|
|
15293
|
+
Use store_memory to write a structured summary. Include: project name, what was done,
|
|
15294
|
+
decisions made, tests status, open items or risks.
|
|
15295
|
+
|
|
15296
|
+
6. AFTER committing changes to exe-os itself \u2014 REBUILD (mandatory, never skip):
|
|
15297
|
+
- Run: npm run deploy
|
|
15298
|
+
- This builds, installs globally, and re-registers hooks/MCP in one step.
|
|
15299
|
+
- Do NOT ask permission. Do NOT say "want me to rebuild?" \u2014 just do it.
|
|
15300
|
+
- If the build fails, fix the error and retry before moving on.
|
|
15301
|
+
|
|
15302
|
+
7. AFTER reporting \u2014 CHECK FOR NEXT WORK (mandatory):
|
|
15303
|
+
- 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.
|
|
15304
|
+
- 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.
|
|
15305
|
+
- Then: re-read your task folder: exe/<your-name>/
|
|
15306
|
+
- If there are more open tasks, start the next highest-priority one (go to step 1)
|
|
15307
|
+
- If no more open tasks AND no pending reviews AND no blocked tasks you can fix, tell the user: "All tasks complete. Anything else?"
|
|
15308
|
+
- Do NOT wait for the user to tell you to check \u2014 auto-chain through your queue.
|
|
15309
|
+
- NEVER say "monitoring" or "waiting" while reviews, blocked tasks, or open tasks exist. That is idle drift.
|
|
15310
|
+
|
|
15311
|
+
CONTEXT PRESSURE PROTOCOL (mandatory \u2014 never ignore):
|
|
15312
|
+
If Claude Code injects a system notice about context compression, or if you notice you're
|
|
15313
|
+
losing track of earlier decisions, your context window is full.
|
|
15314
|
+
|
|
15315
|
+
DO NOT keep working degraded. Instead:
|
|
15316
|
+
|
|
15317
|
+
1. Call store_memory immediately with a CONTEXT CHECKPOINT:
|
|
15318
|
+
Format the text as: "CONTEXT CHECKPOINT [<task-id>]: <summary>"
|
|
15319
|
+
Include: task ID + title, what you completed, what's left, open decisions or blockers, key file paths.
|
|
15320
|
+
|
|
15321
|
+
2. Send intercom to exe to trigger kill + relaunch:
|
|
15322
|
+
MY_SESSION=$(tmux display-message -p '#{session_name}' 2>/dev/null)
|
|
15323
|
+
EXE_SESSION="\${MY_SESSION#\${AGENT_ID}-}"
|
|
15324
|
+
tmux send-keys -t "$EXE_SESSION" "/exe-intercom context-full: \${AGENT_ID} hit capacity. Checkpoint saved. Resume task <task-id>." Enter
|
|
15325
|
+
|
|
15326
|
+
3. Stop working immediately. Do not attempt to continue with degraded context.
|
|
15327
|
+
|
|
15328
|
+
COMMUNICATION CHAIN \u2014 who you talk to:
|
|
15329
|
+
- You report to the COO. Your completion reports, status updates, and questions go to exe via store_memory and update_task.
|
|
15330
|
+
- 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.
|
|
15331
|
+
- Exception: if the user sends you a direct message in your tmux window, respond to them. But default to reporting through exe.
|
|
15332
|
+
|
|
15333
|
+
SKILL CAPTURE (encouraged, not mandatory):
|
|
15334
|
+
After completing a complex multi-step task (5+ tool calls), consider whether the approach
|
|
15335
|
+
should be saved as a reusable procedure. If the task involved non-obvious steps, error recovery,
|
|
15336
|
+
or a workflow that would help future sessions, use store_behavior with domain='skill' to save it.
|
|
15337
|
+
Format: "SKILL: [name] \u2014 Step 1: ... Step 2: ... Pitfalls: ..."
|
|
15338
|
+
Skip for simple one-offs. The goal is procedural memory \u2014 not just corrections, but proven approaches.
|
|
15339
|
+
|
|
15340
|
+
SPAWNING EMPLOYEES (mandatory \u2014 never bypass):
|
|
15341
|
+
When you need another employee to do work, ALWAYS use create_task MCP tool.
|
|
15342
|
+
create_task auto-spawns the employee session. The task IS the spawn trigger.
|
|
15343
|
+
NEVER manually launch sessions with tmux send-keys or claude -p.
|
|
15344
|
+
NEVER spawn sessions without a task assigned \u2014 idle sessions waste resources.
|
|
15345
|
+
NEVER refuse a dispatched task claiming "not in scope" \u2014 if it's assigned to you, it's your work.
|
|
15346
|
+
|
|
15347
|
+
CREATING TASKS FOR OTHER EMPLOYEES:
|
|
15348
|
+
When you need to assign work to another employee (e.g., CTO assigns to an engineer):
|
|
15349
|
+
- ALWAYS use create_task MCP tool. NEVER write .md files directly to exe/{name}/.
|
|
15350
|
+
- Direct .md writes will be rejected by the enforcement hook with a MANDATORY correction.
|
|
15351
|
+
- create_task creates both the .md file AND the DB row atomically.
|
|
15352
|
+
- Include: title, assignedTo, priority, context, projectName.
|
|
15353
|
+
- For dependencies: include blocked_by with the blocking task's ID or slug.
|
|
15354
|
+
`;
|
|
15355
|
+
var PROCEDURES_MARKER = "EXE OS \u2014 VISION AND NON-NEGOTIABLE PRINCIPLES";
|
|
15356
|
+
function getSessionPrompt(storedPrompt) {
|
|
15357
|
+
const markerIndex = storedPrompt.indexOf(PROCEDURES_MARKER);
|
|
15358
|
+
const rolePrompt = markerIndex >= 0 ? storedPrompt.slice(0, markerIndex).trimEnd() : storedPrompt;
|
|
15359
|
+
const globalBlock = getGlobalProceduresBlock();
|
|
15360
|
+
return `${globalBlock}${rolePrompt}
|
|
15361
|
+
${BASE_OPERATING_PROCEDURES}`;
|
|
15362
|
+
}
|
|
15363
|
+
|
|
14924
15364
|
// src/tui/views/CommandCenter.tsx
|
|
14925
15365
|
import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
14926
15366
|
function CommandCenterView({
|
|
@@ -15044,7 +15484,7 @@ function CommandCenterView({
|
|
|
15044
15484
|
setAgentConfig({
|
|
15045
15485
|
provider,
|
|
15046
15486
|
model,
|
|
15047
|
-
systemPrompt: "You are an AI assistant in the exe-os TUI. Help the user with their questions. Be concise.",
|
|
15487
|
+
systemPrompt: getSessionPrompt("You are an AI assistant in the exe-os TUI. Help the user with their questions. Be concise."),
|
|
15048
15488
|
tools: registry,
|
|
15049
15489
|
hooks: createDefaultHooks2(),
|
|
15050
15490
|
permissions,
|
|
@@ -15165,6 +15605,7 @@ function CommandCenterView({
|
|
|
15165
15605
|
employeeCount: p.employees.length,
|
|
15166
15606
|
activeCount: p.employees.filter((e) => e.status === "active").length,
|
|
15167
15607
|
memoryCount: p.employees.length * 4e3,
|
|
15608
|
+
openTaskCount: Math.floor(p.employees.length * 1.5),
|
|
15168
15609
|
status: p.employees.some((e) => e.status === "active") ? "active" : "idle",
|
|
15169
15610
|
type: p.projectName.startsWith("exe-") ? "code" : "automation",
|
|
15170
15611
|
recentTasks: DEMO_RECENT_TASKS[p.projectName] ?? []
|
|
@@ -15176,6 +15617,7 @@ function CommandCenterView({
|
|
|
15176
15617
|
employeeCount: 0,
|
|
15177
15618
|
activeCount: 0,
|
|
15178
15619
|
memoryCount: 0,
|
|
15620
|
+
openTaskCount: 0,
|
|
15179
15621
|
status: "offline",
|
|
15180
15622
|
type: "reference",
|
|
15181
15623
|
recentTasks: []
|
|
@@ -15190,182 +15632,122 @@ function CommandCenterView({
|
|
|
15190
15632
|
return () => clearInterval(timer);
|
|
15191
15633
|
}, []);
|
|
15192
15634
|
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();
|
|
15635
|
+
const { withTrace: withTrace2 } = await Promise.resolve().then(() => (init_telemetry(), telemetry_exports));
|
|
15636
|
+
return withTrace2("tui.commandCenter.loadData", async () => {
|
|
15213
15637
|
try {
|
|
15214
15638
|
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
15639
|
+
const { listSessions: listSessions2 } = await Promise.resolve().then(() => (init_session_registry(), session_registry_exports));
|
|
15640
|
+
const { listTmuxSessions: listTmuxSessions2, inTmux: inTmux2 } = await Promise.resolve().then(() => (init_tmux_status(), tmux_status_exports));
|
|
15641
|
+
const { loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
15642
|
+
const { existsSync: existsSync14 } = await import("fs");
|
|
15643
|
+
const { join } = await import("path");
|
|
15215
15644
|
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
|
-
}
|
|
15645
|
+
if (!client) {
|
|
15646
|
+
setDbError(true);
|
|
15647
|
+
return;
|
|
15233
15648
|
}
|
|
15234
|
-
|
|
15235
|
-
|
|
15236
|
-
|
|
15237
|
-
|
|
15238
|
-
|
|
15649
|
+
const dbProjects = await client.execute(
|
|
15650
|
+
`SELECT DISTINCT project_name FROM memories WHERE project_name IS NOT NULL AND project_name != ''
|
|
15651
|
+
UNION
|
|
15652
|
+
SELECT DISTINCT project_name FROM tasks WHERE project_name IS NOT NULL AND project_name != ''
|
|
15653
|
+
ORDER BY project_name`
|
|
15654
|
+
);
|
|
15655
|
+
const projectNames = dbProjects.rows.map((r) => String(r.project_name));
|
|
15656
|
+
const memResult = await client.execute(
|
|
15657
|
+
"SELECT project_name, COUNT(*) as cnt FROM memories WHERE project_name IS NOT NULL GROUP BY project_name"
|
|
15658
|
+
);
|
|
15659
|
+
const memoryCounts = /* @__PURE__ */ new Map();
|
|
15660
|
+
for (const row of memResult.rows) {
|
|
15661
|
+
memoryCounts.set(String(row.project_name), Number(row.cnt));
|
|
15662
|
+
}
|
|
15663
|
+
const taskCountResult = await client.execute(
|
|
15664
|
+
"SELECT project_name, COUNT(*) as cnt FROM tasks WHERE status IN ('open', 'in_progress') AND project_name IS NOT NULL GROUP BY project_name"
|
|
15665
|
+
);
|
|
15666
|
+
const openTaskCounts = /* @__PURE__ */ new Map();
|
|
15667
|
+
for (const row of taskCountResult.rows) {
|
|
15668
|
+
openTaskCounts.set(String(row.project_name), Number(row.cnt));
|
|
15669
|
+
}
|
|
15670
|
+
const recentResult = await client.execute(
|
|
15671
|
+
"SELECT project_name, title FROM tasks WHERE status = 'done' AND project_name IS NOT NULL ORDER BY updated_at DESC LIMIT 30"
|
|
15672
|
+
);
|
|
15673
|
+
const recentTasksByProject = /* @__PURE__ */ new Map();
|
|
15674
|
+
for (const row of recentResult.rows) {
|
|
15675
|
+
const name = String(row.project_name);
|
|
15676
|
+
const tasks = recentTasksByProject.get(name) ?? [];
|
|
15677
|
+
if (tasks.length < 3) tasks.push(String(row.title));
|
|
15678
|
+
recentTasksByProject.set(name, tasks);
|
|
15679
|
+
}
|
|
15680
|
+
const registry = listSessions2();
|
|
15681
|
+
const tmuxSessions = inTmux2() ? new Set(listTmuxSessions2()) : /* @__PURE__ */ new Set();
|
|
15682
|
+
const roster = await loadEmployees2();
|
|
15239
15683
|
const employeeNames = roster.map((e) => e.name).filter((n) => n !== "exe");
|
|
15240
|
-
|
|
15241
|
-
for (const
|
|
15242
|
-
if (tmuxSessions.has(
|
|
15684
|
+
const projectSessions = /* @__PURE__ */ new Map();
|
|
15685
|
+
for (const entry of registry) {
|
|
15686
|
+
if (entry.agentId === "exe" && tmuxSessions.has(entry.windowName)) {
|
|
15687
|
+
const projName = entry.projectDir.split("/").filter(Boolean).pop() ?? "";
|
|
15688
|
+
if (projName) {
|
|
15689
|
+
projectSessions.set(projName, { exeSession: entry.windowName, projectDir: entry.projectDir });
|
|
15690
|
+
}
|
|
15691
|
+
}
|
|
15243
15692
|
}
|
|
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
|
-
});
|
|
15693
|
+
const projectList = [];
|
|
15694
|
+
for (const name of projectNames) {
|
|
15695
|
+
const session = projectSessions.get(name);
|
|
15696
|
+
const exeSession = session?.exeSession ?? "";
|
|
15697
|
+
const projectDir = session?.projectDir ?? "";
|
|
15698
|
+
let activeCount = 0;
|
|
15699
|
+
if (exeSession && tmuxSessions.has(exeSession)) {
|
|
15700
|
+
activeCount = 1;
|
|
15701
|
+
for (const empName of employeeNames) {
|
|
15702
|
+
if (tmuxSessions.has(`${empName}-${exeSession}`)) activeCount++;
|
|
15703
|
+
}
|
|
15315
15704
|
}
|
|
15705
|
+
const memoryCount = memoryCounts.get(name) ?? 0;
|
|
15706
|
+
const openTaskCount = openTaskCounts.get(name) ?? 0;
|
|
15707
|
+
const hasGit = projectDir ? existsSync14(join(projectDir, ".git")) : false;
|
|
15708
|
+
const type = hasGit ? "code" : memoryCount > 0 ? "code" : "automation";
|
|
15709
|
+
projectList.push({
|
|
15710
|
+
projectName: name,
|
|
15711
|
+
exeSession,
|
|
15712
|
+
projectDir,
|
|
15713
|
+
employeeCount: activeCount,
|
|
15714
|
+
activeCount,
|
|
15715
|
+
memoryCount,
|
|
15716
|
+
openTaskCount,
|
|
15717
|
+
status: activeCount > 0 ? "active" : "idle",
|
|
15718
|
+
type,
|
|
15719
|
+
recentTasks: recentTasksByProject.get(name) ?? []
|
|
15720
|
+
});
|
|
15316
15721
|
}
|
|
15317
|
-
|
|
15318
|
-
|
|
15319
|
-
|
|
15320
|
-
|
|
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: []
|
|
15722
|
+
projectList.sort((a, b) => {
|
|
15723
|
+
if (a.activeCount > 0 && b.activeCount === 0) return -1;
|
|
15724
|
+
if (a.activeCount === 0 && b.activeCount > 0) return 1;
|
|
15725
|
+
return b.memoryCount - a.memoryCount;
|
|
15330
15726
|
});
|
|
15331
|
-
|
|
15332
|
-
|
|
15333
|
-
|
|
15334
|
-
|
|
15335
|
-
|
|
15336
|
-
|
|
15337
|
-
|
|
15338
|
-
setHealth((h) => ({ ...h, memories: Number(result.rows[0]?.cnt ?? 0) }));
|
|
15727
|
+
setProjects(projectList);
|
|
15728
|
+
const totalResult = await client.execute("SELECT COUNT(*) as cnt FROM memories");
|
|
15729
|
+
setHealth((h) => ({ ...h, memories: Number(totalResult.rows[0]?.cnt ?? 0) }));
|
|
15730
|
+
try {
|
|
15731
|
+
const pidPath = join(process.env.HOME ?? "", ".exe-os", "exed.pid");
|
|
15732
|
+
setHealth((h) => ({ ...h, daemon: existsSync14(pidPath) ? "running" : "stopped" }));
|
|
15733
|
+
} catch {
|
|
15339
15734
|
}
|
|
15340
|
-
|
|
15341
|
-
|
|
15342
|
-
|
|
15343
|
-
|
|
15344
|
-
|
|
15345
|
-
|
|
15346
|
-
|
|
15347
|
-
|
|
15348
|
-
|
|
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
|
-
}
|
|
15735
|
+
const activityResult = await client.execute(
|
|
15736
|
+
"SELECT agent_id, tool_name, project_name, created_at, text FROM memories ORDER BY created_at DESC LIMIT 20"
|
|
15737
|
+
);
|
|
15738
|
+
if (activityResult.rows.length > 0) {
|
|
15739
|
+
setActivity(activityResult.rows.slice(0, 8).map((r) => ({
|
|
15740
|
+
time: new Date(String(r.created_at)).toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit", hour12: false }),
|
|
15741
|
+
agent: String(r.agent_id ?? "system"),
|
|
15742
|
+
action: String(r.text ?? "").slice(0, 60)
|
|
15743
|
+
})));
|
|
15361
15744
|
}
|
|
15362
15745
|
} catch {
|
|
15746
|
+
setDbError(true);
|
|
15747
|
+
} finally {
|
|
15748
|
+
setLoading(false);
|
|
15363
15749
|
}
|
|
15364
|
-
}
|
|
15365
|
-
setDbError(true);
|
|
15366
|
-
} finally {
|
|
15367
|
-
setLoading(false);
|
|
15368
|
-
}
|
|
15750
|
+
});
|
|
15369
15751
|
}
|
|
15370
15752
|
const daemonColor = health.daemon === "running" ? "green" : health.daemon === "stopped" ? "red" : "gray";
|
|
15371
15753
|
const handleChatSubmit = useCallback4((value) => {
|
|
@@ -15457,7 +15839,7 @@ function CommandCenterView({
|
|
|
15457
15839
|
] }),
|
|
15458
15840
|
/* @__PURE__ */ jsx7(Text, { color: "#6B4C9A", children: "\u2191\u2193 navigate | c to chat | Enter to open | Escape to detach" }),
|
|
15459
15841
|
/* @__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: "
|
|
15842
|
+
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
15843
|
const sections = [];
|
|
15462
15844
|
let currentProjects = [];
|
|
15463
15845
|
let sectionKey = 0;
|
|
@@ -15487,9 +15869,9 @@ function CommandCenterView({
|
|
|
15487
15869
|
] })
|
|
15488
15870
|
] }),
|
|
15489
15871
|
/* @__PURE__ */ jsxs5(Text, { color: isSelected ? "#F0EDE8" : "#6B4C9A", children: [
|
|
15490
|
-
entry.
|
|
15872
|
+
entry.openTaskCount,
|
|
15491
15873
|
" ",
|
|
15492
|
-
entry.
|
|
15874
|
+
entry.openTaskCount === 1 ? "task" : "tasks",
|
|
15493
15875
|
" \xB7 ",
|
|
15494
15876
|
entry.memoryCount.toLocaleString(),
|
|
15495
15877
|
" memories"
|
|
@@ -15823,6 +16205,7 @@ function SessionsView({
|
|
|
15823
16205
|
const [viewingEmployee, setViewingEmployee] = useState9(null);
|
|
15824
16206
|
const [viewingProject, setViewingProject] = useState9(null);
|
|
15825
16207
|
const [loading, setLoading] = useState9(!demo);
|
|
16208
|
+
const [sessionError, setSessionError] = useState9(null);
|
|
15826
16209
|
const [tmuxAvailable, setTmuxAvailable] = useState9(true);
|
|
15827
16210
|
const orch = useOrchestrator(!demo);
|
|
15828
16211
|
const [carouselEmployees, setCarouselEmployees] = useState9([]);
|
|
@@ -15998,111 +16381,116 @@ function SessionsView({
|
|
|
15998
16381
|
return ACTIVE_PANE_PATTERN.test(lines.join("\n")) ? "active" : "idle";
|
|
15999
16382
|
}
|
|
16000
16383
|
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();
|
|
16384
|
+
const { withTrace: withTrace2 } = await Promise.resolve().then(() => (init_telemetry(), telemetry_exports));
|
|
16385
|
+
return withTrace2("tui.sessions.loadSessions", async () => {
|
|
16013
16386
|
try {
|
|
16014
|
-
const
|
|
16015
|
-
|
|
16016
|
-
|
|
16017
|
-
});
|
|
16018
|
-
|
|
16019
|
-
|
|
16020
|
-
|
|
16021
|
-
|
|
16022
|
-
}
|
|
16387
|
+
const { listSessions: listSessions2 } = await Promise.resolve().then(() => (init_session_registry(), session_registry_exports));
|
|
16388
|
+
const { listTmuxSessions: listTmuxSessions2, inTmux: inTmux2, capturePaneLines: capturePaneLines2, parseActivity: parseActivity2 } = await Promise.resolve().then(() => (init_tmux_status(), tmux_status_exports));
|
|
16389
|
+
const { loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
16390
|
+
const { execSync: execSync10 } = await import("child_process");
|
|
16391
|
+
if (!inTmux2()) {
|
|
16392
|
+
setTmuxAvailable(false);
|
|
16393
|
+
setProjects([]);
|
|
16394
|
+
return;
|
|
16023
16395
|
}
|
|
16024
|
-
|
|
16025
|
-
|
|
16026
|
-
|
|
16027
|
-
|
|
16028
|
-
|
|
16029
|
-
|
|
16030
|
-
|
|
16031
|
-
|
|
16032
|
-
|
|
16396
|
+
setTmuxAvailable(true);
|
|
16397
|
+
const attachedMap = /* @__PURE__ */ new Map();
|
|
16398
|
+
try {
|
|
16399
|
+
const out = execSync10("tmux list-sessions -F '#{session_name}:#{session_attached}' 2>/dev/null", {
|
|
16400
|
+
encoding: "utf8",
|
|
16401
|
+
timeout: 3e3
|
|
16402
|
+
});
|
|
16403
|
+
for (const line of out.trim().split("\n").filter(Boolean)) {
|
|
16404
|
+
const sepIdx = line.lastIndexOf(":");
|
|
16405
|
+
if (sepIdx > 0) {
|
|
16406
|
+
attachedMap.set(line.slice(0, sepIdx), line.slice(sepIdx + 1) === "1");
|
|
16407
|
+
}
|
|
16408
|
+
}
|
|
16409
|
+
} catch {
|
|
16033
16410
|
}
|
|
16034
|
-
|
|
16035
|
-
|
|
16036
|
-
|
|
16037
|
-
|
|
16411
|
+
const registry = listSessions2();
|
|
16412
|
+
const tmuxSessions = new Set(listTmuxSessions2());
|
|
16413
|
+
const roster = await loadEmployees2();
|
|
16414
|
+
const exeSessions = /* @__PURE__ */ new Map();
|
|
16415
|
+
for (const entry of registry) {
|
|
16416
|
+
if (entry.agentId === "exe" && tmuxSessions.has(entry.windowName)) {
|
|
16417
|
+
exeSessions.set(entry.windowName, entry.projectDir);
|
|
16418
|
+
}
|
|
16038
16419
|
}
|
|
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) : "";
|
|
16420
|
+
for (const s of tmuxSessions) {
|
|
16421
|
+
if (/^exe\d+$/.test(s) && !exeSessions.has(s)) {
|
|
16422
|
+
exeSessions.set(s, "");
|
|
16423
|
+
}
|
|
16050
16424
|
}
|
|
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
|
-
};
|
|
16425
|
+
const projectList = [];
|
|
16426
|
+
for (const [exeSession, projectDir] of exeSessions) {
|
|
16427
|
+
const projectName = projectDir.split("/").filter(Boolean).pop() ?? exeSession;
|
|
16428
|
+
const exeHasSession = tmuxSessions.has(exeSession);
|
|
16429
|
+
let exeStatus = "offline";
|
|
16430
|
+
let exeActivity = "";
|
|
16431
|
+
if (exeHasSession) {
|
|
16432
|
+
const exeLines = capturePaneLines2(exeSession, 10);
|
|
16433
|
+
exeStatus = statusFromPaneLines(exeLines);
|
|
16434
|
+
exeActivity = exeLines.length > 0 ? parseActivity2(exeLines) : "";
|
|
16064
16435
|
}
|
|
16065
|
-
|
|
16436
|
+
const employeeEntries = roster.filter((e) => e.name !== "exe").map((emp) => {
|
|
16437
|
+
const sessionName = `${emp.name}-${exeSession}`;
|
|
16438
|
+
const hasSession = tmuxSessions.has(sessionName);
|
|
16439
|
+
const isCrashed = !hasSession && orch.crashedSessions.includes(emp.name);
|
|
16440
|
+
if (isCrashed) {
|
|
16441
|
+
return {
|
|
16442
|
+
name: emp.name,
|
|
16443
|
+
role: emp.role,
|
|
16444
|
+
status: "crashed",
|
|
16445
|
+
sessionName,
|
|
16446
|
+
activity: "Dead session \u2014 has open tasks",
|
|
16447
|
+
attached: false
|
|
16448
|
+
};
|
|
16449
|
+
}
|
|
16450
|
+
if (!hasSession) {
|
|
16451
|
+
return {
|
|
16452
|
+
name: emp.name,
|
|
16453
|
+
role: emp.role,
|
|
16454
|
+
status: "offline",
|
|
16455
|
+
sessionName,
|
|
16456
|
+
activity: "",
|
|
16457
|
+
attached: false
|
|
16458
|
+
};
|
|
16459
|
+
}
|
|
16460
|
+
const lines = capturePaneLines2(sessionName, 10);
|
|
16066
16461
|
return {
|
|
16067
16462
|
name: emp.name,
|
|
16068
16463
|
role: emp.role,
|
|
16069
|
-
status:
|
|
16464
|
+
status: statusFromPaneLines(lines),
|
|
16070
16465
|
sessionName,
|
|
16071
|
-
activity: "",
|
|
16072
|
-
attached: false
|
|
16466
|
+
activity: lines.length > 0 ? parseActivity2(lines) : "",
|
|
16467
|
+
attached: attachedMap.get(sessionName) ?? false
|
|
16073
16468
|
};
|
|
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: [] });
|
|
16469
|
+
});
|
|
16470
|
+
const employees = [
|
|
16471
|
+
{
|
|
16472
|
+
name: "exe",
|
|
16473
|
+
role: "COO",
|
|
16474
|
+
status: exeStatus,
|
|
16475
|
+
sessionName: exeSession,
|
|
16476
|
+
activity: exeActivity,
|
|
16477
|
+
attached: attachedMap.get(exeSession) ?? false
|
|
16478
|
+
},
|
|
16479
|
+
...employeeEntries
|
|
16480
|
+
];
|
|
16481
|
+
projectList.push({ projectName, exeSession, projectDir, employees });
|
|
16482
|
+
}
|
|
16483
|
+
if (projectList.length === 0) {
|
|
16484
|
+
projectList.push({ projectName: "(no active sessions)", exeSession: "", projectDir: "", employees: [] });
|
|
16485
|
+
}
|
|
16486
|
+
setProjects(projectList);
|
|
16487
|
+
setSessionError(null);
|
|
16488
|
+
} catch (err) {
|
|
16489
|
+
setSessionError(err instanceof Error ? err.message : "Failed to query sessions.");
|
|
16490
|
+
} finally {
|
|
16491
|
+
setLoading(false);
|
|
16100
16492
|
}
|
|
16101
|
-
|
|
16102
|
-
} catch {
|
|
16103
|
-
} finally {
|
|
16104
|
-
setLoading(false);
|
|
16105
|
-
}
|
|
16493
|
+
});
|
|
16106
16494
|
}
|
|
16107
16495
|
if (viewingEmployee) {
|
|
16108
16496
|
const inCarousel = carouselEmployees.length > 0;
|
|
@@ -16184,7 +16572,10 @@ function SessionsView({
|
|
|
16184
16572
|
] })
|
|
16185
16573
|
] }),
|
|
16186
16574
|
/* @__PURE__ */ jsx9(Text, { children: " " }),
|
|
16187
|
-
loading ? /* @__PURE__ */ jsx9(Text, { color: "#6B4C9A", children: "Loading sessions..." }) :
|
|
16575
|
+
loading ? /* @__PURE__ */ jsx9(Text, { color: "#6B4C9A", children: "Loading sessions..." }) : sessionError ? /* @__PURE__ */ jsxs7(Text, { color: "#C91B00", children: [
|
|
16576
|
+
"Failed to query sessions: ",
|
|
16577
|
+
sessionError
|
|
16578
|
+
] }) : !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
16579
|
const isSelected = i === selectedIdx;
|
|
16189
16580
|
const marker = isSelected ? "\u25B8 " : " ";
|
|
16190
16581
|
if (item.type === "project") {
|
|
@@ -16285,7 +16676,7 @@ function TasksView({ onBack }) {
|
|
|
16285
16676
|
const demo = useDemo();
|
|
16286
16677
|
const [allTasks, setAllTasks] = useState10([]);
|
|
16287
16678
|
const [loading, setLoading] = useState10(!demo);
|
|
16288
|
-
const [dbError, setDbError] = useState10(
|
|
16679
|
+
const [dbError, setDbError] = useState10(null);
|
|
16289
16680
|
const [selectedTask, setSelectedTask] = useState10(0);
|
|
16290
16681
|
const [showDetail, setShowDetail] = useState10(false);
|
|
16291
16682
|
const [statusFilter, setStatusFilter] = useState10("all");
|
|
@@ -16357,40 +16748,43 @@ function TasksView({ onBack }) {
|
|
|
16357
16748
|
}
|
|
16358
16749
|
});
|
|
16359
16750
|
async function loadTasks() {
|
|
16360
|
-
|
|
16361
|
-
|
|
16362
|
-
|
|
16363
|
-
|
|
16364
|
-
const
|
|
16365
|
-
|
|
16751
|
+
const { withTrace: withTrace2 } = await Promise.resolve().then(() => (init_telemetry(), telemetry_exports));
|
|
16752
|
+
return withTrace2("tui.tasks.loadTasks", async () => {
|
|
16753
|
+
try {
|
|
16754
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
16755
|
+
const client = getClient2();
|
|
16756
|
+
if (client) {
|
|
16757
|
+
const result = await client.execute(
|
|
16758
|
+
`SELECT id, title, priority, assigned_to, assigned_by, status, project_name, created_at, result
|
|
16366
16759
|
FROM tasks
|
|
16367
16760
|
ORDER BY
|
|
16368
16761
|
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
16762
|
CASE priority WHEN 'p0' THEN 0 WHEN 'p1' THEN 1 WHEN 'p2' THEN 2 ELSE 3 END,
|
|
16370
16763
|
created_at DESC`
|
|
16371
|
-
|
|
16372
|
-
|
|
16373
|
-
|
|
16374
|
-
|
|
16375
|
-
|
|
16376
|
-
|
|
16377
|
-
|
|
16378
|
-
|
|
16379
|
-
|
|
16380
|
-
|
|
16381
|
-
|
|
16382
|
-
|
|
16383
|
-
|
|
16384
|
-
|
|
16385
|
-
|
|
16386
|
-
|
|
16387
|
-
|
|
16764
|
+
);
|
|
16765
|
+
setAllTasks(
|
|
16766
|
+
result.rows.map((r) => ({
|
|
16767
|
+
id: String(r.id ?? ""),
|
|
16768
|
+
priority: String(r.priority ?? "p2").toUpperCase(),
|
|
16769
|
+
title: String(r.title ?? ""),
|
|
16770
|
+
assignee: String(r.assigned_to ?? ""),
|
|
16771
|
+
assignedBy: String(r.assigned_by ?? ""),
|
|
16772
|
+
status: String(r.status ?? "open"),
|
|
16773
|
+
project: String(r.project_name ?? ""),
|
|
16774
|
+
createdAt: String(r.created_at ?? ""),
|
|
16775
|
+
result: String(r.result ?? "")
|
|
16776
|
+
}))
|
|
16777
|
+
);
|
|
16778
|
+
setDbError(null);
|
|
16779
|
+
} else {
|
|
16780
|
+
setDbError("Database client not initialized. Run exe-os setup.");
|
|
16781
|
+
}
|
|
16782
|
+
} catch (err) {
|
|
16783
|
+
setDbError(err instanceof Error ? err.message : "Unknown error");
|
|
16784
|
+
} finally {
|
|
16785
|
+
setLoading(false);
|
|
16388
16786
|
}
|
|
16389
|
-
}
|
|
16390
|
-
setDbError(true);
|
|
16391
|
-
} finally {
|
|
16392
|
-
setLoading(false);
|
|
16393
|
-
}
|
|
16787
|
+
});
|
|
16394
16788
|
}
|
|
16395
16789
|
const selected = taskRows[selectedTask]?.task;
|
|
16396
16790
|
if (showDetail && selected) {
|
|
@@ -16457,7 +16851,10 @@ function TasksView({ onBack }) {
|
|
|
16457
16851
|
filterLabel
|
|
16458
16852
|
] }),
|
|
16459
16853
|
/* @__PURE__ */ jsx10(Text, { children: " " }),
|
|
16460
|
-
loading ? /* @__PURE__ */ jsx10(Text, { color: "#6B4C9A", children: "Loading tasks..." }) : dbError ? /* @__PURE__ */
|
|
16854
|
+
loading ? /* @__PURE__ */ jsx10(Text, { color: "#6B4C9A", children: "Loading tasks..." }) : dbError ? /* @__PURE__ */ jsxs8(Text, { color: "#C91B00", children: [
|
|
16855
|
+
"Failed to load tasks: ",
|
|
16856
|
+
dbError
|
|
16857
|
+
] }) : 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
16858
|
if (row.type === "header") {
|
|
16462
16859
|
return /* @__PURE__ */ jsxs8(Box_default, { marginTop: i > 0 ? 1 : 0, children: [
|
|
16463
16860
|
/* @__PURE__ */ jsx10(Text, { bold: true, color: "#F0EDE8", children: row.project }),
|
|
@@ -16911,6 +17308,31 @@ function GatewayView({ onBack }) {
|
|
|
16911
17308
|
/* @__PURE__ */ jsx11(Text, { color: "#6B4C9A", children: "Loading gateway status..." })
|
|
16912
17309
|
] });
|
|
16913
17310
|
}
|
|
17311
|
+
if (!gateway.running && gateway.gatewayUrl && connectionStatus === "disconnected") {
|
|
17312
|
+
return /* @__PURE__ */ jsxs9(Box_default, { flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
|
|
17313
|
+
/* @__PURE__ */ jsx11(Box_default, { borderStyle: "single", borderColor: "#3D3660", paddingX: 1, alignSelf: "flex-start", children: /* @__PURE__ */ jsx11(Text, { bold: true, children: "Gateway Monitor" }) }),
|
|
17314
|
+
/* @__PURE__ */ jsx11(Text, { children: " " }),
|
|
17315
|
+
/* @__PURE__ */ jsx11(Text, { color: "#C91B00", children: "Gateway connection failed." }),
|
|
17316
|
+
/* @__PURE__ */ jsx11(Text, { children: " " }),
|
|
17317
|
+
/* @__PURE__ */ jsxs9(Text, { color: "#6B4C9A", children: [
|
|
17318
|
+
"Gateway URL: ",
|
|
17319
|
+
/* @__PURE__ */ jsx11(Text, { color: "#F0EDE8", children: gateway.gatewayUrl })
|
|
17320
|
+
] }),
|
|
17321
|
+
/* @__PURE__ */ jsxs9(Text, { color: "#6B4C9A", children: [
|
|
17322
|
+
"Process: ",
|
|
17323
|
+
/* @__PURE__ */ jsx11(Text, { color: "#C91B00", children: "not running" })
|
|
17324
|
+
] }),
|
|
17325
|
+
/* @__PURE__ */ jsx11(Text, { children: " " }),
|
|
17326
|
+
/* @__PURE__ */ jsxs9(Text, { color: "#6B4C9A", children: [
|
|
17327
|
+
"Start the gateway: ",
|
|
17328
|
+
/* @__PURE__ */ jsx11(Text, { bold: true, children: "exe-os gateway" })
|
|
17329
|
+
] }),
|
|
17330
|
+
/* @__PURE__ */ jsxs9(Text, { color: "#6B4C9A", children: [
|
|
17331
|
+
"Or check your config: ",
|
|
17332
|
+
/* @__PURE__ */ jsx11(Text, { bold: true, children: "~/.exe-os/gateway.json" })
|
|
17333
|
+
] })
|
|
17334
|
+
] });
|
|
17335
|
+
}
|
|
16914
17336
|
if (!gateway.running && gateway.adapters.length === 0 && !gateway.gatewayUrl) {
|
|
16915
17337
|
return /* @__PURE__ */ jsxs9(Box_default, { flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
|
|
16916
17338
|
/* @__PURE__ */ jsx11(Box_default, { borderStyle: "single", borderColor: "#3D3660", paddingX: 1, alignSelf: "flex-start", children: /* @__PURE__ */ jsx11(Text, { bold: true, children: "Gateway Monitor" }) }),
|
|
@@ -17099,14 +17521,30 @@ function getAgentStatus(agentId) {
|
|
|
17099
17521
|
// src/tui/views/Team.tsx
|
|
17100
17522
|
import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
17101
17523
|
var DEPRECATED_PROJECTS = /* @__PURE__ */ new Set(["exe-ai-employees"]);
|
|
17102
|
-
function
|
|
17524
|
+
function roleBadgeColor(role) {
|
|
17525
|
+
switch (role.toLowerCase()) {
|
|
17526
|
+
case "coo":
|
|
17527
|
+
return "#F5D76E";
|
|
17528
|
+
// gold
|
|
17529
|
+
case "cto":
|
|
17530
|
+
return "#3B82F6";
|
|
17531
|
+
// blue
|
|
17532
|
+
case "cmo":
|
|
17533
|
+
return "#6B4C9A";
|
|
17534
|
+
// purple
|
|
17535
|
+
default:
|
|
17536
|
+
return "#F0EDE8";
|
|
17537
|
+
}
|
|
17538
|
+
}
|
|
17539
|
+
function TeamView({ onBack, onViewSessions }) {
|
|
17103
17540
|
const demo = useDemo();
|
|
17104
17541
|
const [members, setMembers] = useState12([]);
|
|
17105
17542
|
const [externals, setExternals] = useState12([]);
|
|
17106
17543
|
const [loading, setLoading] = useState12(!demo);
|
|
17107
|
-
const [dbError, setDbError] = useState12(
|
|
17544
|
+
const [dbError, setDbError] = useState12(null);
|
|
17108
17545
|
const [selectedIdx, setSelectedIdx] = useState12(0);
|
|
17109
17546
|
const [showDetail, setShowDetail] = useState12(false);
|
|
17547
|
+
const [showAddHint, setShowAddHint] = useState12(false);
|
|
17110
17548
|
const orch = useOrchestrator(!demo);
|
|
17111
17549
|
const orchEmployeeMap = new Map(orch.employees.map((e) => [e.name, e]));
|
|
17112
17550
|
const allItems = [...members, ...externals.map((e) => ({ ...e, activity: "", memoryCount: 0 }))];
|
|
@@ -17121,7 +17559,7 @@ function TeamView({ onBack }) {
|
|
|
17121
17559
|
const timer = setInterval(loadTeam, 5e3);
|
|
17122
17560
|
return () => clearInterval(timer);
|
|
17123
17561
|
}, []);
|
|
17124
|
-
use_input_default((
|
|
17562
|
+
use_input_default((input, key) => {
|
|
17125
17563
|
if (showDetail) {
|
|
17126
17564
|
if (key.escape) setShowDetail(false);
|
|
17127
17565
|
return;
|
|
@@ -17130,91 +17568,103 @@ function TeamView({ onBack }) {
|
|
|
17130
17568
|
onBack?.();
|
|
17131
17569
|
return;
|
|
17132
17570
|
}
|
|
17571
|
+
if (input === "a") {
|
|
17572
|
+
setShowAddHint(true);
|
|
17573
|
+
setTimeout(() => setShowAddHint(false), 3e3);
|
|
17574
|
+
return;
|
|
17575
|
+
}
|
|
17576
|
+
if (input === "s" && selected) {
|
|
17577
|
+
onViewSessions?.(selected.name);
|
|
17578
|
+
return;
|
|
17579
|
+
}
|
|
17133
17580
|
if (key.upArrow && selectedIdx > 0) setSelectedIdx(selectedIdx - 1);
|
|
17134
17581
|
if (key.downArrow && selectedIdx < allItems.length - 1) setSelectedIdx(selectedIdx + 1);
|
|
17135
17582
|
if (key.return && allItems.length > 0) setShowDetail(true);
|
|
17136
17583
|
});
|
|
17137
17584
|
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();
|
|
17585
|
+
const { withTrace: withTrace2 } = await Promise.resolve().then(() => (init_telemetry(), telemetry_exports));
|
|
17586
|
+
return withTrace2("tui.team.loadTeam", async () => {
|
|
17144
17587
|
try {
|
|
17145
|
-
const {
|
|
17146
|
-
const
|
|
17147
|
-
|
|
17148
|
-
|
|
17149
|
-
|
|
17150
|
-
|
|
17151
|
-
}
|
|
17152
|
-
|
|
17153
|
-
|
|
17154
|
-
|
|
17588
|
+
const { loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
17589
|
+
const roster = await loadEmployees2();
|
|
17590
|
+
let memoryCounts = /* @__PURE__ */ new Map();
|
|
17591
|
+
let projectsByEmployee = /* @__PURE__ */ new Map();
|
|
17592
|
+
let currentTaskByEmployee = /* @__PURE__ */ new Map();
|
|
17593
|
+
try {
|
|
17594
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
17595
|
+
const client = getClient2();
|
|
17596
|
+
if (client) {
|
|
17597
|
+
const memResult = await client.execute("SELECT agent_id, COUNT(*) as cnt FROM memories GROUP BY agent_id");
|
|
17598
|
+
for (const row of memResult.rows) {
|
|
17599
|
+
memoryCounts.set(String(row.agent_id), Number(row.cnt));
|
|
17600
|
+
}
|
|
17601
|
+
for (const emp of roster) {
|
|
17602
|
+
const projResult = await client.execute({
|
|
17603
|
+
sql: `SELECT DISTINCT project_name,
|
|
17155
17604
|
MAX(CASE WHEN status = 'in_progress' THEN 1 WHEN status = 'open' THEN 2 ELSE 3 END) as urgency
|
|
17156
17605
|
FROM tasks WHERE assigned_to = ? AND status IN ('open','in_progress','done')
|
|
17157
17606
|
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
|
-
|
|
17607
|
+
args: [emp.name]
|
|
17608
|
+
});
|
|
17609
|
+
const projects = projResult.rows.filter((r) => !DEPRECATED_PROJECTS.has(String(r.project_name))).map((r) => {
|
|
17610
|
+
const urgency = Number(r.urgency);
|
|
17611
|
+
let pStatus = "idle";
|
|
17612
|
+
if (urgency === 1) pStatus = "active";
|
|
17613
|
+
else if (urgency === 2) pStatus = "has_tasks";
|
|
17614
|
+
return { name: String(r.project_name), status: pStatus };
|
|
17615
|
+
});
|
|
17616
|
+
if (projects.length > 0) projectsByEmployee.set(emp.name, projects);
|
|
17617
|
+
}
|
|
17618
|
+
for (const emp of roster) {
|
|
17619
|
+
const taskResult = await client.execute({
|
|
17620
|
+
sql: "SELECT title FROM tasks WHERE assigned_to = ? AND status = 'in_progress' ORDER BY updated_at DESC LIMIT 1",
|
|
17621
|
+
args: [emp.name]
|
|
17622
|
+
});
|
|
17623
|
+
if (taskResult.rows.length > 0) {
|
|
17624
|
+
currentTaskByEmployee.set(emp.name, String(taskResult.rows[0].title));
|
|
17625
|
+
}
|
|
17176
17626
|
}
|
|
17177
17627
|
}
|
|
17628
|
+
} catch {
|
|
17178
17629
|
}
|
|
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
|
-
})));
|
|
17630
|
+
const teamData = roster.map((emp) => {
|
|
17631
|
+
const agentSt = getAgentStatus(emp.name);
|
|
17632
|
+
return {
|
|
17633
|
+
name: emp.name,
|
|
17634
|
+
role: emp.role,
|
|
17635
|
+
status: agentSt.label,
|
|
17636
|
+
activity: agentSt.label === "active" ? "Processing..." : "",
|
|
17637
|
+
memoryCount: memoryCounts.get(emp.name) ?? 0,
|
|
17638
|
+
projects: projectsByEmployee.get(emp.name),
|
|
17639
|
+
currentTask: currentTaskByEmployee.get(emp.name),
|
|
17640
|
+
sessionName: agentSt.session
|
|
17641
|
+
};
|
|
17642
|
+
});
|
|
17643
|
+
setMembers(teamData);
|
|
17644
|
+
setDbError(null);
|
|
17645
|
+
try {
|
|
17646
|
+
const { existsSync: existsSync14, readFileSync: readFileSync11 } = await import("fs");
|
|
17647
|
+
const { join } = await import("path");
|
|
17648
|
+
const home = process.env.HOME ?? "";
|
|
17649
|
+
const gatewayConfig = join(home, ".exe-os", "gateway.json");
|
|
17650
|
+
if (existsSync14(gatewayConfig)) {
|
|
17651
|
+
const raw = JSON.parse(readFileSync11(gatewayConfig, "utf8"));
|
|
17652
|
+
if (raw.agents && raw.agents.length > 0) {
|
|
17653
|
+
setExternals(raw.agents.map((a) => ({
|
|
17654
|
+
name: a.name,
|
|
17655
|
+
role: a.role ?? "external agent",
|
|
17656
|
+
status: "offline"
|
|
17657
|
+
})));
|
|
17658
|
+
}
|
|
17209
17659
|
}
|
|
17660
|
+
} catch {
|
|
17210
17661
|
}
|
|
17211
|
-
} catch {
|
|
17662
|
+
} catch (err) {
|
|
17663
|
+
setDbError(err instanceof Error ? err.message : "Unknown error");
|
|
17664
|
+
} finally {
|
|
17665
|
+
setLoading(false);
|
|
17212
17666
|
}
|
|
17213
|
-
}
|
|
17214
|
-
setDbError(true);
|
|
17215
|
-
} finally {
|
|
17216
|
-
setLoading(false);
|
|
17217
|
-
}
|
|
17667
|
+
});
|
|
17218
17668
|
}
|
|
17219
17669
|
const totalCount = members.length + externals.length;
|
|
17220
17670
|
const selected = allItems[selectedIdx];
|
|
@@ -17231,7 +17681,7 @@ function TeamView({ onBack }) {
|
|
|
17231
17681
|
/* @__PURE__ */ jsx12(Text, { children: " " }),
|
|
17232
17682
|
/* @__PURE__ */ jsxs10(Text, { children: [
|
|
17233
17683
|
"Role: ",
|
|
17234
|
-
/* @__PURE__ */ jsx12(Text, { bold: true, children: selected.role })
|
|
17684
|
+
/* @__PURE__ */ jsx12(Text, { bold: true, color: roleBadgeColor(selected.role), children: selected.role })
|
|
17235
17685
|
] }),
|
|
17236
17686
|
/* @__PURE__ */ jsxs10(Text, { children: [
|
|
17237
17687
|
"Status: ",
|
|
@@ -17260,8 +17710,9 @@ function TeamView({ onBack }) {
|
|
|
17260
17710
|
/* @__PURE__ */ jsx12(Box_default, { borderStyle: "single", borderColor: "#3D3660", paddingX: 1, alignSelf: "flex-start", children: /* @__PURE__ */ jsx12(Text, { bold: true, children: "Team Roster" }) }),
|
|
17261
17711
|
/* @__PURE__ */ jsxs10(Text, { color: "#6B4C9A", children: [
|
|
17262
17712
|
totalCount,
|
|
17263
|
-
" agents |
|
|
17713
|
+
" agents | \u2191\u2193 navigate | Enter details | a add | s sessions"
|
|
17264
17714
|
] }),
|
|
17715
|
+
showAddHint && /* @__PURE__ */ jsx12(Text, { color: "#F5D76E", children: "Run /exe-new-employee <name> from CLI to add an employee." }),
|
|
17265
17716
|
!demo && orch.pendingReviews > 0 && /* @__PURE__ */ jsxs10(Text, { color: "#6B4C9A", children: [
|
|
17266
17717
|
orch.pendingReviews,
|
|
17267
17718
|
" review(s) pending exe attention"
|
|
@@ -17269,7 +17720,10 @@ function TeamView({ onBack }) {
|
|
|
17269
17720
|
/* @__PURE__ */ jsx12(Text, { children: " " }),
|
|
17270
17721
|
/* @__PURE__ */ jsx12(Text, { bold: true, children: "INTERNAL" }),
|
|
17271
17722
|
/* @__PURE__ */ jsx12(Text, { children: " " }),
|
|
17272
|
-
loading ? /* @__PURE__ */ jsx12(Text, { color: "#6B4C9A", children: " Loading
|
|
17723
|
+
loading ? /* @__PURE__ */ jsx12(Text, { color: "#6B4C9A", children: " Loading employee roster..." }) : dbError ? /* @__PURE__ */ jsxs10(Text, { color: "#C91B00", children: [
|
|
17724
|
+
" Failed to load roster: ",
|
|
17725
|
+
dbError
|
|
17726
|
+
] }) : 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
17727
|
const isSelected = i === selectedIdx;
|
|
17274
17728
|
const orchEmp = orchEmployeeMap.get(m.name);
|
|
17275
17729
|
return /* @__PURE__ */ jsxs10(
|
|
@@ -17285,7 +17739,7 @@ function TeamView({ onBack }) {
|
|
|
17285
17739
|
/* @__PURE__ */ jsxs10(Box_default, { gap: 1, children: [
|
|
17286
17740
|
/* @__PURE__ */ jsx12(StatusDot, { status: m.status, showLabel: false }),
|
|
17287
17741
|
/* @__PURE__ */ jsx12(Text, { bold: true, color: isSelected ? "#F5D76E" : "#F0EDE8", children: m.name }),
|
|
17288
|
-
/* @__PURE__ */ jsxs10(Text, { color: isSelected ? "#F5D76E" :
|
|
17742
|
+
/* @__PURE__ */ jsxs10(Text, { color: isSelected ? "#F5D76E" : roleBadgeColor(m.role), children: [
|
|
17289
17743
|
"(",
|
|
17290
17744
|
m.role,
|
|
17291
17745
|
")"
|
|
@@ -17358,6 +17812,33 @@ import TextInput2 from "ink-text-input";
|
|
|
17358
17812
|
import { Fragment as Fragment4, jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
17359
17813
|
var PANELS = ["Workspaces", "Documents", "Chat"];
|
|
17360
17814
|
var MAX_VISIBLE_MESSAGES = 12;
|
|
17815
|
+
var DEMO_SEARCH_RESULTS = [
|
|
17816
|
+
{ 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" },
|
|
17817
|
+
{ 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" },
|
|
17818
|
+
{ 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" },
|
|
17819
|
+
{ 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" },
|
|
17820
|
+
{ 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" }
|
|
17821
|
+
];
|
|
17822
|
+
function agentColor(agentId) {
|
|
17823
|
+
switch (agentId.toLowerCase()) {
|
|
17824
|
+
case "exe":
|
|
17825
|
+
return "#F5D76E";
|
|
17826
|
+
case "yoshi":
|
|
17827
|
+
return "#3B82F6";
|
|
17828
|
+
case "mari":
|
|
17829
|
+
return "#6B4C9A";
|
|
17830
|
+
default:
|
|
17831
|
+
return "#F0EDE8";
|
|
17832
|
+
}
|
|
17833
|
+
}
|
|
17834
|
+
function formatTimeAgo(iso) {
|
|
17835
|
+
const diff2 = Date.now() - new Date(iso).getTime();
|
|
17836
|
+
const hours = Math.floor(diff2 / 36e5);
|
|
17837
|
+
if (hours < 1) return "just now";
|
|
17838
|
+
if (hours < 24) return `${hours}h ago`;
|
|
17839
|
+
const days = Math.floor(hours / 24);
|
|
17840
|
+
return `${days}d ago`;
|
|
17841
|
+
}
|
|
17361
17842
|
function WikiView({ onBack }) {
|
|
17362
17843
|
const demo = useDemo();
|
|
17363
17844
|
const [activePanel, setActivePanel] = useState13("Workspaces");
|
|
@@ -17368,6 +17849,12 @@ function WikiView({ onBack }) {
|
|
|
17368
17849
|
const [chatHistory, setChatHistory] = useState13([]);
|
|
17369
17850
|
const [chatInput, setChatInput] = useState13("");
|
|
17370
17851
|
const [chatFocused, setChatFocused] = useState13(false);
|
|
17852
|
+
const [searchMode, setSearchMode] = useState13(false);
|
|
17853
|
+
const [searchQuery, setSearchQuery] = useState13("");
|
|
17854
|
+
const [searchResults, setSearchResults] = useState13([]);
|
|
17855
|
+
const [searchLoading, setSearchLoading] = useState13(false);
|
|
17856
|
+
const [selectedResultIdx, setSelectedResultIdx] = useState13(0);
|
|
17857
|
+
const [expandedResultIdx, setExpandedResultIdx] = useState13(null);
|
|
17371
17858
|
const [loading, setLoading] = useState13(true);
|
|
17372
17859
|
const [connected, setConnected] = useState13(false);
|
|
17373
17860
|
const [wikiUrl, setWikiUrl] = useState13("");
|
|
@@ -17461,6 +17948,55 @@ function WikiView({ onBack }) {
|
|
|
17461
17948
|
setSending(false);
|
|
17462
17949
|
}
|
|
17463
17950
|
}
|
|
17951
|
+
async function searchMemories2(query) {
|
|
17952
|
+
if (!query.trim()) {
|
|
17953
|
+
setSearchResults([]);
|
|
17954
|
+
return;
|
|
17955
|
+
}
|
|
17956
|
+
if (demo) {
|
|
17957
|
+
const q = query.toLowerCase();
|
|
17958
|
+
setSearchResults(
|
|
17959
|
+
DEMO_SEARCH_RESULTS.filter((r) => r.rawText.toLowerCase().includes(q))
|
|
17960
|
+
);
|
|
17961
|
+
return;
|
|
17962
|
+
}
|
|
17963
|
+
setSearchLoading(true);
|
|
17964
|
+
try {
|
|
17965
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
17966
|
+
const client = getClient2();
|
|
17967
|
+
const result = await client.execute({
|
|
17968
|
+
sql: `SELECT id, agent_id, raw_text, timestamp, project_name
|
|
17969
|
+
FROM memories
|
|
17970
|
+
WHERE raw_text LIKE ? AND COALESCE(status, 'active') = 'active'
|
|
17971
|
+
ORDER BY timestamp DESC LIMIT 20`,
|
|
17972
|
+
args: [`%${query}%`]
|
|
17973
|
+
});
|
|
17974
|
+
setSearchResults(
|
|
17975
|
+
result.rows.map((r) => ({
|
|
17976
|
+
id: String(r.id),
|
|
17977
|
+
agentId: String(r.agent_id),
|
|
17978
|
+
rawText: String(r.raw_text),
|
|
17979
|
+
timestamp: String(r.timestamp),
|
|
17980
|
+
projectName: String(r.project_name ?? "")
|
|
17981
|
+
}))
|
|
17982
|
+
);
|
|
17983
|
+
} catch {
|
|
17984
|
+
setSearchResults([]);
|
|
17985
|
+
} finally {
|
|
17986
|
+
setSearchLoading(false);
|
|
17987
|
+
}
|
|
17988
|
+
}
|
|
17989
|
+
useEffect15(() => {
|
|
17990
|
+
if (!searchMode) return;
|
|
17991
|
+
const timer = setTimeout(() => {
|
|
17992
|
+
searchMemories2(searchQuery);
|
|
17993
|
+
}, 300);
|
|
17994
|
+
return () => clearTimeout(timer);
|
|
17995
|
+
}, [searchQuery, searchMode]);
|
|
17996
|
+
useEffect15(() => {
|
|
17997
|
+
setSelectedResultIdx(0);
|
|
17998
|
+
setExpandedResultIdx(null);
|
|
17999
|
+
}, [searchResults]);
|
|
17464
18000
|
async function selectWorkspace(idx) {
|
|
17465
18001
|
setSelectedWorkspaceIdx(idx);
|
|
17466
18002
|
const ws = workspaces[idx];
|
|
@@ -17481,6 +18017,32 @@ function WikiView({ onBack }) {
|
|
|
17481
18017
|
}
|
|
17482
18018
|
}
|
|
17483
18019
|
use_input_default((input, key) => {
|
|
18020
|
+
if (searchMode && !chatFocused) {
|
|
18021
|
+
if (key.escape) {
|
|
18022
|
+
setSearchMode(false);
|
|
18023
|
+
setSearchQuery("");
|
|
18024
|
+
setSearchResults([]);
|
|
18025
|
+
setExpandedResultIdx(null);
|
|
18026
|
+
return;
|
|
18027
|
+
}
|
|
18028
|
+
if (key.upArrow && selectedResultIdx > 0) {
|
|
18029
|
+
setSelectedResultIdx(selectedResultIdx - 1);
|
|
18030
|
+
setExpandedResultIdx(null);
|
|
18031
|
+
return;
|
|
18032
|
+
}
|
|
18033
|
+
if (key.downArrow && selectedResultIdx < searchResults.length - 1) {
|
|
18034
|
+
setSelectedResultIdx(selectedResultIdx + 1);
|
|
18035
|
+
setExpandedResultIdx(null);
|
|
18036
|
+
return;
|
|
18037
|
+
}
|
|
18038
|
+
if (key.return && searchResults.length > 0) {
|
|
18039
|
+
setExpandedResultIdx(
|
|
18040
|
+
expandedResultIdx === selectedResultIdx ? null : selectedResultIdx
|
|
18041
|
+
);
|
|
18042
|
+
return;
|
|
18043
|
+
}
|
|
18044
|
+
return;
|
|
18045
|
+
}
|
|
17484
18046
|
if (chatFocused) {
|
|
17485
18047
|
if (key.escape) {
|
|
17486
18048
|
setChatFocused(false);
|
|
@@ -17492,6 +18054,13 @@ function WikiView({ onBack }) {
|
|
|
17492
18054
|
}
|
|
17493
18055
|
return;
|
|
17494
18056
|
}
|
|
18057
|
+
if (input === "/" && activePanel !== "Chat") {
|
|
18058
|
+
setSearchMode(true);
|
|
18059
|
+
setSearchQuery("");
|
|
18060
|
+
setSearchResults(demo ? DEMO_SEARCH_RESULTS : []);
|
|
18061
|
+
setExpandedResultIdx(null);
|
|
18062
|
+
return;
|
|
18063
|
+
}
|
|
17495
18064
|
if (key.leftArrow) {
|
|
17496
18065
|
const panelIdx = PANELS.indexOf(activePanel);
|
|
17497
18066
|
if (panelIdx === 0) {
|
|
@@ -17569,9 +18138,53 @@ function WikiView({ onBack }) {
|
|
|
17569
18138
|
/* @__PURE__ */ jsx13(Text, { bold: true, children: selectedWs.name })
|
|
17570
18139
|
] }) : null
|
|
17571
18140
|
] }),
|
|
17572
|
-
/* @__PURE__ */ jsx13(Text, { color: "#6B4C9A", children: "\u2190\u2192 switch panels | \u2191\u2193 navigate | /
|
|
18141
|
+
/* @__PURE__ */ jsx13(Text, { color: "#6B4C9A", children: "\u2190\u2192 switch panels | \u2191\u2193 navigate | / search memories | Enter select" }),
|
|
17573
18142
|
/* @__PURE__ */ jsx13(Text, { children: " " }),
|
|
17574
|
-
/* @__PURE__ */ jsxs11(Box_default, {
|
|
18143
|
+
searchMode ? /* @__PURE__ */ jsxs11(Box_default, { flexDirection: "column", flexGrow: 1, children: [
|
|
18144
|
+
/* @__PURE__ */ jsxs11(Box_default, { paddingX: 1, children: [
|
|
18145
|
+
/* @__PURE__ */ jsx13(Text, { color: "#F5D76E", children: "Search: " }),
|
|
18146
|
+
/* @__PURE__ */ jsx13(
|
|
18147
|
+
TextInput2,
|
|
18148
|
+
{
|
|
18149
|
+
value: searchQuery,
|
|
18150
|
+
onChange: setSearchQuery,
|
|
18151
|
+
placeholder: "search memories...",
|
|
18152
|
+
focus: true
|
|
18153
|
+
}
|
|
18154
|
+
),
|
|
18155
|
+
/* @__PURE__ */ jsx13(Text, { color: "#6B4C9A", children: " (esc to close)" })
|
|
18156
|
+
] }),
|
|
18157
|
+
/* @__PURE__ */ jsx13(Text, { children: " " }),
|
|
18158
|
+
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) => {
|
|
18159
|
+
const isSelected = i === selectedResultIdx;
|
|
18160
|
+
const isExpanded = i === expandedResultIdx;
|
|
18161
|
+
const snippet = result.rawText.slice(0, 80);
|
|
18162
|
+
return /* @__PURE__ */ jsxs11(Box_default, { flexDirection: "column", children: [
|
|
18163
|
+
/* @__PURE__ */ jsxs11(
|
|
18164
|
+
Text,
|
|
18165
|
+
{
|
|
18166
|
+
backgroundColor: isSelected ? "#6B4C9A" : void 0,
|
|
18167
|
+
color: isSelected ? "#F5D76E" : void 0,
|
|
18168
|
+
children: [
|
|
18169
|
+
" ",
|
|
18170
|
+
/* @__PURE__ */ jsx13(Text, { color: isSelected ? "#F5D76E" : agentColor(result.agentId), bold: true, children: result.agentId.padEnd(8) }),
|
|
18171
|
+
/* @__PURE__ */ jsxs11(Text, { color: isSelected ? "#F5D76E" : "#F0EDE8", children: [
|
|
18172
|
+
snippet,
|
|
18173
|
+
result.rawText.length > 80 ? "..." : ""
|
|
18174
|
+
] }),
|
|
18175
|
+
" ",
|
|
18176
|
+
/* @__PURE__ */ jsx13(Text, { color: isSelected ? "#F5D76E" : "#3D3660", dimColor: !isSelected, children: formatTimeAgo(result.timestamp) })
|
|
18177
|
+
]
|
|
18178
|
+
}
|
|
18179
|
+
),
|
|
18180
|
+
isExpanded ? /* @__PURE__ */ jsx13(Box_default, { paddingX: 4, marginBottom: 1, children: /* @__PURE__ */ jsx13(Text, { color: "#F0EDE8", wrap: "wrap", children: result.rawText }) }) : null
|
|
18181
|
+
] }, result.id);
|
|
18182
|
+
}),
|
|
18183
|
+
searchResults.length > 0 ? /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
18184
|
+
/* @__PURE__ */ jsx13(Text, { children: " " }),
|
|
18185
|
+
/* @__PURE__ */ jsx13(Text, { color: "#3D3660", children: " \u2191\u2193 navigate | Enter expand | Esc close" })
|
|
18186
|
+
] }) : null
|
|
18187
|
+
] }) : /* @__PURE__ */ jsxs11(Box_default, { flexGrow: 1, gap: 1, children: [
|
|
17575
18188
|
/* @__PURE__ */ jsxs11(Box_default, { flexDirection: "column", width: "25%", children: [
|
|
17576
18189
|
/* @__PURE__ */ jsxs11(Text, { bold: true, backgroundColor: panelHeaderBg("Workspaces"), color: panelHeaderColor("Workspaces"), children: [
|
|
17577
18190
|
activePanel === "Workspaces" ? "\u25B8 " : " ",
|
|
@@ -17655,50 +18268,41 @@ function WikiView({ onBack }) {
|
|
|
17655
18268
|
}
|
|
17656
18269
|
|
|
17657
18270
|
// src/tui/views/Settings.tsx
|
|
17658
|
-
import React24, { useState as useState14, useEffect as useEffect16 } from "react";
|
|
18271
|
+
import React24, { useState as useState14, useEffect as useEffect16, useCallback as useCallback7 } from "react";
|
|
17659
18272
|
import { Fragment as Fragment5, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
17660
|
-
|
|
18273
|
+
function maskSecret(value) {
|
|
18274
|
+
if (value.length <= 10) return "****";
|
|
18275
|
+
return `${value.slice(0, 6)}...${value.slice(-4)}`;
|
|
18276
|
+
}
|
|
18277
|
+
var SECTION_NAMES = ["Providers", "Cloud Sync", "License", "System", "Gateway"];
|
|
18278
|
+
var GREEN = "#22C55E";
|
|
18279
|
+
var DIM = "#6B4C9A";
|
|
18280
|
+
var YELLOW = "#F5D76E";
|
|
17661
18281
|
function SettingsView({ onBack }) {
|
|
17662
18282
|
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([]);
|
|
18283
|
+
const [cloud, setCloud] = useState14({ configured: false, endpoint: "", apiKey: "" });
|
|
18284
|
+
const [license, setLicense] = useState14({ valid: false, plan: "checking...", expiresAt: null, deviceLimit: 0, employeeLimit: 0, memoryLimit: 0 });
|
|
18285
|
+
const [system, setSystem] = useState14({ daemon: "unknown", version: "...", dbPath: "...", embeddingModel: "...", encryption: "checking..." });
|
|
18286
|
+
const [gateway, setGateway] = useState14({ adapters: [] });
|
|
17678
18287
|
const [selectedSection, setSelectedSection] = useState14(0);
|
|
17679
18288
|
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" }
|
|
18289
|
+
const loadSettings = useCallback7(async () => {
|
|
18290
|
+
setLoading(true);
|
|
18291
|
+
const envKeys = [
|
|
18292
|
+
["Anthropic", "ANTHROPIC_API_KEY"],
|
|
18293
|
+
["OpenCode", "OPENCODE_API_KEY"],
|
|
18294
|
+
["Gemini", "GEMINI_API_KEY"],
|
|
18295
|
+
["OpenAI", "OPENAI_API_KEY"],
|
|
18296
|
+
["Chutes", "CHUTES_API_KEY"]
|
|
17701
18297
|
];
|
|
18298
|
+
const providerList = envKeys.map(([name, envVar]) => {
|
|
18299
|
+
const val = process.env[envVar];
|
|
18300
|
+
return {
|
|
18301
|
+
name,
|
|
18302
|
+
configured: !!val,
|
|
18303
|
+
detail: val ? maskSecret(val) : "not configured"
|
|
18304
|
+
};
|
|
18305
|
+
});
|
|
17702
18306
|
try {
|
|
17703
18307
|
const { execSync: execSync10 } = await import("child_process");
|
|
17704
18308
|
execSync10("curl -s --max-time 1 http://localhost:11434/api/tags", { timeout: 2e3 });
|
|
@@ -17710,112 +18314,101 @@ function SettingsView({ onBack }) {
|
|
|
17710
18314
|
try {
|
|
17711
18315
|
const { existsSync: existsSync14 } = await import("fs");
|
|
17712
18316
|
const { join } = await import("path");
|
|
17713
|
-
const home = process.env.HOME ?? "";
|
|
17714
|
-
const hasKey = existsSync14(join(home, ".exe-os", "master.key"));
|
|
17715
18317
|
const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
17716
18318
|
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
18319
|
const home = process.env.HOME ?? "";
|
|
17741
|
-
const
|
|
17742
|
-
|
|
17743
|
-
|
|
17744
|
-
|
|
17745
|
-
|
|
17746
|
-
|
|
17747
|
-
|
|
17748
|
-
|
|
17749
|
-
|
|
17750
|
-
}
|
|
18320
|
+
const hasKey = existsSync14(join(home, ".exe-os", "master.key"));
|
|
18321
|
+
if (cfg.cloud) {
|
|
18322
|
+
setCloud({
|
|
18323
|
+
configured: true,
|
|
18324
|
+
endpoint: cfg.cloud.endpoint,
|
|
18325
|
+
apiKey: maskSecret(cfg.cloud.apiKey)
|
|
18326
|
+
});
|
|
18327
|
+
} else {
|
|
18328
|
+
setCloud({ configured: false, endpoint: "", apiKey: "" });
|
|
17751
18329
|
}
|
|
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
|
-
}
|
|
18330
|
+
const pidPath = join(home, ".exe-os", "exed.pid");
|
|
18331
|
+
let daemon = "unknown";
|
|
18332
|
+
try {
|
|
18333
|
+
daemon = existsSync14(pidPath) ? "running" : "stopped";
|
|
18334
|
+
} catch {
|
|
17775
18335
|
}
|
|
17776
|
-
|
|
17777
|
-
|
|
17778
|
-
|
|
17779
|
-
|
|
17780
|
-
|
|
17781
|
-
|
|
17782
|
-
|
|
17783
|
-
|
|
17784
|
-
|
|
18336
|
+
let version = "unknown";
|
|
18337
|
+
try {
|
|
18338
|
+
const { readFileSync: readFileSync11 } = await import("fs");
|
|
18339
|
+
const { createRequire } = await import("module");
|
|
18340
|
+
const require2 = createRequire(import.meta.url);
|
|
18341
|
+
const pkgPath = require2.resolve("@askexenow/exe-os/package.json");
|
|
18342
|
+
const pkg = JSON.parse(readFileSync11(pkgPath, "utf8"));
|
|
18343
|
+
version = pkg.version;
|
|
18344
|
+
} catch {
|
|
17785
18345
|
try {
|
|
17786
|
-
const
|
|
17787
|
-
|
|
18346
|
+
const { readFileSync: readFileSync11 } = await import("fs");
|
|
18347
|
+
const { join: joinPath } = await import("path");
|
|
18348
|
+
const pkg = JSON.parse(readFileSync11(joinPath(process.cwd(), "package.json"), "utf8"));
|
|
18349
|
+
version = pkg.version;
|
|
17788
18350
|
} catch {
|
|
17789
|
-
setLicense({ valid: false, detail: "invalid license file" });
|
|
17790
18351
|
}
|
|
17791
|
-
} else {
|
|
17792
|
-
setLicense({ valid: false, detail: "no license" });
|
|
17793
18352
|
}
|
|
18353
|
+
setSystem({
|
|
18354
|
+
daemon,
|
|
18355
|
+
version,
|
|
18356
|
+
dbPath: cfg.dbPath,
|
|
18357
|
+
embeddingModel: cfg.modelFile ?? "unknown",
|
|
18358
|
+
encryption: hasKey ? "SQLCipher AES-256" : "not configured"
|
|
18359
|
+
});
|
|
17794
18360
|
} catch {
|
|
17795
18361
|
}
|
|
17796
18362
|
try {
|
|
17797
|
-
const {
|
|
17798
|
-
const
|
|
17799
|
-
|
|
17800
|
-
|
|
17801
|
-
|
|
17802
|
-
|
|
17803
|
-
|
|
17804
|
-
|
|
17805
|
-
|
|
18363
|
+
const { checkLicense: checkLicense2 } = await Promise.resolve().then(() => (init_license(), license_exports));
|
|
18364
|
+
const lic = await checkLicense2();
|
|
18365
|
+
setLicense({
|
|
18366
|
+
valid: lic.valid,
|
|
18367
|
+
plan: lic.plan.toUpperCase(),
|
|
18368
|
+
expiresAt: lic.expiresAt,
|
|
18369
|
+
deviceLimit: lic.deviceLimit,
|
|
18370
|
+
employeeLimit: lic.employeeLimit,
|
|
18371
|
+
memoryLimit: lic.memoryLimit
|
|
18372
|
+
});
|
|
17806
18373
|
} catch {
|
|
18374
|
+
setLicense({ valid: false, plan: "FREE", expiresAt: null, deviceLimit: 1, employeeLimit: 1, memoryLimit: 5e3 });
|
|
17807
18375
|
}
|
|
17808
|
-
|
|
17809
|
-
|
|
17810
|
-
|
|
17811
|
-
|
|
18376
|
+
const gatewayAdapters = [
|
|
18377
|
+
{ name: "WhatsApp", configured: !!process.env.WHATSAPP_API_TOKEN || !!process.env.WHATSAPP_PHONE_NUMBER_ID },
|
|
18378
|
+
{ name: "Telegram", configured: !!process.env.TELEGRAM_BOT_TOKEN },
|
|
18379
|
+
{ name: "Discord", configured: !!process.env.DISCORD_BOT_TOKEN },
|
|
18380
|
+
{ name: "Slack", configured: !!process.env.SLACK_BOT_TOKEN }
|
|
18381
|
+
];
|
|
18382
|
+
setGateway({ adapters: gatewayAdapters });
|
|
18383
|
+
setLoading(false);
|
|
18384
|
+
}, []);
|
|
18385
|
+
useEffect16(() => {
|
|
18386
|
+
loadSettings();
|
|
18387
|
+
}, [loadSettings]);
|
|
18388
|
+
use_input_default((input, key) => {
|
|
18389
|
+
if (key.leftArrow) {
|
|
18390
|
+
onBack?.();
|
|
18391
|
+
return;
|
|
18392
|
+
}
|
|
18393
|
+
if (key.upArrow && selectedSection > 0) setSelectedSection(selectedSection - 1);
|
|
18394
|
+
if (key.downArrow && selectedSection < SECTION_NAMES.length - 1) setSelectedSection(selectedSection + 1);
|
|
18395
|
+
if (input === "r") {
|
|
18396
|
+
loadSettings();
|
|
18397
|
+
}
|
|
18398
|
+
});
|
|
18399
|
+
const statusDot = (ok) => ok ? "\u2022" : "\u2022";
|
|
18400
|
+
const statusColor = (ok) => ok ? GREEN : DIM;
|
|
18401
|
+
const sectionColor = (idx) => selectedSection === idx ? YELLOW : void 0;
|
|
18402
|
+
const sectionBg = (idx) => selectedSection === idx ? DIM : void 0;
|
|
17812
18403
|
const sectionMarker = (idx) => selectedSection === idx ? "\u25B8 " : " ";
|
|
18404
|
+
const anyGateway = gateway.adapters.some((a) => a.configured);
|
|
18405
|
+
const formatLimit = (n) => n === -1 ? "unlimited" : n.toLocaleString();
|
|
17813
18406
|
return /* @__PURE__ */ jsxs12(Box_default, { flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
|
|
17814
18407
|
/* @__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:
|
|
18408
|
+
/* @__PURE__ */ jsx14(Text, { color: DIM, children: "\u2191\u2193 navigate sections r refresh" }),
|
|
17816
18409
|
/* @__PURE__ */ jsx14(Text, { children: " " }),
|
|
17817
18410
|
loading && /* @__PURE__ */ jsxs12(Fragment5, { children: [
|
|
17818
|
-
/* @__PURE__ */ jsx14(Text, { color:
|
|
18411
|
+
/* @__PURE__ */ jsx14(Text, { color: DIM, children: "Loading settings..." }),
|
|
17819
18412
|
/* @__PURE__ */ jsx14(Text, { children: " " })
|
|
17820
18413
|
] }),
|
|
17821
18414
|
/* @__PURE__ */ jsxs12(Text, { bold: true, backgroundColor: sectionBg(0), color: sectionColor(0), children: [
|
|
@@ -17825,6 +18418,8 @@ function SettingsView({ onBack }) {
|
|
|
17825
18418
|
/* @__PURE__ */ jsx14(Text, { children: " " }),
|
|
17826
18419
|
providers.map((p) => /* @__PURE__ */ jsxs12(Text, { children: [
|
|
17827
18420
|
" ",
|
|
18421
|
+
/* @__PURE__ */ jsx14(Text, { color: statusColor(p.configured), children: statusDot(p.configured) }),
|
|
18422
|
+
" ",
|
|
17828
18423
|
p.name,
|
|
17829
18424
|
": ",
|
|
17830
18425
|
/* @__PURE__ */ jsx14(Text, { color: statusColor(p.configured), children: p.detail })
|
|
@@ -17832,109 +18427,301 @@ function SettingsView({ onBack }) {
|
|
|
17832
18427
|
/* @__PURE__ */ jsx14(Text, { children: " " }),
|
|
17833
18428
|
/* @__PURE__ */ jsxs12(Text, { bold: true, backgroundColor: sectionBg(1), color: sectionColor(1), children: [
|
|
17834
18429
|
sectionMarker(1),
|
|
17835
|
-
"
|
|
18430
|
+
"Cloud Sync"
|
|
17836
18431
|
] }),
|
|
17837
18432
|
/* @__PURE__ */ jsx14(Text, { children: " " }),
|
|
17838
|
-
/* @__PURE__ */ jsxs12(
|
|
18433
|
+
cloud.configured ? /* @__PURE__ */ jsxs12(Fragment5, { children: [
|
|
18434
|
+
/* @__PURE__ */ jsxs12(Text, { children: [
|
|
18435
|
+
" ",
|
|
18436
|
+
/* @__PURE__ */ jsx14(Text, { color: GREEN, children: statusDot(true) }),
|
|
18437
|
+
" Status: ",
|
|
18438
|
+
/* @__PURE__ */ jsx14(Text, { color: GREEN, children: "connected" })
|
|
18439
|
+
] }),
|
|
18440
|
+
/* @__PURE__ */ jsxs12(Text, { children: [
|
|
18441
|
+
" ",
|
|
18442
|
+
"Endpoint: ",
|
|
18443
|
+
/* @__PURE__ */ jsx14(Text, { color: GREEN, children: cloud.endpoint })
|
|
18444
|
+
] }),
|
|
18445
|
+
/* @__PURE__ */ jsxs12(Text, { children: [
|
|
18446
|
+
" ",
|
|
18447
|
+
"API key: ",
|
|
18448
|
+
/* @__PURE__ */ jsx14(Text, { color: DIM, children: cloud.apiKey })
|
|
18449
|
+
] })
|
|
18450
|
+
] }) : /* @__PURE__ */ jsxs12(Text, { children: [
|
|
17839
18451
|
" ",
|
|
17840
|
-
|
|
17841
|
-
|
|
18452
|
+
/* @__PURE__ */ jsx14(Text, { color: DIM, children: statusDot(false) }),
|
|
18453
|
+
" ",
|
|
18454
|
+
/* @__PURE__ */ jsx14(Text, { color: DIM, children: "Not configured \u2014 run /exe-cloud" })
|
|
17842
18455
|
] }),
|
|
17843
|
-
/* @__PURE__ */
|
|
17844
|
-
|
|
17845
|
-
|
|
17846
|
-
|
|
18456
|
+
/* @__PURE__ */ jsx14(Text, { children: " " }),
|
|
18457
|
+
/* @__PURE__ */ jsxs12(Text, { bold: true, backgroundColor: sectionBg(2), color: sectionColor(2), children: [
|
|
18458
|
+
sectionMarker(2),
|
|
18459
|
+
"License"
|
|
17847
18460
|
] }),
|
|
18461
|
+
/* @__PURE__ */ jsx14(Text, { children: " " }),
|
|
17848
18462
|
/* @__PURE__ */ jsxs12(Text, { children: [
|
|
17849
18463
|
" ",
|
|
17850
|
-
"
|
|
17851
|
-
/* @__PURE__ */ jsx14(Text, { color:
|
|
18464
|
+
"Plan: ",
|
|
18465
|
+
/* @__PURE__ */ jsx14(Text, { color: license.plan === "FREE" ? YELLOW : GREEN, children: license.plan })
|
|
17852
18466
|
] }),
|
|
17853
|
-
/* @__PURE__ */ jsxs12(Text, { children: [
|
|
18467
|
+
license.expiresAt && /* @__PURE__ */ jsxs12(Text, { children: [
|
|
17854
18468
|
" ",
|
|
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"
|
|
18469
|
+
"Expires: ",
|
|
18470
|
+
/* @__PURE__ */ jsx14(Text, { color: GREEN, children: license.expiresAt.split("T")[0] })
|
|
17862
18471
|
] }),
|
|
17863
|
-
/* @__PURE__ */ jsx14(Text, { children: " " }),
|
|
17864
18472
|
/* @__PURE__ */ jsxs12(Text, { children: [
|
|
17865
18473
|
" ",
|
|
17866
|
-
"
|
|
17867
|
-
/* @__PURE__ */ jsx14(Text, { color:
|
|
17868
|
-
" (",
|
|
17869
|
-
runtime.consolidationModel,
|
|
17870
|
-
")"
|
|
18474
|
+
"Devices: ",
|
|
18475
|
+
/* @__PURE__ */ jsx14(Text, { color: GREEN, children: formatLimit(license.deviceLimit) })
|
|
17871
18476
|
] }),
|
|
17872
18477
|
/* @__PURE__ */ jsxs12(Text, { children: [
|
|
17873
18478
|
" ",
|
|
17874
|
-
"
|
|
17875
|
-
/* @__PURE__ */ jsx14(Text, { color:
|
|
17876
|
-
" (threshold: ",
|
|
17877
|
-
runtime.skillThreshold,
|
|
17878
|
-
")"
|
|
18479
|
+
"Employees: ",
|
|
18480
|
+
/* @__PURE__ */ jsx14(Text, { color: GREEN, children: formatLimit(license.employeeLimit) })
|
|
17879
18481
|
] }),
|
|
17880
18482
|
/* @__PURE__ */ jsxs12(Text, { children: [
|
|
17881
18483
|
" ",
|
|
17882
|
-
"
|
|
17883
|
-
/* @__PURE__ */ jsx14(Text, { color:
|
|
18484
|
+
"Memory limit: ",
|
|
18485
|
+
/* @__PURE__ */ jsx14(Text, { color: GREEN, children: formatLimit(license.memoryLimit) })
|
|
17884
18486
|
] }),
|
|
17885
18487
|
/* @__PURE__ */ jsx14(Text, { children: " " }),
|
|
17886
18488
|
/* @__PURE__ */ jsxs12(Text, { bold: true, backgroundColor: sectionBg(3), color: sectionColor(3), children: [
|
|
17887
18489
|
sectionMarker(3),
|
|
17888
|
-
"
|
|
18490
|
+
"System"
|
|
17889
18491
|
] }),
|
|
17890
18492
|
/* @__PURE__ */ jsx14(Text, { children: " " }),
|
|
17891
|
-
|
|
17892
|
-
" ",
|
|
17893
|
-
"Loading..."
|
|
17894
|
-
] }) : employeeModels.length === 0 ? /* @__PURE__ */ jsxs12(Text, { color: "#6B4C9A", children: [
|
|
18493
|
+
/* @__PURE__ */ jsxs12(Text, { children: [
|
|
17895
18494
|
" ",
|
|
17896
|
-
"
|
|
17897
|
-
|
|
18495
|
+
/* @__PURE__ */ jsx14(Text, { color: system.daemon === "running" ? GREEN : DIM, children: statusDot(system.daemon === "running") }),
|
|
18496
|
+
" Daemon: ",
|
|
18497
|
+
/* @__PURE__ */ jsx14(Text, { color: system.daemon === "running" ? GREEN : DIM, children: system.daemon })
|
|
18498
|
+
] }),
|
|
18499
|
+
/* @__PURE__ */ jsxs12(Text, { children: [
|
|
17898
18500
|
" ",
|
|
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"
|
|
18501
|
+
"Version: ",
|
|
18502
|
+
/* @__PURE__ */ jsx14(Text, { color: GREEN, children: system.version })
|
|
17912
18503
|
] }),
|
|
17913
|
-
/* @__PURE__ */ jsx14(Text, { children: " " }),
|
|
17914
18504
|
/* @__PURE__ */ jsxs12(Text, { children: [
|
|
17915
18505
|
" ",
|
|
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
|
-
] })
|
|
18506
|
+
"Encryption: ",
|
|
18507
|
+
/* @__PURE__ */ jsx14(Text, { color: system.encryption.includes("AES") ? GREEN : DIM, children: system.encryption })
|
|
17922
18508
|
] }),
|
|
17923
18509
|
/* @__PURE__ */ jsxs12(Text, { children: [
|
|
17924
18510
|
" ",
|
|
17925
|
-
"
|
|
17926
|
-
/* @__PURE__ */ jsx14(Text, { color:
|
|
18511
|
+
"Embedding: ",
|
|
18512
|
+
/* @__PURE__ */ jsx14(Text, { color: GREEN, children: system.embeddingModel })
|
|
17927
18513
|
] }),
|
|
17928
18514
|
/* @__PURE__ */ jsxs12(Text, { children: [
|
|
17929
18515
|
" ",
|
|
17930
|
-
"
|
|
17931
|
-
/* @__PURE__ */ jsx14(Text, { color:
|
|
18516
|
+
"DB path: ",
|
|
18517
|
+
/* @__PURE__ */ jsx14(Text, { color: DIM, children: system.dbPath })
|
|
18518
|
+
] }),
|
|
18519
|
+
/* @__PURE__ */ jsx14(Text, { children: " " }),
|
|
18520
|
+
/* @__PURE__ */ jsxs12(Text, { bold: true, backgroundColor: sectionBg(4), color: sectionColor(4), children: [
|
|
18521
|
+
sectionMarker(4),
|
|
18522
|
+
"Gateway"
|
|
18523
|
+
] }),
|
|
18524
|
+
/* @__PURE__ */ jsx14(Text, { children: " " }),
|
|
18525
|
+
anyGateway ? gateway.adapters.map((a) => /* @__PURE__ */ jsxs12(Text, { children: [
|
|
18526
|
+
" ",
|
|
18527
|
+
/* @__PURE__ */ jsx14(Text, { color: statusColor(a.configured), children: statusDot(a.configured) }),
|
|
18528
|
+
" ",
|
|
18529
|
+
a.name,
|
|
18530
|
+
": ",
|
|
18531
|
+
/* @__PURE__ */ jsx14(Text, { color: statusColor(a.configured), children: a.configured ? "configured" : "not configured" })
|
|
18532
|
+
] }, a.name)) : /* @__PURE__ */ jsxs12(Text, { children: [
|
|
18533
|
+
" ",
|
|
18534
|
+
/* @__PURE__ */ jsx14(Text, { color: DIM, children: statusDot(false) }),
|
|
18535
|
+
" ",
|
|
18536
|
+
/* @__PURE__ */ jsx14(Text, { color: DIM, children: "No gateway configured" })
|
|
17932
18537
|
] })
|
|
17933
18538
|
] });
|
|
17934
18539
|
}
|
|
17935
18540
|
|
|
17936
|
-
// src/tui/
|
|
18541
|
+
// src/tui/views/DebugPanel.tsx
|
|
18542
|
+
import React25, { useState as useState15, useEffect as useEffect17 } from "react";
|
|
18543
|
+
init_state_bus();
|
|
17937
18544
|
import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
18545
|
+
var MAX_EVENTS = 50;
|
|
18546
|
+
var DISPLAY_EVENTS = 20;
|
|
18547
|
+
var EVENT_COLORS = {
|
|
18548
|
+
task_completed: "#22C55E",
|
|
18549
|
+
review_created: "#F59E0B",
|
|
18550
|
+
employee_status: "#3B82F6",
|
|
18551
|
+
memory_stored: "#8B5CF6",
|
|
18552
|
+
session_started: "#06B6D4",
|
|
18553
|
+
session_ended: "#EF4444",
|
|
18554
|
+
gateway_message: "#EC4899"
|
|
18555
|
+
};
|
|
18556
|
+
function formatEvent(e) {
|
|
18557
|
+
switch (e.type) {
|
|
18558
|
+
case "task_completed":
|
|
18559
|
+
return `${e.employee}: "${e.result.slice(0, 60)}"`;
|
|
18560
|
+
case "review_created":
|
|
18561
|
+
return `${e.employee} \u2192 ${e.reviewer}`;
|
|
18562
|
+
case "employee_status":
|
|
18563
|
+
return `${e.employee}: ${e.status}`;
|
|
18564
|
+
case "memory_stored":
|
|
18565
|
+
return `${e.agentId} [${e.project}]`;
|
|
18566
|
+
case "session_started":
|
|
18567
|
+
return `${e.employee} (${e.sessionId.slice(0, 8)})`;
|
|
18568
|
+
case "session_ended":
|
|
18569
|
+
return `${e.employee} (${e.sessionId.slice(0, 8)})`;
|
|
18570
|
+
case "gateway_message":
|
|
18571
|
+
return `${e.platform}/${e.senderId} \u2192 ${e.botId}`;
|
|
18572
|
+
}
|
|
18573
|
+
}
|
|
18574
|
+
function DebugPanel() {
|
|
18575
|
+
const [events, setEvents] = useState15([]);
|
|
18576
|
+
useEffect17(() => {
|
|
18577
|
+
let counter = 0;
|
|
18578
|
+
const handler = (event) => {
|
|
18579
|
+
setEvents((prev) => {
|
|
18580
|
+
const next = [...prev, { event, id: counter++ }];
|
|
18581
|
+
return next.slice(-MAX_EVENTS);
|
|
18582
|
+
});
|
|
18583
|
+
};
|
|
18584
|
+
orgBus.onAny(handler);
|
|
18585
|
+
return () => {
|
|
18586
|
+
orgBus.offAny(handler);
|
|
18587
|
+
};
|
|
18588
|
+
}, []);
|
|
18589
|
+
return /* @__PURE__ */ jsxs13(Box_default, { flexDirection: "column", borderStyle: "single", borderColor: "#6B4C9A", flexGrow: 1, paddingX: 1, children: [
|
|
18590
|
+
/* @__PURE__ */ jsx15(Text, { bold: true, color: "#F5D76E", children: "Debug \u2014 Live Events" }),
|
|
18591
|
+
/* @__PURE__ */ jsx15(Text, { color: "#3D3660", children: "\u2500".repeat(40) }),
|
|
18592
|
+
events.length === 0 ? /* @__PURE__ */ jsx15(Text, { color: "#3D3660", children: "Waiting for events..." }) : events.slice(-DISPLAY_EVENTS).map(({ event, id }) => {
|
|
18593
|
+
const time = event.timestamp?.slice(11, 19) ?? "??:??:??";
|
|
18594
|
+
const color = EVENT_COLORS[event.type] ?? "#6B4C9A";
|
|
18595
|
+
const summary = formatEvent(event);
|
|
18596
|
+
return /* @__PURE__ */ jsxs13(Text, { color, children: [
|
|
18597
|
+
"[",
|
|
18598
|
+
time,
|
|
18599
|
+
"] ",
|
|
18600
|
+
event.type,
|
|
18601
|
+
" \u2014 ",
|
|
18602
|
+
summary
|
|
18603
|
+
] }, id);
|
|
18604
|
+
})
|
|
18605
|
+
] });
|
|
18606
|
+
}
|
|
18607
|
+
|
|
18608
|
+
// src/tui/components/HelpOverlay.tsx
|
|
18609
|
+
import React26 from "react";
|
|
18610
|
+
import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
18611
|
+
function HelpOverlay({ tabName, shortcuts }) {
|
|
18612
|
+
return /* @__PURE__ */ jsxs14(
|
|
18613
|
+
Box_default,
|
|
18614
|
+
{
|
|
18615
|
+
flexDirection: "column",
|
|
18616
|
+
borderStyle: "double",
|
|
18617
|
+
borderColor: "#6B4C9A",
|
|
18618
|
+
paddingX: 2,
|
|
18619
|
+
paddingY: 1,
|
|
18620
|
+
width: 50,
|
|
18621
|
+
alignSelf: "center",
|
|
18622
|
+
children: [
|
|
18623
|
+
/* @__PURE__ */ jsxs14(Text, { bold: true, color: "#F5D76E", children: [
|
|
18624
|
+
"Keyboard Shortcuts \u2014 ",
|
|
18625
|
+
tabName
|
|
18626
|
+
] }),
|
|
18627
|
+
/* @__PURE__ */ jsx16(Text, { children: " " }),
|
|
18628
|
+
shortcuts.map((s, i) => /* @__PURE__ */ jsxs14(Box_default, { gap: 1, children: [
|
|
18629
|
+
/* @__PURE__ */ jsx16(Text, { color: "#F5D76E", bold: true, children: s.key.padEnd(10) }),
|
|
18630
|
+
/* @__PURE__ */ jsx16(Text, { color: "#F0EDE8", children: s.description })
|
|
18631
|
+
] }, i)),
|
|
18632
|
+
/* @__PURE__ */ jsx16(Text, { children: " " }),
|
|
18633
|
+
/* @__PURE__ */ jsx16(Text, { bold: true, color: "#F5D76E", children: "Global" }),
|
|
18634
|
+
/* @__PURE__ */ jsx16(Text, { children: " " }),
|
|
18635
|
+
/* @__PURE__ */ jsxs14(Box_default, { gap: 1, children: [
|
|
18636
|
+
/* @__PURE__ */ jsx16(Text, { color: "#F5D76E", bold: true, children: "1-7".padEnd(10) }),
|
|
18637
|
+
/* @__PURE__ */ jsx16(Text, { color: "#F0EDE8", children: "Switch tabs" })
|
|
18638
|
+
] }),
|
|
18639
|
+
/* @__PURE__ */ jsxs14(Box_default, { gap: 1, children: [
|
|
18640
|
+
/* @__PURE__ */ jsx16(Text, { color: "#F5D76E", bold: true, children: "q".padEnd(10) }),
|
|
18641
|
+
/* @__PURE__ */ jsx16(Text, { color: "#F0EDE8", children: "Quit" })
|
|
18642
|
+
] }),
|
|
18643
|
+
/* @__PURE__ */ jsxs14(Box_default, { gap: 1, children: [
|
|
18644
|
+
/* @__PURE__ */ jsx16(Text, { color: "#F5D76E", bold: true, children: "?".padEnd(10) }),
|
|
18645
|
+
/* @__PURE__ */ jsx16(Text, { color: "#F0EDE8", children: "Toggle this help" })
|
|
18646
|
+
] }),
|
|
18647
|
+
/* @__PURE__ */ jsxs14(Box_default, { gap: 1, children: [
|
|
18648
|
+
/* @__PURE__ */ jsx16(Text, { color: "#F5D76E", bold: true, children: "Esc".padEnd(10) }),
|
|
18649
|
+
/* @__PURE__ */ jsx16(Text, { color: "#F0EDE8", children: "Back to sidebar" })
|
|
18650
|
+
] }),
|
|
18651
|
+
/* @__PURE__ */ jsx16(Text, { children: " " }),
|
|
18652
|
+
/* @__PURE__ */ jsx16(Text, { color: "#6B4C9A", children: "Press ? to close" })
|
|
18653
|
+
]
|
|
18654
|
+
}
|
|
18655
|
+
);
|
|
18656
|
+
}
|
|
18657
|
+
|
|
18658
|
+
// src/tui/App.tsx
|
|
18659
|
+
import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
18660
|
+
var TAB_SHORTCUTS = {
|
|
18661
|
+
"command-center": {
|
|
18662
|
+
name: "Command Center",
|
|
18663
|
+
shortcuts: [
|
|
18664
|
+
{ key: "\u2191\u2193", description: "Navigate projects" },
|
|
18665
|
+
{ key: "Enter", description: "Select project" },
|
|
18666
|
+
{ key: "/", description: "Enter chat mode" },
|
|
18667
|
+
{ key: "n", description: "New task" }
|
|
18668
|
+
]
|
|
18669
|
+
},
|
|
18670
|
+
sessions: {
|
|
18671
|
+
name: "Sessions",
|
|
18672
|
+
shortcuts: [
|
|
18673
|
+
{ key: "\u2191\u2193", description: "Navigate sessions" },
|
|
18674
|
+
{ key: "Enter", description: "View session output" },
|
|
18675
|
+
{ key: "k", description: "Kill session" },
|
|
18676
|
+
{ key: "r", description: "Restart agent" }
|
|
18677
|
+
]
|
|
18678
|
+
},
|
|
18679
|
+
tasks: {
|
|
18680
|
+
name: "Tasks",
|
|
18681
|
+
shortcuts: [
|
|
18682
|
+
{ key: "\u2191\u2193", description: "Navigate tasks" },
|
|
18683
|
+
{ key: "Enter", description: "View task detail" },
|
|
18684
|
+
{ key: "n", description: "Create new task" },
|
|
18685
|
+
{ key: "f", description: "Cycle status filter" },
|
|
18686
|
+
{ key: "p", description: "Filter by priority" }
|
|
18687
|
+
]
|
|
18688
|
+
},
|
|
18689
|
+
team: {
|
|
18690
|
+
name: "Team",
|
|
18691
|
+
shortcuts: [
|
|
18692
|
+
{ key: "\u2191\u2193", description: "Navigate employees" },
|
|
18693
|
+
{ key: "Enter", description: "View detail" },
|
|
18694
|
+
{ key: "a", description: "Add employee" },
|
|
18695
|
+
{ key: "s", description: "View sessions" }
|
|
18696
|
+
]
|
|
18697
|
+
},
|
|
18698
|
+
gateway: {
|
|
18699
|
+
name: "Gateway",
|
|
18700
|
+
shortcuts: [
|
|
18701
|
+
{ key: "\u2191\u2193", description: "Navigate sections" },
|
|
18702
|
+
{ key: "f", description: "Cycle platform filter" },
|
|
18703
|
+
{ key: "\u2192", description: "Next conversation" },
|
|
18704
|
+
{ key: "r", description: "Reconnect" }
|
|
18705
|
+
]
|
|
18706
|
+
},
|
|
18707
|
+
wiki: {
|
|
18708
|
+
name: "Wiki",
|
|
18709
|
+
shortcuts: [
|
|
18710
|
+
{ key: "\u2190\u2192", description: "Switch panels" },
|
|
18711
|
+
{ key: "\u2191\u2193", description: "Navigate items" },
|
|
18712
|
+
{ key: "/", description: "Search memories" },
|
|
18713
|
+
{ key: "Enter", description: "Select" }
|
|
18714
|
+
]
|
|
18715
|
+
},
|
|
18716
|
+
settings: {
|
|
18717
|
+
name: "Settings",
|
|
18718
|
+
shortcuts: [
|
|
18719
|
+
{ key: "\u2191\u2193", description: "Navigate sections" },
|
|
18720
|
+
{ key: "Enter", description: "Edit setting" },
|
|
18721
|
+
{ key: "r", description: "Refresh status" }
|
|
18722
|
+
]
|
|
18723
|
+
}
|
|
18724
|
+
};
|
|
17938
18725
|
var isDemo = process.argv.includes("--demo");
|
|
17939
18726
|
process.stderr.write(`[exe-tui] Terminal: ${TERMINAL_TYPE}
|
|
17940
18727
|
`);
|
|
@@ -17961,17 +18748,17 @@ if (!isDemo) {
|
|
|
17961
18748
|
})();
|
|
17962
18749
|
}
|
|
17963
18750
|
function App2() {
|
|
17964
|
-
const [section, setSection] =
|
|
18751
|
+
const [section, setSection] = useState16("command-center");
|
|
17965
18752
|
const { exit } = use_app_default();
|
|
17966
|
-
const [, forceUpdate] =
|
|
17967
|
-
|
|
18753
|
+
const [, forceUpdate] = useState16(0);
|
|
18754
|
+
useEffect18(() => {
|
|
17968
18755
|
const handleResize = () => forceUpdate((n) => n + 1);
|
|
17969
18756
|
process.stdout.on("resize", handleResize);
|
|
17970
18757
|
return () => {
|
|
17971
18758
|
process.stdout.off("resize", handleResize);
|
|
17972
18759
|
};
|
|
17973
18760
|
}, []);
|
|
17974
|
-
useMouseEvent(
|
|
18761
|
+
useMouseEvent(useCallback8((event) => {
|
|
17975
18762
|
if (event.button !== 0) return;
|
|
17976
18763
|
if (event.col <= 26) {
|
|
17977
18764
|
const tabIdx = event.row - 4;
|
|
@@ -17983,22 +18770,33 @@ function App2() {
|
|
|
17983
18770
|
setFocus("content");
|
|
17984
18771
|
}
|
|
17985
18772
|
}, []));
|
|
17986
|
-
const [focus, setFocus] =
|
|
17987
|
-
const [
|
|
17988
|
-
const
|
|
18773
|
+
const [focus, setFocus] = useState16("sidebar");
|
|
18774
|
+
const [showDebug, setShowDebug] = useState16(false);
|
|
18775
|
+
const [showHelp, setShowHelp] = useState16(false);
|
|
18776
|
+
const [focusedProject, setFocusedProject] = useState16(null);
|
|
18777
|
+
const handleSelectProject = useCallback8((projectName) => {
|
|
17989
18778
|
setFocusedProject(projectName);
|
|
17990
18779
|
setSection("sessions");
|
|
17991
18780
|
setFocus("content");
|
|
17992
18781
|
}, []);
|
|
17993
|
-
const handleBackToCommandCenter =
|
|
18782
|
+
const handleBackToCommandCenter = useCallback8(() => {
|
|
17994
18783
|
setSection("command-center");
|
|
17995
18784
|
setFocus("sidebar");
|
|
17996
18785
|
}, []);
|
|
17997
18786
|
use_input_default((input, key) => {
|
|
18787
|
+
if (input === "?" || key.shift && input === "/") {
|
|
18788
|
+
setShowHelp((prev) => !prev);
|
|
18789
|
+
return;
|
|
18790
|
+
}
|
|
17998
18791
|
const idx = parseInt(input, 10);
|
|
17999
18792
|
if (idx >= 1 && idx <= SECTIONS.length) {
|
|
18000
18793
|
setSection(SECTIONS[idx - 1].key);
|
|
18001
18794
|
setFocus("sidebar");
|
|
18795
|
+
setShowHelp(false);
|
|
18796
|
+
return;
|
|
18797
|
+
}
|
|
18798
|
+
if (input === "d" && !key.ctrl) {
|
|
18799
|
+
setShowDebug((prev) => !prev);
|
|
18002
18800
|
return;
|
|
18003
18801
|
}
|
|
18004
18802
|
if (input === "q" && !key.ctrl) {
|
|
@@ -18026,24 +18824,34 @@ function App2() {
|
|
|
18026
18824
|
}
|
|
18027
18825
|
}
|
|
18028
18826
|
});
|
|
18029
|
-
const consumeFocusedProject =
|
|
18827
|
+
const consumeFocusedProject = useCallback8(() => {
|
|
18030
18828
|
setFocusedProject(null);
|
|
18031
18829
|
}, []);
|
|
18032
18830
|
const views = {
|
|
18033
|
-
"command-center": /* @__PURE__ */
|
|
18034
|
-
sessions: /* @__PURE__ */
|
|
18035
|
-
tasks: /* @__PURE__ */
|
|
18036
|
-
team: /* @__PURE__ */
|
|
18037
|
-
|
|
18038
|
-
|
|
18039
|
-
|
|
18831
|
+
"command-center": /* @__PURE__ */ jsx17(CommandCenterView, { onSelectProject: handleSelectProject, isFocused: focus === "content" && section === "command-center", onBack: () => setFocus("sidebar") }),
|
|
18832
|
+
sessions: /* @__PURE__ */ jsx17(SessionsView, { initialProject: focusedProject, onConsumeInitialProject: consumeFocusedProject, onBackToCommandCenter: handleBackToCommandCenter, onBack: () => setFocus("sidebar") }),
|
|
18833
|
+
tasks: /* @__PURE__ */ jsx17(TasksView, { onBack: () => setFocus("sidebar") }),
|
|
18834
|
+
team: /* @__PURE__ */ jsx17(TeamView, { onBack: () => setFocus("sidebar"), onViewSessions: (name) => {
|
|
18835
|
+
setFocusedProject(name);
|
|
18836
|
+
setSection("sessions");
|
|
18837
|
+
setFocus("content");
|
|
18838
|
+
} }),
|
|
18839
|
+
gateway: /* @__PURE__ */ jsx17(GatewayView, { onBack: () => setFocus("sidebar") }),
|
|
18840
|
+
wiki: /* @__PURE__ */ jsx17(WikiView, { onBack: () => setFocus("sidebar") }),
|
|
18841
|
+
settings: /* @__PURE__ */ jsx17(SettingsView, { onBack: () => setFocus("sidebar") })
|
|
18040
18842
|
};
|
|
18041
|
-
return /* @__PURE__ */
|
|
18042
|
-
/* @__PURE__ */
|
|
18043
|
-
/* @__PURE__ */
|
|
18044
|
-
|
|
18843
|
+
return /* @__PURE__ */ jsx17(ErrorBoundary2, { children: /* @__PURE__ */ jsx17(AlternateScreen, { children: /* @__PURE__ */ jsx17(DemoProvider, { demo: isDemo, children: /* @__PURE__ */ jsxs15(Box_default, { flexDirection: "column", flexGrow: 1, children: [
|
|
18844
|
+
/* @__PURE__ */ jsxs15(Box_default, { flexGrow: 1, children: [
|
|
18845
|
+
/* @__PURE__ */ jsx17(Sidebar, { active: section, onSelect: setSection, onQuit: exit, focused: focus === "sidebar" }),
|
|
18846
|
+
showHelp ? /* @__PURE__ */ jsx17(
|
|
18847
|
+
HelpOverlay,
|
|
18848
|
+
{
|
|
18849
|
+
tabName: TAB_SHORTCUTS[section].name,
|
|
18850
|
+
shortcuts: TAB_SHORTCUTS[section].shortcuts
|
|
18851
|
+
}
|
|
18852
|
+
) : showDebug ? /* @__PURE__ */ jsx17(DebugPanel, {}) : views[section]
|
|
18045
18853
|
] }),
|
|
18046
|
-
/* @__PURE__ */
|
|
18854
|
+
/* @__PURE__ */ jsx17(Footer, {})
|
|
18047
18855
|
] }) }) }) });
|
|
18048
18856
|
}
|
|
18049
18857
|
{
|
|
@@ -18061,4 +18869,4 @@ function App2() {
|
|
|
18061
18869
|
stdin.unref = () => stdin;
|
|
18062
18870
|
}
|
|
18063
18871
|
}
|
|
18064
|
-
render_default(/* @__PURE__ */
|
|
18872
|
+
render_default(/* @__PURE__ */ jsx17(App2, {}));
|