@lihuu/dsh-about 0.1.0 → 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
@@ -1,40 +1,33 @@
1
- # dsh-about
1
+ # @lihuu/dsh-about
2
2
 
3
- "About" settings section for DeepSeek Harness web GUI. Registers a "关于" page in the settings panel that shows the running version and build date, read live from the host zero main-repo changes.
3
+ A [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) plugin that adds an **About** page to the web GUI settings panel.
4
4
 
5
5
  ## What it does
6
6
 
7
- - **Host half** (`src/index.ts`): registers the `aboutInfo` Typert Remote service. `aboutInfo/get` reads the running version from `apps/cli/package.json` and the build date from the built CLI's mtime (`apps/cli/lib/bin.js`).
8
- - **Browser half** (`lib/client.js`): registers a "关于" page into the `settings.section` list slot and resolves the data through `connection.rpc.call('/api', 'aboutInfo/get')`.
7
+ - Shows the **running version** of DeepSeek Harness
8
+ - Shows the **build date** of the currently running build
9
+ - Values are read live on every page open, so they always reflect the current build
9
10
 
10
- ## Install
11
+ ## Requirements
11
12
 
12
- From the `dsh-plugins` repo root:
13
+ - [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 0.1.2+
13
14
 
14
- ```sh
15
- ./install.sh
16
- ```
15
+ ## Install
17
16
 
18
- This symlinks the plugin into `$DSH_HOME/plugins/dsh-about` and adds its row to `$DSH_HOME/cordis.patch.yml`. Then restart dsh-web:
17
+ The package is a **bundle**: it ships its own configuration layer, so installing it into a profile activates the plugin automatically.
19
18
 
20
19
  ```sh
21
- launchctl kickstart -k gui/501/com.lihu.dsh-web
20
+ dsh plugin --profile web add @lihuu/dsh-about
22
21
  ```
23
22
 
24
- ## Build
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.
25
24
 
26
- The host half is TypeScript; rebuild it after editing `src/index.ts`:
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.
27
26
 
28
- ```sh
29
- cd plugins/dsh-about && ./node_modules/typescript/bin/tsc -p tsconfig.json
30
- ```
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`.
31
28
 
32
- The browser half (`lib/client.js`) is hand-written plain JS and needs no build.
29
+ Then open **Settings About** in the GUI.
33
30
 
34
- ## Notes
31
+ ## License
35
32
 
36
- - The harness checkout path is read from `$DSH_REPO` (falling back to the
37
- process working directory), so the plugin carries no machine-specific path.
38
- Export `DSH_REPO` in your launchd env (the dsh-plugins `env.sh` does) or run
39
- dsh from its checkout.
40
- - Version and build date are read live on each page open, so they always reflect the currently running build.
33
+ MIT
@@ -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.0",
4
- "description": "About section for DeepSeek Harness web GUI settings: shows the running version and build date, read live from the host (apps/cli/package.json + built CLI mtime) — zero main-repo changes.",
3
+ "version": "0.1.3",
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