@gajae-code/coding-agent 0.16.7 → 0.17.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/CHANGELOG.md +180 -1
- package/dist/types/capability/fs.d.ts +37 -4
- package/dist/types/capability/index.d.ts +19 -0
- package/dist/types/capability/types.d.ts +9 -0
- package/dist/types/cli/doctor/args.d.ts +36 -0
- package/dist/types/cli/doctor/checks.d.ts +18 -0
- package/dist/types/cli/doctor/config-repairs.d.ts +38 -0
- package/dist/types/cli/doctor/context.d.ts +89 -0
- package/dist/types/cli/doctor/files.d.ts +27 -0
- package/dist/types/cli/doctor/ids.d.ts +20 -0
- package/dist/types/cli/doctor/install-repairs.d.ts +94 -0
- package/dist/types/cli/doctor/journal.d.ts +43 -0
- package/dist/types/cli/doctor/managed-link.d.ts +39 -0
- package/dist/types/cli/doctor/native-probe.d.ts +2 -0
- package/dist/types/cli/doctor/permission-repairs.d.ts +25 -0
- package/dist/types/cli/doctor/plugin-quarantine.d.ts +77 -0
- package/dist/types/cli/doctor/plugin-restore.d.ts +40 -0
- package/dist/types/cli/doctor/plugin-targets.d.ts +11 -0
- package/dist/types/cli/doctor/probe-client.d.ts +9 -0
- package/dist/types/cli/doctor/probe-types.d.ts +18 -0
- package/dist/types/cli/doctor/probe.d.ts +3 -0
- package/dist/types/cli/doctor/projection-probe.d.ts +2 -0
- package/dist/types/cli/doctor/repairs.d.ts +28 -0
- package/dist/types/cli/doctor/report.d.ts +27 -0
- package/dist/types/cli/doctor/runner.d.ts +4 -0
- package/dist/types/cli/doctor/safety.d.ts +10 -0
- package/dist/types/cli/doctor/service-repairs.d.ts +8 -0
- package/dist/types/cli/doctor/service-targets.d.ts +41 -0
- package/dist/types/cli/doctor/types.d.ts +145 -0
- package/dist/types/cli/doctor-cli.d.ts +7 -0
- package/dist/types/cli/doctor-supervisor.d.ts +121 -0
- package/dist/types/cli/doctor-worker.d.ts +29 -0
- package/dist/types/cli/install-activation.d.ts +158 -0
- package/dist/types/cli/macos-community-app.d.ts +41 -0
- package/dist/types/cli/mcp-cli.d.ts +0 -11
- package/dist/types/cli/update-cli.d.ts +41 -4
- package/dist/types/cli-main.d.ts +174 -0
- package/dist/types/cli.d.ts +1 -171
- package/dist/types/commands/doctor.d.ts +7 -0
- package/dist/types/commands/sdk.d.ts +17 -8
- package/dist/types/config/autorouting-tier-map.d.ts +19 -0
- package/dist/types/config/file-lock.d.ts +27 -3
- package/dist/types/config/model-preset-registry.d.ts +1 -0
- package/dist/types/config/model-registry.d.ts +12 -5
- package/dist/types/config/model-resolver.d.ts +16 -3
- package/dist/types/config/models-config-schema.d.ts +2 -0
- package/dist/types/config/settings-schema.d.ts +1 -1
- package/dist/types/coordinator-mcp/question-gate-codec.d.ts +1 -1
- package/dist/types/coordinator-mcp/session-reaper.d.ts +15 -5
- package/dist/types/cursor.d.ts +9 -9
- package/dist/types/discovery/agents-md.d.ts +6 -1
- package/dist/types/discovery/helpers.d.ts +36 -7
- package/dist/types/discovery/index.d.ts +1 -1
- package/dist/types/discovery/mcp-json.d.ts +2 -0
- package/dist/types/extensibility/extensions/loader.d.ts +22 -1
- package/dist/types/extensibility/gjc-plugins/lifecycle.d.ts +14 -1
- package/dist/types/extensibility/gjc-plugins/paths.d.ts +2 -1
- package/dist/types/extensibility/gjc-plugins/types.d.ts +25 -0
- package/dist/types/extensibility/plugins/manager.d.ts +33 -4
- package/dist/types/extensibility/plugins/marketplace/cache.d.ts +6 -0
- package/dist/types/extensibility/plugins/marketplace/manager.d.ts +186 -0
- package/dist/types/extensibility/plugins/marketplace/registry.d.ts +27 -0
- package/dist/types/extensibility/plugins/marketplace/source-resolver.d.ts +16 -1
- package/dist/types/extensibility/runtime-skill-discovery.d.ts +16 -3
- package/dist/types/gjc-runtime/autoresearch-runtime.d.ts +6 -0
- package/dist/types/gjc-runtime/launch-worktree.d.ts +53 -0
- package/dist/types/gjc-runtime/session-layout.d.ts +8 -0
- package/dist/types/gjc-runtime/session-state-lock.d.ts +15 -0
- package/dist/types/gjc-runtime/session-state-sidecar.d.ts +13 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +6 -0
- package/dist/types/main.d.ts +19 -1
- package/dist/types/modes/acp/acp-agent.d.ts +40 -0
- package/dist/types/modes/components/agent-dashboard.d.ts +1 -0
- package/dist/types/modes/components/model-selector.d.ts +2 -0
- package/dist/types/modes/interactive-mode.d.ts +1 -1
- package/dist/types/runtime-mcp/config-writer.d.ts +47 -0
- package/dist/types/runtime-mcp/policy-json-edit.d.ts +60 -0
- package/dist/types/runtime-mcp/startup-policy.d.ts +4 -0
- package/dist/types/runtime-mcp/types.d.ts +2 -2
- package/dist/types/sdk/acp/adapter.d.ts +5 -1
- package/dist/types/sdk/broker/broker.d.ts +51 -0
- package/dist/types/sdk/broker/daemon-entry.d.ts +39 -0
- package/dist/types/sdk/broker/discovery.d.ts +38 -0
- package/dist/types/sdk/broker/doctor-restart.d.ts +79 -0
- package/dist/types/sdk/broker/endpoint-authority.d.ts +7 -0
- package/dist/types/sdk/broker/ensure.d.ts +14 -0
- package/dist/types/sdk/broker/lifecycle.d.ts +2 -0
- package/dist/types/sdk/broker/process-incarnation.d.ts +50 -0
- package/dist/types/sdk/broker/runtime.d.ts +26 -0
- package/dist/types/sdk/broker/session-index.d.ts +13 -4
- package/dist/types/sdk/broker/worktree-occupancy.d.ts +14 -0
- package/dist/types/sdk/bus/chat-daemon-cli.d.ts +16 -0
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +101 -6
- package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +16 -0
- package/dist/types/sdk/bus/daemon-startup-exclusion.d.ts +43 -0
- package/dist/types/sdk/bus/doctor-daemon-restart-client.d.ts +51 -0
- package/dist/types/sdk/bus/doctor-daemon-restart.d.ts +39 -0
- package/dist/types/sdk/bus/index.d.ts +2 -0
- package/dist/types/sdk/bus/notification-service.d.ts +3 -0
- package/dist/types/sdk/bus/telegram-daemon-cli.d.ts +11 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +1 -1
- package/dist/types/sdk/bus/telegram-daemon-control.d.ts +5 -0
- package/dist/types/sdk/bus/telegram-daemon-owner-registry.d.ts +1 -0
- package/dist/types/sdk/bus/telegram-daemon.d.ts +36 -5
- package/dist/types/sdk/cli/session-cli.d.ts +1 -0
- package/dist/types/sdk/host/session-runtime.d.ts +4 -0
- package/dist/types/sdk/host/surface-policy.d.ts +3 -1
- package/dist/types/sdk/lifecycle/service.d.ts +44 -10
- package/dist/types/sdk/prompt-deadline-lease.d.ts +6 -3
- package/dist/types/sdk/prompt-deadline-manager.d.ts +2 -2
- package/dist/types/sdk/prompt-failure.d.ts +47 -0
- package/dist/types/sdk/prompt-status.d.ts +19 -0
- package/dist/types/sdk/router/session-router.d.ts +3 -4
- package/dist/types/sdk/service-artifact-paths.d.ts +16 -0
- package/dist/types/sdk/session-authority.d.ts +9 -0
- package/dist/types/sdk/session.d.ts +3 -1
- package/dist/types/session/agent-session.d.ts +1 -1
- package/dist/types/session/blob-store.d.ts +1 -1
- package/dist/types/session/fallback-chain-controller.d.ts +3 -6
- package/dist/types/session/internal/managed-session-scope.d.ts +44 -0
- package/dist/types/session/primary-control-surface.d.ts +4 -0
- package/dist/types/session/session-manager.d.ts +6 -0
- package/dist/types/system-prompt.d.ts +6 -0
- package/dist/types/tools/ask.d.ts +25 -0
- package/dist/types/tools/image-gen.d.ts +0 -4
- package/dist/types/tools/skill-discovery.d.ts +7 -5
- package/dist/types/tools/ultragoal-ask-guard.d.ts +7 -4
- package/dist/types/utils/changelog.d.ts +0 -9
- package/dist/types/utils/mupdf-wasm.d.ts +1 -0
- package/package.json +9 -8
- package/scripts/compile-args.ts +8 -4
- package/src/capability/fs.ts +395 -17
- package/src/capability/index.ts +273 -10
- package/src/capability/types.ts +9 -0
- package/src/cli/customize-doctor.ts +18 -12
- package/src/cli/doctor/args.ts +236 -0
- package/src/cli/doctor/checks.ts +431 -0
- package/src/cli/doctor/config-repairs.ts +517 -0
- package/src/cli/doctor/context.ts +149 -0
- package/src/cli/doctor/files.ts +149 -0
- package/src/cli/doctor/ids.ts +115 -0
- package/src/cli/doctor/install-repairs.ts +335 -0
- package/src/cli/doctor/journal.ts +423 -0
- package/src/cli/doctor/managed-link.ts +514 -0
- package/src/cli/doctor/native-probe.ts +13 -0
- package/src/cli/doctor/permission-repairs.ts +242 -0
- package/src/cli/doctor/plugin-quarantine.ts +377 -0
- package/src/cli/doctor/plugin-restore.ts +59 -0
- package/src/cli/doctor/plugin-targets.ts +373 -0
- package/src/cli/doctor/probe-client.ts +195 -0
- package/src/cli/doctor/probe-types.ts +21 -0
- package/src/cli/doctor/probe.ts +42 -0
- package/src/cli/doctor/projection-probe.ts +249 -0
- package/src/cli/doctor/repairs.ts +1157 -0
- package/src/cli/doctor/report.ts +176 -0
- package/src/cli/doctor/runner.ts +342 -0
- package/src/cli/doctor/safety.ts +40 -0
- package/src/cli/doctor/service-repairs.ts +452 -0
- package/src/cli/doctor/service-targets.ts +274 -0
- package/src/cli/doctor/types.ts +164 -0
- package/src/cli/doctor-cli.ts +62 -0
- package/src/cli/doctor-supervisor.ts +571 -0
- package/src/cli/doctor-worker.ts +181 -0
- package/src/cli/install-activation.ts +666 -0
- package/src/cli/macos-community-app.ts +1449 -0
- package/src/cli/mcp-cli.ts +11 -21
- package/src/cli/nofile-limit.ts +5 -1
- package/src/cli/plugin-cli.ts +6 -1
- package/src/cli/update-cli.ts +362 -264
- package/src/cli-main.ts +517 -0
- package/src/cli.ts +64 -433
- package/src/commands/autoresearch.ts +11 -5
- package/src/commands/completion.ts +1 -1
- package/src/commands/doctor.ts +13 -0
- package/src/commands/sdk.ts +58 -10
- package/src/commands/ultragoal.ts +11 -5
- package/src/config/autorouting-tier-map.ts +7 -0
- package/src/config/file-lock.ts +736 -71
- package/src/config/mcp-schema.json +3 -3
- package/src/config/model-preset-registry.ts +1 -0
- package/src/config/model-registry.ts +80 -27
- package/src/config/model-resolver.ts +33 -4
- package/src/config/models-config-schema.ts +2 -0
- package/src/config/settings-schema.ts +6 -2
- package/src/coordinator-mcp/question-gate-codec.ts +1 -0
- package/src/coordinator-mcp/server.ts +534 -51
- package/src/coordinator-mcp/session-reaper.ts +64 -8
- package/src/cursor.ts +223 -53
- package/src/discovery/agents-md.ts +74 -8
- package/src/discovery/agents.ts +32 -7
- package/src/discovery/builtin.ts +184 -75
- package/src/discovery/claude-plugins.ts +85 -17
- package/src/discovery/cline.ts +38 -10
- package/src/discovery/cursor.ts +19 -6
- package/src/discovery/gemini.ts +62 -22
- package/src/discovery/github.ts +13 -3
- package/src/discovery/helpers.ts +483 -89
- package/src/discovery/index.ts +1 -0
- package/src/discovery/mcp-json.ts +36 -10
- package/src/discovery/opencode.ts +36 -19
- package/src/discovery/ssh.ts +11 -8
- package/src/discovery/windsurf.ts +12 -3
- package/src/exec/bash-executor.ts +10 -3
- package/src/exec/isolated-shell.ts +15 -2
- package/src/extensibility/extensions/loader.ts +88 -26
- package/src/extensibility/gjc-plugins/lifecycle.ts +189 -0
- package/src/extensibility/gjc-plugins/paths.ts +4 -1
- package/src/extensibility/gjc-plugins/types.ts +27 -0
- package/src/extensibility/plugins/manager.ts +200 -22
- package/src/extensibility/plugins/marketplace/cache.ts +55 -2
- package/src/extensibility/plugins/marketplace/manager.ts +1262 -162
- package/src/extensibility/plugins/marketplace/registry.ts +153 -0
- package/src/extensibility/plugins/marketplace/source-resolver.ts +116 -10
- package/src/extensibility/runtime-skill-discovery.ts +61 -9
- package/src/extensibility/skill-management.ts +7 -1
- package/src/gjc-runtime/autoresearch-runtime.ts +10 -1
- package/src/gjc-runtime/launch-worktree.test.ts +248 -0
- package/src/gjc-runtime/launch-worktree.ts +275 -38
- package/src/gjc-runtime/repository-binding.ts +26 -1
- package/src/gjc-runtime/session-layout.ts +10 -0
- package/src/gjc-runtime/session-state-lock.ts +330 -23
- package/src/gjc-runtime/session-state-sidecar.ts +328 -80
- package/src/gjc-runtime/ultragoal-runtime.ts +10 -1
- package/src/harness-control-plane/session-lease.ts +2 -2
- package/src/internal-urls/docs-index.generated.ts +28 -26
- package/src/main.ts +150 -29
- package/src/memories/index.ts +24 -2
- package/src/modes/acp/acp-agent.ts +522 -68
- package/src/modes/components/agent-dashboard.ts +3 -1
- package/src/modes/components/model-selector.ts +28 -19
- package/src/modes/components/plugin-settings.ts +2 -1
- package/src/modes/controllers/selector-controller.ts +15 -9
- package/src/modes/interactive-mode.ts +21 -3
- package/src/prompts/system/system-prompt.md +5 -1
- package/src/prompts/tools/browser.md +1 -1
- package/src/prompts/tools/move-session.md +4 -0
- package/src/prompts/tools/read.md +2 -1
- package/src/prompts/tools/skill-discovery.md +6 -5
- package/src/prompts/tools/task.md +1 -0
- package/src/runtime-mcp/config-writer.ts +228 -0
- package/src/runtime-mcp/oauth-discovery.ts +114 -14
- package/src/runtime-mcp/policy-json-edit.ts +129 -0
- package/src/runtime-mcp/startup-policy.ts +14 -0
- package/src/runtime-mcp/types.ts +2 -2
- package/src/sdk/acp/adapter.ts +27 -12
- package/src/sdk/broker/broker.ts +273 -44
- package/src/sdk/broker/daemon-entry.ts +119 -0
- package/src/sdk/broker/discovery.ts +173 -20
- package/src/sdk/broker/doctor-restart.ts +206 -0
- package/src/sdk/broker/endpoint-authority.ts +36 -0
- package/src/sdk/broker/ensure.ts +49 -14
- package/src/sdk/broker/lifecycle.ts +174 -42
- package/src/sdk/broker/process-incarnation.ts +86 -2
- package/src/sdk/broker/runtime.ts +145 -21
- package/src/sdk/broker/session-index.ts +136 -22
- package/src/sdk/broker/spawn-substrate.ts +4 -1
- package/src/sdk/broker/transport.ts +5 -0
- package/src/sdk/broker/worktree-occupancy.ts +21 -1
- package/src/sdk/bus/chat-daemon-cli.ts +63 -0
- package/src/sdk/bus/chat-daemon-control.ts +260 -64
- package/src/sdk/bus/chat-daemon-runtime.ts +141 -25
- package/src/sdk/bus/daemon-startup-exclusion.ts +119 -0
- package/src/sdk/bus/doctor-daemon-restart-client.ts +291 -0
- package/src/sdk/bus/doctor-daemon-restart.ts +92 -0
- package/src/sdk/bus/index.ts +252 -51
- package/src/sdk/bus/kind-aware-reconciliation.ts +76 -41
- package/src/sdk/bus/notification-service.ts +21 -3
- package/src/sdk/bus/reconciliation-store.ts +17 -11
- package/src/sdk/bus/telegram-daemon-cli.ts +91 -5
- package/src/sdk/bus/telegram-daemon-contract.ts +1 -1
- package/src/sdk/bus/telegram-daemon-control.ts +47 -0
- package/src/sdk/bus/telegram-daemon-owner-registry.ts +1 -1
- package/src/sdk/bus/telegram-daemon.ts +178 -13
- package/src/sdk/cli/session-cli.ts +100 -12
- package/src/sdk/host/host.ts +2 -7
- package/src/sdk/host/session-runtime.test.ts +329 -8
- package/src/sdk/host/session-runtime.ts +202 -50
- package/src/sdk/host/surface-policy.ts +8 -1
- package/src/sdk/lifecycle/service.ts +199 -22
- package/src/sdk/mcp/server.ts +1 -1
- package/src/sdk/prompt-deadline-lease.ts +12 -4
- package/src/sdk/prompt-deadline-manager.ts +5 -7
- package/src/sdk/prompt-failure.ts +148 -0
- package/src/sdk/prompt-status.ts +30 -1
- package/src/sdk/prompt-watchdog.ts +11 -3
- package/src/sdk/protocol/operation-inventory.generated.json +18 -0
- package/src/sdk/protocol/operation-registry.ts +20 -8
- package/src/sdk/router/session-router.ts +8 -3
- package/src/sdk/service-artifact-paths.ts +26 -0
- package/src/sdk/session-authority.ts +10 -0
- package/src/sdk/session.ts +361 -194
- package/src/session/agent-session.ts +398 -93
- package/src/session/blob-store.ts +9 -9
- package/src/session/fallback-chain-controller.ts +3 -7
- package/src/session/internal/managed-session-scope.ts +445 -29
- package/src/session/internal/managed-session-storage.ts +38 -6
- package/src/session/primary-control-surface.ts +12 -0
- package/src/session/session-manager.ts +11 -3
- package/src/session/session-storage.ts +1 -1
- package/src/session-import/codex.ts +6 -1
- package/src/session-import/redact.ts +7 -0
- package/src/skill-state/workflow-mutation-guard.ts +645 -39
- package/src/slash-commands/builtin-registry.ts +7 -3
- package/src/system-prompt.ts +8 -0
- package/src/task/executor.ts +36 -3
- package/src/task/types.ts +27 -5
- package/src/tools/ask.ts +114 -34
- package/src/tools/browser/actions.ts +2 -2
- package/src/tools/browser/tab-worker.ts +11 -8
- package/src/tools/descriptors.ts +6 -1
- package/src/tools/fetch.ts +7 -2
- package/src/tools/image-gen.ts +33 -34
- package/src/tools/read.ts +78 -32
- package/src/tools/skill-discovery.ts +17 -7
- package/src/tools/tool-catalog.generated.ts +8 -8
- package/src/tools/ultragoal-ask-guard.ts +16 -26
- package/src/utils/changelog.ts +7 -1
- package/src/utils/git.ts +3 -1
- package/src/utils/markit.ts +24 -2
- package/src/utils/mupdf-wasm.ts +26 -0
- package/src/web/search/providers/openai-compatible.ts +191 -14
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import { type BigIntStats, constants } from "node:fs";
|
|
2
|
+
import * as fs from "node:fs/promises";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import type { NativeExactFileIdentity } from "@gajae-code/natives";
|
|
5
|
+
import { daemonPaths, telegramDaemonOwnerMarkerPath } from "../../sdk/bus/daemon-paths";
|
|
6
|
+
import {
|
|
7
|
+
BROKER_ARTIFACT_PATHS,
|
|
8
|
+
CHAT_DAEMON_DIRECTORY,
|
|
9
|
+
CHAT_DAEMON_FILES,
|
|
10
|
+
DOCTOR_RESTART_CONTROL_FILE,
|
|
11
|
+
} from "../../sdk/service-artifact-paths";
|
|
12
|
+
import { doctorCheck } from "./checks";
|
|
13
|
+
import type { DoctorContext } from "./context";
|
|
14
|
+
import { type DoctorFileObservation, doctorErrno, doctorMapping, readDoctorFile } from "./files";
|
|
15
|
+
import { artifactTargetId, serviceTargetId } from "./ids";
|
|
16
|
+
import type { DoctorCheck } from "./types";
|
|
17
|
+
|
|
18
|
+
export const DOCTOR_SERVICES = ["broker", "telegram", "discord", "slack"] as const;
|
|
19
|
+
export type DoctorServiceKind = (typeof DOCTOR_SERVICES)[number];
|
|
20
|
+
export type DoctorArtifactSlot = "discovery" | "owner-lock" | "startup-marker";
|
|
21
|
+
|
|
22
|
+
export interface DoctorServicePaths {
|
|
23
|
+
readonly state: string;
|
|
24
|
+
readonly owner: string;
|
|
25
|
+
readonly restartIntent: string;
|
|
26
|
+
readonly directoryOwner?: string;
|
|
27
|
+
readonly startupMarker?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface DoctorDirectoryObservation {
|
|
31
|
+
readonly status: "directory";
|
|
32
|
+
readonly mode: number;
|
|
33
|
+
readonly owner: number;
|
|
34
|
+
readonly exactIdentity: NativeExactFileIdentity;
|
|
35
|
+
}
|
|
36
|
+
export type DoctorArtifactObservation = DoctorFileObservation | DoctorDirectoryObservation;
|
|
37
|
+
|
|
38
|
+
export interface DoctorServiceObservation {
|
|
39
|
+
readonly service: DoctorServiceKind;
|
|
40
|
+
readonly paths: DoctorServicePaths;
|
|
41
|
+
readonly state: DoctorFileObservation;
|
|
42
|
+
readonly owner: DoctorFileObservation;
|
|
43
|
+
readonly restartIntent: DoctorFileObservation;
|
|
44
|
+
readonly directoryOwner?: DoctorArtifactObservation;
|
|
45
|
+
readonly startupMarker?: DoctorFileObservation;
|
|
46
|
+
readonly ownerMarker?: { readonly path: string; readonly observation: DoctorFileObservation };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Only product-defined paths are addressable; record content never supplies a path. */
|
|
50
|
+
export function doctorServicePaths(agentDir: string, service: DoctorServiceKind): DoctorServicePaths {
|
|
51
|
+
if (service === "broker")
|
|
52
|
+
return {
|
|
53
|
+
state: path.join(agentDir, BROKER_ARTIFACT_PATHS.discovery),
|
|
54
|
+
owner: path.join(agentDir, BROKER_ARTIFACT_PATHS.ownerRecord),
|
|
55
|
+
restartIntent: path.join(agentDir, BROKER_ARTIFACT_PATHS.restartIntent),
|
|
56
|
+
directoryOwner: path.join(agentDir, BROKER_ARTIFACT_PATHS.ownerLock),
|
|
57
|
+
};
|
|
58
|
+
if (service === "telegram") {
|
|
59
|
+
const paths = daemonPaths(agentDir);
|
|
60
|
+
return {
|
|
61
|
+
state: paths.state,
|
|
62
|
+
owner: paths.lock,
|
|
63
|
+
startupMarker: paths.steal,
|
|
64
|
+
restartIntent: path.join(paths.dir, DOCTOR_RESTART_CONTROL_FILE),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
const directory = path.join(agentDir, CHAT_DAEMON_DIRECTORY, service);
|
|
68
|
+
return {
|
|
69
|
+
state: path.join(directory, CHAT_DAEMON_FILES.state),
|
|
70
|
+
owner: path.join(directory, CHAT_DAEMON_FILES.ownerLock),
|
|
71
|
+
restartIntent: path.join(directory, DOCTOR_RESTART_CONTROL_FILE),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async function checkParents(root: string, file: string): Promise<DoctorFileObservation | undefined> {
|
|
76
|
+
const relative = path.relative(root, file);
|
|
77
|
+
if (relative === "" || path.isAbsolute(relative) || relative.split(path.sep).includes(".."))
|
|
78
|
+
return { status: "unreadable", errno: "EINVAL" };
|
|
79
|
+
let current = root;
|
|
80
|
+
try {
|
|
81
|
+
for (const component of ["", ...relative.split(path.sep).slice(0, -1)]) {
|
|
82
|
+
if (component) current = path.join(current, component);
|
|
83
|
+
const stat = await fs.lstat(current);
|
|
84
|
+
if (stat.isSymbolicLink()) return { status: "symlink" };
|
|
85
|
+
if (!stat.isDirectory()) return { status: "unreadable", errno: "ENOTDIR" };
|
|
86
|
+
}
|
|
87
|
+
return undefined;
|
|
88
|
+
} catch (error) {
|
|
89
|
+
const errno = doctorErrno(error);
|
|
90
|
+
return { status: errno === "ENOENT" ? "missing" : "unreadable", errno };
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function readServiceFile(root: string, file: string): Promise<DoctorFileObservation> {
|
|
95
|
+
return (await checkParents(root, file)) ?? (await readDoctorFile(file, 128 * 1024));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function sameDirectory(left: BigIntStats, right: BigIntStats): boolean {
|
|
99
|
+
return (
|
|
100
|
+
right.isDirectory() &&
|
|
101
|
+
!right.isSymbolicLink() &&
|
|
102
|
+
left.dev === right.dev &&
|
|
103
|
+
left.ino === right.ino &&
|
|
104
|
+
left.mode === right.mode &&
|
|
105
|
+
left.uid === right.uid &&
|
|
106
|
+
left.nlink === right.nlink &&
|
|
107
|
+
left.size === right.size &&
|
|
108
|
+
left.mtimeNs === right.mtimeNs &&
|
|
109
|
+
left.ctimeNs === right.ctimeNs
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async function readServiceDirectory(root: string, directory: string): Promise<DoctorArtifactObservation> {
|
|
114
|
+
const failure = await checkParents(root, directory);
|
|
115
|
+
if (failure) return failure;
|
|
116
|
+
let handle: fs.FileHandle | undefined;
|
|
117
|
+
try {
|
|
118
|
+
const before = await fs.lstat(directory, { bigint: true });
|
|
119
|
+
if (before.isSymbolicLink()) return { status: "symlink" };
|
|
120
|
+
if (!before.isDirectory()) return { status: "not_regular" };
|
|
121
|
+
handle = await fs.open(
|
|
122
|
+
directory,
|
|
123
|
+
constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW | constants.O_NONBLOCK,
|
|
124
|
+
);
|
|
125
|
+
const opened = await handle.stat({ bigint: true });
|
|
126
|
+
const parent = await fs.lstat(path.dirname(directory), { bigint: true });
|
|
127
|
+
const after = await handle.stat({ bigint: true });
|
|
128
|
+
const lexical = await fs.lstat(directory, { bigint: true });
|
|
129
|
+
const parentAfter = await fs.lstat(path.dirname(directory), { bigint: true });
|
|
130
|
+
if (
|
|
131
|
+
!sameDirectory(before, opened) ||
|
|
132
|
+
!sameDirectory(opened, after) ||
|
|
133
|
+
!sameDirectory(after, lexical) ||
|
|
134
|
+
parent.isSymbolicLink() ||
|
|
135
|
+
parentAfter.isSymbolicLink() ||
|
|
136
|
+
!parent.isDirectory() ||
|
|
137
|
+
parent.dev !== parentAfter.dev ||
|
|
138
|
+
parent.ino !== parentAfter.ino
|
|
139
|
+
)
|
|
140
|
+
return { status: "changed" };
|
|
141
|
+
return {
|
|
142
|
+
status: "directory",
|
|
143
|
+
mode: Number(after.mode),
|
|
144
|
+
owner: Number(after.uid),
|
|
145
|
+
exactIdentity: {
|
|
146
|
+
dev: after.dev,
|
|
147
|
+
ino: after.ino,
|
|
148
|
+
nlink: after.nlink,
|
|
149
|
+
size: after.size,
|
|
150
|
+
mtimeNs: after.mtimeNs,
|
|
151
|
+
parentDev: parent.dev,
|
|
152
|
+
parentIno: parent.ino,
|
|
153
|
+
directory: true,
|
|
154
|
+
detachOnly: true,
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
} catch (error) {
|
|
158
|
+
const errno = doctorErrno(error);
|
|
159
|
+
return { status: errno === "ENOENT" ? "missing" : "unreadable", errno };
|
|
160
|
+
} finally {
|
|
161
|
+
await handle?.close();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export function parseServiceRecord(observation: DoctorFileObservation): Record<string, unknown> | undefined {
|
|
166
|
+
if (observation.status !== "read") return undefined;
|
|
167
|
+
try {
|
|
168
|
+
return doctorMapping(JSON.parse(observation.text));
|
|
169
|
+
} catch {
|
|
170
|
+
return undefined;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export async function readDoctorService(root: string, service: DoctorServiceKind): Promise<DoctorServiceObservation> {
|
|
175
|
+
const paths = doctorServicePaths(root, service);
|
|
176
|
+
const [state, owner, directoryOwner, startupMarker, restartIntent] = await Promise.all([
|
|
177
|
+
readServiceFile(root, paths.state),
|
|
178
|
+
readServiceFile(root, paths.owner),
|
|
179
|
+
paths.directoryOwner ? readServiceDirectory(root, paths.directoryOwner) : undefined,
|
|
180
|
+
paths.startupMarker ? readServiceFile(root, paths.startupMarker) : undefined,
|
|
181
|
+
readServiceFile(root, paths.restartIntent),
|
|
182
|
+
]);
|
|
183
|
+
let ownerMarker: DoctorServiceObservation["ownerMarker"];
|
|
184
|
+
if (service === "telegram") {
|
|
185
|
+
const record = parseServiceRecord(state) ?? parseServiceRecord(owner);
|
|
186
|
+
const acquisitionId = record?.acquisitionId;
|
|
187
|
+
if (typeof acquisitionId === "string" && /^[A-Za-z0-9_-]{1,128}$/.test(acquisitionId)) {
|
|
188
|
+
const marker = telegramDaemonOwnerMarkerPath(root, acquisitionId);
|
|
189
|
+
ownerMarker = { path: marker, observation: await readServiceFile(root, marker) };
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return { service, paths, state, owner, directoryOwner, startupMarker, ownerMarker, restartIntent };
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export function serviceArtifactObservation(
|
|
196
|
+
service: DoctorServiceObservation,
|
|
197
|
+
slot: DoctorArtifactSlot,
|
|
198
|
+
): DoctorArtifactObservation | undefined {
|
|
199
|
+
if (slot === "discovery") return service.state;
|
|
200
|
+
if (slot === "owner-lock") return service.directoryOwner ?? service.owner;
|
|
201
|
+
return service.startupMarker;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** Metadata only: no service import, connection, process probe, or ownership acquisition. */
|
|
205
|
+
export async function collectServiceTargets(context: DoctorContext): Promise<DoctorCheck[]> {
|
|
206
|
+
const checks: DoctorCheck[] = [];
|
|
207
|
+
for (const service of DOCTOR_SERVICES) {
|
|
208
|
+
const observation = await readDoctorService(context.agentRoot.locator, service);
|
|
209
|
+
const targetId = serviceTargetId(context.agentRoot.rootId, service);
|
|
210
|
+
context.targets.set(targetId, { kind: "service", targetId, service, root: context.agentRoot, observation });
|
|
211
|
+
for (const slot of ["discovery", "owner-lock", "startup-marker"] as const) {
|
|
212
|
+
const artifactId = artifactTargetId(context.agentRoot.rootId, service, slot);
|
|
213
|
+
context.targets.set(artifactId, {
|
|
214
|
+
kind: "artifact",
|
|
215
|
+
targetId: artifactId,
|
|
216
|
+
service,
|
|
217
|
+
slot,
|
|
218
|
+
root: context.agentRoot,
|
|
219
|
+
observation,
|
|
220
|
+
});
|
|
221
|
+
const artifact = serviceArtifactObservation(observation, slot);
|
|
222
|
+
if (!artifact) continue;
|
|
223
|
+
const present = artifact.status === "read" || artifact.status === "directory";
|
|
224
|
+
const malformed = artifact.status === "read" && !parseServiceRecord(artifact);
|
|
225
|
+
checks.push(
|
|
226
|
+
doctorCheck(`service.${service}.${slot}`, artifactId, {
|
|
227
|
+
execution: present || artifact.status === "missing" ? "completed" : "blocked",
|
|
228
|
+
health: malformed
|
|
229
|
+
? "error"
|
|
230
|
+
: present
|
|
231
|
+
? "ok"
|
|
232
|
+
: artifact.status === "missing"
|
|
233
|
+
? "not_applicable"
|
|
234
|
+
: "unknown",
|
|
235
|
+
evidenceLevel: "observed",
|
|
236
|
+
reasonCode: malformed
|
|
237
|
+
? "service_metadata_invalid"
|
|
238
|
+
: present
|
|
239
|
+
? "service_artifact_present"
|
|
240
|
+
: `service_artifact_${artifact.status}`,
|
|
241
|
+
evidence: {
|
|
242
|
+
present,
|
|
243
|
+
runtimeProbed: false,
|
|
244
|
+
authenticationProbed: false,
|
|
245
|
+
...(artifact.status === "directory" ? { fileKind: "directory", mode: artifact.mode & 0o777 } : {}),
|
|
246
|
+
...("errno" in artifact ? { errno: artifact.errno } : {}),
|
|
247
|
+
},
|
|
248
|
+
remediationIds: present ? ["service.detach-owned-stale-artifact"] : [],
|
|
249
|
+
}),
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
checks.push(
|
|
253
|
+
doctorCheck(`service.${service}.owner`, targetId, {
|
|
254
|
+
execution:
|
|
255
|
+
observation.state.status === "read" || observation.state.status === "missing" ? "completed" : "blocked",
|
|
256
|
+
health:
|
|
257
|
+
observation.state.status === "missing"
|
|
258
|
+
? "not_applicable"
|
|
259
|
+
: observation.state.status === "read"
|
|
260
|
+
? "ok"
|
|
261
|
+
: "unknown",
|
|
262
|
+
evidenceLevel: "observed",
|
|
263
|
+
reasonCode: "service_metadata_only",
|
|
264
|
+
evidence: {
|
|
265
|
+
present: observation.state.status === "read",
|
|
266
|
+
runtimeProbed: false,
|
|
267
|
+
authenticationProbed: false,
|
|
268
|
+
},
|
|
269
|
+
remediationIds: observation.state.status === "read" ? ["service.restart-owned"] : [],
|
|
270
|
+
}),
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
return checks;
|
|
274
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
export type DoctorMode = "diagnose" | "dry-run" | "fix";
|
|
2
|
+
/**
|
|
3
|
+
* `unsupported` and `not_selected` are the coverage vocabulary this process
|
|
4
|
+
* accepts across the worker/probe boundary and reports in `DoctorCoverage`; the
|
|
5
|
+
* collectors on this platform never emit them, so their consumers are deliberate
|
|
6
|
+
* validation rather than reachable branches.
|
|
7
|
+
*/
|
|
8
|
+
export type CheckExecution = "completed" | "blocked" | "timeout" | "cancelled" | "unsupported" | "not_selected";
|
|
9
|
+
export type Health = "ok" | "warning" | "error" | "unknown" | "not_applicable";
|
|
10
|
+
export type EvidenceLevel = "observed" | "not_probed";
|
|
11
|
+
export type Verdict = "healthy" | "degraded" | "unhealthy" | "inconclusive";
|
|
12
|
+
export type RepairState =
|
|
13
|
+
| "planned"
|
|
14
|
+
| "blocked"
|
|
15
|
+
| "not_needed"
|
|
16
|
+
// Transient base value only: every construction site overrides it before the
|
|
17
|
+
// repair is returned, so it never reaches a report.
|
|
18
|
+
| "preparing"
|
|
19
|
+
| "pending_activation"
|
|
20
|
+
| "verified"
|
|
21
|
+
| "failed"
|
|
22
|
+
| "uncertain"
|
|
23
|
+
| "rolled_back"
|
|
24
|
+
| "rollback_conflict";
|
|
25
|
+
export type ReadinessFactCode =
|
|
26
|
+
| "authorization_missing"
|
|
27
|
+
| "confirmation_required"
|
|
28
|
+
| "candidate_unresolved"
|
|
29
|
+
| "pin_missing"
|
|
30
|
+
| "candidate_selection_missing"
|
|
31
|
+
| "identity_recheck_required"
|
|
32
|
+
| "target_resolution_incomplete"
|
|
33
|
+
| "unsupported";
|
|
34
|
+
export type DoctorScope = "user" | "project";
|
|
35
|
+
|
|
36
|
+
export type DoctorRiskClass =
|
|
37
|
+
| "config-change"
|
|
38
|
+
| "permission-change"
|
|
39
|
+
| "install-replace"
|
|
40
|
+
| "plugin-change"
|
|
41
|
+
| "service-interruption"
|
|
42
|
+
| "artifact-detach"
|
|
43
|
+
| "network"
|
|
44
|
+
| "external-execution";
|
|
45
|
+
export type JsonPrimitive = string | number | boolean | null;
|
|
46
|
+
export type JsonValue = JsonPrimitive | JsonValue[] | { readonly [key: string]: JsonValue };
|
|
47
|
+
|
|
48
|
+
export interface CheckEvidence {
|
|
49
|
+
readonly runtimeVersion?: string;
|
|
50
|
+
readonly platform?: string;
|
|
51
|
+
readonly arch?: string;
|
|
52
|
+
readonly channel?: string;
|
|
53
|
+
readonly schemaCoverage?: "selected_fields" | "complete";
|
|
54
|
+
readonly startupStatus?: "autoload" | "autoload-off" | "disabled";
|
|
55
|
+
readonly runtimeProbed?: boolean;
|
|
56
|
+
readonly aclCoverage?: "not_probed" | "verified";
|
|
57
|
+
readonly mode?: number;
|
|
58
|
+
readonly ownerMatches?: boolean;
|
|
59
|
+
readonly contentsRead?: boolean;
|
|
60
|
+
readonly authenticationProbed?: boolean;
|
|
61
|
+
readonly present?: boolean;
|
|
62
|
+
readonly enabled?: boolean;
|
|
63
|
+
readonly autoload?: boolean;
|
|
64
|
+
readonly hasAuth?: boolean;
|
|
65
|
+
readonly status?: string;
|
|
66
|
+
readonly sourceClass?: string;
|
|
67
|
+
/** Closed observation of a known plugin artifact; never a path or content. */
|
|
68
|
+
readonly artifactStatus?: "present" | "absent" | "unreadable";
|
|
69
|
+
readonly transport?: "stdio" | "http" | "sse" | "unknown";
|
|
70
|
+
readonly count?: number;
|
|
71
|
+
readonly warningCount?: number;
|
|
72
|
+
readonly counts?: Readonly<Record<string, number>>;
|
|
73
|
+
readonly errno?: string;
|
|
74
|
+
readonly fileKind?: string;
|
|
75
|
+
readonly schemaLocation?: string;
|
|
76
|
+
readonly version?: string;
|
|
77
|
+
readonly integrityResult?: string;
|
|
78
|
+
readonly processObservation?: JsonValue;
|
|
79
|
+
readonly generation?: string;
|
|
80
|
+
readonly occupancy?: string;
|
|
81
|
+
readonly readiness?: readonly ReadinessFactCode[];
|
|
82
|
+
readonly rootId?: string;
|
|
83
|
+
readonly safeLabel?: string;
|
|
84
|
+
readonly candidateCount?: number;
|
|
85
|
+
}
|
|
86
|
+
export interface DoctorCheck {
|
|
87
|
+
readonly id: string;
|
|
88
|
+
readonly targetId: string;
|
|
89
|
+
readonly scope?: DoctorScope;
|
|
90
|
+
readonly execution: CheckExecution;
|
|
91
|
+
readonly health: Health;
|
|
92
|
+
readonly reasonCode?: string;
|
|
93
|
+
readonly evidenceLevel: EvidenceLevel;
|
|
94
|
+
readonly observedAt?: string;
|
|
95
|
+
readonly durationMs?: number;
|
|
96
|
+
readonly dependsOn: readonly string[];
|
|
97
|
+
readonly evidence: CheckEvidence;
|
|
98
|
+
readonly remediationIds: readonly string[];
|
|
99
|
+
}
|
|
100
|
+
export interface RepairCandidate {
|
|
101
|
+
readonly id: string;
|
|
102
|
+
readonly sourceChannel: string;
|
|
103
|
+
readonly ref?: string;
|
|
104
|
+
readonly sha256?: string;
|
|
105
|
+
readonly evidence: CheckEvidence;
|
|
106
|
+
}
|
|
107
|
+
export interface DoctorRepair {
|
|
108
|
+
readonly id: string;
|
|
109
|
+
readonly targetId: string;
|
|
110
|
+
readonly riskClasses: readonly DoctorRiskClass[];
|
|
111
|
+
readonly authorization: readonly string[];
|
|
112
|
+
readonly readiness: readonly ReadinessFactCode[];
|
|
113
|
+
readonly sourceChannel?: string;
|
|
114
|
+
readonly candidates: readonly RepairCandidate[];
|
|
115
|
+
readonly selectedCandidate?: string;
|
|
116
|
+
readonly preconditions: readonly string[];
|
|
117
|
+
readonly rollbackClass?: string;
|
|
118
|
+
readonly state: RepairState;
|
|
119
|
+
readonly reasonCode?: string;
|
|
120
|
+
readonly sideEffectStarted?: boolean;
|
|
121
|
+
readonly outcome?: { readonly mutationVerified: boolean; readonly desiredStartupStateAchieved?: boolean };
|
|
122
|
+
readonly beforeCheckIds: readonly string[];
|
|
123
|
+
readonly afterCheckIds: readonly string[];
|
|
124
|
+
readonly restartRequired: boolean;
|
|
125
|
+
readonly restartScope?: "none" | "new-session" | "service";
|
|
126
|
+
readonly nonrollbackableEffects: readonly string[];
|
|
127
|
+
readonly activationRecordRef?: string;
|
|
128
|
+
}
|
|
129
|
+
export interface DoctorCoverage {
|
|
130
|
+
readonly requested: number;
|
|
131
|
+
readonly expanded: number;
|
|
132
|
+
readonly attempted: number;
|
|
133
|
+
readonly completed: number;
|
|
134
|
+
readonly blocked: number;
|
|
135
|
+
readonly timedOut: number;
|
|
136
|
+
readonly unsupported: number;
|
|
137
|
+
}
|
|
138
|
+
export interface DoctorSummary {
|
|
139
|
+
readonly verdict: Verdict;
|
|
140
|
+
readonly exitCode: number;
|
|
141
|
+
}
|
|
142
|
+
export interface DoctorReport {
|
|
143
|
+
readonly schemaVersion: 1;
|
|
144
|
+
readonly command: "doctor";
|
|
145
|
+
readonly runId: string;
|
|
146
|
+
readonly mode: DoctorMode;
|
|
147
|
+
readonly generatedAt: string;
|
|
148
|
+
readonly durationMs: number;
|
|
149
|
+
readonly subject: {
|
|
150
|
+
readonly gjcVersion: string;
|
|
151
|
+
readonly platform: string;
|
|
152
|
+
readonly arch: string;
|
|
153
|
+
readonly channel: string;
|
|
154
|
+
readonly scope?: DoctorScope;
|
|
155
|
+
readonly rootIds: readonly string[];
|
|
156
|
+
};
|
|
157
|
+
readonly selection: { readonly checks: readonly string[]; readonly repair?: string; readonly targetId?: string };
|
|
158
|
+
readonly coverage: DoctorCoverage;
|
|
159
|
+
readonly summary: DoctorSummary;
|
|
160
|
+
readonly checks: readonly DoctorCheck[];
|
|
161
|
+
readonly repairs: readonly DoctorRepair[];
|
|
162
|
+
readonly limits: { readonly [key: string]: JsonValue };
|
|
163
|
+
readonly invocationError?: string;
|
|
164
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { parseDoctorArgs } from "./doctor/args";
|
|
2
|
+
import { DOCTOR_EXIT_CODES, renderDoctorJson, renderDoctorText } from "./doctor/report";
|
|
3
|
+
import { runSupervisedDoctor } from "./doctor-supervisor";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Execute the boot-safe doctor parser and delegate collection to an owned,
|
|
7
|
+
* verified-terminated child worker (`doctor-supervisor.ts`). Diagnostics and
|
|
8
|
+
* repairs never run in this process: a `Promise.race` here cannot bound
|
|
9
|
+
* synchronous fs/native work, so only the child-process boundary can.
|
|
10
|
+
*/
|
|
11
|
+
export async function runDoctorCli(argv: readonly string[]): Promise<void> {
|
|
12
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
13
|
+
process.stdout.write(doctorHelp());
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const parsed = parseDoctorArgs(argv);
|
|
17
|
+
if (parsed.error || !parsed.options) {
|
|
18
|
+
const message = parsed.error ?? "invalid arguments";
|
|
19
|
+
if (argv.includes("--json"))
|
|
20
|
+
process.stdout.write(
|
|
21
|
+
`${JSON.stringify({
|
|
22
|
+
schemaVersion: 1,
|
|
23
|
+
command: "doctor",
|
|
24
|
+
error: { code: "invalid_arguments", message },
|
|
25
|
+
summary: { verdict: "inconclusive", exitCode: DOCTOR_EXIT_CODES.usage },
|
|
26
|
+
})}\n`,
|
|
27
|
+
);
|
|
28
|
+
else process.stderr.write(`gjc doctor: ${message}\n`);
|
|
29
|
+
process.exitCode = DOCTOR_EXIT_CODES.usage;
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
const report = await runSupervisedDoctor({
|
|
34
|
+
argv,
|
|
35
|
+
options: {
|
|
36
|
+
...parsed.options,
|
|
37
|
+
cwd: process.cwd(),
|
|
38
|
+
tty: Boolean(process.stdin.isTTY && process.stdout.isTTY),
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
process.stdout.write(parsed.options.json ? renderDoctorJson(report) : renderDoctorText(report));
|
|
42
|
+
process.exitCode = report.summary.exitCode;
|
|
43
|
+
} catch {
|
|
44
|
+
// The supervisor itself synthesizes bounded reports for every abnormal
|
|
45
|
+
// ending; reaching here means something outside its own contract threw
|
|
46
|
+
// (e.g. a module load failure), so degrade to the same sanitized envelope
|
|
47
|
+
// used elsewhere rather than surfacing a raw exception.
|
|
48
|
+
const envelope = {
|
|
49
|
+
schemaVersion: 1,
|
|
50
|
+
command: "doctor",
|
|
51
|
+
error: { code: "doctor_supervisor_failure", message: "Doctor diagnostics could not be completed." },
|
|
52
|
+
summary: { verdict: "inconclusive", exitCode: DOCTOR_EXIT_CODES.incomplete },
|
|
53
|
+
};
|
|
54
|
+
if (parsed.options.json) process.stdout.write(`${JSON.stringify(envelope)}\n`);
|
|
55
|
+
else process.stderr.write("gjc doctor: Doctor diagnostics could not be completed.\n");
|
|
56
|
+
process.exitCode = DOCTOR_EXIT_CODES.incomplete;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function doctorHelp(): string {
|
|
61
|
+
return `Usage: gjc doctor [options]\n\nRead-only bootstrap diagnostics and explicitly targeted repairs.\n\nOptions:\n --json Emit machine-readable JSON\n --fix --repair <action> Apply one approved repair action\n --dry-run Preview repair candidates without mutation\n --target <stable-id> Select the exact report target\n --check <id> Select a check (repeatable)\n --scope <user|project> Constrain target scope\n --set-value-json <true|false> Boolean value for config/MCP repairs\n --ref <candidate-ref> Select a repair candidate\n --sha256 <hex> Pin an artifact by digest\n --allow-risk <class> Approve a required risk class (repeatable)\n --yes Skip interactive confirmation\n --timeout-ms <n> Bound diagnostic work\n --drain Drain before service restart\n\nPlatform notes:\n Repairs fenced by the crash-recovery journal (config.set-validated,\n mcp.set-startup-policy, permissions.restrict-owned-config,\n install.repair-managed-link, plugin.quarantine-selected,\n service.detach-owned-stale-artifact) are unsupported on Windows in this\n release and are refused before any mutation. Diagnosis and --dry-run work\n on every platform.\n`;
|
|
62
|
+
}
|