@nextclaw/service 0.1.1
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/LICENSE +21 -0
- package/dist/cli/commands/agent/agent-runtime.utils.d.ts +15 -0
- package/dist/cli/commands/agent/agent-runtime.utils.js +85 -0
- package/dist/cli/commands/agent/cli-agent-runner.utils.d.ts +21 -0
- package/dist/cli/commands/agent/cli-agent-runner.utils.js +89 -0
- package/dist/cli/commands/agent/index.d.ts +3 -0
- package/dist/cli/commands/agent/index.js +3 -0
- package/dist/cli/commands/agent/services/agent-commands.service.d.ts +17 -0
- package/dist/cli/commands/agent/services/agent-commands.service.js +112 -0
- package/dist/cli/commands/companion/index.d.ts +15 -0
- package/dist/cli/commands/companion/index.js +24 -0
- package/dist/cli/commands/companion/services/companion-process.service.d.ts +17 -0
- package/dist/cli/commands/companion/services/companion-process.service.js +49 -0
- package/dist/cli/commands/config/index.d.ts +2 -0
- package/dist/cli/commands/config/index.js +2 -0
- package/dist/cli/commands/config/services/config-commands.service.d.ts +18 -0
- package/dist/cli/commands/config/services/config-commands.service.js +133 -0
- package/dist/cli/commands/cron/index.d.ts +2 -0
- package/dist/cli/commands/cron/index.js +2 -0
- package/dist/cli/commands/cron/services/cron-commands.service.d.ts +22 -0
- package/dist/cli/commands/cron/services/cron-commands.service.js +107 -0
- package/dist/cli/commands/cron/services/cron-local.service.d.ts +25 -0
- package/dist/cli/commands/cron/services/cron-local.service.js +95 -0
- package/dist/cli/commands/cron/utils/cron-job.utils.d.ts +31 -0
- package/dist/cli/commands/cron/utils/cron-job.utils.js +15 -0
- package/dist/cli/commands/diagnostics/index.d.ts +2 -0
- package/dist/cli/commands/diagnostics/index.js +2 -0
- package/dist/cli/commands/diagnostics/services/diagnostics-commands.service.d.ts +22 -0
- package/dist/cli/commands/diagnostics/services/diagnostics-commands.service.js +319 -0
- package/dist/cli/commands/diagnostics/utils/diagnostics-render.utils.d.ts +23 -0
- package/dist/cli/commands/diagnostics/utils/diagnostics-render.utils.js +66 -0
- package/dist/cli/commands/gateway/index.d.ts +14 -0
- package/dist/cli/commands/gateway/index.js +15 -0
- package/dist/cli/commands/logs/index.d.ts +12 -0
- package/dist/cli/commands/logs/index.js +29 -0
- package/dist/cli/commands/mcp/index.d.ts +14 -0
- package/dist/cli/commands/mcp/index.js +193 -0
- package/dist/cli/commands/restart/index.d.ts +20 -0
- package/dist/cli/commands/restart/index.js +88 -0
- package/dist/cli/commands/secrets/index.d.ts +22 -0
- package/dist/cli/commands/secrets/index.js +280 -0
- package/dist/cli/commands/serve/index.d.ts +14 -0
- package/dist/cli/commands/serve/index.js +19 -0
- package/dist/cli/commands/skills/index.d.ts +26 -0
- package/dist/cli/commands/skills/index.js +147 -0
- package/dist/cli/commands/skills/marketplace-client.d.ts +31 -0
- package/dist/cli/commands/skills/marketplace-client.js +84 -0
- package/dist/cli/commands/skills/marketplace-command-options.utils.d.ts +25 -0
- package/dist/cli/commands/skills/marketplace-command-options.utils.js +31 -0
- package/dist/cli/commands/skills/marketplace-identity.utils.d.ts +14 -0
- package/dist/cli/commands/skills/marketplace-identity.utils.js +77 -0
- package/dist/cli/commands/skills/marketplace-network-retry.d.ts +4 -0
- package/dist/cli/commands/skills/marketplace-network-retry.js +32 -0
- package/dist/cli/commands/skills/marketplace.metadata.d.ts +29 -0
- package/dist/cli/commands/skills/marketplace.metadata.js +158 -0
- package/dist/cli/commands/skills/marketplace.service.d.ts +46 -0
- package/dist/cli/commands/skills/marketplace.service.js +238 -0
- package/dist/cli/commands/skills/skills-query.service.d.ts +141 -0
- package/dist/cli/commands/skills/skills-query.service.js +212 -0
- package/dist/cli/commands/start/index.d.ts +18 -0
- package/dist/cli/commands/start/index.js +25 -0
- package/dist/cli/commands/stop/index.d.ts +12 -0
- package/dist/cli/commands/stop/index.js +11 -0
- package/dist/cli/commands/ui/index.d.ts +14 -0
- package/dist/cli/commands/ui/index.js +17 -0
- package/dist/cli/commands/usage/index.d.ts +2 -0
- package/dist/cli/commands/usage/index.js +2 -0
- package/dist/cli/commands/usage/services/llm-usage-command.service.d.ts +22 -0
- package/dist/cli/commands/usage/services/llm-usage-command.service.js +160 -0
- package/dist/cli/commands/usage/services/llm-usage-query.service.d.ts +43 -0
- package/dist/cli/commands/usage/services/llm-usage-query.service.js +85 -0
- package/dist/commands/channel/channel-config-view.d.ts +7 -0
- package/dist/commands/channel/channel-config-view.js +7 -0
- package/dist/commands/channel/index.d.ts +28 -0
- package/dist/commands/channel/index.js +224 -0
- package/dist/commands/platform-auth/index.d.ts +2 -0
- package/dist/commands/platform-auth/index.js +2 -0
- package/dist/commands/platform-auth/services/account-status.service.d.ts +18 -0
- package/dist/commands/platform-auth/services/account-status.service.js +34 -0
- package/dist/commands/platform-auth/services/platform-auth-commands.service.d.ts +77 -0
- package/dist/commands/platform-auth/services/platform-auth-commands.service.js +295 -0
- package/dist/commands/platform-auth/utils/payload.utils.d.ts +28 -0
- package/dist/commands/platform-auth/utils/payload.utils.js +87 -0
- package/dist/commands/plugin/development-source/dev-plugin-overrides.utils.d.ts +18 -0
- package/dist/commands/plugin/development-source/dev-plugin-overrides.utils.js +111 -0
- package/dist/commands/plugin/development-source/first-party-plugin-load-paths.d.ts +9 -0
- package/dist/commands/plugin/development-source/first-party-plugin-load-paths.js +183 -0
- package/dist/commands/plugin/index.d.ts +30 -0
- package/dist/commands/plugin/index.js +266 -0
- package/dist/commands/plugin/plugin-command-utils.d.ts +13 -0
- package/dist/commands/plugin/plugin-command-utils.js +37 -0
- package/dist/commands/plugin/plugin-extension-registry.d.ts +10 -0
- package/dist/commands/plugin/plugin-extension-registry.js +35 -0
- package/dist/commands/plugin/plugin-mutation-actions.d.ts +15 -0
- package/dist/commands/plugin/plugin-mutation-actions.js +162 -0
- package/dist/commands/plugin/plugin-registry-loader.d.ts +15 -0
- package/dist/commands/plugin/plugin-registry-loader.js +43 -0
- package/dist/commands/plugin/plugin-reload.d.ts +13 -0
- package/dist/commands/plugin/plugin-reload.js +42 -0
- package/dist/commands/remote/index.d.ts +47 -0
- package/dist/commands/remote/index.js +174 -0
- package/dist/commands/remote/services/remote-access-host.service.d.ts +41 -0
- package/dist/commands/remote/services/remote-access-host.service.js +126 -0
- package/dist/commands/remote/services/remote-runtime-support.service.d.ts +15 -0
- package/dist/commands/remote/services/remote-runtime-support.service.js +79 -0
- package/dist/commands/remote/services/remote-service-control.service.d.ts +33 -0
- package/dist/commands/remote/services/remote-service-control.service.js +188 -0
- package/dist/commands/remote/utils/platform-api-base.utils.d.ts +14 -0
- package/dist/commands/remote/utils/platform-api-base.utils.js +39 -0
- package/dist/commands/service/index.d.ts +16 -0
- package/dist/commands/service/index.js +31 -0
- package/dist/commands/service/services/autostart/host-autostart-command.service.d.ts +29 -0
- package/dist/commands/service/services/autostart/host-autostart-command.service.js +158 -0
- package/dist/commands/service/services/autostart/host-autostart-runtime.service.d.ts +23 -0
- package/dist/commands/service/services/autostart/host-autostart-runtime.service.js +53 -0
- package/dist/commands/service/services/autostart/host-autostart.service.d.ts +41 -0
- package/dist/commands/service/services/autostart/host-autostart.service.js +48 -0
- package/dist/commands/service/services/autostart/linux-systemd-autostart.service.d.ts +48 -0
- package/dist/commands/service/services/autostart/linux-systemd-autostart.service.js +433 -0
- package/dist/commands/service/services/autostart/macos-launch-agent-autostart.service.d.ts +54 -0
- package/dist/commands/service/services/autostart/macos-launch-agent-autostart.service.js +405 -0
- package/dist/commands/service/services/autostart/windows-task-autostart.service.d.ts +54 -0
- package/dist/commands/service/services/autostart/windows-task-autostart.service.js +403 -0
- package/dist/commands/service/types/autostart/host-autostart.types.d.ts +64 -0
- package/dist/commands/service/types/autostart/host-autostart.types.js +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/launcher/npm-runtime-bundle-layout.store.d.ts +23 -0
- package/dist/launcher/npm-runtime-bundle-layout.store.js +37 -0
- package/dist/launcher/npm-runtime-bundle-manifest.service.d.ts +9 -0
- package/dist/launcher/npm-runtime-bundle-manifest.service.js +39 -0
- package/dist/launcher/npm-runtime-bundle.service.d.ts +47 -0
- package/dist/launcher/npm-runtime-bundle.service.js +150 -0
- package/dist/launcher/npm-runtime-bundle.types.d.ts +49 -0
- package/dist/launcher/npm-runtime-bundle.types.js +1 -0
- package/dist/launcher/npm-runtime-launcher.service.d.ts +19 -0
- package/dist/launcher/npm-runtime-launcher.service.js +57 -0
- package/dist/launcher/npm-runtime-update-command.service.d.ts +12 -0
- package/dist/launcher/npm-runtime-update-command.service.js +87 -0
- package/dist/launcher/npm-runtime-update-source.service.d.ts +19 -0
- package/dist/launcher/npm-runtime-update-source.service.js +57 -0
- package/dist/launcher/npm-runtime-update-state.store.d.ts +17 -0
- package/dist/launcher/npm-runtime-update-state.store.js +92 -0
- package/dist/launcher/npm-runtime-update.manager.d.ts +42 -0
- package/dist/launcher/npm-runtime-update.manager.js +179 -0
- package/dist/launcher/npm-runtime-update.service.d.ts +54 -0
- package/dist/launcher/npm-runtime-update.service.js +183 -0
- package/dist/service-runtime.service.d.ts +91 -0
- package/dist/service-runtime.service.js +392 -0
- package/dist/shared/controllers/gateway.controller.d.ts +61 -0
- package/dist/shared/controllers/gateway.controller.js +318 -0
- package/dist/shared/services/extensions/extension-lifecycle.service.d.ts +56 -0
- package/dist/shared/services/extensions/extension-lifecycle.service.js +143 -0
- package/dist/shared/services/extensions/service-extension-runtime.service.d.ts +51 -0
- package/dist/shared/services/extensions/service-extension-runtime.service.js +338 -0
- package/dist/shared/services/gateway/cron-job-handler.service.d.ts +26 -0
- package/dist/shared/services/gateway/cron-job-handler.service.js +100 -0
- package/dist/shared/services/gateway/gateway-restart-wake.service.d.ts +12 -0
- package/dist/shared/services/gateway/gateway-restart-wake.service.js +91 -0
- package/dist/shared/services/gateway/managers/gateway-plugin.manager.d.ts +37 -0
- package/dist/shared/services/gateway/managers/gateway-plugin.manager.js +218 -0
- package/dist/shared/services/gateway/managers/gateway-remote.manager.d.ts +20 -0
- package/dist/shared/services/gateway/managers/gateway-remote.manager.js +25 -0
- package/dist/shared/services/gateway/nextclaw-app.service.d.ts +22 -0
- package/dist/shared/services/gateway/nextclaw-app.service.js +53 -0
- package/dist/shared/services/gateway/nextclaw-gateway-runtime.service.d.ts +89 -0
- package/dist/shared/services/gateway/nextclaw-gateway-runtime.service.js +337 -0
- package/dist/shared/services/gateway/service-bootstrap-status.d.ts +33 -0
- package/dist/shared/services/gateway/service-bootstrap-status.js +152 -0
- package/dist/shared/services/gateway/service-startup-support.service.d.ts +42 -0
- package/dist/shared/services/gateway/service-startup-support.service.js +96 -0
- package/dist/shared/services/gateway/utils/gateway-runtime-lifecycle.utils.d.ts +9 -0
- package/dist/shared/services/gateway/utils/gateway-runtime-lifecycle.utils.js +10 -0
- package/dist/shared/services/marketplace/service-marketplace-installer.service.d.ts +31 -0
- package/dist/shared/services/marketplace/service-marketplace-installer.service.js +99 -0
- package/dist/shared/services/marketplace/service-mcp-marketplace-ops.d.ts +39 -0
- package/dist/shared/services/marketplace/service-mcp-marketplace-ops.js +67 -0
- package/dist/shared/services/plugin/utils/plugin-dev-hot-reload.utils.d.ts +24 -0
- package/dist/shared/services/plugin/utils/plugin-dev-hot-reload.utils.js +117 -0
- package/dist/shared/services/plugin/utils/plugin-runtime-bridge.utils.d.ts +6 -0
- package/dist/shared/services/plugin/utils/plugin-runtime-bridge.utils.js +96 -0
- package/dist/shared/services/restart/restart-coordinator.service.d.ts +30 -0
- package/dist/shared/services/restart/restart-coordinator.service.js +51 -0
- package/dist/shared/services/restart/restart-sentinel.service.d.ts +39 -0
- package/dist/shared/services/restart/restart-sentinel.service.js +88 -0
- package/dist/shared/services/restart/runtime-restart-request.service.d.ts +24 -0
- package/dist/shared/services/restart/runtime-restart-request.service.js +42 -0
- package/dist/shared/services/runtime/runtime-command.service.d.ts +37 -0
- package/dist/shared/services/runtime/runtime-command.service.js +163 -0
- package/dist/shared/services/runtime/runtime-config-init.service.d.ts +4 -0
- package/dist/shared/services/runtime/runtime-config-init.service.js +10 -0
- package/dist/shared/services/runtime/service-managed-startup.service.d.ts +146 -0
- package/dist/shared/services/runtime/service-managed-startup.service.js +426 -0
- package/dist/shared/services/runtime/service-remote-runtime.service.d.ts +53 -0
- package/dist/shared/services/runtime/service-remote-runtime.service.js +173 -0
- package/dist/shared/services/runtime/utils/skills-loader.utils.d.ts +12 -0
- package/dist/shared/services/runtime/utils/skills-loader.utils.js +9 -0
- package/dist/shared/services/session/service-deferred-ncp-agent.service.d.ts +14 -0
- package/dist/shared/services/session/service-deferred-ncp-agent.service.js +85 -0
- package/dist/shared/services/ui/companion-runtime.service.d.ts +33 -0
- package/dist/shared/services/ui/companion-runtime.service.js +145 -0
- package/dist/shared/services/ui/local-ui-discovery.service.d.ts +19 -0
- package/dist/shared/services/ui/local-ui-discovery.service.js +41 -0
- package/dist/shared/services/ui/npm-runtime-update-host.service.d.ts +40 -0
- package/dist/shared/services/ui/npm-runtime-update-host.service.js +181 -0
- package/dist/shared/services/ui/runtime-control-host.service.d.ts +28 -0
- package/dist/shared/services/ui/runtime-control-host.service.js +89 -0
- package/dist/shared/services/ui/service-remote-access.service.d.ts +25 -0
- package/dist/shared/services/ui/service-remote-access.service.js +38 -0
- package/dist/shared/services/ui/ui-bridge-api.service.d.ts +16 -0
- package/dist/shared/services/ui/ui-bridge-api.service.js +43 -0
- package/dist/shared/services/workspace/workspace-manager.service.d.ts +19 -0
- package/dist/shared/services/workspace/workspace-manager.service.js +135 -0
- package/dist/shared/stores/companion-runtime.store.d.ts +15 -0
- package/dist/shared/stores/companion-runtime.store.js +27 -0
- package/dist/shared/stores/local-ui-runtime.store.d.ts +25 -0
- package/dist/shared/stores/local-ui-runtime.store.js +54 -0
- package/dist/shared/stores/managed-service-state.store.d.ts +28 -0
- package/dist/shared/stores/managed-service-state.store.js +38 -0
- package/dist/shared/stores/pending-restart.store.d.ts +21 -0
- package/dist/shared/stores/pending-restart.store.js +35 -0
- package/dist/shared/types/cli.types.d.ts +295 -0
- package/dist/shared/types/cli.types.js +1 -0
- package/dist/shared/utils/cli.utils.d.ts +34 -0
- package/dist/shared/utils/cli.utils.js +262 -0
- package/dist/shared/utils/config-path.d.ts +15 -0
- package/dist/shared/utils/config-path.js +167 -0
- package/dist/shared/utils/marketplace/cli-subcommand-launch.utils.d.ts +16 -0
- package/dist/shared/utils/marketplace/cli-subcommand-launch.utils.js +46 -0
- package/dist/shared/utils/marketplace/service-marketplace-helpers.utils.d.ts +9 -0
- package/dist/shared/utils/marketplace/service-marketplace-helpers.utils.js +33 -0
- package/dist/shared/utils/package/package-manifest.utils.d.ts +8 -0
- package/dist/shared/utils/package/package-manifest.utils.js +48 -0
- package/dist/shared/utils/runtime-helpers.d.ts +14 -0
- package/dist/shared/utils/runtime-helpers.js +26 -0
- package/dist/shared/utils/service-port-probe.utils.d.ts +41 -0
- package/dist/shared/utils/service-port-probe.utils.js +164 -0
- package/dist/shared/utils/startup-trace.d.ts +7 -0
- package/dist/shared/utils/startup-trace.js +37 -0
- package/dist/shared/utils/top-level-nextclaw-command-env.utils.d.ts +4 -0
- package/dist/shared/utils/top-level-nextclaw-command-env.utils.js +10 -0
- package/package.json +68 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { CronAddOptions } from "../../../../shared/types/cli.types.js";
|
|
2
|
+
import { CronLocalService } from "./cron-local.service.js";
|
|
3
|
+
|
|
4
|
+
//#region src/cli/commands/cron/services/cron-commands.service.d.ts
|
|
5
|
+
declare class CronCommands {
|
|
6
|
+
private local;
|
|
7
|
+
constructor(local?: CronLocalService);
|
|
8
|
+
private createApiClient;
|
|
9
|
+
list: (opts: {
|
|
10
|
+
enabledOnly?: boolean;
|
|
11
|
+
}) => Promise<void>;
|
|
12
|
+
add: (opts: CronAddOptions) => Promise<void>;
|
|
13
|
+
remove: (jobId: string) => Promise<void>;
|
|
14
|
+
enable: (jobId: string, opts: {
|
|
15
|
+
disable?: boolean;
|
|
16
|
+
}) => Promise<void>;
|
|
17
|
+
run: (jobId: string, opts: {
|
|
18
|
+
force?: boolean;
|
|
19
|
+
}) => Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
export { CronCommands };
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { UiBridgeApiClient, resolveLocalUiApiBase } from "../../../../shared/services/ui/ui-bridge-api.service.js";
|
|
2
|
+
import { printCronJobs } from "../utils/cron-job.utils.js";
|
|
3
|
+
import { CronLocalService, createCronCreateRequest } from "./cron-local.service.js";
|
|
4
|
+
//#region src/cli/commands/cron/services/cron-commands.service.ts
|
|
5
|
+
function readErrorMessage(error) {
|
|
6
|
+
if (error instanceof Error && error.message.trim().length > 0) return error.message.trim();
|
|
7
|
+
return String(error ?? "unknown error");
|
|
8
|
+
}
|
|
9
|
+
var CronCommands = class {
|
|
10
|
+
constructor(local = new CronLocalService()) {
|
|
11
|
+
this.local = local;
|
|
12
|
+
}
|
|
13
|
+
createApiClient = () => {
|
|
14
|
+
const apiBase = resolveLocalUiApiBase();
|
|
15
|
+
if (!apiBase) return null;
|
|
16
|
+
return new UiBridgeApiClient(apiBase);
|
|
17
|
+
};
|
|
18
|
+
list = async (opts) => {
|
|
19
|
+
const includeDisabled = opts.enabledOnly !== true;
|
|
20
|
+
const apiClient = this.createApiClient();
|
|
21
|
+
if (apiClient) try {
|
|
22
|
+
const query = includeDisabled ? "" : "?enabledOnly=1";
|
|
23
|
+
printCronJobs((await apiClient.request({ path: `/api/cron${query}` })).jobs);
|
|
24
|
+
return;
|
|
25
|
+
} catch {}
|
|
26
|
+
printCronJobs(this.local.list(includeDisabled));
|
|
27
|
+
};
|
|
28
|
+
add = async (opts) => {
|
|
29
|
+
const request = createCronCreateRequest(opts);
|
|
30
|
+
if (!request.request) {
|
|
31
|
+
console.error(request.error ?? "Error: Failed to add job");
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const apiClient = this.createApiClient();
|
|
35
|
+
if (apiClient) try {
|
|
36
|
+
const data = await apiClient.request({
|
|
37
|
+
path: "/api/cron",
|
|
38
|
+
method: "POST",
|
|
39
|
+
body: request.request
|
|
40
|
+
});
|
|
41
|
+
console.log(`✓ Added job '${data.job.name}' (${data.job.id})`);
|
|
42
|
+
return;
|
|
43
|
+
} catch (error) {
|
|
44
|
+
console.error(`Error: ${readErrorMessage(error)}`);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const job = this.local.addRequest(request.request);
|
|
48
|
+
console.log(`✓ Added job '${job.name}' (${job.id})`);
|
|
49
|
+
};
|
|
50
|
+
remove = async (jobId) => {
|
|
51
|
+
const apiClient = this.createApiClient();
|
|
52
|
+
if (apiClient) try {
|
|
53
|
+
if ((await apiClient.request({
|
|
54
|
+
path: `/api/cron/${encodeURIComponent(jobId)}`,
|
|
55
|
+
method: "DELETE"
|
|
56
|
+
})).deleted) {
|
|
57
|
+
console.log(`✓ Removed job ${jobId}`);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
} catch (error) {
|
|
61
|
+
console.error(`Error: ${readErrorMessage(error)}`);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (this.local.remove(jobId)) console.log(`✓ Removed job ${jobId}`);
|
|
65
|
+
else console.log(`Job ${jobId} not found`);
|
|
66
|
+
};
|
|
67
|
+
enable = async (jobId, opts) => {
|
|
68
|
+
const apiClient = this.createApiClient();
|
|
69
|
+
const enabled = !opts.disable;
|
|
70
|
+
if (apiClient) try {
|
|
71
|
+
const data = await apiClient.request({
|
|
72
|
+
path: `/api/cron/${encodeURIComponent(jobId)}/enable`,
|
|
73
|
+
method: "PUT",
|
|
74
|
+
body: { enabled }
|
|
75
|
+
});
|
|
76
|
+
if (data.job) {
|
|
77
|
+
console.log(`✓ Job '${data.job.name}' ${opts.disable ? "disabled" : "enabled"}`);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
} catch (error) {
|
|
81
|
+
console.error(`Error: ${readErrorMessage(error)}`);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const job = this.local.enable(jobId, enabled);
|
|
85
|
+
if (job) console.log(`✓ Job '${job.name}' ${opts.disable ? "disabled" : "enabled"}`);
|
|
86
|
+
else console.log(`Job ${jobId} not found`);
|
|
87
|
+
};
|
|
88
|
+
run = async (jobId, opts) => {
|
|
89
|
+
const apiClient = this.createApiClient();
|
|
90
|
+
if (apiClient) try {
|
|
91
|
+
const data = await apiClient.request({
|
|
92
|
+
path: `/api/cron/${encodeURIComponent(jobId)}/run`,
|
|
93
|
+
method: "POST",
|
|
94
|
+
body: { force: Boolean(opts.force) }
|
|
95
|
+
});
|
|
96
|
+
console.log(data.executed ? "✓ Job executed" : `Failed to run job ${jobId}`);
|
|
97
|
+
return;
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.error(`Error: ${readErrorMessage(error)}`);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const ok = await this.local.run(jobId, Boolean(opts.force));
|
|
103
|
+
console.log(ok ? "✓ Job executed" : `Failed to run job ${jobId}`);
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
//#endregion
|
|
107
|
+
export { CronCommands };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { CronAddOptions } from "../../../../shared/types/cli.types.js";
|
|
2
|
+
import { CronJobView } from "../utils/cron-job.utils.js";
|
|
3
|
+
import { CronCreateRequest } from "@nextclaw/server";
|
|
4
|
+
import { AutomationManager } from "@nextclaw/kernel";
|
|
5
|
+
|
|
6
|
+
//#region src/cli/commands/cron/services/cron-local.service.d.ts
|
|
7
|
+
declare function createCronCreateRequest(opts: CronAddOptions): {
|
|
8
|
+
request?: CronCreateRequest;
|
|
9
|
+
error?: string;
|
|
10
|
+
};
|
|
11
|
+
declare class CronLocalService {
|
|
12
|
+
private readonly automation;
|
|
13
|
+
constructor(automation?: AutomationManager);
|
|
14
|
+
readonly list: (all: boolean) => CronJobView[];
|
|
15
|
+
readonly addRequest: (request: CronCreateRequest) => CronJobView;
|
|
16
|
+
readonly add: (opts: CronAddOptions) => {
|
|
17
|
+
job: CronJobView | null;
|
|
18
|
+
error?: string;
|
|
19
|
+
};
|
|
20
|
+
readonly remove: (jobId: string) => boolean;
|
|
21
|
+
readonly enable: (jobId: string, enabled: boolean) => CronJobView | null;
|
|
22
|
+
readonly run: (jobId: string, force: boolean) => Promise<boolean>;
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
export { CronLocalService, createCronCreateRequest };
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import { getDataDir } from "@nextclaw/core";
|
|
3
|
+
import { AutomationManager } from "@nextclaw/kernel";
|
|
4
|
+
//#region src/cli/commands/cron/services/cron-local.service.ts
|
|
5
|
+
function readTrimmed(value) {
|
|
6
|
+
if (typeof value !== "string") return;
|
|
7
|
+
return value.trim() || void 0;
|
|
8
|
+
}
|
|
9
|
+
function toSchedule(opts) {
|
|
10
|
+
const every = readTrimmed(opts.every);
|
|
11
|
+
const cron = readTrimmed(opts.cron);
|
|
12
|
+
const at = readTrimmed(opts.at);
|
|
13
|
+
if ([
|
|
14
|
+
every,
|
|
15
|
+
cron,
|
|
16
|
+
at
|
|
17
|
+
].filter((value) => value !== void 0).length !== 1) return { error: "Error: Must specify exactly one of --every, --cron, or --at" };
|
|
18
|
+
if (every) {
|
|
19
|
+
const everySeconds = Number(every);
|
|
20
|
+
if (!Number.isFinite(everySeconds) || everySeconds <= 0) return { error: "Error: --every must be a positive number of seconds" };
|
|
21
|
+
return { schedule: {
|
|
22
|
+
kind: "every",
|
|
23
|
+
everyMs: everySeconds * 1e3
|
|
24
|
+
} };
|
|
25
|
+
}
|
|
26
|
+
if (cron) return { schedule: {
|
|
27
|
+
kind: "cron",
|
|
28
|
+
expr: cron
|
|
29
|
+
} };
|
|
30
|
+
const atMs = Date.parse(String(at));
|
|
31
|
+
if (!Number.isFinite(atMs)) return { error: "Error: --at must be a valid ISO datetime" };
|
|
32
|
+
return { schedule: {
|
|
33
|
+
kind: "at",
|
|
34
|
+
atMs
|
|
35
|
+
} };
|
|
36
|
+
}
|
|
37
|
+
function createCronCreateRequest(opts) {
|
|
38
|
+
const name = readTrimmed(opts.name);
|
|
39
|
+
const message = readTrimmed(opts.message);
|
|
40
|
+
if (!name || !message) return { error: "Error: name and message are required" };
|
|
41
|
+
const schedule = toSchedule(opts);
|
|
42
|
+
if (!schedule.schedule) return { error: schedule.error ?? "Error: Must specify --every, --cron, or --at" };
|
|
43
|
+
return { request: {
|
|
44
|
+
name,
|
|
45
|
+
message,
|
|
46
|
+
schedule: schedule.schedule,
|
|
47
|
+
agentId: readTrimmed(opts.agent),
|
|
48
|
+
sessionId: readTrimmed(opts.session),
|
|
49
|
+
deliver: Boolean(opts.deliver),
|
|
50
|
+
channel: readTrimmed(opts.channel),
|
|
51
|
+
to: readTrimmed(opts.to),
|
|
52
|
+
accountId: readTrimmed(opts.account)
|
|
53
|
+
} };
|
|
54
|
+
}
|
|
55
|
+
var CronLocalService = class {
|
|
56
|
+
constructor(automation = new AutomationManager({ storePath: resolve(getDataDir(), "cron", "jobs.json") })) {
|
|
57
|
+
this.automation = automation;
|
|
58
|
+
}
|
|
59
|
+
list = (all) => {
|
|
60
|
+
return this.automation.listJobs(all);
|
|
61
|
+
};
|
|
62
|
+
addRequest = (request) => {
|
|
63
|
+
return this.automation.addJob({
|
|
64
|
+
name: request.name,
|
|
65
|
+
schedule: request.schedule,
|
|
66
|
+
message: request.message,
|
|
67
|
+
agentId: request.agentId ?? void 0,
|
|
68
|
+
sessionId: request.sessionId ?? void 0,
|
|
69
|
+
deliver: request.deliver === true,
|
|
70
|
+
channel: request.channel ?? void 0,
|
|
71
|
+
to: request.to ?? void 0,
|
|
72
|
+
accountId: request.accountId ?? void 0,
|
|
73
|
+
deleteAfterRun: request.deleteAfterRun === true
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
add = (opts) => {
|
|
77
|
+
const request = createCronCreateRequest(opts);
|
|
78
|
+
if (!request.request) return {
|
|
79
|
+
job: null,
|
|
80
|
+
error: request.error
|
|
81
|
+
};
|
|
82
|
+
return { job: this.addRequest(request.request) };
|
|
83
|
+
};
|
|
84
|
+
remove = (jobId) => {
|
|
85
|
+
return this.automation.removeJob(jobId);
|
|
86
|
+
};
|
|
87
|
+
enable = (jobId, enabled) => {
|
|
88
|
+
return this.automation.enableJob(jobId, enabled) ?? null;
|
|
89
|
+
};
|
|
90
|
+
run = async (jobId, force) => {
|
|
91
|
+
return this.automation.runJob(jobId, force);
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
//#endregion
|
|
95
|
+
export { CronLocalService, createCronCreateRequest };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
//#region src/cli/commands/cron/utils/cron-job.utils.d.ts
|
|
2
|
+
type CronSchedule = {
|
|
3
|
+
kind: "every";
|
|
4
|
+
everyMs?: number | null;
|
|
5
|
+
} | {
|
|
6
|
+
kind: "cron";
|
|
7
|
+
expr?: string | null;
|
|
8
|
+
} | {
|
|
9
|
+
kind: "at";
|
|
10
|
+
atMs?: number | null;
|
|
11
|
+
};
|
|
12
|
+
type CronPayload = {
|
|
13
|
+
message: string;
|
|
14
|
+
agentId?: string | null;
|
|
15
|
+
sessionId?: string | null;
|
|
16
|
+
deliver?: boolean;
|
|
17
|
+
channel?: string | null;
|
|
18
|
+
to?: string | null;
|
|
19
|
+
accountId?: string | null;
|
|
20
|
+
};
|
|
21
|
+
type CronJobView = {
|
|
22
|
+
id: string;
|
|
23
|
+
name: string;
|
|
24
|
+
enabled: boolean;
|
|
25
|
+
schedule: CronSchedule;
|
|
26
|
+
payload: CronPayload;
|
|
27
|
+
};
|
|
28
|
+
declare function formatCronSchedule(schedule: CronSchedule): string;
|
|
29
|
+
declare function printCronJobs(jobs: CronJobView[]): void;
|
|
30
|
+
//#endregion
|
|
31
|
+
export { CronJobView, CronPayload, CronSchedule, formatCronSchedule, printCronJobs };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/cli/commands/cron/utils/cron-job.utils.ts
|
|
2
|
+
function formatCronSchedule(schedule) {
|
|
3
|
+
if (schedule.kind === "every") return `every ${Math.round((schedule.everyMs ?? 0) / 1e3)}s`;
|
|
4
|
+
if (schedule.kind === "cron") return schedule.expr ?? "";
|
|
5
|
+
return schedule.atMs ? new Date(schedule.atMs).toISOString() : "";
|
|
6
|
+
}
|
|
7
|
+
function printCronJobs(jobs) {
|
|
8
|
+
if (!jobs.length) {
|
|
9
|
+
console.log("No scheduled jobs.");
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
for (const job of jobs) console.log(`${job.id} [${job.enabled ? "enabled" : "disabled"}] ${job.name} ${formatCronSchedule(job.schedule)}`);
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
export { formatCronSchedule, printCronJobs };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { DoctorCommandOptions, StatusCommandOptions } from "../../../../shared/types/cli.types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/cli/commands/diagnostics/services/diagnostics-commands.service.d.ts
|
|
4
|
+
declare class DiagnosticsCommands {
|
|
5
|
+
private deps;
|
|
6
|
+
constructor(deps: {
|
|
7
|
+
logo: string;
|
|
8
|
+
});
|
|
9
|
+
readonly status: (opts?: StatusCommandOptions) => Promise<void>;
|
|
10
|
+
readonly doctor: (opts?: DoctorCommandOptions) => Promise<void>;
|
|
11
|
+
private readonly resolveDoctorPortCheckTarget;
|
|
12
|
+
private readonly buildDoctorChecks;
|
|
13
|
+
private readonly resolveDoctorExitCode;
|
|
14
|
+
private readonly collectRuntimeStatus;
|
|
15
|
+
private readonly probeApiHealth;
|
|
16
|
+
private readonly listProviderStatuses;
|
|
17
|
+
private readonly collectRuntimeIssues;
|
|
18
|
+
private readonly readLogTail;
|
|
19
|
+
private readonly checkPortAvailability;
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
export { DiagnosticsCommands };
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import { isProcessRunning, resolveUiApiBase, resolveUiConfig } from "../../../../shared/utils/cli.utils.js";
|
|
2
|
+
import { managedServiceStateStore } from "../../../../shared/stores/managed-service-state.store.js";
|
|
3
|
+
import { resolveNextclawRemoteStatusSnapshot } from "../../../../commands/remote/services/remote-runtime-support.service.js";
|
|
4
|
+
import "../../../../commands/remote/index.js";
|
|
5
|
+
import { printDoctorReport, printStatusReport } from "../utils/diagnostics-render.utils.js";
|
|
6
|
+
import { APP_NAME, getConfigPath, getWorkspacePath, hasSecretRef, loadConfig, resolveAppLogPath } from "@nextclaw/core";
|
|
7
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
8
|
+
import { createServer } from "node:net";
|
|
9
|
+
import { listBuiltinProviders } from "@nextclaw/runtime";
|
|
10
|
+
//#region src/cli/commands/diagnostics/services/diagnostics-commands.service.ts
|
|
11
|
+
var DiagnosticsCommands = class {
|
|
12
|
+
constructor(deps) {
|
|
13
|
+
this.deps = deps;
|
|
14
|
+
}
|
|
15
|
+
status = async (opts = {}) => {
|
|
16
|
+
const report = await this.collectRuntimeStatus({
|
|
17
|
+
verbose: Boolean(opts.verbose),
|
|
18
|
+
fix: Boolean(opts.fix)
|
|
19
|
+
});
|
|
20
|
+
if (opts.json) {
|
|
21
|
+
console.log(JSON.stringify(report, null, 2));
|
|
22
|
+
process.exitCode = 0;
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
printStatusReport({
|
|
26
|
+
logo: this.deps.logo,
|
|
27
|
+
report,
|
|
28
|
+
verbose: Boolean(opts.verbose)
|
|
29
|
+
});
|
|
30
|
+
process.exitCode = 0;
|
|
31
|
+
};
|
|
32
|
+
doctor = async (opts = {}) => {
|
|
33
|
+
const report = await this.collectRuntimeStatus({
|
|
34
|
+
verbose: Boolean(opts.verbose),
|
|
35
|
+
fix: Boolean(opts.fix)
|
|
36
|
+
});
|
|
37
|
+
const checkPort = await this.checkPortAvailability(this.resolveDoctorPortCheckTarget(report));
|
|
38
|
+
const checks = this.buildDoctorChecks(report, checkPort);
|
|
39
|
+
const exitCode = this.resolveDoctorExitCode(checks);
|
|
40
|
+
if (opts.json) {
|
|
41
|
+
console.log(JSON.stringify({
|
|
42
|
+
generatedAt: report.generatedAt,
|
|
43
|
+
checks,
|
|
44
|
+
status: report,
|
|
45
|
+
exitCode
|
|
46
|
+
}, null, 2));
|
|
47
|
+
process.exitCode = exitCode;
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
printDoctorReport({
|
|
51
|
+
logo: this.deps.logo,
|
|
52
|
+
generatedAt: report.generatedAt,
|
|
53
|
+
checks,
|
|
54
|
+
recommendations: report.recommendations,
|
|
55
|
+
verbose: Boolean(opts.verbose),
|
|
56
|
+
logTail: report.logTail
|
|
57
|
+
});
|
|
58
|
+
process.exitCode = exitCode;
|
|
59
|
+
};
|
|
60
|
+
resolveDoctorPortCheckTarget = (report) => {
|
|
61
|
+
const host = report.process.running && report.endpoints.uiUrl ? new URL(report.endpoints.uiUrl).hostname : "127.0.0.1";
|
|
62
|
+
try {
|
|
63
|
+
const base = report.process.running && report.endpoints.uiUrl ? report.endpoints.uiUrl : report.endpoints.configuredUiUrl;
|
|
64
|
+
return {
|
|
65
|
+
host,
|
|
66
|
+
port: Number(new URL(base).port || 80)
|
|
67
|
+
};
|
|
68
|
+
} catch {
|
|
69
|
+
return {
|
|
70
|
+
host,
|
|
71
|
+
port: 55667
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
buildDoctorChecks = (report, checkPort) => {
|
|
76
|
+
const providerConfigured = report.providers.some((provider) => provider.configured);
|
|
77
|
+
return [
|
|
78
|
+
{
|
|
79
|
+
name: "config-file",
|
|
80
|
+
status: report.configExists ? "pass" : "fail",
|
|
81
|
+
detail: report.configPath
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
name: "workspace-dir",
|
|
85
|
+
status: report.workspaceExists ? "pass" : "warn",
|
|
86
|
+
detail: report.workspacePath
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
name: "service-state",
|
|
90
|
+
status: report.process.staleState ? "fail" : report.process.running ? "pass" : "warn",
|
|
91
|
+
detail: report.process.running ? `PID ${report.process.pid}` : report.process.staleState ? "state exists but process is not running" : "service not running"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: "service-health",
|
|
95
|
+
status: report.process.running ? report.health.managed.state === "ok" ? "pass" : "fail" : "warn",
|
|
96
|
+
detail: report.process.running ? `${report.health.managed.state}: ${report.health.managed.detail}` : `${report.health.configured.state}: ${report.health.configured.detail}`
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: "ui-port-availability",
|
|
100
|
+
status: report.process.running || checkPort.available ? "pass" : "fail",
|
|
101
|
+
detail: report.process.running ? "managed by running service" : checkPort.available ? "available" : checkPort.detail
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
name: "provider-config",
|
|
105
|
+
status: providerConfigured ? "pass" : "warn",
|
|
106
|
+
detail: providerConfigured ? "at least one provider configured" : "no provider api key configured"
|
|
107
|
+
}
|
|
108
|
+
];
|
|
109
|
+
};
|
|
110
|
+
resolveDoctorExitCode = (checks) => {
|
|
111
|
+
if (checks.some((check) => check.status === "fail")) return 1;
|
|
112
|
+
if (checks.some((check) => check.status === "warn")) return 1;
|
|
113
|
+
return 0;
|
|
114
|
+
};
|
|
115
|
+
collectRuntimeStatus = async (params) => {
|
|
116
|
+
const configPath = getConfigPath();
|
|
117
|
+
const config = loadConfig();
|
|
118
|
+
const workspacePath = getWorkspacePath(config.agents.defaults.workspace);
|
|
119
|
+
const serviceStatePath = managedServiceStateStore.path;
|
|
120
|
+
const fixActions = [];
|
|
121
|
+
let serviceState = managedServiceStateStore.read();
|
|
122
|
+
if (params.fix && serviceState && !isProcessRunning(serviceState.pid)) {
|
|
123
|
+
managedServiceStateStore.clear();
|
|
124
|
+
fixActions.push("Cleared stale service state file.");
|
|
125
|
+
serviceState = managedServiceStateStore.read();
|
|
126
|
+
}
|
|
127
|
+
const managedByState = Boolean(serviceState);
|
|
128
|
+
const running = Boolean(serviceState && isProcessRunning(serviceState.pid));
|
|
129
|
+
const staleState = Boolean(serviceState && !running);
|
|
130
|
+
const configuredUi = resolveUiConfig(config, {
|
|
131
|
+
enabled: true,
|
|
132
|
+
host: config.ui.host,
|
|
133
|
+
port: config.ui.port
|
|
134
|
+
});
|
|
135
|
+
const configuredUiUrl = resolveUiApiBase(configuredUi.host, configuredUi.port);
|
|
136
|
+
const configuredApiUrl = `${configuredUiUrl}/api`;
|
|
137
|
+
const managedUiUrl = serviceState?.uiUrl ?? null;
|
|
138
|
+
const managedApiUrl = serviceState?.apiUrl ?? null;
|
|
139
|
+
const managedHealth = running && managedApiUrl ? await this.probeApiHealth(`${managedApiUrl}/health`) : {
|
|
140
|
+
state: "unreachable",
|
|
141
|
+
detail: "service not running"
|
|
142
|
+
};
|
|
143
|
+
const configuredHealth = await this.probeApiHealth(`${configuredApiUrl}/health`, 900);
|
|
144
|
+
const remote = resolveNextclawRemoteStatusSnapshot(config);
|
|
145
|
+
const orphanSuspected = !running && configuredHealth.state === "ok";
|
|
146
|
+
const providers = this.listProviderStatuses(config);
|
|
147
|
+
const issues = [];
|
|
148
|
+
const recommendations = [];
|
|
149
|
+
this.collectRuntimeIssues({
|
|
150
|
+
configPath,
|
|
151
|
+
workspacePath,
|
|
152
|
+
staleState,
|
|
153
|
+
running,
|
|
154
|
+
managedHealth,
|
|
155
|
+
serviceState,
|
|
156
|
+
orphanSuspected,
|
|
157
|
+
providers,
|
|
158
|
+
issues,
|
|
159
|
+
recommendations
|
|
160
|
+
});
|
|
161
|
+
const logTail = params.verbose ? this.readLogTail(serviceState?.logPath ?? resolveAppLogPath("service"), 25) : [];
|
|
162
|
+
const level = running ? managedHealth.state === "ok" ? issues.length > 0 ? "degraded" : "healthy" : "degraded" : "stopped";
|
|
163
|
+
return {
|
|
164
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
165
|
+
configPath,
|
|
166
|
+
configExists: existsSync(configPath),
|
|
167
|
+
workspacePath,
|
|
168
|
+
workspaceExists: existsSync(workspacePath),
|
|
169
|
+
model: config.agents.defaults.model,
|
|
170
|
+
providers,
|
|
171
|
+
serviceStatePath,
|
|
172
|
+
serviceStateExists: existsSync(serviceStatePath),
|
|
173
|
+
fixActions,
|
|
174
|
+
process: {
|
|
175
|
+
managedByState,
|
|
176
|
+
pid: serviceState?.pid ?? null,
|
|
177
|
+
running,
|
|
178
|
+
staleState,
|
|
179
|
+
orphanSuspected,
|
|
180
|
+
startedAt: serviceState?.startedAt ?? null
|
|
181
|
+
},
|
|
182
|
+
endpoints: {
|
|
183
|
+
uiUrl: managedUiUrl,
|
|
184
|
+
apiUrl: managedApiUrl,
|
|
185
|
+
configuredUiUrl,
|
|
186
|
+
configuredApiUrl
|
|
187
|
+
},
|
|
188
|
+
health: {
|
|
189
|
+
managed: managedHealth,
|
|
190
|
+
configured: configuredHealth
|
|
191
|
+
},
|
|
192
|
+
issues,
|
|
193
|
+
recommendations,
|
|
194
|
+
logTail,
|
|
195
|
+
remote,
|
|
196
|
+
level,
|
|
197
|
+
exitCode: 0
|
|
198
|
+
};
|
|
199
|
+
};
|
|
200
|
+
probeApiHealth = async (url, timeoutMs = 1500) => {
|
|
201
|
+
const controller = new AbortController();
|
|
202
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
203
|
+
try {
|
|
204
|
+
const response = await fetch(url, {
|
|
205
|
+
method: "GET",
|
|
206
|
+
signal: controller.signal
|
|
207
|
+
});
|
|
208
|
+
if (!response.ok) return {
|
|
209
|
+
state: "invalid-response",
|
|
210
|
+
detail: `HTTP ${response.status}`
|
|
211
|
+
};
|
|
212
|
+
const payload = await response.json();
|
|
213
|
+
if (payload?.ok === true && payload?.data?.status === "ok") return {
|
|
214
|
+
state: "ok",
|
|
215
|
+
detail: "health endpoint returned ok",
|
|
216
|
+
payload
|
|
217
|
+
};
|
|
218
|
+
return {
|
|
219
|
+
state: "invalid-response",
|
|
220
|
+
detail: "unexpected health payload",
|
|
221
|
+
payload
|
|
222
|
+
};
|
|
223
|
+
} catch (error) {
|
|
224
|
+
return {
|
|
225
|
+
state: "unreachable",
|
|
226
|
+
detail: String(error)
|
|
227
|
+
};
|
|
228
|
+
} finally {
|
|
229
|
+
clearTimeout(timer);
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
listProviderStatuses = (config) => {
|
|
233
|
+
return listBuiltinProviders().map((spec) => {
|
|
234
|
+
const provider = config.providers[spec.name];
|
|
235
|
+
const apiKeyRefSet = hasSecretRef(config, `providers.${spec.name}.apiKey`);
|
|
236
|
+
if (!provider) return {
|
|
237
|
+
name: spec.displayName ?? spec.name,
|
|
238
|
+
configured: false,
|
|
239
|
+
detail: "missing config"
|
|
240
|
+
};
|
|
241
|
+
if (provider.enabled === false) return {
|
|
242
|
+
name: spec.displayName ?? spec.name,
|
|
243
|
+
configured: false,
|
|
244
|
+
detail: "disabled"
|
|
245
|
+
};
|
|
246
|
+
if (spec.isLocal) return {
|
|
247
|
+
name: spec.displayName ?? spec.name,
|
|
248
|
+
configured: Boolean(provider.apiBase),
|
|
249
|
+
detail: provider.apiBase ? provider.apiBase : "apiBase not set"
|
|
250
|
+
};
|
|
251
|
+
return {
|
|
252
|
+
name: spec.displayName ?? spec.name,
|
|
253
|
+
configured: Boolean(provider.apiKey) || apiKeyRefSet,
|
|
254
|
+
detail: provider.apiKey ? "apiKey set" : apiKeyRefSet ? "apiKey ref set" : "apiKey not set"
|
|
255
|
+
};
|
|
256
|
+
});
|
|
257
|
+
};
|
|
258
|
+
collectRuntimeIssues = (params) => {
|
|
259
|
+
const { configPath, issues, managedHealth, orphanSuspected, providers, recommendations, running, serviceState, staleState, workspacePath } = params;
|
|
260
|
+
if (!existsSync(configPath)) {
|
|
261
|
+
issues.push("Config file is missing.");
|
|
262
|
+
recommendations.push(`Run ${APP_NAME} init to create config files.`);
|
|
263
|
+
}
|
|
264
|
+
if (!existsSync(workspacePath)) {
|
|
265
|
+
issues.push("Workspace directory does not exist.");
|
|
266
|
+
recommendations.push(`Run ${APP_NAME} init to create workspace templates.`);
|
|
267
|
+
}
|
|
268
|
+
if (staleState) {
|
|
269
|
+
issues.push("Service state is stale (state exists but process is not running).");
|
|
270
|
+
recommendations.push(`Run ${APP_NAME} status --fix to clean stale state.`);
|
|
271
|
+
}
|
|
272
|
+
if (running && managedHealth.state !== "ok") {
|
|
273
|
+
issues.push(`Managed service health check failed: ${managedHealth.detail}`);
|
|
274
|
+
recommendations.push(`Check logs at ${serviceState?.logPath ?? resolveAppLogPath("service")}.`);
|
|
275
|
+
}
|
|
276
|
+
if (running && serviceState?.startupState === "degraded" && managedHealth.state !== "ok") {
|
|
277
|
+
const startupHint = serviceState.startupLastProbeError ? ` (${serviceState.startupLastProbeError})` : "";
|
|
278
|
+
issues.push(`Service is in degraded startup state${startupHint}.`);
|
|
279
|
+
recommendations.push(`Wait and re-check ${APP_NAME} status; if it does not recover, inspect logs and restart.`);
|
|
280
|
+
}
|
|
281
|
+
if (!running) recommendations.push(`Run ${APP_NAME} start to launch the service.`);
|
|
282
|
+
if (orphanSuspected) {
|
|
283
|
+
issues.push("A service appears healthy on configured API endpoint, but state is missing/stale.");
|
|
284
|
+
recommendations.push("Another process may be occupying the UI port; stop it or use --ui-port with a free port.");
|
|
285
|
+
}
|
|
286
|
+
if (!providers.some((provider) => provider.configured)) recommendations.push("Configure at least one provider API key in UI or config before expecting agent replies.");
|
|
287
|
+
};
|
|
288
|
+
readLogTail = (path, maxLines = 25) => {
|
|
289
|
+
if (!existsSync(path)) return [];
|
|
290
|
+
try {
|
|
291
|
+
const lines = readFileSync(path, "utf-8").split(/\r?\n/).filter(Boolean);
|
|
292
|
+
if (lines.length <= maxLines) return lines;
|
|
293
|
+
return lines.slice(lines.length - maxLines);
|
|
294
|
+
} catch {
|
|
295
|
+
return [];
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
checkPortAvailability = async (params) => {
|
|
299
|
+
return await new Promise((resolve) => {
|
|
300
|
+
const server = createServer();
|
|
301
|
+
server.once("error", (error) => {
|
|
302
|
+
resolve({
|
|
303
|
+
available: false,
|
|
304
|
+
detail: `bind failed on ${params.host}:${params.port} (${String(error)})`
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
server.listen(params.port, params.host, () => {
|
|
308
|
+
server.close(() => {
|
|
309
|
+
resolve({
|
|
310
|
+
available: true,
|
|
311
|
+
detail: `bind ok on ${params.host}:${params.port}`
|
|
312
|
+
});
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
});
|
|
316
|
+
};
|
|
317
|
+
};
|
|
318
|
+
//#endregion
|
|
319
|
+
export { DiagnosticsCommands };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { RuntimeStatusReport } from "../../../../shared/types/cli.types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/cli/commands/diagnostics/utils/diagnostics-render.utils.d.ts
|
|
4
|
+
type DoctorCheck = {
|
|
5
|
+
name: string;
|
|
6
|
+
status: "pass" | "warn" | "fail";
|
|
7
|
+
detail: string;
|
|
8
|
+
};
|
|
9
|
+
declare function printStatusReport(params: {
|
|
10
|
+
logo: string;
|
|
11
|
+
report: RuntimeStatusReport;
|
|
12
|
+
verbose: boolean;
|
|
13
|
+
}): void;
|
|
14
|
+
declare function printDoctorReport(params: {
|
|
15
|
+
logo: string;
|
|
16
|
+
generatedAt: string;
|
|
17
|
+
checks: DoctorCheck[];
|
|
18
|
+
recommendations: string[];
|
|
19
|
+
verbose: boolean;
|
|
20
|
+
logTail: string[];
|
|
21
|
+
}): void;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { DoctorCheck, printDoctorReport, printStatusReport };
|