dsh-gitbash-shell 0.24.4 → 0.25.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 +503 -0
- package/README.md +46 -3
- package/README_EN.md +62 -0
- package/dsh.plugin.json +1 -1
- package/package.json +2 -1
- package/src/client.js +123 -3
- package/src/index.js +253 -44
package/src/index.js
CHANGED
|
@@ -95,6 +95,36 @@ const MARKER_FILE = '.plugin-managed.json'
|
|
|
95
95
|
/** Default preset ids this plugin materializes, in roster order (configurable). */
|
|
96
96
|
export const PRESET_IDS = ['standard-gitbash', 'minimal-gitbash', 'code-gitbash', 'cordis-gitbash']
|
|
97
97
|
|
|
98
|
+
/**
|
|
99
|
+
* The variant dsh-ptc-cordis-preset already covers while cooperating: its
|
|
100
|
+
* `PTC 创造模式` is materialized against Git Bash too, so our own
|
|
101
|
+
* `创造模式 · Git Bash` describes the same mode (their issue #7).
|
|
102
|
+
*/
|
|
103
|
+
export const PEER_COVERED_PRESET_ID = 'cordis-gitbash'
|
|
104
|
+
|
|
105
|
+
/** Service dsh-ptc-cordis-preset publishes: `{ id, gitBashActive }`. */
|
|
106
|
+
export const PEER_CAPABILITY = 'ptcCordisPreset'
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* The roster this plugin serves: the configured list, minus the variant a peer
|
|
110
|
+
* already covers. Two independent facts must BOTH hold before anything is
|
|
111
|
+
* dropped — the user's `suppressPeerCordis` switch (row Config, default OFF)
|
|
112
|
+
* and the peer actually reporting a Git Bash-materialized preset. A peer that
|
|
113
|
+
* is absent, inactive, or mounted later than this row therefore never costs
|
|
114
|
+
* the user a variant, and the default keeps the historical four-variant roster
|
|
115
|
+
* byte for byte.
|
|
116
|
+
* @param {string[]} configured - the row's `presets` list (empty/absent = default).
|
|
117
|
+
* @param {object} [options] - live decision inputs.
|
|
118
|
+
* @param {boolean} [options.suppress] - the live `suppressPeerCordis` switch.
|
|
119
|
+
* @param {boolean} [options.peerGitBash] - the peer capability's `gitBashActive`.
|
|
120
|
+
* @returns {string[]} the ids to register (or materialize), in configured order.
|
|
121
|
+
*/
|
|
122
|
+
export function effectivePresetIds(configured, { suppress, peerGitBash } = {}) {
|
|
123
|
+
const list = Array.isArray(configured) && configured.length > 0 ? [...configured] : [...PRESET_IDS]
|
|
124
|
+
if (suppress !== true || peerGitBash !== true) return list
|
|
125
|
+
return list.filter((id) => id !== PEER_COVERED_PRESET_ID)
|
|
126
|
+
}
|
|
127
|
+
|
|
98
128
|
/** Git Bash binary default — must match src/shell.js. */
|
|
99
129
|
const DEFAULT_GIT_BASH = 'C:/Program Files/Git/bin/bash.exe'
|
|
100
130
|
|
|
@@ -721,6 +751,16 @@ export const Config = Schema === null ? undefined : Schema.object({
|
|
|
721
751
|
gitAutocrlf: live(Schema.boolean().default(true)),
|
|
722
752
|
bashPath: live(Schema.string().default('')),
|
|
723
753
|
adoptSidebar: live(Schema.boolean().default(true)),
|
|
754
|
+
/**
|
|
755
|
+
* Dedupe switch against dsh-ptc-cordis-preset (their issue #7, v0.25.0):
|
|
756
|
+
* ON while that plugin is installed AND materializing its `PTC 创造模式`
|
|
757
|
+
* against Git Bash drops OUR `创造模式 · Git Bash` from the roster, because
|
|
758
|
+
* the two describe the same mode. Default OFF — the historical four-variant
|
|
759
|
+
* roster is unchanged until asked for. The same state is rendered on their
|
|
760
|
+
* settings card too (their card binds this row through configForms), so
|
|
761
|
+
* changing it on either side changes it here.
|
|
762
|
+
*/
|
|
763
|
+
suppressPeerCordis: live(Schema.boolean().default(false)),
|
|
724
764
|
})
|
|
725
765
|
|
|
726
766
|
/** Read one Config value across eras: Volatile ref (>= 0.1.7) or plain value. */
|
|
@@ -735,7 +775,7 @@ export function valueOf(value) {
|
|
|
735
775
|
* reading the registered namespace through the settings service.
|
|
736
776
|
* @param {object} ctx - the plugin's mounting context.
|
|
737
777
|
* @param {object|undefined} config - apply()'s resolved Config.
|
|
738
|
-
* @returns {{ dialect: () => object, posix: () => boolean, adoptSidebar: () => boolean }}
|
|
778
|
+
* @returns {{ dialect: () => object, posix: () => boolean, adoptSidebar: () => boolean, suppressPeerCordis: () => boolean }}
|
|
739
779
|
*/
|
|
740
780
|
function makeLiveReader(ctx, config) {
|
|
741
781
|
let legacy = false
|
|
@@ -762,6 +802,8 @@ function makeLiveReader(ctx, config) {
|
|
|
762
802
|
dialect,
|
|
763
803
|
posix: () => dialect().posixPaths === true,
|
|
764
804
|
adoptSidebar: () => dialect().adoptSidebar !== false,
|
|
805
|
+
// Default OFF on both eras: only an explicit true asks for deduplication.
|
|
806
|
+
suppressPeerCordis: () => (legacy || !hasConfig ? readSuppressPeerCordis(ctx) : valueOf(config.suppressPeerCordis) === true),
|
|
765
807
|
}
|
|
766
808
|
}
|
|
767
809
|
|
|
@@ -859,6 +901,52 @@ export function readAdoptSidebar(ctxLike) {
|
|
|
859
901
|
}
|
|
860
902
|
}
|
|
861
903
|
|
|
904
|
+
/**
|
|
905
|
+
* Read the peer-dedupe switch (v0.25.0, default OFF) from the OLD era's
|
|
906
|
+
* registered namespace — on dsh >= 0.1.7 the row Config is the surface and
|
|
907
|
+
* `makeLiveReader` reads it directly. Never throws.
|
|
908
|
+
*/
|
|
909
|
+
export function readSuppressPeerCordis(ctxLike) {
|
|
910
|
+
try {
|
|
911
|
+
const settings = ctxLike && typeof ctxLike.get === 'function' ? ctxLike.get('settings') : undefined
|
|
912
|
+
const value = settings && typeof settings.get === 'function' ? settings.get(SETTINGS_NAMESPACE) : undefined
|
|
913
|
+
return !!(value && value.suppressPeerCordis === true)
|
|
914
|
+
} catch {
|
|
915
|
+
return false
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
/**
|
|
920
|
+
* Bounded probe for dsh-ptc-cordis-preset's coverage capability. The OLD era
|
|
921
|
+
* has no registration registry to watch, and rows mount concurrently, so poll
|
|
922
|
+
* briefly when the service is not there yet; a short absence means the peer is
|
|
923
|
+
* not installed (or is older than 0.14.0) and every configured variant stays.
|
|
924
|
+
* @param {object} ctx - the plugin's mounting context.
|
|
925
|
+
* @param {number} [timeoutMs] - total wait before giving up.
|
|
926
|
+
* @param {number} [intervalMs] - poll interval.
|
|
927
|
+
* @returns {Promise<boolean>} the peer's `gitBashActive`, false when unknown.
|
|
928
|
+
*/
|
|
929
|
+
export async function detectPeerCoverage(ctx, timeoutMs = 1000, intervalMs = 25) {
|
|
930
|
+
try {
|
|
931
|
+
const probe = () => {
|
|
932
|
+
const capability = ctx.get(PEER_CAPABILITY)
|
|
933
|
+
return capability === null || capability === undefined ? undefined : capability
|
|
934
|
+
}
|
|
935
|
+
let capability = probe()
|
|
936
|
+
if (capability === undefined) {
|
|
937
|
+
const deadline = Date.now() + timeoutMs
|
|
938
|
+
while (Date.now() < deadline) {
|
|
939
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs))
|
|
940
|
+
capability = probe()
|
|
941
|
+
if (capability !== undefined) break
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
return capability?.gitBashActive === true
|
|
945
|
+
} catch {
|
|
946
|
+
return false
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
|
|
862
950
|
// Windows absolute path -> MSYS drive-root form, for rewriting PROSE in place
|
|
863
951
|
// (v0.10.0). Quoted spaced paths ("C:\Program Files\Git") are matched whole; a bare
|
|
864
952
|
// path stops at a closing punctuation and crosses a space ONLY into a token that
|
|
@@ -1166,6 +1254,36 @@ const translateEnvCache = new Map()
|
|
|
1166
1254
|
* (the default install plus every PATH entry) and accepts a root only when
|
|
1167
1255
|
* <root>/usr/bin exists, which excludes the WSL bash shim in WindowsApps.
|
|
1168
1256
|
*/
|
|
1257
|
+
/**
|
|
1258
|
+
* One dispatch's path-bearing arguments in the host dialect (pure). The
|
|
1259
|
+
* tools/execute wrapper's decision surface, exported so a test can drive the
|
|
1260
|
+
* whole argument face without a Windows host — the shape issue #8 escaped
|
|
1261
|
+
* through: pure helpers were covered, the wiring that feeds them was not.
|
|
1262
|
+
* @param {{ name?: string, arguments?: object }} exec - the dispatch envelope.
|
|
1263
|
+
* @param {object} dialect - live dialect switches (posixPaths/globSplit/codePaths).
|
|
1264
|
+
* @param {object|null} env - mount table (buildTranslateEnv), null when mounts are off.
|
|
1265
|
+
* @returns {object|undefined} the translated arguments (same reference when untouched).
|
|
1266
|
+
*/
|
|
1267
|
+
export function translateDispatch(exec, dialect, env) {
|
|
1268
|
+
if (!exec || !exec.arguments || typeof exec.arguments !== 'object') return exec?.arguments
|
|
1269
|
+
let translated = translatePathArguments(exec.arguments, env)
|
|
1270
|
+
if (exec.name === 'glob' && dialect.globSplit) {
|
|
1271
|
+
const globTranslated = translateGlobArguments(translated, env)
|
|
1272
|
+
if (globTranslated !== translated) translated = globTranslated
|
|
1273
|
+
}
|
|
1274
|
+
// v0.20.0: a run_code program is DATA for a native Node process, so a
|
|
1275
|
+
// '/c/...' literal inside it never reached this layer and landed on the
|
|
1276
|
+
// current drive as '<drive>:\c\...'. The same mount table covers the program
|
|
1277
|
+
// path literals (see rewriteCodePaths; anything unclear leaves the code
|
|
1278
|
+
// untouched).
|
|
1279
|
+
if (exec.name === 'run_code' && dialect.codePaths && typeof translated.code === 'string') {
|
|
1280
|
+
const rewritten = rewriteCodePaths(translated.code, env)
|
|
1281
|
+
const nextCode = programPrelude(env) + rewritten
|
|
1282
|
+
if (nextCode !== translated.code) translated = { ...translated, code: nextCode }
|
|
1283
|
+
}
|
|
1284
|
+
return translated
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1169
1287
|
export function buildTranslateEnv(configuredBashPath) {
|
|
1170
1288
|
const cacheKey = typeof configuredBashPath === 'string' && configuredBashPath !== '' ? configuredBashPath : ''
|
|
1171
1289
|
const cached = translateEnvCache.get(cacheKey)
|
|
@@ -1781,13 +1899,13 @@ function adoptSidebarShell(ctx, bashPath, readAdopt) {
|
|
|
1781
1899
|
reverted = true
|
|
1782
1900
|
const s = ctx.get('settings')
|
|
1783
1901
|
if (!s || typeof s.update !== 'function') return
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
if (String(now
|
|
1902
|
+
// Era-aware read (v0.25.1): `settings.get(ns)` is gone on dsh >= 0.1.7, so
|
|
1903
|
+
// the old call threw straight into the catch and the takeover was NEVER
|
|
1904
|
+
// reverted when this plugin unloaded — same missed-era-read class as
|
|
1905
|
+
// issue #8 (readShell above carries both branches).
|
|
1906
|
+
const now = readShell()
|
|
1907
|
+
if (now === null) return
|
|
1908
|
+
if (String(now) === bashPath) {
|
|
1791
1909
|
s.update(SIDEBAR_NS, { terminalShell: previous }).catch(() => {})
|
|
1792
1910
|
}
|
|
1793
1911
|
},
|
|
@@ -1920,26 +2038,107 @@ async function registerVariant(ctx, presetId, { gitBashActive, skillsDir }) {
|
|
|
1920
2038
|
}
|
|
1921
2039
|
|
|
1922
2040
|
/**
|
|
1923
|
-
* Declarative-era wiring:
|
|
1924
|
-
*
|
|
1925
|
-
*
|
|
1926
|
-
*
|
|
2041
|
+
* Declarative-era wiring: keep exactly one registration per VARIANT THIS HOST
|
|
2042
|
+
* SHOULD SERVE for the plugin's lifetime, and re-reconcile whenever that set
|
|
2043
|
+
* changes. Two inputs drive it — the live `suppressPeerCordis` switch and the
|
|
2044
|
+
* peer capability appearing (or leaving) via `ctx.inject`, which fires
|
|
2045
|
+
* independent of row activation order — and the peer's own coverage only
|
|
2046
|
+
* counts while it reports a Git Bash-materialized preset.
|
|
2047
|
+
*
|
|
2048
|
+
* The roster picks entries up immediately; sessions already pinned to a
|
|
2049
|
+
* variant keep their revision until recomposed, so suppressing a variant never
|
|
2050
|
+
* rewrites a running session.
|
|
2051
|
+
* @param {object} ctx - the plugin's mounting context.
|
|
2052
|
+
* @param {string[]} presetIds - the row's configured variants.
|
|
2053
|
+
* @param {() => boolean} readSuppress - live dedupe switch reader.
|
|
2054
|
+
* @returns {Promise<void>} resolves once the first reconcile finished.
|
|
1927
2055
|
*/
|
|
1928
|
-
async function runDeclarativeEra(ctx, presetIds) {
|
|
2056
|
+
async function runDeclarativeEra(ctx, presetIds, readSuppress) {
|
|
1929
2057
|
cleanupLegacyTrees(presetIds)
|
|
1930
2058
|
const gitBashActive = process.platform === 'win32'
|
|
1931
2059
|
const skillsDir = await resolveSkillsDir()
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
2060
|
+
/** presetId -> unregister, i.e. exactly what is live right now. */
|
|
2061
|
+
const live = new Map()
|
|
2062
|
+
let peerGitBash = false
|
|
2063
|
+
let serial = Promise.resolve()
|
|
2064
|
+
|
|
2065
|
+
const desired = () => effectivePresetIds(presetIds, { suppress: readSuppress(), peerGitBash })
|
|
2066
|
+
|
|
2067
|
+
const reconcile = () => {
|
|
2068
|
+
serial = serial.then(async () => {
|
|
2069
|
+
const want = desired()
|
|
2070
|
+
for (const [presetId, off] of [...live]) {
|
|
2071
|
+
if (want.includes(presetId)) continue
|
|
2072
|
+
live.delete(presetId)
|
|
2073
|
+
try {
|
|
2074
|
+
await off()
|
|
2075
|
+
console.log(TAG + " preset '" + presetId + "' retired (dsh-ptc-cordis-preset covers Creation mode on Git Bash)")
|
|
2076
|
+
} catch (error) {
|
|
2077
|
+
console.log(TAG + " preset '" + presetId + "' retirement failed: " + (error && error.message ? error.message : error))
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
for (const presetId of want) {
|
|
2081
|
+
if (live.has(presetId)) continue
|
|
2082
|
+
try {
|
|
2083
|
+
const unregister = await registerVariant(ctx, presetId, { gitBashActive, skillsDir })
|
|
2084
|
+
if (unregister) {
|
|
2085
|
+
live.set(presetId, unregister)
|
|
2086
|
+
console.log(TAG + " preset '" + presetId + "' registered declaratively")
|
|
2087
|
+
}
|
|
2088
|
+
} catch (error) {
|
|
2089
|
+
console.log(TAG + " preset '" + presetId + "' registration failed: " + (error && error.message ? error.message : error))
|
|
2090
|
+
}
|
|
2091
|
+
}
|
|
2092
|
+
}).catch((error) => {
|
|
2093
|
+
console.log(TAG + ' preset reconcile failed: ' + (error && error.message ? error.message : error))
|
|
2094
|
+
})
|
|
2095
|
+
return serial
|
|
2096
|
+
}
|
|
2097
|
+
|
|
2098
|
+
await reconcile()
|
|
2099
|
+
console.log(TAG + ' registered ' + live.size + ' preset(s) declaratively (' + [...live.keys()].join(', ') + ')')
|
|
2100
|
+
|
|
2101
|
+
// The peer's capability: `ctx.inject` makes this independent of row order,
|
|
2102
|
+
// and the child scope's disposer runs when the peer unmounts (or its row is
|
|
2103
|
+
// disabled), which restores the variant.
|
|
2104
|
+
try {
|
|
2105
|
+
ctx.inject([PEER_CAPABILITY], (peerCtx) => {
|
|
2106
|
+
try {
|
|
2107
|
+
const coverage = peerCtx[PEER_CAPABILITY] ?? peerCtx.get(PEER_CAPABILITY)
|
|
2108
|
+
const next = coverage?.gitBashActive === true
|
|
2109
|
+
if (next !== peerGitBash) {
|
|
2110
|
+
peerGitBash = next
|
|
2111
|
+
void reconcile()
|
|
2112
|
+
}
|
|
2113
|
+
} catch (error) {
|
|
2114
|
+
console.log(TAG + ' peer coverage read failed: ' + (error && error.message ? error.message : error))
|
|
2115
|
+
}
|
|
2116
|
+
peerCtx.effect(() => () => {
|
|
2117
|
+
if (!peerGitBash) return
|
|
2118
|
+
peerGitBash = false
|
|
2119
|
+
void reconcile()
|
|
2120
|
+
}, 'dsh-gitbash-shell: peer coverage release')
|
|
2121
|
+
})
|
|
2122
|
+
} catch (error) {
|
|
2123
|
+
console.log(TAG + ' peer capability wiring failed: ' + (error && error.message ? error.message : error))
|
|
1940
2124
|
}
|
|
1941
|
-
|
|
1942
|
-
|
|
2125
|
+
|
|
2126
|
+
// The switch itself: a volatile Config edit on this row lands as a
|
|
2127
|
+
// loader/volatile-update event on this fiber.
|
|
2128
|
+
try {
|
|
2129
|
+
ctx.on('loader/volatile-update', (paths) => {
|
|
2130
|
+
try {
|
|
2131
|
+
if (!Array.isArray(paths) || !paths.some((path) => Array.isArray(path) && path[0] === 'suppressPeerCordis')) return
|
|
2132
|
+
void reconcile()
|
|
2133
|
+
} catch (error) {
|
|
2134
|
+
console.log(TAG + ' dedupe switch handling failed: ' + (error && error.message ? error.message : error))
|
|
2135
|
+
}
|
|
2136
|
+
})
|
|
2137
|
+
} catch (error) {
|
|
2138
|
+
console.log(TAG + ' dedupe switch wiring failed: ' + (error && error.message ? error.message : error))
|
|
2139
|
+
}
|
|
2140
|
+
|
|
2141
|
+
ctx.effect(() => () => { for (const off of live.values()) void off() }, 'dsh-gitbash-shell: declarative preset registrations')
|
|
1943
2142
|
}
|
|
1944
2143
|
|
|
1945
2144
|
export async function apply(ctx, config = {}) {
|
|
@@ -2019,6 +2218,10 @@ export async function apply(ctx, config = {}) {
|
|
|
2019
2218
|
gitAutocrlf: Schema.boolean().default(true),
|
|
2020
2219
|
bashPath: Schema.string().default(''),
|
|
2021
2220
|
adoptSidebar: Schema.boolean().default(true),
|
|
2221
|
+
// v0.25.0: same switch as the row Config carries on dsh >= 0.1.7
|
|
2222
|
+
// (the OLD era has no cross-namespace edits, so this namespace is
|
|
2223
|
+
// the only side that can change it here).
|
|
2224
|
+
suppressPeerCordis: Schema.boolean().default(false),
|
|
2022
2225
|
}))
|
|
2023
2226
|
sidebarScope = scope
|
|
2024
2227
|
console.log(`${TAG} settings namespace registered: ${SETTINGS_NAMESPACE} (posixPaths default on, adoptSidebar default on)`)
|
|
@@ -2158,27 +2361,21 @@ export async function apply(ctx, config = {}) {
|
|
|
2158
2361
|
let echo = false
|
|
2159
2362
|
let echoEnv = null
|
|
2160
2363
|
try {
|
|
2161
|
-
|
|
2364
|
+
// The LIVE, era-aware reader (v0.25.1, issue #8). The legacy
|
|
2365
|
+
// `readDialectSettings(ctx)` reads `settings.get(ns)`, which does not
|
|
2366
|
+
// exist on dsh >= 0.1.7 — it returned the all-off fallback, so this
|
|
2367
|
+
// wrapper translated NOTHING while the directive and the shell env
|
|
2368
|
+
// (both already on the live reader) kept working: `/c/...` reached the
|
|
2369
|
+
// file tools untranslated, `~` was never expanded, `glob.path` and
|
|
2370
|
+
// `bash.workdir` went through raw, and an in-workspace `/c/...` write
|
|
2371
|
+
// fell outside the sandbox. One missed call site, five symptoms.
|
|
2372
|
+
const dialect = liveSettings.dialect()
|
|
2162
2373
|
if (dialect.posixPaths) {
|
|
2163
2374
|
echo = true
|
|
2164
2375
|
const env = dialect.virtualMounts ? buildTranslateEnv(dialect.bashPath) : null
|
|
2165
2376
|
echoEnv = env
|
|
2166
2377
|
if (exec && exec.arguments && typeof exec.arguments === 'object') {
|
|
2167
|
-
|
|
2168
|
-
if (exec.name === 'glob' && dialect.globSplit) {
|
|
2169
|
-
const globTranslated = translateGlobArguments(translated, env)
|
|
2170
|
-
if (globTranslated !== translated) translated = globTranslated
|
|
2171
|
-
}
|
|
2172
|
-
// v0.20.0: a run_code program is DATA for a native Node process, so
|
|
2173
|
-
// a '/c/...' literal inside it never reached this layer and landed
|
|
2174
|
-
// on the current drive as '<drive>:\\c\\...'. The same mount table
|
|
2175
|
-
// now covers the program path literals (see rewriteCodePaths;
|
|
2176
|
-
// anything unclear leaves the code untouched).
|
|
2177
|
-
if (exec.name === 'run_code' && dialect.codePaths && typeof translated.code === 'string') {
|
|
2178
|
-
const rewritten = rewriteCodePaths(translated.code, env)
|
|
2179
|
-
const nextCode = programPrelude(env) + rewritten
|
|
2180
|
-
if (nextCode !== translated.code) translated = { ...translated, code: nextCode }
|
|
2181
|
-
}
|
|
2378
|
+
const translated = translateDispatch(exec, dialect, env)
|
|
2182
2379
|
if (translated !== exec.arguments) exec.arguments = translated
|
|
2183
2380
|
}
|
|
2184
2381
|
}
|
|
@@ -2304,7 +2501,7 @@ export async function apply(ctx, config = {}) {
|
|
|
2304
2501
|
// more), so this branch serves the variants and returns.
|
|
2305
2502
|
if (ctx.agentPresets && typeof ctx.agentPresets.register === 'function') {
|
|
2306
2503
|
try {
|
|
2307
|
-
await runDeclarativeEra(ctx, presetIds)
|
|
2504
|
+
await runDeclarativeEra(ctx, presetIds, () => liveSettings.suppressPeerCordis())
|
|
2308
2505
|
} catch (error) {
|
|
2309
2506
|
console.log(TAG + ' declarative registration failed: ' + (error && error.message ? error.message : error))
|
|
2310
2507
|
}
|
|
@@ -2343,9 +2540,21 @@ export async function apply(ctx, config = {}) {
|
|
|
2343
2540
|
// 0.1.6-alpha.1, so the materializer copies whatever the host itself ships.
|
|
2344
2541
|
const rows = await detectRowForms(ctx.agentPresets)
|
|
2345
2542
|
const userRootPath = userRoot.path
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2543
|
+
// Same dedupe decision as the declarative era, taken once at startup here:
|
|
2544
|
+
// this host has no roster registry to watch and no live Config writes, so the
|
|
2545
|
+
// switch is read per boot (documented in the README). `purgeOrphans` retires
|
|
2546
|
+
// a copy an earlier boot materialized, and flipping the switch back
|
|
2547
|
+
// re-materializes it on the next start.
|
|
2548
|
+
const suppressPeer = liveSettings.suppressPeerCordis()
|
|
2549
|
+
const peerGitBash = suppressPeer ? await detectPeerCoverage(ctx) : false
|
|
2550
|
+
const effectiveIds = effectivePresetIds(presetIds, { suppress: suppressPeer, peerGitBash })
|
|
2551
|
+
if (effectiveIds.length !== presetIds.length) {
|
|
2552
|
+
const skipped = presetIds.filter((presetId) => !effectiveIds.includes(presetId))
|
|
2553
|
+
console.log(`${TAG} dsh-ptc-cordis-preset covers Creation mode on Git Bash — not materializing: ${skipped.join(', ')}`)
|
|
2554
|
+
}
|
|
2555
|
+
purgeOrphans(userRootPath, effectiveIds)
|
|
2556
|
+
|
|
2557
|
+
for (const presetId of effectiveIds) {
|
|
2349
2558
|
const target = join(userRootPath, presetId)
|
|
2350
2559
|
const state = classify(target)
|
|
2351
2560
|
if (state === 'foreign') {
|
|
@@ -2387,4 +2596,4 @@ export async function apply(ctx, config = {}) {
|
|
|
2387
2596
|
}
|
|
2388
2597
|
|
|
2389
2598
|
// Test surface: pure helpers, no Cordis context required.
|
|
2390
|
-
export const _internal = { PRESET_IDS, translateMsysPath, translatePathArguments, rewriteCodePaths, scanCodeLiterals, programPrelude, translateGlobArguments, buildTranslateEnv, rewriteErrorContent, rewriteErrorMessage, rewriteFailureMessage, msysEcho, driveToMsys, pathEcho, ERROR_CONTENT_TOOLS, readPosixPaths, readAdoptSidebar, readDialectSettings, windowsToMsys, rewriteResultPaths, adoptSidebarShell, MARKER_FILE, classify, materialize, cleanupOnDispose, firstUserRoot, hashTree, skillsHashes, syncDecision, installRegisterShim, baseForRoster, detectBase, pickComposition, personaEraForText, detectPersonaEra, injectPresentRow, hostHasToolPresent, detectPresentSupport, injectPluginManagerRow, hostHasPluginManagerTools, rowFormOf, rowFormsOf, alignEngineRow, alignRalphRow, ROW_SOURCE }
|
|
2599
|
+
export const _internal = { PRESET_IDS, PEER_COVERED_PRESET_ID, PEER_CAPABILITY, effectivePresetIds, detectPeerCoverage, readSuppressPeerCordis, translateDispatch, translateMsysPath, translatePathArguments, rewriteCodePaths, scanCodeLiterals, programPrelude, translateGlobArguments, buildTranslateEnv, rewriteErrorContent, rewriteErrorMessage, rewriteFailureMessage, msysEcho, driveToMsys, pathEcho, ERROR_CONTENT_TOOLS, readPosixPaths, readAdoptSidebar, readDialectSettings, windowsToMsys, rewriteResultPaths, adoptSidebarShell, MARKER_FILE, classify, materialize, cleanupOnDispose, firstUserRoot, hashTree, skillsHashes, syncDecision, installRegisterShim, baseForRoster, detectBase, pickComposition, personaEraForText, detectPersonaEra, injectPresentRow, hostHasToolPresent, detectPresentSupport, injectPluginManagerRow, hostHasPluginManagerTools, rowFormOf, rowFormsOf, alignEngineRow, alignRalphRow, ROW_SOURCE }
|