dsh-lark-agent 0.3.1 → 0.3.2
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 +1 -1
- package/dist/onboarding/host.d.ts +3 -2
- package/dist/onboarding/host.js +2 -2
- package/dist/onboarding/updates.d.ts +13 -3
- package/dist/onboarding/updates.js +24 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -53,7 +53,7 @@ Then restart `dsh web`.
|
|
|
53
53
|
|
|
54
54
|
### Update
|
|
55
55
|
|
|
56
|
-
When a new version
|
|
56
|
+
When a new version has been out for a day, the Feishu settings page shows a notice with these steps (in the desktop app it also opens the plugin list for you). Until then the desktop app and `dsh plugin` still install the previous version, because pnpm 11 skips releases less than 24 hours old. If an install picks an older version that your DeepSeek Harness rejects as incompatible, see [Troubleshooting](https://github.com/Nirvana-Jie/dsh-lark-agent/blob/main/DEVELOPMENT.md#排障).
|
|
57
57
|
|
|
58
58
|
1. On the Feishu settings page, click **暂停连接** (pause) and back up as described in [Upgrade](https://github.com/Nirvana-Jie/dsh-lark-agent/blob/main/DEVELOPMENT.md#升级).
|
|
59
59
|
2. Desktop app: the Add plugin dialog says third-party plugins must be uninstalled before a new version is installed, so uninstall `dsh-lark-agent` on the Plugins page and add it again (this in-app upgrade hasn't been tested end to end yet; an earlier source build is listed as `dsh-larkbot`). CLI: run `dsh plugin --profile web update dsh-lark-agent@latest`, then restart `dsh web`.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Context } from '@deepseek-ai/cordis';
|
|
2
2
|
import { ConnectionController } from './controller.js';
|
|
3
3
|
import type { ConnectionResult } from './protocol.js';
|
|
4
|
+
import { type Release } from './updates.js';
|
|
4
5
|
interface Peer {
|
|
5
6
|
principal?: {
|
|
6
7
|
kind?: string;
|
|
@@ -29,11 +30,11 @@ export declare function registerConnectionRpc(rpc: RpcHost, controller: Connecti
|
|
|
29
30
|
export declare function findLarkExecutable(explicit?: string): Promise<string>;
|
|
30
31
|
/**
|
|
31
32
|
* Attach the control plane without requiring any user-written team configuration.
|
|
32
|
-
* `
|
|
33
|
+
* `latestRelease` replaces the npm lookup behind the upgrade notice (tests use it to stay offline).
|
|
33
34
|
*/
|
|
34
35
|
export declare function applyOnboarding(ctx: Context, options?: {
|
|
35
36
|
dataDir?: string;
|
|
36
37
|
executable?: string;
|
|
37
|
-
|
|
38
|
+
latestRelease?: (signal: AbortSignal) => Promise<Release | undefined>;
|
|
38
39
|
}): Promise<void>;
|
|
39
40
|
export {};
|
package/dist/onboarding/host.js
CHANGED
|
@@ -203,7 +203,7 @@ async function waitReady(service, signal) {
|
|
|
203
203
|
}
|
|
204
204
|
/**
|
|
205
205
|
* Attach the control plane without requiring any user-written team configuration.
|
|
206
|
-
* `
|
|
206
|
+
* `latestRelease` replaces the npm lookup behind the upgrade notice (tests use it to stay offline).
|
|
207
207
|
*/
|
|
208
208
|
export async function applyOnboarding(ctx, options = {}) {
|
|
209
209
|
const connection = ctx.get('connection');
|
|
@@ -260,7 +260,7 @@ export async function applyOnboarding(ctx, options = {}) {
|
|
|
260
260
|
}
|
|
261
261
|
}, });
|
|
262
262
|
const installed = installedPackage();
|
|
263
|
-
const updates = new UpdateCheck(installed?.version, options.
|
|
263
|
+
const updates = new UpdateCheck(installed?.version, options.latestRelease
|
|
264
264
|
?? (signal => installed ? npmLatest(installed.name, signal) : Promise.resolve(undefined)));
|
|
265
265
|
const control = {
|
|
266
266
|
snapshot: () => withUpdate(controller.snapshot(), updates),
|
|
@@ -1,11 +1,21 @@
|
|
|
1
|
+
/** A published release and when npm says it was published (epoch milliseconds). */
|
|
2
|
+
export interface Release {
|
|
3
|
+
version: string;
|
|
4
|
+
publishedAt: number;
|
|
5
|
+
}
|
|
1
6
|
/** True when `next` is a later release than `current`; a prerelease comes before its release. */
|
|
2
7
|
export declare function newerVersion(next: string, current: string): boolean;
|
|
3
|
-
/**
|
|
4
|
-
|
|
8
|
+
/**
|
|
9
|
+
* npm's `latest` release of a package and its publish time, when it names a stable release.
|
|
10
|
+
* Only the full package document carries publish times. Sends only the package name.
|
|
11
|
+
*/
|
|
12
|
+
export declare function npmLatest(name: string, signal: AbortSignal): Promise<Release | undefined>;
|
|
5
13
|
/**
|
|
6
14
|
* Whether a newer release of this plugin is available, for the settings page.
|
|
7
15
|
* A status read never waits for the registry: it returns what is known and
|
|
8
16
|
* starts a background check when one is due. Failures just show no notice.
|
|
17
|
+
* A release younger than a day is not offered yet, since installing it would
|
|
18
|
+
* still pick an older one; it shows up once it ages, without another check.
|
|
9
19
|
*/
|
|
10
20
|
export declare class UpdateCheck {
|
|
11
21
|
private readonly current;
|
|
@@ -14,7 +24,7 @@ export declare class UpdateCheck {
|
|
|
14
24
|
private latest?;
|
|
15
25
|
private nextCheck;
|
|
16
26
|
private running;
|
|
17
|
-
constructor(current: string | undefined, lookup: (signal: AbortSignal) => Promise<
|
|
27
|
+
constructor(current: string | undefined, lookup: (signal: AbortSignal) => Promise<Release | undefined>, now?: () => number);
|
|
18
28
|
status(): {
|
|
19
29
|
current: string;
|
|
20
30
|
latest: string;
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
const CHECK_EVERY_MS = 6 * 60 * 60_000;
|
|
3
3
|
// A failed check (offline, blocked registry) waits this long before the next try.
|
|
4
4
|
const RETRY_AFTER_MS = 30 * 60_000;
|
|
5
|
+
// pnpm 11, which the App and `dsh plugin` install with, skips releases younger than a day
|
|
6
|
+
// (`minimumReleaseAge`) and installs an older one instead, so a release is offered only after that.
|
|
7
|
+
const INSTALLABLE_AFTER_MS = 24 * 60 * 60_000;
|
|
5
8
|
const VERSION = /^(\d{1,9})\.(\d{1,9})\.(\d{1,9})(?:-([0-9A-Za-z.-]{1,40}))?$/;
|
|
6
9
|
/** True when `next` is a later release than `current`; a prerelease comes before its release. */
|
|
7
10
|
export function newerVersion(next, current) {
|
|
@@ -15,19 +18,29 @@ export function newerVersion(next, current) {
|
|
|
15
18
|
}
|
|
16
19
|
return !a[4] && Boolean(b[4]);
|
|
17
20
|
}
|
|
18
|
-
/**
|
|
21
|
+
/**
|
|
22
|
+
* npm's `latest` release of a package and its publish time, when it names a stable release.
|
|
23
|
+
* Only the full package document carries publish times. Sends only the package name.
|
|
24
|
+
*/
|
|
19
25
|
export async function npmLatest(name, signal) {
|
|
20
|
-
const response = await fetch(`https://registry.npmjs.org
|
|
26
|
+
const response = await fetch(`https://registry.npmjs.org/${name.replace('/', '%2f')}`, { signal, headers: { accept: 'application/json' } });
|
|
21
27
|
if (!response.ok)
|
|
22
28
|
return;
|
|
23
|
-
const
|
|
24
|
-
const latest = tags?.latest;
|
|
25
|
-
|
|
29
|
+
const document = await response.json();
|
|
30
|
+
const latest = document?.['dist-tags']?.latest;
|
|
31
|
+
if (typeof latest !== 'string' || !VERSION.test(latest) || latest.includes('-'))
|
|
32
|
+
return;
|
|
33
|
+
const time = document?.time;
|
|
34
|
+
const stamp = time && typeof time === 'object' ? time[latest] : undefined;
|
|
35
|
+
const publishedAt = typeof stamp === 'string' ? Date.parse(stamp) : Number.NaN;
|
|
36
|
+
return Number.isFinite(publishedAt) ? { version: latest, publishedAt } : undefined;
|
|
26
37
|
}
|
|
27
38
|
/**
|
|
28
39
|
* Whether a newer release of this plugin is available, for the settings page.
|
|
29
40
|
* A status read never waits for the registry: it returns what is known and
|
|
30
41
|
* starts a background check when one is due. Failures just show no notice.
|
|
42
|
+
* A release younger than a day is not offered yet, since installing it would
|
|
43
|
+
* still pick an older one; it shows up once it ages, without another check.
|
|
31
44
|
*/
|
|
32
45
|
export class UpdateCheck {
|
|
33
46
|
current;
|
|
@@ -46,15 +59,18 @@ export class UpdateCheck {
|
|
|
46
59
|
return;
|
|
47
60
|
if (!this.running && this.now() >= this.nextCheck)
|
|
48
61
|
void this.refresh();
|
|
49
|
-
|
|
62
|
+
const latest = this.latest;
|
|
63
|
+
if (!latest || this.now() - latest.publishedAt < INSTALLABLE_AFTER_MS)
|
|
64
|
+
return;
|
|
65
|
+
return newerVersion(latest.version, this.current) ? { current: this.current, latest: latest.version } : undefined;
|
|
50
66
|
}
|
|
51
67
|
async refresh() {
|
|
52
68
|
this.running = true;
|
|
53
69
|
this.nextCheck = this.now() + RETRY_AFTER_MS;
|
|
54
70
|
try {
|
|
55
71
|
const latest = await this.lookup(AbortSignal.timeout(10_000));
|
|
56
|
-
if (latest && VERSION.test(latest)) {
|
|
57
|
-
this.latest = latest;
|
|
72
|
+
if (latest && VERSION.test(latest.version) && Number.isFinite(latest.publishedAt)) {
|
|
73
|
+
this.latest = { version: latest.version, publishedAt: latest.publishedAt };
|
|
58
74
|
this.nextCheck = this.now() + CHECK_EVERY_MS;
|
|
59
75
|
}
|
|
60
76
|
}
|