cc-viewer 1.9.9 → 1.9.10
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 +1 -1
- package/cli.js +4 -3
- package/dist/assets/App-Ci9GYs24.js +2 -0
- package/dist/assets/{MdxEditorPanel-BJVD_bcU.js → MdxEditorPanel-8fwlNHMz.js} +1 -1
- package/dist/assets/Mobile-DngSOqYr.js +1 -0
- package/dist/assets/ProxyStatsModal-CWSIELLj.js +1 -0
- package/dist/assets/{_baseUniq-CwQykUuc.js → _baseUniq-6ZLcdMmL.js} +1 -1
- package/dist/assets/{arc-EdUdBxtG.js → arc-Dirf6EZP.js} +1 -1
- package/dist/assets/{architectureDiagram-Q4EWVU46-DtBIdElY.js → architectureDiagram-Q4EWVU46-BfIhmu_I.js} +1 -1
- package/dist/assets/{blockDiagram-DXYQGD6D-guNZIKkZ.js → blockDiagram-DXYQGD6D-D0y4ALi1.js} +1 -1
- package/dist/assets/{c4Diagram-AHTNJAMY-xV5vB-Z9.js → c4Diagram-AHTNJAMY-Dlfp4SUK.js} +1 -1
- package/dist/assets/{channel-DYEktNap.js → channel-CaNcU8SI.js} +1 -1
- package/dist/assets/{chunk-4BX2VUAB-ZTkItpvj.js → chunk-4BX2VUAB-ki0vHNS-.js} +1 -1
- package/dist/assets/{chunk-4TB4RGXK-dYIewyyR.js → chunk-4TB4RGXK-D8yO8Iuv.js} +1 -1
- package/dist/assets/{chunk-55IACEB6-CSsPNgPX.js → chunk-55IACEB6-BvIgaNPO.js} +1 -1
- package/dist/assets/{chunk-EDXVE4YY-CnMiuqzQ.js → chunk-EDXVE4YY-DF2Of_VO.js} +1 -1
- package/dist/assets/{chunk-FMBD7UC4-CVpATPZ3.js → chunk-FMBD7UC4-BIw7SXs-.js} +1 -1
- package/dist/assets/{chunk-OYMX7WX6-Dpq4s8dW.js → chunk-OYMX7WX6-AB76s0A0.js} +1 -1
- package/dist/assets/{chunk-QZHKN3VN-Bnojh6X6.js → chunk-QZHKN3VN-CuN2LCFc.js} +1 -1
- package/dist/assets/{chunk-YZCP3GAM-BYqK4Dsa.js → chunk-YZCP3GAM-D4DLBzBN.js} +1 -1
- package/dist/assets/classDiagram-6PBFFD2Q-DLJzWgYm.js +1 -0
- package/dist/assets/classDiagram-v2-HSJHXN6E-DLJzWgYm.js +1 -0
- package/dist/assets/clone-H_VGsHn9.js +1 -0
- package/dist/assets/{cose-bilkent-S5V4N54A-OJ7mmWyV.js → cose-bilkent-S5V4N54A-Bn485PX9.js} +1 -1
- package/dist/assets/{dagre-KV5264BT-B1Kwd_Rk.js → dagre-KV5264BT-e4QVCf17.js} +1 -1
- package/dist/assets/{diagram-5BDNPKRD-D8qrw8sp.js → diagram-5BDNPKRD-_SBFGgnf.js} +1 -1
- package/dist/assets/{diagram-G4DWMVQ6-ip-N4ho8.js → diagram-G4DWMVQ6-Bz1ovxLs.js} +1 -1
- package/dist/assets/{diagram-MMDJMWI5-2PZaskUF.js → diagram-MMDJMWI5-B-oojW8K.js} +1 -1
- package/dist/assets/{diagram-TYMM5635-CeAOQUZP.js → diagram-TYMM5635-CTAyNaOj.js} +1 -1
- package/dist/assets/{erDiagram-SMLLAGMA-BCBaEYEb.js → erDiagram-SMLLAGMA-BfvKAqq2.js} +1 -1
- package/dist/assets/{flowDiagram-DWJPFMVM-CsGyIqcX.js → flowDiagram-DWJPFMVM-BpTEZEAe.js} +1 -1
- package/dist/assets/{ganttDiagram-T4ZO3ILL-COsj3FZ-.js → ganttDiagram-T4ZO3ILL-DUD_vkyE.js} +1 -1
- package/dist/assets/{gitGraphDiagram-UUTBAWPF-DvQVQGJG.js → gitGraphDiagram-UUTBAWPF-DnlXcTud.js} +1 -1
- package/dist/assets/{graph-BSB9fDSP.js → graph-D4xsUKSn.js} +1 -1
- package/dist/assets/{index-DKufsAzx.js → index-84-BjpGl.js} +1 -1
- package/dist/assets/index-BDKwOnE3.js +2 -0
- package/dist/assets/{index-Bo-12bug.js → index-BniBLRtZ.js} +1 -1
- package/dist/assets/{index-BRw4Iz2O.js → index-C2Zo3KOg.js} +1 -1
- package/dist/assets/{index-BuVComcY.js → index-CWZoKT7e.js} +1 -1
- package/dist/assets/{index-eM2ih5n7.js → index-D-4EsFub.js} +1 -1
- package/dist/assets/{index-CNNAYjkF.js → index-D3KzRmkP.js} +1 -1
- package/dist/assets/{index-DXBfwPYD.js → index-NGgdum2i.js} +1 -1
- package/dist/assets/{infoDiagram-42DDH7IO-eNucS4iW.js → infoDiagram-42DDH7IO-BbdvmCDt.js} +1 -1
- package/dist/assets/{ishikawaDiagram-UXIWVN3A-Dxxj-gUX.js → ishikawaDiagram-UXIWVN3A-oZBOPoTO.js} +1 -1
- package/dist/assets/{journeyDiagram-VCZTEJTY-yJJzVEBb.js → journeyDiagram-VCZTEJTY-DWoH0hs9.js} +1 -1
- package/dist/assets/{jszip.min-ByI0ds5u.js → jszip.min-I5y9RZhq.js} +1 -1
- package/dist/assets/{kanban-definition-6JOO6SKY-2rfTi2zw.js → kanban-definition-6JOO6SKY-BLHtjKsS.js} +1 -1
- package/dist/assets/{layout-DTmHj0Wm.js → layout-C116SNcQ.js} +1 -1
- package/dist/assets/{linear-BOA3a9FE.js → linear-Br08WCkF.js} +1 -1
- package/dist/assets/{mermaid.core-5H-NR79H.js → mermaid.core-D-4dTrvI.js} +2 -2
- package/dist/assets/{min-CpjFTEec.js → min-khs74HbH.js} +1 -1
- package/dist/assets/{mindmap-definition-QFDTVHPH-B8KCjFgB.js → mindmap-definition-QFDTVHPH-C3_yItFF.js} +1 -1
- package/dist/assets/{pieDiagram-DEJITSTG-BARy96g5.js → pieDiagram-DEJITSTG-ByCwM2_P.js} +1 -1
- package/dist/assets/{quadrantDiagram-34T5L4WZ-DYoTapuI.js → quadrantDiagram-34T5L4WZ-CjV65X1r.js} +1 -1
- package/dist/assets/{requirementDiagram-MS252O5E-EeANLLK2.js → requirementDiagram-MS252O5E-DFJ_dbtV.js} +1 -1
- package/dist/assets/{sankeyDiagram-XADWPNL6-DmQ-YVPj.js → sankeyDiagram-XADWPNL6-BBvXoBfj.js} +1 -1
- package/dist/assets/{seqResourceLoaders-C0cU2e1o.css → seqResourceLoaders-C34z9uOa.css} +2 -2
- package/dist/assets/seqResourceLoaders-JJzgZZzU.js +2 -0
- package/dist/assets/{sequenceDiagram-FGHM5R23-SZtW0rYC.js → sequenceDiagram-FGHM5R23-BJM04Y3N.js} +1 -1
- package/dist/assets/{stateDiagram-FHFEXIEX-CEygsIld.js → stateDiagram-FHFEXIEX-DI2q_Kkn.js} +1 -1
- package/dist/assets/{stateDiagram-v2-QKLJ7IA2-BU1XPhBe.js → stateDiagram-v2-QKLJ7IA2-CrGC6kEY.js} +1 -1
- package/dist/assets/{timeline-definition-GMOUNBTQ-DhPBaQBt.js → timeline-definition-GMOUNBTQ-JcfRUsjD.js} +1 -1
- package/dist/assets/vendor-antd-DxEVqVhD.js +17 -0
- package/dist/assets/vendor-codemirror-CgNlkZva.js +1 -0
- package/dist/assets/{vendor-mdxeditor-Cz09a1_I.js → vendor-mdxeditor-DoreQf4A.js} +2 -2
- package/dist/assets/{vendor-qrcode-qbbntD6-.js → vendor-qrcode-q1CKtOyX.js} +1 -1
- package/dist/assets/{vendor-virtuoso-Sk8fQ4Hx.js → vendor-virtuoso-BXGe9q7E.js} +1 -1
- package/dist/assets/{vennDiagram-DHZGUBPP-NniTHxDw.js → vennDiagram-DHZGUBPP-mAHR1Ugj.js} +1 -1
- package/dist/assets/{wardley-RL74JXVD-D9SNOrDw.js → wardley-RL74JXVD-mlTq_P-4.js} +1 -1
- package/dist/assets/{wardleyDiagram-NUSXRM2D-DvHXKNza.js → wardleyDiagram-NUSXRM2D-BDGfajRb.js} +1 -1
- package/dist/assets/{xychartDiagram-5P7HB3ND-CaiwPTQB.js → xychartDiagram-5P7HB3ND-Cf2pR1mV.js} +1 -1
- package/dist/index.html +4 -4
- package/package.json +1 -1
- package/plugins/README.md +9 -1
- package/server/interceptor.js +1 -1
- package/server/lib/builtin-model-prompts.js +1 -1
- package/server/lib/chat-queue.js +1 -1
- package/server/lib/credential-access.js +1 -1
- package/server/lib/credential-migrate.js +1 -1
- package/server/lib/error-report.js +26 -0
- package/server/lib/json-store.js +1 -1
- package/server/lib/launch-config.js +1 -1
- package/server/lib/log-watcher.js +1 -1
- package/server/lib/plugin-host.mjs +198 -0
- package/server/lib/plugin-loader.js +346 -90
- package/server/lib/plugin-manager.js +46 -2
- package/server/lib/plugin-manifest.js +329 -0
- package/server/lib/plugin-panels.js +183 -0
- package/server/lib/plugin-proxy.js +408 -0
- package/server/lib/plugin-runtime.js +775 -0
- package/server/lib/plugin-service-manager.js +463 -0
- package/server/lib/proxy/proxy-retry.js +1 -1
- package/server/lib/proxy/proxy-stats.js +1 -1
- package/server/lib/resume-watchdog.js +1 -1
- package/server/lib/same-origin.js +13 -3
- package/server/lib/sdk-manager.js +16 -9
- package/server/lib/sdk-session-index.js +1 -1
- package/server/lib/stats-worker.js +1 -1
- package/server/lib/system-prompt-files.js +1 -1
- package/server/lib/system-prompt-live.js +1 -1
- package/server/lib/system-prompt-snapshots.js +1 -1
- package/server/lib/v2/adapter.js +1 -1
- package/server/lib/v2/convert.js +1 -1
- package/server/lib/v2/jsonl-read.js +1 -1
- package/server/lib/v2/live-feed.js +1 -1
- package/server/lib/v2/meta-rows.js +1 -1
- package/server/lib/v2/resume-list.js +1 -1
- package/server/lib/v2/session-list.js +1 -1
- package/server/lib/v2/session-owner.js +1 -1
- package/server/lib/v2/v2-writer.js +1 -1
- package/server/lib/wire-compress.js +1 -1
- package/server/lib/ws-mux.js +1 -1
- package/server/proxy.js +1 -1
- package/server/pty-manager.js +1 -1
- package/server/routes/ask-perm.js +1 -1
- package/server/routes/events.js +1 -1
- package/server/routes/expert.js +1 -1
- package/server/routes/files-content.js +1 -1
- package/server/routes/files-fs.js +4 -2
- package/server/routes/misc.js +11 -0
- package/server/routes/plugin-services.js +104 -0
- package/server/routes/plugins.js +145 -17
- package/server/routes/preferences.js +1 -1
- package/server/routes/resume.js +1 -1
- package/server/routes/sdk-context.js +1 -1
- package/server/routes/sdk-mcp-status.js +1 -1
- package/server/routes/workspaces.js +1 -1
- package/server/server.js +328 -171
- package/dist/assets/App-CLteNB83.js +0 -2
- package/dist/assets/Mobile-CJCQf3MQ.js +0 -1
- package/dist/assets/ProxyStatsModal-B5ccoOPy.js +0 -1
- package/dist/assets/classDiagram-6PBFFD2Q-ClGF33bF.js +0 -1
- package/dist/assets/classDiagram-v2-HSJHXN6E-ClGF33bF.js +0 -1
- package/dist/assets/clone-CFj55h49.js +0 -1
- package/dist/assets/index-CqX5TkEL.js +0 -2
- package/dist/assets/seqResourceLoaders-7lsgbvGa.js +0 -2
- package/dist/assets/vendor-antd-CS_S2mBN.js +0 -17
- package/dist/assets/vendor-codemirror-B5l-VbBO.js +0 -1
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
// mirroring readJsonlTolerant's torn-tail tolerance (spec §14).
|
|
15
15
|
|
|
16
16
|
import { existsSync, openSync, readSync, closeSync, statSync } from 'node:fs';
|
|
17
|
-
import { reportSwallowed } from '
|
|
17
|
+
import { reportSwallowed } from '../../lib/error-report.js';
|
|
18
18
|
|
|
19
19
|
const DEFAULT_CHUNK_BYTES = 8 * 1024 * 1024;
|
|
20
20
|
// Node's max string length is 0x1fffffe8 (~512MiB) — a line this long can
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
|
|
25
25
|
import { watch, existsSync, readdirSync, readFileSync, statSync, openSync, readSync, closeSync } from 'node:fs';
|
|
26
26
|
import { join } from 'node:path';
|
|
27
|
-
import { reportSwallowed } from '
|
|
27
|
+
import { reportSwallowed } from '../../lib/error-report.js';
|
|
28
28
|
import { createIncrementalReconstructor } from '@ccv/core/delta-reconstructor';
|
|
29
29
|
import { processWatchedEntry, sendEventToClients, sendEventRawToClients } from '../log-watcher.js';
|
|
30
30
|
import { filterClientsByInstance } from './view-router.js';
|
|
@@ -21,7 +21,7 @@ import { readJsonlTolerant } from './replay.js';
|
|
|
21
21
|
import { iterateJsonlLines } from './jsonl-read.js';
|
|
22
22
|
import { iterateV2Items, findTeammateSessionDirs } from './adapter.js';
|
|
23
23
|
import { SingleFlight } from './singleflight.js';
|
|
24
|
-
import { reportSwallowed } from '
|
|
24
|
+
import { reportSwallowed } from '../../lib/error-report.js';
|
|
25
25
|
import { classifyRequest, withAgentNameSubType } from '@ccv/core/requestType';
|
|
26
26
|
|
|
27
27
|
// KEEP IN SYNC: server/lib/v2/adapter.js itemKey — (sessionId, seq) identity.
|
|
@@ -25,7 +25,7 @@ import { summarizeSessionPage } from './session-list.js';
|
|
|
25
25
|
import { sessionHasMainOrTeammateReq } from './session-select.js';
|
|
26
26
|
import { readPin } from '../session-pin-store.js';
|
|
27
27
|
import { LIVE_SESSION_MTIME_MS } from '../log-file-utils.js';
|
|
28
|
-
import { reportSwallowed } from '
|
|
28
|
+
import { reportSwallowed } from '../../lib/error-report.js';
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
31
|
* Liveness heuristic for the "running" placeholder column. A session is
|
|
@@ -26,7 +26,7 @@ import { listSessionIds, readJsonlTolerant } from './replay.js';
|
|
|
26
26
|
import { readPromptsHead, collectPromptsFromEvents } from '../user-prompt-extract.js';
|
|
27
27
|
import { isDiscardableSession } from './session-select.js';
|
|
28
28
|
import { isSupportedWireFormat, dirSizeSync } from './layout.js';
|
|
29
|
-
import { reportSwallowed } from '
|
|
29
|
+
import { reportSwallowed } from '../../lib/error-report.js';
|
|
30
30
|
|
|
31
31
|
const MAX_PROJECTS = 32;
|
|
32
32
|
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
import { readFileSync, writeFileSync, unlinkSync, existsSync } from 'node:fs';
|
|
27
27
|
import { join } from 'node:path';
|
|
28
28
|
import { isPidAlive } from '../pid-alive.js';
|
|
29
|
-
import { reportSwallowed } from '
|
|
29
|
+
import { reportSwallowed } from '../../lib/error-report.js';
|
|
30
30
|
|
|
31
31
|
export const OWNER_LOCK_NAME = 'owner.lock';
|
|
32
32
|
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
import { statfsSync, existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
20
20
|
import { join, basename, sep } from 'node:path';
|
|
21
21
|
import { AsyncWriteQueue } from '../async-write-queue.js';
|
|
22
|
-
import { reportSwallowed } from '
|
|
22
|
+
import { reportSwallowed } from '../../lib/error-report.js';
|
|
23
23
|
import { ensureSessionDirSync, compactLocalTs14, sanitizePathComponent, normalizeSessionCwd } from './layout.js';
|
|
24
24
|
import { resolveSessionDirName, latestMainSession } from './session-select.js';
|
|
25
25
|
import { acquireSessionClaim, releaseSessionClaim, isForeignLiveOwned } from './session-owner.js';
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* knee on large sessions; q5 collapses to ~2.5x there).
|
|
20
20
|
*/
|
|
21
21
|
import zlib from 'node:zlib';
|
|
22
|
-
import { reportSwallowed } from '
|
|
22
|
+
import { reportSwallowed } from '../lib/error-report.js';
|
|
23
23
|
import { awaitDrainOrClose } from './sse-backpressure.js';
|
|
24
24
|
|
|
25
25
|
const C = zlib.constants;
|
package/server/lib/ws-mux.js
CHANGED
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
*/
|
|
43
43
|
import { randomBytes } from 'node:crypto';
|
|
44
44
|
import { EventEmitter } from 'node:events';
|
|
45
|
-
import { reportSwallowed as defaultReport } from '
|
|
45
|
+
import { reportSwallowed as defaultReport } from '../lib/error-report.js';
|
|
46
46
|
import { createBackpressureGate } from './ws-backpressure.js';
|
|
47
47
|
|
|
48
48
|
const STREAM_ID_RE = /^[A-Za-z0-9_-]{1,64}$/;
|
package/server/proxy.js
CHANGED
|
@@ -13,7 +13,7 @@ import { parseAgentId, findHeader } from './lib/v2/agent-id.js';
|
|
|
13
13
|
import { liveSystemPromptEnabled } from './lib/system-prompt-live.js';
|
|
14
14
|
import { executeRequest, extractModel } from './lib/proxy/proxy-retry.js';
|
|
15
15
|
import { buildRecord, appendRecord, dailyFilePath, todayStr, emitProxyStatsUpdate } from './lib/proxy/proxy-stats.js';
|
|
16
|
-
import { reportSwallowed } from '
|
|
16
|
+
import { reportSwallowed } from './lib/error-report.js';
|
|
17
17
|
import { LOG_DIR } from '../findcc.js';
|
|
18
18
|
|
|
19
19
|
// Setup interceptor to patch fetch
|
package/server/pty-manager.js
CHANGED
|
@@ -17,7 +17,7 @@ import { randomBytes } from 'node:crypto';
|
|
|
17
17
|
// (shared with the SDK link). Re-exported here for existing consumers/tests.
|
|
18
18
|
import { withDefaultThinkingDisplay, resolveLaunchSystemPrompt, insertBeforeDashDash } from './lib/launch-config.js';
|
|
19
19
|
export { withDefaultThinkingDisplay } from './lib/launch-config.js';
|
|
20
|
-
import { reportSwallowed } from '
|
|
20
|
+
import { reportSwallowed } from './lib/error-report.js';
|
|
21
21
|
import { t, tFor } from './i18n.js';
|
|
22
22
|
|
|
23
23
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -6,7 +6,7 @@ import { filterClientsByScope } from '../lib/v2/view-router.js';
|
|
|
6
6
|
import { _projectName } from '../interceptor.js';
|
|
7
7
|
import { readPrefsRaw } from '../lib/prefs-store.js';
|
|
8
8
|
import { getCurrentProjectKey, hasFork, resolveScoped } from '../lib/project-prefs.js';
|
|
9
|
-
import { reportSwallowed } from '
|
|
9
|
+
import { reportSwallowed } from '../lib/error-report.js';
|
|
10
10
|
|
|
11
11
|
function pendingAsks(req, res, parsedUrl, isLocal, deps) {
|
|
12
12
|
try {
|
package/server/routes/events.js
CHANGED
|
@@ -5,7 +5,7 @@ import { _projectName, getLiveLogSource, isContinuedLaunch } from '../intercepto
|
|
|
5
5
|
import { LOG_DIR } from '../../findcc.js';
|
|
6
6
|
import { streamRawEntriesAsync } from '../lib/log-stream.js';
|
|
7
7
|
import { migrationStatus } from '../lib/v2/migrate-prompt.js';
|
|
8
|
-
import { reportSwallowed } from '
|
|
8
|
+
import { reportSwallowed } from '../lib/error-report.js';
|
|
9
9
|
import { sseHead, sseWrite, needsDrain, wireEnd, awaitWireDrain, isWireV3Enabled } from '../lib/wire-compress.js';
|
|
10
10
|
import { scopeKeyForProducer } from '../lib/scope-router.js';
|
|
11
11
|
import { readV2ColdBundle } from '../lib/v2/meta-rows.js';
|
package/server/routes/expert.js
CHANGED
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
matchBuiltinModelPrompt, isBuiltinDisabled,
|
|
20
20
|
readBuiltinDisabled, setBuiltinDisabled, listBuiltinModelPrompts,
|
|
21
21
|
} from '../lib/builtin-model-prompts.js';
|
|
22
|
-
import { reportSwallowed } from '
|
|
22
|
+
import { reportSwallowed } from '../lib/error-report.js';
|
|
23
23
|
import { resolveSpawnModel } from '../lib/spawn-model-resolver.js';
|
|
24
24
|
import { listSystemPromptPresets, groupPresetsByCategory, getSystemPromptVariablesDoc } from '../lib/system-prompt-presets.js';
|
|
25
25
|
import { LOG_DIR } from '../../findcc.js';
|
|
@@ -6,7 +6,7 @@ import { ERROR_STATUS_MAP } from '../lib/file-api.js';
|
|
|
6
6
|
import { viewRootOrReply } from '../lib/view-root.js';
|
|
7
7
|
import { loadWorkspaces } from '../workspace-registry.js';
|
|
8
8
|
import { listLivePtys } from '../pty-manager.js';
|
|
9
|
-
import { reportSwallowed } from '
|
|
9
|
+
import { reportSwallowed } from '../lib/error-report.js';
|
|
10
10
|
import { discoverClaudeMdCandidates, readCandidateById } from '../lib/claude-md-discovery.js';
|
|
11
11
|
import { getClaudeConfigDir } from '../../findcc.js';
|
|
12
12
|
import { _projectName } from '../interceptor.js';
|
|
@@ -125,8 +125,10 @@ function importFile(req, res, parsedUrl, isLocal, deps) {
|
|
|
125
125
|
res.end(JSON.stringify({ error: 'Missing boundary' }));
|
|
126
126
|
return;
|
|
127
127
|
}
|
|
128
|
-
|
|
129
|
-
|
|
128
|
+
// Reuse the parsedUrl that handleRequest already validated: req.headers.host may be a
|
|
129
|
+
// malformed value llhttp accepts but URL parsing rejects, and a fresh new URL() here
|
|
130
|
+
// would throw synchronously inside dispatch → unhandled rejection.
|
|
131
|
+
const dir = parsedUrl.searchParams.get('dir') || '';
|
|
130
132
|
// 在 mkdirSync 之前纯字符串校验,防 symlink 副作用目录被创建在项目外
|
|
131
133
|
const dirCheck = validateImportDir(dir);
|
|
132
134
|
if (!dirCheck.ok) {
|
package/server/routes/misc.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
import { getUserProfile } from '../lib/user-profile.js';
|
|
3
3
|
import { runWaterfallHook } from '../lib/plugin-loader.js';
|
|
4
4
|
import { normalizeBasePath } from '../lib/base-path.js';
|
|
5
|
+
import { isAdminReq } from '../lib/is-admin.js';
|
|
6
|
+
import { isSameOriginBrowserRequest } from '../lib/same-origin.js';
|
|
5
7
|
|
|
6
8
|
async function userProfile(req, res) {
|
|
7
9
|
const profile = await getUserProfile();
|
|
@@ -10,6 +12,15 @@ async function userProfile(req, res) {
|
|
|
10
12
|
}
|
|
11
13
|
|
|
12
14
|
async function localUrl(req, res, parsedUrl, isLocal, deps) {
|
|
15
|
+
// The response embeds the full ACCESS_TOKEN. Without this gate the permissive global
|
|
16
|
+
// CORS prelude would let any cross-site page read the token from a loopback server
|
|
17
|
+
// (loopback skips auth) and then bypass every Origin/admin check end-to-end.
|
|
18
|
+
// CLI/native clients (no Origin header) and same-origin admin pages stay allowed.
|
|
19
|
+
if (!isAdminReq(req, isLocal) || !isSameOriginBrowserRequest(req, parsedUrl)) {
|
|
20
|
+
res.writeHead(403, { 'Content-Type': 'application/json' });
|
|
21
|
+
res.end(JSON.stringify({ error: 'Forbidden: admin and same-origin required' }));
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
13
24
|
const localIp = deps.getLocalIp();
|
|
14
25
|
// 反代子路径部署时分享/二维码 URL 也要带前缀,否则扫码绕过代理直连源站端口(与
|
|
15
26
|
// server.startedNetwork 启动打印保持一致)。未设 CCV_BASE_PATH 时为空串,行为不变。
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// Routes for service-plugin proxies (/plugins/<name>/*) and panel bundles
|
|
2
|
+
// (/plugin-panels/<name>/*). Registered in server.js's _routes after pluginsRoutes.
|
|
3
|
+
// Unknown plugin names return 404 here — requests must NOT fall through to the SPA
|
|
4
|
+
// fallback (it would serve index.html as JS/JSON).
|
|
5
|
+
import { getPluginEntries } from '../lib/plugin-loader.js';
|
|
6
|
+
import { tryProxyHttp } from '../lib/plugin-runtime.js';
|
|
7
|
+
import { servePanelFile } from '../lib/plugin-panels.js';
|
|
8
|
+
import { reportSwallowed } from '../lib/error-report.js';
|
|
9
|
+
import { isSameOriginBrowserRequest } from '../lib/same-origin.js';
|
|
10
|
+
|
|
11
|
+
function findPanelEntry(name) {
|
|
12
|
+
for (const entry of getPluginEntries()) {
|
|
13
|
+
if (entry.shape === 'dir' && entry.enabled && !entry.loadError && entry.panel && entry.name === name) {
|
|
14
|
+
return entry;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function pluginProxyHandler(req, res, parsedUrl) {
|
|
21
|
+
try {
|
|
22
|
+
// Plugin services are same-machine capabilities reachable through the main origin.
|
|
23
|
+
// A cross-site browser page must not drive them just because loopback trusts the
|
|
24
|
+
// socket peer; CLI/native callers (no Origin) and same-origin pages pass.
|
|
25
|
+
if (!isSameOriginBrowserRequest(req, parsedUrl)) {
|
|
26
|
+
res.writeHead(403, { 'Content-Type': 'application/json' });
|
|
27
|
+
res.end(JSON.stringify({ error: 'Forbidden: cross-site plugin proxy request' }));
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const handled = tryProxyHttp(req, res, parsedUrl);
|
|
31
|
+
if (!handled) {
|
|
32
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
33
|
+
res.end(JSON.stringify({ error: 'unknown plugin service' }));
|
|
34
|
+
}
|
|
35
|
+
} catch (err) {
|
|
36
|
+
reportSwallowed('plugin-services.proxy-route', err);
|
|
37
|
+
try {
|
|
38
|
+
if (!res.headersSent) {
|
|
39
|
+
res.writeHead(502, { 'Content-Type': 'application/json' });
|
|
40
|
+
res.end(JSON.stringify({ error: 'plugin proxy failure' }));
|
|
41
|
+
} else {
|
|
42
|
+
res.destroy();
|
|
43
|
+
}
|
|
44
|
+
} catch { /* noop */ }
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function pluginPanelHandler(req, res, parsedUrl) {
|
|
49
|
+
try {
|
|
50
|
+
if (req.method !== 'GET' && req.method !== 'HEAD') {
|
|
51
|
+
res.writeHead(405, { 'Content-Type': 'text/plain; charset=utf-8' });
|
|
52
|
+
res.end('method not allowed');
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
// /plugin-panels/<name>/<rel...>
|
|
56
|
+
const rest = parsedUrl.pathname.slice('/plugin-panels/'.length);
|
|
57
|
+
const slash = rest.indexOf('/');
|
|
58
|
+
const name = slash === -1 ? rest : rest.slice(0, slash);
|
|
59
|
+
const relPath = slash === -1 ? '' : rest.slice(slash + 1);
|
|
60
|
+
let decodedName;
|
|
61
|
+
try {
|
|
62
|
+
decodedName = decodeURIComponent(name);
|
|
63
|
+
} catch {
|
|
64
|
+
res.writeHead(400, { 'Content-Type': 'text/plain; charset=utf-8' });
|
|
65
|
+
res.end('bad plugin name');
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const entry = findPanelEntry(decodedName);
|
|
69
|
+
if (!entry) {
|
|
70
|
+
res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });
|
|
71
|
+
res.end('unknown plugin panel');
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (!relPath) {
|
|
75
|
+
// Bare directory path -> entry bundle (relative rootDir = drop the first segment of entryRel)
|
|
76
|
+
const entryRel = entry.panel.entryRel;
|
|
77
|
+
const rel = entryRel.slice(entryRel.indexOf('/') + 1);
|
|
78
|
+
servePanelFile(req, res, entry, rel);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
servePanelFile(req, res, entry, relPath);
|
|
82
|
+
} catch (err) {
|
|
83
|
+
reportSwallowed('plugin-services.panel-route', err);
|
|
84
|
+
try {
|
|
85
|
+
if (!res.headersSent) {
|
|
86
|
+
res.writeHead(500, { 'Content-Type': 'text/plain; charset=utf-8' });
|
|
87
|
+
res.end('panel route failure');
|
|
88
|
+
} else {
|
|
89
|
+
res.destroy();
|
|
90
|
+
}
|
|
91
|
+
} catch { /* noop */ }
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export const pluginServicesRoutes = [
|
|
96
|
+
{
|
|
97
|
+
predicate: (url) => url === '/plugins' || url.startsWith('/plugins/'),
|
|
98
|
+
handler: pluginProxyHandler,
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
predicate: (url) => url === '/plugin-panels' || url.startsWith('/plugin-panels/'),
|
|
102
|
+
handler: pluginPanelHandler,
|
|
103
|
+
},
|
|
104
|
+
];
|
package/server/routes/plugins.js
CHANGED
|
@@ -1,17 +1,84 @@
|
|
|
1
1
|
// Plugin management routes (moved verbatim from server.js handleRequest).
|
|
2
|
+
// Write operations go through the plugin runtime's single-flight queue so service
|
|
3
|
+
// plugins are deactivated/stopped/re-spawned — never a bare loadPlugins() that would
|
|
4
|
+
// leave child processes behind.
|
|
2
5
|
import { existsSync, unlinkSync } from 'node:fs';
|
|
3
6
|
import { join } from 'node:path';
|
|
4
|
-
import {
|
|
5
|
-
import { uploadPlugins, installPluginFromUrl } from '../lib/plugin-manager.js';
|
|
7
|
+
import { getPluginsInfo, getPluginsDir, getPluginEntries } from '../lib/plugin-loader.js';
|
|
8
|
+
import { uploadPlugins, installPluginFromUrl, deletePluginDir } from '../lib/plugin-manager.js';
|
|
9
|
+
import {
|
|
10
|
+
reloadRuntime,
|
|
11
|
+
unloadPlugin,
|
|
12
|
+
restartPlugin,
|
|
13
|
+
getRuntimePluginStatus,
|
|
14
|
+
isRuntimeStopping,
|
|
15
|
+
} from '../lib/plugin-runtime.js';
|
|
16
|
+
import { buildPanelDescriptor } from '../lib/plugin-panels.js';
|
|
6
17
|
import { SERVER_LIB } from '../_paths.js';
|
|
18
|
+
import { reportSwallowed } from '../lib/error-report.js';
|
|
19
|
+
import { isAdminReq } from '../lib/is-admin.js';
|
|
20
|
+
import { isSameOriginBrowserRequest } from '../lib/same-origin.js';
|
|
21
|
+
|
|
22
|
+
// Write endpoints execute arbitrary plugin code (reload/restart), install remote files,
|
|
23
|
+
// or delete on-disk plugins. They require an admin AND a same-origin browser context:
|
|
24
|
+
// the global ACAO:* prelude would otherwise let a cross-site page drive a localhost
|
|
25
|
+
// server that trusts its socket peer. CLI/native clients (no Origin) stay allowed.
|
|
26
|
+
function rejectWrite(req, res, isLocal, parsedUrl) {
|
|
27
|
+
// Refuse during the shutdown teardown window: a reload/restart accepted here could
|
|
28
|
+
// spawn a child after onServerStopping already swept the runtime, leaking a lock file.
|
|
29
|
+
if (isRuntimeStopping()) {
|
|
30
|
+
res.writeHead(503, { 'Content-Type': 'application/json' });
|
|
31
|
+
res.end(JSON.stringify({ error: 'server is stopping' }));
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
if (isAdminReq(req, isLocal) && isSameOriginBrowserRequest(req, parsedUrl)) return false;
|
|
35
|
+
res.writeHead(403, { 'Content-Type': 'application/json' });
|
|
36
|
+
res.end(JSON.stringify({ error: 'Forbidden: admin and same-origin required' }));
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function decorateWithRuntime(plugins) {
|
|
41
|
+
return plugins.map(p => {
|
|
42
|
+
// Only service plugins have a service status; lifecycle-only dir plugins also get a
|
|
43
|
+
// runtime entry, but exposing it as serviceStatus would imply a service exists.
|
|
44
|
+
if (p.type !== 'service') return p;
|
|
45
|
+
const status = getRuntimePluginStatus(p.name);
|
|
46
|
+
return status ? { ...p, serviceStatus: status } : p;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
7
49
|
|
|
8
50
|
function pluginsList(req, res) {
|
|
9
|
-
const plugins = getPluginsInfo();
|
|
51
|
+
const plugins = decorateWithRuntime(getPluginsInfo());
|
|
10
52
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
11
53
|
res.end(JSON.stringify({ plugins, pluginsDir: getPluginsDir() }));
|
|
12
54
|
}
|
|
13
55
|
|
|
14
|
-
async function pluginsDelete(req, res, parsedUrl) {
|
|
56
|
+
async function pluginsDelete(req, res, parsedUrl, isLocal) {
|
|
57
|
+
if (rejectWrite(req, res, isLocal, parsedUrl)) return;
|
|
58
|
+
const dir = parsedUrl.searchParams.get('dir');
|
|
59
|
+
if (dir) {
|
|
60
|
+
try {
|
|
61
|
+
const unloaded = await unloadPlugin(dir, 'delete');
|
|
62
|
+
if (!unloaded.ok) {
|
|
63
|
+
res.writeHead(503, { 'Content-Type': 'application/json' });
|
|
64
|
+
res.end(JSON.stringify({ error: unloaded.error || 'plugin runtime is stopping' }));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
deletePluginDir(getPluginsDir(), dir);
|
|
68
|
+
const result = await reloadRuntime();
|
|
69
|
+
if (!result.ok) {
|
|
70
|
+
res.writeHead(503, { 'Content-Type': 'application/json' });
|
|
71
|
+
res.end(JSON.stringify({ error: result.error || 'plugin runtime is stopping' }));
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
75
|
+
res.end(JSON.stringify({ ok: true, plugins: decorateWithRuntime(getPluginsInfo()), pluginsDir: getPluginsDir(), generation: result.generation }));
|
|
76
|
+
} catch (err) {
|
|
77
|
+
res.writeHead(err.statusCode || 500, { 'Content-Type': 'application/json' });
|
|
78
|
+
res.end(JSON.stringify({ error: err.message }));
|
|
79
|
+
}
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
15
82
|
const file = parsedUrl.searchParams.get('file');
|
|
16
83
|
if (!file || file.includes('..') || file.includes('/') || file.includes('\\')) {
|
|
17
84
|
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
@@ -26,39 +93,93 @@ async function pluginsDelete(req, res, parsedUrl) {
|
|
|
26
93
|
return;
|
|
27
94
|
}
|
|
28
95
|
unlinkSync(filePath);
|
|
29
|
-
await
|
|
30
|
-
|
|
96
|
+
const result = await reloadRuntime();
|
|
97
|
+
if (!result.ok) {
|
|
98
|
+
res.writeHead(503, { 'Content-Type': 'application/json' });
|
|
99
|
+
res.end(JSON.stringify({ error: result.error || 'plugin runtime is stopping' }));
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
31
102
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
32
|
-
res.end(JSON.stringify({ ok: true, plugins, pluginsDir: getPluginsDir() }));
|
|
103
|
+
res.end(JSON.stringify({ ok: true, plugins: decorateWithRuntime(getPluginsInfo()), pluginsDir: getPluginsDir(), generation: result.generation }));
|
|
33
104
|
} catch (err) {
|
|
34
105
|
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
35
106
|
res.end(JSON.stringify({ error: err.message }));
|
|
36
107
|
}
|
|
37
108
|
}
|
|
38
109
|
|
|
39
|
-
async function pluginsReload(req, res) {
|
|
110
|
+
async function pluginsReload(req, res, parsedUrl, isLocal) {
|
|
111
|
+
if (rejectWrite(req, res, isLocal, parsedUrl)) return;
|
|
40
112
|
try {
|
|
41
|
-
|
|
42
|
-
const
|
|
113
|
+
// ?reason=disable: the UI disable toggle goes through preferences + reload, so deactivate must receive 'disable'
|
|
114
|
+
const reason = parsedUrl && parsedUrl.searchParams.get('reason');
|
|
115
|
+
const result = await reloadRuntime(reason === 'disable' ? { reason: 'disable' } : {});
|
|
116
|
+
if (!result.ok) {
|
|
117
|
+
res.writeHead(503, { 'Content-Type': 'application/json' });
|
|
118
|
+
res.end(JSON.stringify({ error: result.error || 'plugin runtime is stopping' }));
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
43
121
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
44
|
-
res.end(JSON.stringify({ ok: true, plugins, pluginsDir: getPluginsDir() }));
|
|
122
|
+
res.end(JSON.stringify({ ok: true, plugins: decorateWithRuntime(getPluginsInfo()), pluginsDir: getPluginsDir(), generation: result.generation }));
|
|
123
|
+
} catch (err) {
|
|
124
|
+
reportSwallowed('plugins.reload', err);
|
|
125
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
126
|
+
res.end(JSON.stringify({ error: err.message }));
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async function pluginsRestart(req, res, parsedUrl, isLocal) {
|
|
131
|
+
if (rejectWrite(req, res, isLocal, parsedUrl)) return;
|
|
132
|
+
const name = parsedUrl.searchParams.get('name');
|
|
133
|
+
if (!name) {
|
|
134
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
135
|
+
res.end(JSON.stringify({ error: 'name is required' }));
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
const result = await restartPlugin(name);
|
|
140
|
+
res.writeHead(result.ok ? 200 : 400, { 'Content-Type': 'application/json' });
|
|
141
|
+
res.end(JSON.stringify(result));
|
|
142
|
+
} catch (err) {
|
|
143
|
+
reportSwallowed('plugins.restart', err);
|
|
144
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
145
|
+
res.end(JSON.stringify({ error: err.message }));
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function pluginPanelsList(req, res) {
|
|
150
|
+
try {
|
|
151
|
+
const panels = [];
|
|
152
|
+
for (const entry of getPluginEntries()) {
|
|
153
|
+
if (entry.shape !== 'dir' || !entry.enabled || entry.loadError || !entry.panel) continue;
|
|
154
|
+
const status = getRuntimePluginStatus(entry.name);
|
|
155
|
+
panels.push(buildPanelDescriptor(entry, { serviceStatus: status }));
|
|
156
|
+
}
|
|
157
|
+
panels.sort((a, b) => a.name.localeCompare(b.name));
|
|
158
|
+
res.writeHead(200, { 'Content-Type': 'application/json', 'Cache-Control': 'no-store' });
|
|
159
|
+
res.end(JSON.stringify({ ok: true, panels }));
|
|
45
160
|
} catch (err) {
|
|
161
|
+
reportSwallowed('plugins.panels', err);
|
|
46
162
|
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
47
163
|
res.end(JSON.stringify({ error: err.message }));
|
|
48
164
|
}
|
|
49
165
|
}
|
|
50
166
|
|
|
51
167
|
function pluginsUpload(req, res, parsedUrl, isLocal, deps) {
|
|
168
|
+
if (rejectWrite(req, res, isLocal, parsedUrl)) return;
|
|
52
169
|
let body = '';
|
|
53
170
|
req.on('data', chunk => { body += chunk; if (body.length > deps.MAX_POST_BODY) req.destroy(); });
|
|
54
171
|
req.on('end', async () => {
|
|
55
172
|
try {
|
|
56
173
|
const { files: fileList } = JSON.parse(body);
|
|
57
174
|
uploadPlugins(getPluginsDir(), fileList);
|
|
58
|
-
await
|
|
59
|
-
|
|
175
|
+
const result = await reloadRuntime();
|
|
176
|
+
if (!result.ok) {
|
|
177
|
+
res.writeHead(503, { 'Content-Type': 'application/json' });
|
|
178
|
+
res.end(JSON.stringify({ error: result.error || 'plugin runtime is stopping' }));
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
60
181
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
61
|
-
res.end(JSON.stringify({ ok: true, plugins, pluginsDir: getPluginsDir() }));
|
|
182
|
+
res.end(JSON.stringify({ ok: true, plugins: decorateWithRuntime(getPluginsInfo()), pluginsDir: getPluginsDir(), generation: result.generation }));
|
|
62
183
|
} catch (err) {
|
|
63
184
|
const status = err.statusCode || 500;
|
|
64
185
|
res.writeHead(status, { 'Content-Type': 'application/json' });
|
|
@@ -68,6 +189,7 @@ function pluginsUpload(req, res, parsedUrl, isLocal, deps) {
|
|
|
68
189
|
}
|
|
69
190
|
|
|
70
191
|
function pluginsInstallFromUrl(req, res, parsedUrl, isLocal, deps) {
|
|
192
|
+
if (rejectWrite(req, res, isLocal, parsedUrl)) return;
|
|
71
193
|
let body = '';
|
|
72
194
|
req.on('data', chunk => { body += chunk; if (body.length > deps.MAX_POST_BODY) req.destroy(); });
|
|
73
195
|
req.on('end', async () => {
|
|
@@ -75,10 +197,14 @@ function pluginsInstallFromUrl(req, res, parsedUrl, isLocal, deps) {
|
|
|
75
197
|
const { url: fileUrl } = JSON.parse(body);
|
|
76
198
|
const extractScript = join(SERVER_LIB, 'extract-plugin-name.mjs');
|
|
77
199
|
await installPluginFromUrl(getPluginsDir(), fileUrl, extractScript);
|
|
78
|
-
await
|
|
79
|
-
|
|
200
|
+
const result = await reloadRuntime();
|
|
201
|
+
if (!result.ok) {
|
|
202
|
+
res.writeHead(503, { 'Content-Type': 'application/json' });
|
|
203
|
+
res.end(JSON.stringify({ error: result.error || 'plugin runtime is stopping' }));
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
80
206
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
81
|
-
res.end(JSON.stringify({ ok: true, plugins, pluginsDir: getPluginsDir() }));
|
|
207
|
+
res.end(JSON.stringify({ ok: true, plugins: decorateWithRuntime(getPluginsInfo()), pluginsDir: getPluginsDir(), generation: result.generation }));
|
|
82
208
|
} catch (err) {
|
|
83
209
|
const status = err.statusCode || 500;
|
|
84
210
|
res.writeHead(status, { 'Content-Type': 'application/json' });
|
|
@@ -91,6 +217,8 @@ export const pluginsRoutes = [
|
|
|
91
217
|
{ method: 'GET', match: 'exact', path: '/api/plugins', handler: pluginsList },
|
|
92
218
|
{ method: 'DELETE', match: 'exact', path: '/api/plugins', handler: pluginsDelete },
|
|
93
219
|
{ method: 'POST', match: 'exact', path: '/api/plugins/reload', handler: pluginsReload },
|
|
220
|
+
{ method: 'POST', match: 'exact', path: '/api/plugins/restart', handler: pluginsRestart },
|
|
221
|
+
{ method: 'GET', match: 'exact', path: '/api/plugin-panels', handler: pluginPanelsList },
|
|
94
222
|
{ method: 'POST', match: 'exact', path: '/api/plugins/upload', handler: pluginsUpload },
|
|
95
223
|
{ method: 'POST', match: 'exact', path: '/api/plugins/install-from-url', handler: pluginsInstallFromUrl },
|
|
96
224
|
];
|
|
@@ -7,7 +7,7 @@ import { PROFILE_PATH, _defaultConfig, getActiveProfileId, getStoredRoles, isOff
|
|
|
7
7
|
import { migrateProxyProfileList, isValidRoleValue, PROXY_ROLE_KEYS } from '../lib/interceptor-core.js';
|
|
8
8
|
import { DEFAULT_RETRY_CONFIG, validateRetryConfig, resolveRetryConfig } from '../lib/proxy/proxy-retry.js';
|
|
9
9
|
import { discoverCcSwitchProviders, mergeImportedProfiles } from '../lib/ccswitch-import.js';
|
|
10
|
-
import { reportSwallowed } from '
|
|
10
|
+
import { reportSwallowed } from '../lib/error-report.js';
|
|
11
11
|
import { setLang } from '../i18n.js';
|
|
12
12
|
import { reconcileVoicePackPrefs as vpReconcile } from '../lib/voice-pack-manager.js';
|
|
13
13
|
import { readClaudeProjectModel } from '../lib/context-watcher.js';
|
package/server/routes/resume.js
CHANGED
|
@@ -53,7 +53,7 @@ import { bumpWorkspacesVersion } from '../lib/file-access-policy.js';
|
|
|
53
53
|
import { isAdminReq } from '../lib/is-admin.js';
|
|
54
54
|
import { isSameOriginBrowserRequest } from '../lib/same-origin.js';
|
|
55
55
|
import { sseWrite } from '../lib/wire-compress.js';
|
|
56
|
-
import { reportSwallowed } from '
|
|
56
|
+
import { reportSwallowed } from '../lib/error-report.js';
|
|
57
57
|
import { findSdkSessionByInstance, listSdkSessionInstances } from '../lib/sdk-session-index.js';
|
|
58
58
|
|
|
59
59
|
function sendJson(res, code, obj) {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// the automatic turn-end/compact refreshes flow over the WS broadcast instead. A
|
|
3
3
|
// `session-inactive` outcome is a NORMAL state (no turn run yet / query dead), so it
|
|
4
4
|
// returns 200 with { ok:false, reason } rather than an HTTP error.
|
|
5
|
-
import { reportSwallowed } from '
|
|
5
|
+
import { reportSwallowed } from '../lib/error-report.js';
|
|
6
6
|
|
|
7
7
|
async function sdkContextUsage(req, res) {
|
|
8
8
|
try {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// pull; there is no turn-driven refresh (MCP status is not turn-correlated). A
|
|
3
3
|
// `session-inactive` outcome is a NORMAL state (no turn run yet / query dead), so it
|
|
4
4
|
// returns 200 with { ok:false, reason } rather than an HTTP error.
|
|
5
|
-
import { reportSwallowed } from '
|
|
5
|
+
import { reportSwallowed } from '../lib/error-report.js';
|
|
6
6
|
|
|
7
7
|
async function sdkMcpStatus(req, res) {
|
|
8
8
|
try {
|
|
@@ -4,7 +4,7 @@ import { basename } from 'node:path';
|
|
|
4
4
|
import { initForWorkspace, resetWorkspace, getLiveLogSource, markContinuedLaunch, markForkSession, markResumeSession, isContinuedLaunch, clearScopeState } from '../interceptor.js';
|
|
5
5
|
import { LOG_DIR } from '../../findcc.js';
|
|
6
6
|
import { migrationStatus } from '../lib/v2/migrate-prompt.js';
|
|
7
|
-
import { reportSwallowed } from '
|
|
7
|
+
import { reportSwallowed } from '../lib/error-report.js';
|
|
8
8
|
|
|
9
9
|
// P2: claude continuation flags — the workspace launcher injects `-c` itself
|
|
10
10
|
// (WorkspaceList's logCount heuristic), so argv scanning in cli.js never sees
|