@monotykamary/dsh 0.1.7 → 0.1.9

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.i18n.yaml CHANGED
@@ -1,6 +1,6 @@
1
1
  # Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
2
2
  # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
3
  # after editing either side, bring the other along and re-record with:
4
- # pnpm run verify-translation-pairing --write apps/cli/README.md
5
- README.md: 98048c14ccc99fc1f86f17f75fb3b822318e4849
6
- README.zh.md: 412687905628248f32227e024d3467c801d66599
4
+ # bun run verify-translation-pairing --write apps/cli/README.md
5
+ README.md: 4978c08597b54d0f2bc33d5764366eede43e3d16
6
+ README.zh.md: 1ec6a471b318549ef7e9842a0758dbf813e43aa8
package/README.md CHANGED
@@ -11,7 +11,7 @@ The `dsh` command is the product launcher for profiles: ordered stacks of plugin
11
11
  | `dsh --profile <name>` | Boot the named profile under `$DSH_HOME/profiles/<name>`. |
12
12
  | `dsh --profile headless "job"` | Run one fresh persisted session, print the final answer, and exit. |
13
13
  | `dsh web` | Alias of `--profile web`. |
14
- | `dsh plugin --profile <name> <pnpm args>` | Manage a profile's plugins by forwarding to pnpm in the profile directory. |
14
+ | `dsh plugin --profile <name> <bun args>` | Manage a profile's plugins by forwarding to bun in the profile directory. |
15
15
  | `dsh version [--json]` | Report the installed DSH, Fabric, and Fovea closure. |
16
16
  | `dsh update [--check] [--json]` | Check versions or hand an npm-global update to a detached worker. |
17
17
  | `dsh doctor [--json]` | Report the installation channel, Node version, DSH home, and package versions. |
@@ -39,7 +39,7 @@ The tree composes over an empty root:
39
39
  - then the profile's `cordis.patch.yml`, then the home-level `$DSH_HOME/cordis.patch.yml`
40
40
  - then `--patch` overlays
41
41
 
42
- Bundles named in `dsh.profile.bundles` resolve from the dsh installation first (`@monotykamary/dsh-base`, `@monotykamary/dsh-web-app`, `@monotykamary/dsh-headless`), then from the profile's own `node_modules`, where pnpm installs out-of-tree plugins.
42
+ Bundles named in `dsh.profile.bundles` resolve from the dsh installation first (`@monotykamary/dsh-base`, `@monotykamary/dsh-web-app`, `@monotykamary/dsh-headless`), then from the profile's own `node_modules`, where bun installs out-of-tree plugins.
43
43
 
44
44
  Use `--dump-default-config` and `--dump-config` to inspect the composed tree without booting it.
45
45
 
@@ -47,4 +47,4 @@ The [CLI behavior reference](reference/README.md) owns exact layer precedence, f
47
47
 
48
48
  ## Development
49
49
 
50
- Production runs require built package and frontend artifacts. From the repository root, run `pnpm run build` separately, then use `pnpm dsh <args...>` to run the TypeScript entry and forward every argument; the [source-execution reference](reference/README.md#source-execution) owns the module-resolution contract.
50
+ Production runs require built package and frontend artifacts. From the repository root, run `bun run build` separately, then use `bun dsh <args...>` to run the TypeScript entry and forward every argument; the [source-execution reference](reference/README.md#source-execution) owns the module-resolution contract.
package/README.zh.md CHANGED
@@ -11,7 +11,7 @@
11
11
  | `dsh --profile <name>` | 启动位于 `$DSH_HOME/profiles/<name>` 的指定 profile。 |
12
12
  | `dsh --profile headless "job"` | 运行一个全新的持久化会话,打印最终答案并退出。 |
13
13
  | `dsh web` | `--profile web` 的别名。 |
14
- | `dsh plugin --profile <name> <pnpm args>` | 通过在 profile 目录中转发给 pnpm 来管理该 profile 的插件。 |
14
+ | `dsh plugin --profile <name> <bun args>` | 通过在 profile 目录中转发给 bun 来管理该 profile 的插件。 |
15
15
  | `dsh version [--json]` | 报告已安装的 DSH、Fabric 与 Fovea 闭包。 |
16
16
  | `dsh update [--check] [--json]` | 检查版本,或把 npm 全局更新交给分离 Worker。 |
17
17
  | `dsh doctor [--json]` | 报告安装渠道、Node 版本、DSH home 与包版本。 |
@@ -41,7 +41,7 @@ profile 目录包含一个 `package.json`,其中记录树外插件依赖、由
41
41
  - profile 自身的 `cordis.patch.yml`,然后是 home 级的 `$DSH_HOME/cordis.patch.yml`
42
42
  - `--patch` 指定的覆盖层
43
43
 
44
- `dsh.profile.bundles` 中列出的组合包先从 dsh 安装目录解析(`@monotykamary/dsh-base`、`@monotykamary/dsh-web-app`、`@monotykamary/dsh-headless`),再从 profile 自身的 `node_modules` 解析;pnpm 会将树外插件安装到该目录。
44
+ `dsh.profile.bundles` 中列出的组合包先从 dsh 安装目录解析(`@monotykamary/dsh-base`、`@monotykamary/dsh-web-app`、`@monotykamary/dsh-headless`),再从 profile 自身的 `node_modules` 解析;bun 会将树外插件安装到该目录。
45
45
 
46
46
  使用 `--dump-default-config` 和 `--dump-config` 可在不启动的情况下检查组合后的配置树。
47
47
 
@@ -49,4 +49,4 @@ profile 目录包含一个 `package.json`,其中记录树外插件依赖、由
49
49
 
50
50
  ## 开发
51
51
 
52
- 生产运行需要已构建的包与前端产物。请在仓库根目录单独运行 `pnpm run build`,然后使用 `pnpm dsh <args...>` 运行 TypeScript 入口并转发所有参数;模块解析约定以[源码执行参考](reference/README.zh.md#source-execution)为准。
52
+ 生产运行需要已构建的包与前端产物。请在仓库根目录单独运行 `bun run build`,然后使用 `bun dsh <args...>` 运行 TypeScript 入口并转发所有参数;模块解析约定以[源码执行参考](reference/README.zh.md#source-execution)为准。
package/lib/bin.js CHANGED
@@ -17,7 +17,7 @@ import { Command, CommanderError } from "commander";
17
17
  * and `dsh --profile web -h` prints the web app's help, not this one's.
18
18
  *
19
19
  * `web` is a hardcoded alias for `--profile web`; `plugin` manages a profile's
20
- * plugin dependencies by forwarding to pnpm.
20
+ * plugin dependencies by forwarding to Bun.
21
21
  * @module @monotykamary/dsh/args
22
22
  */
23
23
  /**
@@ -96,10 +96,10 @@ function parseDshArgs(argv, version) {
96
96
  rejectParentOptions("web");
97
97
  resolved = resolveBoot(web, "web", options, args);
98
98
  });
99
- program.command("plugin").description("manage a profile's plugins by forwarding the remaining arguments to pnpm in the profile directory").requiredOption("--profile <name>", "the profile whose plugins to manage (initialized on first use)").allowUnknownOption().argument("[args...]", "pnpm arguments, forwarded verbatim (add <pkg>, remove <pkg>, why <pkg>, ...)").action((args, options) => {
99
+ program.command("plugin").description("manage a profile's plugins by forwarding the remaining arguments to Bun in the profile directory").requiredOption("--profile <name>", "the profile whose plugins to manage (initialized on first use)").allowUnknownOption().argument("[args...]", "Bun arguments, forwarded verbatim (add <pkg>, remove <pkg>, why <pkg>, ...)").action((args, options) => {
100
100
  rejectParentOptions("plugin");
101
101
  if (options.profile === "") program.error("error: --profile needs a name");
102
- if (args.length === 0) program.error("error: plugin needs pnpm arguments to forward (e.g. add <package>)");
102
+ if (args.length === 0) program.error("error: plugin needs Bun arguments to forward (e.g. add <package>)");
103
103
  resolved = {
104
104
  mode: "plugin",
105
105
  profile: options.profile,
@@ -163,7 +163,7 @@ switch (invocation.mode) {
163
163
  break;
164
164
  }
165
165
  case "plugin": {
166
- const { runPlugin } = await import("./plugin-Cgl0ZnNV.js");
166
+ const { runPlugin } = await import("./plugin-BcPTOxhP.js");
167
167
  process.exit(runPlugin(invocation.profile, invocation.args));
168
168
  break;
169
169
  }
@@ -0,0 +1,64 @@
1
+ import { i as prepareProfile, n as PROFILE_ROOT_FILENAME, r as homePatchPath } from "./profile-boot-EVnLskjy.js";
2
+ import { existsSync } from "node:fs";
3
+ import { loadOptionalPatches, loadOverlayPatches, renderConfigDump } from "@monotykamary/dsh-app-boot";
4
+ import { join, resolve } from "node:path";
5
+ //#region lib/types/dump-config.js
6
+ /**
7
+ * Config-dump entry for `dsh --profile <name> --dump-config`: compose the
8
+ * profile's patch layers through the include plugin's patch algorithm without
9
+ * booting or evaluating `!!js`, with one source layer per bundle, the
10
+ * profile's own patch file, and each `--patch` overlay.
11
+ * @module @monotykamary/dsh/dump-config
12
+ */
13
+ const NAME = "dsh";
14
+ /**
15
+ * Print a profile composition with comments naming each source file and patch layer.
16
+ * @param profile - the profile name.
17
+ * @param defaultOnly - omit the profile's user layer and `--patch` overlays
18
+ * (the recovery diagnostic for a broken `cordis.patch.yml`, which is then
19
+ * never parsed).
20
+ * @param patches - `--patch` overlay paths, in argv order.
21
+ */
22
+ function runDumpConfig(profile, defaultOnly, patches) {
23
+ const loaded = prepareProfile(profile, !defaultOnly);
24
+ const layers = loaded.layers.map((layer) => ({
25
+ label: layer.packageName,
26
+ patches: layer.patches
27
+ }));
28
+ if (process.env.DSH_TOOLS_MODE !== void 0) {
29
+ const lastBundleTools = loaded.layers.flatMap((layer) => layer.patches).reverse().find((patch) => patch.id === "tools" && !Array.isArray(patch.insert));
30
+ const toolsConfig = lastBundleTools?.config !== void 0 && typeof lastBundleTools.config === "object" ? { ...lastBundleTools.config } : {};
31
+ layers.push({
32
+ label: "dsh launcher (DSH_TOOLS_MODE)",
33
+ patches: [{
34
+ id: "tools",
35
+ config: {
36
+ ...toolsConfig,
37
+ mode: process.env.DSH_TOOLS_MODE
38
+ }
39
+ }]
40
+ });
41
+ }
42
+ if (!defaultOnly) {
43
+ if (existsSync(loaded.patchPath)) layers.push({
44
+ label: loaded.patchPath,
45
+ patches: loaded.patches
46
+ });
47
+ const homePatchFile = homePatchPath();
48
+ const homePatches = loadOptionalPatches(NAME, homePatchFile);
49
+ if (homePatches !== void 0) layers.push({
50
+ label: homePatchFile,
51
+ patches: homePatches
52
+ });
53
+ for (const file of patches) {
54
+ const absolute = resolve(file);
55
+ layers.push({
56
+ label: absolute,
57
+ patches: loadOverlayPatches(NAME, absolute)
58
+ });
59
+ }
60
+ }
61
+ process.stdout.write(renderConfigDump(NAME, join(loaded.dir, PROFILE_ROOT_FILENAME), layers));
62
+ }
63
+ //#endregion
64
+ export { runDumpConfig };
@@ -0,0 +1,128 @@
1
+ import { t as INSTALL_ANCHOR } from "./profile-boot-Bt4vObgm.js";
2
+ import { existsSync } from "node:fs";
3
+ import { DEFAULT_PROFILE_BUNDLES, PROFILE_TEMPLATES, initProfile, readProfileManifest, resolveBundleDir, resolveProfileDir, writeProfileManifest } from "@monotykamary/dsh-app-boot";
4
+ import { join, resolve } from "node:path";
5
+ import { spawnSync } from "node:child_process";
6
+ //#region lib/types/plugin.js
7
+ /**
8
+ * `dsh plugin --profile <name> <args...>` — profile plugin management as a
9
+ * thin Bun forwarder: initialize the profile on first use, run
10
+ * `Bun <args...>` in the profile directory, then reconcile the
11
+ * `dsh.profile.bundles` layer list against the installed state (a dependency
12
+ * resolving to a package that declares `dsh.bundle` joins the layer stack; a
13
+ * removed or bundle-less dependency leaves it). Reconciling by installed
14
+ * state, not by dependency diff, means `update` activates a package that
15
+ * gained its `dsh.bundle` declaration in a newer version.
16
+ * @module @monotykamary/dsh/plugin
17
+ */
18
+ const NAME = "dsh";
19
+ /**
20
+ * Whether a resolved dependency exports a profile patch, i.e. is a bundle.
21
+ * @param packageName - the dependency's package name.
22
+ * @param profileDir - the profile directory (resolution anchor).
23
+ * @returns true when the package manifest declares `dsh.bundle`.
24
+ */
25
+ function exportsPatch(packageName, profileDir) {
26
+ let dir;
27
+ try {
28
+ dir = resolveBundleDir(NAME, packageName, INSTALL_ANCHOR, profileDir);
29
+ } catch {
30
+ return false;
31
+ }
32
+ return readProfileManifest(NAME, dir).dsh?.bundle?.patch !== void 0;
33
+ }
34
+ /**
35
+ * Reconcile `dsh.profile.bundles` against the installed state: Bun has
36
+ * already written the real installed names (so a git/path/tarball/alias spec
37
+ * on the command line reconciles by its true package name) and materialized
38
+ * the packages. A dependency that resolves to a `dsh.bundle`-declaring
39
+ * package joins the layer stack (appended in dependency order); a
40
+ * dependency-listed name that no longer does — removed, or the installed
41
+ * version dropped the declaration — leaves it. In-box bundles from the
42
+ * profile template are not dependencies and are never touched. Warns once
43
+ * per newly-added bundle-less dependency (a plain library is fine; the
44
+ * warning is orientation).
45
+ */
46
+ function reconcilePlugins(before, profileDir) {
47
+ const after = readProfileManifest(NAME, profileDir);
48
+ const beforeDeps = new Set(Object.keys(before.dependencies ?? {}));
49
+ const dependencies = Object.keys(after.dependencies ?? {});
50
+ const plugins = after.dsh?.profile?.bundles ?? [];
51
+ let changed = false;
52
+ for (const packageName of dependencies) {
53
+ const isBundle = exportsPatch(packageName, profileDir);
54
+ if (isBundle && !plugins.includes(packageName)) {
55
+ plugins.push(packageName);
56
+ changed = true;
57
+ } else if (!isBundle && !beforeDeps.has(packageName)) process.stderr.write(`${NAME}: warning: ${packageName} declares no dsh.bundle — installed as a plain dependency, not a profile layer (a later update that gains one activates it automatically)
58
+ `);
59
+ }
60
+ const dependencySet = new Set(dependencies);
61
+ for (const packageName of [...plugins]) {
62
+ const wasDependency = beforeDeps.has(packageName) || dependencySet.has(packageName);
63
+ const stillBundle = dependencySet.has(packageName) && exportsPatch(packageName, profileDir);
64
+ if (wasDependency && !stillBundle) {
65
+ plugins.splice(plugins.indexOf(packageName), 1);
66
+ changed = true;
67
+ }
68
+ }
69
+ if (!changed) return;
70
+ after.dsh = {
71
+ ...after.dsh,
72
+ profile: {
73
+ ...after.dsh?.profile,
74
+ bundles: plugins
75
+ }
76
+ };
77
+ writeProfileManifest(profileDir, after);
78
+ }
79
+ /**
80
+ * Rewrite relative filesystem specs against the user's invoking directory.
81
+ * Bun runs with cwd = the profile directory, so a bare `.` or `../plugin`
82
+ * (or their `file:`/`link:` forms) would silently resolve inside the profile
83
+ * — `add .` from a plugin checkout would self-link the profile. Absolute
84
+ * specs, registry names, and every other Bun argument pass through
85
+ * untouched.
86
+ * @param argument - one Bun argument, verbatim from argv.
87
+ * @param cwd - the directory `dsh` was invoked from.
88
+ * @returns the argument with a relative path spec anchored to `cwd`.
89
+ */
90
+ function anchorPathSpec(argument, cwd) {
91
+ const match = /^(?<prefix>(?:file|link):)?(?<path>\.{1,2}(?:[/\\].*)?)$/.exec(argument);
92
+ if (match?.groups?.path === void 0) return argument;
93
+ return `${match.groups.prefix ?? ""}${resolve(cwd, match.groups.path)}`;
94
+ }
95
+ /**
96
+ * Run one `dsh plugin` invocation: init if needed, forward to Bun, reconcile.
97
+ * @param profile - the profile name.
98
+ * @param args - Bun arguments with relative path specs anchored to the invoking directory.
99
+ * @returns the Bun exit code.
100
+ */
101
+ function runPlugin(profile, args) {
102
+ const dir = resolveProfileDir(profile);
103
+ const template = PROFILE_TEMPLATES[profile];
104
+ const initialized = !existsSync(join(dir, "package.json"));
105
+ initProfile(dir, template ?? DEFAULT_PROFILE_BUNDLES, template === void 0 ? void 0 : profile);
106
+ if (initialized) process.stderr.write(`${NAME}: initialized profile ${profile} at ${dir}\n`);
107
+ const before = readProfileManifest(NAME, dir);
108
+ const result = spawnSync(process.platform === "win32" ? "bun.exe" : "bun", args.map((argument) => anchorPathSpec(argument, process.cwd())), {
109
+ cwd: dir,
110
+ stdio: "inherit"
111
+ });
112
+ if (result.error !== void 0) {
113
+ if (result.error.code === "ENOENT") {
114
+ process.stderr.write(`${NAME}: Bun not found on PATH — install Bun to manage profile plugins\n`);
115
+ return 127;
116
+ }
117
+ throw result.error;
118
+ }
119
+ const exitCode = result.status ?? 1;
120
+ if (exitCode === 0) reconcilePlugins(before, dir);
121
+ else {
122
+ process.stderr.write(`${NAME}: Bun failed in profile directory ${dir}\n`);
123
+ if (args.some((argument) => /^git\+|^github:|\.git(?:#|$)/.test(argument))) process.stderr.write(`${NAME}: if this git-hosted plugin requires a prepare script, re-run the add with --trust or trust it from ${dir} with bun pm trust <package>\n`);
124
+ }
125
+ return exitCode;
126
+ }
127
+ //#endregion
128
+ export { runPlugin };
@@ -0,0 +1,129 @@
1
+ import { t as INSTALL_ANCHOR } from "./profile-boot-Bt4vObgm.js";
2
+ import { existsSync } from "node:fs";
3
+ import { DEFAULT_PROFILE_BUNDLES, PROFILE_TEMPLATES, initProfile, readProfileManifest, resolveBundleDir, resolveProfileDir, writeProfileManifest } from "@monotykamary/dsh-app-boot";
4
+ import { join, resolve } from "node:path";
5
+ import { spawnSync } from "node:child_process";
6
+ //#region lib/types/plugin.js
7
+ /**
8
+ * `dsh plugin --profile <name> <args...>` — profile plugin management as a
9
+ * thin Bun forwarder: initialize the profile on first use, run
10
+ * `Bun <args...>` in the profile directory, then reconcile the
11
+ * `dsh.profile.bundles` layer list against the installed state (a dependency
12
+ * resolving to a package that declares `dsh.bundle` joins the layer stack; a
13
+ * removed or bundle-less dependency leaves it). Reconciling by installed
14
+ * state, not by dependency diff, means `update` activates a package that
15
+ * gained its `dsh.bundle` declaration in a newer version.
16
+ * @module @monotykamary/dsh/plugin
17
+ */
18
+ const NAME = "dsh";
19
+ /**
20
+ * Whether a resolved dependency exports a profile patch, i.e. is a bundle.
21
+ * @param packageName - the dependency's package name.
22
+ * @param profileDir - the profile directory (resolution anchor).
23
+ * @returns true when the package manifest declares `dsh.bundle`.
24
+ */
25
+ function exportsPatch(packageName, profileDir) {
26
+ let dir;
27
+ try {
28
+ dir = resolveBundleDir(NAME, packageName, INSTALL_ANCHOR, profileDir);
29
+ } catch {
30
+ return false;
31
+ }
32
+ return readProfileManifest(NAME, dir).dsh?.bundle?.patch !== void 0;
33
+ }
34
+ /**
35
+ * Reconcile `dsh.profile.bundles` against the installed state: Bun has
36
+ * already written the real installed names (so a git/path/tarball/alias spec
37
+ * on the command line reconciles by its true package name) and materialized
38
+ * the packages. A dependency that resolves to a `dsh.bundle`-declaring
39
+ * package joins the layer stack (appended in dependency order); a
40
+ * dependency-listed name that no longer does — removed, or the installed
41
+ * version dropped the declaration — leaves it. In-box bundles from the
42
+ * profile template are not dependencies and are never touched. Warns once
43
+ * per newly-added bundle-less dependency (a plain library is fine; the
44
+ * warning is orientation).
45
+ */
46
+ function reconcilePlugins(before, profileDir) {
47
+ const after = readProfileManifest(NAME, profileDir);
48
+ const beforeDeps = new Set(Object.keys(before.dependencies ?? {}));
49
+ const dependencies = Object.keys(after.dependencies ?? {});
50
+ const plugins = after.dsh?.profile?.bundles ?? [];
51
+ let changed = false;
52
+ for (const packageName of dependencies) {
53
+ const isBundle = exportsPatch(packageName, profileDir);
54
+ if (isBundle && !plugins.includes(packageName)) {
55
+ plugins.push(packageName);
56
+ changed = true;
57
+ } else if (!isBundle && !beforeDeps.has(packageName)) process.stderr.write(`${NAME}: warning: ${packageName} declares no dsh.bundle — installed as a plain dependency, not a profile layer (a later update that gains one activates it automatically)
58
+ `);
59
+ }
60
+ const dependencySet = new Set(dependencies);
61
+ for (const packageName of [...plugins]) {
62
+ const wasDependency = beforeDeps.has(packageName) || dependencySet.has(packageName);
63
+ const stillBundle = dependencySet.has(packageName) && exportsPatch(packageName, profileDir);
64
+ if (wasDependency && !stillBundle) {
65
+ plugins.splice(plugins.indexOf(packageName), 1);
66
+ changed = true;
67
+ }
68
+ }
69
+ if (!changed) return;
70
+ after.dsh = {
71
+ ...after.dsh,
72
+ profile: {
73
+ ...after.dsh?.profile,
74
+ bundles: plugins
75
+ }
76
+ };
77
+ writeProfileManifest(profileDir, after);
78
+ }
79
+ /**
80
+ * Rewrite relative filesystem specs against the user's invoking directory.
81
+ * Bun runs with cwd = the profile directory, so a bare `.` or `../plugin`
82
+ * (or their `file:`/`link:` forms) would silently resolve inside the profile
83
+ * — `add .` from a plugin checkout would self-link the profile. Absolute
84
+ * specs, registry names, and every other Bun argument pass through
85
+ * untouched.
86
+ * @param argument - one Bun argument, verbatim from argv.
87
+ * @param cwd - the directory `dsh` was invoked from.
88
+ * @returns the argument with a relative path spec anchored to `cwd`.
89
+ */
90
+ function anchorPathSpec(argument, cwd) {
91
+ const match = /^(?<prefix>(?:file|link):)?(?<path>\.{1,2}(?:[/\\].*)?)$/.exec(argument);
92
+ if (match?.groups?.path === void 0) return argument;
93
+ return `${match.groups.prefix ?? ""}${resolve(cwd, match.groups.path)}`;
94
+ }
95
+ /**
96
+ * Run one `dsh plugin` invocation: init if needed, forward to Bun, reconcile.
97
+ * @param profile - the profile name.
98
+ * @param args - Bun arguments with relative path specs anchored to the invoking directory.
99
+ * @returns the Bun exit code.
100
+ */
101
+ function runPlugin(profile, args) {
102
+ const dir = resolveProfileDir(profile);
103
+ const template = PROFILE_TEMPLATES[profile];
104
+ const initialized = !existsSync(join(dir, "package.json"));
105
+ initProfile(dir, template ?? DEFAULT_PROFILE_BUNDLES, template === void 0 ? void 0 : profile);
106
+ if (initialized) process.stderr.write(`${NAME}: initialized profile ${profile} at ${dir}\n`);
107
+ const before = readProfileManifest(NAME, dir);
108
+ const executable = process.platform === "win32" ? "bun.exe" : "bun";
109
+ const result = spawnSync(executable, args.map((argument) => anchorPathSpec(argument, process.cwd())), {
110
+ cwd: dir,
111
+ stdio: "inherit"
112
+ });
113
+ if (result.error !== void 0) {
114
+ if (result.error.code === "ENOENT") {
115
+ process.stderr.write(`${NAME}: Bun not found on PATH — install Bun to manage profile plugins\n`);
116
+ return 127;
117
+ }
118
+ throw result.error;
119
+ }
120
+ const exitCode = result.status ?? 1;
121
+ if (exitCode === 0) reconcilePlugins(before, dir);
122
+ else {
123
+ process.stderr.write(`${NAME}: Bun failed in profile directory ${dir}\n`);
124
+ if (args.some((argument) => /^git\+|^github:|\.git(?:#|$)/.test(argument))) process.stderr.write(`${NAME}: if this git-hosted plugin requires a prepare script, re-run the add with --trust or trust it from ${dir} with bun pm trust <package>\n`);
125
+ }
126
+ return exitCode;
127
+ }
128
+ //#endregion
129
+ export { runPlugin };
@@ -0,0 +1,130 @@
1
+ import { t as INSTALL_ANCHOR } from "./profile-boot-EVnLskjy.js";
2
+ import { existsSync } from "node:fs";
3
+ import { DEFAULT_PROFILE_BUNDLES, PROFILE_TEMPLATES, initProfile, readProfileManifest, resolveBundleDir, resolveProfileDir, writeProfileManifest } from "@monotykamary/dsh-app-boot";
4
+ import { join, resolve } from "node:path";
5
+ import { spawnSync } from "node:child_process";
6
+ //#region lib/types/plugin.js
7
+ /**
8
+ * `dsh plugin --profile <name> <args...>` — profile plugin management as a
9
+ * thin pnpm forwarder: initialize the profile on first use, run
10
+ * `pnpm <args...>` in the profile directory, then reconcile the
11
+ * `dsh.profile.bundles` layer list against the installed state (a dependency
12
+ * resolving to a package that declares `dsh.bundle` joins the layer stack; a
13
+ * removed or bundle-less dependency leaves it). Reconciling by installed
14
+ * state, not by dependency diff, means `update` activates a package that
15
+ * gained its `dsh.bundle` declaration in a newer version.
16
+ * @module @monotykamary/dsh/plugin
17
+ */
18
+ const NAME = "dsh";
19
+ /**
20
+ * Whether a resolved dependency exports a profile patch, i.e. is a bundle.
21
+ * @param packageName - the dependency's package name.
22
+ * @param profileDir - the profile directory (resolution anchor).
23
+ * @returns true when the package manifest declares `dsh.bundle`.
24
+ */
25
+ function exportsPatch(packageName, profileDir) {
26
+ let dir;
27
+ try {
28
+ dir = resolveBundleDir(NAME, packageName, INSTALL_ANCHOR, profileDir);
29
+ } catch {
30
+ return false;
31
+ }
32
+ return readProfileManifest(NAME, dir).dsh?.bundle?.patch !== void 0;
33
+ }
34
+ /**
35
+ * Reconcile `dsh.profile.bundles` against the installed state: pnpm has
36
+ * already written the real installed names (so a git/path/tarball/alias spec
37
+ * on the command line reconciles by its true package name) and materialized
38
+ * the packages. A dependency that resolves to a `dsh.bundle`-declaring
39
+ * package joins the layer stack (appended in dependency order); a
40
+ * dependency-listed name that no longer does — removed, or the installed
41
+ * version dropped the declaration — leaves it. In-box bundles from the
42
+ * profile template are not dependencies and are never touched. Warns once
43
+ * per newly-added bundle-less dependency (a plain library is fine; the
44
+ * warning is orientation).
45
+ */
46
+ function reconcilePlugins(before, profileDir) {
47
+ const after = readProfileManifest(NAME, profileDir);
48
+ const beforeDeps = new Set(Object.keys(before.dependencies ?? {}));
49
+ const dependencies = Object.keys(after.dependencies ?? {});
50
+ const plugins = after.dsh?.profile?.bundles ?? [];
51
+ let changed = false;
52
+ for (const packageName of dependencies) {
53
+ const isBundle = exportsPatch(packageName, profileDir);
54
+ if (isBundle && !plugins.includes(packageName)) {
55
+ plugins.push(packageName);
56
+ changed = true;
57
+ } else if (!isBundle && !beforeDeps.has(packageName)) process.stderr.write(`${NAME}: warning: ${packageName} declares no dsh.bundle — installed as a plain dependency, not a profile layer (a later update that gains one activates it automatically)
58
+ `);
59
+ }
60
+ const dependencySet = new Set(dependencies);
61
+ for (const packageName of [...plugins]) {
62
+ const wasDependency = beforeDeps.has(packageName) || dependencySet.has(packageName);
63
+ const stillBundle = dependencySet.has(packageName) && exportsPatch(packageName, profileDir);
64
+ if (wasDependency && !stillBundle) {
65
+ plugins.splice(plugins.indexOf(packageName), 1);
66
+ changed = true;
67
+ }
68
+ }
69
+ if (!changed) return;
70
+ after.dsh = {
71
+ ...after.dsh,
72
+ profile: {
73
+ ...after.dsh?.profile,
74
+ bundles: plugins
75
+ }
76
+ };
77
+ writeProfileManifest(profileDir, after);
78
+ }
79
+ /**
80
+ * Rewrite relative filesystem specs against the user's invoking directory.
81
+ * pnpm runs with cwd = the profile directory, so a bare `.` or `../plugin`
82
+ * (or their `file:`/`link:` forms) would silently resolve inside the profile
83
+ * — `add .` from a plugin checkout would self-link the profile. Absolute
84
+ * specs, registry names, and every other pnpm argument pass through
85
+ * untouched.
86
+ * @param argument - one pnpm argument, verbatim from argv.
87
+ * @param cwd - the directory `dsh` was invoked from.
88
+ * @returns the argument with a relative path spec anchored to `cwd`.
89
+ */
90
+ function anchorPathSpec(argument, cwd) {
91
+ const match = /^(?<prefix>(?:file|link):)?(?<path>\.{1,2}(?:[/\\].*)?)$/.exec(argument);
92
+ if (match?.groups?.path === void 0) return argument;
93
+ return `${match.groups.prefix ?? ""}${resolve(cwd, match.groups.path)}`;
94
+ }
95
+ /**
96
+ * Run one `dsh plugin` invocation: init if needed, forward to pnpm, reconcile.
97
+ * @param profile - the profile name.
98
+ * @param args - pnpm arguments with relative path specs anchored to the invoking directory.
99
+ * @returns the pnpm exit code.
100
+ */
101
+ function runPlugin(profile, args) {
102
+ const dir = resolveProfileDir(profile);
103
+ if (!existsSync(join(dir, "package.json"))) {
104
+ const template = PROFILE_TEMPLATES[profile];
105
+ initProfile(dir, template ?? DEFAULT_PROFILE_BUNDLES, template === void 0 ? void 0 : profile);
106
+ process.stderr.write(`${NAME}: initialized profile ${profile} at ${dir}\n`);
107
+ }
108
+ const before = readProfileManifest(NAME, dir);
109
+ const result = spawnSync("pnpm", args.map((argument) => anchorPathSpec(argument, process.cwd())), {
110
+ cwd: dir,
111
+ stdio: "inherit",
112
+ shell: process.platform === "win32"
113
+ });
114
+ if (result.error !== void 0) {
115
+ if (result.error.code === "ENOENT") {
116
+ process.stderr.write(`${NAME}: pnpm not found on PATH — install pnpm to manage profile plugins\n`);
117
+ return 127;
118
+ }
119
+ throw result.error;
120
+ }
121
+ const exitCode = result.status ?? 1;
122
+ if (exitCode === 0) reconcilePlugins(before, dir);
123
+ else {
124
+ process.stderr.write(`${NAME}: pnpm failed in profile directory ${dir}\n`);
125
+ if (args.some((argument) => /^git\+|^github:|\.git(?:#|$)/.test(argument))) process.stderr.write(`${NAME}: git-hosted plugins build on install via their prepare script, which pnpm blocks until allowed — add the exact key pnpm printed above under allowBuilds in ${join(dir, "pnpm-workspace.yaml")}, then re-run\n`);
126
+ }
127
+ return exitCode;
128
+ }
129
+ //#endregion
130
+ export { runPlugin };
@@ -0,0 +1,2 @@
1
+ import { a as runProfile } from "./profile-boot-EVnLskjy.js";
2
+ export { runProfile };
@@ -0,0 +1,276 @@
1
+ import { writeFileSync } from "node:fs";
2
+ import { fileURLToPath, pathToFileURL } from "node:url";
3
+ import { PROFILE_PATCH_FILENAME, boot, composeEntries, healProfilesModuleFallback, installFailLoud, loadOptionalPatches, loadOverlayPatches, loadProfile, watchUserPatches } from "@monotykamary/dsh-app-boot";
4
+ import { resolveDshHome } from "@monotykamary/dsh-home-paths";
5
+ import { join, resolve } from "node:path";
6
+ import { DSH_LAUNCH_ENVIRONMENT_KEY } from "@monotykamary/dsh-launch-environment";
7
+ import { provideCmdline } from "@monotykamary/dsh-cmdline";
8
+ //#region lib/types/process-shutdown.js
9
+ /** Bounded, escalating process shutdown for the long-lived CLI surfaces. */
10
+ /** Maximum grace allowed for the application tree to dispose before process exit. */
11
+ const PROCESS_SHUTDOWN_TIMEOUT_MS = 5e3;
12
+ /**
13
+ * Create one process-exit controller around an application disposer.
14
+ * @param dispose - Whole-application teardown that resolves at quiescence.
15
+ * @param forceExit - Function that exits the process immediately, replaceable by tests.
16
+ * @param complete - Function that records the natural completion code, replaceable by tests.
17
+ * @param timeoutMs - Grace before forced exit, replaceable by tests.
18
+ * @returns A controller whose normal calls coalesce and whose repeated signal call escalates.
19
+ */
20
+ function createProcessShutdown(dispose, forceExit = (code) => {
21
+ process.exit(code);
22
+ }, complete = (code) => {
23
+ process.exitCode = code;
24
+ }, timeoutMs = PROCESS_SHUTDOWN_TIMEOUT_MS) {
25
+ let pending;
26
+ let timeout;
27
+ let completed = false;
28
+ let forceExited = false;
29
+ const clearExitTimeout = () => {
30
+ if (timeout !== void 0) clearTimeout(timeout);
31
+ };
32
+ const forceExitOnce = (code) => {
33
+ if (forceExited) return;
34
+ forceExited = true;
35
+ clearExitTimeout();
36
+ forceExit(code);
37
+ };
38
+ const completeOnce = (code) => {
39
+ if (completed || forceExited) return;
40
+ completed = true;
41
+ clearExitTimeout();
42
+ complete(code);
43
+ };
44
+ const start = (code, forceAfterDispose) => {
45
+ if (pending !== void 0) return pending;
46
+ timeout = setTimeout(() => {
47
+ forceExitOnce(code);
48
+ }, timeoutMs);
49
+ pending = Promise.resolve().then(dispose).then(() => {
50
+ if (forceAfterDispose) forceExitOnce(code);
51
+ else completeOnce(code);
52
+ }, () => {
53
+ forceExitOnce(code);
54
+ });
55
+ return pending;
56
+ };
57
+ return {
58
+ shutdown(code) {
59
+ return start(code, false);
60
+ },
61
+ interrupt(code) {
62
+ if (pending !== void 0) {
63
+ forceExitOnce(code);
64
+ return;
65
+ }
66
+ start(code, true);
67
+ }
68
+ };
69
+ }
70
+ //#endregion
71
+ //#region lib/types/profile-boot.js
72
+ /**
73
+ * Shared profile boot for every `dsh` surface: resolve the profile, stack its
74
+ * patch layers (bundle layers in `dsh.profile.bundles` order, the profile's
75
+ * own `cordis.patch.yml`, `--patch` overlays), mount the
76
+ * tree over the profile's empty root config, keep the profile patch layer
77
+ * live, and wire fail-loud plus bounded shutdown.
78
+ *
79
+ * App flags are not the launcher's business: the invocation's inner arguments
80
+ * are provided to the tree through `ctx.cmdlineArgs`, where any injected app
81
+ * plugin may read the same immutable snapshot.
82
+ * @module @monotykamary/dsh/profile-boot
83
+ */
84
+ /** Shipped agent-preset root: beside this app's own config, in both source and built layouts. */
85
+ const SHIPPED_PRESET_ROOT = fileURLToPath(new URL("../config/agent-presets/", import.meta.url));
86
+ const NAME = "dsh";
87
+ /**
88
+ * The home-level user patch layer (`$DSH_HOME/cordis.patch.yml`), applied
89
+ * over every profile's own layer. Resolved per call, not at module load:
90
+ * `$DSH_HOME` may be set by the test or launcher after import.
91
+ * @returns the absolute patch-file path.
92
+ */
93
+ function homePatchPath() {
94
+ return join(resolveDshHome(), PROFILE_PATCH_FILENAME);
95
+ }
96
+ /** Absolute path of this dsh installation's package.json (both anchors: src/ and lib/ sit one level under apps/cli). */
97
+ const INSTALL_ANCHOR = fileURLToPath(new URL("../package.json", import.meta.url));
98
+ /** The empty root entry list every profile tree patches over. */
99
+ const PROFILE_ROOT_CONFIG = `# dsh profile root — an empty entry list. The tree is composed as patches:
100
+ # each bundle in package.json's dsh.profile.bundles, then cordis.patch.yml, then any
101
+ # --patch overlays. Edit cordis.patch.yml, not this file.
102
+ []
103
+ `;
104
+ /** Root config filename inside a profile directory. */
105
+ const PROFILE_ROOT_FILENAME = "cordis.yml";
106
+ /**
107
+ * Load a resolved profile for `name`: heal the shared module fallback, then
108
+ * (re)write the empty root config. The root is always rewritten: the whole
109
+ * composition is patch layers, and the vendored Loader's tree write-back (a
110
+ * plugin self-disposing persists the current tree) can bake composed rows
111
+ * into this file — which would duplicate every bundle insert on the next
112
+ * boot. The file exists on disk only because the Loader needs a real include
113
+ * root to anchor `baseUrl` at the profile directory (the config dump anchors
114
+ * on the same file, so both compose over the identical base).
115
+ * @param name - the profile name.
116
+ * @param userLayer - `false` skips parsing `cordis.patch.yml` (the default dump).
117
+ * @returns the loaded profile.
118
+ */
119
+ function prepareProfile(name, userLayer = true) {
120
+ healProfilesModuleFallback(INSTALL_ANCHOR);
121
+ const profile = loadProfile(NAME, name, INSTALL_ANCHOR, void 0, { userLayer });
122
+ writeFileSync(join(profile.dir, PROFILE_ROOT_FILENAME), PROFILE_ROOT_CONFIG);
123
+ return profile;
124
+ }
125
+ /** The full patch stack of one composed profile, in application order. */
126
+ function allPatches(composed) {
127
+ return [
128
+ ...composed.bundlePatches,
129
+ ...composed.profile.patches,
130
+ ...composed.homePatches,
131
+ ...composed.overlays
132
+ ];
133
+ }
134
+ /**
135
+ * Load `name` and compose its effective patch stack: bundle layers in
136
+ * `dsh.profile.bundles` order (the base bundle gates the shell stacks by
137
+ * platform on its own rows), the profile's user layer, the home-level user
138
+ * layer (`$DSH_HOME/cordis.patch.yml` — machine-local preferences that apply
139
+ * to every profile, so it outranks the per-profile layer), and `--patch`
140
+ * overlays.
141
+ * @param name - the profile name.
142
+ * @param patchFiles - `--patch` overlay paths, in argv order.
143
+ * @returns the profile, its patch layers, and the composed row index.
144
+ */
145
+ function composeProfile(name, patchFiles) {
146
+ const profile = prepareProfile(name);
147
+ const homePatches = loadOptionalPatches(NAME, homePatchPath()) ?? [];
148
+ const overlays = patchFiles.flatMap((file) => loadOverlayPatches(NAME, resolve(file)));
149
+ const bundlePatches = profile.layers.flatMap((layer) => layer.patches);
150
+ const toolMode = process.env.DSH_TOOLS_MODE;
151
+ if (toolMode !== void 0) {
152
+ const lastTools = [...bundlePatches].reverse().find((patch) => patch.id === "tools" && !Array.isArray(patch.insert));
153
+ const toolsConfig = lastTools?.config !== void 0 && typeof lastTools.config === "object" ? { ...lastTools.config } : {};
154
+ bundlePatches.push({
155
+ id: "tools",
156
+ config: {
157
+ ...toolsConfig,
158
+ mode: toolMode
159
+ }
160
+ });
161
+ }
162
+ if (bundlePatches.some((patch) => patch.id === "distribution-update" || Array.isArray(patch.insert) && patch.insert.some((row) => row.id === "distribution-update"))) bundlePatches.push({
163
+ id: "distribution-update",
164
+ config: { appManifest: INSTALL_ANCHOR }
165
+ });
166
+ const rows = /* @__PURE__ */ new Map();
167
+ for (const row of composeEntries([
168
+ bundlePatches,
169
+ profile.patches,
170
+ homePatches,
171
+ overlays
172
+ ])) if (typeof row.id === "string") rows.set(row.id, row);
173
+ const composedOverlays = [...overlays];
174
+ if (rows.has("agent-presets")) composedOverlays.push({
175
+ id: "agent-presets",
176
+ config: {
177
+ ...rows.get("agent-presets")?.config ?? {},
178
+ roots: [{
179
+ path: SHIPPED_PRESET_ROOT,
180
+ trust: "system"
181
+ }]
182
+ }
183
+ });
184
+ return {
185
+ profile,
186
+ bundlePatches,
187
+ homePatches,
188
+ overlays: composedOverlays,
189
+ rows
190
+ };
191
+ }
192
+ /**
193
+ * Re-throw a watcher-setup failure unless a shutdown already owns the tree:
194
+ * a signal aborted this invocation, or an app requested exit (`ctx.appExit`
195
+ * from a fast one-shot) and the root's disposal rejected the in-flight setup
196
+ * await. Either way the failure describes a tree that is exiting as asked,
197
+ * not a broken watch.
198
+ * @param ctx - the booted root context.
199
+ * @param signal - this invocation's signal-shutdown fact.
200
+ * @param error - the setup failure.
201
+ */
202
+ function suppressShutdownError(ctx, signal, error) {
203
+ if (signal.aborted) return;
204
+ if (ctx.fiber.state !== 2 || ctx.get("loader") === void 0) return;
205
+ throw error;
206
+ }
207
+ /**
208
+ * Boot one profile invocation end to end and leave process lifetime to the
209
+ * mounted plugins (or to a one-shot runner the composition mounts).
210
+ * @param options - environment snapshot, profile name, overlays, and the booted app's own arguments.
211
+ * @returns the settled root context and the shutdown controller.
212
+ */
213
+ async function runProfile(options) {
214
+ const composed = composeProfile(options.profile, options.patchFiles);
215
+ const app = {};
216
+ const shutdown = createProcessShutdown(async () => {
217
+ await app.current?.fiber.dispose();
218
+ });
219
+ const signalShutdown = new AbortController();
220
+ const interrupt = (code) => {
221
+ signalShutdown.abort();
222
+ shutdown.interrupt(code);
223
+ };
224
+ process.on("SIGTERM", () => {
225
+ interrupt(0);
226
+ });
227
+ process.on("SIGINT", () => {
228
+ interrupt(130);
229
+ });
230
+ installFailLoud(NAME, process, async () => {
231
+ await app.current?.fiber.dispose();
232
+ });
233
+ const rootConfig = join(composed.profile.dir, PROFILE_ROOT_FILENAME);
234
+ const composeLive = () => structuredClone([
235
+ ...composed.bundlePatches,
236
+ ...loadOptionalPatches(NAME, composed.profile.patchPath) ?? [],
237
+ ...loadOptionalPatches(NAME, homePatchPath()) ?? [],
238
+ ...composed.overlays
239
+ ]);
240
+ const ctx = await boot(NAME, rootConfig, structuredClone(allPatches(composed)), (hostCtx) => {
241
+ app.current = hostCtx;
242
+ hostCtx.provide(DSH_LAUNCH_ENVIRONMENT_KEY, options.environment);
243
+ provideCmdline(hostCtx, {
244
+ args: options.args,
245
+ exit: (code) => void shutdown.shutdown(code)
246
+ });
247
+ }, pathToFileURL(rootConfig).href);
248
+ app.current = ctx;
249
+ if (!signalShutdown.signal.aborted && ctx.fiber.state === 2 && ctx.get("loader") !== void 0 && ctx.get("headlessStartup") === void 0) try {
250
+ if (ctx.get("hmr") === void 0) {
251
+ if (ctx.get("timer") === void 0) await ctx.loader.create({ name: "@monotykamary/cordis-plugin-timer" });
252
+ await ctx.loader.create({
253
+ name: "@monotykamary/cordis-plugin-hmr",
254
+ config: { root: [] }
255
+ });
256
+ }
257
+ await watchUserPatches(ctx, {
258
+ binName: NAME,
259
+ filename: composed.profile.patchPath,
260
+ compose: composeLive
261
+ });
262
+ await watchUserPatches(ctx, {
263
+ binName: NAME,
264
+ filename: homePatchPath(),
265
+ compose: composeLive
266
+ });
267
+ } catch (error) {
268
+ suppressShutdownError(ctx, signalShutdown.signal, error);
269
+ }
270
+ return {
271
+ ctx,
272
+ shutdown
273
+ };
274
+ }
275
+ //#endregion
276
+ export { runProfile as a, prepareProfile as i, PROFILE_ROOT_FILENAME as n, homePatchPath as r, INSTALL_ANCHOR as t };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@monotykamary/dsh",
3
3
  "description": "dsh CLI: profile boot, plugin management, and the browser UI alias",
4
- "version": "0.1.7",
4
+ "version": "0.1.9",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -20,101 +20,101 @@
20
20
  ],
21
21
  "license": "MIT",
22
22
  "dependencies": {
23
+ "@monotykamary/cordis-plugin-group": "^1.0.1",
24
+ "@monotykamary/cordis-plugin-hmr": "^1.0.16",
25
+ "@monotykamary/cordis-plugin-include": "^1.0.6",
26
+ "@monotykamary/cordis-plugin-loader": "^1.0.2",
27
+ "@monotykamary/cordis-plugin-timer": "^1.1.3",
28
+ "@monotykamary/dsh-agent-tool-presentation": "^0.1.9",
29
+ "@monotykamary/dsh-app-boot": "^0.1.9",
30
+ "@monotykamary/dsh-base": "^0.1.9",
31
+ "@monotykamary/dsh-cordis-client-runner": "^0.1.9",
32
+ "@monotykamary/dsh-client-ui-agent-preset": "^0.1.9",
33
+ "@monotykamary/dsh-client-ui-cordis": "^0.1.9",
34
+ "@monotykamary/dsh-command-compact": "^0.1.9",
35
+ "@monotykamary/dsh-command-goal": "^0.1.9",
36
+ "@monotykamary/dsh-compaction-basic": "^0.1.9",
37
+ "@monotykamary/dsh-compaction-tool-result-pruner": "^0.1.9",
38
+ "@monotykamary/dsh-goal": "^0.1.9",
39
+ "@monotykamary/dsh-goal-round-driver": "^0.1.9",
40
+ "@monotykamary/dsh-cmdline": "^0.1.9",
41
+ "@monotykamary/dsh-launch-environment": "^0.1.9",
42
+ "@monotykamary/dsh-fs-local": "^0.1.9",
43
+ "@monotykamary/dsh-headless": "^0.1.9",
44
+ "@monotykamary/dsh-mcp-client": "^0.1.9",
45
+ "@monotykamary/dsh-home-paths": "^0.1.9",
46
+ "@monotykamary/dsh-persona": "^0.1.9",
47
+ "@monotykamary/dsh-plan-mode": "^0.1.9",
48
+ "@monotykamary/dsh-terminal": "^0.1.9",
49
+ "@monotykamary/dsh-terminal-bash": "^0.1.9",
50
+ "@monotykamary/dsh-pwsh-local": "^0.1.9",
51
+ "@monotykamary/dsh-pwsh-sandbox": "^0.1.9",
52
+ "@monotykamary/dsh-session-projection": "^0.1.9",
53
+ "@monotykamary/dsh-session-reference": "^0.1.9",
54
+ "@monotykamary/dsh-time-context": "^0.1.9",
55
+ "@monotykamary/dsh-skill": "^0.1.9",
56
+ "@monotykamary/dsh-skill-filesystem": "^0.1.9",
57
+ "@monotykamary/dsh-jobs-local": "^0.1.9",
58
+ "@monotykamary/dsh-tmux-context": "^0.1.9",
59
+ "@monotykamary/dsh-token-meter": "^0.1.9",
60
+ "@monotykamary/dsh-tool-ask-user": "^0.1.9",
61
+ "@monotykamary/dsh-tool-bash": "^0.1.9",
62
+ "@monotykamary/dsh-tool-bash-persistent": "^0.1.9",
63
+ "@monotykamary/dsh-tool-pwsh-persistent": "^0.1.9",
64
+ "@monotykamary/dsh-tool-cordis": "^0.1.9",
65
+ "@monotykamary/dsh-tool-fs": "^0.1.9",
66
+ "@monotykamary/dsh-tool-fs-search": "^0.1.9",
67
+ "@monotykamary/dsh-tool-goal": "^0.1.9",
68
+ "@monotykamary/dsh-tool-pwsh": "^0.1.9",
69
+ "@monotykamary/dsh-tool-ralph": "^0.1.9",
70
+ "@monotykamary/dsh-schedule": "^0.1.9",
71
+ "@monotykamary/dsh-tool-skill": "^0.1.9",
72
+ "@monotykamary/dsh-tool-str-replace-editor": "^0.1.9",
73
+ "@monotykamary/dsh-tool-subagent": "^0.1.9",
74
+ "@monotykamary/dsh-tool-subagent-control": "^0.1.9",
75
+ "@monotykamary/dsh-tool-jobs": "^0.1.9",
76
+ "@monotykamary/dsh-tool-todo": "^0.1.9",
77
+ "@monotykamary/dsh-tool-web": "^0.1.9",
78
+ "@monotykamary/dsh-tool-workflow": "^0.1.9",
79
+ "@monotykamary/dsh-web-app": "^0.1.9",
80
+ "@monotykamary/dsh-workflow-worker-thread": "^0.1.9",
81
+ "@monotykamary/dsh-agent-instructions": "^0.1.9",
23
82
  "commander": "^15.0.0",
83
+ "@monotykamary/cordis": "^4.0.1",
24
84
  "js-yaml": "^4.2.0",
25
85
  "node-addon-require-builtin": "^0.1.4",
26
86
  "dsh-tool-repair": "0.1.1",
27
87
  "dsh-multiprovider": "0.1.1",
28
- "dsh-fabric": "0.1.7",
88
+ "dsh-fabric": "0.1.12",
29
89
  "dsh-fovea": "0.5.1",
30
- "dsh-factory": "0.1.8",
31
- "@monotykamary/cordis-plugin-group": "^1.0.1",
32
- "@monotykamary/cordis-plugin-include": "^1.0.6",
33
- "@monotykamary/cordis-plugin-loader": "^1.0.2",
34
- "@monotykamary/cordis-plugin-hmr": "^1.0.16",
35
- "@monotykamary/cordis-plugin-timer": "^1.1.3",
36
- "@monotykamary/dsh-agent-tool-presentation": "^0.1.7",
37
- "@monotykamary/dsh-app-boot": "^0.1.7",
38
- "@monotykamary/dsh-base": "^0.1.7",
39
- "@monotykamary/dsh-client-ui-agent-preset": "^0.1.7",
40
- "@monotykamary/dsh-client-ui-cordis": "^0.1.7",
41
- "@monotykamary/dsh-command-compact": "^0.1.7",
42
- "@monotykamary/dsh-command-goal": "^0.1.7",
43
- "@monotykamary/dsh-cordis-client-runner": "^0.1.7",
44
- "@monotykamary/dsh-compaction-basic": "^0.1.7",
45
- "@monotykamary/dsh-goal": "^0.1.7",
46
- "@monotykamary/dsh-compaction-tool-result-pruner": "^0.1.7",
47
- "@monotykamary/dsh-goal-round-driver": "^0.1.7",
48
- "@monotykamary/dsh-cmdline": "^0.1.7",
49
- "@monotykamary/dsh-launch-environment": "^0.1.7",
50
- "@monotykamary/dsh-headless": "^0.1.7",
51
- "@monotykamary/dsh-fs-local": "^0.1.7",
52
- "@monotykamary/dsh-mcp-client": "^0.1.7",
53
- "@monotykamary/dsh-home-paths": "^0.1.7",
54
- "@monotykamary/dsh-plan-mode": "^0.1.7",
55
- "@monotykamary/dsh-terminal": "^0.1.7",
56
- "@monotykamary/dsh-terminal-bash": "^0.1.7",
57
- "@monotykamary/dsh-pwsh-sandbox": "^0.1.7",
58
- "@monotykamary/dsh-session-projection": "^0.1.7",
59
- "@monotykamary/dsh-persona": "^0.1.7",
60
- "@monotykamary/dsh-pwsh-local": "^0.1.7",
61
- "@monotykamary/dsh-time-context": "^0.1.7",
62
- "@monotykamary/dsh-skill": "^0.1.7",
63
- "@monotykamary/dsh-session-reference": "^0.1.7",
64
- "@monotykamary/dsh-skill-filesystem": "^0.1.7",
65
- "@monotykamary/dsh-jobs-local": "^0.1.7",
66
- "@monotykamary/dsh-token-meter": "^0.1.7",
67
- "@monotykamary/dsh-tool-ask-user": "^0.1.7",
68
- "@monotykamary/dsh-tool-bash": "^0.1.7",
69
- "@monotykamary/dsh-tool-pwsh-persistent": "^0.1.7",
70
- "@monotykamary/dsh-tool-cordis": "^0.1.7",
71
- "@monotykamary/dsh-tool-bash-persistent": "^0.1.7",
72
- "@monotykamary/dsh-tmux-context": "^0.1.7",
73
- "@monotykamary/dsh-tool-fs": "^0.1.7",
74
- "@monotykamary/dsh-tool-fs-search": "^0.1.7",
75
- "@monotykamary/dsh-tool-pwsh": "^0.1.7",
76
- "@monotykamary/dsh-tool-goal": "^0.1.7",
77
- "@monotykamary/dsh-tool-ralph": "^0.1.7",
78
- "@monotykamary/dsh-schedule": "^0.1.7",
79
- "@monotykamary/dsh-tool-skill": "^0.1.7",
80
- "@monotykamary/dsh-tool-str-replace-editor": "^0.1.7",
81
- "@monotykamary/dsh-tool-subagent-control": "^0.1.7",
82
- "@monotykamary/dsh-tool-jobs": "^0.1.7",
83
- "@monotykamary/dsh-tool-todo": "^0.1.7",
84
- "@monotykamary/dsh-tool-subagent": "^0.1.7",
85
- "@monotykamary/dsh-tool-workflow": "^0.1.7",
86
- "@monotykamary/dsh-tool-web": "^0.1.7",
87
- "@monotykamary/dsh-web-app": "^0.1.7",
88
- "@monotykamary/dsh-workflow-worker-thread": "^0.1.7",
89
- "@monotykamary/dsh-agent-instructions": "^0.1.7",
90
- "@monotykamary/dsh-distribution-update": "^0.1.7",
91
- "@monotykamary/cordis": "^4.0.1"
90
+ "dsh-factory": "0.1.9",
91
+ "@monotykamary/dsh-distribution-update": "^0.1.9"
92
92
  },
93
93
  "devDependencies": {
94
+ "@monotykamary/dsh-agent": "^0.1.9",
95
+ "@monotykamary/dsh-host-frontend-static": "^0.1.9",
96
+ "@monotykamary/dsh-host-apiproxy": "^0.1.9",
97
+ "@monotykamary/dsh-host-webserver": "^0.1.9",
98
+ "@monotykamary/dsh-llm": "^0.1.9",
99
+ "@monotykamary/dsh-llm-mock-server": "^0.1.9",
100
+ "@monotykamary/dsh-loader-smoke": "^0.1.9",
101
+ "@monotykamary/dsh-session": "^0.1.9",
102
+ "@monotykamary/dsh-settings": "^0.1.9",
103
+ "@monotykamary/dsh-subagent": "^0.1.9",
104
+ "@monotykamary/dsh-system-prompt": "^0.1.9",
105
+ "@monotykamary/dsh-tools": "^0.1.9",
94
106
  "@types/js-yaml": "^4.0.9",
95
- "execa": "^10.0.0",
96
- "@monotykamary/dsh-agent": "^0.1.7",
97
- "@monotykamary/dsh-host-frontend-static": "^0.1.7",
98
- "@monotykamary/dsh-host-webserver": "^0.1.7",
99
- "@monotykamary/dsh-llm": "^0.1.7",
100
- "@monotykamary/dsh-loader-smoke": "^0.1.7",
101
- "@monotykamary/dsh-llm-mock-server": "^0.1.7",
102
- "@monotykamary/dsh-session": "^0.1.7",
103
- "@monotykamary/dsh-host-apiproxy": "^0.1.7",
104
- "@monotykamary/dsh-subagent": "^0.1.7",
105
- "@monotykamary/dsh-settings": "^0.1.7",
106
- "@monotykamary/dsh-tools": "^0.1.7",
107
- "@monotykamary/dsh-system-prompt": "^0.1.7"
107
+ "execa": "^10.0.0"
108
108
  },
109
109
  "dsh": {
110
110
  "distribution": {
111
111
  "companions": {
112
112
  "dsh-tool-repair": "0.1.1",
113
113
  "dsh-multiprovider": "0.1.1",
114
- "dsh-fabric": "0.1.7",
114
+ "dsh-fabric": "0.1.12",
115
115
  "dsh-fovea": "0.5.1",
116
- "dsh-factory": "0.1.8"
116
+ "dsh-factory": "0.1.9"
117
117
  }
118
118
  }
119
119
  }
120
- }
120
+ }
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 DeepSeek
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.