@cleocode/core 2026.3.72 → 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/hooks/handlers/agent-hooks.d.ts +48 -0
- package/dist/hooks/handlers/agent-hooks.d.ts.map +1 -0
- package/dist/hooks/handlers/context-hooks.d.ts +53 -0
- package/dist/hooks/handlers/context-hooks.d.ts.map +1 -0
- package/dist/hooks/handlers/error-hooks.d.ts +4 -4
- package/dist/hooks/handlers/error-hooks.d.ts.map +1 -1
- package/dist/hooks/handlers/file-hooks.d.ts +3 -3
- package/dist/hooks/handlers/file-hooks.d.ts.map +1 -1
- package/dist/hooks/handlers/index.d.ts +8 -1
- package/dist/hooks/handlers/index.d.ts.map +1 -1
- package/dist/hooks/handlers/mcp-hooks.d.ts +29 -7
- package/dist/hooks/handlers/mcp-hooks.d.ts.map +1 -1
- package/dist/hooks/handlers/session-hooks.d.ts +5 -5
- package/dist/hooks/handlers/session-hooks.d.ts.map +1 -1
- package/dist/hooks/handlers/task-hooks.d.ts +5 -5
- package/dist/hooks/handlers/task-hooks.d.ts.map +1 -1
- package/dist/hooks/handlers/work-capture-hooks.d.ts +7 -7
- package/dist/hooks/handlers/work-capture-hooks.d.ts.map +1 -1
- package/dist/hooks/payload-schemas.d.ts +177 -11
- package/dist/hooks/payload-schemas.d.ts.map +1 -1
- package/dist/hooks/provider-hooks.d.ts +33 -7
- package/dist/hooks/provider-hooks.d.ts.map +1 -1
- package/dist/hooks/registry.d.ts +26 -6
- package/dist/hooks/registry.d.ts.map +1 -1
- package/dist/hooks/types.d.ts +132 -38
- package/dist/hooks/types.d.ts.map +1 -1
- package/dist/index.js +818 -233
- 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/dist/sessions/snapshot.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/cleo.ts +14 -0
- package/src/hooks/handlers/__tests__/hook-automation-e2e.test.ts +634 -0
- package/src/hooks/handlers/agent-hooks.ts +148 -0
- package/src/hooks/handlers/context-hooks.ts +156 -0
- package/src/hooks/handlers/error-hooks.ts +8 -5
- package/src/hooks/handlers/file-hooks.ts +6 -4
- package/src/hooks/handlers/index.ts +12 -1
- package/src/hooks/handlers/mcp-hooks.ts +74 -9
- package/src/hooks/handlers/session-hooks.ts +7 -7
- package/src/hooks/handlers/task-hooks.ts +7 -7
- package/src/hooks/handlers/work-capture-hooks.ts +12 -12
- package/src/hooks/payload-schemas.ts +96 -26
- package/src/hooks/provider-hooks.ts +50 -9
- package/src/hooks/registry.ts +86 -23
- package/src/hooks/types.ts +175 -39
- package/src/nexus/index.ts +15 -0
- package/src/nexus/workspace.ts +508 -0
- package/src/sessions/index.ts +4 -4
- package/src/sessions/snapshot.ts +4 -2
- package/src/store/json.ts +2 -2
- package/src/task-work/index.ts +4 -4
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";
|
|
@@ -732,22 +739,42 @@ __export(registry_exports, {
|
|
|
732
739
|
HookRegistry: () => HookRegistry,
|
|
733
740
|
hooks: () => hooks
|
|
734
741
|
});
|
|
735
|
-
var DEFAULT_HOOK_CONFIG, HookRegistry, hooks;
|
|
742
|
+
var LEGACY_EVENT_MAP, DEFAULT_HOOK_CONFIG, HookRegistry, hooks;
|
|
736
743
|
var init_registry = __esm({
|
|
737
744
|
"packages/core/src/hooks/registry.ts"() {
|
|
738
745
|
"use strict";
|
|
739
746
|
init_logger();
|
|
747
|
+
LEGACY_EVENT_MAP = {
|
|
748
|
+
onSessionStart: "SessionStart",
|
|
749
|
+
onSessionEnd: "SessionEnd",
|
|
750
|
+
onToolStart: "PreToolUse",
|
|
751
|
+
onToolComplete: "PostToolUse",
|
|
752
|
+
onFileChange: "Notification",
|
|
753
|
+
onError: "PostToolUseFailure",
|
|
754
|
+
onPromptSubmit: "PromptSubmit",
|
|
755
|
+
onResponseComplete: "ResponseComplete"
|
|
756
|
+
};
|
|
740
757
|
DEFAULT_HOOK_CONFIG = {
|
|
741
758
|
enabled: true,
|
|
742
759
|
events: {
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
760
|
+
// CAAMP canonical events (16)
|
|
761
|
+
SessionStart: true,
|
|
762
|
+
SessionEnd: true,
|
|
763
|
+
PromptSubmit: true,
|
|
764
|
+
ResponseComplete: true,
|
|
765
|
+
PreToolUse: true,
|
|
766
|
+
PostToolUse: true,
|
|
767
|
+
PostToolUseFailure: true,
|
|
768
|
+
PermissionRequest: true,
|
|
769
|
+
SubagentStart: true,
|
|
770
|
+
SubagentStop: true,
|
|
771
|
+
PreModel: true,
|
|
772
|
+
PostModel: true,
|
|
773
|
+
PreCompact: true,
|
|
774
|
+
PostCompact: true,
|
|
775
|
+
Notification: true,
|
|
776
|
+
ConfigChange: true,
|
|
777
|
+
// CLEO internal coordination events (5)
|
|
751
778
|
onWorkAvailable: true,
|
|
752
779
|
onAgentSpawn: true,
|
|
753
780
|
onAgentComplete: true,
|
|
@@ -758,12 +785,33 @@ var init_registry = __esm({
|
|
|
758
785
|
HookRegistry = class {
|
|
759
786
|
handlers = /* @__PURE__ */ new Map();
|
|
760
787
|
config = DEFAULT_HOOK_CONFIG;
|
|
788
|
+
/**
|
|
789
|
+
* Resolve a potentially-legacy event name to its canonical equivalent.
|
|
790
|
+
*
|
|
791
|
+
* If the event name matches a known legacy `on`-prefix name, it is
|
|
792
|
+
* remapped and a deprecation warning is logged. Unknown names pass through
|
|
793
|
+
* unchanged so callers using the new canonical names are unaffected.
|
|
794
|
+
*/
|
|
795
|
+
resolveEvent(event) {
|
|
796
|
+
const canonical = LEGACY_EVENT_MAP[event];
|
|
797
|
+
if (canonical) {
|
|
798
|
+
getLogger("hooks").warn(
|
|
799
|
+
{ legacyEvent: event, canonicalEvent: canonical },
|
|
800
|
+
`[DEPRECATED] Hook event '${event}' has been renamed to '${canonical}'. Update your handler registration.`
|
|
801
|
+
);
|
|
802
|
+
return canonical;
|
|
803
|
+
}
|
|
804
|
+
return event;
|
|
805
|
+
}
|
|
761
806
|
/**
|
|
762
807
|
* Register a hook handler for a specific event.
|
|
763
808
|
*
|
|
764
809
|
* Handlers are sorted by priority (highest first) and executed
|
|
765
810
|
* in parallel when the event is dispatched.
|
|
766
811
|
*
|
|
812
|
+
* Backward compatibility: legacy `on`-prefix event names are automatically
|
|
813
|
+
* remapped to their canonical equivalents.
|
|
814
|
+
*
|
|
767
815
|
* @param registration - The hook registration containing event, handler, priority, and ID
|
|
768
816
|
* @returns A function to unregister the handler
|
|
769
817
|
*
|
|
@@ -771,7 +819,7 @@ var init_registry = __esm({
|
|
|
771
819
|
* ```typescript
|
|
772
820
|
* const unregister = hooks.register({
|
|
773
821
|
* id: 'my-handler',
|
|
774
|
-
* event: '
|
|
822
|
+
* event: 'SessionStart',
|
|
775
823
|
* handler: async (root, payload) => { console.log('Session started'); },
|
|
776
824
|
* priority: 100
|
|
777
825
|
* });
|
|
@@ -780,12 +828,14 @@ var init_registry = __esm({
|
|
|
780
828
|
* ```
|
|
781
829
|
*/
|
|
782
830
|
register(registration) {
|
|
783
|
-
const
|
|
784
|
-
|
|
831
|
+
const resolvedEvent = this.resolveEvent(registration.event);
|
|
832
|
+
const resolvedRegistration = { ...registration, event: resolvedEvent };
|
|
833
|
+
const list = this.handlers.get(resolvedEvent) || [];
|
|
834
|
+
list.push(resolvedRegistration);
|
|
785
835
|
list.sort((a, b) => b.priority - a.priority);
|
|
786
|
-
this.handlers.set(
|
|
836
|
+
this.handlers.set(resolvedEvent, list);
|
|
787
837
|
return () => {
|
|
788
|
-
const handlers = this.handlers.get(
|
|
838
|
+
const handlers = this.handlers.get(resolvedEvent);
|
|
789
839
|
if (handlers) {
|
|
790
840
|
const idx = handlers.findIndex((h) => h.id === registration.id);
|
|
791
841
|
if (idx !== -1) handlers.splice(idx, 1);
|
|
@@ -799,14 +849,17 @@ var init_registry = __esm({
|
|
|
799
849
|
* execution. Errors in individual handlers are logged but do not block
|
|
800
850
|
* other handlers or propagate to the caller.
|
|
801
851
|
*
|
|
802
|
-
*
|
|
852
|
+
* Backward compatibility: legacy `on`-prefix event names are automatically
|
|
853
|
+
* remapped to their canonical equivalents.
|
|
854
|
+
*
|
|
855
|
+
* @param event - The CAAMP canonical hook event to dispatch
|
|
803
856
|
* @param projectRoot - The project root directory path
|
|
804
857
|
* @param payload - The event payload (typed by event)
|
|
805
858
|
* @returns Promise that resolves when all handlers have completed
|
|
806
859
|
*
|
|
807
860
|
* @example
|
|
808
861
|
* ```typescript
|
|
809
|
-
* await hooks.dispatch('
|
|
862
|
+
* await hooks.dispatch('SessionStart', '/project', {
|
|
810
863
|
* timestamp: new Date().toISOString(),
|
|
811
864
|
* sessionId: 'sess-123',
|
|
812
865
|
* name: 'My Session',
|
|
@@ -816,15 +869,19 @@ var init_registry = __esm({
|
|
|
816
869
|
*/
|
|
817
870
|
async dispatch(event, projectRoot, payload) {
|
|
818
871
|
if (!this.config.enabled) return;
|
|
819
|
-
|
|
820
|
-
|
|
872
|
+
const resolvedEvent = this.resolveEvent(event);
|
|
873
|
+
if (!this.config.events[resolvedEvent]) return;
|
|
874
|
+
const handlers = this.handlers.get(resolvedEvent);
|
|
821
875
|
if (!handlers || handlers.length === 0) return;
|
|
822
876
|
await Promise.allSettled(
|
|
823
877
|
handlers.map(async (reg) => {
|
|
824
878
|
try {
|
|
825
879
|
await reg.handler(projectRoot, payload);
|
|
826
880
|
} catch (error40) {
|
|
827
|
-
getLogger("hooks").warn(
|
|
881
|
+
getLogger("hooks").warn(
|
|
882
|
+
{ err: error40, hookId: reg.id, event: resolvedEvent },
|
|
883
|
+
"Hook handler failed"
|
|
884
|
+
);
|
|
828
885
|
}
|
|
829
886
|
})
|
|
830
887
|
);
|
|
@@ -833,12 +890,14 @@ var init_registry = __esm({
|
|
|
833
890
|
* Check if a specific event is currently enabled.
|
|
834
891
|
*
|
|
835
892
|
* Both the global enabled flag and the per-event flag must be true.
|
|
893
|
+
* Automatically resolves legacy `on`-prefix event names.
|
|
836
894
|
*
|
|
837
895
|
* @param event - The CAAMP hook event to check
|
|
838
896
|
* @returns True if the event is enabled
|
|
839
897
|
*/
|
|
840
898
|
isEnabled(event) {
|
|
841
|
-
|
|
899
|
+
const resolvedEvent = this.resolveEvent(event);
|
|
900
|
+
return this.config.enabled && this.config.events[resolvedEvent];
|
|
842
901
|
}
|
|
843
902
|
/**
|
|
844
903
|
* Update the hook system configuration.
|
|
@@ -850,7 +909,7 @@ var init_registry = __esm({
|
|
|
850
909
|
* @example
|
|
851
910
|
* ```typescript
|
|
852
911
|
* hooks.setConfig({ enabled: false }); // Disable all hooks
|
|
853
|
-
* hooks.setConfig({ events: {
|
|
912
|
+
* hooks.setConfig({ events: { PostToolUseFailure: false } }); // Disable specific event
|
|
854
913
|
* ```
|
|
855
914
|
*/
|
|
856
915
|
setConfig(config2) {
|
|
@@ -868,12 +927,14 @@ var init_registry = __esm({
|
|
|
868
927
|
* List all registered handlers for a specific event.
|
|
869
928
|
*
|
|
870
929
|
* Returns handlers in priority order (highest first).
|
|
930
|
+
* Automatically resolves legacy `on`-prefix event names.
|
|
871
931
|
*
|
|
872
932
|
* @param event - The CAAMP hook event
|
|
873
933
|
* @returns Array of hook registrations
|
|
874
934
|
*/
|
|
875
935
|
listHandlers(event) {
|
|
876
|
-
|
|
936
|
+
const resolvedEvent = this.resolveEvent(event);
|
|
937
|
+
return [...this.handlers.get(resolvedEvent) || []];
|
|
877
938
|
}
|
|
878
939
|
};
|
|
879
940
|
hooks = new HookRegistry();
|
|
@@ -13584,7 +13645,7 @@ async function saveJson(filePath, data, options) {
|
|
|
13584
13645
|
}
|
|
13585
13646
|
await atomicWriteJson(filePath, data, { indent: options?.indent });
|
|
13586
13647
|
Promise.resolve().then(() => (init_registry(), registry_exports)).then(
|
|
13587
|
-
({ hooks: h }) => h.dispatch("
|
|
13648
|
+
({ hooks: h }) => h.dispatch("Notification", process.cwd(), {
|
|
13588
13649
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
13589
13650
|
filePath,
|
|
13590
13651
|
changeType: "write"
|
|
@@ -18379,13 +18440,13 @@ var init_session_hooks = __esm({
|
|
|
18379
18440
|
init_memory_bridge_refresh();
|
|
18380
18441
|
hooks.register({
|
|
18381
18442
|
id: "brain-session-start",
|
|
18382
|
-
event: "
|
|
18443
|
+
event: "SessionStart",
|
|
18383
18444
|
handler: handleSessionStart,
|
|
18384
18445
|
priority: 100
|
|
18385
18446
|
});
|
|
18386
18447
|
hooks.register({
|
|
18387
18448
|
id: "brain-session-end",
|
|
18388
|
-
event: "
|
|
18449
|
+
event: "SessionEnd",
|
|
18389
18450
|
handler: handleSessionEnd,
|
|
18390
18451
|
priority: 100
|
|
18391
18452
|
});
|
|
@@ -18432,13 +18493,13 @@ var init_task_hooks = __esm({
|
|
|
18432
18493
|
init_memory_bridge_refresh();
|
|
18433
18494
|
hooks.register({
|
|
18434
18495
|
id: "brain-tool-start",
|
|
18435
|
-
event: "
|
|
18496
|
+
event: "PreToolUse",
|
|
18436
18497
|
handler: handleToolStart,
|
|
18437
18498
|
priority: 100
|
|
18438
18499
|
});
|
|
18439
18500
|
hooks.register({
|
|
18440
18501
|
id: "brain-tool-complete",
|
|
18441
|
-
event: "
|
|
18502
|
+
event: "PostToolUse",
|
|
18442
18503
|
handler: handleToolComplete,
|
|
18443
18504
|
priority: 100
|
|
18444
18505
|
});
|
|
@@ -18468,7 +18529,7 @@ var init_error_hooks = __esm({
|
|
|
18468
18529
|
init_registry();
|
|
18469
18530
|
hooks.register({
|
|
18470
18531
|
id: "brain-error",
|
|
18471
|
-
event: "
|
|
18532
|
+
event: "PostToolUseFailure",
|
|
18472
18533
|
handler: handleError,
|
|
18473
18534
|
priority: 100
|
|
18474
18535
|
});
|
|
@@ -18499,6 +18560,7 @@ async function isFileCaptureEnabled(projectRoot) {
|
|
|
18499
18560
|
}
|
|
18500
18561
|
}
|
|
18501
18562
|
async function handleFileChange(projectRoot, payload) {
|
|
18563
|
+
if (!payload.filePath || !payload.changeType) return;
|
|
18502
18564
|
if (!await isFileCaptureEnabled(projectRoot)) return;
|
|
18503
18565
|
const now = Date.now();
|
|
18504
18566
|
const lastWrite = recentWrites.get(payload.filePath);
|
|
@@ -18545,7 +18607,7 @@ var init_file_hooks = __esm({
|
|
|
18545
18607
|
];
|
|
18546
18608
|
hooks.register({
|
|
18547
18609
|
id: "brain-file-change",
|
|
18548
|
-
event: "
|
|
18610
|
+
event: "Notification",
|
|
18549
18611
|
handler: handleFileChange,
|
|
18550
18612
|
priority: 100
|
|
18551
18613
|
});
|
|
@@ -18599,22 +18661,51 @@ async function handleResponseComplete(projectRoot, payload) {
|
|
|
18599
18661
|
if (!isMissingBrainSchemaError4(err)) throw err;
|
|
18600
18662
|
}
|
|
18601
18663
|
}
|
|
18664
|
+
async function handleSystemNotification(projectRoot, payload) {
|
|
18665
|
+
if (payload.filePath || payload.changeType) return;
|
|
18666
|
+
if (!payload.message) return;
|
|
18667
|
+
try {
|
|
18668
|
+
const { loadConfig: loadConfig3 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
18669
|
+
const config2 = await loadConfig3(projectRoot);
|
|
18670
|
+
if (!config2.brain?.autoCapture) return;
|
|
18671
|
+
} catch {
|
|
18672
|
+
return;
|
|
18673
|
+
}
|
|
18674
|
+
const { observeBrain: observeBrain2 } = await Promise.resolve().then(() => (init_brain_retrieval(), brain_retrieval_exports));
|
|
18675
|
+
try {
|
|
18676
|
+
await observeBrain2(projectRoot, {
|
|
18677
|
+
text: `System notification: ${payload.message}`,
|
|
18678
|
+
title: `Notification: ${payload.message.slice(0, 60)}`,
|
|
18679
|
+
type: "discovery",
|
|
18680
|
+
sourceSessionId: payload.sessionId,
|
|
18681
|
+
sourceType: "agent"
|
|
18682
|
+
});
|
|
18683
|
+
} catch (err) {
|
|
18684
|
+
if (!isMissingBrainSchemaError4(err)) throw err;
|
|
18685
|
+
}
|
|
18686
|
+
}
|
|
18602
18687
|
var init_mcp_hooks = __esm({
|
|
18603
18688
|
"packages/core/src/hooks/handlers/mcp-hooks.ts"() {
|
|
18604
18689
|
"use strict";
|
|
18605
18690
|
init_registry();
|
|
18606
18691
|
hooks.register({
|
|
18607
18692
|
id: "brain-prompt-submit",
|
|
18608
|
-
event: "
|
|
18693
|
+
event: "PromptSubmit",
|
|
18609
18694
|
handler: handlePromptSubmit,
|
|
18610
18695
|
priority: 100
|
|
18611
18696
|
});
|
|
18612
18697
|
hooks.register({
|
|
18613
18698
|
id: "brain-response-complete",
|
|
18614
|
-
event: "
|
|
18699
|
+
event: "ResponseComplete",
|
|
18615
18700
|
handler: handleResponseComplete,
|
|
18616
18701
|
priority: 100
|
|
18617
18702
|
});
|
|
18703
|
+
hooks.register({
|
|
18704
|
+
id: "brain-system-notification",
|
|
18705
|
+
event: "Notification",
|
|
18706
|
+
handler: handleSystemNotification,
|
|
18707
|
+
priority: 90
|
|
18708
|
+
});
|
|
18618
18709
|
}
|
|
18619
18710
|
});
|
|
18620
18711
|
|
|
@@ -18691,19 +18782,158 @@ var init_work_capture_hooks = __esm({
|
|
|
18691
18782
|
]);
|
|
18692
18783
|
hooks.register({
|
|
18693
18784
|
id: "work-capture-prompt-submit",
|
|
18694
|
-
event: "
|
|
18785
|
+
event: "PromptSubmit",
|
|
18695
18786
|
handler: handleWorkPromptSubmit,
|
|
18696
18787
|
priority: 90
|
|
18697
18788
|
});
|
|
18698
18789
|
hooks.register({
|
|
18699
18790
|
id: "work-capture-response-complete",
|
|
18700
|
-
event: "
|
|
18791
|
+
event: "ResponseComplete",
|
|
18701
18792
|
handler: handleWorkResponseComplete,
|
|
18702
18793
|
priority: 90
|
|
18703
18794
|
});
|
|
18704
18795
|
}
|
|
18705
18796
|
});
|
|
18706
18797
|
|
|
18798
|
+
// packages/core/src/hooks/handlers/agent-hooks.ts
|
|
18799
|
+
function isMissingBrainSchemaError6(err) {
|
|
18800
|
+
if (!(err instanceof Error)) return false;
|
|
18801
|
+
const message = String(err.message || "").toLowerCase();
|
|
18802
|
+
return message.includes("no such table") && message.includes("brain_");
|
|
18803
|
+
}
|
|
18804
|
+
async function isAutoCaptureEnabled(projectRoot) {
|
|
18805
|
+
try {
|
|
18806
|
+
const { loadConfig: loadConfig3 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
18807
|
+
const config2 = await loadConfig3(projectRoot);
|
|
18808
|
+
return config2.brain?.autoCapture ?? false;
|
|
18809
|
+
} catch {
|
|
18810
|
+
return false;
|
|
18811
|
+
}
|
|
18812
|
+
}
|
|
18813
|
+
async function handleSubagentStart(projectRoot, payload) {
|
|
18814
|
+
if (!await isAutoCaptureEnabled(projectRoot)) return;
|
|
18815
|
+
const { observeBrain: observeBrain2 } = await Promise.resolve().then(() => (init_brain_retrieval(), brain_retrieval_exports));
|
|
18816
|
+
const rolePart = payload.role ? ` role=${payload.role}` : "";
|
|
18817
|
+
const taskPart = payload.taskId ? ` task=${payload.taskId}` : "";
|
|
18818
|
+
try {
|
|
18819
|
+
await observeBrain2(projectRoot, {
|
|
18820
|
+
text: `Subagent spawned: ${payload.agentId}${rolePart}${taskPart}`,
|
|
18821
|
+
title: `Subagent start: ${payload.agentId}`,
|
|
18822
|
+
type: "discovery",
|
|
18823
|
+
sourceSessionId: payload.sessionId,
|
|
18824
|
+
sourceType: "agent"
|
|
18825
|
+
});
|
|
18826
|
+
} catch (err) {
|
|
18827
|
+
if (!isMissingBrainSchemaError6(err)) throw err;
|
|
18828
|
+
}
|
|
18829
|
+
}
|
|
18830
|
+
async function handleSubagentStop(projectRoot, payload) {
|
|
18831
|
+
if (!await isAutoCaptureEnabled(projectRoot)) return;
|
|
18832
|
+
const { observeBrain: observeBrain2 } = await Promise.resolve().then(() => (init_brain_retrieval(), brain_retrieval_exports));
|
|
18833
|
+
const statusPart = payload.status ? ` status=${payload.status}` : "";
|
|
18834
|
+
const taskPart = payload.taskId ? ` task=${payload.taskId}` : "";
|
|
18835
|
+
const summaryPart = payload.summary ? `
|
|
18836
|
+
Summary: ${payload.summary}` : "";
|
|
18837
|
+
try {
|
|
18838
|
+
await observeBrain2(projectRoot, {
|
|
18839
|
+
text: `Subagent completed: ${payload.agentId}${statusPart}${taskPart}${summaryPart}`,
|
|
18840
|
+
title: `Subagent stop: ${payload.agentId}`,
|
|
18841
|
+
type: "change",
|
|
18842
|
+
sourceSessionId: payload.sessionId,
|
|
18843
|
+
sourceType: "agent"
|
|
18844
|
+
});
|
|
18845
|
+
} catch (err) {
|
|
18846
|
+
if (!isMissingBrainSchemaError6(err)) throw err;
|
|
18847
|
+
}
|
|
18848
|
+
}
|
|
18849
|
+
var init_agent_hooks = __esm({
|
|
18850
|
+
"packages/core/src/hooks/handlers/agent-hooks.ts"() {
|
|
18851
|
+
"use strict";
|
|
18852
|
+
init_registry();
|
|
18853
|
+
hooks.register({
|
|
18854
|
+
id: "brain-subagent-start",
|
|
18855
|
+
event: "SubagentStart",
|
|
18856
|
+
handler: handleSubagentStart,
|
|
18857
|
+
priority: 100
|
|
18858
|
+
});
|
|
18859
|
+
hooks.register({
|
|
18860
|
+
id: "brain-subagent-stop",
|
|
18861
|
+
event: "SubagentStop",
|
|
18862
|
+
handler: handleSubagentStop,
|
|
18863
|
+
priority: 100
|
|
18864
|
+
});
|
|
18865
|
+
}
|
|
18866
|
+
});
|
|
18867
|
+
|
|
18868
|
+
// packages/core/src/hooks/handlers/context-hooks.ts
|
|
18869
|
+
function isMissingBrainSchemaError7(err) {
|
|
18870
|
+
if (!(err instanceof Error)) return false;
|
|
18871
|
+
const message = String(err.message || "").toLowerCase();
|
|
18872
|
+
return message.includes("no such table") && message.includes("brain_");
|
|
18873
|
+
}
|
|
18874
|
+
async function isAutoCaptureEnabled2(projectRoot) {
|
|
18875
|
+
try {
|
|
18876
|
+
const { loadConfig: loadConfig3 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
18877
|
+
const config2 = await loadConfig3(projectRoot);
|
|
18878
|
+
return config2.brain?.autoCapture ?? false;
|
|
18879
|
+
} catch {
|
|
18880
|
+
return false;
|
|
18881
|
+
}
|
|
18882
|
+
}
|
|
18883
|
+
async function handlePreCompact(projectRoot, payload) {
|
|
18884
|
+
if (!await isAutoCaptureEnabled2(projectRoot)) return;
|
|
18885
|
+
const { observeBrain: observeBrain2 } = await Promise.resolve().then(() => (init_brain_retrieval(), brain_retrieval_exports));
|
|
18886
|
+
const tokensPart = payload.tokensBefore != null ? ` (~${payload.tokensBefore.toLocaleString()} tokens)` : "";
|
|
18887
|
+
const reasonPart = payload.reason ? ` Reason: ${payload.reason}` : "";
|
|
18888
|
+
try {
|
|
18889
|
+
await observeBrain2(projectRoot, {
|
|
18890
|
+
text: `Context compaction about to begin${tokensPart}.${reasonPart}`,
|
|
18891
|
+
title: "Pre-compaction context snapshot",
|
|
18892
|
+
type: "discovery",
|
|
18893
|
+
sourceSessionId: payload.sessionId,
|
|
18894
|
+
sourceType: "agent"
|
|
18895
|
+
});
|
|
18896
|
+
} catch (err) {
|
|
18897
|
+
if (!isMissingBrainSchemaError7(err)) throw err;
|
|
18898
|
+
}
|
|
18899
|
+
}
|
|
18900
|
+
async function handlePostCompact(projectRoot, payload) {
|
|
18901
|
+
if (!await isAutoCaptureEnabled2(projectRoot)) return;
|
|
18902
|
+
const { observeBrain: observeBrain2 } = await Promise.resolve().then(() => (init_brain_retrieval(), brain_retrieval_exports));
|
|
18903
|
+
const statusPart = payload.success ? "succeeded" : "failed";
|
|
18904
|
+
const beforePart = payload.tokensBefore != null ? ` before=${payload.tokensBefore.toLocaleString()}` : "";
|
|
18905
|
+
const afterPart = payload.tokensAfter != null ? ` after=${payload.tokensAfter.toLocaleString()}` : "";
|
|
18906
|
+
try {
|
|
18907
|
+
await observeBrain2(projectRoot, {
|
|
18908
|
+
text: `Context compaction ${statusPart}${beforePart}${afterPart}`,
|
|
18909
|
+
title: "Post-compaction record",
|
|
18910
|
+
type: "change",
|
|
18911
|
+
sourceSessionId: payload.sessionId,
|
|
18912
|
+
sourceType: "agent"
|
|
18913
|
+
});
|
|
18914
|
+
} catch (err) {
|
|
18915
|
+
if (!isMissingBrainSchemaError7(err)) throw err;
|
|
18916
|
+
}
|
|
18917
|
+
}
|
|
18918
|
+
var init_context_hooks = __esm({
|
|
18919
|
+
"packages/core/src/hooks/handlers/context-hooks.ts"() {
|
|
18920
|
+
"use strict";
|
|
18921
|
+
init_registry();
|
|
18922
|
+
hooks.register({
|
|
18923
|
+
id: "brain-pre-compact",
|
|
18924
|
+
event: "PreCompact",
|
|
18925
|
+
handler: handlePreCompact,
|
|
18926
|
+
priority: 100
|
|
18927
|
+
});
|
|
18928
|
+
hooks.register({
|
|
18929
|
+
id: "brain-post-compact",
|
|
18930
|
+
event: "PostCompact",
|
|
18931
|
+
handler: handlePostCompact,
|
|
18932
|
+
priority: 100
|
|
18933
|
+
});
|
|
18934
|
+
}
|
|
18935
|
+
});
|
|
18936
|
+
|
|
18707
18937
|
// packages/core/src/hooks/handlers/index.ts
|
|
18708
18938
|
var init_handlers = __esm({
|
|
18709
18939
|
"packages/core/src/hooks/handlers/index.ts"() {
|
|
@@ -18714,6 +18944,10 @@ var init_handlers = __esm({
|
|
|
18714
18944
|
init_file_hooks();
|
|
18715
18945
|
init_mcp_hooks();
|
|
18716
18946
|
init_work_capture_hooks();
|
|
18947
|
+
init_agent_hooks();
|
|
18948
|
+
init_context_hooks();
|
|
18949
|
+
init_agent_hooks();
|
|
18950
|
+
init_context_hooks();
|
|
18717
18951
|
init_error_hooks();
|
|
18718
18952
|
init_file_hooks();
|
|
18719
18953
|
init_mcp_hooks();
|
|
@@ -20564,7 +20798,7 @@ async function startSession(options, cwd, accessor) {
|
|
|
20564
20798
|
});
|
|
20565
20799
|
}
|
|
20566
20800
|
const { hooks: hooks2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
20567
|
-
hooks2.dispatch("
|
|
20801
|
+
hooks2.dispatch("SessionStart", cwd ?? process.cwd(), {
|
|
20568
20802
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
20569
20803
|
sessionId: session.id,
|
|
20570
20804
|
name: options.name,
|
|
@@ -20602,7 +20836,7 @@ async function endSession(options = {}, cwd, accessor) {
|
|
|
20602
20836
|
session.endedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
20603
20837
|
const duration3 = Math.floor((Date.now() - new Date(session.startedAt).getTime()) / 1e3);
|
|
20604
20838
|
const { hooks: hooks2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
20605
|
-
hooks2.dispatch("
|
|
20839
|
+
hooks2.dispatch("SessionEnd", cwd ?? process.cwd(), {
|
|
20606
20840
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
20607
20841
|
sessionId: session.id,
|
|
20608
20842
|
duration: duration3,
|
|
@@ -21285,6 +21519,54 @@ var init_codebase_map = __esm({
|
|
|
21285
21519
|
}
|
|
21286
21520
|
});
|
|
21287
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
|
+
|
|
21288
21570
|
// packages/core/src/tasks/hierarchy.ts
|
|
21289
21571
|
function getParentChain(taskId, tasks2) {
|
|
21290
21572
|
const chain = [];
|
|
@@ -24731,7 +25013,150 @@ var init_registry3 = __esm({
|
|
|
24731
25013
|
}
|
|
24732
25014
|
});
|
|
24733
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
|
+
|
|
24734
25155
|
// packages/core/src/tasks/complete.ts
|
|
25156
|
+
var complete_exports = {};
|
|
25157
|
+
__export(complete_exports, {
|
|
25158
|
+
completeTask: () => completeTask
|
|
25159
|
+
});
|
|
24735
25160
|
function isVerificationGate(value) {
|
|
24736
25161
|
return VERIFICATION_GATES.has(value);
|
|
24737
25162
|
}
|
|
@@ -28502,10 +28927,15 @@ __export(hooks_exports, {
|
|
|
28502
28927
|
OnWorkAvailablePayloadSchema: () => OnWorkAvailablePayloadSchema,
|
|
28503
28928
|
handleError: () => handleError,
|
|
28504
28929
|
handleFileChange: () => handleFileChange,
|
|
28930
|
+
handlePostCompact: () => handlePostCompact,
|
|
28931
|
+
handlePreCompact: () => handlePreCompact,
|
|
28505
28932
|
handlePromptSubmit: () => handlePromptSubmit,
|
|
28506
28933
|
handleResponseComplete: () => handleResponseComplete,
|
|
28507
28934
|
handleSessionEnd: () => handleSessionEnd,
|
|
28508
28935
|
handleSessionStart: () => handleSessionStart,
|
|
28936
|
+
handleSubagentStart: () => handleSubagentStart,
|
|
28937
|
+
handleSubagentStop: () => handleSubagentStop,
|
|
28938
|
+
handleSystemNotification: () => handleSystemNotification,
|
|
28509
28939
|
handleToolComplete: () => handleToolComplete,
|
|
28510
28940
|
handleToolStart: () => handleToolStart,
|
|
28511
28941
|
handleWorkPromptSubmit: () => handleWorkPromptSubmit,
|
|
@@ -39662,33 +40092,42 @@ var HookPayloadSchema = external_exports.object({
|
|
|
39662
40092
|
providerId: external_exports.string().optional(),
|
|
39663
40093
|
metadata: external_exports.record(external_exports.string(), external_exports.unknown()).optional()
|
|
39664
40094
|
});
|
|
39665
|
-
var
|
|
40095
|
+
var SessionStartPayloadSchema = HookPayloadSchema.extend({
|
|
39666
40096
|
sessionId: external_exports.string(),
|
|
39667
40097
|
name: external_exports.string(),
|
|
39668
40098
|
scope: external_exports.string(),
|
|
39669
40099
|
agent: external_exports.string().optional()
|
|
39670
40100
|
});
|
|
39671
|
-
var
|
|
40101
|
+
var OnSessionStartPayloadSchema = SessionStartPayloadSchema;
|
|
40102
|
+
var SessionEndPayloadSchema = HookPayloadSchema.extend({
|
|
39672
40103
|
sessionId: external_exports.string(),
|
|
39673
40104
|
duration: external_exports.number(),
|
|
39674
40105
|
tasksCompleted: external_exports.array(external_exports.string())
|
|
39675
40106
|
});
|
|
39676
|
-
var
|
|
40107
|
+
var OnSessionEndPayloadSchema = SessionEndPayloadSchema;
|
|
40108
|
+
var PreToolUsePayloadSchema = HookPayloadSchema.extend({
|
|
39677
40109
|
taskId: external_exports.string(),
|
|
39678
40110
|
taskTitle: external_exports.string(),
|
|
39679
|
-
previousTask: external_exports.string().optional()
|
|
40111
|
+
previousTask: external_exports.string().optional(),
|
|
40112
|
+
toolName: external_exports.string().optional(),
|
|
40113
|
+
toolInput: external_exports.record(external_exports.string(), external_exports.unknown()).optional()
|
|
39680
40114
|
});
|
|
39681
|
-
var
|
|
40115
|
+
var OnToolStartPayloadSchema = PreToolUsePayloadSchema;
|
|
40116
|
+
var PostToolUsePayloadSchema = HookPayloadSchema.extend({
|
|
39682
40117
|
taskId: external_exports.string(),
|
|
39683
40118
|
taskTitle: external_exports.string(),
|
|
39684
|
-
status: external_exports.enum(["done", "archived", "cancelled"])
|
|
40119
|
+
status: external_exports.enum(["done", "archived", "cancelled"]),
|
|
40120
|
+
toolResult: external_exports.record(external_exports.string(), external_exports.unknown()).optional()
|
|
39685
40121
|
});
|
|
39686
|
-
var
|
|
39687
|
-
|
|
39688
|
-
|
|
39689
|
-
|
|
40122
|
+
var OnToolCompletePayloadSchema = PostToolUsePayloadSchema;
|
|
40123
|
+
var NotificationPayloadSchema = HookPayloadSchema.extend({
|
|
40124
|
+
filePath: external_exports.string().optional(),
|
|
40125
|
+
changeType: external_exports.enum(["write", "create", "delete"]).optional(),
|
|
40126
|
+
sizeBytes: external_exports.number().optional(),
|
|
40127
|
+
message: external_exports.string().optional()
|
|
39690
40128
|
});
|
|
39691
|
-
var
|
|
40129
|
+
var OnFileChangePayloadSchema = NotificationPayloadSchema;
|
|
40130
|
+
var PostToolUseFailurePayloadSchema = HookPayloadSchema.extend({
|
|
39692
40131
|
errorCode: external_exports.union([external_exports.number(), external_exports.string()]),
|
|
39693
40132
|
message: external_exports.string(),
|
|
39694
40133
|
domain: external_exports.string().optional(),
|
|
@@ -39696,13 +40135,15 @@ var OnErrorPayloadSchema = HookPayloadSchema.extend({
|
|
|
39696
40135
|
gateway: external_exports.string().optional(),
|
|
39697
40136
|
stack: external_exports.string().optional()
|
|
39698
40137
|
});
|
|
39699
|
-
var
|
|
40138
|
+
var OnErrorPayloadSchema = PostToolUseFailurePayloadSchema;
|
|
40139
|
+
var PromptSubmitPayloadSchema = HookPayloadSchema.extend({
|
|
39700
40140
|
gateway: external_exports.string(),
|
|
39701
40141
|
domain: external_exports.string(),
|
|
39702
40142
|
operation: external_exports.string(),
|
|
39703
40143
|
source: external_exports.string().optional()
|
|
39704
40144
|
});
|
|
39705
|
-
var
|
|
40145
|
+
var OnPromptSubmitPayloadSchema = PromptSubmitPayloadSchema;
|
|
40146
|
+
var ResponseCompletePayloadSchema = HookPayloadSchema.extend({
|
|
39706
40147
|
gateway: external_exports.string(),
|
|
39707
40148
|
domain: external_exports.string(),
|
|
39708
40149
|
operation: external_exports.string(),
|
|
@@ -39710,6 +40151,32 @@ var OnResponseCompletePayloadSchema = HookPayloadSchema.extend({
|
|
|
39710
40151
|
durationMs: external_exports.number().optional(),
|
|
39711
40152
|
errorCode: external_exports.string().optional()
|
|
39712
40153
|
});
|
|
40154
|
+
var OnResponseCompletePayloadSchema = ResponseCompletePayloadSchema;
|
|
40155
|
+
var SubagentStartPayloadSchema = HookPayloadSchema.extend({
|
|
40156
|
+
agentId: external_exports.string(),
|
|
40157
|
+
role: external_exports.string().optional(),
|
|
40158
|
+
taskId: external_exports.string().optional()
|
|
40159
|
+
});
|
|
40160
|
+
var SubagentStopPayloadSchema = HookPayloadSchema.extend({
|
|
40161
|
+
agentId: external_exports.string(),
|
|
40162
|
+
status: external_exports.enum(["complete", "partial", "blocked", "failed"]).optional(),
|
|
40163
|
+
taskId: external_exports.string().optional(),
|
|
40164
|
+
summary: external_exports.string().optional()
|
|
40165
|
+
});
|
|
40166
|
+
var PreCompactPayloadSchema = HookPayloadSchema.extend({
|
|
40167
|
+
tokensBefore: external_exports.number().optional(),
|
|
40168
|
+
reason: external_exports.string().optional()
|
|
40169
|
+
});
|
|
40170
|
+
var PostCompactPayloadSchema = HookPayloadSchema.extend({
|
|
40171
|
+
tokensBefore: external_exports.number().optional(),
|
|
40172
|
+
tokensAfter: external_exports.number().optional(),
|
|
40173
|
+
success: external_exports.boolean()
|
|
40174
|
+
});
|
|
40175
|
+
var ConfigChangePayloadSchema = HookPayloadSchema.extend({
|
|
40176
|
+
key: external_exports.string(),
|
|
40177
|
+
previousValue: external_exports.unknown().optional(),
|
|
40178
|
+
newValue: external_exports.unknown().optional()
|
|
40179
|
+
});
|
|
39713
40180
|
var OnWorkAvailablePayloadSchema = HookPayloadSchema.extend({
|
|
39714
40181
|
taskIds: external_exports.array(external_exports.string()),
|
|
39715
40182
|
epicId: external_exports.string().optional(),
|
|
@@ -39741,14 +40208,21 @@ var OnPatrolPayloadSchema = HookPayloadSchema.extend({
|
|
|
39741
40208
|
scope: external_exports.string().optional()
|
|
39742
40209
|
});
|
|
39743
40210
|
var EVENT_SCHEMA_MAP = {
|
|
39744
|
-
|
|
39745
|
-
|
|
39746
|
-
|
|
39747
|
-
|
|
39748
|
-
|
|
39749
|
-
|
|
39750
|
-
|
|
39751
|
-
|
|
40211
|
+
// CAAMP canonical events (16)
|
|
40212
|
+
SessionStart: SessionStartPayloadSchema,
|
|
40213
|
+
SessionEnd: SessionEndPayloadSchema,
|
|
40214
|
+
PreToolUse: PreToolUsePayloadSchema,
|
|
40215
|
+
PostToolUse: PostToolUsePayloadSchema,
|
|
40216
|
+
Notification: NotificationPayloadSchema,
|
|
40217
|
+
PostToolUseFailure: PostToolUseFailurePayloadSchema,
|
|
40218
|
+
PromptSubmit: PromptSubmitPayloadSchema,
|
|
40219
|
+
ResponseComplete: ResponseCompletePayloadSchema,
|
|
40220
|
+
SubagentStart: SubagentStartPayloadSchema,
|
|
40221
|
+
SubagentStop: SubagentStopPayloadSchema,
|
|
40222
|
+
PreCompact: PreCompactPayloadSchema,
|
|
40223
|
+
PostCompact: PostCompactPayloadSchema,
|
|
40224
|
+
ConfigChange: ConfigChangePayloadSchema,
|
|
40225
|
+
// CLEO internal coordination events (5)
|
|
39752
40226
|
onWorkAvailable: OnWorkAvailablePayloadSchema,
|
|
39753
40227
|
onAgentSpawn: OnAgentSpawnPayloadSchema,
|
|
39754
40228
|
onAgentComplete: OnAgentCompletePayloadSchema,
|
|
@@ -40590,50 +41064,8 @@ async function maybeExtractLearning(taskId, task, verification, confidenceScore,
|
|
|
40590
41064
|
// packages/core/src/intelligence/impact.ts
|
|
40591
41065
|
init_data_accessor();
|
|
40592
41066
|
|
|
40593
|
-
// packages/core/src/tasks/dependency-check.ts
|
|
40594
|
-
function getUnresolvedDeps(taskId, tasks2) {
|
|
40595
|
-
const task = tasks2.find((t) => t.id === taskId);
|
|
40596
|
-
if (!task?.depends?.length) return [];
|
|
40597
|
-
const completedIds = new Set(
|
|
40598
|
-
tasks2.filter((t) => t.status === "done" || t.status === "cancelled").map((t) => t.id)
|
|
40599
|
-
);
|
|
40600
|
-
return task.depends.filter((depId) => !completedIds.has(depId));
|
|
40601
|
-
}
|
|
40602
|
-
function topologicalSort2(tasks2) {
|
|
40603
|
-
const inDegree = /* @__PURE__ */ new Map();
|
|
40604
|
-
const adjList = /* @__PURE__ */ new Map();
|
|
40605
|
-
for (const task of tasks2) {
|
|
40606
|
-
inDegree.set(task.id, 0);
|
|
40607
|
-
adjList.set(task.id, []);
|
|
40608
|
-
}
|
|
40609
|
-
for (const task of tasks2) {
|
|
40610
|
-
if (!task.depends?.length) continue;
|
|
40611
|
-
for (const depId of task.depends) {
|
|
40612
|
-
if (adjList.has(depId)) {
|
|
40613
|
-
adjList.get(depId).push(task.id);
|
|
40614
|
-
inDegree.set(task.id, (inDegree.get(task.id) ?? 0) + 1);
|
|
40615
|
-
}
|
|
40616
|
-
}
|
|
40617
|
-
}
|
|
40618
|
-
const queue = [];
|
|
40619
|
-
for (const [id, degree] of inDegree) {
|
|
40620
|
-
if (degree === 0) queue.push(id);
|
|
40621
|
-
}
|
|
40622
|
-
const sorted = [];
|
|
40623
|
-
while (queue.length > 0) {
|
|
40624
|
-
const id = queue.shift();
|
|
40625
|
-
sorted.push(id);
|
|
40626
|
-
for (const dependent of adjList.get(id) ?? []) {
|
|
40627
|
-
const newDegree = (inDegree.get(dependent) ?? 1) - 1;
|
|
40628
|
-
inDegree.set(dependent, newDegree);
|
|
40629
|
-
if (newDegree === 0) queue.push(dependent);
|
|
40630
|
-
}
|
|
40631
|
-
}
|
|
40632
|
-
if (sorted.length !== tasks2.length) return null;
|
|
40633
|
-
return sorted;
|
|
40634
|
-
}
|
|
40635
|
-
|
|
40636
41067
|
// packages/core/src/tasks/graph-ops.ts
|
|
41068
|
+
init_dependency_check();
|
|
40637
41069
|
function getCriticalPath(tasks2) {
|
|
40638
41070
|
const activeTasks = tasks2.filter((t) => t.status !== "done" && t.status !== "cancelled");
|
|
40639
41071
|
if (activeTasks.length === 0) return [];
|
|
@@ -46510,6 +46942,7 @@ __export(nexus_exports, {
|
|
|
46510
46942
|
nexusSyncAll: () => nexusSyncAll,
|
|
46511
46943
|
nexusUnregister: () => nexusUnregister,
|
|
46512
46944
|
orphanDetection: () => orphanDetection,
|
|
46945
|
+
parseDirective: () => parseDirective,
|
|
46513
46946
|
parseQuery: () => parseQuery,
|
|
46514
46947
|
permissionLevel: () => permissionLevel,
|
|
46515
46948
|
previewTransfer: () => previewTransfer,
|
|
@@ -46520,10 +46953,13 @@ __export(nexus_exports, {
|
|
|
46520
46953
|
resolveCrossDeps: () => resolveCrossDeps,
|
|
46521
46954
|
resolveProjectPath: () => resolveProjectPath2,
|
|
46522
46955
|
resolveTask: () => resolveTask,
|
|
46956
|
+
routeDirective: () => routeDirective,
|
|
46523
46957
|
searchAcrossProjects: () => searchAcrossProjects,
|
|
46524
46958
|
setPermission: () => setPermission,
|
|
46525
46959
|
syncGitignore: () => syncGitignore,
|
|
46526
|
-
validateSyntax: () => validateSyntax
|
|
46960
|
+
validateSyntax: () => validateSyntax,
|
|
46961
|
+
workspaceAgents: () => workspaceAgents,
|
|
46962
|
+
workspaceStatus: () => workspaceStatus
|
|
46527
46963
|
});
|
|
46528
46964
|
|
|
46529
46965
|
// packages/core/src/nexus/deps.ts
|
|
@@ -47749,6 +48185,275 @@ async function executeTransferInternal(params) {
|
|
|
47749
48185
|
return result;
|
|
47750
48186
|
}
|
|
47751
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
|
+
|
|
47752
48457
|
// packages/core/src/observability/index.ts
|
|
47753
48458
|
var observability_exports = {};
|
|
47754
48459
|
__export(observability_exports, {
|
|
@@ -60551,137 +61256,8 @@ async function uncancelTask(projectRoot, params) {
|
|
|
60551
61256
|
};
|
|
60552
61257
|
}
|
|
60553
61258
|
|
|
60554
|
-
// packages/core/src/
|
|
60555
|
-
|
|
60556
|
-
__export(task_work_exports, {
|
|
60557
|
-
currentTask: () => currentTask,
|
|
60558
|
-
getTaskHistory: () => getTaskHistory,
|
|
60559
|
-
getWorkHistory: () => getWorkHistory,
|
|
60560
|
-
startTask: () => startTask,
|
|
60561
|
-
stopTask: () => stopTask
|
|
60562
|
-
});
|
|
60563
|
-
init_src();
|
|
60564
|
-
init_errors3();
|
|
60565
|
-
init_data_accessor();
|
|
60566
|
-
init_add();
|
|
60567
|
-
init_handlers();
|
|
60568
|
-
async function currentTask(cwd, accessor) {
|
|
60569
|
-
const acc = accessor ?? await getAccessor(cwd);
|
|
60570
|
-
const focus = await acc.getMetaValue("focus_state");
|
|
60571
|
-
return {
|
|
60572
|
-
currentTask: focus?.currentTask ?? null,
|
|
60573
|
-
currentPhase: focus?.currentPhase ?? null,
|
|
60574
|
-
sessionNote: focus?.sessionNote ?? null,
|
|
60575
|
-
nextAction: focus?.nextAction ?? null
|
|
60576
|
-
};
|
|
60577
|
-
}
|
|
60578
|
-
async function startTask(taskId, cwd, accessor) {
|
|
60579
|
-
if (!taskId) {
|
|
60580
|
-
throw new CleoError(2 /* INVALID_INPUT */, "Task ID is required");
|
|
60581
|
-
}
|
|
60582
|
-
const acc = accessor ?? await getAccessor(cwd);
|
|
60583
|
-
const task = await acc.loadSingleTask(taskId);
|
|
60584
|
-
if (!task) {
|
|
60585
|
-
throw new CleoError(4 /* NOT_FOUND */, `Task not found: ${taskId}`, {
|
|
60586
|
-
fix: `Use 'cleo find "${taskId}"' to search`
|
|
60587
|
-
});
|
|
60588
|
-
}
|
|
60589
|
-
const { tasks: allTasks } = await acc.queryTasks({});
|
|
60590
|
-
const unresolvedDeps = getUnresolvedDeps(taskId, allTasks);
|
|
60591
|
-
if (unresolvedDeps.length > 0) {
|
|
60592
|
-
throw new CleoError(
|
|
60593
|
-
5 /* DEPENDENCY_ERROR */,
|
|
60594
|
-
`Task ${taskId} is blocked by unresolved dependencies: ${unresolvedDeps.join(", ")}`,
|
|
60595
|
-
{
|
|
60596
|
-
fix: `Complete blockers first: ${unresolvedDeps.map((d) => `cleo complete ${d}`).join(", ")}`
|
|
60597
|
-
}
|
|
60598
|
-
);
|
|
60599
|
-
}
|
|
60600
|
-
const focus = await acc.getMetaValue("focus_state") ?? {};
|
|
60601
|
-
const previousTask = focus.currentTask ?? null;
|
|
60602
|
-
focus.currentTask = taskId;
|
|
60603
|
-
focus.currentPhase = task.phase ?? null;
|
|
60604
|
-
const noteEntry = {
|
|
60605
|
-
note: `Started work on ${taskId}: ${task.title}`,
|
|
60606
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
60607
|
-
};
|
|
60608
|
-
if (!focus.sessionNotes) {
|
|
60609
|
-
focus.sessionNotes = [];
|
|
60610
|
-
}
|
|
60611
|
-
focus.sessionNotes.push(noteEntry);
|
|
60612
|
-
await acc.setMetaValue("focus_state", focus);
|
|
60613
|
-
await logOperation(
|
|
60614
|
-
"task_start",
|
|
60615
|
-
taskId,
|
|
60616
|
-
{
|
|
60617
|
-
previousTask,
|
|
60618
|
-
title: task.title
|
|
60619
|
-
},
|
|
60620
|
-
accessor
|
|
60621
|
-
);
|
|
60622
|
-
const { hooks: hooks2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
60623
|
-
hooks2.dispatch("onToolStart", cwd ?? process.cwd(), {
|
|
60624
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
60625
|
-
taskId,
|
|
60626
|
-
taskTitle: task.title
|
|
60627
|
-
}).catch(() => {
|
|
60628
|
-
});
|
|
60629
|
-
return {
|
|
60630
|
-
taskId,
|
|
60631
|
-
taskTitle: task.title,
|
|
60632
|
-
previousTask
|
|
60633
|
-
};
|
|
60634
|
-
}
|
|
60635
|
-
async function stopTask(cwd, accessor) {
|
|
60636
|
-
const acc = accessor ?? await getAccessor(cwd);
|
|
60637
|
-
const focus = await acc.getMetaValue("focus_state");
|
|
60638
|
-
const previousTask = focus?.currentTask ?? null;
|
|
60639
|
-
if (!focus) {
|
|
60640
|
-
return { previousTask: null };
|
|
60641
|
-
}
|
|
60642
|
-
const taskId = focus.currentTask;
|
|
60643
|
-
const task = taskId ? await acc.loadSingleTask(taskId) : void 0;
|
|
60644
|
-
focus.currentTask = null;
|
|
60645
|
-
focus.nextAction = null;
|
|
60646
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
60647
|
-
if (taskId && task) {
|
|
60648
|
-
const { hooks: hooks2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
60649
|
-
hooks2.dispatch("onToolComplete", cwd ?? process.cwd(), {
|
|
60650
|
-
timestamp: now,
|
|
60651
|
-
taskId,
|
|
60652
|
-
taskTitle: task.title,
|
|
60653
|
-
status: "done"
|
|
60654
|
-
}).catch(() => {
|
|
60655
|
-
});
|
|
60656
|
-
}
|
|
60657
|
-
await acc.setMetaValue("focus_state", focus);
|
|
60658
|
-
await logOperation(
|
|
60659
|
-
"task_stop",
|
|
60660
|
-
previousTask ?? "none",
|
|
60661
|
-
{
|
|
60662
|
-
previousTask
|
|
60663
|
-
},
|
|
60664
|
-
accessor
|
|
60665
|
-
);
|
|
60666
|
-
return { previousTask };
|
|
60667
|
-
}
|
|
60668
|
-
async function getWorkHistory(cwd, accessor) {
|
|
60669
|
-
const acc = accessor ?? await getAccessor(cwd);
|
|
60670
|
-
const focus = await acc.getMetaValue("focus_state");
|
|
60671
|
-
const notes = focus?.sessionNotes ?? [];
|
|
60672
|
-
const history = [];
|
|
60673
|
-
for (const note of notes) {
|
|
60674
|
-
const match = note.note.match(/^(?:Focus set to|Started work on) (T\d+)/);
|
|
60675
|
-
if (match) {
|
|
60676
|
-
history.push({
|
|
60677
|
-
taskId: match[1],
|
|
60678
|
-
timestamp: note.timestamp
|
|
60679
|
-
});
|
|
60680
|
-
}
|
|
60681
|
-
}
|
|
60682
|
-
return history.reverse();
|
|
60683
|
-
}
|
|
60684
|
-
var getTaskHistory = getWorkHistory;
|
|
61259
|
+
// packages/core/src/index.ts
|
|
61260
|
+
init_task_work();
|
|
60685
61261
|
|
|
60686
61262
|
// packages/core/src/tasks/index.ts
|
|
60687
61263
|
var tasks_exports = {};
|
|
@@ -65364,7 +65940,7 @@ async function restoreSession(projectRoot, snapshot, options = {}, accessor) {
|
|
|
65364
65940
|
await acc.upsertSingleSession(restoredSession);
|
|
65365
65941
|
try {
|
|
65366
65942
|
const { hooks: hooks2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
65367
|
-
await hooks2.dispatch("
|
|
65943
|
+
await hooks2.dispatch("SessionStart", projectRoot, {
|
|
65368
65944
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
65369
65945
|
sessionId: restoredSession.id,
|
|
65370
65946
|
name: restoredSession.name,
|
|
@@ -65380,6 +65956,7 @@ async function restoreSession(projectRoot, snapshot, options = {}, accessor) {
|
|
|
65380
65956
|
|
|
65381
65957
|
// packages/core/src/cleo.ts
|
|
65382
65958
|
init_data_accessor();
|
|
65959
|
+
init_task_work();
|
|
65383
65960
|
init_add();
|
|
65384
65961
|
init_complete();
|
|
65385
65962
|
init_update2();
|
|
@@ -65604,7 +66181,14 @@ var Cleo = class _Cleo {
|
|
|
65604
66181
|
discover: (p) => discoverRelated(p.query, p.method, p.limit),
|
|
65605
66182
|
search: (p) => searchAcrossProjects(p.pattern, p.project, p.limit),
|
|
65606
66183
|
setPermission: (p) => setPermission(p.name, p.level),
|
|
65607
|
-
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()
|
|
65608
66192
|
};
|
|
65609
66193
|
}
|
|
65610
66194
|
// === Agents ===
|
|
@@ -65665,6 +66249,7 @@ init_registry();
|
|
|
65665
66249
|
init_brain_retrieval();
|
|
65666
66250
|
init_brain_search();
|
|
65667
66251
|
init_sessions();
|
|
66252
|
+
init_task_work();
|
|
65668
66253
|
init_add();
|
|
65669
66254
|
init_complete();
|
|
65670
66255
|
init_update2();
|