@cleocode/core 2026.3.73 → 2026.3.74
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/cleo.d.ts.map +1 -1
- package/dist/index.js +485 -176
- package/dist/index.js.map +4 -4
- package/dist/nexus/index.d.ts +2 -0
- package/dist/nexus/index.d.ts.map +1 -1
- package/dist/nexus/workspace.d.ts +128 -0
- package/dist/nexus/workspace.d.ts.map +1 -0
- package/package.json +5 -5
- package/src/cleo.ts +14 -0
- package/src/nexus/index.ts +15 -0
- package/src/nexus/workspace.ts +508 -0
package/dist/index.js
CHANGED
|
@@ -631,6 +631,13 @@ var init_discovery = __esm({
|
|
|
631
631
|
});
|
|
632
632
|
|
|
633
633
|
// packages/core/src/logger.ts
|
|
634
|
+
var logger_exports = {};
|
|
635
|
+
__export(logger_exports, {
|
|
636
|
+
closeLogger: () => closeLogger,
|
|
637
|
+
getLogDir: () => getLogDir,
|
|
638
|
+
getLogger: () => getLogger,
|
|
639
|
+
initLogger: () => initLogger
|
|
640
|
+
});
|
|
634
641
|
import { existsSync as existsSync2 } from "node:fs";
|
|
635
642
|
import { dirname, join as join3 } from "node:path";
|
|
636
643
|
import pino from "pino";
|
|
@@ -21512,6 +21519,54 @@ var init_codebase_map = __esm({
|
|
|
21512
21519
|
}
|
|
21513
21520
|
});
|
|
21514
21521
|
|
|
21522
|
+
// packages/core/src/tasks/dependency-check.ts
|
|
21523
|
+
function getUnresolvedDeps(taskId, tasks2) {
|
|
21524
|
+
const task = tasks2.find((t) => t.id === taskId);
|
|
21525
|
+
if (!task?.depends?.length) return [];
|
|
21526
|
+
const completedIds = new Set(
|
|
21527
|
+
tasks2.filter((t) => t.status === "done" || t.status === "cancelled").map((t) => t.id)
|
|
21528
|
+
);
|
|
21529
|
+
return task.depends.filter((depId) => !completedIds.has(depId));
|
|
21530
|
+
}
|
|
21531
|
+
function topologicalSort2(tasks2) {
|
|
21532
|
+
const inDegree = /* @__PURE__ */ new Map();
|
|
21533
|
+
const adjList = /* @__PURE__ */ new Map();
|
|
21534
|
+
for (const task of tasks2) {
|
|
21535
|
+
inDegree.set(task.id, 0);
|
|
21536
|
+
adjList.set(task.id, []);
|
|
21537
|
+
}
|
|
21538
|
+
for (const task of tasks2) {
|
|
21539
|
+
if (!task.depends?.length) continue;
|
|
21540
|
+
for (const depId of task.depends) {
|
|
21541
|
+
if (adjList.has(depId)) {
|
|
21542
|
+
adjList.get(depId).push(task.id);
|
|
21543
|
+
inDegree.set(task.id, (inDegree.get(task.id) ?? 0) + 1);
|
|
21544
|
+
}
|
|
21545
|
+
}
|
|
21546
|
+
}
|
|
21547
|
+
const queue = [];
|
|
21548
|
+
for (const [id, degree] of inDegree) {
|
|
21549
|
+
if (degree === 0) queue.push(id);
|
|
21550
|
+
}
|
|
21551
|
+
const sorted = [];
|
|
21552
|
+
while (queue.length > 0) {
|
|
21553
|
+
const id = queue.shift();
|
|
21554
|
+
sorted.push(id);
|
|
21555
|
+
for (const dependent of adjList.get(id) ?? []) {
|
|
21556
|
+
const newDegree = (inDegree.get(dependent) ?? 1) - 1;
|
|
21557
|
+
inDegree.set(dependent, newDegree);
|
|
21558
|
+
if (newDegree === 0) queue.push(dependent);
|
|
21559
|
+
}
|
|
21560
|
+
}
|
|
21561
|
+
if (sorted.length !== tasks2.length) return null;
|
|
21562
|
+
return sorted;
|
|
21563
|
+
}
|
|
21564
|
+
var init_dependency_check = __esm({
|
|
21565
|
+
"packages/core/src/tasks/dependency-check.ts"() {
|
|
21566
|
+
"use strict";
|
|
21567
|
+
}
|
|
21568
|
+
});
|
|
21569
|
+
|
|
21515
21570
|
// packages/core/src/tasks/hierarchy.ts
|
|
21516
21571
|
function getParentChain(taskId, tasks2) {
|
|
21517
21572
|
const chain = [];
|
|
@@ -24958,7 +25013,150 @@ var init_registry3 = __esm({
|
|
|
24958
25013
|
}
|
|
24959
25014
|
});
|
|
24960
25015
|
|
|
25016
|
+
// packages/core/src/task-work/index.ts
|
|
25017
|
+
var task_work_exports = {};
|
|
25018
|
+
__export(task_work_exports, {
|
|
25019
|
+
currentTask: () => currentTask,
|
|
25020
|
+
getTaskHistory: () => getTaskHistory,
|
|
25021
|
+
getWorkHistory: () => getWorkHistory,
|
|
25022
|
+
startTask: () => startTask,
|
|
25023
|
+
stopTask: () => stopTask
|
|
25024
|
+
});
|
|
25025
|
+
async function currentTask(cwd, accessor) {
|
|
25026
|
+
const acc = accessor ?? await getAccessor(cwd);
|
|
25027
|
+
const focus = await acc.getMetaValue("focus_state");
|
|
25028
|
+
return {
|
|
25029
|
+
currentTask: focus?.currentTask ?? null,
|
|
25030
|
+
currentPhase: focus?.currentPhase ?? null,
|
|
25031
|
+
sessionNote: focus?.sessionNote ?? null,
|
|
25032
|
+
nextAction: focus?.nextAction ?? null
|
|
25033
|
+
};
|
|
25034
|
+
}
|
|
25035
|
+
async function startTask(taskId, cwd, accessor) {
|
|
25036
|
+
if (!taskId) {
|
|
25037
|
+
throw new CleoError(2 /* INVALID_INPUT */, "Task ID is required");
|
|
25038
|
+
}
|
|
25039
|
+
const acc = accessor ?? await getAccessor(cwd);
|
|
25040
|
+
const task = await acc.loadSingleTask(taskId);
|
|
25041
|
+
if (!task) {
|
|
25042
|
+
throw new CleoError(4 /* NOT_FOUND */, `Task not found: ${taskId}`, {
|
|
25043
|
+
fix: `Use 'cleo find "${taskId}"' to search`
|
|
25044
|
+
});
|
|
25045
|
+
}
|
|
25046
|
+
const { tasks: allTasks } = await acc.queryTasks({});
|
|
25047
|
+
const unresolvedDeps = getUnresolvedDeps(taskId, allTasks);
|
|
25048
|
+
if (unresolvedDeps.length > 0) {
|
|
25049
|
+
throw new CleoError(
|
|
25050
|
+
5 /* DEPENDENCY_ERROR */,
|
|
25051
|
+
`Task ${taskId} is blocked by unresolved dependencies: ${unresolvedDeps.join(", ")}`,
|
|
25052
|
+
{
|
|
25053
|
+
fix: `Complete blockers first: ${unresolvedDeps.map((d) => `cleo complete ${d}`).join(", ")}`
|
|
25054
|
+
}
|
|
25055
|
+
);
|
|
25056
|
+
}
|
|
25057
|
+
const focus = await acc.getMetaValue("focus_state") ?? {};
|
|
25058
|
+
const previousTask = focus.currentTask ?? null;
|
|
25059
|
+
focus.currentTask = taskId;
|
|
25060
|
+
focus.currentPhase = task.phase ?? null;
|
|
25061
|
+
const noteEntry = {
|
|
25062
|
+
note: `Started work on ${taskId}: ${task.title}`,
|
|
25063
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
25064
|
+
};
|
|
25065
|
+
if (!focus.sessionNotes) {
|
|
25066
|
+
focus.sessionNotes = [];
|
|
25067
|
+
}
|
|
25068
|
+
focus.sessionNotes.push(noteEntry);
|
|
25069
|
+
await acc.setMetaValue("focus_state", focus);
|
|
25070
|
+
await logOperation(
|
|
25071
|
+
"task_start",
|
|
25072
|
+
taskId,
|
|
25073
|
+
{
|
|
25074
|
+
previousTask,
|
|
25075
|
+
title: task.title
|
|
25076
|
+
},
|
|
25077
|
+
accessor
|
|
25078
|
+
);
|
|
25079
|
+
const { hooks: hooks2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
25080
|
+
hooks2.dispatch("PreToolUse", cwd ?? process.cwd(), {
|
|
25081
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
25082
|
+
taskId,
|
|
25083
|
+
taskTitle: task.title
|
|
25084
|
+
}).catch(() => {
|
|
25085
|
+
});
|
|
25086
|
+
return {
|
|
25087
|
+
taskId,
|
|
25088
|
+
taskTitle: task.title,
|
|
25089
|
+
previousTask
|
|
25090
|
+
};
|
|
25091
|
+
}
|
|
25092
|
+
async function stopTask(cwd, accessor) {
|
|
25093
|
+
const acc = accessor ?? await getAccessor(cwd);
|
|
25094
|
+
const focus = await acc.getMetaValue("focus_state");
|
|
25095
|
+
const previousTask = focus?.currentTask ?? null;
|
|
25096
|
+
if (!focus) {
|
|
25097
|
+
return { previousTask: null };
|
|
25098
|
+
}
|
|
25099
|
+
const taskId = focus.currentTask;
|
|
25100
|
+
const task = taskId ? await acc.loadSingleTask(taskId) : void 0;
|
|
25101
|
+
focus.currentTask = null;
|
|
25102
|
+
focus.nextAction = null;
|
|
25103
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
25104
|
+
if (taskId && task) {
|
|
25105
|
+
const { hooks: hooks2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
25106
|
+
hooks2.dispatch("PostToolUse", cwd ?? process.cwd(), {
|
|
25107
|
+
timestamp: now,
|
|
25108
|
+
taskId,
|
|
25109
|
+
taskTitle: task.title,
|
|
25110
|
+
status: "done"
|
|
25111
|
+
}).catch(() => {
|
|
25112
|
+
});
|
|
25113
|
+
}
|
|
25114
|
+
await acc.setMetaValue("focus_state", focus);
|
|
25115
|
+
await logOperation(
|
|
25116
|
+
"task_stop",
|
|
25117
|
+
previousTask ?? "none",
|
|
25118
|
+
{
|
|
25119
|
+
previousTask
|
|
25120
|
+
},
|
|
25121
|
+
accessor
|
|
25122
|
+
);
|
|
25123
|
+
return { previousTask };
|
|
25124
|
+
}
|
|
25125
|
+
async function getWorkHistory(cwd, accessor) {
|
|
25126
|
+
const acc = accessor ?? await getAccessor(cwd);
|
|
25127
|
+
const focus = await acc.getMetaValue("focus_state");
|
|
25128
|
+
const notes = focus?.sessionNotes ?? [];
|
|
25129
|
+
const history = [];
|
|
25130
|
+
for (const note of notes) {
|
|
25131
|
+
const match = note.note.match(/^(?:Focus set to|Started work on) (T\d+)/);
|
|
25132
|
+
if (match) {
|
|
25133
|
+
history.push({
|
|
25134
|
+
taskId: match[1],
|
|
25135
|
+
timestamp: note.timestamp
|
|
25136
|
+
});
|
|
25137
|
+
}
|
|
25138
|
+
}
|
|
25139
|
+
return history.reverse();
|
|
25140
|
+
}
|
|
25141
|
+
var getTaskHistory;
|
|
25142
|
+
var init_task_work = __esm({
|
|
25143
|
+
"packages/core/src/task-work/index.ts"() {
|
|
25144
|
+
"use strict";
|
|
25145
|
+
init_src();
|
|
25146
|
+
init_errors3();
|
|
25147
|
+
init_data_accessor();
|
|
25148
|
+
init_add();
|
|
25149
|
+
init_dependency_check();
|
|
25150
|
+
init_handlers();
|
|
25151
|
+
getTaskHistory = getWorkHistory;
|
|
25152
|
+
}
|
|
25153
|
+
});
|
|
25154
|
+
|
|
24961
25155
|
// packages/core/src/tasks/complete.ts
|
|
25156
|
+
var complete_exports = {};
|
|
25157
|
+
__export(complete_exports, {
|
|
25158
|
+
completeTask: () => completeTask
|
|
25159
|
+
});
|
|
24962
25160
|
function isVerificationGate(value) {
|
|
24963
25161
|
return VERIFICATION_GATES.has(value);
|
|
24964
25162
|
}
|
|
@@ -40866,50 +41064,8 @@ async function maybeExtractLearning(taskId, task, verification, confidenceScore,
|
|
|
40866
41064
|
// packages/core/src/intelligence/impact.ts
|
|
40867
41065
|
init_data_accessor();
|
|
40868
41066
|
|
|
40869
|
-
// packages/core/src/tasks/dependency-check.ts
|
|
40870
|
-
function getUnresolvedDeps(taskId, tasks2) {
|
|
40871
|
-
const task = tasks2.find((t) => t.id === taskId);
|
|
40872
|
-
if (!task?.depends?.length) return [];
|
|
40873
|
-
const completedIds = new Set(
|
|
40874
|
-
tasks2.filter((t) => t.status === "done" || t.status === "cancelled").map((t) => t.id)
|
|
40875
|
-
);
|
|
40876
|
-
return task.depends.filter((depId) => !completedIds.has(depId));
|
|
40877
|
-
}
|
|
40878
|
-
function topologicalSort2(tasks2) {
|
|
40879
|
-
const inDegree = /* @__PURE__ */ new Map();
|
|
40880
|
-
const adjList = /* @__PURE__ */ new Map();
|
|
40881
|
-
for (const task of tasks2) {
|
|
40882
|
-
inDegree.set(task.id, 0);
|
|
40883
|
-
adjList.set(task.id, []);
|
|
40884
|
-
}
|
|
40885
|
-
for (const task of tasks2) {
|
|
40886
|
-
if (!task.depends?.length) continue;
|
|
40887
|
-
for (const depId of task.depends) {
|
|
40888
|
-
if (adjList.has(depId)) {
|
|
40889
|
-
adjList.get(depId).push(task.id);
|
|
40890
|
-
inDegree.set(task.id, (inDegree.get(task.id) ?? 0) + 1);
|
|
40891
|
-
}
|
|
40892
|
-
}
|
|
40893
|
-
}
|
|
40894
|
-
const queue = [];
|
|
40895
|
-
for (const [id, degree] of inDegree) {
|
|
40896
|
-
if (degree === 0) queue.push(id);
|
|
40897
|
-
}
|
|
40898
|
-
const sorted = [];
|
|
40899
|
-
while (queue.length > 0) {
|
|
40900
|
-
const id = queue.shift();
|
|
40901
|
-
sorted.push(id);
|
|
40902
|
-
for (const dependent of adjList.get(id) ?? []) {
|
|
40903
|
-
const newDegree = (inDegree.get(dependent) ?? 1) - 1;
|
|
40904
|
-
inDegree.set(dependent, newDegree);
|
|
40905
|
-
if (newDegree === 0) queue.push(dependent);
|
|
40906
|
-
}
|
|
40907
|
-
}
|
|
40908
|
-
if (sorted.length !== tasks2.length) return null;
|
|
40909
|
-
return sorted;
|
|
40910
|
-
}
|
|
40911
|
-
|
|
40912
41067
|
// packages/core/src/tasks/graph-ops.ts
|
|
41068
|
+
init_dependency_check();
|
|
40913
41069
|
function getCriticalPath(tasks2) {
|
|
40914
41070
|
const activeTasks = tasks2.filter((t) => t.status !== "done" && t.status !== "cancelled");
|
|
40915
41071
|
if (activeTasks.length === 0) return [];
|
|
@@ -46786,6 +46942,7 @@ __export(nexus_exports, {
|
|
|
46786
46942
|
nexusSyncAll: () => nexusSyncAll,
|
|
46787
46943
|
nexusUnregister: () => nexusUnregister,
|
|
46788
46944
|
orphanDetection: () => orphanDetection,
|
|
46945
|
+
parseDirective: () => parseDirective,
|
|
46789
46946
|
parseQuery: () => parseQuery,
|
|
46790
46947
|
permissionLevel: () => permissionLevel,
|
|
46791
46948
|
previewTransfer: () => previewTransfer,
|
|
@@ -46796,10 +46953,13 @@ __export(nexus_exports, {
|
|
|
46796
46953
|
resolveCrossDeps: () => resolveCrossDeps,
|
|
46797
46954
|
resolveProjectPath: () => resolveProjectPath2,
|
|
46798
46955
|
resolveTask: () => resolveTask,
|
|
46956
|
+
routeDirective: () => routeDirective,
|
|
46799
46957
|
searchAcrossProjects: () => searchAcrossProjects,
|
|
46800
46958
|
setPermission: () => setPermission,
|
|
46801
46959
|
syncGitignore: () => syncGitignore,
|
|
46802
|
-
validateSyntax: () => validateSyntax
|
|
46960
|
+
validateSyntax: () => validateSyntax,
|
|
46961
|
+
workspaceAgents: () => workspaceAgents,
|
|
46962
|
+
workspaceStatus: () => workspaceStatus
|
|
46803
46963
|
});
|
|
46804
46964
|
|
|
46805
46965
|
// packages/core/src/nexus/deps.ts
|
|
@@ -48025,6 +48185,275 @@ async function executeTransferInternal(params) {
|
|
|
48025
48185
|
return result;
|
|
48026
48186
|
}
|
|
48027
48187
|
|
|
48188
|
+
// packages/core/src/nexus/workspace.ts
|
|
48189
|
+
init_src();
|
|
48190
|
+
init_errors3();
|
|
48191
|
+
init_data_accessor();
|
|
48192
|
+
init_registry3();
|
|
48193
|
+
var RATE_LIMIT_WINDOW_MS = 6e4;
|
|
48194
|
+
var RATE_LIMIT_MAX_OPS = 100;
|
|
48195
|
+
var rateLimitCounters = /* @__PURE__ */ new Map();
|
|
48196
|
+
function checkRateLimit(agentId) {
|
|
48197
|
+
const now = Date.now();
|
|
48198
|
+
const entry = rateLimitCounters.get(agentId);
|
|
48199
|
+
if (!entry || now - entry.windowStart > RATE_LIMIT_WINDOW_MS) {
|
|
48200
|
+
rateLimitCounters.set(agentId, { count: 1, windowStart: now });
|
|
48201
|
+
return;
|
|
48202
|
+
}
|
|
48203
|
+
entry.count++;
|
|
48204
|
+
if (entry.count > RATE_LIMIT_MAX_OPS) {
|
|
48205
|
+
throw new CleoError(
|
|
48206
|
+
1 /* GENERAL_ERROR */,
|
|
48207
|
+
`Agent '${agentId}' exceeded rate limit: ${RATE_LIMIT_MAX_OPS} routing ops per ${RATE_LIMIT_WINDOW_MS / 1e3}s`
|
|
48208
|
+
);
|
|
48209
|
+
}
|
|
48210
|
+
}
|
|
48211
|
+
var DEFAULT_ACL = { authorizedAgents: ["*"] };
|
|
48212
|
+
async function loadProjectACL(projectPath) {
|
|
48213
|
+
try {
|
|
48214
|
+
const { loadConfig: loadConfig3 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
48215
|
+
const config2 = await loadConfig3(projectPath);
|
|
48216
|
+
const agents = config2?.authorizedAgents;
|
|
48217
|
+
if (Array.isArray(agents) && agents.length > 0) {
|
|
48218
|
+
return { authorizedAgents: agents };
|
|
48219
|
+
}
|
|
48220
|
+
} catch {
|
|
48221
|
+
}
|
|
48222
|
+
return DEFAULT_ACL;
|
|
48223
|
+
}
|
|
48224
|
+
function isAuthorized(acl, agentId) {
|
|
48225
|
+
if (acl.authorizedAgents.includes("*")) return true;
|
|
48226
|
+
return acl.authorizedAgents.includes(agentId);
|
|
48227
|
+
}
|
|
48228
|
+
var TASK_REF_PATTERN = /\bT(\d+)\b/g;
|
|
48229
|
+
function parseDirective(message) {
|
|
48230
|
+
const content = message.content;
|
|
48231
|
+
const verbMatch = content.match(/^\/(\w+)/);
|
|
48232
|
+
if (!verbMatch) return null;
|
|
48233
|
+
const verb = verbMatch[1];
|
|
48234
|
+
const taskRefs = [];
|
|
48235
|
+
const pattern = new RegExp(TASK_REF_PATTERN.source, "g");
|
|
48236
|
+
for (const m of content.matchAll(pattern)) {
|
|
48237
|
+
taskRefs.push(`T${m[1]}`);
|
|
48238
|
+
}
|
|
48239
|
+
const metaRefs = message.metadata?.taskRefs;
|
|
48240
|
+
if (Array.isArray(metaRefs)) {
|
|
48241
|
+
for (const ref of metaRefs) {
|
|
48242
|
+
if (typeof ref === "string" && !taskRefs.includes(ref)) {
|
|
48243
|
+
taskRefs.push(ref);
|
|
48244
|
+
}
|
|
48245
|
+
}
|
|
48246
|
+
}
|
|
48247
|
+
if (taskRefs.length === 0) return null;
|
|
48248
|
+
return {
|
|
48249
|
+
verb,
|
|
48250
|
+
taskRefs,
|
|
48251
|
+
agentId: message.from,
|
|
48252
|
+
messageId: message.id,
|
|
48253
|
+
timestamp: message.timestamp
|
|
48254
|
+
};
|
|
48255
|
+
}
|
|
48256
|
+
var VERB_TO_OPERATION = {
|
|
48257
|
+
claim: "tasks.start",
|
|
48258
|
+
done: "tasks.complete",
|
|
48259
|
+
complete: "tasks.complete",
|
|
48260
|
+
blocked: "tasks.update",
|
|
48261
|
+
// Update status to blocked
|
|
48262
|
+
start: "tasks.start",
|
|
48263
|
+
stop: "tasks.stop"
|
|
48264
|
+
};
|
|
48265
|
+
async function routeDirective(directive) {
|
|
48266
|
+
checkRateLimit(directive.agentId);
|
|
48267
|
+
const results = [];
|
|
48268
|
+
const operation = VERB_TO_OPERATION[directive.verb];
|
|
48269
|
+
if (!operation) {
|
|
48270
|
+
return results;
|
|
48271
|
+
}
|
|
48272
|
+
const projects = await nexusList();
|
|
48273
|
+
for (const taskRef of directive.taskRefs) {
|
|
48274
|
+
const result = await routeSingleTask(taskRef, directive, operation, projects);
|
|
48275
|
+
results.push(result);
|
|
48276
|
+
}
|
|
48277
|
+
return results;
|
|
48278
|
+
}
|
|
48279
|
+
async function routeSingleTask(taskId, directive, operation, projects) {
|
|
48280
|
+
let targetProject = null;
|
|
48281
|
+
let targetAccessor = null;
|
|
48282
|
+
for (const project of projects) {
|
|
48283
|
+
try {
|
|
48284
|
+
const acc = await getAccessor(project.path);
|
|
48285
|
+
const { tasks: tasks2 } = await acc.queryTasks({});
|
|
48286
|
+
const task = tasks2.find((t) => t.id === taskId);
|
|
48287
|
+
if (task) {
|
|
48288
|
+
targetProject = project;
|
|
48289
|
+
targetAccessor = acc;
|
|
48290
|
+
break;
|
|
48291
|
+
}
|
|
48292
|
+
} catch {
|
|
48293
|
+
}
|
|
48294
|
+
}
|
|
48295
|
+
if (!targetProject || !targetAccessor) {
|
|
48296
|
+
return {
|
|
48297
|
+
success: false,
|
|
48298
|
+
project: "unknown",
|
|
48299
|
+
projectPath: "",
|
|
48300
|
+
taskId,
|
|
48301
|
+
operation,
|
|
48302
|
+
error: `Task ${taskId} not found in any registered project`
|
|
48303
|
+
};
|
|
48304
|
+
}
|
|
48305
|
+
const acl = await loadProjectACL(targetProject.path);
|
|
48306
|
+
if (!isAuthorized(acl, directive.agentId)) {
|
|
48307
|
+
return {
|
|
48308
|
+
success: false,
|
|
48309
|
+
project: targetProject.name,
|
|
48310
|
+
projectPath: targetProject.path,
|
|
48311
|
+
taskId,
|
|
48312
|
+
operation,
|
|
48313
|
+
error: `Agent '${directive.agentId}' not authorized to mutate project '${targetProject.name}'`
|
|
48314
|
+
};
|
|
48315
|
+
}
|
|
48316
|
+
try {
|
|
48317
|
+
await executeOperation(operation, taskId, targetProject.path, targetAccessor, directive);
|
|
48318
|
+
await logRouteAudit(directive, targetProject.name, taskId, operation, true);
|
|
48319
|
+
return {
|
|
48320
|
+
success: true,
|
|
48321
|
+
project: targetProject.name,
|
|
48322
|
+
projectPath: targetProject.path,
|
|
48323
|
+
taskId,
|
|
48324
|
+
operation
|
|
48325
|
+
};
|
|
48326
|
+
} catch (err) {
|
|
48327
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
48328
|
+
await logRouteAudit(directive, targetProject.name, taskId, operation, false, errorMsg);
|
|
48329
|
+
return {
|
|
48330
|
+
success: false,
|
|
48331
|
+
project: targetProject.name,
|
|
48332
|
+
projectPath: targetProject.path,
|
|
48333
|
+
taskId,
|
|
48334
|
+
operation,
|
|
48335
|
+
error: errorMsg
|
|
48336
|
+
};
|
|
48337
|
+
}
|
|
48338
|
+
}
|
|
48339
|
+
async function executeOperation(operation, taskId, projectPath, accessor, directive) {
|
|
48340
|
+
switch (operation) {
|
|
48341
|
+
case "tasks.start": {
|
|
48342
|
+
const { startTask: startTask2 } = await Promise.resolve().then(() => (init_task_work(), task_work_exports));
|
|
48343
|
+
await startTask2(taskId, projectPath, accessor);
|
|
48344
|
+
break;
|
|
48345
|
+
}
|
|
48346
|
+
case "tasks.complete": {
|
|
48347
|
+
const { completeTask: completeTask2 } = await Promise.resolve().then(() => (init_complete(), complete_exports));
|
|
48348
|
+
await completeTask2(
|
|
48349
|
+
{ taskId, notes: `Completed via Conduit directive from ${directive.agentId}` },
|
|
48350
|
+
projectPath,
|
|
48351
|
+
accessor
|
|
48352
|
+
);
|
|
48353
|
+
break;
|
|
48354
|
+
}
|
|
48355
|
+
case "tasks.stop": {
|
|
48356
|
+
const { stopTask: stopTask2 } = await Promise.resolve().then(() => (init_task_work(), task_work_exports));
|
|
48357
|
+
await stopTask2(projectPath, accessor);
|
|
48358
|
+
break;
|
|
48359
|
+
}
|
|
48360
|
+
case "tasks.update": {
|
|
48361
|
+
const { updateTask: updateTask2 } = await Promise.resolve().then(() => (init_update2(), update_exports));
|
|
48362
|
+
await updateTask2(
|
|
48363
|
+
{ taskId, notes: `Marked blocked via Conduit directive from ${directive.agentId}` },
|
|
48364
|
+
projectPath,
|
|
48365
|
+
accessor
|
|
48366
|
+
);
|
|
48367
|
+
break;
|
|
48368
|
+
}
|
|
48369
|
+
}
|
|
48370
|
+
}
|
|
48371
|
+
async function logRouteAudit(directive, projectName, taskId, operation, success2, error40) {
|
|
48372
|
+
try {
|
|
48373
|
+
const { getLogger: getLogger2 } = await Promise.resolve().then(() => (init_logger(), logger_exports));
|
|
48374
|
+
const log9 = getLogger2("nexus.route");
|
|
48375
|
+
const level = success2 ? "info" : "warn";
|
|
48376
|
+
log9[level](
|
|
48377
|
+
{
|
|
48378
|
+
directive: directive.verb,
|
|
48379
|
+
agentId: directive.agentId,
|
|
48380
|
+
messageId: directive.messageId,
|
|
48381
|
+
project: projectName,
|
|
48382
|
+
taskId,
|
|
48383
|
+
operation,
|
|
48384
|
+
success: success2,
|
|
48385
|
+
error: error40
|
|
48386
|
+
},
|
|
48387
|
+
`Conduit directive routed: ${directive.verb} ${taskId} \u2192 ${projectName} (${success2 ? "OK" : "FAILED"})`
|
|
48388
|
+
);
|
|
48389
|
+
} catch {
|
|
48390
|
+
}
|
|
48391
|
+
}
|
|
48392
|
+
async function workspaceStatus() {
|
|
48393
|
+
const projects = await nexusList();
|
|
48394
|
+
const summaries = [];
|
|
48395
|
+
const totals = { pending: 0, active: 0, done: 0, total: 0 };
|
|
48396
|
+
for (const project of projects) {
|
|
48397
|
+
try {
|
|
48398
|
+
const acc = await getAccessor(project.path);
|
|
48399
|
+
const { tasks: tasks2 } = await acc.queryTasks({});
|
|
48400
|
+
const counts = {
|
|
48401
|
+
pending: tasks2.filter((t) => t.status === "pending").length,
|
|
48402
|
+
active: tasks2.filter((t) => t.status === "active").length,
|
|
48403
|
+
done: tasks2.filter((t) => t.status === "done").length,
|
|
48404
|
+
total: tasks2.length
|
|
48405
|
+
};
|
|
48406
|
+
summaries.push({
|
|
48407
|
+
name: project.name,
|
|
48408
|
+
path: project.path,
|
|
48409
|
+
counts,
|
|
48410
|
+
health: project.healthStatus,
|
|
48411
|
+
lastSync: project.lastSync
|
|
48412
|
+
});
|
|
48413
|
+
totals.pending += counts.pending;
|
|
48414
|
+
totals.active += counts.active;
|
|
48415
|
+
totals.done += counts.done;
|
|
48416
|
+
totals.total += counts.total;
|
|
48417
|
+
} catch {
|
|
48418
|
+
summaries.push({
|
|
48419
|
+
name: project.name,
|
|
48420
|
+
path: project.path,
|
|
48421
|
+
counts: { pending: 0, active: 0, done: 0, total: 0 },
|
|
48422
|
+
health: "unreachable",
|
|
48423
|
+
lastSync: project.lastSync
|
|
48424
|
+
});
|
|
48425
|
+
}
|
|
48426
|
+
}
|
|
48427
|
+
return {
|
|
48428
|
+
projectCount: projects.length,
|
|
48429
|
+
projects: summaries,
|
|
48430
|
+
totals,
|
|
48431
|
+
computedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
48432
|
+
};
|
|
48433
|
+
}
|
|
48434
|
+
async function workspaceAgents() {
|
|
48435
|
+
const projects = await nexusList();
|
|
48436
|
+
const agents = [];
|
|
48437
|
+
for (const project of projects) {
|
|
48438
|
+
try {
|
|
48439
|
+
const { listAgentInstances: listAgentInstances2 } = await Promise.resolve().then(() => (init_registry2(), registry_exports2));
|
|
48440
|
+
const instances = await listAgentInstances2(void 0, project.path);
|
|
48441
|
+
for (const inst of instances) {
|
|
48442
|
+
agents.push({
|
|
48443
|
+
agentId: inst.id,
|
|
48444
|
+
agentType: inst.agentType,
|
|
48445
|
+
status: inst.status,
|
|
48446
|
+
project: project.name,
|
|
48447
|
+
taskId: inst.taskId ?? null,
|
|
48448
|
+
lastHeartbeat: inst.lastHeartbeat
|
|
48449
|
+
});
|
|
48450
|
+
}
|
|
48451
|
+
} catch {
|
|
48452
|
+
}
|
|
48453
|
+
}
|
|
48454
|
+
return agents;
|
|
48455
|
+
}
|
|
48456
|
+
|
|
48028
48457
|
// packages/core/src/observability/index.ts
|
|
48029
48458
|
var observability_exports = {};
|
|
48030
48459
|
__export(observability_exports, {
|
|
@@ -60827,137 +61256,8 @@ async function uncancelTask(projectRoot, params) {
|
|
|
60827
61256
|
};
|
|
60828
61257
|
}
|
|
60829
61258
|
|
|
60830
|
-
// packages/core/src/
|
|
60831
|
-
|
|
60832
|
-
__export(task_work_exports, {
|
|
60833
|
-
currentTask: () => currentTask,
|
|
60834
|
-
getTaskHistory: () => getTaskHistory,
|
|
60835
|
-
getWorkHistory: () => getWorkHistory,
|
|
60836
|
-
startTask: () => startTask,
|
|
60837
|
-
stopTask: () => stopTask
|
|
60838
|
-
});
|
|
60839
|
-
init_src();
|
|
60840
|
-
init_errors3();
|
|
60841
|
-
init_data_accessor();
|
|
60842
|
-
init_add();
|
|
60843
|
-
init_handlers();
|
|
60844
|
-
async function currentTask(cwd, accessor) {
|
|
60845
|
-
const acc = accessor ?? await getAccessor(cwd);
|
|
60846
|
-
const focus = await acc.getMetaValue("focus_state");
|
|
60847
|
-
return {
|
|
60848
|
-
currentTask: focus?.currentTask ?? null,
|
|
60849
|
-
currentPhase: focus?.currentPhase ?? null,
|
|
60850
|
-
sessionNote: focus?.sessionNote ?? null,
|
|
60851
|
-
nextAction: focus?.nextAction ?? null
|
|
60852
|
-
};
|
|
60853
|
-
}
|
|
60854
|
-
async function startTask(taskId, cwd, accessor) {
|
|
60855
|
-
if (!taskId) {
|
|
60856
|
-
throw new CleoError(2 /* INVALID_INPUT */, "Task ID is required");
|
|
60857
|
-
}
|
|
60858
|
-
const acc = accessor ?? await getAccessor(cwd);
|
|
60859
|
-
const task = await acc.loadSingleTask(taskId);
|
|
60860
|
-
if (!task) {
|
|
60861
|
-
throw new CleoError(4 /* NOT_FOUND */, `Task not found: ${taskId}`, {
|
|
60862
|
-
fix: `Use 'cleo find "${taskId}"' to search`
|
|
60863
|
-
});
|
|
60864
|
-
}
|
|
60865
|
-
const { tasks: allTasks } = await acc.queryTasks({});
|
|
60866
|
-
const unresolvedDeps = getUnresolvedDeps(taskId, allTasks);
|
|
60867
|
-
if (unresolvedDeps.length > 0) {
|
|
60868
|
-
throw new CleoError(
|
|
60869
|
-
5 /* DEPENDENCY_ERROR */,
|
|
60870
|
-
`Task ${taskId} is blocked by unresolved dependencies: ${unresolvedDeps.join(", ")}`,
|
|
60871
|
-
{
|
|
60872
|
-
fix: `Complete blockers first: ${unresolvedDeps.map((d) => `cleo complete ${d}`).join(", ")}`
|
|
60873
|
-
}
|
|
60874
|
-
);
|
|
60875
|
-
}
|
|
60876
|
-
const focus = await acc.getMetaValue("focus_state") ?? {};
|
|
60877
|
-
const previousTask = focus.currentTask ?? null;
|
|
60878
|
-
focus.currentTask = taskId;
|
|
60879
|
-
focus.currentPhase = task.phase ?? null;
|
|
60880
|
-
const noteEntry = {
|
|
60881
|
-
note: `Started work on ${taskId}: ${task.title}`,
|
|
60882
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
60883
|
-
};
|
|
60884
|
-
if (!focus.sessionNotes) {
|
|
60885
|
-
focus.sessionNotes = [];
|
|
60886
|
-
}
|
|
60887
|
-
focus.sessionNotes.push(noteEntry);
|
|
60888
|
-
await acc.setMetaValue("focus_state", focus);
|
|
60889
|
-
await logOperation(
|
|
60890
|
-
"task_start",
|
|
60891
|
-
taskId,
|
|
60892
|
-
{
|
|
60893
|
-
previousTask,
|
|
60894
|
-
title: task.title
|
|
60895
|
-
},
|
|
60896
|
-
accessor
|
|
60897
|
-
);
|
|
60898
|
-
const { hooks: hooks2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
60899
|
-
hooks2.dispatch("PreToolUse", cwd ?? process.cwd(), {
|
|
60900
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
60901
|
-
taskId,
|
|
60902
|
-
taskTitle: task.title
|
|
60903
|
-
}).catch(() => {
|
|
60904
|
-
});
|
|
60905
|
-
return {
|
|
60906
|
-
taskId,
|
|
60907
|
-
taskTitle: task.title,
|
|
60908
|
-
previousTask
|
|
60909
|
-
};
|
|
60910
|
-
}
|
|
60911
|
-
async function stopTask(cwd, accessor) {
|
|
60912
|
-
const acc = accessor ?? await getAccessor(cwd);
|
|
60913
|
-
const focus = await acc.getMetaValue("focus_state");
|
|
60914
|
-
const previousTask = focus?.currentTask ?? null;
|
|
60915
|
-
if (!focus) {
|
|
60916
|
-
return { previousTask: null };
|
|
60917
|
-
}
|
|
60918
|
-
const taskId = focus.currentTask;
|
|
60919
|
-
const task = taskId ? await acc.loadSingleTask(taskId) : void 0;
|
|
60920
|
-
focus.currentTask = null;
|
|
60921
|
-
focus.nextAction = null;
|
|
60922
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
60923
|
-
if (taskId && task) {
|
|
60924
|
-
const { hooks: hooks2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
60925
|
-
hooks2.dispatch("PostToolUse", cwd ?? process.cwd(), {
|
|
60926
|
-
timestamp: now,
|
|
60927
|
-
taskId,
|
|
60928
|
-
taskTitle: task.title,
|
|
60929
|
-
status: "done"
|
|
60930
|
-
}).catch(() => {
|
|
60931
|
-
});
|
|
60932
|
-
}
|
|
60933
|
-
await acc.setMetaValue("focus_state", focus);
|
|
60934
|
-
await logOperation(
|
|
60935
|
-
"task_stop",
|
|
60936
|
-
previousTask ?? "none",
|
|
60937
|
-
{
|
|
60938
|
-
previousTask
|
|
60939
|
-
},
|
|
60940
|
-
accessor
|
|
60941
|
-
);
|
|
60942
|
-
return { previousTask };
|
|
60943
|
-
}
|
|
60944
|
-
async function getWorkHistory(cwd, accessor) {
|
|
60945
|
-
const acc = accessor ?? await getAccessor(cwd);
|
|
60946
|
-
const focus = await acc.getMetaValue("focus_state");
|
|
60947
|
-
const notes = focus?.sessionNotes ?? [];
|
|
60948
|
-
const history = [];
|
|
60949
|
-
for (const note of notes) {
|
|
60950
|
-
const match = note.note.match(/^(?:Focus set to|Started work on) (T\d+)/);
|
|
60951
|
-
if (match) {
|
|
60952
|
-
history.push({
|
|
60953
|
-
taskId: match[1],
|
|
60954
|
-
timestamp: note.timestamp
|
|
60955
|
-
});
|
|
60956
|
-
}
|
|
60957
|
-
}
|
|
60958
|
-
return history.reverse();
|
|
60959
|
-
}
|
|
60960
|
-
var getTaskHistory = getWorkHistory;
|
|
61259
|
+
// packages/core/src/index.ts
|
|
61260
|
+
init_task_work();
|
|
60961
61261
|
|
|
60962
61262
|
// packages/core/src/tasks/index.ts
|
|
60963
61263
|
var tasks_exports = {};
|
|
@@ -65656,6 +65956,7 @@ async function restoreSession(projectRoot, snapshot, options = {}, accessor) {
|
|
|
65656
65956
|
|
|
65657
65957
|
// packages/core/src/cleo.ts
|
|
65658
65958
|
init_data_accessor();
|
|
65959
|
+
init_task_work();
|
|
65659
65960
|
init_add();
|
|
65660
65961
|
init_complete();
|
|
65661
65962
|
init_update2();
|
|
@@ -65880,7 +66181,14 @@ var Cleo = class _Cleo {
|
|
|
65880
66181
|
discover: (p) => discoverRelated(p.query, p.method, p.limit),
|
|
65881
66182
|
search: (p) => searchAcrossProjects(p.pattern, p.project, p.limit),
|
|
65882
66183
|
setPermission: (p) => setPermission(p.name, p.level),
|
|
65883
|
-
sharingStatus: () => getSharingStatus()
|
|
66184
|
+
sharingStatus: () => getSharingStatus(),
|
|
66185
|
+
route: (message) => {
|
|
66186
|
+
const directive = parseDirective(message);
|
|
66187
|
+
if (!directive) return Promise.resolve([]);
|
|
66188
|
+
return routeDirective(directive);
|
|
66189
|
+
},
|
|
66190
|
+
workspaceStatus: () => workspaceStatus(),
|
|
66191
|
+
workspaceAgents: () => workspaceAgents()
|
|
65884
66192
|
};
|
|
65885
66193
|
}
|
|
65886
66194
|
// === Agents ===
|
|
@@ -65941,6 +66249,7 @@ init_registry();
|
|
|
65941
66249
|
init_brain_retrieval();
|
|
65942
66250
|
init_brain_search();
|
|
65943
66251
|
init_sessions();
|
|
66252
|
+
init_task_work();
|
|
65944
66253
|
init_add();
|
|
65945
66254
|
init_complete();
|
|
65946
66255
|
init_update2();
|