@cleocode/cleo 2026.3.71 → 2026.3.73
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/cli/index.js +731 -107
- package/dist/cli/index.js.map +4 -4
- package/dist/mcp/index.js +661 -108
- package/dist/mcp/index.js.map +4 -4
- package/package.json +4 -4
package/dist/cli/index.js
CHANGED
|
@@ -733,22 +733,42 @@ __export(registry_exports, {
|
|
|
733
733
|
HookRegistry: () => HookRegistry,
|
|
734
734
|
hooks: () => hooks
|
|
735
735
|
});
|
|
736
|
-
var DEFAULT_HOOK_CONFIG, HookRegistry, hooks;
|
|
736
|
+
var LEGACY_EVENT_MAP, DEFAULT_HOOK_CONFIG, HookRegistry, hooks;
|
|
737
737
|
var init_registry = __esm({
|
|
738
738
|
"packages/core/src/hooks/registry.ts"() {
|
|
739
739
|
"use strict";
|
|
740
740
|
init_logger();
|
|
741
|
+
LEGACY_EVENT_MAP = {
|
|
742
|
+
onSessionStart: "SessionStart",
|
|
743
|
+
onSessionEnd: "SessionEnd",
|
|
744
|
+
onToolStart: "PreToolUse",
|
|
745
|
+
onToolComplete: "PostToolUse",
|
|
746
|
+
onFileChange: "Notification",
|
|
747
|
+
onError: "PostToolUseFailure",
|
|
748
|
+
onPromptSubmit: "PromptSubmit",
|
|
749
|
+
onResponseComplete: "ResponseComplete"
|
|
750
|
+
};
|
|
741
751
|
DEFAULT_HOOK_CONFIG = {
|
|
742
752
|
enabled: true,
|
|
743
753
|
events: {
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
754
|
+
// CAAMP canonical events (16)
|
|
755
|
+
SessionStart: true,
|
|
756
|
+
SessionEnd: true,
|
|
757
|
+
PromptSubmit: true,
|
|
758
|
+
ResponseComplete: true,
|
|
759
|
+
PreToolUse: true,
|
|
760
|
+
PostToolUse: true,
|
|
761
|
+
PostToolUseFailure: true,
|
|
762
|
+
PermissionRequest: true,
|
|
763
|
+
SubagentStart: true,
|
|
764
|
+
SubagentStop: true,
|
|
765
|
+
PreModel: true,
|
|
766
|
+
PostModel: true,
|
|
767
|
+
PreCompact: true,
|
|
768
|
+
PostCompact: true,
|
|
769
|
+
Notification: true,
|
|
770
|
+
ConfigChange: true,
|
|
771
|
+
// CLEO internal coordination events (5)
|
|
752
772
|
onWorkAvailable: true,
|
|
753
773
|
onAgentSpawn: true,
|
|
754
774
|
onAgentComplete: true,
|
|
@@ -759,12 +779,33 @@ var init_registry = __esm({
|
|
|
759
779
|
HookRegistry = class {
|
|
760
780
|
handlers = /* @__PURE__ */ new Map();
|
|
761
781
|
config = DEFAULT_HOOK_CONFIG;
|
|
782
|
+
/**
|
|
783
|
+
* Resolve a potentially-legacy event name to its canonical equivalent.
|
|
784
|
+
*
|
|
785
|
+
* If the event name matches a known legacy `on`-prefix name, it is
|
|
786
|
+
* remapped and a deprecation warning is logged. Unknown names pass through
|
|
787
|
+
* unchanged so callers using the new canonical names are unaffected.
|
|
788
|
+
*/
|
|
789
|
+
resolveEvent(event) {
|
|
790
|
+
const canonical = LEGACY_EVENT_MAP[event];
|
|
791
|
+
if (canonical) {
|
|
792
|
+
getLogger("hooks").warn(
|
|
793
|
+
{ legacyEvent: event, canonicalEvent: canonical },
|
|
794
|
+
`[DEPRECATED] Hook event '${event}' has been renamed to '${canonical}'. Update your handler registration.`
|
|
795
|
+
);
|
|
796
|
+
return canonical;
|
|
797
|
+
}
|
|
798
|
+
return event;
|
|
799
|
+
}
|
|
762
800
|
/**
|
|
763
801
|
* Register a hook handler for a specific event.
|
|
764
802
|
*
|
|
765
803
|
* Handlers are sorted by priority (highest first) and executed
|
|
766
804
|
* in parallel when the event is dispatched.
|
|
767
805
|
*
|
|
806
|
+
* Backward compatibility: legacy `on`-prefix event names are automatically
|
|
807
|
+
* remapped to their canonical equivalents.
|
|
808
|
+
*
|
|
768
809
|
* @param registration - The hook registration containing event, handler, priority, and ID
|
|
769
810
|
* @returns A function to unregister the handler
|
|
770
811
|
*
|
|
@@ -772,7 +813,7 @@ var init_registry = __esm({
|
|
|
772
813
|
* ```typescript
|
|
773
814
|
* const unregister = hooks.register({
|
|
774
815
|
* id: 'my-handler',
|
|
775
|
-
* event: '
|
|
816
|
+
* event: 'SessionStart',
|
|
776
817
|
* handler: async (root, payload) => { console.log('Session started'); },
|
|
777
818
|
* priority: 100
|
|
778
819
|
* });
|
|
@@ -781,12 +822,14 @@ var init_registry = __esm({
|
|
|
781
822
|
* ```
|
|
782
823
|
*/
|
|
783
824
|
register(registration) {
|
|
784
|
-
const
|
|
785
|
-
|
|
825
|
+
const resolvedEvent = this.resolveEvent(registration.event);
|
|
826
|
+
const resolvedRegistration = { ...registration, event: resolvedEvent };
|
|
827
|
+
const list = this.handlers.get(resolvedEvent) || [];
|
|
828
|
+
list.push(resolvedRegistration);
|
|
786
829
|
list.sort((a, b) => b.priority - a.priority);
|
|
787
|
-
this.handlers.set(
|
|
830
|
+
this.handlers.set(resolvedEvent, list);
|
|
788
831
|
return () => {
|
|
789
|
-
const handlers = this.handlers.get(
|
|
832
|
+
const handlers = this.handlers.get(resolvedEvent);
|
|
790
833
|
if (handlers) {
|
|
791
834
|
const idx = handlers.findIndex((h) => h.id === registration.id);
|
|
792
835
|
if (idx !== -1) handlers.splice(idx, 1);
|
|
@@ -800,14 +843,17 @@ var init_registry = __esm({
|
|
|
800
843
|
* execution. Errors in individual handlers are logged but do not block
|
|
801
844
|
* other handlers or propagate to the caller.
|
|
802
845
|
*
|
|
803
|
-
*
|
|
846
|
+
* Backward compatibility: legacy `on`-prefix event names are automatically
|
|
847
|
+
* remapped to their canonical equivalents.
|
|
848
|
+
*
|
|
849
|
+
* @param event - The CAAMP canonical hook event to dispatch
|
|
804
850
|
* @param projectRoot - The project root directory path
|
|
805
851
|
* @param payload - The event payload (typed by event)
|
|
806
852
|
* @returns Promise that resolves when all handlers have completed
|
|
807
853
|
*
|
|
808
854
|
* @example
|
|
809
855
|
* ```typescript
|
|
810
|
-
* await hooks.dispatch('
|
|
856
|
+
* await hooks.dispatch('SessionStart', '/project', {
|
|
811
857
|
* timestamp: new Date().toISOString(),
|
|
812
858
|
* sessionId: 'sess-123',
|
|
813
859
|
* name: 'My Session',
|
|
@@ -817,15 +863,19 @@ var init_registry = __esm({
|
|
|
817
863
|
*/
|
|
818
864
|
async dispatch(event, projectRoot, payload) {
|
|
819
865
|
if (!this.config.enabled) return;
|
|
820
|
-
|
|
821
|
-
|
|
866
|
+
const resolvedEvent = this.resolveEvent(event);
|
|
867
|
+
if (!this.config.events[resolvedEvent]) return;
|
|
868
|
+
const handlers = this.handlers.get(resolvedEvent);
|
|
822
869
|
if (!handlers || handlers.length === 0) return;
|
|
823
870
|
await Promise.allSettled(
|
|
824
871
|
handlers.map(async (reg) => {
|
|
825
872
|
try {
|
|
826
873
|
await reg.handler(projectRoot, payload);
|
|
827
874
|
} catch (error40) {
|
|
828
|
-
getLogger("hooks").warn(
|
|
875
|
+
getLogger("hooks").warn(
|
|
876
|
+
{ err: error40, hookId: reg.id, event: resolvedEvent },
|
|
877
|
+
"Hook handler failed"
|
|
878
|
+
);
|
|
829
879
|
}
|
|
830
880
|
})
|
|
831
881
|
);
|
|
@@ -834,12 +884,14 @@ var init_registry = __esm({
|
|
|
834
884
|
* Check if a specific event is currently enabled.
|
|
835
885
|
*
|
|
836
886
|
* Both the global enabled flag and the per-event flag must be true.
|
|
887
|
+
* Automatically resolves legacy `on`-prefix event names.
|
|
837
888
|
*
|
|
838
889
|
* @param event - The CAAMP hook event to check
|
|
839
890
|
* @returns True if the event is enabled
|
|
840
891
|
*/
|
|
841
892
|
isEnabled(event) {
|
|
842
|
-
|
|
893
|
+
const resolvedEvent = this.resolveEvent(event);
|
|
894
|
+
return this.config.enabled && this.config.events[resolvedEvent];
|
|
843
895
|
}
|
|
844
896
|
/**
|
|
845
897
|
* Update the hook system configuration.
|
|
@@ -851,7 +903,7 @@ var init_registry = __esm({
|
|
|
851
903
|
* @example
|
|
852
904
|
* ```typescript
|
|
853
905
|
* hooks.setConfig({ enabled: false }); // Disable all hooks
|
|
854
|
-
* hooks.setConfig({ events: {
|
|
906
|
+
* hooks.setConfig({ events: { PostToolUseFailure: false } }); // Disable specific event
|
|
855
907
|
* ```
|
|
856
908
|
*/
|
|
857
909
|
setConfig(config2) {
|
|
@@ -869,12 +921,14 @@ var init_registry = __esm({
|
|
|
869
921
|
* List all registered handlers for a specific event.
|
|
870
922
|
*
|
|
871
923
|
* Returns handlers in priority order (highest first).
|
|
924
|
+
* Automatically resolves legacy `on`-prefix event names.
|
|
872
925
|
*
|
|
873
926
|
* @param event - The CAAMP hook event
|
|
874
927
|
* @returns Array of hook registrations
|
|
875
928
|
*/
|
|
876
929
|
listHandlers(event) {
|
|
877
|
-
|
|
930
|
+
const resolvedEvent = this.resolveEvent(event);
|
|
931
|
+
return [...this.handlers.get(resolvedEvent) || []];
|
|
878
932
|
}
|
|
879
933
|
};
|
|
880
934
|
hooks = new HookRegistry();
|
|
@@ -13695,7 +13749,7 @@ async function saveJson(filePath, data, options) {
|
|
|
13695
13749
|
}
|
|
13696
13750
|
await atomicWriteJson(filePath, data, { indent: options?.indent });
|
|
13697
13751
|
Promise.resolve().then(() => (init_registry(), registry_exports)).then(
|
|
13698
|
-
({ hooks: h }) => h.dispatch("
|
|
13752
|
+
({ hooks: h }) => h.dispatch("Notification", process.cwd(), {
|
|
13699
13753
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
13700
13754
|
filePath,
|
|
13701
13755
|
changeType: "write"
|
|
@@ -20929,13 +20983,13 @@ var init_session_hooks = __esm({
|
|
|
20929
20983
|
init_memory_bridge_refresh();
|
|
20930
20984
|
hooks.register({
|
|
20931
20985
|
id: "brain-session-start",
|
|
20932
|
-
event: "
|
|
20986
|
+
event: "SessionStart",
|
|
20933
20987
|
handler: handleSessionStart,
|
|
20934
20988
|
priority: 100
|
|
20935
20989
|
});
|
|
20936
20990
|
hooks.register({
|
|
20937
20991
|
id: "brain-session-end",
|
|
20938
|
-
event: "
|
|
20992
|
+
event: "SessionEnd",
|
|
20939
20993
|
handler: handleSessionEnd,
|
|
20940
20994
|
priority: 100
|
|
20941
20995
|
});
|
|
@@ -20982,13 +21036,13 @@ var init_task_hooks = __esm({
|
|
|
20982
21036
|
init_memory_bridge_refresh();
|
|
20983
21037
|
hooks.register({
|
|
20984
21038
|
id: "brain-tool-start",
|
|
20985
|
-
event: "
|
|
21039
|
+
event: "PreToolUse",
|
|
20986
21040
|
handler: handleToolStart,
|
|
20987
21041
|
priority: 100
|
|
20988
21042
|
});
|
|
20989
21043
|
hooks.register({
|
|
20990
21044
|
id: "brain-tool-complete",
|
|
20991
|
-
event: "
|
|
21045
|
+
event: "PostToolUse",
|
|
20992
21046
|
handler: handleToolComplete,
|
|
20993
21047
|
priority: 100
|
|
20994
21048
|
});
|
|
@@ -21018,7 +21072,7 @@ var init_error_hooks = __esm({
|
|
|
21018
21072
|
init_registry();
|
|
21019
21073
|
hooks.register({
|
|
21020
21074
|
id: "brain-error",
|
|
21021
|
-
event: "
|
|
21075
|
+
event: "PostToolUseFailure",
|
|
21022
21076
|
handler: handleError,
|
|
21023
21077
|
priority: 100
|
|
21024
21078
|
});
|
|
@@ -21049,6 +21103,7 @@ async function isFileCaptureEnabled(projectRoot) {
|
|
|
21049
21103
|
}
|
|
21050
21104
|
}
|
|
21051
21105
|
async function handleFileChange(projectRoot, payload) {
|
|
21106
|
+
if (!payload.filePath || !payload.changeType) return;
|
|
21052
21107
|
if (!await isFileCaptureEnabled(projectRoot)) return;
|
|
21053
21108
|
const now2 = Date.now();
|
|
21054
21109
|
const lastWrite = recentWrites.get(payload.filePath);
|
|
@@ -21095,7 +21150,7 @@ var init_file_hooks = __esm({
|
|
|
21095
21150
|
];
|
|
21096
21151
|
hooks.register({
|
|
21097
21152
|
id: "brain-file-change",
|
|
21098
|
-
event: "
|
|
21153
|
+
event: "Notification",
|
|
21099
21154
|
handler: handleFileChange,
|
|
21100
21155
|
priority: 100
|
|
21101
21156
|
});
|
|
@@ -21149,22 +21204,51 @@ async function handleResponseComplete(projectRoot, payload) {
|
|
|
21149
21204
|
if (!isMissingBrainSchemaError4(err)) throw err;
|
|
21150
21205
|
}
|
|
21151
21206
|
}
|
|
21207
|
+
async function handleSystemNotification(projectRoot, payload) {
|
|
21208
|
+
if (payload.filePath || payload.changeType) return;
|
|
21209
|
+
if (!payload.message) return;
|
|
21210
|
+
try {
|
|
21211
|
+
const { loadConfig: loadConfig4 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
21212
|
+
const config2 = await loadConfig4(projectRoot);
|
|
21213
|
+
if (!config2.brain?.autoCapture) return;
|
|
21214
|
+
} catch {
|
|
21215
|
+
return;
|
|
21216
|
+
}
|
|
21217
|
+
const { observeBrain: observeBrain2 } = await Promise.resolve().then(() => (init_brain_retrieval(), brain_retrieval_exports));
|
|
21218
|
+
try {
|
|
21219
|
+
await observeBrain2(projectRoot, {
|
|
21220
|
+
text: `System notification: ${payload.message}`,
|
|
21221
|
+
title: `Notification: ${payload.message.slice(0, 60)}`,
|
|
21222
|
+
type: "discovery",
|
|
21223
|
+
sourceSessionId: payload.sessionId,
|
|
21224
|
+
sourceType: "agent"
|
|
21225
|
+
});
|
|
21226
|
+
} catch (err) {
|
|
21227
|
+
if (!isMissingBrainSchemaError4(err)) throw err;
|
|
21228
|
+
}
|
|
21229
|
+
}
|
|
21152
21230
|
var init_mcp_hooks = __esm({
|
|
21153
21231
|
"packages/core/src/hooks/handlers/mcp-hooks.ts"() {
|
|
21154
21232
|
"use strict";
|
|
21155
21233
|
init_registry();
|
|
21156
21234
|
hooks.register({
|
|
21157
21235
|
id: "brain-prompt-submit",
|
|
21158
|
-
event: "
|
|
21236
|
+
event: "PromptSubmit",
|
|
21159
21237
|
handler: handlePromptSubmit,
|
|
21160
21238
|
priority: 100
|
|
21161
21239
|
});
|
|
21162
21240
|
hooks.register({
|
|
21163
21241
|
id: "brain-response-complete",
|
|
21164
|
-
event: "
|
|
21242
|
+
event: "ResponseComplete",
|
|
21165
21243
|
handler: handleResponseComplete,
|
|
21166
21244
|
priority: 100
|
|
21167
21245
|
});
|
|
21246
|
+
hooks.register({
|
|
21247
|
+
id: "brain-system-notification",
|
|
21248
|
+
event: "Notification",
|
|
21249
|
+
handler: handleSystemNotification,
|
|
21250
|
+
priority: 90
|
|
21251
|
+
});
|
|
21168
21252
|
}
|
|
21169
21253
|
});
|
|
21170
21254
|
|
|
@@ -21241,19 +21325,158 @@ var init_work_capture_hooks = __esm({
|
|
|
21241
21325
|
]);
|
|
21242
21326
|
hooks.register({
|
|
21243
21327
|
id: "work-capture-prompt-submit",
|
|
21244
|
-
event: "
|
|
21328
|
+
event: "PromptSubmit",
|
|
21245
21329
|
handler: handleWorkPromptSubmit,
|
|
21246
21330
|
priority: 90
|
|
21247
21331
|
});
|
|
21248
21332
|
hooks.register({
|
|
21249
21333
|
id: "work-capture-response-complete",
|
|
21250
|
-
event: "
|
|
21334
|
+
event: "ResponseComplete",
|
|
21251
21335
|
handler: handleWorkResponseComplete,
|
|
21252
21336
|
priority: 90
|
|
21253
21337
|
});
|
|
21254
21338
|
}
|
|
21255
21339
|
});
|
|
21256
21340
|
|
|
21341
|
+
// packages/core/src/hooks/handlers/agent-hooks.ts
|
|
21342
|
+
function isMissingBrainSchemaError6(err) {
|
|
21343
|
+
if (!(err instanceof Error)) return false;
|
|
21344
|
+
const message = String(err.message || "").toLowerCase();
|
|
21345
|
+
return message.includes("no such table") && message.includes("brain_");
|
|
21346
|
+
}
|
|
21347
|
+
async function isAutoCaptureEnabled(projectRoot) {
|
|
21348
|
+
try {
|
|
21349
|
+
const { loadConfig: loadConfig4 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
21350
|
+
const config2 = await loadConfig4(projectRoot);
|
|
21351
|
+
return config2.brain?.autoCapture ?? false;
|
|
21352
|
+
} catch {
|
|
21353
|
+
return false;
|
|
21354
|
+
}
|
|
21355
|
+
}
|
|
21356
|
+
async function handleSubagentStart(projectRoot, payload) {
|
|
21357
|
+
if (!await isAutoCaptureEnabled(projectRoot)) return;
|
|
21358
|
+
const { observeBrain: observeBrain2 } = await Promise.resolve().then(() => (init_brain_retrieval(), brain_retrieval_exports));
|
|
21359
|
+
const rolePart = payload.role ? ` role=${payload.role}` : "";
|
|
21360
|
+
const taskPart = payload.taskId ? ` task=${payload.taskId}` : "";
|
|
21361
|
+
try {
|
|
21362
|
+
await observeBrain2(projectRoot, {
|
|
21363
|
+
text: `Subagent spawned: ${payload.agentId}${rolePart}${taskPart}`,
|
|
21364
|
+
title: `Subagent start: ${payload.agentId}`,
|
|
21365
|
+
type: "discovery",
|
|
21366
|
+
sourceSessionId: payload.sessionId,
|
|
21367
|
+
sourceType: "agent"
|
|
21368
|
+
});
|
|
21369
|
+
} catch (err) {
|
|
21370
|
+
if (!isMissingBrainSchemaError6(err)) throw err;
|
|
21371
|
+
}
|
|
21372
|
+
}
|
|
21373
|
+
async function handleSubagentStop(projectRoot, payload) {
|
|
21374
|
+
if (!await isAutoCaptureEnabled(projectRoot)) return;
|
|
21375
|
+
const { observeBrain: observeBrain2 } = await Promise.resolve().then(() => (init_brain_retrieval(), brain_retrieval_exports));
|
|
21376
|
+
const statusPart = payload.status ? ` status=${payload.status}` : "";
|
|
21377
|
+
const taskPart = payload.taskId ? ` task=${payload.taskId}` : "";
|
|
21378
|
+
const summaryPart = payload.summary ? `
|
|
21379
|
+
Summary: ${payload.summary}` : "";
|
|
21380
|
+
try {
|
|
21381
|
+
await observeBrain2(projectRoot, {
|
|
21382
|
+
text: `Subagent completed: ${payload.agentId}${statusPart}${taskPart}${summaryPart}`,
|
|
21383
|
+
title: `Subagent stop: ${payload.agentId}`,
|
|
21384
|
+
type: "change",
|
|
21385
|
+
sourceSessionId: payload.sessionId,
|
|
21386
|
+
sourceType: "agent"
|
|
21387
|
+
});
|
|
21388
|
+
} catch (err) {
|
|
21389
|
+
if (!isMissingBrainSchemaError6(err)) throw err;
|
|
21390
|
+
}
|
|
21391
|
+
}
|
|
21392
|
+
var init_agent_hooks = __esm({
|
|
21393
|
+
"packages/core/src/hooks/handlers/agent-hooks.ts"() {
|
|
21394
|
+
"use strict";
|
|
21395
|
+
init_registry();
|
|
21396
|
+
hooks.register({
|
|
21397
|
+
id: "brain-subagent-start",
|
|
21398
|
+
event: "SubagentStart",
|
|
21399
|
+
handler: handleSubagentStart,
|
|
21400
|
+
priority: 100
|
|
21401
|
+
});
|
|
21402
|
+
hooks.register({
|
|
21403
|
+
id: "brain-subagent-stop",
|
|
21404
|
+
event: "SubagentStop",
|
|
21405
|
+
handler: handleSubagentStop,
|
|
21406
|
+
priority: 100
|
|
21407
|
+
});
|
|
21408
|
+
}
|
|
21409
|
+
});
|
|
21410
|
+
|
|
21411
|
+
// packages/core/src/hooks/handlers/context-hooks.ts
|
|
21412
|
+
function isMissingBrainSchemaError7(err) {
|
|
21413
|
+
if (!(err instanceof Error)) return false;
|
|
21414
|
+
const message = String(err.message || "").toLowerCase();
|
|
21415
|
+
return message.includes("no such table") && message.includes("brain_");
|
|
21416
|
+
}
|
|
21417
|
+
async function isAutoCaptureEnabled2(projectRoot) {
|
|
21418
|
+
try {
|
|
21419
|
+
const { loadConfig: loadConfig4 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
21420
|
+
const config2 = await loadConfig4(projectRoot);
|
|
21421
|
+
return config2.brain?.autoCapture ?? false;
|
|
21422
|
+
} catch {
|
|
21423
|
+
return false;
|
|
21424
|
+
}
|
|
21425
|
+
}
|
|
21426
|
+
async function handlePreCompact(projectRoot, payload) {
|
|
21427
|
+
if (!await isAutoCaptureEnabled2(projectRoot)) return;
|
|
21428
|
+
const { observeBrain: observeBrain2 } = await Promise.resolve().then(() => (init_brain_retrieval(), brain_retrieval_exports));
|
|
21429
|
+
const tokensPart = payload.tokensBefore != null ? ` (~${payload.tokensBefore.toLocaleString()} tokens)` : "";
|
|
21430
|
+
const reasonPart = payload.reason ? ` Reason: ${payload.reason}` : "";
|
|
21431
|
+
try {
|
|
21432
|
+
await observeBrain2(projectRoot, {
|
|
21433
|
+
text: `Context compaction about to begin${tokensPart}.${reasonPart}`,
|
|
21434
|
+
title: "Pre-compaction context snapshot",
|
|
21435
|
+
type: "discovery",
|
|
21436
|
+
sourceSessionId: payload.sessionId,
|
|
21437
|
+
sourceType: "agent"
|
|
21438
|
+
});
|
|
21439
|
+
} catch (err) {
|
|
21440
|
+
if (!isMissingBrainSchemaError7(err)) throw err;
|
|
21441
|
+
}
|
|
21442
|
+
}
|
|
21443
|
+
async function handlePostCompact(projectRoot, payload) {
|
|
21444
|
+
if (!await isAutoCaptureEnabled2(projectRoot)) return;
|
|
21445
|
+
const { observeBrain: observeBrain2 } = await Promise.resolve().then(() => (init_brain_retrieval(), brain_retrieval_exports));
|
|
21446
|
+
const statusPart = payload.success ? "succeeded" : "failed";
|
|
21447
|
+
const beforePart = payload.tokensBefore != null ? ` before=${payload.tokensBefore.toLocaleString()}` : "";
|
|
21448
|
+
const afterPart = payload.tokensAfter != null ? ` after=${payload.tokensAfter.toLocaleString()}` : "";
|
|
21449
|
+
try {
|
|
21450
|
+
await observeBrain2(projectRoot, {
|
|
21451
|
+
text: `Context compaction ${statusPart}${beforePart}${afterPart}`,
|
|
21452
|
+
title: "Post-compaction record",
|
|
21453
|
+
type: "change",
|
|
21454
|
+
sourceSessionId: payload.sessionId,
|
|
21455
|
+
sourceType: "agent"
|
|
21456
|
+
});
|
|
21457
|
+
} catch (err) {
|
|
21458
|
+
if (!isMissingBrainSchemaError7(err)) throw err;
|
|
21459
|
+
}
|
|
21460
|
+
}
|
|
21461
|
+
var init_context_hooks = __esm({
|
|
21462
|
+
"packages/core/src/hooks/handlers/context-hooks.ts"() {
|
|
21463
|
+
"use strict";
|
|
21464
|
+
init_registry();
|
|
21465
|
+
hooks.register({
|
|
21466
|
+
id: "brain-pre-compact",
|
|
21467
|
+
event: "PreCompact",
|
|
21468
|
+
handler: handlePreCompact,
|
|
21469
|
+
priority: 100
|
|
21470
|
+
});
|
|
21471
|
+
hooks.register({
|
|
21472
|
+
id: "brain-post-compact",
|
|
21473
|
+
event: "PostCompact",
|
|
21474
|
+
handler: handlePostCompact,
|
|
21475
|
+
priority: 100
|
|
21476
|
+
});
|
|
21477
|
+
}
|
|
21478
|
+
});
|
|
21479
|
+
|
|
21257
21480
|
// packages/core/src/hooks/handlers/index.ts
|
|
21258
21481
|
var init_handlers = __esm({
|
|
21259
21482
|
"packages/core/src/hooks/handlers/index.ts"() {
|
|
@@ -21264,6 +21487,10 @@ var init_handlers = __esm({
|
|
|
21264
21487
|
init_file_hooks();
|
|
21265
21488
|
init_mcp_hooks();
|
|
21266
21489
|
init_work_capture_hooks();
|
|
21490
|
+
init_agent_hooks();
|
|
21491
|
+
init_context_hooks();
|
|
21492
|
+
init_agent_hooks();
|
|
21493
|
+
init_context_hooks();
|
|
21267
21494
|
init_error_hooks();
|
|
21268
21495
|
init_file_hooks();
|
|
21269
21496
|
init_mcp_hooks();
|
|
@@ -23114,7 +23341,7 @@ async function startSession(options, cwd, accessor) {
|
|
|
23114
23341
|
});
|
|
23115
23342
|
}
|
|
23116
23343
|
const { hooks: hooks2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
23117
|
-
hooks2.dispatch("
|
|
23344
|
+
hooks2.dispatch("SessionStart", cwd ?? process.cwd(), {
|
|
23118
23345
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
23119
23346
|
sessionId: session.id,
|
|
23120
23347
|
name: options.name,
|
|
@@ -23152,7 +23379,7 @@ async function endSession(options = {}, cwd, accessor) {
|
|
|
23152
23379
|
session.endedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
23153
23380
|
const duration3 = Math.floor((Date.now() - new Date(session.startedAt).getTime()) / 1e3);
|
|
23154
23381
|
const { hooks: hooks2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
23155
|
-
hooks2.dispatch("
|
|
23382
|
+
hooks2.dispatch("SessionEnd", cwd ?? process.cwd(), {
|
|
23156
23383
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
23157
23384
|
sessionId: session.id,
|
|
23158
23385
|
duration: duration3,
|
|
@@ -35888,7 +36115,7 @@ function validatePayload(event, payload) {
|
|
|
35888
36115
|
const errors = result.error.issues.map((issue2) => `${issue2.path.join(".")}: ${issue2.message}`);
|
|
35889
36116
|
return { valid: false, errors };
|
|
35890
36117
|
}
|
|
35891
|
-
var HookPayloadSchema, OnSessionStartPayloadSchema, OnSessionEndPayloadSchema, OnToolStartPayloadSchema, OnToolCompletePayloadSchema, OnFileChangePayloadSchema, OnErrorPayloadSchema, OnPromptSubmitPayloadSchema, OnResponseCompletePayloadSchema, OnWorkAvailablePayloadSchema, OnAgentSpawnPayloadSchema, OnAgentCompletePayloadSchema, OnCascadeStartPayloadSchema, OnPatrolPayloadSchema, EVENT_SCHEMA_MAP;
|
|
36118
|
+
var HookPayloadSchema, SessionStartPayloadSchema, OnSessionStartPayloadSchema, SessionEndPayloadSchema, OnSessionEndPayloadSchema, PreToolUsePayloadSchema, OnToolStartPayloadSchema, PostToolUsePayloadSchema, OnToolCompletePayloadSchema, NotificationPayloadSchema, OnFileChangePayloadSchema, PostToolUseFailurePayloadSchema, OnErrorPayloadSchema, PromptSubmitPayloadSchema, OnPromptSubmitPayloadSchema, ResponseCompletePayloadSchema, OnResponseCompletePayloadSchema, SubagentStartPayloadSchema, SubagentStopPayloadSchema, PreCompactPayloadSchema, PostCompactPayloadSchema, ConfigChangePayloadSchema, OnWorkAvailablePayloadSchema, OnAgentSpawnPayloadSchema, OnAgentCompletePayloadSchema, OnCascadeStartPayloadSchema, OnPatrolPayloadSchema, EVENT_SCHEMA_MAP;
|
|
35892
36119
|
var init_payload_schemas = __esm({
|
|
35893
36120
|
"packages/core/src/hooks/payload-schemas.ts"() {
|
|
35894
36121
|
"use strict";
|
|
@@ -35900,33 +36127,42 @@ var init_payload_schemas = __esm({
|
|
|
35900
36127
|
providerId: external_exports.string().optional(),
|
|
35901
36128
|
metadata: external_exports.record(external_exports.string(), external_exports.unknown()).optional()
|
|
35902
36129
|
});
|
|
35903
|
-
|
|
36130
|
+
SessionStartPayloadSchema = HookPayloadSchema.extend({
|
|
35904
36131
|
sessionId: external_exports.string(),
|
|
35905
36132
|
name: external_exports.string(),
|
|
35906
36133
|
scope: external_exports.string(),
|
|
35907
36134
|
agent: external_exports.string().optional()
|
|
35908
36135
|
});
|
|
35909
|
-
|
|
36136
|
+
OnSessionStartPayloadSchema = SessionStartPayloadSchema;
|
|
36137
|
+
SessionEndPayloadSchema = HookPayloadSchema.extend({
|
|
35910
36138
|
sessionId: external_exports.string(),
|
|
35911
36139
|
duration: external_exports.number(),
|
|
35912
36140
|
tasksCompleted: external_exports.array(external_exports.string())
|
|
35913
36141
|
});
|
|
35914
|
-
|
|
36142
|
+
OnSessionEndPayloadSchema = SessionEndPayloadSchema;
|
|
36143
|
+
PreToolUsePayloadSchema = HookPayloadSchema.extend({
|
|
35915
36144
|
taskId: external_exports.string(),
|
|
35916
36145
|
taskTitle: external_exports.string(),
|
|
35917
|
-
previousTask: external_exports.string().optional()
|
|
36146
|
+
previousTask: external_exports.string().optional(),
|
|
36147
|
+
toolName: external_exports.string().optional(),
|
|
36148
|
+
toolInput: external_exports.record(external_exports.string(), external_exports.unknown()).optional()
|
|
35918
36149
|
});
|
|
35919
|
-
|
|
36150
|
+
OnToolStartPayloadSchema = PreToolUsePayloadSchema;
|
|
36151
|
+
PostToolUsePayloadSchema = HookPayloadSchema.extend({
|
|
35920
36152
|
taskId: external_exports.string(),
|
|
35921
36153
|
taskTitle: external_exports.string(),
|
|
35922
|
-
status: external_exports.enum(["done", "archived", "cancelled"])
|
|
36154
|
+
status: external_exports.enum(["done", "archived", "cancelled"]),
|
|
36155
|
+
toolResult: external_exports.record(external_exports.string(), external_exports.unknown()).optional()
|
|
35923
36156
|
});
|
|
35924
|
-
|
|
35925
|
-
|
|
35926
|
-
|
|
35927
|
-
|
|
36157
|
+
OnToolCompletePayloadSchema = PostToolUsePayloadSchema;
|
|
36158
|
+
NotificationPayloadSchema = HookPayloadSchema.extend({
|
|
36159
|
+
filePath: external_exports.string().optional(),
|
|
36160
|
+
changeType: external_exports.enum(["write", "create", "delete"]).optional(),
|
|
36161
|
+
sizeBytes: external_exports.number().optional(),
|
|
36162
|
+
message: external_exports.string().optional()
|
|
35928
36163
|
});
|
|
35929
|
-
|
|
36164
|
+
OnFileChangePayloadSchema = NotificationPayloadSchema;
|
|
36165
|
+
PostToolUseFailurePayloadSchema = HookPayloadSchema.extend({
|
|
35930
36166
|
errorCode: external_exports.union([external_exports.number(), external_exports.string()]),
|
|
35931
36167
|
message: external_exports.string(),
|
|
35932
36168
|
domain: external_exports.string().optional(),
|
|
@@ -35934,13 +36170,15 @@ var init_payload_schemas = __esm({
|
|
|
35934
36170
|
gateway: external_exports.string().optional(),
|
|
35935
36171
|
stack: external_exports.string().optional()
|
|
35936
36172
|
});
|
|
35937
|
-
|
|
36173
|
+
OnErrorPayloadSchema = PostToolUseFailurePayloadSchema;
|
|
36174
|
+
PromptSubmitPayloadSchema = HookPayloadSchema.extend({
|
|
35938
36175
|
gateway: external_exports.string(),
|
|
35939
36176
|
domain: external_exports.string(),
|
|
35940
36177
|
operation: external_exports.string(),
|
|
35941
36178
|
source: external_exports.string().optional()
|
|
35942
36179
|
});
|
|
35943
|
-
|
|
36180
|
+
OnPromptSubmitPayloadSchema = PromptSubmitPayloadSchema;
|
|
36181
|
+
ResponseCompletePayloadSchema = HookPayloadSchema.extend({
|
|
35944
36182
|
gateway: external_exports.string(),
|
|
35945
36183
|
domain: external_exports.string(),
|
|
35946
36184
|
operation: external_exports.string(),
|
|
@@ -35948,6 +36186,32 @@ var init_payload_schemas = __esm({
|
|
|
35948
36186
|
durationMs: external_exports.number().optional(),
|
|
35949
36187
|
errorCode: external_exports.string().optional()
|
|
35950
36188
|
});
|
|
36189
|
+
OnResponseCompletePayloadSchema = ResponseCompletePayloadSchema;
|
|
36190
|
+
SubagentStartPayloadSchema = HookPayloadSchema.extend({
|
|
36191
|
+
agentId: external_exports.string(),
|
|
36192
|
+
role: external_exports.string().optional(),
|
|
36193
|
+
taskId: external_exports.string().optional()
|
|
36194
|
+
});
|
|
36195
|
+
SubagentStopPayloadSchema = HookPayloadSchema.extend({
|
|
36196
|
+
agentId: external_exports.string(),
|
|
36197
|
+
status: external_exports.enum(["complete", "partial", "blocked", "failed"]).optional(),
|
|
36198
|
+
taskId: external_exports.string().optional(),
|
|
36199
|
+
summary: external_exports.string().optional()
|
|
36200
|
+
});
|
|
36201
|
+
PreCompactPayloadSchema = HookPayloadSchema.extend({
|
|
36202
|
+
tokensBefore: external_exports.number().optional(),
|
|
36203
|
+
reason: external_exports.string().optional()
|
|
36204
|
+
});
|
|
36205
|
+
PostCompactPayloadSchema = HookPayloadSchema.extend({
|
|
36206
|
+
tokensBefore: external_exports.number().optional(),
|
|
36207
|
+
tokensAfter: external_exports.number().optional(),
|
|
36208
|
+
success: external_exports.boolean()
|
|
36209
|
+
});
|
|
36210
|
+
ConfigChangePayloadSchema = HookPayloadSchema.extend({
|
|
36211
|
+
key: external_exports.string(),
|
|
36212
|
+
previousValue: external_exports.unknown().optional(),
|
|
36213
|
+
newValue: external_exports.unknown().optional()
|
|
36214
|
+
});
|
|
35951
36215
|
OnWorkAvailablePayloadSchema = HookPayloadSchema.extend({
|
|
35952
36216
|
taskIds: external_exports.array(external_exports.string()),
|
|
35953
36217
|
epicId: external_exports.string().optional(),
|
|
@@ -35979,14 +36243,21 @@ var init_payload_schemas = __esm({
|
|
|
35979
36243
|
scope: external_exports.string().optional()
|
|
35980
36244
|
});
|
|
35981
36245
|
EVENT_SCHEMA_MAP = {
|
|
35982
|
-
|
|
35983
|
-
|
|
35984
|
-
|
|
35985
|
-
|
|
35986
|
-
|
|
35987
|
-
|
|
35988
|
-
|
|
35989
|
-
|
|
36246
|
+
// CAAMP canonical events (16)
|
|
36247
|
+
SessionStart: SessionStartPayloadSchema,
|
|
36248
|
+
SessionEnd: SessionEndPayloadSchema,
|
|
36249
|
+
PreToolUse: PreToolUsePayloadSchema,
|
|
36250
|
+
PostToolUse: PostToolUsePayloadSchema,
|
|
36251
|
+
Notification: NotificationPayloadSchema,
|
|
36252
|
+
PostToolUseFailure: PostToolUseFailurePayloadSchema,
|
|
36253
|
+
PromptSubmit: PromptSubmitPayloadSchema,
|
|
36254
|
+
ResponseComplete: ResponseCompletePayloadSchema,
|
|
36255
|
+
SubagentStart: SubagentStartPayloadSchema,
|
|
36256
|
+
SubagentStop: SubagentStopPayloadSchema,
|
|
36257
|
+
PreCompact: PreCompactPayloadSchema,
|
|
36258
|
+
PostCompact: PostCompactPayloadSchema,
|
|
36259
|
+
ConfigChange: ConfigChangePayloadSchema,
|
|
36260
|
+
// CLEO internal coordination events (5)
|
|
35990
36261
|
onWorkAvailable: OnWorkAvailablePayloadSchema,
|
|
35991
36262
|
onAgentSpawn: OnAgentSpawnPayloadSchema,
|
|
35992
36263
|
onAgentComplete: OnAgentCompletePayloadSchema,
|
|
@@ -36016,10 +36287,15 @@ __export(hooks_exports, {
|
|
|
36016
36287
|
OnWorkAvailablePayloadSchema: () => OnWorkAvailablePayloadSchema,
|
|
36017
36288
|
handleError: () => handleError,
|
|
36018
36289
|
handleFileChange: () => handleFileChange,
|
|
36290
|
+
handlePostCompact: () => handlePostCompact,
|
|
36291
|
+
handlePreCompact: () => handlePreCompact,
|
|
36019
36292
|
handlePromptSubmit: () => handlePromptSubmit,
|
|
36020
36293
|
handleResponseComplete: () => handleResponseComplete,
|
|
36021
36294
|
handleSessionEnd: () => handleSessionEnd,
|
|
36022
36295
|
handleSessionStart: () => handleSessionStart,
|
|
36296
|
+
handleSubagentStart: () => handleSubagentStart,
|
|
36297
|
+
handleSubagentStop: () => handleSubagentStop,
|
|
36298
|
+
handleSystemNotification: () => handleSystemNotification,
|
|
36023
36299
|
handleToolComplete: () => handleToolComplete,
|
|
36024
36300
|
handleToolStart: () => handleToolStart,
|
|
36025
36301
|
handleWorkPromptSubmit: () => handleWorkPromptSubmit,
|
|
@@ -62451,7 +62727,7 @@ async function startTask(taskId, cwd, accessor) {
|
|
|
62451
62727
|
accessor
|
|
62452
62728
|
);
|
|
62453
62729
|
const { hooks: hooks2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
62454
|
-
hooks2.dispatch("
|
|
62730
|
+
hooks2.dispatch("PreToolUse", cwd ?? process.cwd(), {
|
|
62455
62731
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
62456
62732
|
taskId,
|
|
62457
62733
|
taskTitle: task.title
|
|
@@ -62477,7 +62753,7 @@ async function stopTask(cwd, accessor) {
|
|
|
62477
62753
|
const now2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
62478
62754
|
if (taskId && task) {
|
|
62479
62755
|
const { hooks: hooks2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
62480
|
-
hooks2.dispatch("
|
|
62756
|
+
hooks2.dispatch("PostToolUse", cwd ?? process.cwd(), {
|
|
62481
62757
|
timestamp: now2,
|
|
62482
62758
|
taskId,
|
|
62483
62759
|
taskTitle: task.title,
|
|
@@ -67884,6 +68160,162 @@ var init_bootstrap = __esm({
|
|
|
67884
68160
|
}
|
|
67885
68161
|
});
|
|
67886
68162
|
|
|
68163
|
+
// packages/core/src/sessions/snapshot.ts
|
|
68164
|
+
async function serializeSession(projectRoot, options = {}, accessor) {
|
|
68165
|
+
const acc = accessor ?? await getAccessor(projectRoot);
|
|
68166
|
+
const maxObs = options.maxObservations ?? 10;
|
|
68167
|
+
const maxDescLen = options.maxDescriptionLength ?? 500;
|
|
68168
|
+
const sessions2 = await acc.loadSessions();
|
|
68169
|
+
let session;
|
|
68170
|
+
if (options.sessionId) {
|
|
68171
|
+
session = sessions2.find((s) => s.id === options.sessionId);
|
|
68172
|
+
} else {
|
|
68173
|
+
session = sessions2.filter((s) => s.status === "active").sort((a, b) => new Date(b.startedAt).getTime() - new Date(a.startedAt).getTime())[0];
|
|
68174
|
+
}
|
|
68175
|
+
if (!session) {
|
|
68176
|
+
throw new CleoError(
|
|
68177
|
+
31 /* SESSION_NOT_FOUND */,
|
|
68178
|
+
options.sessionId ? `Session '${options.sessionId}' not found` : "No active session to serialize",
|
|
68179
|
+
{ fix: "Use 'cleo session list' to see available sessions" }
|
|
68180
|
+
);
|
|
68181
|
+
}
|
|
68182
|
+
const handoff = await computeHandoff(projectRoot, { sessionId: session.id });
|
|
68183
|
+
const decisionLog = await getDecisionLog(projectRoot, { sessionId: session.id });
|
|
68184
|
+
const decisions = decisionLog.map((d) => ({
|
|
68185
|
+
decision: d.decision,
|
|
68186
|
+
rationale: d.rationale,
|
|
68187
|
+
taskId: d.taskId,
|
|
68188
|
+
recordedAt: d.timestamp ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
68189
|
+
}));
|
|
68190
|
+
let observations = [];
|
|
68191
|
+
try {
|
|
68192
|
+
const { searchBrainCompact: searchBrainCompact2 } = await Promise.resolve().then(() => (init_brain_retrieval(), brain_retrieval_exports));
|
|
68193
|
+
const results = await searchBrainCompact2(projectRoot, {
|
|
68194
|
+
query: session.id,
|
|
68195
|
+
limit: maxObs,
|
|
68196
|
+
tables: ["observations"]
|
|
68197
|
+
});
|
|
68198
|
+
if (Array.isArray(results)) {
|
|
68199
|
+
observations = results.map(
|
|
68200
|
+
(r) => ({
|
|
68201
|
+
id: r.id,
|
|
68202
|
+
text: r.text ?? "",
|
|
68203
|
+
type: r.type ?? "discovery",
|
|
68204
|
+
createdAt: r.createdAt ?? ""
|
|
68205
|
+
})
|
|
68206
|
+
);
|
|
68207
|
+
}
|
|
68208
|
+
} catch {
|
|
68209
|
+
}
|
|
68210
|
+
let activeTask = null;
|
|
68211
|
+
if (session.taskWork?.taskId) {
|
|
68212
|
+
try {
|
|
68213
|
+
const { tasks: tasks2 } = await acc.queryTasks({});
|
|
68214
|
+
const task = tasks2.find((t) => t.id === session.taskWork?.taskId);
|
|
68215
|
+
if (task) {
|
|
68216
|
+
const desc7 = task.description ?? "";
|
|
68217
|
+
activeTask = {
|
|
68218
|
+
taskId: task.id,
|
|
68219
|
+
title: task.title,
|
|
68220
|
+
status: task.status,
|
|
68221
|
+
priority: task.priority ?? "medium",
|
|
68222
|
+
description: desc7.length > maxDescLen ? desc7.slice(0, maxDescLen) + "..." : desc7,
|
|
68223
|
+
acceptance: Array.isArray(task.acceptance) ? task.acceptance.join("\n") : task.acceptance ?? void 0
|
|
68224
|
+
};
|
|
68225
|
+
}
|
|
68226
|
+
} catch {
|
|
68227
|
+
}
|
|
68228
|
+
}
|
|
68229
|
+
const startTime = new Date(session.startedAt).getTime();
|
|
68230
|
+
const now2 = Date.now();
|
|
68231
|
+
const durationMinutes = Math.round((now2 - startTime) / 6e4);
|
|
68232
|
+
return {
|
|
68233
|
+
version: SNAPSHOT_VERSION,
|
|
68234
|
+
capturedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
68235
|
+
session,
|
|
68236
|
+
handoff,
|
|
68237
|
+
decisions,
|
|
68238
|
+
observations,
|
|
68239
|
+
activeTask,
|
|
68240
|
+
durationMinutes
|
|
68241
|
+
};
|
|
68242
|
+
}
|
|
68243
|
+
async function restoreSession(projectRoot, snapshot, options = {}, accessor) {
|
|
68244
|
+
if (snapshot.version > SNAPSHOT_VERSION) {
|
|
68245
|
+
throw new CleoError(
|
|
68246
|
+
6 /* VALIDATION_ERROR */,
|
|
68247
|
+
`Snapshot version ${snapshot.version} is newer than supported version ${SNAPSHOT_VERSION}`,
|
|
68248
|
+
{ fix: "Upgrade @cleocode/core to a newer version that supports this snapshot format" }
|
|
68249
|
+
);
|
|
68250
|
+
}
|
|
68251
|
+
const acc = accessor ?? await getAccessor(projectRoot);
|
|
68252
|
+
const activate = options.activate ?? true;
|
|
68253
|
+
if (activate) {
|
|
68254
|
+
const sessions2 = await acc.loadSessions();
|
|
68255
|
+
const scope = snapshot.session.scope;
|
|
68256
|
+
const activeConflict = sessions2.find(
|
|
68257
|
+
(s) => s.status === "active" && s.scope.type === scope.type && s.scope.epicId === scope.epicId && s.id !== snapshot.session.id
|
|
68258
|
+
);
|
|
68259
|
+
if (activeConflict) {
|
|
68260
|
+
throw new CleoError(
|
|
68261
|
+
32 /* SCOPE_CONFLICT */,
|
|
68262
|
+
`Active session '${activeConflict.id}' already exists for scope ${scope.type}${scope.epicId ? ":" + scope.epicId : ""}`,
|
|
68263
|
+
{
|
|
68264
|
+
fix: `End the active session first with 'cleo session end' or restore without activating`,
|
|
68265
|
+
alternatives: [
|
|
68266
|
+
{ action: "End conflicting session", command: "cleo session end" },
|
|
68267
|
+
{ action: "Restore without activating", command: "Restore with activate: false" }
|
|
68268
|
+
]
|
|
68269
|
+
}
|
|
68270
|
+
);
|
|
68271
|
+
}
|
|
68272
|
+
}
|
|
68273
|
+
const restoredSession = {
|
|
68274
|
+
...snapshot.session,
|
|
68275
|
+
status: activate ? "active" : snapshot.session.status,
|
|
68276
|
+
notes: [
|
|
68277
|
+
...snapshot.session.notes ?? [],
|
|
68278
|
+
`Restored from snapshot at ${(/* @__PURE__ */ new Date()).toISOString()} (captured ${snapshot.capturedAt}, duration ${snapshot.durationMinutes}m)`
|
|
68279
|
+
],
|
|
68280
|
+
resumeCount: (snapshot.session.resumeCount ?? 0) + 1
|
|
68281
|
+
};
|
|
68282
|
+
if (options.agent) {
|
|
68283
|
+
restoredSession.agent = options.agent;
|
|
68284
|
+
restoredSession.notes = [
|
|
68285
|
+
...restoredSession.notes ?? [],
|
|
68286
|
+
`Agent handoff: ${snapshot.session.agent ?? "unknown"} \u2192 ${options.agent}`
|
|
68287
|
+
];
|
|
68288
|
+
}
|
|
68289
|
+
restoredSession.handoffJson = JSON.stringify(snapshot.handoff);
|
|
68290
|
+
await acc.upsertSingleSession(restoredSession);
|
|
68291
|
+
try {
|
|
68292
|
+
const { hooks: hooks2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
68293
|
+
await hooks2.dispatch("SessionStart", projectRoot, {
|
|
68294
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
68295
|
+
sessionId: restoredSession.id,
|
|
68296
|
+
name: restoredSession.name,
|
|
68297
|
+
scope: restoredSession.scope,
|
|
68298
|
+
agent: restoredSession.agent,
|
|
68299
|
+
restored: true,
|
|
68300
|
+
snapshotCapturedAt: snapshot.capturedAt
|
|
68301
|
+
});
|
|
68302
|
+
} catch {
|
|
68303
|
+
}
|
|
68304
|
+
return restoredSession;
|
|
68305
|
+
}
|
|
68306
|
+
var SNAPSHOT_VERSION;
|
|
68307
|
+
var init_snapshot2 = __esm({
|
|
68308
|
+
"packages/core/src/sessions/snapshot.ts"() {
|
|
68309
|
+
"use strict";
|
|
68310
|
+
init_src();
|
|
68311
|
+
init_errors3();
|
|
68312
|
+
init_data_accessor();
|
|
68313
|
+
init_decisions();
|
|
68314
|
+
init_handoff();
|
|
68315
|
+
SNAPSHOT_VERSION = 1;
|
|
68316
|
+
}
|
|
68317
|
+
});
|
|
68318
|
+
|
|
67887
68319
|
// packages/core/src/cleo.ts
|
|
67888
68320
|
import path from "node:path";
|
|
67889
68321
|
var Cleo;
|
|
@@ -67906,6 +68338,7 @@ var init_cleo = __esm({
|
|
|
67906
68338
|
init_link_store();
|
|
67907
68339
|
init_release2();
|
|
67908
68340
|
init_sessions();
|
|
68341
|
+
init_snapshot2();
|
|
67909
68342
|
init_sticky();
|
|
67910
68343
|
init_data_accessor();
|
|
67911
68344
|
init_task_work();
|
|
@@ -68015,7 +68448,15 @@ var init_cleo = __esm({
|
|
|
68015
68448
|
recordAssumption: (p) => recordAssumption(root, p),
|
|
68016
68449
|
contextDrift: (p) => getContextDrift(root, p),
|
|
68017
68450
|
decisionLog: (p) => getDecisionLog(root, { sessionId: p?.sessionId, taskId: p?.taskId }),
|
|
68018
|
-
lastHandoff: (scope) => getLastHandoff(root, scope)
|
|
68451
|
+
lastHandoff: (scope) => getLastHandoff(root, scope),
|
|
68452
|
+
serialize: (p) => serializeSession(root, {
|
|
68453
|
+
sessionId: p?.sessionId,
|
|
68454
|
+
maxObservations: p?.maxObservations
|
|
68455
|
+
}),
|
|
68456
|
+
restore: (snapshot, p) => restoreSession(root, snapshot, {
|
|
68457
|
+
agent: p?.agent,
|
|
68458
|
+
activate: p?.activate
|
|
68459
|
+
})
|
|
68019
68460
|
};
|
|
68020
68461
|
}
|
|
68021
68462
|
// === Memory ===
|
|
@@ -68371,6 +68812,7 @@ __export(src_exports, {
|
|
|
68371
68812
|
remote: () => remote_exports,
|
|
68372
68813
|
research: () => research_exports,
|
|
68373
68814
|
resolveProjectPath: () => resolveProjectPath,
|
|
68815
|
+
restoreSession: () => restoreSession,
|
|
68374
68816
|
resumeSession: () => resumeSession,
|
|
68375
68817
|
roadmap: () => roadmap_exports,
|
|
68376
68818
|
routing: () => routing_exports,
|
|
@@ -68387,6 +68829,7 @@ __export(src_exports, {
|
|
|
68387
68829
|
selectSessionSchema: () => selectSessionSchema,
|
|
68388
68830
|
selectTaskSchema: () => selectTaskSchema,
|
|
68389
68831
|
sequence: () => sequence_exports,
|
|
68832
|
+
serializeSession: () => serializeSession,
|
|
68390
68833
|
sessionStatus: () => sessionStatus,
|
|
68391
68834
|
sessionStatusSchema: () => sessionStatusSchema,
|
|
68392
68835
|
sessions: () => sessions_exports,
|
|
@@ -68497,6 +68940,7 @@ var init_src2 = __esm({
|
|
|
68497
68940
|
init_migration();
|
|
68498
68941
|
init_reconciliation();
|
|
68499
68942
|
init_sessions();
|
|
68943
|
+
init_snapshot2();
|
|
68500
68944
|
init_migrate();
|
|
68501
68945
|
init_storage_preflight();
|
|
68502
68946
|
init_task_work();
|
|
@@ -69671,6 +70115,14 @@ var init_protocol_enforcement = __esm({
|
|
|
69671
70115
|
});
|
|
69672
70116
|
|
|
69673
70117
|
// packages/core/src/hooks/types.ts
|
|
70118
|
+
import {
|
|
70119
|
+
buildHookMatrix,
|
|
70120
|
+
CANONICAL_HOOK_EVENTS,
|
|
70121
|
+
HOOK_CATEGORIES,
|
|
70122
|
+
supportsHook,
|
|
70123
|
+
toCanonical,
|
|
70124
|
+
toNative
|
|
70125
|
+
} from "@cleocode/caamp";
|
|
69674
70126
|
import { getCommonHookEvents, getProvidersByHookEvent } from "@cleocode/caamp";
|
|
69675
70127
|
function isProviderHookEvent(event) {
|
|
69676
70128
|
return !INTERNAL_HOOK_EVENT_SET.has(event);
|
|
@@ -79745,6 +80197,7 @@ __export(internal_exports, {
|
|
|
79745
80197
|
resolveTask: () => resolveTask,
|
|
79746
80198
|
restoreBackup: () => restoreBackup,
|
|
79747
80199
|
restoreFromBackup: () => restoreFromBackup,
|
|
80200
|
+
restoreSession: () => restoreSession,
|
|
79748
80201
|
resumeSession: () => resumeSession,
|
|
79749
80202
|
roadmap: () => roadmap_exports,
|
|
79750
80203
|
rollbackRelease: () => rollbackRelease,
|
|
@@ -79772,6 +80225,7 @@ __export(internal_exports, {
|
|
|
79772
80225
|
selectSessionSchema: () => selectSessionSchema,
|
|
79773
80226
|
selectTaskSchema: () => selectTaskSchema,
|
|
79774
80227
|
sequence: () => sequence_exports,
|
|
80228
|
+
serializeSession: () => serializeSession,
|
|
79775
80229
|
sessionStatus: () => sessionStatus,
|
|
79776
80230
|
sessionStatusSchema: () => sessionStatusSchema,
|
|
79777
80231
|
sessions: () => sessions_exports,
|
|
@@ -83405,6 +83859,30 @@ var init_registry5 = __esm({
|
|
|
83405
83859
|
sessionRequired: false,
|
|
83406
83860
|
requiredParams: []
|
|
83407
83861
|
},
|
|
83862
|
+
{
|
|
83863
|
+
gateway: "query",
|
|
83864
|
+
domain: "admin",
|
|
83865
|
+
operation: "hooks.matrix",
|
|
83866
|
+
description: "admin.hooks.matrix (query) \u2014 cross-provider hook support matrix using CAAMP canonical taxonomy",
|
|
83867
|
+
tier: 1,
|
|
83868
|
+
idempotent: true,
|
|
83869
|
+
sessionRequired: false,
|
|
83870
|
+
requiredParams: [],
|
|
83871
|
+
params: [
|
|
83872
|
+
{
|
|
83873
|
+
name: "providerIds",
|
|
83874
|
+
type: "string",
|
|
83875
|
+
required: false,
|
|
83876
|
+
description: "Limit matrix to specific provider IDs (default: all mapped providers)"
|
|
83877
|
+
},
|
|
83878
|
+
{
|
|
83879
|
+
name: "detectProvider",
|
|
83880
|
+
type: "boolean",
|
|
83881
|
+
required: false,
|
|
83882
|
+
description: "Detect current runtime provider (default: true)"
|
|
83883
|
+
}
|
|
83884
|
+
]
|
|
83885
|
+
},
|
|
83408
83886
|
{
|
|
83409
83887
|
gateway: "query",
|
|
83410
83888
|
domain: "admin",
|
|
@@ -84229,6 +84707,114 @@ var init_config_engine = __esm({
|
|
|
84229
84707
|
}
|
|
84230
84708
|
});
|
|
84231
84709
|
|
|
84710
|
+
// packages/cleo/src/dispatch/engines/hooks-engine.ts
|
|
84711
|
+
var hooks_engine_exports = {};
|
|
84712
|
+
__export(hooks_engine_exports, {
|
|
84713
|
+
queryCommonHooks: () => queryCommonHooks,
|
|
84714
|
+
queryHookProviders: () => queryHookProviders,
|
|
84715
|
+
systemHooksMatrix: () => systemHooksMatrix
|
|
84716
|
+
});
|
|
84717
|
+
async function queryHookProviders(event) {
|
|
84718
|
+
if (!isProviderHookEvent(event)) {
|
|
84719
|
+
return engineSuccess({
|
|
84720
|
+
event,
|
|
84721
|
+
providers: []
|
|
84722
|
+
});
|
|
84723
|
+
}
|
|
84724
|
+
const { getProvidersByHookEvent: getProvidersByHookEvent2 } = await import("@cleocode/caamp");
|
|
84725
|
+
const providers = getProvidersByHookEvent2(event);
|
|
84726
|
+
return engineSuccess({
|
|
84727
|
+
event,
|
|
84728
|
+
providers: providers.map((p) => ({
|
|
84729
|
+
id: p.id,
|
|
84730
|
+
name: p.name,
|
|
84731
|
+
supportedHooks: p.capabilities?.hooks?.supported ?? []
|
|
84732
|
+
}))
|
|
84733
|
+
});
|
|
84734
|
+
}
|
|
84735
|
+
async function queryCommonHooks(providerIds) {
|
|
84736
|
+
const { getCommonHookEvents: getCommonHookEvents2 } = await import("@cleocode/caamp");
|
|
84737
|
+
const commonEvents = getCommonHookEvents2(providerIds);
|
|
84738
|
+
return engineSuccess({
|
|
84739
|
+
providerIds,
|
|
84740
|
+
commonEvents
|
|
84741
|
+
});
|
|
84742
|
+
}
|
|
84743
|
+
async function systemHooksMatrix(params) {
|
|
84744
|
+
try {
|
|
84745
|
+
const { buildHookMatrix: buildHookMatrix2, getProviderSummary, getHookMappingsVersion, detectAllProviders: detectAllProviders3 } = await import("@cleocode/caamp");
|
|
84746
|
+
const caampVersion = getHookMappingsVersion();
|
|
84747
|
+
const raw = buildHookMatrix2(params?.providerIds);
|
|
84748
|
+
const boolMatrix = {};
|
|
84749
|
+
for (const event of raw.events) {
|
|
84750
|
+
boolMatrix[event] = {};
|
|
84751
|
+
for (const providerId of raw.providers) {
|
|
84752
|
+
const mapping = raw.matrix[event]?.[providerId];
|
|
84753
|
+
boolMatrix[event][providerId] = mapping?.supported ?? false;
|
|
84754
|
+
}
|
|
84755
|
+
}
|
|
84756
|
+
const summary = raw.providers.map((providerId) => {
|
|
84757
|
+
const provSummary = getProviderSummary(providerId);
|
|
84758
|
+
if (provSummary) {
|
|
84759
|
+
return {
|
|
84760
|
+
providerId,
|
|
84761
|
+
supportedCount: provSummary.supportedCount,
|
|
84762
|
+
totalCanonical: provSummary.totalCanonical,
|
|
84763
|
+
coverage: provSummary.coverage,
|
|
84764
|
+
supported: provSummary.supported,
|
|
84765
|
+
unsupported: provSummary.unsupported
|
|
84766
|
+
};
|
|
84767
|
+
}
|
|
84768
|
+
const supported = raw.events.filter((ev) => boolMatrix[ev]?.[providerId] === true);
|
|
84769
|
+
const unsupported = raw.events.filter((ev) => boolMatrix[ev]?.[providerId] !== true);
|
|
84770
|
+
const totalCanonical = raw.events.length;
|
|
84771
|
+
const coverage = totalCanonical > 0 ? Math.round(supported.length / totalCanonical * 100) : 0;
|
|
84772
|
+
return {
|
|
84773
|
+
providerId,
|
|
84774
|
+
supportedCount: supported.length,
|
|
84775
|
+
totalCanonical,
|
|
84776
|
+
coverage,
|
|
84777
|
+
supported,
|
|
84778
|
+
unsupported
|
|
84779
|
+
};
|
|
84780
|
+
});
|
|
84781
|
+
let detectedProvider = null;
|
|
84782
|
+
const shouldDetect = params?.detectProvider !== false;
|
|
84783
|
+
if (shouldDetect) {
|
|
84784
|
+
try {
|
|
84785
|
+
const detectionResults = detectAllProviders3();
|
|
84786
|
+
const detected = detectionResults.find((r) => r.installed && r.projectDetected);
|
|
84787
|
+
if (detected) {
|
|
84788
|
+
detectedProvider = detected.provider.id;
|
|
84789
|
+
} else {
|
|
84790
|
+
const anyInstalled = detectionResults.find((r) => r.installed);
|
|
84791
|
+
if (anyInstalled) {
|
|
84792
|
+
detectedProvider = anyInstalled.provider.id;
|
|
84793
|
+
}
|
|
84794
|
+
}
|
|
84795
|
+
} catch {
|
|
84796
|
+
}
|
|
84797
|
+
}
|
|
84798
|
+
return engineSuccess({
|
|
84799
|
+
caampVersion,
|
|
84800
|
+
events: raw.events,
|
|
84801
|
+
providers: raw.providers,
|
|
84802
|
+
matrix: boolMatrix,
|
|
84803
|
+
summary,
|
|
84804
|
+
detectedProvider
|
|
84805
|
+
});
|
|
84806
|
+
} catch (err) {
|
|
84807
|
+
return engineError("E_GENERAL", err.message);
|
|
84808
|
+
}
|
|
84809
|
+
}
|
|
84810
|
+
var init_hooks_engine = __esm({
|
|
84811
|
+
"packages/cleo/src/dispatch/engines/hooks-engine.ts"() {
|
|
84812
|
+
"use strict";
|
|
84813
|
+
init_internal();
|
|
84814
|
+
init_error();
|
|
84815
|
+
}
|
|
84816
|
+
});
|
|
84817
|
+
|
|
84232
84818
|
// packages/cleo/src/dispatch/engines/init-engine.ts
|
|
84233
84819
|
async function initProject2(projectRoot, options) {
|
|
84234
84820
|
try {
|
|
@@ -87851,6 +88437,7 @@ var init_engine2 = __esm({
|
|
|
87851
88437
|
init_internal();
|
|
87852
88438
|
init_codebase_map_engine();
|
|
87853
88439
|
init_config_engine();
|
|
88440
|
+
init_hooks_engine();
|
|
87854
88441
|
init_init_engine();
|
|
87855
88442
|
init_lifecycle_engine();
|
|
87856
88443
|
init_memory_engine();
|
|
@@ -88379,6 +88966,13 @@ var init_admin2 = __esm({
|
|
|
88379
88966
|
const result = await systemSmoke();
|
|
88380
88967
|
return wrapResult(result, "query", "admin", operation, startTime);
|
|
88381
88968
|
}
|
|
88969
|
+
case "hooks.matrix": {
|
|
88970
|
+
const result = await systemHooksMatrix({
|
|
88971
|
+
providerIds: params?.providerIds,
|
|
88972
|
+
detectProvider: params?.detectProvider !== false
|
|
88973
|
+
});
|
|
88974
|
+
return wrapResult(result, "query", "admin", operation, startTime);
|
|
88975
|
+
}
|
|
88382
88976
|
default:
|
|
88383
88977
|
return unsupportedOp("query", "admin", operation, startTime);
|
|
88384
88978
|
}
|
|
@@ -88863,7 +89457,8 @@ var init_admin2 = __esm({
|
|
|
88863
89457
|
"backup",
|
|
88864
89458
|
"export",
|
|
88865
89459
|
"map",
|
|
88866
|
-
"smoke"
|
|
89460
|
+
"smoke",
|
|
89461
|
+
"hooks.matrix"
|
|
88867
89462
|
],
|
|
88868
89463
|
mutate: [
|
|
88869
89464
|
"init",
|
|
@@ -92595,46 +93190,6 @@ var init_tasks4 = __esm({
|
|
|
92595
93190
|
}
|
|
92596
93191
|
});
|
|
92597
93192
|
|
|
92598
|
-
// packages/cleo/src/dispatch/engines/hooks-engine.ts
|
|
92599
|
-
var hooks_engine_exports = {};
|
|
92600
|
-
__export(hooks_engine_exports, {
|
|
92601
|
-
queryCommonHooks: () => queryCommonHooks,
|
|
92602
|
-
queryHookProviders: () => queryHookProviders
|
|
92603
|
-
});
|
|
92604
|
-
async function queryHookProviders(event) {
|
|
92605
|
-
if (!isProviderHookEvent(event)) {
|
|
92606
|
-
return engineSuccess({
|
|
92607
|
-
event,
|
|
92608
|
-
providers: []
|
|
92609
|
-
});
|
|
92610
|
-
}
|
|
92611
|
-
const { getProvidersByHookEvent: getProvidersByHookEvent2 } = await import("@cleocode/caamp");
|
|
92612
|
-
const providers = getProvidersByHookEvent2(event);
|
|
92613
|
-
return engineSuccess({
|
|
92614
|
-
event,
|
|
92615
|
-
providers: providers.map((p) => ({
|
|
92616
|
-
id: p.id,
|
|
92617
|
-
name: p.name,
|
|
92618
|
-
supportedHooks: p.capabilities?.hooks?.supported ?? []
|
|
92619
|
-
}))
|
|
92620
|
-
});
|
|
92621
|
-
}
|
|
92622
|
-
async function queryCommonHooks(providerIds) {
|
|
92623
|
-
const { getCommonHookEvents: getCommonHookEvents2 } = await import("@cleocode/caamp");
|
|
92624
|
-
const commonEvents = getCommonHookEvents2(providerIds);
|
|
92625
|
-
return engineSuccess({
|
|
92626
|
-
providerIds,
|
|
92627
|
-
commonEvents
|
|
92628
|
-
});
|
|
92629
|
-
}
|
|
92630
|
-
var init_hooks_engine = __esm({
|
|
92631
|
-
"packages/cleo/src/dispatch/engines/hooks-engine.ts"() {
|
|
92632
|
-
"use strict";
|
|
92633
|
-
init_internal();
|
|
92634
|
-
init_error();
|
|
92635
|
-
}
|
|
92636
|
-
});
|
|
92637
|
-
|
|
92638
93193
|
// packages/cleo/src/dispatch/engines/tools-engine.ts
|
|
92639
93194
|
import {
|
|
92640
93195
|
buildInjectionContent,
|
|
@@ -94224,7 +94779,7 @@ async function dispatchFromCli(gateway, domain2, operation, params, outputOpts)
|
|
|
94224
94779
|
const dispatcher = getCliDispatcher();
|
|
94225
94780
|
const projectRoot = getProjectRoot();
|
|
94226
94781
|
const dispatchStart = Date.now();
|
|
94227
|
-
hooks.dispatch("
|
|
94782
|
+
hooks.dispatch("PromptSubmit", projectRoot, {
|
|
94228
94783
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
94229
94784
|
gateway,
|
|
94230
94785
|
domain: domain2,
|
|
@@ -94240,7 +94795,7 @@ async function dispatchFromCli(gateway, domain2, operation, params, outputOpts)
|
|
|
94240
94795
|
source: "cli",
|
|
94241
94796
|
requestId: randomUUID10()
|
|
94242
94797
|
});
|
|
94243
|
-
hooks.dispatch("
|
|
94798
|
+
hooks.dispatch("ResponseComplete", projectRoot, {
|
|
94244
94799
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
94245
94800
|
gateway,
|
|
94246
94801
|
domain: domain2,
|
|
@@ -94297,7 +94852,7 @@ async function dispatchRaw(gateway, domain2, operation, params) {
|
|
|
94297
94852
|
const dispatcher = getCliDispatcher();
|
|
94298
94853
|
const projectRoot = getProjectRoot();
|
|
94299
94854
|
const dispatchStart = Date.now();
|
|
94300
|
-
hooks.dispatch("
|
|
94855
|
+
hooks.dispatch("PromptSubmit", projectRoot, {
|
|
94301
94856
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
94302
94857
|
gateway,
|
|
94303
94858
|
domain: domain2,
|
|
@@ -94313,7 +94868,7 @@ async function dispatchRaw(gateway, domain2, operation, params) {
|
|
|
94313
94868
|
source: "cli",
|
|
94314
94869
|
requestId: randomUUID10()
|
|
94315
94870
|
});
|
|
94316
|
-
hooks.dispatch("
|
|
94871
|
+
hooks.dispatch("ResponseComplete", projectRoot, {
|
|
94317
94872
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
94318
94873
|
gateway,
|
|
94319
94874
|
domain: domain2,
|
|
@@ -96684,15 +97239,84 @@ function createUpgradeProgress(enabled) {
|
|
|
96684
97239
|
}
|
|
96685
97240
|
|
|
96686
97241
|
// packages/cleo/src/cli/commands/doctor.ts
|
|
97242
|
+
function renderHookMatrixHuman(data) {
|
|
97243
|
+
const { events, providers, matrix, summary, caampVersion, detectedProvider } = data;
|
|
97244
|
+
process.stdout.write(`
|
|
97245
|
+
Provider Hook Matrix (CAAMP ${caampVersion} canonical taxonomy)
|
|
97246
|
+
|
|
97247
|
+
`);
|
|
97248
|
+
if (detectedProvider) {
|
|
97249
|
+
process.stdout.write(`Detected provider: ${detectedProvider}
|
|
97250
|
+
|
|
97251
|
+
`);
|
|
97252
|
+
}
|
|
97253
|
+
if (providers.length === 0) {
|
|
97254
|
+
process.stdout.write("No providers found in CAAMP registry.\n");
|
|
97255
|
+
return;
|
|
97256
|
+
}
|
|
97257
|
+
const EVENT_COL = Math.max(...events.map((e) => e.length), "Event".length);
|
|
97258
|
+
const provCols = providers.map((p) => Math.max(p.length, 5));
|
|
97259
|
+
const headerParts = [
|
|
97260
|
+
"Event".padEnd(EVENT_COL),
|
|
97261
|
+
...providers.map((p, i) => p.padEnd(provCols[i]))
|
|
97262
|
+
];
|
|
97263
|
+
process.stdout.write(` ${headerParts.join(" ")}
|
|
97264
|
+
`);
|
|
97265
|
+
const sepParts = ["-".repeat(EVENT_COL), ...provCols.map((w) => "-".repeat(w))];
|
|
97266
|
+
process.stdout.write(` ${sepParts.join(" ")}
|
|
97267
|
+
`);
|
|
97268
|
+
for (const event of events) {
|
|
97269
|
+
const cells = providers.map((p, i) => {
|
|
97270
|
+
const supported = matrix[event]?.[p] === true;
|
|
97271
|
+
const symbol2 = supported ? "\u2713" : "-";
|
|
97272
|
+
return symbol2.padEnd(provCols[i]);
|
|
97273
|
+
});
|
|
97274
|
+
process.stdout.write(` ${event.padEnd(EVENT_COL)} ${cells.join(" ")}
|
|
97275
|
+
`);
|
|
97276
|
+
}
|
|
97277
|
+
process.stdout.write("\n");
|
|
97278
|
+
const coverageParts = summary.map(
|
|
97279
|
+
(s) => `${s.providerId} ${s.supportedCount}/${s.totalCanonical} (${s.coverage}%)`
|
|
97280
|
+
);
|
|
97281
|
+
process.stdout.write(`Coverage: ${coverageParts.join(", ")}
|
|
97282
|
+
|
|
97283
|
+
`);
|
|
97284
|
+
}
|
|
96687
97285
|
function registerDoctorCommand(program) {
|
|
96688
|
-
program.command("doctor").description("Run system diagnostics and health checks").option("--detailed", "Show detailed health check results").option("--comprehensive", "Run comprehensive doctor report").option("--full", "Run operational smoke tests across all domains").option("--fix", "Auto-fix failed checks").option("--coherence", "Run coherence check across task data").action(async (opts, command) => {
|
|
97286
|
+
program.command("doctor").description("Run system diagnostics and health checks").option("--detailed", "Show detailed health check results").option("--comprehensive", "Run comprehensive doctor report").option("--full", "Run operational smoke tests across all domains").option("--fix", "Auto-fix failed checks").option("--coherence", "Run coherence check across task data").option("--hooks", "Show cross-provider hook support matrix (CAAMP canonical taxonomy)").action(async (opts, command) => {
|
|
96689
97287
|
const globalOpts = command.optsWithGlobals ? command.optsWithGlobals() : command.opts();
|
|
96690
97288
|
const mergedOpts = { ...globalOpts, ...opts };
|
|
96691
97289
|
const isHuman = mergedOpts["human"] === true || !!process.stdout.isTTY && mergedOpts["json"] !== true;
|
|
96692
97290
|
const progress = createDoctorProgress(isHuman);
|
|
96693
97291
|
progress.start();
|
|
96694
97292
|
try {
|
|
96695
|
-
if (mergedOpts["
|
|
97293
|
+
if (mergedOpts["hooks"]) {
|
|
97294
|
+
progress.step(0, "Building provider hook matrix");
|
|
97295
|
+
if (isHuman) {
|
|
97296
|
+
const response = await dispatchRaw("query", "admin", "hooks.matrix", {
|
|
97297
|
+
detectProvider: true
|
|
97298
|
+
});
|
|
97299
|
+
progress.complete("Hook matrix complete");
|
|
97300
|
+
if (response.success && response.data) {
|
|
97301
|
+
renderHookMatrixHuman(response.data);
|
|
97302
|
+
} else {
|
|
97303
|
+
process.stderr.write(
|
|
97304
|
+
`Error: ${response.error?.message ?? "Failed to build hook matrix"}
|
|
97305
|
+
`
|
|
97306
|
+
);
|
|
97307
|
+
process.exitCode = 1;
|
|
97308
|
+
}
|
|
97309
|
+
} else {
|
|
97310
|
+
await dispatchFromCli(
|
|
97311
|
+
"query",
|
|
97312
|
+
"admin",
|
|
97313
|
+
"hooks.matrix",
|
|
97314
|
+
{ detectProvider: true },
|
|
97315
|
+
{ command: "doctor", operation: "admin.hooks.matrix" }
|
|
97316
|
+
);
|
|
97317
|
+
progress.complete("Hook matrix complete");
|
|
97318
|
+
}
|
|
97319
|
+
} else if (mergedOpts["full"]) {
|
|
96696
97320
|
progress.step(0, "Running operational smoke tests");
|
|
96697
97321
|
await dispatchFromCli(
|
|
96698
97322
|
"query",
|