@lihuu/dsh-about 0.1.2 → 0.1.3

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 CHANGED
@@ -14,11 +14,19 @@ A [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) plugin tha
14
14
 
15
15
  ## Install
16
16
 
17
+ The package is a **bundle**: it ships its own configuration layer, so installing it into a profile activates the plugin automatically.
18
+
17
19
  ```sh
18
20
  dsh plugin --profile web add @lihuu/dsh-about
19
21
  ```
20
22
 
21
- Restart the web service, then open **Settings About** in the GUI.
23
+ `dsh plugin add` appends the bundle to the profile's layer stack (`dsh.profile.bundles`), and the bundle's patch file mounts the plugin row. No manual patch editing is needed.
24
+
25
+ > If you previously mounted this plugin by hand (a `dsh-about` row in `~/.dsh/cordis.patch.yml`), remove that row before installing the bundle — the duplicate row id fails the boot.
26
+
27
+ Restart the web service once after installing (bundle layers are composed at boot). Later edits to your own patch files hot-reload on profiles with `patchReload: live`.
28
+
29
+ Then open **Settings → About** in the GUI.
22
30
 
23
31
  ## License
24
32
 
@@ -0,0 +1,6 @@
1
+ # The dsh-about bundle patch: mounts the About page plugin row.
2
+ # Applied as a profile layer when the profile lists this bundle; the row
3
+ # references the package by name so Node resolution finds the installed code.
4
+ - insert:
5
+ - id: dsh-about
6
+ name: '@lihuu/dsh-about'
package/lib/client.js CHANGED
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * dsh-about — independent "About" settings section (BROWSER half).
3
3
  *
4
- * Plain-JS client bundle served as `/plugins/@local/dsh-about/client.js`.
5
- * Registers the "关于" page into the settings.section list slot and resolves
4
+ * Plain-JS client bundle served as `/plugins/@lihuu/dsh-about/client.js`.
5
+ * Registers the "About" page into the settings.section list slot and resolves
6
6
  * the running version + build date through the host's runtime Typert Remote
7
7
  * endpoint `aboutInfo/get` via the generic `/api` RPC channel — no generated
8
8
  * artifacts, no main-repo changes.
package/lib/index.d.ts CHANGED
@@ -3,12 +3,11 @@
3
3
  * (HOST half).
4
4
  *
5
5
  * Provides the `aboutInfo` Typert Remote service: the browser half's settings
6
- * "关于" page resolves the running version and build date through the runtime
6
+ * "About" page resolves the running version and build date through the runtime
7
7
  * `aboutInfo/get` endpoint. The host gateway (`dsh-api-gateway`) dispatches
8
8
  * `/api/aboutInfo/get` to this live service via source-mode discovery
9
- * (`typertRemote` binding + `Remote` markers), so NO compile-time generated
10
- * artifacts and NO main-repo changes are involved: the whole feature mounts as
11
- * an installable `@local` plugin.
9
+ * (`typertRemote` binding + `Remote` markers), so no compile-time generated
10
+ * artifacts and no main-repo changes are involved.
12
11
  *
13
12
  * @module dsh-about
14
13
  */
@@ -18,9 +17,9 @@ import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
18
17
  export declare const name = "dsh-about";
19
18
  /** The about payload the settings page renders. */
20
19
  export interface AboutInfo {
21
- /** Running version, read from apps/cli/package.json. */
20
+ /** Running version, read from the dsh CLI's package.json. */
22
21
  readonly version: string;
23
- /** Build date, from the built CLI's mtime. */
22
+ /** Build date, from the built CLI entry's mtime. */
24
23
  readonly buildDate: string;
25
24
  }
26
25
  /**
@@ -37,7 +36,7 @@ export declare class AboutInfoService extends TypertRemoteService {
37
36
  constructor(ctx: Context);
38
37
  /**
39
38
  * Read the running version and build date.
40
- * @Remote('get') — invoked by the host gateway in source mode.
39
+ * @Remote('get') — invoked by the host gateway.
41
40
  * @returns version + build date; unknown fields degrade to 'unknown'.
42
41
  */
43
42
  get(): Promise<AboutInfo>;
package/lib/index.js CHANGED
@@ -3,12 +3,11 @@
3
3
  * (HOST half).
4
4
  *
5
5
  * Provides the `aboutInfo` Typert Remote service: the browser half's settings
6
- * "关于" page resolves the running version and build date through the runtime
6
+ * "About" page resolves the running version and build date through the runtime
7
7
  * `aboutInfo/get` endpoint. The host gateway (`dsh-api-gateway`) dispatches
8
8
  * `/api/aboutInfo/get` to this live service via source-mode discovery
9
- * (`typertRemote` binding + `Remote` markers), so NO compile-time generated
10
- * artifacts and NO main-repo changes are involved: the whole feature mounts as
11
- * an installable `@local` plugin.
9
+ * (`typertRemote` binding + `Remote` markers), so no compile-time generated
10
+ * artifacts and no main-repo changes are involved.
12
11
  *
13
12
  * @module dsh-about
14
13
  */
@@ -46,17 +45,56 @@ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn,
46
45
  if (target) Object.defineProperty(target, contextIn.name, descriptor);
47
46
  done = true;
48
47
  };
48
+ import { realpathSync } from 'node:fs';
49
+ import { dirname, join } from 'node:path';
49
50
  import { TypertRemoteService, Remote } from '@deepseek-ai/dsh-typert-protocol';
50
51
  /** Stable plugin row name (used by the cordis loader entry). */
51
52
  export const name = 'dsh-about';
52
53
  /**
53
- * Harness source checkout this deployment runs from. Read from `$DSH_REPO`
54
- * (the launchd env.sh exports it) so the plugin carries no machine-specific
55
- * path; falls back to the process working directory, which is the repo root
56
- * when dsh is launched from its checkout. A wrong value degrades to 'unknown'
57
- * via the try/catch below.
54
+ * Absolute paths of the running dsh CLI's package.json, most specific first.
55
+ * Mirrors the CLI's own version resolution (`../package.json` relative to its
56
+ * entry script) so any install layout resolves: a source checkout exporting
57
+ * `$DSH_REPO`, the running CLI entry (`process.argv[1]`, symlink-resolved for
58
+ * npm-installed bins), or a source checkout launched from its root.
58
59
  */
59
- const REPO = process.env.DSH_REPO ?? process.cwd();
60
+ function cliManifestCandidates() {
61
+ const candidates = [];
62
+ const repo = process.env.DSH_REPO;
63
+ if (repo !== undefined)
64
+ candidates.push(join(repo, 'apps/cli/package.json'));
65
+ const entry = process.argv[1];
66
+ if (entry !== undefined) {
67
+ try {
68
+ candidates.push(join(dirname(realpathSync(entry)), '../package.json'));
69
+ }
70
+ catch {
71
+ // entry path unresolvable — try the remaining candidates
72
+ }
73
+ }
74
+ candidates.push(join(process.cwd(), 'apps/cli/package.json'));
75
+ return candidates;
76
+ }
77
+ /**
78
+ * Absolute paths of the running dsh CLI's built entry file, most specific
79
+ * first; its mtime is the build date.
80
+ */
81
+ function cliEntryCandidates() {
82
+ const candidates = [];
83
+ const entry = process.argv[1];
84
+ if (entry !== undefined) {
85
+ try {
86
+ candidates.push(realpathSync(entry));
87
+ }
88
+ catch {
89
+ // entry path unresolvable — try the remaining candidates
90
+ }
91
+ }
92
+ const repo = process.env.DSH_REPO;
93
+ if (repo !== undefined)
94
+ candidates.push(join(repo, 'apps/cli/lib/bin.js'));
95
+ candidates.push(join(process.cwd(), 'apps/cli/lib/bin.js'));
96
+ return candidates;
97
+ }
60
98
  /**
61
99
  * About info remote service. Registered under `aboutInfo`; the `get` method is
62
100
  * the single `@Remote` endpoint the browser half calls through
@@ -85,36 +123,43 @@ let AboutInfoService = (() => {
85
123
  }
86
124
  /**
87
125
  * Read the running version and build date.
88
- * @Remote('get') — invoked by the host gateway in source mode.
126
+ * @Remote('get') — invoked by the host gateway.
89
127
  * @returns version + build date; unknown fields degrade to 'unknown'.
90
128
  */
91
129
  async get() {
92
130
  let version = 'unknown';
93
131
  let buildDate = 'unknown';
94
132
  if (this.fs !== undefined) {
95
- try {
96
- const target = await this.fs.resolve(`${REPO}/apps/cli/package.json`);
97
- const text = await this.fs.readText(target);
98
- const m = text.match(/"version"\s*:\s*"([^"]+)"/);
99
- if (m !== null)
100
- version = m[1];
101
- }
102
- catch {
103
- // fs unavailable or read failed — keep 'unknown'
133
+ for (const manifest of cliManifestCandidates()) {
134
+ try {
135
+ const target = await this.fs.resolve(manifest);
136
+ const text = await this.fs.readText(target);
137
+ const m = text.match(/"version"\s*:\s*"([^"]+)"/);
138
+ if (m !== null) {
139
+ version = m[1];
140
+ break;
141
+ }
142
+ }
143
+ catch {
144
+ // candidate unreadable — try the next one
145
+ }
104
146
  }
105
147
  }
106
148
  if (this.shell !== undefined) {
107
- try {
108
- const spec = this.shell.resolve({
109
- command: `stat -f "%Sm" -t "%Y-%m-%d %H:%M" ${REPO}/apps/cli/lib/bin.js`,
110
- });
111
- const result = await this.shell.run(spec);
112
- const out = result.stdout.text.trim();
113
- if (out !== '')
114
- buildDate = out;
115
- }
116
- catch {
117
- // shell unavailable or stat failed — keep 'unknown'
149
+ const flag = process.platform === 'darwin' ? '-f "%Sm" -t "%Y-%m-%d %H:%M"' : '-c "%y"';
150
+ for (const entry of cliEntryCandidates()) {
151
+ try {
152
+ const spec = this.shell.resolve({ command: `stat ${flag} "${entry}"` });
153
+ const result = await this.shell.run(spec);
154
+ const out = result.stdout.text.trim();
155
+ if (out !== '') {
156
+ buildDate = out;
157
+ break;
158
+ }
159
+ }
160
+ catch {
161
+ // candidate unstat-able — try the next one
162
+ }
118
163
  }
119
164
  }
120
165
  return { version, buildDate };
package/package.json CHANGED
@@ -1,22 +1,30 @@
1
1
  {
2
2
  "name": "@lihuu/dsh-about",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "DeepSeek Harness plugin: adds an About page to the web GUI settings showing the running version and build date.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "exports": {
8
8
  ".": "./lib/index.js",
9
9
  "./client": "./lib/client.js",
10
+ "./cordis.patch.yml": "./cordis.patch.yml",
10
11
  "./package.json": "./package.json"
11
12
  },
12
13
  "dsh": {
13
14
  "client": {
14
15
  "platform": "web"
16
+ },
17
+ "bundle": {
18
+ "patch": "./cordis.patch.yml"
15
19
  }
16
20
  },
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
17
24
  "files": [
18
25
  "lib",
19
26
  "src",
27
+ "cordis.patch.yml",
20
28
  "README.md"
21
29
  ],
22
30
  "scripts": {
package/src/index.ts CHANGED
@@ -3,16 +3,17 @@
3
3
  * (HOST half).
4
4
  *
5
5
  * Provides the `aboutInfo` Typert Remote service: the browser half's settings
6
- * "关于" page resolves the running version and build date through the runtime
6
+ * "About" page resolves the running version and build date through the runtime
7
7
  * `aboutInfo/get` endpoint. The host gateway (`dsh-api-gateway`) dispatches
8
8
  * `/api/aboutInfo/get` to this live service via source-mode discovery
9
- * (`typertRemote` binding + `Remote` markers), so NO compile-time generated
10
- * artifacts and NO main-repo changes are involved: the whole feature mounts as
11
- * an installable `@local` plugin.
9
+ * (`typertRemote` binding + `Remote` markers), so no compile-time generated
10
+ * artifacts and no main-repo changes are involved.
12
11
  *
13
12
  * @module dsh-about
14
13
  */
15
14
 
15
+ import { realpathSync } from 'node:fs'
16
+ import { dirname, join } from 'node:path'
16
17
  import type { Context } from '@deepseek-ai/cordis'
17
18
  import { TypertRemoteService, Remote } from '@deepseek-ai/dsh-typert-protocol'
18
19
 
@@ -21,9 +22,9 @@ export const name = 'dsh-about'
21
22
 
22
23
  /** The about payload the settings page renders. */
23
24
  export interface AboutInfo {
24
- /** Running version, read from apps/cli/package.json. */
25
+ /** Running version, read from the dsh CLI's package.json. */
25
26
  readonly version: string
26
- /** Build date, from the built CLI's mtime. */
27
+ /** Build date, from the built CLI entry's mtime. */
27
28
  readonly buildDate: string
28
29
  }
29
30
 
@@ -43,13 +44,47 @@ interface ShellLike {
43
44
  }
44
45
 
45
46
  /**
46
- * Harness source checkout this deployment runs from. Read from `$DSH_REPO`
47
- * (the launchd env.sh exports it) so the plugin carries no machine-specific
48
- * path; falls back to the process working directory, which is the repo root
49
- * when dsh is launched from its checkout. A wrong value degrades to 'unknown'
50
- * via the try/catch below.
47
+ * Absolute paths of the running dsh CLI's package.json, most specific first.
48
+ * Mirrors the CLI's own version resolution (`../package.json` relative to its
49
+ * entry script) so any install layout resolves: a source checkout exporting
50
+ * `$DSH_REPO`, the running CLI entry (`process.argv[1]`, symlink-resolved for
51
+ * npm-installed bins), or a source checkout launched from its root.
51
52
  */
52
- const REPO = process.env.DSH_REPO ?? process.cwd()
53
+ function cliManifestCandidates(): string[] {
54
+ const candidates: string[] = []
55
+ const repo = process.env.DSH_REPO
56
+ if (repo !== undefined) candidates.push(join(repo, 'apps/cli/package.json'))
57
+ const entry = process.argv[1]
58
+ if (entry !== undefined) {
59
+ try {
60
+ candidates.push(join(dirname(realpathSync(entry)), '../package.json'))
61
+ } catch {
62
+ // entry path unresolvable — try the remaining candidates
63
+ }
64
+ }
65
+ candidates.push(join(process.cwd(), 'apps/cli/package.json'))
66
+ return candidates
67
+ }
68
+
69
+ /**
70
+ * Absolute paths of the running dsh CLI's built entry file, most specific
71
+ * first; its mtime is the build date.
72
+ */
73
+ function cliEntryCandidates(): string[] {
74
+ const candidates: string[] = []
75
+ const entry = process.argv[1]
76
+ if (entry !== undefined) {
77
+ try {
78
+ candidates.push(realpathSync(entry))
79
+ } catch {
80
+ // entry path unresolvable — try the remaining candidates
81
+ }
82
+ }
83
+ const repo = process.env.DSH_REPO
84
+ if (repo !== undefined) candidates.push(join(repo, 'apps/cli/lib/bin.js'))
85
+ candidates.push(join(process.cwd(), 'apps/cli/lib/bin.js'))
86
+ return candidates
87
+ }
53
88
 
54
89
  /**
55
90
  * About info remote service. Registered under `aboutInfo`; the `get` method is
@@ -71,7 +106,7 @@ export class AboutInfoService extends TypertRemoteService {
71
106
 
72
107
  /**
73
108
  * Read the running version and build date.
74
- * @Remote('get') — invoked by the host gateway in source mode.
109
+ * @Remote('get') — invoked by the host gateway.
75
110
  * @returns version + build date; unknown fields degrade to 'unknown'.
76
111
  */
77
112
  @Remote('get')
@@ -80,26 +115,35 @@ export class AboutInfoService extends TypertRemoteService {
80
115
  let buildDate = 'unknown'
81
116
 
82
117
  if (this.fs !== undefined) {
83
- try {
84
- const target = await this.fs.resolve(`${REPO}/apps/cli/package.json`)
85
- const text = await this.fs.readText(target)
86
- const m = text.match(/"version"\s*:\s*"([^"]+)"/)
87
- if (m !== null) version = m[1]
88
- } catch {
89
- // fs unavailable or read failed — keep 'unknown'
118
+ for (const manifest of cliManifestCandidates()) {
119
+ try {
120
+ const target = await this.fs.resolve(manifest)
121
+ const text = await this.fs.readText(target)
122
+ const m = text.match(/"version"\s*:\s*"([^"]+)"/)
123
+ if (m !== null) {
124
+ version = m[1]
125
+ break
126
+ }
127
+ } catch {
128
+ // candidate unreadable — try the next one
129
+ }
90
130
  }
91
131
  }
92
132
 
93
133
  if (this.shell !== undefined) {
94
- try {
95
- const spec = this.shell.resolve({
96
- command: `stat -f "%Sm" -t "%Y-%m-%d %H:%M" ${REPO}/apps/cli/lib/bin.js`,
97
- })
98
- const result = await this.shell.run(spec)
99
- const out = result.stdout.text.trim()
100
- if (out !== '') buildDate = out
101
- } catch {
102
- // shell unavailable or stat failed — keep 'unknown'
134
+ const flag = process.platform === 'darwin' ? '-f "%Sm" -t "%Y-%m-%d %H:%M"' : '-c "%y"'
135
+ for (const entry of cliEntryCandidates()) {
136
+ try {
137
+ const spec = this.shell.resolve({ command: `stat ${flag} "${entry}"` })
138
+ const result = await this.shell.run(spec)
139
+ const out = result.stdout.text.trim()
140
+ if (out !== '') {
141
+ buildDate = out
142
+ break
143
+ }
144
+ } catch {
145
+ // candidate unstat-able — try the next one
146
+ }
103
147
  }
104
148
  }
105
149