@intutic/sync-daemon 1.9.0 → 1.10.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/README.md +2 -2
- package/dist/agentReporter.d.ts +205 -0
- package/dist/agentReporter.d.ts.map +1 -0
- package/dist/agentReporter.js +394 -0
- package/dist/agentReporter.js.map +1 -0
- package/dist/configReader.d.ts +39 -2
- package/dist/configReader.d.ts.map +1 -1
- package/dist/configReader.js +56 -2
- package/dist/configReader.js.map +1 -1
- package/dist/configWriter.d.ts +51 -1
- package/dist/configWriter.d.ts.map +1 -1
- package/dist/configWriter.js +490 -63
- package/dist/configWriter.js.map +1 -1
- package/dist/harness/antigravityHooks.d.ts.map +1 -1
- package/dist/harness/antigravityHooks.js +33 -55
- package/dist/harness/antigravityHooks.js.map +1 -1
- package/dist/harness/claudeCodeHooks.d.ts +47 -13
- package/dist/harness/claudeCodeHooks.d.ts.map +1 -1
- package/dist/harness/claudeCodeHooks.js +323 -55
- package/dist/harness/claudeCodeHooks.js.map +1 -1
- package/dist/harness/claudeDesktopHooks.d.ts.map +1 -1
- package/dist/harness/claudeDesktopHooks.js +35 -48
- package/dist/harness/claudeDesktopHooks.js.map +1 -1
- package/dist/harness/clineHooks.d.ts.map +1 -1
- package/dist/harness/clineHooks.js +42 -34
- package/dist/harness/clineHooks.js.map +1 -1
- package/dist/harness/codexHooks.d.ts +36 -0
- package/dist/harness/codexHooks.d.ts.map +1 -0
- package/dist/harness/codexHooks.js +227 -0
- package/dist/harness/codexHooks.js.map +1 -0
- package/dist/harness/continueHooks.d.ts +45 -5
- package/dist/harness/continueHooks.d.ts.map +1 -1
- package/dist/harness/continueHooks.js +225 -5
- package/dist/harness/continueHooks.js.map +1 -1
- package/dist/harness/cursorHooks.d.ts +31 -0
- package/dist/harness/cursorHooks.d.ts.map +1 -1
- package/dist/harness/cursorHooks.js +78 -49
- package/dist/harness/cursorHooks.js.map +1 -1
- package/dist/harness/dshHooks.d.ts +198 -0
- package/dist/harness/dshHooks.d.ts.map +1 -0
- package/dist/harness/dshHooks.js +569 -0
- package/dist/harness/dshHooks.js.map +1 -0
- package/dist/harness/gateBody.d.ts +422 -0
- package/dist/harness/gateBody.d.ts.map +1 -0
- package/dist/harness/gateBody.js +1816 -0
- package/dist/harness/gateBody.js.map +1 -0
- package/dist/harness/gateKind.d.ts +164 -0
- package/dist/harness/gateKind.d.ts.map +1 -0
- package/dist/harness/gateKind.js +143 -0
- package/dist/harness/gateKind.js.map +1 -0
- package/dist/harness/githubCopilotHooks.d.ts +54 -0
- package/dist/harness/githubCopilotHooks.d.ts.map +1 -0
- package/dist/harness/githubCopilotHooks.js +218 -0
- package/dist/harness/githubCopilotHooks.js.map +1 -0
- package/dist/harness/gooseHooks.d.ts.map +1 -1
- package/dist/harness/gooseHooks.js +67 -37
- package/dist/harness/gooseHooks.js.map +1 -1
- package/dist/harness/grokHooks.d.ts +77 -0
- package/dist/harness/grokHooks.d.ts.map +1 -0
- package/dist/harness/grokHooks.js +350 -0
- package/dist/harness/grokHooks.js.map +1 -0
- package/dist/harness/hermesHooks.d.ts.map +1 -1
- package/dist/harness/hermesHooks.js +26 -55
- package/dist/harness/hermesHooks.js.map +1 -1
- package/dist/harness/holdRedaction.d.ts +69 -0
- package/dist/harness/holdRedaction.d.ts.map +1 -0
- package/dist/harness/holdRedaction.js +211 -0
- package/dist/harness/holdRedaction.js.map +1 -0
- package/dist/harness/jetbrainsXmlConfig.d.ts +51 -0
- package/dist/harness/jetbrainsXmlConfig.d.ts.map +1 -0
- package/dist/harness/jetbrainsXmlConfig.js +151 -0
- package/dist/harness/jetbrainsXmlConfig.js.map +1 -0
- package/dist/harness/mcpAutoWrite.d.ts +100 -3
- package/dist/harness/mcpAutoWrite.d.ts.map +1 -1
- package/dist/harness/mcpAutoWrite.js +712 -90
- package/dist/harness/mcpAutoWrite.js.map +1 -1
- package/dist/harness/museHooks.d.ts +53 -0
- package/dist/harness/museHooks.d.ts.map +1 -0
- package/dist/harness/museHooks.js +273 -0
- package/dist/harness/museHooks.js.map +1 -0
- package/dist/harness/n8nHooks.d.ts +25 -9
- package/dist/harness/n8nHooks.d.ts.map +1 -1
- package/dist/harness/n8nHooks.js +174 -9
- package/dist/harness/n8nHooks.js.map +1 -1
- package/dist/harness/openCodeHooks.d.ts +93 -0
- package/dist/harness/openCodeHooks.d.ts.map +1 -0
- package/dist/harness/openCodeHooks.js +248 -0
- package/dist/harness/openCodeHooks.js.map +1 -0
- package/dist/harness/openWebuiHooks.d.ts.map +1 -1
- package/dist/harness/openWebuiHooks.js +56 -11
- package/dist/harness/openWebuiHooks.js.map +1 -1
- package/dist/harness/openclawHooks.d.ts.map +1 -1
- package/dist/harness/openclawHooks.js +30 -54
- package/dist/harness/openclawHooks.js.map +1 -1
- package/dist/harness/openhandsHooks.d.ts.map +1 -1
- package/dist/harness/openhandsHooks.js +35 -41
- package/dist/harness/openhandsHooks.js.map +1 -1
- package/dist/harness/piHooks.d.ts.map +1 -1
- package/dist/harness/piHooks.js +31 -58
- package/dist/harness/piHooks.js.map +1 -1
- package/dist/harness/protectedPaths.d.ts +353 -0
- package/dist/harness/protectedPaths.d.ts.map +1 -0
- package/dist/harness/protectedPaths.js +805 -0
- package/dist/harness/protectedPaths.js.map +1 -0
- package/dist/harness/rooCodeHooks.d.ts.map +1 -1
- package/dist/harness/rooCodeHooks.js +34 -48
- package/dist/harness/rooCodeHooks.js.map +1 -1
- package/dist/harness/windsurfHooks.d.ts +72 -0
- package/dist/harness/windsurfHooks.d.ts.map +1 -1
- package/dist/harness/windsurfHooks.js +172 -58
- package/dist/harness/windsurfHooks.js.map +1 -1
- package/dist/harness/windsurfJetBrainsProxy.d.ts +78 -0
- package/dist/harness/windsurfJetBrainsProxy.d.ts.map +1 -0
- package/dist/harness/windsurfJetBrainsProxy.js +159 -0
- package/dist/harness/windsurfJetBrainsProxy.js.map +1 -0
- package/dist/hashReporter.js +1 -1
- package/dist/hashReporter.js.map +1 -1
- package/dist/index.d.ts +12 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -6
- package/dist/index.js.map +1 -1
- package/dist/integrityStore.d.ts +0 -8
- package/dist/integrityStore.d.ts.map +1 -1
- package/dist/integrityStore.js +6 -29
- package/dist/integrityStore.js.map +1 -1
- package/dist/lib/approvedBypasses.d.ts +76 -0
- package/dist/lib/approvedBypasses.d.ts.map +1 -0
- package/dist/lib/approvedBypasses.js +140 -0
- package/dist/lib/approvedBypasses.js.map +1 -0
- package/dist/lib/complianceProbes.d.ts.map +1 -1
- package/dist/lib/complianceProbes.js +5 -0
- package/dist/lib/complianceProbes.js.map +1 -1
- package/dist/lib/decisionsDigest.d.ts +99 -0
- package/dist/lib/decisionsDigest.d.ts.map +1 -0
- package/dist/lib/decisionsDigest.js +199 -0
- package/dist/lib/decisionsDigest.js.map +1 -0
- package/dist/lib/egressPolicy.d.ts +69 -0
- package/dist/lib/egressPolicy.d.ts.map +1 -0
- package/dist/lib/egressPolicy.js +126 -0
- package/dist/lib/egressPolicy.js.map +1 -0
- package/dist/lib/gitWorktrees.d.ts +140 -0
- package/dist/lib/gitWorktrees.d.ts.map +1 -0
- package/dist/lib/gitWorktrees.js +191 -0
- package/dist/lib/gitWorktrees.js.map +1 -0
- package/dist/lib/policySnapshot.d.ts +224 -0
- package/dist/lib/policySnapshot.d.ts.map +1 -0
- package/dist/lib/policySnapshot.js +637 -0
- package/dist/lib/policySnapshot.js.map +1 -0
- package/dist/lib/processPoller.d.ts +44 -0
- package/dist/lib/processPoller.d.ts.map +1 -1
- package/dist/lib/processPoller.js +176 -1
- package/dist/lib/processPoller.js.map +1 -1
- package/dist/lib/runtimeEnv.d.ts +8 -0
- package/dist/lib/runtimeEnv.d.ts.map +1 -1
- package/dist/lib/runtimeEnv.js +3 -0
- package/dist/lib/runtimeEnv.js.map +1 -1
- package/dist/localTrajectoryHeuristics.d.ts +51 -0
- package/dist/localTrajectoryHeuristics.d.ts.map +1 -0
- package/dist/localTrajectoryHeuristics.js +90 -0
- package/dist/localTrajectoryHeuristics.js.map +1 -0
- package/dist/sessionReporter.d.ts +70 -0
- package/dist/sessionReporter.d.ts.map +1 -0
- package/dist/sessionReporter.js +140 -0
- package/dist/sessionReporter.js.map +1 -0
- package/dist/skillWriter.d.ts +1 -1
- package/dist/skillWriter.d.ts.map +1 -1
- package/dist/skillWriter.js +6 -3
- package/dist/skillWriter.js.map +1 -1
- package/dist/syncLoop.d.ts +105 -3
- package/dist/syncLoop.d.ts.map +1 -1
- package/dist/syncLoop.js +397 -65
- package/dist/syncLoop.js.map +1 -1
- package/dist/trajectoryMonitor.d.ts +2 -0
- package/dist/trajectoryMonitor.d.ts.map +1 -1
- package/dist/trajectoryMonitor.js +57 -0
- package/dist/trajectoryMonitor.js.map +1 -1
- package/dist/watcher/driftWatcher.d.ts.map +1 -1
- package/dist/watcher/driftWatcher.js +12 -3
- package/dist/watcher/driftWatcher.js.map +1 -1
- package/dist/watcher/settingsGuard.d.ts +23 -0
- package/dist/watcher/settingsGuard.d.ts.map +1 -1
- package/dist/watcher/settingsGuard.js +202 -17
- package/dist/watcher/settingsGuard.js.map +1 -1
- package/package.json +37 -6
- package/dist/brainIndexer.d.ts +0 -51
- package/dist/brainIndexer.d.ts.map +0 -1
- package/dist/brainIndexer.js +0 -148
- package/dist/brainIndexer.js.map +0 -1
- package/dist/harness/cursorHooksJson.d.ts +0 -29
- package/dist/harness/cursorHooksJson.d.ts.map +0 -1
- package/dist/harness/cursorHooksJson.js +0 -130
- package/dist/harness/cursorHooksJson.js.map +0 -1
- package/dist/harness/gooseHooksWriter.d.ts +0 -27
- package/dist/harness/gooseHooksWriter.d.ts.map +0 -1
- package/dist/harness/gooseHooksWriter.js +0 -147
- package/dist/harness/gooseHooksWriter.js.map +0 -1
- package/dist/harness/openhandsHooksWriter.d.ts +0 -23
- package/dist/harness/openhandsHooksWriter.d.ts.map +0 -1
- package/dist/harness/openhandsHooksWriter.js +0 -146
- package/dist/harness/openhandsHooksWriter.js.map +0 -1
|
@@ -0,0 +1,569 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dshHooks.ts — DeepSeek "dsh" (developer preview, `@deepseek-ai/dsh`) Cordis
|
|
3
|
+
* plugin registration + LLM egress routing.
|
|
4
|
+
*
|
|
5
|
+
* dsh has no `hooks.json`/shell-script gate surface at all — it is
|
|
6
|
+
* plugin-first ("Cordis", DeepSeek's own extensibility framework), and the
|
|
7
|
+
* blocking gate for this harness ships as a real TypeScript module,
|
|
8
|
+
* `@intutic/gate/dsh` (`packages/gate-js/src/dsh.ts`), not a generated
|
|
9
|
+
* string of shell/JS this writer assembles the way `grokHooks.ts`/
|
|
10
|
+
* `museHooks.ts` do. This writer's job is narrower than theirs: merge-write
|
|
11
|
+
* the ROW that tells dsh's own Cordis loader to load that module, into every
|
|
12
|
+
* dsh profile this machine has, plus the LLM egress override.
|
|
13
|
+
*
|
|
14
|
+
* # What this phase confirmed against a REAL install — not the plan's guess
|
|
15
|
+
*
|
|
16
|
+
* `@deepseek-ai/dsh` and its Cordis framework packages (`@deepseek-ai/cordis`,
|
|
17
|
+
* `@deepseek-ai/dsh-app-boot`, `@deepseek-ai/dsh-tools`, `@deepseek-ai/dsh-base`,
|
|
18
|
+
* `@deepseek-ai/dsh-llm-pi-ai`, `@deepseek-ai/dsh-home-paths`, ...) are public
|
|
19
|
+
* on the npm registry (first published 2026-08-13, ~161 KB unpacked for the
|
|
20
|
+
* `dsh` package itself) — reachable and installable from this sandbox, unlike
|
|
21
|
+
* Muse Code/Grok Build in Wave 1. This writer was authored against a real
|
|
22
|
+
* `npm pack` + read of those packages' shipped `.d.ts`/README files, not
|
|
23
|
+
* solely the phase brief's prior research (see the TD entry this phase filed
|
|
24
|
+
* for exactly what was checked and what is still genuinely unconfirmed —
|
|
25
|
+
* dsh-permission, dsh-settings-local, and dsh-fs-policy 404'd as
|
|
26
|
+
* `publishConfig.access: restricted`, so the exact settings.yaml schema
|
|
27
|
+
* dsh-settings-local enforces was not directly inspected, only inferred from
|
|
28
|
+
* `dsh-base`'s own `cordis.patch.yml` comments and `dsh-llm-pi-ai`'s README).
|
|
29
|
+
*
|
|
30
|
+
* Confirmed facts this writer relies on:
|
|
31
|
+
*
|
|
32
|
+
* - `$DSH_HOME` resolution (`dsh-home-paths`): an explicit configured path,
|
|
33
|
+
* then `$DSH_HOME`, then `~/.dsh` — {@link resolveDshHome} below mirrors
|
|
34
|
+
* the env-var half (this writer has no "explicit configured path" input).
|
|
35
|
+
* - A **profile** is `$DSH_HOME/profiles/<name>/` holding a `package.json`
|
|
36
|
+
* (the profile manifest) and a `cordis.patch.yml` (`PROFILE_PATCH_FILENAME`
|
|
37
|
+
* — "the user patch layer inside a profile directory, hot-reloaded") —
|
|
38
|
+
* confirmed from `@deepseek-ai/dsh-app-boot`'s shipped `profile.d.ts`.
|
|
39
|
+
* - The patch-list format (`@deepseek-ai/cordis-plugin-include`'s
|
|
40
|
+
* `applyEntryPatches`, read from its shipped `lib/index.js`): a top-level
|
|
41
|
+
* YAML array of patch operations. `{ insert: [...] }` with no `id`
|
|
42
|
+
* appends the listed rows to the array; `{ id, insert: [...] }` inserts
|
|
43
|
+
* into an existing GROUP row's own `config` array; `{ id, name?,
|
|
44
|
+
* config?, ... }` (no `insert`) looks up the row by `id` and overwrites
|
|
45
|
+
* the named fields in place. This writer only ever emits the first shape
|
|
46
|
+
* (a fresh, self-contained `insert:` block naming this row by `id`), so
|
|
47
|
+
* its own writes are always recognizable on a later sync regardless of
|
|
48
|
+
* which shape a human or an older version of this writer left.
|
|
49
|
+
* - Plugin resolution (`@deepseek-ai/cordis-plugin-loader`'s shipped
|
|
50
|
+
* `lib/index.js`): a patch row's `name` is resolved via a plain dynamic
|
|
51
|
+
* `import(name)` when it is not a relative path — a bare specifier like
|
|
52
|
+
* `@intutic/gate/dsh` resolves exactly the way any other bundle package
|
|
53
|
+
* name in `dsh-base`'s own `cordis.patch.yml` does, subpath exports
|
|
54
|
+
* included. Node resolves it from the profile directory's own
|
|
55
|
+
* `node_modules` (the "two-anchor" resolution `profile.d.ts` documents
|
|
56
|
+
* for out-of-tree plugins) — which means `@intutic/gate` must actually be
|
|
57
|
+
* installed there; see {@link mergeProfileDependency} and the TD entry
|
|
58
|
+
* for why this writer cannot run `pnpm install` on the user's behalf.
|
|
59
|
+
* - `settings.yaml`'s `llm-pi-ai.providers.<id>.baseURL` path — CONFIRMED,
|
|
60
|
+
* not merely the plan's assumption: `dsh-llm-pi-ai`'s shipped README shows
|
|
61
|
+
* exactly this shape overriding an EXISTING catalog route's endpoint
|
|
62
|
+
* (`providers.openai.baseURL: https://proxy.example.com:8443`), the same
|
|
63
|
+
* "override base_url on what already resolves, don't invent a model
|
|
64
|
+
* picker entry" shape `grokHooks.ts`'s `[model.*]` merge uses. `llm-pi-ai`
|
|
65
|
+
* is NOT dsh's default LLM route (`llm-deepseek`, the native DeepSeek
|
|
66
|
+
* adapter, is — see `dsh-base`'s own `agent-default-model` row) and
|
|
67
|
+
* mounts **dormant** until a `llm-pi-ai:` settings section exists at all,
|
|
68
|
+
* so this override alone never redirected a fresh profile's DEFAULT
|
|
69
|
+
* egress — it only added a selectable route.
|
|
70
|
+
* - **TD-370 follow-up, closed this phase:** `@deepseek-ai/dsh-llm-deepseek`
|
|
71
|
+
* (registry-public, `npm pack`ed and read directly — 0.1.0-rc.8, the
|
|
72
|
+
* current prerelease at the time) IS the adapter `dsh-base`'s
|
|
73
|
+
* `agent-default-model` routes through by default, and its own shipped
|
|
74
|
+
* README CONFIRMS the same live-reload settings seam `llm-pi-ai` has:
|
|
75
|
+
* "the plugin registers the `llm-deepseek` namespace with this same
|
|
76
|
+
* `Config` schema ... so a `llm-deepseek:` section in the user settings
|
|
77
|
+
* document overrides any field without a restart." {@link mergeSettingsYaml}
|
|
78
|
+
* now also merges `llm-deepseek.baseURL`, touching only that one field
|
|
79
|
+
* (same "override base_url on what already resolves" discipline as the
|
|
80
|
+
* `llm-pi-ai` merge and `grokHooks.ts`'s `[model.*]` merge) — this is the
|
|
81
|
+
* one that actually redirects DEFAULT egress. The `llm-pi-ai` merge is
|
|
82
|
+
* kept alongside it (a selectable route remains useful), not replaced.
|
|
83
|
+
* - The `@intutic/gate/dsh` veto contract itself (`tools/pre-execute`,
|
|
84
|
+
* `PreToolDecision`'s real `'deny'`/`'allow'`/`'ask'` shape, Cordis's
|
|
85
|
+
* `waterfall` `next()` semantics) is confirmed from `dsh-tools`'s shipped
|
|
86
|
+
* `.d.ts` — see `packages/gate-js/src/dsh.ts`'s own module doc for the
|
|
87
|
+
* full record, including where the phase brief's prior guess
|
|
88
|
+
* (`agent/pre-step`, `{kind:'reject'}`) was wrong.
|
|
89
|
+
*
|
|
90
|
+
* HLD §3.14 — Harness Onboarding Matrix
|
|
91
|
+
* @module
|
|
92
|
+
*/
|
|
93
|
+
import * as fs from 'node:fs/promises';
|
|
94
|
+
import { existsSync } from 'node:fs';
|
|
95
|
+
import * as path from 'node:path';
|
|
96
|
+
import * as os from 'node:os';
|
|
97
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
98
|
+
import { isMap, isSeq, parseDocument } from 'yaml';
|
|
99
|
+
import { createLogger } from '@intutic/logger';
|
|
100
|
+
const log = createLogger('sync-dsh-hooks');
|
|
101
|
+
/** Mirrors `dsh-home-paths`' `DSH_HOME_ENV`/`DSH_HOME_DIR_NAME` constants. */
|
|
102
|
+
const DSH_HOME_ENV = 'DSH_HOME';
|
|
103
|
+
const DSH_HOME_DIR_NAME = '.dsh';
|
|
104
|
+
/** Mirrors `dsh-app-boot`'s `PROFILES_DIR`/`PROFILE_PATCH_FILENAME`. */
|
|
105
|
+
const PROFILES_DIR = 'profiles';
|
|
106
|
+
const PROFILE_PATCH_FILENAME = 'cordis.patch.yml';
|
|
107
|
+
const SETTINGS_FILENAME = 'settings.yaml';
|
|
108
|
+
/** Stable row id — recognized on every later sync regardless of which of the
|
|
109
|
+
* patch-op shapes (see module doc) a prior write or a human left. */
|
|
110
|
+
const PLUGIN_ROW_ID = 'intutic-governance';
|
|
111
|
+
/** Resolved via a bare `import()` from the profile's own `node_modules` — see
|
|
112
|
+
* {@link mergeProfileDependency}. */
|
|
113
|
+
const PLUGIN_MODULE_NAME = '@intutic/gate/dsh';
|
|
114
|
+
/** The pinned `@intutic/gate` version range written into a profile's
|
|
115
|
+
* `package.json` dependency — dsh's own preview-software stance (stated
|
|
116
|
+
* breaking-changes policy) is matched here the same way Muse Code/Grok Build
|
|
117
|
+
* pin themselves against a *tested* version rather than `latest`. Bump this
|
|
118
|
+
* alongside `packages/gate-js/package.json`'s own `version` field. */
|
|
119
|
+
const INTUTIC_GATE_VERSION_RANGE = '^0.1.0';
|
|
120
|
+
/** `$DSH_HOME` resolution: an explicit env override, else `~/.dsh` — mirrors
|
|
121
|
+
* `dsh-home-paths`' `resolveDshHome()` (this writer has no "explicit
|
|
122
|
+
* configured path" input the way a booted dsh process might). An
|
|
123
|
+
* empty/whitespace-only `$DSH_HOME` is treated as unset, matching that
|
|
124
|
+
* package's own documented behaviour. */
|
|
125
|
+
export function resolveDshHome() {
|
|
126
|
+
const configured = process.env[DSH_HOME_ENV];
|
|
127
|
+
if (configured && configured.trim())
|
|
128
|
+
return configured.trim();
|
|
129
|
+
return path.join(os.homedir(), DSH_HOME_DIR_NAME);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Every EXISTING dsh profile directory on this machine — one containing its
|
|
133
|
+
* own `package.json` (the profile manifest `dsh-app-boot` requires; a bare
|
|
134
|
+
* directory, such as the flat `profiles/node_modules` fallback dsh itself
|
|
135
|
+
* maintains, is not a profile).
|
|
136
|
+
*
|
|
137
|
+
* Deliberately does not invent a profile: dsh's own CLI requires `--profile
|
|
138
|
+
* <name>` on every invocation (confirmed from `dsh`'s shipped `bin.js` — there
|
|
139
|
+
* is no bare "default" profile dsh falls back to), so this writer has no name
|
|
140
|
+
* to seed one under that a user did not already choose. A machine with no
|
|
141
|
+
* profile initialized yet gets governed on the next sync after the user's
|
|
142
|
+
* first `dsh --profile <name>` run creates one — see the TD entry.
|
|
143
|
+
*/
|
|
144
|
+
export async function listDshProfileDirs(dshHome) {
|
|
145
|
+
const profilesRoot = path.join(dshHome, PROFILES_DIR);
|
|
146
|
+
let entries;
|
|
147
|
+
try {
|
|
148
|
+
entries = await fs.readdir(profilesRoot, { withFileTypes: true });
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
return [];
|
|
152
|
+
}
|
|
153
|
+
const out = [];
|
|
154
|
+
for (const entry of entries) {
|
|
155
|
+
if (!entry.isDirectory())
|
|
156
|
+
continue;
|
|
157
|
+
if (existsSync(path.join(profilesRoot, entry.name, 'package.json'))) {
|
|
158
|
+
out.push(path.join(profilesRoot, entry.name));
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return out;
|
|
162
|
+
}
|
|
163
|
+
// ─── Coverage-gap detection (TD-370: the silent no-profile window) ────────
|
|
164
|
+
/** Markers dsh leaves under `$DSH_HOME` even before any profile exists —
|
|
165
|
+
* mirrors `tools/cli/src/harness/dsh.ts`'s own `detect()` list, minus the
|
|
166
|
+
* `profiles` marker itself (which is what "zero profiles" already answers
|
|
167
|
+
* for {@link detectDshCoverageGap} below). */
|
|
168
|
+
const DSH_HOME_PRESENCE_MARKERS = ['settings.yaml', '.credentials.yaml'];
|
|
169
|
+
/** Is `dsh` (the binary) reachable on `$PATH`? Best-effort, synchronous —
|
|
170
|
+
* same PATH-scan convention `dsh.ts`'s adapter `detect()` uses. */
|
|
171
|
+
function isDshOnPath() {
|
|
172
|
+
const pathDirs = (process.env.PATH ?? '').split(process.platform === 'win32' ? ';' : ':');
|
|
173
|
+
for (const dir of pathDirs) {
|
|
174
|
+
if (dir && existsSync(path.join(dir, 'dsh')))
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Detects TD-370's "silent no-profile window": the stretch between `intutic
|
|
181
|
+
* connect` and the user's first `dsh --profile <name>` run, during which dsh
|
|
182
|
+
* is entirely ungoverned — {@link writeDshHooks} is a documented no-op with
|
|
183
|
+
* nothing to register into yet — and, before this function existed, nothing
|
|
184
|
+
* made that visible.
|
|
185
|
+
*
|
|
186
|
+
* A pure detector, deliberately: no logging, no side effect, so it stays
|
|
187
|
+
* trivially unit-testable. `watcher/settingsGuard.ts`'s `warnIfDshCoverageGap`
|
|
188
|
+
* is the side-effecting caller that actually logs the gap.
|
|
189
|
+
*/
|
|
190
|
+
export async function detectDshCoverageGap(dshHome = resolveDshHome()) {
|
|
191
|
+
const profileCount = (await listDshProfileDirs(dshHome)).length;
|
|
192
|
+
if (profileCount > 0)
|
|
193
|
+
return { dshDetected: true, profileCount, gap: false };
|
|
194
|
+
const dshDetected = DSH_HOME_PRESENCE_MARKERS.some((marker) => existsSync(path.join(dshHome, marker))) || isDshOnPath();
|
|
195
|
+
return { dshDetected, profileCount: 0, gap: dshDetected };
|
|
196
|
+
}
|
|
197
|
+
// ─── cordis.patch.yml: plugin row registration ────────────────────────────
|
|
198
|
+
function buildDesiredRow(workspaceRoot, workspaceId) {
|
|
199
|
+
return {
|
|
200
|
+
id: PLUGIN_ROW_ID,
|
|
201
|
+
name: PLUGIN_MODULE_NAME,
|
|
202
|
+
config: { workspaceId, repoRoot: workspaceRoot },
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
/** Finds this writer's own row wherever it lives in a parsed patch-list
|
|
206
|
+
* (either an `insert:`-wrapped block it wrote itself, or a bare `{id, ...}`
|
|
207
|
+
* update-in-place row a human or an older writer left) — see module doc. */
|
|
208
|
+
function findOwnRow(patchList) {
|
|
209
|
+
for (let i = 0; i < patchList.length; i++) {
|
|
210
|
+
const item = patchList[i];
|
|
211
|
+
if (!item || typeof item !== 'object')
|
|
212
|
+
continue;
|
|
213
|
+
const obj = item;
|
|
214
|
+
if (Array.isArray(obj.insert)) {
|
|
215
|
+
const inner = obj.insert.find((r) => r && typeof r === 'object' && r.id === PLUGIN_ROW_ID);
|
|
216
|
+
if (inner)
|
|
217
|
+
return { index: i, row: inner };
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
if (obj.id === PLUGIN_ROW_ID)
|
|
221
|
+
return { index: i, row: obj };
|
|
222
|
+
}
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Append-only fallback for a `cordis.patch.yml` that does not parse as YAML
|
|
227
|
+
* at all. Mirrors `injectGooseAppendOnly`'s exact reasoning: a parser that
|
|
228
|
+
* cannot safely represent a malformed file cannot safely round-trip it
|
|
229
|
+
* either, so this never touches (or even parses) anything else in the file.
|
|
230
|
+
* Best-effort de-dup on the literal row id substring — a false "already
|
|
231
|
+
* present" here just means the fallback path stays a fallback for one more
|
|
232
|
+
* sync cycle rather than double-inserting; it does not corrupt anything.
|
|
233
|
+
*/
|
|
234
|
+
async function mergeProfilePatchAppendOnly(patchPath, existingYaml, desiredRow) {
|
|
235
|
+
if (existingYaml.includes(`id: ${PLUGIN_ROW_ID}`))
|
|
236
|
+
return;
|
|
237
|
+
const config = desiredRow.config;
|
|
238
|
+
const block = [
|
|
239
|
+
'',
|
|
240
|
+
'# Intutic governance plugin — auto-appended (fallback: this file did not parse as YAML).',
|
|
241
|
+
'- insert:',
|
|
242
|
+
` - id: ${PLUGIN_ROW_ID}`,
|
|
243
|
+
` name: ${JSON.stringify(desiredRow.name)}`,
|
|
244
|
+
' config:',
|
|
245
|
+
` workspaceId: ${JSON.stringify(config.workspaceId ?? '')}`,
|
|
246
|
+
` repoRoot: ${JSON.stringify(config.repoRoot ?? '')}`,
|
|
247
|
+
].join('\n');
|
|
248
|
+
const text = (existingYaml || '[]').trimEnd() + '\n' + block + '\n';
|
|
249
|
+
await fs.mkdir(path.dirname(patchPath), { recursive: true });
|
|
250
|
+
const tmp = patchPath + '.intutic-tmp';
|
|
251
|
+
await fs.writeFile(tmp, text, 'utf-8');
|
|
252
|
+
await fs.rename(tmp, patchPath);
|
|
253
|
+
log.info({ action: 'dsh_patch_written', path: patchPath, mode: 'append_only_fallback' }, 'dsh cordis.patch.yml updated (append-only fallback)');
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Structurally merges the Intutic governance plugin row into one profile's
|
|
257
|
+
* `cordis.patch.yml`, via the `yaml` package's `parseDocument`/`setIn` — the
|
|
258
|
+
* same "parse structurally, write-if-changed, preserve unrelated content,
|
|
259
|
+
* fall back to append-only on unparseable input" discipline `injectGoose`
|
|
260
|
+
* (`mcpAutoWrite.ts`) established for YAML in this codebase, reusing the same
|
|
261
|
+
* dependency rather than inventing a second approach.
|
|
262
|
+
*/
|
|
263
|
+
export async function mergeProfilePatch(profileDir, workspaceRoot, workspaceId) {
|
|
264
|
+
const patchPath = path.join(profileDir, PROFILE_PATCH_FILENAME);
|
|
265
|
+
let existingYaml = '';
|
|
266
|
+
try {
|
|
267
|
+
existingYaml = await fs.readFile(patchPath, 'utf-8');
|
|
268
|
+
}
|
|
269
|
+
catch {
|
|
270
|
+
// No cordis.patch.yml yet — `initProfile()` always seeds an empty `[]`
|
|
271
|
+
// one, but a profile this writer discovered some other way might not
|
|
272
|
+
// have it. Falls through with '' so a fresh file is written below.
|
|
273
|
+
}
|
|
274
|
+
const desiredRow = buildDesiredRow(workspaceRoot, workspaceId);
|
|
275
|
+
let doc;
|
|
276
|
+
try {
|
|
277
|
+
doc = parseDocument(existingYaml.trim() ? existingYaml : '[]');
|
|
278
|
+
if (doc.errors.length > 0)
|
|
279
|
+
throw doc.errors[0];
|
|
280
|
+
}
|
|
281
|
+
catch (err) {
|
|
282
|
+
log.warn({ action: 'dsh_patch_unparseable', path: patchPath, err: err.message }, 'dsh cordis.patch.yml did not parse as YAML — falling back to append-only text injection');
|
|
283
|
+
await mergeProfilePatchAppendOnly(patchPath, existingYaml, desiredRow);
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
if (doc.contents == null || !isSeq(doc.contents)) {
|
|
287
|
+
// `cordis.patch.yml` exists but its root isn't a sequence (e.g. `null`,
|
|
288
|
+
// a bare scalar, a mapping) — nothing safe to preserve there; the
|
|
289
|
+
// documented shape (PROFILE_PATCH_TEMPLATE, confirmed from
|
|
290
|
+
// dsh-app-boot's shipped source) is "a top-level YAML array", so this
|
|
291
|
+
// replaces the root with a fresh empty one, same as injectGoose's
|
|
292
|
+
// `mcp: null` handling.
|
|
293
|
+
doc.contents = doc.createNode([]);
|
|
294
|
+
}
|
|
295
|
+
const patchList = doc.toJS();
|
|
296
|
+
const found = findOwnRow(patchList);
|
|
297
|
+
const desiredNode = doc.createNode({ insert: [desiredRow] });
|
|
298
|
+
let changed = false;
|
|
299
|
+
if (found === null) {
|
|
300
|
+
doc.addIn([], desiredNode);
|
|
301
|
+
changed = true;
|
|
302
|
+
}
|
|
303
|
+
else if (!isDeepStrictEqual(found.row, desiredRow)) {
|
|
304
|
+
// Replace the WHOLE item at that index with our own self-contained
|
|
305
|
+
// `insert:` block, regardless of which shape the existing row was in —
|
|
306
|
+
// this writer only ever emits the `insert:`-wrapped shape, so a later
|
|
307
|
+
// sync always finds (and safely replaces) exactly this shape.
|
|
308
|
+
doc.setIn([found.index], desiredNode);
|
|
309
|
+
changed = true;
|
|
310
|
+
}
|
|
311
|
+
if (!changed)
|
|
312
|
+
return;
|
|
313
|
+
await fs.mkdir(profileDir, { recursive: true });
|
|
314
|
+
const tmp = patchPath + '.intutic-tmp';
|
|
315
|
+
await fs.writeFile(tmp, doc.toString(), 'utf-8');
|
|
316
|
+
await fs.rename(tmp, patchPath);
|
|
317
|
+
log.info({ action: 'dsh_patch_written', path: patchPath, mode: 'yaml' }, 'dsh cordis.patch.yml updated (structural YAML edit)');
|
|
318
|
+
}
|
|
319
|
+
// ─── profile package.json: @intutic/gate dependency ───────────────────────
|
|
320
|
+
/**
|
|
321
|
+
* Ensures `@intutic/gate` is declared in the profile's own `package.json`
|
|
322
|
+
* `dependencies` — the "out-of-tree plugin" mechanism `dsh-app-boot`'s
|
|
323
|
+
* `profile.d.ts` documents (a profile's `node_modules` is pnpm-managed).
|
|
324
|
+
*
|
|
325
|
+
* This writer declares the dependency but does NOT run `pnpm install` in the
|
|
326
|
+
* profile directory — the daemon has no general "run an arbitrary package
|
|
327
|
+
* manager in a directory it does not own" capability, and every other
|
|
328
|
+
* writer in this codebase only ever writes config, never invokes a package
|
|
329
|
+
* manager on the user's behalf. Until the user (or their own tooling) runs
|
|
330
|
+
* one, the `cordis.patch.yml` row this module also writes resolves to a
|
|
331
|
+
* MISSING module and dsh's own loader reports that row's activation failed
|
|
332
|
+
* (`assertEntriesActivated`, confirmed from `dsh-app-boot`'s exports) rather
|
|
333
|
+
* than silently no-op — a fail-LOUD gap, not a fail-open one, but a real
|
|
334
|
+
* manual step nonetheless. See the TD entry and `apps/docs/integrations/dsh.md`.
|
|
335
|
+
*/
|
|
336
|
+
export async function mergeProfileDependency(profileDir) {
|
|
337
|
+
const manifestPath = path.join(profileDir, 'package.json');
|
|
338
|
+
let manifest;
|
|
339
|
+
try {
|
|
340
|
+
manifest = JSON.parse(await fs.readFile(manifestPath, 'utf-8'));
|
|
341
|
+
}
|
|
342
|
+
catch {
|
|
343
|
+
// No manifest — an existing profile always has one (dsh-app-boot
|
|
344
|
+
// requires it), so this is defensive only; nothing to merge into yet.
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
const deps = (manifest.dependencies && typeof manifest.dependencies === 'object'
|
|
348
|
+
? manifest.dependencies
|
|
349
|
+
: {});
|
|
350
|
+
if (deps['@intutic/gate'] === INTUTIC_GATE_VERSION_RANGE)
|
|
351
|
+
return;
|
|
352
|
+
manifest.dependencies = { ...deps, '@intutic/gate': INTUTIC_GATE_VERSION_RANGE };
|
|
353
|
+
const tmp = manifestPath + '.intutic-tmp';
|
|
354
|
+
await fs.writeFile(tmp, JSON.stringify(manifest, null, 2) + '\n', 'utf-8');
|
|
355
|
+
await fs.rename(tmp, manifestPath);
|
|
356
|
+
log.info({ action: 'dsh_dependency_written', path: manifestPath }, 'dsh profile package.json dependency updated');
|
|
357
|
+
}
|
|
358
|
+
// ─── settings.yaml: llm-deepseek (default route) + llm-pi-ai (selectable) ──
|
|
359
|
+
/** dsh's ACTUAL DEFAULT LLM route — `@deepseek-ai/dsh-llm-deepseek`, per
|
|
360
|
+
* `dsh-base`'s own `agent-default-model` row. See module doc for the
|
|
361
|
+
* README confirmation that a `llm-deepseek:` settings section overrides
|
|
362
|
+
* this adapter's config live, no restart. */
|
|
363
|
+
const DEFAULT_LLM_SECTION = 'llm-deepseek';
|
|
364
|
+
/** A SELECTABLE route, mounts dormant until this section exists at all —
|
|
365
|
+
* see module doc. Kept alongside the default-route merge, not replaced. */
|
|
366
|
+
const SELECTABLE_LLM_SECTION = 'llm-pi-ai';
|
|
367
|
+
async function mergeSettingsYamlAppendOnly(settingsPath, existingYaml, proxyUrl) {
|
|
368
|
+
const blocks = [];
|
|
369
|
+
if (!existingYaml.includes(`${DEFAULT_LLM_SECTION}:`)) {
|
|
370
|
+
blocks.push('', '# Intutic proxy route — auto-appended (fallback: this file did not parse as YAML).', "# Redirects dsh's DEFAULT LLM route (llm-deepseek, the native DeepSeek", "# adapter — see dsh-base's agent-default-model row) through the proxy.", `${DEFAULT_LLM_SECTION}:`, ` baseURL: ${JSON.stringify(proxyUrl)}`);
|
|
371
|
+
}
|
|
372
|
+
if (!existingYaml.includes(`${SELECTABLE_LLM_SECTION}:`)) {
|
|
373
|
+
blocks.push('', '# Intutic proxy route — auto-appended (fallback: this file did not parse as YAML).', `${SELECTABLE_LLM_SECTION}:`, ' providers:', ' intutic:', ' displayName: Intutic Governance Proxy', ' api: openai-completions', ` baseURL: ${JSON.stringify(proxyUrl)}`);
|
|
374
|
+
}
|
|
375
|
+
if (blocks.length === 0)
|
|
376
|
+
return;
|
|
377
|
+
const text = existingYaml.trimEnd() + '\n' + blocks.join('\n') + '\n';
|
|
378
|
+
await fs.mkdir(path.dirname(settingsPath), { recursive: true });
|
|
379
|
+
const tmp = settingsPath + '.intutic-tmp';
|
|
380
|
+
await fs.writeFile(tmp, text, 'utf-8');
|
|
381
|
+
await fs.rename(tmp, settingsPath);
|
|
382
|
+
log.info({ action: 'dsh_settings_written', path: settingsPath, mode: 'append_only_fallback' }, 'dsh settings.yaml updated (append-only fallback)');
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Structurally merges the Intutic proxy into TWO `settings.yaml` sections:
|
|
386
|
+
*
|
|
387
|
+
* - `llm-deepseek.baseURL` — dsh's ACTUAL DEFAULT LLM route (CONFIRMED
|
|
388
|
+
* against `@deepseek-ai/dsh-llm-deepseek`'s own shipped README this
|
|
389
|
+
* phase — see module doc). Only `baseURL` is touched; `apiKeyEnv`,
|
|
390
|
+
* `thinking`, `models`, etc. round-trip untouched, the same
|
|
391
|
+
* "override base_url on what already resolves, never invent the rest of
|
|
392
|
+
* the section" discipline `grokHooks.ts`'s `[model.*]` merge uses. This
|
|
393
|
+
* is the merge that actually redirects DEFAULT egress — see the TD entry
|
|
394
|
+
* for why the `llm-pi-ai` merge alone (below) never did.
|
|
395
|
+
* - `llm-pi-ai.providers.intutic` — a SELECTABLE route (mounts dormant
|
|
396
|
+
* until this section exists at all — see module doc). Kept alongside the
|
|
397
|
+
* new default-route merge: a user, or a future sync, can still point a
|
|
398
|
+
* model at it explicitly.
|
|
399
|
+
*
|
|
400
|
+
* Both overrides preserve every other provider and every other top-level
|
|
401
|
+
* section untouched.
|
|
402
|
+
*/
|
|
403
|
+
export async function mergeSettingsYaml(dshHome, proxyUrl) {
|
|
404
|
+
const settingsPath = path.join(dshHome, SETTINGS_FILENAME);
|
|
405
|
+
let existingYaml = '';
|
|
406
|
+
try {
|
|
407
|
+
existingYaml = await fs.readFile(settingsPath, 'utf-8');
|
|
408
|
+
}
|
|
409
|
+
catch {
|
|
410
|
+
// No settings.yaml yet — falls through with '' so a fresh file is
|
|
411
|
+
// written below.
|
|
412
|
+
}
|
|
413
|
+
let doc;
|
|
414
|
+
try {
|
|
415
|
+
doc = parseDocument(existingYaml.trim() ? existingYaml : '{}');
|
|
416
|
+
if (doc.errors.length > 0)
|
|
417
|
+
throw doc.errors[0];
|
|
418
|
+
}
|
|
419
|
+
catch (err) {
|
|
420
|
+
log.warn({ action: 'dsh_settings_unparseable', path: settingsPath, err: err.message }, 'dsh settings.yaml did not parse as YAML — falling back to append-only text injection');
|
|
421
|
+
await mergeSettingsYamlAppendOnly(settingsPath, existingYaml, proxyUrl);
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
if (doc.contents == null || !isMap(doc.contents)) {
|
|
425
|
+
doc.contents = doc.createNode({});
|
|
426
|
+
}
|
|
427
|
+
// Defensive per-level checks: `setIn` auto-vivifies a MISSING intermediate
|
|
428
|
+
// key as a map, but throws on an EXISTING non-collection value at that key
|
|
429
|
+
// (confirmed empirically against the `yaml` package) — same failure mode
|
|
430
|
+
// `injectGoose` guards for `mcp: null`. Reset only the offending level,
|
|
431
|
+
// never the whole document.
|
|
432
|
+
for (const keyPath of [
|
|
433
|
+
[DEFAULT_LLM_SECTION],
|
|
434
|
+
[SELECTABLE_LLM_SECTION],
|
|
435
|
+
[SELECTABLE_LLM_SECTION, 'providers'],
|
|
436
|
+
]) {
|
|
437
|
+
const node = doc.getIn(keyPath);
|
|
438
|
+
if (node !== undefined && !isMap(node)) {
|
|
439
|
+
doc.setIn(keyPath, {});
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
const settingsJs = doc.toJS();
|
|
443
|
+
let changed = false;
|
|
444
|
+
// ── llm-deepseek: DEFAULT route ──────────────────────────────────────
|
|
445
|
+
const deepseekSection = settingsJs[DEFAULT_LLM_SECTION] ?? {};
|
|
446
|
+
const desiredDeepseekSection = { ...deepseekSection, baseURL: proxyUrl };
|
|
447
|
+
if (!isDeepStrictEqual(deepseekSection, desiredDeepseekSection)) {
|
|
448
|
+
doc.setIn([DEFAULT_LLM_SECTION], desiredDeepseekSection);
|
|
449
|
+
changed = true;
|
|
450
|
+
}
|
|
451
|
+
// ── llm-pi-ai: SELECTABLE route ──────────────────────────────────────
|
|
452
|
+
const llmPiAi = settingsJs[SELECTABLE_LLM_SECTION] ?? {};
|
|
453
|
+
const providers = llmPiAi.providers ?? {};
|
|
454
|
+
const existingRoute = providers.intutic ?? {};
|
|
455
|
+
const desiredRoute = {
|
|
456
|
+
...existingRoute,
|
|
457
|
+
displayName: 'Intutic Governance Proxy',
|
|
458
|
+
api: 'openai-completions',
|
|
459
|
+
baseURL: proxyUrl,
|
|
460
|
+
};
|
|
461
|
+
if (!isDeepStrictEqual(existingRoute, desiredRoute)) {
|
|
462
|
+
doc.setIn([SELECTABLE_LLM_SECTION, 'providers', 'intutic'], desiredRoute);
|
|
463
|
+
changed = true;
|
|
464
|
+
}
|
|
465
|
+
if (!changed)
|
|
466
|
+
return;
|
|
467
|
+
await fs.mkdir(dshHome, { recursive: true });
|
|
468
|
+
const tmp = settingsPath + '.intutic-tmp';
|
|
469
|
+
await fs.writeFile(tmp, doc.toString(), 'utf-8');
|
|
470
|
+
await fs.rename(tmp, settingsPath);
|
|
471
|
+
log.info({ action: 'dsh_settings_written', path: settingsPath, mode: 'yaml' }, 'dsh settings.yaml updated (structural YAML edit)');
|
|
472
|
+
}
|
|
473
|
+
// ─── INSTALL.md: the manual pnpm-install / `dsh plugin add` step ──────────
|
|
474
|
+
/**
|
|
475
|
+
* `$DSH_HOME/INSTALL.md` — same purpose and shape as `n8nHooks.ts`'s
|
|
476
|
+
* `buildInstallMd`: this writer declares `@intutic/gate` in each profile's
|
|
477
|
+
* `package.json` (see {@link mergeProfileDependency}) but cannot run a
|
|
478
|
+
* package manager in a directory it does not own, so the row it also writes
|
|
479
|
+
* into `cordis.patch.yml` resolves to a MISSING module until a human — or
|
|
480
|
+
* dsh's own forwarding command — installs it. See the TD entry.
|
|
481
|
+
*/
|
|
482
|
+
function buildDshInstallMd(profileNames) {
|
|
483
|
+
const profileLines = profileNames.length > 0
|
|
484
|
+
? profileNames.map((name) => `- \`${name}\` — run: \`dsh plugin --profile ${name} add @intutic/gate\``).join('\n')
|
|
485
|
+
: '(no dsh profiles are registered yet)';
|
|
486
|
+
return `# Intutic governance for dsh — installation
|
|
487
|
+
|
|
488
|
+
Auto-generated by the Intutic sync-daemon. One artifact, one manual step.
|
|
489
|
+
|
|
490
|
+
## The blocking gate is registered, but not yet activated
|
|
491
|
+
|
|
492
|
+
Every sync writes the \`intutic-governance\` row into each profile's
|
|
493
|
+
\`cordis.patch.yml\` (naming \`@intutic/gate/dsh\`) and declares
|
|
494
|
+
\`@intutic/gate\` in that profile's \`package.json\` \`dependencies\` — but this
|
|
495
|
+
daemon has no general capability to run a package manager in a directory it
|
|
496
|
+
does not own, so the dependency itself is never installed by this writer.
|
|
497
|
+
Until it is, dsh's own Cordis loader reports that row's activation as
|
|
498
|
+
FAILED (fail-loud, not silent — \`dsh-app-boot\`'s \`assertEntriesActivated\`)
|
|
499
|
+
rather than silently skipping it, but it also means nothing is governed yet.
|
|
500
|
+
|
|
501
|
+
Finish activation with dsh's own forwarding command, once per profile:
|
|
502
|
+
|
|
503
|
+
${profileLines}
|
|
504
|
+
|
|
505
|
+
That is equivalent to \`cd $DSH_HOME/profiles/<name> && pnpm install\` —
|
|
506
|
+
either works; the forwarding command is dsh's own documented shortcut for
|
|
507
|
+
exactly this case.
|
|
508
|
+
|
|
509
|
+
## Default LLM egress needs no manual step
|
|
510
|
+
|
|
511
|
+
The Intutic proxy is merged into \`settings.yaml\`'s \`llm-deepseek\` (dsh's
|
|
512
|
+
default LLM route) and \`llm-pi-ai\` (a selectable route) sections on every
|
|
513
|
+
sync — both take effect on dsh's next request without a restart.
|
|
514
|
+
`;
|
|
515
|
+
}
|
|
516
|
+
/** Write-if-changed, atomic rename — same discipline every other writer in
|
|
517
|
+
* this file follows. Regenerated every sync so the profile list here never
|
|
518
|
+
* goes stale. */
|
|
519
|
+
async function writeDshInstallMd(dshHome, profileNames) {
|
|
520
|
+
const installPath = path.join(dshHome, 'INSTALL.md');
|
|
521
|
+
const content = buildDshInstallMd(profileNames);
|
|
522
|
+
let existing = '';
|
|
523
|
+
try {
|
|
524
|
+
existing = await fs.readFile(installPath, 'utf-8');
|
|
525
|
+
}
|
|
526
|
+
catch {
|
|
527
|
+
// First write.
|
|
528
|
+
}
|
|
529
|
+
if (existing === content)
|
|
530
|
+
return;
|
|
531
|
+
await fs.mkdir(dshHome, { recursive: true });
|
|
532
|
+
const tmp = installPath + '.intutic-tmp';
|
|
533
|
+
await fs.writeFile(tmp, content, 'utf-8');
|
|
534
|
+
await fs.rename(tmp, installPath);
|
|
535
|
+
log.info({ action: 'dsh_install_md_written', path: installPath }, 'dsh INSTALL.md updated');
|
|
536
|
+
}
|
|
537
|
+
// ─── Public API ────────────────────────────────────────────────────────────
|
|
538
|
+
/**
|
|
539
|
+
* Register the Intutic governance plugin against every existing dsh profile
|
|
540
|
+
* on this machine, and merge the Intutic proxy into `settings.yaml`'s
|
|
541
|
+
* `llm-deepseek` (default) and `llm-pi-ai` (selectable) routes.
|
|
542
|
+
*
|
|
543
|
+
* A no-op (logged, not an error) when `$DSH_HOME/profiles` does not exist
|
|
544
|
+
* yet — dsh has not been run with any `--profile <name>` on this machine, so
|
|
545
|
+
* there is nothing to register into; the next sync cycle picks it up once
|
|
546
|
+
* the user's first `dsh` run creates one. Safe to call every cycle: every
|
|
547
|
+
* merge below is write-if-changed.
|
|
548
|
+
*
|
|
549
|
+
* @param workspaceRoot - Absolute workspace root (stored in the plugin row's
|
|
550
|
+
* `config.repoRoot`).
|
|
551
|
+
* @param proxyUrl - Intutic proxy URL, merged into settings.yaml.
|
|
552
|
+
* @param workspaceId - Workspace ID, stored in the plugin row's config.
|
|
553
|
+
*/
|
|
554
|
+
export async function writeDshHooks(workspaceRoot, proxyUrl, workspaceId = '') {
|
|
555
|
+
const dshHome = resolveDshHome();
|
|
556
|
+
const profileDirs = await listDshProfileDirs(dshHome);
|
|
557
|
+
if (profileDirs.length === 0) {
|
|
558
|
+
log.debug({ action: 'dsh_skip', dshHome }, 'No dsh profiles found — skipping (nothing to register into yet)');
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
for (const profileDir of profileDirs) {
|
|
562
|
+
await mergeProfilePatch(profileDir, workspaceRoot, workspaceId);
|
|
563
|
+
await mergeProfileDependency(profileDir);
|
|
564
|
+
log.info({ action: 'dsh_profile_written', profile: path.basename(profileDir) }, 'dsh profile governance plugin registered');
|
|
565
|
+
}
|
|
566
|
+
await mergeSettingsYaml(dshHome, proxyUrl);
|
|
567
|
+
await writeDshInstallMd(dshHome, profileDirs.map((d) => path.basename(d)));
|
|
568
|
+
}
|
|
569
|
+
//# sourceMappingURL=dshHooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dshHooks.js","sourceRoot":"","sources":["../../src/harness/dshHooks.ts"],"names":[],"mappings":"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"}
|