@xopcai/xopc 0.0.89 → 0.0.91
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/README.md +36 -12
- package/README.zh-CN.md +36 -12
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/Combination-HAlzriaz.js +41 -0
- package/dist/gateway/static/root/assets/agents-bVWUlrlD.js +222 -0
- package/dist/gateway/static/root/assets/apps-page-CIC8bmvZ.js +1 -0
- package/dist/gateway/static/root/assets/{attachment-preview-renderer-CpyoFbs4.js → attachment-preview-renderer-DBAxQXb-.js} +2 -2
- package/dist/gateway/static/root/assets/{attachment-process-heavy-CqVriadb.js → attachment-process-heavy-Csq3TrrP.js} +4 -4
- package/dist/gateway/static/root/assets/channels-settings-C8G8RAAP.js +1 -0
- package/dist/gateway/static/root/assets/{channels-status-swr-DaHGkRF1.js → channels-status-swr-CYWL5DLD.js} +1 -1
- package/dist/gateway/static/root/assets/circle-check-C23XjkUj.js +1 -0
- package/dist/gateway/static/root/assets/copy-Dv6d4Dvw.js +1 -0
- package/dist/gateway/static/root/assets/cron-api-TVqLlGAC.js +1 -0
- package/dist/gateway/static/root/assets/cron-dreaming-jobs-Ip703-qM.js +2 -0
- package/dist/gateway/static/root/assets/cron-page-BtcFYlvv.js +1 -0
- package/dist/gateway/static/root/assets/dist-CUV1uY5f.js +1 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-CtuKJ9tE.js → extension-debug-page-mTLHRDp1.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-ykzjOkR5.js → extension-page-iI8BI7WK.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-Ce2qrdpO.js → extension-settings-page-ByXcdubM.js} +1 -1
- package/dist/gateway/static/root/assets/{fetch-C9FFJjuH.js → fetch-BWtQq_Ys.js} +1 -1
- package/dist/gateway/static/root/assets/{field-primitives-BFcrNeTU.js → field-primitives-BsZ-4VT5.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-config-api-CEg4Vr9R.js → heartbeat-config-api-WjTsRLCU.js} +1 -1
- package/dist/gateway/static/root/assets/{index-CZfy9oxs.js → index-CKkR-v9U.js} +101 -97
- package/dist/gateway/static/root/assets/index-VlELBY99.css +1 -0
- package/dist/gateway/static/root/assets/logs-page-ClnIpxfd.js +1 -0
- package/dist/gateway/static/root/assets/note-detail-page-B91pLkEI.css +1 -0
- package/dist/gateway/static/root/assets/note-detail-page-DJ2Mb4x7.js +179 -0
- package/dist/gateway/static/root/assets/note-time-JLBPSLzK.js +1 -0
- package/dist/gateway/static/root/assets/notes-page-BE-75qz9.js +1 -0
- package/dist/gateway/static/root/assets/{pdf-BnEvgIXZ.js → pdf-epILhEOn.js} +1 -1
- package/dist/gateway/static/root/assets/preload-helper-zJ_50EbN.js +1 -0
- package/dist/gateway/static/root/assets/sessions-page-bJJkWtTl.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-BqdzA28u.js → settings-form-section-DSYCknxM.js} +1 -1
- package/dist/gateway/static/root/assets/settings-page-WcMXLq2U.js +3 -0
- package/dist/gateway/static/root/assets/share-preview-page-awRqs4hV.js +2 -0
- package/dist/gateway/static/root/assets/skills-page-Lu-i1JG7.js +2 -0
- package/dist/gateway/static/root/assets/{theme-store-CNqbmTNV.js → theme-store-BC-42BoZ.js} +1 -1
- package/dist/gateway/static/root/assets/toast-z0toXu32.js +1 -0
- package/dist/gateway/static/root/assets/url-CY1RQKTU.js +3 -0
- package/dist/gateway/static/root/assets/{utils-BWm2tG2w.js → utils-DX3TQuap.js} +1 -1
- package/dist/gateway/static/root/assets/vendor-codemirror-DYoKfS8f.js +45 -0
- package/dist/gateway/static/root/assets/voice-api-key-field-B5uKlDqA.js +1 -0
- package/dist/gateway/static/root/assets/workflow-page.utils-ClC37yEp.js +1 -0
- package/dist/gateway/static/root/assets/workflows-page-C7VhIXtR.js +27 -0
- package/dist/gateway/static/root/index.html +11 -7
- package/dist/package.js +1 -1
- package/dist/src/agent/skills/marketplace/adapters/skillhub/adapter.js +20 -18
- package/dist/src/agent/skills/marketplace/adapters/skillhub/adapter.js.map +1 -1
- package/dist/src/agent/tools/cronjob-tool.d.ts +6 -0
- package/dist/src/agent/tools/cronjob-tool.js +74 -9
- package/dist/src/agent/tools/cronjob-tool.js.map +1 -1
- package/dist/src/agent/tools/edit.d.ts +5 -1
- package/dist/src/agent/tools/edit.js +7 -5
- package/dist/src/agent/tools/edit.js.map +1 -1
- package/dist/src/agent/tools/factory.js +2 -2
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/write.d.ts +5 -1
- package/dist/src/agent/tools/write.js +7 -5
- package/dist/src/agent/tools/write.js.map +1 -1
- package/dist/src/agent/workflow/agent-progress.js +2 -0
- package/dist/src/agent/workflow/agent-progress.js.map +1 -1
- package/dist/src/agent/workflow/builtins/client-proposal.d.ts +12 -0
- package/dist/src/agent/workflow/builtins/client-proposal.js +155 -0
- package/dist/src/agent/workflow/builtins/client-proposal.js.map +1 -0
- package/dist/src/agent/workflow/builtins/competitor-scan.d.ts +12 -0
- package/dist/src/agent/workflow/builtins/competitor-scan.js +150 -0
- package/dist/src/agent/workflow/builtins/competitor-scan.js.map +1 -0
- package/dist/src/agent/workflow/builtins/content-draft.d.ts +13 -0
- package/dist/src/agent/workflow/builtins/content-draft.js +146 -0
- package/dist/src/agent/workflow/builtins/content-draft.js.map +1 -0
- package/dist/src/agent/workflow/builtins/content-repurpose.d.ts +11 -0
- package/dist/src/agent/workflow/builtins/content-repurpose.js +137 -0
- package/dist/src/agent/workflow/builtins/content-repurpose.js.map +1 -0
- package/dist/src/agent/workflow/builtins/decision-compare.d.ts +13 -0
- package/dist/src/agent/workflow/builtins/decision-compare.js +173 -0
- package/dist/src/agent/workflow/builtins/decision-compare.js.map +1 -0
- package/dist/src/agent/workflow/builtins/inbox-triage.d.ts +11 -0
- package/dist/src/agent/workflow/builtins/inbox-triage.js +148 -0
- package/dist/src/agent/workflow/builtins/inbox-triage.js.map +1 -0
- package/dist/src/agent/workflow/builtins/index.d.ts +10 -1
- package/dist/src/agent/workflow/builtins/index.js +46 -1
- package/dist/src/agent/workflow/builtins/index.js.map +1 -1
- package/dist/src/agent/workflow/builtins/meeting-prep.d.ts +12 -0
- package/dist/src/agent/workflow/builtins/meeting-prep.js +144 -0
- package/dist/src/agent/workflow/builtins/meeting-prep.js.map +1 -0
- package/dist/src/agent/workflow/builtins/offer-design.d.ts +12 -0
- package/dist/src/agent/workflow/builtins/offer-design.js +161 -0
- package/dist/src/agent/workflow/builtins/offer-design.js.map +1 -0
- package/dist/src/agent/workflow/builtins/weekly-review.d.ts +12 -0
- package/dist/src/agent/workflow/builtins/weekly-review.js +131 -0
- package/dist/src/agent/workflow/builtins/weekly-review.js.map +1 -0
- package/dist/src/agent/workflow/step-labels.js +2 -2
- package/dist/src/agent/workflow/step-labels.js.map +1 -1
- package/dist/src/agent/workflow/subagent-runner.js +3 -1
- package/dist/src/agent/workflow/subagent-runner.js.map +1 -1
- package/dist/src/agent/workflow/types.d.ts +4 -0
- package/dist/src/chat-commands/agent-edit.d.ts +4 -0
- package/dist/src/chat-commands/agent-edit.js +136 -0
- package/dist/src/chat-commands/agent-edit.js.map +1 -0
- package/dist/src/chat-commands/index.d.ts +1 -0
- package/dist/src/chat-commands/index.js +3 -1
- package/dist/src/chat-commands/index.js.map +1 -1
- package/dist/src/cli/bin.js +2 -0
- package/dist/src/cli/bin.js.map +1 -1
- package/dist/src/cli/commands/cron.js +42 -3
- package/dist/src/cli/commands/cron.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/session-integrity.js +79 -56
- package/dist/src/cli/commands/doctor/checks/session-integrity.js.map +1 -1
- package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
- package/dist/src/cli/commands/update.js +86 -79
- package/dist/src/cli/commands/update.js.map +1 -1
- package/dist/src/commands/agents.config.d.ts +3 -2
- package/dist/src/commands/agents.config.js +5 -2
- package/dist/src/commands/agents.config.js.map +1 -1
- package/dist/src/config/agent-typed-models.d.ts +2 -7
- package/dist/src/config/agent-typed-models.js +3 -14
- package/dist/src/config/agent-typed-models.js.map +1 -1
- package/dist/src/config/localized-text.d.ts +6 -0
- package/dist/src/config/localized-text.js +42 -0
- package/dist/src/config/localized-text.js.map +1 -0
- package/dist/src/config/models-json.d.ts +6 -6
- package/dist/src/config/schema.d.ts +6 -21
- package/dist/src/config/schema.js +4 -4
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/cron/executor.d.ts +2 -0
- package/dist/src/cron/executor.js +111 -1
- package/dist/src/cron/executor.js.map +1 -1
- package/dist/src/cron/types.d.ts +8 -1
- package/dist/src/cron/validation.d.ts +4 -0
- package/dist/src/cron/validation.js +4 -3
- package/dist/src/cron/validation.js.map +1 -1
- package/dist/src/cron/workflow-run-completion.d.ts +23 -0
- package/dist/src/cron/workflow-run-completion.js +72 -0
- package/dist/src/cron/workflow-run-completion.js.map +1 -0
- package/dist/src/extensions/update.d.ts +51 -0
- package/dist/src/extensions/update.js +260 -0
- package/dist/src/extensions/update.js.map +1 -0
- package/dist/src/gateway/agents-admin.d.ts +15 -8
- package/dist/src/gateway/agents-admin.js +77 -28
- package/dist/src/gateway/agents-admin.js.map +1 -1
- package/dist/src/gateway/heartbeat/service.js +1 -1
- package/dist/src/gateway/hono/lib/config-payload.d.ts +6 -0
- package/dist/src/gateway/hono/lib/config-payload.js +3 -1
- package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
- package/dist/src/gateway/hono/middleware/auth.d.ts +2 -0
- package/dist/src/gateway/hono/middleware/auth.js +11 -7
- package/dist/src/gateway/hono/middleware/auth.js.map +1 -1
- package/dist/src/gateway/hono/routes/agents.js +55 -12
- package/dist/src/gateway/hono/routes/agents.js.map +1 -1
- package/dist/src/gateway/hono/routes/config-patch/agents.js +1 -1
- package/dist/src/gateway/hono/routes/config-patch/gateway.d.ts +2 -2
- package/dist/src/gateway/hono/routes/config-patch/gateway.js +12 -0
- package/dist/src/gateway/hono/routes/config-patch/gateway.js.map +1 -1
- package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
- package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
- package/dist/src/gateway/hono/routes/notes.d.ts +3 -0
- package/dist/src/gateway/hono/routes/notes.js +274 -0
- package/dist/src/gateway/hono/routes/notes.js.map +1 -0
- package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
- package/dist/src/gateway/hono/routes/update.js +55 -107
- package/dist/src/gateway/hono/routes/update.js.map +1 -1
- package/dist/src/gateway/hono/routes/workflows.js +3 -1
- package/dist/src/gateway/hono/routes/workflows.js.map +1 -1
- package/dist/src/gateway/server.js +2 -0
- package/dist/src/gateway/server.js.map +1 -1
- package/dist/src/gateway/service.d.ts +3 -0
- package/dist/src/gateway/service.js +12 -1
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/gateway/workspace-ripgrep.d.ts +6 -0
- package/dist/src/gateway/workspace-ripgrep.js +62 -11
- package/dist/src/gateway/workspace-ripgrep.js.map +1 -1
- package/dist/src/heartbeat/index.js +1 -1
- package/dist/src/infra/brew.d.ts +4 -0
- package/dist/src/infra/brew.js +20 -0
- package/dist/src/infra/brew.js.map +1 -0
- package/dist/src/infra/package-json.d.ts +2 -0
- package/dist/src/infra/package-json.js +23 -0
- package/dist/src/infra/package-json.js.map +1 -0
- package/dist/src/infra/package-update-steps.d.ts +35 -0
- package/dist/src/infra/package-update-steps.js +304 -0
- package/dist/src/infra/package-update-steps.js.map +1 -0
- package/dist/src/infra/path-env.d.ts +11 -0
- package/dist/src/infra/path-env.js +90 -0
- package/dist/src/infra/path-env.js.map +1 -0
- package/dist/src/infra/path-prepend.d.ts +7 -0
- package/dist/src/infra/path-prepend.js +44 -0
- package/dist/src/infra/path-prepend.js.map +1 -0
- package/dist/src/infra/stable-node-path.d.ts +2 -0
- package/dist/src/infra/stable-node-path.js +28 -0
- package/dist/src/infra/stable-node-path.js.map +1 -0
- package/dist/src/infra/update-global.d.ts +30 -23
- package/dist/src/infra/update-global.js +113 -64
- package/dist/src/infra/update-global.js.map +1 -1
- package/dist/src/infra/update-log.d.ts +1 -0
- package/dist/src/infra/update-log.js +12 -0
- package/dist/src/infra/update-log.js.map +1 -0
- package/dist/src/infra/update-restart.d.ts +20 -0
- package/dist/src/infra/update-restart.js +165 -0
- package/dist/src/infra/update-restart.js.map +1 -0
- package/dist/src/infra/update-runner.d.ts +89 -1
- package/dist/src/infra/update-runner.js +604 -173
- package/dist/src/infra/update-runner.js.map +1 -1
- package/dist/src/infra/update-startup.d.ts +3 -0
- package/dist/src/infra/update-startup.js +8 -4
- package/dist/src/infra/update-startup.js.map +1 -1
- package/dist/src/notes/attachment-ref.d.ts +9 -0
- package/dist/src/notes/attachment-ref.js +27 -0
- package/dist/src/notes/attachment-ref.js.map +1 -0
- package/dist/src/notes/index.d.ts +4 -0
- package/dist/src/notes/index.js +4 -0
- package/dist/src/notes/note-attachment-sync.d.ts +7 -0
- package/dist/src/notes/note-attachment-sync.js +46 -0
- package/dist/src/notes/note-attachment-sync.js.map +1 -0
- package/dist/src/notes/note-index-meta.d.ts +14 -0
- package/dist/src/notes/note-index-meta.js +87 -0
- package/dist/src/notes/note-index-meta.js.map +1 -0
- package/dist/src/notes/paths.d.ts +5 -0
- package/dist/src/notes/paths.js +23 -0
- package/dist/src/notes/paths.js.map +1 -0
- package/dist/src/notes/service.d.ts +42 -0
- package/dist/src/notes/service.js +331 -0
- package/dist/src/notes/service.js.map +1 -0
- package/dist/src/notes/store.d.ts +33 -0
- package/dist/src/notes/store.js +317 -0
- package/dist/src/notes/store.js.map +1 -0
- package/dist/src/notes/types.d.ts +162 -0
- package/dist/src/notes/types.js +1 -0
- package/dist/src/routing/resolve-route.d.ts +3 -1
- package/dist/src/routing/resolve-route.js.map +1 -1
- package/dist/src/session/store.d.ts +5 -3
- package/dist/src/session/store.js +66 -20
- package/dist/src/session/store.js.map +1 -1
- package/dist/src/utils/logger/stats.d.ts +1 -1
- package/dist/src/workflows/domain/event.d.ts +3 -0
- package/dist/src/workflows/domain/run.d.ts +3 -0
- package/dist/src/workflows/domain/run.js.map +1 -1
- package/dist/src/workflows/engine/projector.js +17 -0
- package/dist/src/workflows/engine/projector.js.map +1 -1
- package/dist/src/workflows/engine/workflow-engine.js +127 -0
- package/dist/src/workflows/engine/workflow-engine.js.map +1 -1
- package/dist/src/workflows/index.js +1 -1
- package/dist/src/workflows/service/run-view-to-snapshot.js +3 -1
- package/dist/src/workflows/service/run-view-to-snapshot.js.map +1 -1
- package/dist/src/workflows/service/workflow-run-service.d.ts +1 -0
- package/dist/src/workflows/service/workflow-run-service.js +4 -1
- package/dist/src/workflows/service/workflow-run-service.js.map +1 -1
- package/dist/src/workflows/service/workflow-session-bridge.js +1 -1
- package/package.json +1 -1
- package/dist/gateway/static/root/assets/agents-B6PJB07W.js +0 -222
- package/dist/gateway/static/root/assets/apps-page-BOr0B1wv.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-BelUKggl.js +0 -1
- package/dist/gateway/static/root/assets/cron-api-CjOg-BIj.js +0 -1
- package/dist/gateway/static/root/assets/cron-dreaming-jobs-DueM3rBz.js +0 -2
- package/dist/gateway/static/root/assets/cron-page-DhoZmZXb.js +0 -1
- package/dist/gateway/static/root/assets/dist-6LecgDx5.js +0 -1
- package/dist/gateway/static/root/assets/dist-BTWC-BTN.js +0 -45
- package/dist/gateway/static/root/assets/index-CiN1cQiQ.css +0 -1
- package/dist/gateway/static/root/assets/logs-page-BwWLfqvd.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-DV5WN8uk.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-CfOBRbPX.js +0 -3
- package/dist/gateway/static/root/assets/share-preview-page-Di5Bzh4g.js +0 -2
- package/dist/gateway/static/root/assets/skills-page-D0H5Kaxg.js +0 -2
- package/dist/gateway/static/root/assets/url-aYn-Rj1C.js +0 -7
- package/dist/gateway/static/root/assets/vendor-codemirror-D0yxdRpg.js +0 -58
- package/dist/gateway/static/root/assets/voice-api-key-field-X2UfnHeq.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-BOPpO3NG.js +0 -27
|
@@ -64,6 +64,8 @@ export interface WorkflowAgentStep {
|
|
|
64
64
|
label: string;
|
|
65
65
|
detail?: string;
|
|
66
66
|
status: WorkflowAgentStepStatus;
|
|
67
|
+
resultPreview?: string;
|
|
68
|
+
error?: string;
|
|
67
69
|
startedAtMs?: number;
|
|
68
70
|
durationMs?: number;
|
|
69
71
|
}
|
|
@@ -134,6 +136,8 @@ export type SubagentProgressEvent = {
|
|
|
134
136
|
toolCallId: string;
|
|
135
137
|
toolName: string;
|
|
136
138
|
isError: boolean;
|
|
139
|
+
resultPreview?: string;
|
|
140
|
+
error?: string;
|
|
137
141
|
} | {
|
|
138
142
|
type: 'iteration';
|
|
139
143
|
count: number;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { init_agent_scope, normalizeAgentId, resolveAgentProfileDir } from "../agent/agent-scope.js";
|
|
2
|
+
import { init_agent_session_key, resolveAgentIdFromSessionKey } from "../routing/agent-session-key.js";
|
|
3
|
+
import { WORKSPACE_FILES, init_paths } from "../config/paths.js";
|
|
4
|
+
import { commandRegistry } from "./registry.js";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { readFile } from "node:fs/promises";
|
|
7
|
+
//#region src/chat-commands/agent-edit.ts
|
|
8
|
+
/**
|
|
9
|
+
* /agent-edit — open the current chat as an agent profile editing session.
|
|
10
|
+
*/
|
|
11
|
+
init_agent_session_key();
|
|
12
|
+
init_agent_scope();
|
|
13
|
+
init_paths();
|
|
14
|
+
const PROFILE_FILE_NAMES = [
|
|
15
|
+
WORKSPACE_FILES.SOUL,
|
|
16
|
+
WORKSPACE_FILES.IDENTITY,
|
|
17
|
+
WORKSPACE_FILES.USER,
|
|
18
|
+
WORKSPACE_FILES.TOOLS,
|
|
19
|
+
WORKSPACE_FILES.AGENTS,
|
|
20
|
+
WORKSPACE_FILES.HEARTBEAT,
|
|
21
|
+
WORKSPACE_FILES.MEMORY,
|
|
22
|
+
WORKSPACE_FILES.BOOTSTRAP
|
|
23
|
+
];
|
|
24
|
+
const DEFAULT_PREVIEW_CHARS = 900;
|
|
25
|
+
const MAX_PREVIEW_CHARS = 4e3;
|
|
26
|
+
function parseArgs(args) {
|
|
27
|
+
const trimmed = args.trim();
|
|
28
|
+
if (!trimmed) return { previewChars: DEFAULT_PREVIEW_CHARS };
|
|
29
|
+
const parts = trimmed.split(/\s+/);
|
|
30
|
+
let fileName;
|
|
31
|
+
let previewChars = DEFAULT_PREVIEW_CHARS;
|
|
32
|
+
for (const part of parts) {
|
|
33
|
+
const limitMatch = /^--limit=(\d+)$/.exec(part);
|
|
34
|
+
if (limitMatch) {
|
|
35
|
+
previewChars = Math.min(Number(limitMatch[1]), MAX_PREVIEW_CHARS);
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (!fileName) fileName = part;
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
fileName,
|
|
42
|
+
previewChars
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function normalizeProfileFileName(input) {
|
|
46
|
+
if (!input) return;
|
|
47
|
+
const basename = input.trim().replace(/\\/g, "/").split("/").pop();
|
|
48
|
+
return PROFILE_FILE_NAMES.find((name) => name.toLowerCase() === basename?.toLowerCase());
|
|
49
|
+
}
|
|
50
|
+
async function readPreview(path, limit) {
|
|
51
|
+
try {
|
|
52
|
+
const trimmed = (await readFile(path, "utf-8")).trimEnd();
|
|
53
|
+
if (trimmed.length <= limit) return {
|
|
54
|
+
content: trimmed,
|
|
55
|
+
missing: false
|
|
56
|
+
};
|
|
57
|
+
return {
|
|
58
|
+
content: `${trimmed.slice(0, limit)}\n\n… truncated, ask me to read the full file before editing …`,
|
|
59
|
+
missing: false
|
|
60
|
+
};
|
|
61
|
+
} catch {
|
|
62
|
+
return {
|
|
63
|
+
content: "",
|
|
64
|
+
missing: true
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function buildEditInstructions(agentId, fileNames) {
|
|
69
|
+
const files = fileNames.map((name) => `\`${name}\``).join(", ");
|
|
70
|
+
return [
|
|
71
|
+
`You are editing agent \`${agentId}\`.`,
|
|
72
|
+
"",
|
|
73
|
+
"Tell me what to change, or say things like:",
|
|
74
|
+
"- “Refine `SOUL.md` to sound warmer and more concise.”",
|
|
75
|
+
"- “Update `IDENTITY.md` so this agent is focused on data analysis.”",
|
|
76
|
+
"- “Read `SOUL.md` first, propose changes, then write them back.”",
|
|
77
|
+
"",
|
|
78
|
+
`Editable profile files: ${files}.`,
|
|
79
|
+
"I can read and update these by bare filename with `read_file`, `edit_file`, and `write_file`."
|
|
80
|
+
].join("\n");
|
|
81
|
+
}
|
|
82
|
+
const agentEditCommand = {
|
|
83
|
+
id: "agent.edit",
|
|
84
|
+
name: "agent-edit",
|
|
85
|
+
aliases: ["agentedit"],
|
|
86
|
+
description: "Show editable profile files for the current agent and prepare this chat for profile edits.",
|
|
87
|
+
category: "system",
|
|
88
|
+
scope: [
|
|
89
|
+
"global",
|
|
90
|
+
"private",
|
|
91
|
+
"group"
|
|
92
|
+
],
|
|
93
|
+
acceptsArgs: true,
|
|
94
|
+
examples: [
|
|
95
|
+
"/agent-edit",
|
|
96
|
+
"/agent-edit SOUL.md",
|
|
97
|
+
"/agent-edit IDENTITY.md --limit=2000"
|
|
98
|
+
],
|
|
99
|
+
handler: async (ctx, args) => {
|
|
100
|
+
await ctx.setTyping(true);
|
|
101
|
+
const { fileName: rawFileName, previewChars } = parseArgs(args);
|
|
102
|
+
const fileName = normalizeProfileFileName(rawFileName);
|
|
103
|
+
if (rawFileName && !fileName) return {
|
|
104
|
+
content: `⚠️ Unsupported profile file: \`${rawFileName}\`. Use one of: ${PROFILE_FILE_NAMES.map((name) => `\`${name}\``).join(", ")}.`,
|
|
105
|
+
success: false
|
|
106
|
+
};
|
|
107
|
+
const agentId = normalizeAgentId(resolveAgentIdFromSessionKey(ctx.sessionKey));
|
|
108
|
+
const profileDir = resolveAgentProfileDir(ctx.config, agentId);
|
|
109
|
+
const namesToShow = fileName ? [fileName] : [WORKSPACE_FILES.SOUL, WORKSPACE_FILES.IDENTITY];
|
|
110
|
+
const sections = [];
|
|
111
|
+
for (const name of namesToShow) {
|
|
112
|
+
const preview = await readPreview(join(profileDir, name), previewChars);
|
|
113
|
+
if (preview.missing) sections.push(`## ${name}\n_missing_`);
|
|
114
|
+
else sections.push(`## ${name}\n\`\`\`markdown\n${preview.content}\n\`\`\``);
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
content: [
|
|
118
|
+
"🛠️ Agent editor mode",
|
|
119
|
+
"",
|
|
120
|
+
buildEditInstructions(agentId, PROFILE_FILE_NAMES),
|
|
121
|
+
"",
|
|
122
|
+
`Profile directory: \`${profileDir}\``,
|
|
123
|
+
"",
|
|
124
|
+
...sections
|
|
125
|
+
].join("\n"),
|
|
126
|
+
success: true
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
function registerAgentEditCommand() {
|
|
131
|
+
commandRegistry.register(agentEditCommand);
|
|
132
|
+
}
|
|
133
|
+
//#endregion
|
|
134
|
+
export { registerAgentEditCommand };
|
|
135
|
+
|
|
136
|
+
//# sourceMappingURL=agent-edit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-edit.js","names":[],"sources":["../../../src/chat-commands/agent-edit.ts"],"sourcesContent":["/**\n * /agent-edit — open the current chat as an agent profile editing session.\n */\n\nimport { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport type { CommandContext, CommandDefinition } from './types.js';\nimport { commandRegistry } from './registry.js';\nimport { resolveAgentIdFromSessionKey } from '../routing/agent-session-key.js';\nimport { normalizeAgentId, resolveAgentProfileDir } from '../agent/agent-scope.js';\nimport { WORKSPACE_FILES } from '../config/paths.js';\n\nconst PROFILE_FILE_NAMES = [\n WORKSPACE_FILES.SOUL,\n WORKSPACE_FILES.IDENTITY,\n WORKSPACE_FILES.USER,\n WORKSPACE_FILES.TOOLS,\n WORKSPACE_FILES.AGENTS,\n WORKSPACE_FILES.HEARTBEAT,\n WORKSPACE_FILES.MEMORY,\n WORKSPACE_FILES.BOOTSTRAP,\n] as const;\n\nconst DEFAULT_PREVIEW_CHARS = 900;\nconst MAX_PREVIEW_CHARS = 4_000;\n\nfunction parseArgs(args: string): { fileName?: string; previewChars: number } {\n const trimmed = args.trim();\n if (!trimmed) {\n return { previewChars: DEFAULT_PREVIEW_CHARS };\n }\n\n const parts = trimmed.split(/\\s+/);\n let fileName: string | undefined;\n let previewChars = DEFAULT_PREVIEW_CHARS;\n\n for (const part of parts) {\n const limitMatch = /^--limit=(\\d+)$/.exec(part);\n if (limitMatch) {\n previewChars = Math.min(Number(limitMatch[1]), MAX_PREVIEW_CHARS);\n continue;\n }\n if (!fileName) {\n fileName = part;\n }\n }\n\n return { fileName, previewChars };\n}\n\nfunction normalizeProfileFileName(input: string | undefined): string | undefined {\n if (!input) {\n return undefined;\n }\n const basename = input.trim().replace(/\\\\/g, '/').split('/').pop();\n const matched = PROFILE_FILE_NAMES.find((name) => name.toLowerCase() === basename?.toLowerCase());\n return matched;\n}\n\nasync function readPreview(path: string, limit: number): Promise<{ content: string; missing: boolean }> {\n try {\n const content = await readFile(path, 'utf-8');\n const trimmed = content.trimEnd();\n if (trimmed.length <= limit) {\n return { content: trimmed, missing: false };\n }\n return {\n content: `${trimmed.slice(0, limit)}\\n\\n… truncated, ask me to read the full file before editing …`,\n missing: false,\n };\n } catch {\n return { content: '', missing: true };\n }\n}\n\nfunction buildEditInstructions(agentId: string, fileNames: readonly string[]): string {\n const files = fileNames.map((name) => `\\`${name}\\``).join(', ');\n return [\n `You are editing agent \\`${agentId}\\`.`,\n '',\n 'Tell me what to change, or say things like:',\n '- “Refine `SOUL.md` to sound warmer and more concise.”',\n '- “Update `IDENTITY.md` so this agent is focused on data analysis.”',\n '- “Read `SOUL.md` first, propose changes, then write them back.”',\n '',\n `Editable profile files: ${files}.`,\n 'I can read and update these by bare filename with `read_file`, `edit_file`, and `write_file`.',\n ].join('\\n');\n}\n\nconst agentEditCommand: CommandDefinition = {\n id: 'agent.edit',\n name: 'agent-edit',\n aliases: ['agentedit'],\n description: 'Show editable profile files for the current agent and prepare this chat for profile edits.',\n category: 'system',\n scope: ['global', 'private', 'group'],\n acceptsArgs: true,\n examples: ['/agent-edit', '/agent-edit SOUL.md', '/agent-edit IDENTITY.md --limit=2000'],\n handler: async (ctx: CommandContext, args: string) => {\n await ctx.setTyping(true);\n\n const { fileName: rawFileName, previewChars } = parseArgs(args);\n const fileName = normalizeProfileFileName(rawFileName);\n if (rawFileName && !fileName) {\n return {\n content: `⚠️ Unsupported profile file: \\`${rawFileName}\\`. Use one of: ${PROFILE_FILE_NAMES.map((name) => `\\`${name}\\``).join(', ')}.`,\n success: false,\n };\n }\n\n const agentId = normalizeAgentId(resolveAgentIdFromSessionKey(ctx.sessionKey));\n const profileDir = resolveAgentProfileDir(ctx.config, agentId);\n const namesToShow = fileName ? [fileName] : [WORKSPACE_FILES.SOUL, WORKSPACE_FILES.IDENTITY];\n\n const sections: string[] = [];\n for (const name of namesToShow) {\n const preview = await readPreview(join(profileDir, name), previewChars);\n if (preview.missing) {\n sections.push(`## ${name}\\n_missing_`);\n } else {\n sections.push(`## ${name}\\n\\`\\`\\`markdown\\n${preview.content}\\n\\`\\`\\``);\n }\n }\n\n return {\n content: [\n '🛠️ Agent editor mode',\n '',\n buildEditInstructions(agentId, PROFILE_FILE_NAMES),\n '',\n `Profile directory: \\`${profileDir}\\``,\n '',\n ...sections,\n ].join('\\n'),\n success: true,\n };\n },\n};\n\nexport function registerAgentEditCommand(): void {\n commandRegistry.register(agentEditCommand);\n}\n"],"mappings":"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"}
|
|
@@ -20,6 +20,7 @@ export { registerContextCommands } from './builtins/context.js';
|
|
|
20
20
|
export { registerGoalCommand } from './builtins/goal.js';
|
|
21
21
|
export { registerSubgoalCommand } from './builtins/subgoal.js';
|
|
22
22
|
export { registerWorkflowCommands } from './builtins/workflow.js';
|
|
23
|
+
export { registerAgentEditCommand } from './agent-edit.js';
|
|
23
24
|
/**
|
|
24
25
|
* Initialize the command system with all built-in commands
|
|
25
26
|
*/
|
|
@@ -11,6 +11,7 @@ import { registerContextCommands } from "./builtins/context.js";
|
|
|
11
11
|
import { registerGoalCommand } from "./builtins/goal.js";
|
|
12
12
|
import { registerSubgoalCommand } from "./builtins/subgoal.js";
|
|
13
13
|
import { registerWorkflowCommands } from "./builtins/workflow.js";
|
|
14
|
+
import { registerAgentEditCommand } from "./agent-edit.js";
|
|
14
15
|
import { CommandContextImpl, createCommandContext } from "./context.js";
|
|
15
16
|
//#region src/chat-commands/index.ts
|
|
16
17
|
/**
|
|
@@ -33,8 +34,9 @@ function initializeCommands() {
|
|
|
33
34
|
registerGoalCommand();
|
|
34
35
|
registerSubgoalCommand();
|
|
35
36
|
registerWorkflowCommands();
|
|
37
|
+
registerAgentEditCommand();
|
|
36
38
|
}
|
|
37
39
|
//#endregion
|
|
38
|
-
export { CommandContextImpl, CommandRegistry, commandRegistry, createCommandContext, generateSessionKey, getRoutingInfo, getSessionDisplayName, initializeCommands, isValidSessionKey, normalizeTelegramCommandName, parseSessionKey, parseSlashCommand, registerConfigCommand, registerContextCommands, registerGoalCommand, registerModelCommands, registerSessionCommands, registerSubgoalCommand, registerSystemCommands, registerTTSCommands, registerThinkingCommands, registerWorkflowCommands };
|
|
40
|
+
export { CommandContextImpl, CommandRegistry, commandRegistry, createCommandContext, generateSessionKey, getRoutingInfo, getSessionDisplayName, initializeCommands, isValidSessionKey, normalizeTelegramCommandName, parseSessionKey, parseSlashCommand, registerAgentEditCommand, registerConfigCommand, registerContextCommands, registerGoalCommand, registerModelCommands, registerSessionCommands, registerSubgoalCommand, registerSystemCommands, registerTTSCommands, registerThinkingCommands, registerWorkflowCommands };
|
|
39
41
|
|
|
40
42
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/chat-commands/index.ts"],"sourcesContent":["/**\n * Unified Command System\n *\n * Provides a platform-agnostic command system that works across\n * Telegram, Feishu, Web UI, CLI, and other channel surfaces.\n */\n\n// Built-in Commands (import first to avoid circular deps)\nimport { registerSessionCommands } from './builtins/session.js';\nimport { registerModelCommands } from './builtins/model.js';\nimport { registerSystemCommands } from './builtins/system.js';\nimport { registerTTSCommands } from './builtins/tts.js';\nimport { registerThinkingCommands } from './builtins/thinking.js';\nimport { registerConfigCommand } from './builtins/config.js';\nimport { registerContextCommands } from './builtins/context.js';\nimport { registerGoalCommand } from './builtins/goal.js';\nimport { registerSubgoalCommand } from './builtins/subgoal.js';\nimport { registerWorkflowCommands } from './builtins/workflow.js';\n\n// Types\nexport type {\n MessageSource,\n UnifiedMessage,\n PlatformMetadata,\n MessageAttachment,\n CommandDefinition,\n CommandCategory,\n CommandScope,\n CommandHandler,\n CommandResult,\n CommandContext,\n ReplyOptions,\n UIComponent,\n ButtonGroup,\n SelectMenu,\n ModelPicker,\n UsageDisplay,\n SessionList,\n TextInput,\n ProviderInfo,\n ModelInfo,\n UsageStats,\n SessionInfo,\n PlatformFeature,\n ChannelAdapter,\n ReplyPayload,\n} from './types.js';\n\n// Session Key\nexport {\n generateSessionKey,\n parseSessionKey,\n isValidSessionKey,\n getSessionDisplayName,\n getRoutingInfo,\n type SessionKeyContext,\n} from './session-key.js';\n\n// Command parsing helpers\nexport { normalizeTelegramCommandName, parseSlashCommand } from './command-parse.js';\n\n// Registry\nexport { CommandRegistry, commandRegistry } from './registry.js';\nexport type { CommandRegistry as CommandRegistryType } from './types.js';\n\n// Context\nexport { CommandContextImpl, createCommandContext } from './context.js';\n\n// Built-in Commands\nexport { registerSessionCommands } from './builtins/session.js';\nexport { registerModelCommands } from './builtins/model.js';\nexport { registerSystemCommands } from './builtins/system.js';\nexport { registerTTSCommands } from './builtins/tts.js';\nexport { registerThinkingCommands } from './builtins/thinking.js';\nexport { registerConfigCommand } from './builtins/config.js';\nexport { registerContextCommands } from './builtins/context.js';\nexport { registerGoalCommand } from './builtins/goal.js';\nexport { registerSubgoalCommand } from './builtins/subgoal.js';\nexport { registerWorkflowCommands } from './builtins/workflow.js';\n\n/**\n * Initialize the command system with all built-in commands\n */\nexport function initializeCommands(): void {\n registerSessionCommands();\n registerModelCommands();\n registerSystemCommands();\n registerConfigCommand();\n registerContextCommands();\n registerTTSCommands();\n registerThinkingCommands();\n registerGoalCommand();\n registerSubgoalCommand();\n registerWorkflowCommands();\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/chat-commands/index.ts"],"sourcesContent":["/**\n * Unified Command System\n *\n * Provides a platform-agnostic command system that works across\n * Telegram, Feishu, Web UI, CLI, and other channel surfaces.\n */\n\n// Built-in Commands (import first to avoid circular deps)\nimport { registerSessionCommands } from './builtins/session.js';\nimport { registerModelCommands } from './builtins/model.js';\nimport { registerSystemCommands } from './builtins/system.js';\nimport { registerTTSCommands } from './builtins/tts.js';\nimport { registerThinkingCommands } from './builtins/thinking.js';\nimport { registerConfigCommand } from './builtins/config.js';\nimport { registerContextCommands } from './builtins/context.js';\nimport { registerGoalCommand } from './builtins/goal.js';\nimport { registerSubgoalCommand } from './builtins/subgoal.js';\nimport { registerWorkflowCommands } from './builtins/workflow.js';\nimport { registerAgentEditCommand } from './agent-edit.js';\n\n// Types\nexport type {\n MessageSource,\n UnifiedMessage,\n PlatformMetadata,\n MessageAttachment,\n CommandDefinition,\n CommandCategory,\n CommandScope,\n CommandHandler,\n CommandResult,\n CommandContext,\n ReplyOptions,\n UIComponent,\n ButtonGroup,\n SelectMenu,\n ModelPicker,\n UsageDisplay,\n SessionList,\n TextInput,\n ProviderInfo,\n ModelInfo,\n UsageStats,\n SessionInfo,\n PlatformFeature,\n ChannelAdapter,\n ReplyPayload,\n} from './types.js';\n\n// Session Key\nexport {\n generateSessionKey,\n parseSessionKey,\n isValidSessionKey,\n getSessionDisplayName,\n getRoutingInfo,\n type SessionKeyContext,\n} from './session-key.js';\n\n// Command parsing helpers\nexport { normalizeTelegramCommandName, parseSlashCommand } from './command-parse.js';\n\n// Registry\nexport { CommandRegistry, commandRegistry } from './registry.js';\nexport type { CommandRegistry as CommandRegistryType } from './types.js';\n\n// Context\nexport { CommandContextImpl, createCommandContext } from './context.js';\n\n// Built-in Commands\nexport { registerSessionCommands } from './builtins/session.js';\nexport { registerModelCommands } from './builtins/model.js';\nexport { registerSystemCommands } from './builtins/system.js';\nexport { registerTTSCommands } from './builtins/tts.js';\nexport { registerThinkingCommands } from './builtins/thinking.js';\nexport { registerConfigCommand } from './builtins/config.js';\nexport { registerContextCommands } from './builtins/context.js';\nexport { registerGoalCommand } from './builtins/goal.js';\nexport { registerSubgoalCommand } from './builtins/subgoal.js';\nexport { registerWorkflowCommands } from './builtins/workflow.js';\nexport { registerAgentEditCommand } from './agent-edit.js';\n\n/**\n * Initialize the command system with all built-in commands\n */\nexport function initializeCommands(): void {\n registerSessionCommands();\n registerModelCommands();\n registerSystemCommands();\n registerConfigCommand();\n registerContextCommands();\n registerTTSCommands();\n registerThinkingCommands();\n registerGoalCommand();\n registerSubgoalCommand();\n registerWorkflowCommands();\n registerAgentEditCommand();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAqFA,SAAgB,qBAA2B;AACzC,0BAAyB;AACzB,wBAAuB;AACvB,yBAAwB;AACxB,wBAAuB;AACvB,0BAAyB;AACzB,sBAAqB;AACrB,2BAA0B;AAC1B,sBAAqB;AACrB,yBAAwB;AACxB,2BAA0B;AAC1B,2BAA0B"}
|
package/dist/src/cli/bin.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { version } from "../../package.js";
|
|
3
3
|
import "./cli-log-level-preset.js";
|
|
4
|
+
import { ensureXopcCliOnPath } from "../infra/path-env.js";
|
|
4
5
|
import { formatRootHelp } from "./command-manifest.js";
|
|
5
6
|
//#region src/cli/bin.ts
|
|
7
|
+
ensureXopcCliOnPath();
|
|
6
8
|
function printRootHelp() {
|
|
7
9
|
console.log(formatRootHelp());
|
|
8
10
|
}
|
package/dist/src/cli/bin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bin.js","names":["pkg.version"],"sources":["../../../src/cli/bin.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * CLI entry: log-level preset must run before any module that initializes the logger.\n * (Bundlers may reorder imports in `index.ts`; this file stays dependency-minimal.)\n */\nimport './cli-log-level-preset.js';\n\nimport pkg from '../../package.json' with { type: 'json' };\nimport { formatRootHelp } from './command-manifest.js';\n\nfunction printRootHelp(): void {\n console.log(formatRootHelp());\n}\n\nconst rootArgs = process.argv.slice(2).filter((arg) => arg !== '--');\nif (rootArgs.length === 1 && (rootArgs[0] === '--version' || rootArgs[0] === '-V')) {\n console.log(pkg.version);\n process.exit(0);\n}\nif (rootArgs.length === 1 && (rootArgs[0] === '--help' || rootArgs[0] === '-h' || rootArgs[0] === 'help')) {\n printRootHelp();\n process.exit(0);\n}\n\nconst filteredArgv = process.argv.filter((arg, index) => {\n if (arg !== '--') return true;\n return index < 2;\n});\n\nconst { tryRunGatewayRunFastPath } = await import('./gateway-run-fast-path.js');\nif (await tryRunGatewayRunFastPath(filteredArgv)) {\n process.exit(typeof process.exitCode === 'number' ? process.exitCode : 0);\n}\n\nconst { runCli } = await import('./index.js');\nawait runCli(process.argv);\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"bin.js","names":["pkg.version"],"sources":["../../../src/cli/bin.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * CLI entry: log-level preset must run before any module that initializes the logger.\n * (Bundlers may reorder imports in `index.ts`; this file stays dependency-minimal.)\n */\nimport './cli-log-level-preset.js';\n\nimport pkg from '../../package.json' with { type: 'json' };\nimport { ensureXopcCliOnPath } from '../infra/path-env.js';\nimport { formatRootHelp } from './command-manifest.js';\n\nensureXopcCliOnPath();\n\nfunction printRootHelp(): void {\n console.log(formatRootHelp());\n}\n\nconst rootArgs = process.argv.slice(2).filter((arg) => arg !== '--');\nif (rootArgs.length === 1 && (rootArgs[0] === '--version' || rootArgs[0] === '-V')) {\n console.log(pkg.version);\n process.exit(0);\n}\nif (rootArgs.length === 1 && (rootArgs[0] === '--help' || rootArgs[0] === '-h' || rootArgs[0] === 'help')) {\n printRootHelp();\n process.exit(0);\n}\n\nconst filteredArgv = process.argv.filter((arg, index) => {\n if (arg !== '--') return true;\n return index < 2;\n});\n\nconst { tryRunGatewayRunFastPath } = await import('./gateway-run-fast-path.js');\nif (await tryRunGatewayRunFastPath(filteredArgv)) {\n process.exit(typeof process.exitCode === 'number' ? process.exitCode : 0);\n}\n\nconst { runCli } = await import('./index.js');\nawait runCli(process.argv);\n"],"mappings":";;;;;;AAWA,qBAAqB;AAErB,SAAS,gBAAsB;AAC7B,SAAQ,IAAI,gBAAgB,CAAC;;AAG/B,MAAM,WAAW,QAAQ,KAAK,MAAM,EAAE,CAAC,QAAQ,QAAQ,QAAQ,KAAK;AACpE,IAAI,SAAS,WAAW,MAAM,SAAS,OAAO,eAAe,SAAS,OAAO,OAAO;AAClF,SAAQ,IAAIA,QAAY;AACxB,SAAQ,KAAK,EAAE;;AAEjB,IAAI,SAAS,WAAW,MAAM,SAAS,OAAO,YAAY,SAAS,OAAO,QAAQ,SAAS,OAAO,SAAS;AACzG,gBAAe;AACf,SAAQ,KAAK,EAAE;;AAGjB,MAAM,eAAe,QAAQ,KAAK,QAAQ,KAAK,UAAU;AACvD,KAAI,QAAQ,KAAM,QAAO;AACzB,QAAO,QAAQ;EACf;AAEF,MAAM,EAAE,6BAA6B,MAAM,OAAO;AAClD,IAAI,MAAM,yBAAyB,aAAa,CAC9C,SAAQ,KAAK,OAAO,QAAQ,aAAa,WAAW,QAAQ,WAAW,EAAE;AAG3E,MAAM,EAAE,WAAW,MAAM,OAAO;AAChC,MAAM,OAAO,QAAQ,KAAK"}
|
|
@@ -6,6 +6,7 @@ function createCronCommand(_ctx) {
|
|
|
6
6
|
const cmd = new Command("cron").description("Manage scheduled tasks").addHelpText("after", formatExamples([
|
|
7
7
|
"xopc cron list # List all tasks",
|
|
8
8
|
"xopc cron add --schedule \"0 9 * * *\" --message \"Good morning\"",
|
|
9
|
+
"xopc cron add --schedule \"0 17 * * 5\" --workflow weekly_review --goal \"Weekly review\"",
|
|
9
10
|
"xopc cron enable <job-id> # Enable a task",
|
|
10
11
|
"xopc cron disable <job-id> # Disable a task",
|
|
11
12
|
"xopc cron run <job-id> # Run a task now",
|
|
@@ -29,12 +30,49 @@ function createCronCommand(_ctx) {
|
|
|
29
30
|
}
|
|
30
31
|
});
|
|
31
32
|
}));
|
|
32
|
-
cmd.addCommand(new Command("add").description("Add a scheduled task").option("--name <text>", "Task name").option("--schedule <cron>", "Cron expression (e.g., \"0 9 * * *\")").option("--message <text>", "Message to send").action(async (options) => {
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
cmd.addCommand(new Command("add").description("Add a scheduled task").option("--name <text>", "Task name").option("--schedule <cron>", "Cron expression (e.g., \"0 9 * * *\")").option("--message <text>", "Message to send (system event)").option("--workflow <id>", "Workflow definition id (direct workflow run)").option("--goal <text>", "Optional workflow goal").option("--input-json <json>", "Workflow input payload as JSON object").option("--agent-id <id>", "Agent profile for workflow or isolated jobs").option("--no-wait", "Start workflow and return without waiting for completion").option("--channel <name>", "Delivery channel (e.g. telegram)").option("--to <chatId>", "Delivery recipient chat id").action(async (options) => {
|
|
34
|
+
const hasWorkflow = Boolean(options.workflow?.trim());
|
|
35
|
+
const hasMessage = Boolean(options.message?.trim());
|
|
36
|
+
if (!options.schedule || !hasWorkflow && !hasMessage || hasWorkflow && hasMessage) {
|
|
37
|
+
console.error("Error: --schedule is required; provide exactly one of --message or --workflow");
|
|
35
38
|
process.exit(1);
|
|
36
39
|
}
|
|
37
40
|
await withCronService(async (cronService) => {
|
|
41
|
+
if (hasWorkflow) {
|
|
42
|
+
const { DEFAULT_WORKFLOW_CRON_WAIT_MS } = await import("../../cron/workflow-run-completion.js");
|
|
43
|
+
let inputEnvelope;
|
|
44
|
+
if (options.inputJson) try {
|
|
45
|
+
inputEnvelope = { payload: JSON.parse(options.inputJson) };
|
|
46
|
+
} catch {
|
|
47
|
+
console.error("Error: --input-json must be valid JSON");
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
const agentId = options.agentId?.trim() || void 0;
|
|
51
|
+
const delivery = options.channel?.trim() && options.to?.trim() ? {
|
|
52
|
+
mode: "direct",
|
|
53
|
+
channel: options.channel.trim(),
|
|
54
|
+
to: options.to.trim()
|
|
55
|
+
} : void 0;
|
|
56
|
+
const result = await cronService.addJob(options.schedule, {
|
|
57
|
+
name: options.name,
|
|
58
|
+
sessionTarget: "isolated",
|
|
59
|
+
timeout: DEFAULT_WORKFLOW_CRON_WAIT_MS,
|
|
60
|
+
...agentId ? { agentId } : {},
|
|
61
|
+
delivery,
|
|
62
|
+
payload: {
|
|
63
|
+
kind: "workflowRun",
|
|
64
|
+
definitionId: options.workflow.trim(),
|
|
65
|
+
...options.goal?.trim() ? { goal: options.goal.trim() } : {},
|
|
66
|
+
...inputEnvelope ? { inputEnvelope } : {},
|
|
67
|
+
...agentId ? { agentId } : {},
|
|
68
|
+
...options.noWait ? { waitForCompletion: false } : {}
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
console.log(`✅ Added workflow job ${result.id}`);
|
|
72
|
+
console.log(` Schedule: ${result.schedule}`);
|
|
73
|
+
console.log(` Workflow: ${options.workflow.trim()}`);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
38
76
|
const result = await cronService.addJob(options.schedule, {
|
|
39
77
|
name: options.name,
|
|
40
78
|
payload: {
|
|
@@ -99,6 +137,7 @@ register({
|
|
|
99
137
|
examples: [
|
|
100
138
|
"xopc cron list",
|
|
101
139
|
"xopc cron add --schedule \"0 9 * * *\" --message \"Hello\"",
|
|
140
|
+
"xopc cron add --schedule \"0 17 * * 5\" --workflow weekly_review",
|
|
102
141
|
"xopc cron enable abc12345",
|
|
103
142
|
"xopc cron run abc12345"
|
|
104
143
|
]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cron.js","names":[],"sources":["../../../../src/cli/commands/cron.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { register, formatExamples } from '../registry.js';\nimport type { CLIContext } from '../registry.js';\nimport { withCronService } from './cron-cli.js';\n\nfunction createCronCommand(_ctx: CLIContext): Command {\n const cmd = new Command('cron')\n .description('Manage scheduled tasks')\n .addHelpText(\n 'after',\n formatExamples([\n 'xopc cron list # List all tasks',\n 'xopc cron add --schedule \"0 9 * * *\" --message \"Good morning\"',\n 'xopc cron enable <job-id> # Enable a task',\n 'xopc cron disable <job-id> # Disable a task',\n 'xopc cron run <job-id> # Run a task now',\n 'xopc cron remove <job-id> # Remove a task',\n ]),\n );\n\n cmd.addCommand(\n new Command('list')\n .description('List all scheduled tasks')\n .action(async () => {\n await withCronService(async (cronService) => {\n const jobs = await cronService.listJobs();\n\n if (jobs.length === 0) {\n console.log('No scheduled tasks.');\n return;\n }\n\n console.log('Scheduled Tasks:\\n');\n const { getCronPayloadText } = await import('../../cron/job-content.js');\n for (const job of jobs) {\n const state = job.enabled ? 'enabled ' : 'disabled';\n console.log(` ${job.id} [${state}] - ${job.schedule}`);\n console.log(` ${getCronPayloadText({ payload: job.payload })}`);\n console.log(` Next: ${job.next_run || 'N/A'}`);\n console.log();\n }\n });\n }),\n );\n\n cmd.addCommand(\n new Command('add')\n .description('Add a scheduled task')\n .option('--name <text>', 'Task name')\n .option('--schedule <cron>', 'Cron expression (e.g., \"0 9 * * *\")')\n .option('--message <text>', 'Message to send')\n .action(async (options) => {\n if (!options.schedule || !options.message) {\n console.error('Error: --schedule and --message are required');\n process.exit(1);\n }\n\n await withCronService(async (cronService) => {\n const result = await cronService.addJob(options.schedule, {\n name: options.name,\n payload: { kind: 'systemEvent', text: options.message },\n });\n\n console.log(`✅ Added job ${result.id}`);\n console.log(` Schedule: ${result.schedule}`);\n });\n }),\n );\n\n cmd.addCommand(\n new Command('remove')\n .description('Remove a scheduled task')\n .argument('<id>', 'Job ID')\n .action(async (id) => {\n await withCronService(async (cronService) => {\n const success = await cronService.removeJob(id);\n if (success) {\n console.log(`✅ Removed job ${id}`);\n } else {\n console.error(`Job ${id} not found`);\n process.exit(1);\n }\n });\n }),\n );\n\n cmd.addCommand(\n new Command('enable')\n .description('Enable a scheduled task')\n .argument('<id>', 'Job ID')\n .action(async (id) => {\n await withCronService(async (cronService) => {\n const success = await cronService.toggleJob(id, true);\n if (success) {\n console.log(`✅ Enabled job ${id}`);\n } else {\n console.error(`Job ${id} not found`);\n process.exit(1);\n }\n });\n }),\n );\n\n cmd.addCommand(\n new Command('disable')\n .description('Disable a scheduled task')\n .argument('<id>', 'Job ID')\n .action(async (id) => {\n await withCronService(async (cronService) => {\n const success = await cronService.toggleJob(id, false);\n if (success) {\n console.log(`✅ Disabled job ${id}`);\n } else {\n console.error(`Job ${id} not found`);\n process.exit(1);\n }\n });\n }),\n );\n\n const runNowAction = async (id: string) => {\n await withCronService(async (cronService) => {\n try {\n await cronService.runJobNow(id);\n console.log(`✅ Triggered job ${id}`);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(message);\n process.exit(1);\n }\n });\n };\n\n cmd.addCommand(\n new Command('run')\n .description('Run a scheduled task immediately')\n .argument('<id>', 'Job ID')\n .action(runNowAction),\n );\n\n cmd.addCommand(\n new Command('trigger')\n .description('Alias for `cron run`')\n .argument('<id>', 'Job ID')\n .action(runNowAction),\n );\n\n return cmd;\n}\n\nregister({\n id: 'cron',\n name: 'cron',\n description: 'Manage scheduled tasks',\n factory: createCronCommand,\n metadata: {\n category: 'utility',\n examples: [\n 'xopc cron list',\n 'xopc cron add --schedule \"0 9 * * *\" --message \"Hello\"',\n 'xopc cron enable abc12345',\n 'xopc cron run abc12345',\n ],\n },\n});\n\nexport { createCronCommand };\n"],"mappings":";;;;AAKA,SAAS,kBAAkB,MAA2B;CACpD,MAAM,MAAM,IAAI,QAAQ,OAAO,CAC5B,YAAY,yBAAyB,CACrC,YACC,SACA,eAAe;EACb;EACA;EACA;EACA;EACA;EACA;EACD,CAAC,CACH;AAEH,KAAI,WACF,IAAI,QAAQ,OAAO,CAChB,YAAY,2BAA2B,CACvC,OAAO,YAAY;AAClB,QAAM,gBAAgB,OAAO,gBAAgB;GAC3C,MAAM,OAAO,MAAM,YAAY,UAAU;AAEzC,OAAI,KAAK,WAAW,GAAG;AACrB,YAAQ,IAAI,sBAAsB;AAClC;;AAGF,WAAQ,IAAI,qBAAqB;GACjC,MAAM,EAAE,uBAAuB,MAAM,OAAO;AAC5C,QAAK,MAAM,OAAO,MAAM;IACtB,MAAM,QAAQ,IAAI,UAAU,aAAa;AACzC,YAAQ,IAAI,KAAK,IAAI,GAAG,IAAI,MAAM,MAAM,IAAI,WAAW;AACvD,YAAQ,IAAI,QAAQ,mBAAmB,EAAE,SAAS,IAAI,SAAS,CAAC,GAAG;AACnE,YAAQ,IAAI,cAAc,IAAI,YAAY,QAAQ;AAClD,YAAQ,KAAK;;IAEf;GACF,CACL;AAED,KAAI,WACF,IAAI,QAAQ,MAAM,CACf,YAAY,uBAAuB,CACnC,OAAO,iBAAiB,YAAY,CACpC,OAAO,qBAAqB,wCAAsC,CAClE,OAAO,oBAAoB,kBAAkB,CAC7C,OAAO,OAAO,YAAY;AACzB,MAAI,CAAC,QAAQ,YAAY,CAAC,QAAQ,SAAS;AACzC,WAAQ,MAAM,+CAA+C;AAC7D,WAAQ,KAAK,EAAE;;AAGjB,QAAM,gBAAgB,OAAO,gBAAgB;GAC3C,MAAM,SAAS,MAAM,YAAY,OAAO,QAAQ,UAAU;IACxD,MAAM,QAAQ;IACd,SAAS;KAAE,MAAM;KAAe,MAAM,QAAQ;KAAS;IACxD,CAAC;AAEF,WAAQ,IAAI,eAAe,OAAO,KAAK;AACvC,WAAQ,IAAI,gBAAgB,OAAO,WAAW;IAC9C;GACF,CACL;AAED,KAAI,WACF,IAAI,QAAQ,SAAS,CAClB,YAAY,0BAA0B,CACtC,SAAS,QAAQ,SAAS,CAC1B,OAAO,OAAO,OAAO;AACpB,QAAM,gBAAgB,OAAO,gBAAgB;AAE3C,OAAI,MADkB,YAAY,UAAU,GAAG,CAE7C,SAAQ,IAAI,iBAAiB,KAAK;QAC7B;AACL,YAAQ,MAAM,OAAO,GAAG,YAAY;AACpC,YAAQ,KAAK,EAAE;;IAEjB;GACF,CACL;AAED,KAAI,WACF,IAAI,QAAQ,SAAS,CAClB,YAAY,0BAA0B,CACtC,SAAS,QAAQ,SAAS,CAC1B,OAAO,OAAO,OAAO;AACpB,QAAM,gBAAgB,OAAO,gBAAgB;AAE3C,OAAI,MADkB,YAAY,UAAU,IAAI,KAAK,CAEnD,SAAQ,IAAI,iBAAiB,KAAK;QAC7B;AACL,YAAQ,MAAM,OAAO,GAAG,YAAY;AACpC,YAAQ,KAAK,EAAE;;IAEjB;GACF,CACL;AAED,KAAI,WACF,IAAI,QAAQ,UAAU,CACnB,YAAY,2BAA2B,CACvC,SAAS,QAAQ,SAAS,CAC1B,OAAO,OAAO,OAAO;AACpB,QAAM,gBAAgB,OAAO,gBAAgB;AAE3C,OAAI,MADkB,YAAY,UAAU,IAAI,MAAM,CAEpD,SAAQ,IAAI,kBAAkB,KAAK;QAC9B;AACL,YAAQ,MAAM,OAAO,GAAG,YAAY;AACpC,YAAQ,KAAK,EAAE;;IAEjB;GACF,CACL;CAED,MAAM,eAAe,OAAO,OAAe;AACzC,QAAM,gBAAgB,OAAO,gBAAgB;AAC3C,OAAI;AACF,UAAM,YAAY,UAAU,GAAG;AAC/B,YAAQ,IAAI,mBAAmB,KAAK;YAC7B,KAAK;IACZ,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AAChE,YAAQ,MAAM,QAAQ;AACtB,YAAQ,KAAK,EAAE;;IAEjB;;AAGJ,KAAI,WACF,IAAI,QAAQ,MAAM,CACf,YAAY,mCAAmC,CAC/C,SAAS,QAAQ,SAAS,CAC1B,OAAO,aAAa,CACxB;AAED,KAAI,WACF,IAAI,QAAQ,UAAU,CACnB,YAAY,uBAAuB,CACnC,SAAS,QAAQ,SAAS,CAC1B,OAAO,aAAa,CACxB;AAED,QAAO;;AAGT,SAAS;CACP,IAAI;CACJ,MAAM;CACN,aAAa;CACb,SAAS;CACT,UAAU;EACR,UAAU;EACV,UAAU;GACR;GACA;GACA;GACA;GACD;EACF;CACF,CAAC"}
|
|
1
|
+
{"version":3,"file":"cron.js","names":[],"sources":["../../../../src/cli/commands/cron.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { register, formatExamples } from '../registry.js';\nimport type { CLIContext } from '../registry.js';\nimport { withCronService } from './cron-cli.js';\n\nfunction createCronCommand(_ctx: CLIContext): Command {\n const cmd = new Command('cron')\n .description('Manage scheduled tasks')\n .addHelpText(\n 'after',\n formatExamples([\n 'xopc cron list # List all tasks',\n 'xopc cron add --schedule \"0 9 * * *\" --message \"Good morning\"',\n 'xopc cron add --schedule \"0 17 * * 5\" --workflow weekly_review --goal \"Weekly review\"',\n 'xopc cron enable <job-id> # Enable a task',\n 'xopc cron disable <job-id> # Disable a task',\n 'xopc cron run <job-id> # Run a task now',\n 'xopc cron remove <job-id> # Remove a task',\n ]),\n );\n\n cmd.addCommand(\n new Command('list')\n .description('List all scheduled tasks')\n .action(async () => {\n await withCronService(async (cronService) => {\n const jobs = await cronService.listJobs();\n\n if (jobs.length === 0) {\n console.log('No scheduled tasks.');\n return;\n }\n\n console.log('Scheduled Tasks:\\n');\n const { getCronPayloadText } = await import('../../cron/job-content.js');\n for (const job of jobs) {\n const state = job.enabled ? 'enabled ' : 'disabled';\n console.log(` ${job.id} [${state}] - ${job.schedule}`);\n console.log(` ${getCronPayloadText({ payload: job.payload })}`);\n console.log(` Next: ${job.next_run || 'N/A'}`);\n console.log();\n }\n });\n }),\n );\n\n cmd.addCommand(\n new Command('add')\n .description('Add a scheduled task')\n .option('--name <text>', 'Task name')\n .option('--schedule <cron>', 'Cron expression (e.g., \"0 9 * * *\")')\n .option('--message <text>', 'Message to send (system event)')\n .option('--workflow <id>', 'Workflow definition id (direct workflow run)')\n .option('--goal <text>', 'Optional workflow goal')\n .option('--input-json <json>', 'Workflow input payload as JSON object')\n .option('--agent-id <id>', 'Agent profile for workflow or isolated jobs')\n .option('--no-wait', 'Start workflow and return without waiting for completion')\n .option('--channel <name>', 'Delivery channel (e.g. telegram)')\n .option('--to <chatId>', 'Delivery recipient chat id')\n .action(async (options) => {\n const hasWorkflow = Boolean(options.workflow?.trim());\n const hasMessage = Boolean(options.message?.trim());\n if (!options.schedule || (!hasWorkflow && !hasMessage) || (hasWorkflow && hasMessage)) {\n console.error(\n 'Error: --schedule is required; provide exactly one of --message or --workflow',\n );\n process.exit(1);\n }\n\n await withCronService(async (cronService) => {\n if (hasWorkflow) {\n const { DEFAULT_WORKFLOW_CRON_WAIT_MS } = await import(\n '../../cron/workflow-run-completion.js'\n );\n let inputEnvelope: { payload: unknown } | undefined;\n if (options.inputJson) {\n try {\n inputEnvelope = { payload: JSON.parse(options.inputJson) as unknown };\n } catch {\n console.error('Error: --input-json must be valid JSON');\n process.exit(1);\n }\n }\n const agentId = options.agentId?.trim() || undefined;\n const delivery =\n options.channel?.trim() && options.to?.trim()\n ? {\n mode: 'direct' as const,\n channel: options.channel.trim(),\n to: options.to.trim(),\n }\n : undefined;\n const result = await cronService.addJob(options.schedule, {\n name: options.name,\n sessionTarget: 'isolated',\n timeout: DEFAULT_WORKFLOW_CRON_WAIT_MS,\n ...(agentId ? { agentId } : {}),\n delivery,\n payload: {\n kind: 'workflowRun',\n definitionId: options.workflow.trim(),\n ...(options.goal?.trim() ? { goal: options.goal.trim() } : {}),\n ...(inputEnvelope ? { inputEnvelope } : {}),\n ...(agentId ? { agentId } : {}),\n ...(options.noWait ? { waitForCompletion: false } : {}),\n },\n });\n console.log(`✅ Added workflow job ${result.id}`);\n console.log(` Schedule: ${result.schedule}`);\n console.log(` Workflow: ${options.workflow.trim()}`);\n return;\n }\n\n const result = await cronService.addJob(options.schedule, {\n name: options.name,\n payload: { kind: 'systemEvent', text: options.message },\n });\n\n console.log(`✅ Added job ${result.id}`);\n console.log(` Schedule: ${result.schedule}`);\n });\n }),\n );\n\n cmd.addCommand(\n new Command('remove')\n .description('Remove a scheduled task')\n .argument('<id>', 'Job ID')\n .action(async (id) => {\n await withCronService(async (cronService) => {\n const success = await cronService.removeJob(id);\n if (success) {\n console.log(`✅ Removed job ${id}`);\n } else {\n console.error(`Job ${id} not found`);\n process.exit(1);\n }\n });\n }),\n );\n\n cmd.addCommand(\n new Command('enable')\n .description('Enable a scheduled task')\n .argument('<id>', 'Job ID')\n .action(async (id) => {\n await withCronService(async (cronService) => {\n const success = await cronService.toggleJob(id, true);\n if (success) {\n console.log(`✅ Enabled job ${id}`);\n } else {\n console.error(`Job ${id} not found`);\n process.exit(1);\n }\n });\n }),\n );\n\n cmd.addCommand(\n new Command('disable')\n .description('Disable a scheduled task')\n .argument('<id>', 'Job ID')\n .action(async (id) => {\n await withCronService(async (cronService) => {\n const success = await cronService.toggleJob(id, false);\n if (success) {\n console.log(`✅ Disabled job ${id}`);\n } else {\n console.error(`Job ${id} not found`);\n process.exit(1);\n }\n });\n }),\n );\n\n const runNowAction = async (id: string) => {\n await withCronService(async (cronService) => {\n try {\n await cronService.runJobNow(id);\n console.log(`✅ Triggered job ${id}`);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(message);\n process.exit(1);\n }\n });\n };\n\n cmd.addCommand(\n new Command('run')\n .description('Run a scheduled task immediately')\n .argument('<id>', 'Job ID')\n .action(runNowAction),\n );\n\n cmd.addCommand(\n new Command('trigger')\n .description('Alias for `cron run`')\n .argument('<id>', 'Job ID')\n .action(runNowAction),\n );\n\n return cmd;\n}\n\nregister({\n id: 'cron',\n name: 'cron',\n description: 'Manage scheduled tasks',\n factory: createCronCommand,\n metadata: {\n category: 'utility',\n examples: [\n 'xopc cron list',\n 'xopc cron add --schedule \"0 9 * * *\" --message \"Hello\"',\n 'xopc cron add --schedule \"0 17 * * 5\" --workflow weekly_review',\n 'xopc cron enable abc12345',\n 'xopc cron run abc12345',\n ],\n },\n});\n\nexport { createCronCommand };\n"],"mappings":"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"}
|
|
@@ -1,14 +1,42 @@
|
|
|
1
|
-
import { init_agent_scope, resolveDefaultAgentId } from "../../../../agent/agent-scope.js";
|
|
1
|
+
import { init_agent_scope, listAgentEntries, resolveDefaultAgentId } from "../../../../agent/agent-scope.js";
|
|
2
|
+
import { init_session_key, parseSessionKey } from "../../../../routing/session-key.js";
|
|
2
3
|
import { init_transcript_paths, resolveSessionFilePath } from "../../../../session/parity/transcript-paths.js";
|
|
3
4
|
import { FILENAMES, init_paths, resolveSessionsDir } from "../../../../config/paths.js";
|
|
4
5
|
import { init_loader, loadConfig } from "../../../../config/loader.js";
|
|
5
|
-
import { join } from "node:path";
|
|
6
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
6
|
+
import { basename, join } from "node:path";
|
|
7
|
+
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
7
8
|
//#region src/cli/commands/doctor/checks/session-integrity.ts
|
|
8
9
|
init_agent_scope();
|
|
9
10
|
init_loader();
|
|
10
11
|
init_paths();
|
|
12
|
+
init_session_key();
|
|
11
13
|
init_transcript_paths();
|
|
14
|
+
function discoverSessionMapLocations(config, stateDir) {
|
|
15
|
+
const agentIds = new Set([resolveDefaultAgentId(config), ...listAgentEntries(config).map((agent) => agent.id)]);
|
|
16
|
+
const agentsRoot = join(stateDir, "agents");
|
|
17
|
+
if (existsSync(agentsRoot)) {
|
|
18
|
+
for (const entry of readdirSync(agentsRoot, { withFileTypes: true })) if (entry.isDirectory()) agentIds.add(entry.name);
|
|
19
|
+
}
|
|
20
|
+
const seenMapPaths = /* @__PURE__ */ new Set();
|
|
21
|
+
const locations = [];
|
|
22
|
+
for (const agentId of agentIds) {
|
|
23
|
+
const sessionsDir = resolveSessionsDir(config, agentId);
|
|
24
|
+
const mapPath = join(sessionsDir, FILENAMES.SESSIONS_MAP);
|
|
25
|
+
if (seenMapPaths.has(mapPath)) continue;
|
|
26
|
+
seenMapPaths.add(mapPath);
|
|
27
|
+
locations.push({
|
|
28
|
+
agentId,
|
|
29
|
+
sessionsDir,
|
|
30
|
+
mapPath
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
return locations;
|
|
34
|
+
}
|
|
35
|
+
function readSessionMap(mapPath) {
|
|
36
|
+
const parsed = JSON.parse(readFileSync(mapPath, "utf-8"));
|
|
37
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("invalid sessions map");
|
|
38
|
+
return parsed;
|
|
39
|
+
}
|
|
12
40
|
async function checkSessionIntegrity(ctx) {
|
|
13
41
|
if (!ctx.options.deep) return {
|
|
14
42
|
id: "session-integrity",
|
|
@@ -36,73 +64,68 @@ async function checkSessionIntegrity(ctx) {
|
|
|
36
64
|
hints: []
|
|
37
65
|
};
|
|
38
66
|
}
|
|
39
|
-
const
|
|
40
|
-
const
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
id: "session-integrity",
|
|
51
|
-
label: "Sessions",
|
|
52
|
-
status: "warn",
|
|
53
|
-
message: "`sessions.json` is missing.",
|
|
54
|
-
hints: [mapPath]
|
|
55
|
-
};
|
|
56
|
-
let map;
|
|
57
|
-
try {
|
|
58
|
-
const parsed = JSON.parse(readFileSync(mapPath, "utf-8"));
|
|
59
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("invalid");
|
|
60
|
-
map = parsed;
|
|
61
|
-
} catch {
|
|
62
|
-
return {
|
|
63
|
-
id: "session-integrity",
|
|
64
|
-
label: "Sessions",
|
|
65
|
-
status: "warn",
|
|
66
|
-
message: "`sessions.json` is not valid JSON.",
|
|
67
|
-
hints: [mapPath]
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
const sample = [...Object.keys(map)].sort((a, b) => {
|
|
71
|
-
const ta = map[a]?.updatedAt ?? 0;
|
|
72
|
-
return (map[b]?.updatedAt ?? 0) - ta;
|
|
73
|
-
}).slice(0, 20);
|
|
74
|
-
if (sample.length === 0) return {
|
|
75
|
-
id: "session-integrity",
|
|
76
|
-
label: "Sessions",
|
|
77
|
-
status: "pass",
|
|
78
|
-
message: "`sessions.json` is valid; no sessions to sample.",
|
|
79
|
-
hints: []
|
|
80
|
-
};
|
|
81
|
-
const missing = [];
|
|
82
|
-
for (const sessionKey of sample) {
|
|
83
|
-
const entry = map[sessionKey];
|
|
84
|
-
if (!entry?.sessionId) {
|
|
85
|
-
missing.push(sessionKey);
|
|
67
|
+
const locations = discoverSessionMapLocations(config, ctx.stateDir);
|
|
68
|
+
const missingMaps = [];
|
|
69
|
+
const invalidMaps = [];
|
|
70
|
+
const missingTranscripts = [];
|
|
71
|
+
const agentMismatches = [];
|
|
72
|
+
const orphanTranscripts = [];
|
|
73
|
+
let sessionCount = 0;
|
|
74
|
+
for (const location of locations) {
|
|
75
|
+
if (!existsSync(location.sessionsDir)) continue;
|
|
76
|
+
if (!existsSync(location.mapPath)) {
|
|
77
|
+
missingMaps.push(location.mapPath);
|
|
86
78
|
continue;
|
|
87
79
|
}
|
|
80
|
+
let map;
|
|
88
81
|
try {
|
|
89
|
-
|
|
82
|
+
map = readSessionMap(location.mapPath);
|
|
90
83
|
} catch {
|
|
91
|
-
|
|
84
|
+
invalidMaps.push(location.mapPath);
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
const referencedTranscriptFiles = /* @__PURE__ */ new Set();
|
|
88
|
+
for (const [sessionKey, entry] of Object.entries(map)) {
|
|
89
|
+
sessionCount++;
|
|
90
|
+
const parsed = parseSessionKey(sessionKey);
|
|
91
|
+
if (parsed && parsed.agentId !== location.agentId) agentMismatches.push(`${sessionKey} in agent ${location.agentId}`);
|
|
92
|
+
if (!entry?.sessionId) {
|
|
93
|
+
missingTranscripts.push(sessionKey);
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
const transcriptPath = resolveSessionFilePath(entry.sessionId, entry, { sessionsDir: location.sessionsDir });
|
|
98
|
+
referencedTranscriptFiles.add(basename(transcriptPath));
|
|
99
|
+
if (!existsSync(transcriptPath)) missingTranscripts.push(sessionKey);
|
|
100
|
+
} catch {
|
|
101
|
+
missingTranscripts.push(sessionKey);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
for (const file of readdirSync(location.sessionsDir, { withFileTypes: true })) {
|
|
105
|
+
if (!file.isFile() || !file.name.endsWith(".jsonl") || file.name.includes(".checkpoint.")) continue;
|
|
106
|
+
if (!referencedTranscriptFiles.has(file.name)) orphanTranscripts.push(join(location.sessionsDir, file.name));
|
|
92
107
|
}
|
|
93
108
|
}
|
|
94
|
-
|
|
109
|
+
const hints = [
|
|
110
|
+
...missingMaps.slice(0, 3).map((path) => `Missing sessions.json: ${path}`),
|
|
111
|
+
...invalidMaps.slice(0, 3).map((path) => `Invalid sessions.json: ${path}`),
|
|
112
|
+
...agentMismatches.slice(0, 3).map((item) => `Session key agent mismatch: ${item}`),
|
|
113
|
+
...missingTranscripts.slice(0, 3).map((key) => `Missing transcript for: ${key}`),
|
|
114
|
+
...orphanTranscripts.slice(0, 3).map((path) => `Orphan transcript: ${path}`)
|
|
115
|
+
];
|
|
116
|
+
const warningCount = missingMaps.length + invalidMaps.length + missingTranscripts.length + agentMismatches.length + orphanTranscripts.length;
|
|
117
|
+
if (warningCount > 0) return {
|
|
95
118
|
id: "session-integrity",
|
|
96
119
|
label: "Sessions",
|
|
97
120
|
status: "warn",
|
|
98
|
-
message:
|
|
99
|
-
hints
|
|
121
|
+
message: `Scanned ${locations.length} agent session dir(s), ${sessionCount} session(s); found ${warningCount} issue(s).`,
|
|
122
|
+
hints
|
|
100
123
|
};
|
|
101
124
|
return {
|
|
102
125
|
id: "session-integrity",
|
|
103
126
|
label: "Sessions",
|
|
104
127
|
status: "pass",
|
|
105
|
-
message: `
|
|
128
|
+
message: `Scanned ${locations.length} agent session dir(s), ${sessionCount} session(s); session maps and JSONL transcripts are consistent.`,
|
|
106
129
|
hints: []
|
|
107
130
|
};
|
|
108
131
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-integrity.js","names":[],"sources":["../../../../../../src/cli/commands/doctor/checks/session-integrity.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport { resolveDefaultAgentId } from '../../../../agent/agent-scope.js';\nimport { loadConfig } from '../../../../config/loader.js';\nimport { FILENAMES, resolveSessionsDir } from '../../../../config/paths.js';\nimport { resolveSessionFilePath } from '../../../../session/parity/transcript-paths.js';\nimport type { XopcSessionDiskEntry } from '../../../../session/parity/xopc-session-disk-entry.js';\nimport type { CheckResult, DoctorContext } from '../types.js';\n\nexport async function checkSessionIntegrity(ctx: DoctorContext): Promise<CheckResult> {\n if (!ctx.options.deep) {\n return {\n id: 'session-integrity',\n label: 'Sessions',\n status: 'skip',\n message: 'Deep mode off; session scan skipped.',\n hints: ['Run: xopc doctor --deep'],\n };\n }\n\n if (!existsSync(ctx.configPath)) {\n return {\n id: 'session-integrity',\n label: 'Sessions',\n status: 'skip',\n message: 'No config file; skipped.',\n hints: [],\n };\n }\n\n let config;\n try {\n config = loadConfig(ctx.configPath);\n } catch {\n return {\n id: 'session-integrity',\n label: 'Sessions',\n status: 'skip',\n message: 'Config could not be loaded; skipped.',\n hints: [],\n };\n }\n\n const
|
|
1
|
+
{"version":3,"file":"session-integrity.js","names":[],"sources":["../../../../../../src/cli/commands/doctor/checks/session-integrity.ts"],"sourcesContent":["import { existsSync, readdirSync, readFileSync } from 'node:fs';\nimport { basename, join } from 'node:path';\n\nimport { listAgentEntries, resolveDefaultAgentId } from '../../../../agent/agent-scope.js';\nimport { loadConfig } from '../../../../config/loader.js';\nimport type { Config } from '../../../../config/schema.js';\nimport { FILENAMES, resolveSessionsDir } from '../../../../config/paths.js';\nimport { parseSessionKey } from '../../../../routing/session-key.js';\nimport { resolveSessionFilePath } from '../../../../session/parity/transcript-paths.js';\nimport type { XopcSessionDiskEntry } from '../../../../session/parity/xopc-session-disk-entry.js';\nimport type { CheckResult, DoctorContext } from '../types.js';\n\ninterface SessionMapLocation {\n agentId: string;\n sessionsDir: string;\n mapPath: string;\n}\n\nfunction discoverSessionMapLocations(config: Config, stateDir: string): SessionMapLocation[] {\n const agentIds = new Set<string>([\n resolveDefaultAgentId(config),\n ...listAgentEntries(config).map((agent) => agent.id),\n ]);\n\n const agentsRoot = join(stateDir, 'agents');\n if (existsSync(agentsRoot)) {\n for (const entry of readdirSync(agentsRoot, { withFileTypes: true })) {\n if (entry.isDirectory()) {\n agentIds.add(entry.name);\n }\n }\n }\n\n const seenMapPaths = new Set<string>();\n const locations: SessionMapLocation[] = [];\n for (const agentId of agentIds) {\n const sessionsDir = resolveSessionsDir(config, agentId);\n const mapPath = join(sessionsDir, FILENAMES.SESSIONS_MAP);\n if (seenMapPaths.has(mapPath)) {\n continue;\n }\n seenMapPaths.add(mapPath);\n locations.push({ agentId, sessionsDir, mapPath });\n }\n return locations;\n}\n\nfunction readSessionMap(mapPath: string): Record<string, XopcSessionDiskEntry> {\n const parsed = JSON.parse(readFileSync(mapPath, 'utf-8')) as unknown;\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error('invalid sessions map');\n }\n return parsed as Record<string, XopcSessionDiskEntry>;\n}\n\nexport async function checkSessionIntegrity(ctx: DoctorContext): Promise<CheckResult> {\n if (!ctx.options.deep) {\n return {\n id: 'session-integrity',\n label: 'Sessions',\n status: 'skip',\n message: 'Deep mode off; session scan skipped.',\n hints: ['Run: xopc doctor --deep'],\n };\n }\n\n if (!existsSync(ctx.configPath)) {\n return {\n id: 'session-integrity',\n label: 'Sessions',\n status: 'skip',\n message: 'No config file; skipped.',\n hints: [],\n };\n }\n\n let config: Config;\n try {\n config = loadConfig(ctx.configPath);\n } catch {\n return {\n id: 'session-integrity',\n label: 'Sessions',\n status: 'skip',\n message: 'Config could not be loaded; skipped.',\n hints: [],\n };\n }\n\n const locations = discoverSessionMapLocations(config, ctx.stateDir);\n const missingMaps: string[] = [];\n const invalidMaps: string[] = [];\n const missingTranscripts: string[] = [];\n const agentMismatches: string[] = [];\n const orphanTranscripts: string[] = [];\n let sessionCount = 0;\n\n for (const location of locations) {\n if (!existsSync(location.sessionsDir)) {\n continue;\n }\n if (!existsSync(location.mapPath)) {\n missingMaps.push(location.mapPath);\n continue;\n }\n\n let map: Record<string, XopcSessionDiskEntry>;\n try {\n map = readSessionMap(location.mapPath);\n } catch {\n invalidMaps.push(location.mapPath);\n continue;\n }\n\n const referencedTranscriptFiles = new Set<string>();\n for (const [sessionKey, entry] of Object.entries(map)) {\n sessionCount++;\n const parsed = parseSessionKey(sessionKey);\n if (parsed && parsed.agentId !== location.agentId) {\n agentMismatches.push(`${sessionKey} in agent ${location.agentId}`);\n }\n if (!entry?.sessionId) {\n missingTranscripts.push(sessionKey);\n continue;\n }\n try {\n const transcriptPath = resolveSessionFilePath(entry.sessionId, entry, { sessionsDir: location.sessionsDir });\n referencedTranscriptFiles.add(basename(transcriptPath));\n if (!existsSync(transcriptPath)) {\n missingTranscripts.push(sessionKey);\n }\n } catch {\n missingTranscripts.push(sessionKey);\n }\n }\n\n for (const file of readdirSync(location.sessionsDir, { withFileTypes: true })) {\n if (!file.isFile() || !file.name.endsWith('.jsonl') || file.name.includes('.checkpoint.')) {\n continue;\n }\n if (!referencedTranscriptFiles.has(file.name)) {\n orphanTranscripts.push(join(location.sessionsDir, file.name));\n }\n }\n }\n\n const hints = [\n ...missingMaps.slice(0, 3).map((path) => `Missing sessions.json: ${path}`),\n ...invalidMaps.slice(0, 3).map((path) => `Invalid sessions.json: ${path}`),\n ...agentMismatches.slice(0, 3).map((item) => `Session key agent mismatch: ${item}`),\n ...missingTranscripts.slice(0, 3).map((key) => `Missing transcript for: ${key}`),\n ...orphanTranscripts.slice(0, 3).map((path) => `Orphan transcript: ${path}`),\n ];\n\n const warningCount =\n missingMaps.length + invalidMaps.length + missingTranscripts.length + agentMismatches.length + orphanTranscripts.length;\n\n if (warningCount > 0) {\n return {\n id: 'session-integrity',\n label: 'Sessions',\n status: 'warn',\n message: `Scanned ${locations.length} agent session dir(s), ${sessionCount} session(s); found ${warningCount} issue(s).`,\n hints,\n };\n }\n\n return {\n id: 'session-integrity',\n label: 'Sessions',\n status: 'pass',\n message: `Scanned ${locations.length} agent session dir(s), ${sessionCount} session(s); session maps and JSONL transcripts are consistent.`,\n hints: [],\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { init_paths, resolveConfigPath } from "../../../config/paths.js";
|
|
2
2
|
import { loadConfig } from "../../../config/loader.js";
|
|
3
3
|
import "../../../config/index.js";
|
|
4
|
-
import { resolveGatewayService } from "../../../daemon/service.js";
|
|
5
4
|
import { isRestartEnabled } from "../../../config/commands.flags.js";
|
|
5
|
+
import { resolveGatewayService } from "../../../daemon/service.js";
|
|
6
6
|
import { authorizeGatewaySigusr1Restart, writeGatewayRestartIntentSync } from "../../../infra/restart.js";
|
|
7
7
|
import { findVerifiedGatewayListenerPidsOnPortSync, formatGatewayPidList, signalVerifiedGatewayPidSync } from "../../../infra/gateway-processes.js";
|
|
8
8
|
import { runServiceRestart, runServiceStop } from "./lifecycle-core.js";
|