dsh-reference-anything 0.2.4 → 0.3.0
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/NOTICE.md +5 -34
- package/README.md +84 -43
- package/cordis.patch.yml +18 -20
- package/lib/client.js +980 -1443
- package/lib/contract.d.ts +14 -13
- package/lib/contract.js +6 -8
- package/lib/host.d.ts +12 -11
- package/lib/host.js +15 -7
- package/lib/opencli.d.ts +5 -1
- package/lib/opencli.js +26 -43
- package/lib/profile-mode.d.ts +30 -0
- package/lib/profile-mode.js +90 -0
- package/lib/reference.d.ts +3 -11
- package/lib/reference.js +14 -55
- package/lib/sources/web-chat/index.d.ts +1 -0
- package/lib/sources/web-chat/index.js +5 -0
- package/lib/store/spec.d.ts +13 -0
- package/lib/sync/index.js +4 -4
- package/lib/typert.js +2 -2
- package/lib/web.js +1 -1
- package/lib/wire.d.ts +29 -0
- package/lib/wire.js +16 -7
- package/opencli-plugin/common.js +93 -33
- package/opencli-plugin/opencli-plugin.json +1 -1
- package/opencli-plugin/package.json +1 -1
- package/package.json +21 -16
- package/lib/workspace.d.ts +0 -18
- package/lib/workspace.js +0 -81
package/lib/contract.d.ts
CHANGED
|
@@ -1,18 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import type { InvocationDescriptor } from '@deepseek-ai/dsh-typert-protocol';
|
|
3
|
-
export declare const workspaceEntrySchema: z.ZodReadonly<z.ZodObject<{
|
|
4
|
-
path: z.ZodString;
|
|
5
|
-
kind: z.ZodEnum<{
|
|
6
|
-
file: "file";
|
|
7
|
-
directory: "directory";
|
|
8
|
-
}>;
|
|
9
|
-
}, z.core.$strip>>;
|
|
10
|
-
export declare const sessionCandidateSchema: z.ZodReadonly<z.ZodObject<{
|
|
11
|
-
sessionId: z.ZodString;
|
|
12
|
-
label: z.ZodString;
|
|
13
|
-
cwd: z.ZodOptional<z.ZodString>;
|
|
14
|
-
createdAt: z.ZodNumber;
|
|
15
|
-
}, z.core.$strip>>;
|
|
16
3
|
export declare const searchInputSchema: z.ZodReadonly<z.ZodObject<{
|
|
17
4
|
query: z.ZodString;
|
|
18
5
|
provider: z.ZodOptional<z.ZodEnum<{
|
|
@@ -79,6 +66,7 @@ export declare const healthSchema: z.ZodReadonly<z.ZodObject<{
|
|
|
79
66
|
daemonVersion: z.ZodOptional<z.ZodString>;
|
|
80
67
|
daemonStale: z.ZodBoolean;
|
|
81
68
|
connectivityOk: z.ZodBoolean;
|
|
69
|
+
connectivityChecked: z.ZodBoolean;
|
|
82
70
|
pluginVersion: z.ZodOptional<z.ZodString>;
|
|
83
71
|
adapterCommandsReady: z.ZodBoolean;
|
|
84
72
|
adapterCompatible: z.ZodBoolean;
|
|
@@ -110,6 +98,19 @@ export declare const packageUpdateResultSchema: z.ZodReadonly<z.ZodObject<{
|
|
|
110
98
|
version: z.ZodString;
|
|
111
99
|
restartRequired: z.ZodBoolean;
|
|
112
100
|
}, z.core.$strip>>;
|
|
101
|
+
export declare const referenceUiModeInputSchema: z.ZodReadonly<z.ZodObject<{
|
|
102
|
+
mode: z.ZodEnum<{
|
|
103
|
+
plugin: "plugin";
|
|
104
|
+
official: "official";
|
|
105
|
+
}>;
|
|
106
|
+
}, z.core.$strip>>;
|
|
107
|
+
export declare const referenceUiSwitchResultSchema: z.ZodReadonly<z.ZodObject<{
|
|
108
|
+
mode: z.ZodEnum<{
|
|
109
|
+
plugin: "plugin";
|
|
110
|
+
official: "official";
|
|
111
|
+
}>;
|
|
112
|
+
restartRequired: z.ZodLiteral<false>;
|
|
113
|
+
}, z.core.$strip>>;
|
|
113
114
|
export declare const providerStatsSchema: z.ZodReadonly<z.ZodObject<{
|
|
114
115
|
provider: z.ZodEnum<{
|
|
115
116
|
chatgpt: "chatgpt";
|
package/lib/contract.js
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { providerSchema, settingsRecordSchema } from "./wire.js";
|
|
3
|
-
export const workspaceEntrySchema = z.object({ path: z.string(), kind: z.enum(['file', 'directory']) }).readonly();
|
|
4
|
-
export const sessionCandidateSchema = z.object({ sessionId: z.string(), label: z.string(), cwd: z.string().optional(), createdAt: z.number() }).readonly();
|
|
5
|
-
const agentLookup = { name: 'agent', wire: 'agentId', source: 'lookup', lookup: 'agent',
|
|
6
|
-
codec: { mode: 'strict', typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', schema: z.string().min(1) } };
|
|
2
|
+
import { providerSchema, referenceUiModeSchema, settingsRecordSchema } from "./wire.js";
|
|
7
3
|
export const searchInputSchema = z.object({
|
|
8
4
|
query: z.string(), provider: providerSchema.optional(), limit: z.number().int().min(1).max(100),
|
|
9
5
|
}).readonly();
|
|
@@ -19,7 +15,7 @@ export const healthSchema = z.object({
|
|
|
19
15
|
daemonRunning: z.boolean(), extensionConnected: z.boolean(), extensionState: extensionStateSchema,
|
|
20
16
|
extensionVersion: z.string().optional(), profileCount: z.number().int().nonnegative().optional(),
|
|
21
17
|
opencliCompatible: z.boolean(), daemonVersion: z.string().optional(), daemonStale: z.boolean(),
|
|
22
|
-
connectivityOk: z.boolean(), pluginVersion: z.string().optional(), adapterCommandsReady: z.boolean(), adapterCompatible: z.boolean(),
|
|
18
|
+
connectivityOk: z.boolean(), connectivityChecked: z.boolean(), pluginVersion: z.string().optional(), adapterCommandsReady: z.boolean(), adapterCompatible: z.boolean(),
|
|
23
19
|
versionError: z.string().optional(), daemonError: z.string().optional(), pluginError: z.string().optional(), doctorError: z.string().optional(),
|
|
24
20
|
}).readonly();
|
|
25
21
|
export const browserProfileSchema = z.object({ id: z.string(), alias: z.string().optional(), connected: z.boolean(), isDefault: z.boolean() }).readonly();
|
|
@@ -33,6 +29,8 @@ export const packageUpdateStatusSchema = z.object({
|
|
|
33
29
|
export const packageUpdateResultSchema = z.object({
|
|
34
30
|
version: z.string(), restartRequired: z.boolean(),
|
|
35
31
|
}).readonly();
|
|
32
|
+
export const referenceUiModeInputSchema = z.object({ mode: referenceUiModeSchema }).readonly();
|
|
33
|
+
export const referenceUiSwitchResultSchema = z.object({ mode: referenceUiModeSchema, restartRequired: z.literal(false) }).readonly();
|
|
36
34
|
export const providerStatsSchema = z.object({
|
|
37
35
|
provider: providerSchema, conversations: z.number().int().nonnegative(), lastSyncedAt: z.string(),
|
|
38
36
|
status: z.enum(['ready', 'syncing', 'error', 'empty']), error: z.string().optional(),
|
|
@@ -72,10 +70,9 @@ export const providerSyncStateSchema = z.object({
|
|
|
72
70
|
lastSyncAt: z.string(), lastCompleteScanAt: z.string(), error: z.string(),
|
|
73
71
|
}).readonly();
|
|
74
72
|
export const REFERENCE_ANYTHING_INVOCATIONS = [
|
|
75
|
-
descriptor('workspaceSearch', [agentLookup], strict('WorkspaceEntry[]', z.array(workspaceEntrySchema)), true),
|
|
76
|
-
descriptor('sessionSearch', [agentLookup, { name: 'input', wire: 'input', source: 'json', codec: strict('SessionSearchInput', z.object({ query: z.string(), limit: z.number().int().min(1).max(100) }).readonly()) }], strict('SessionCandidate[]', z.array(sessionCandidateSchema)), true),
|
|
77
73
|
descriptor('search', [{ name: 'input', wire: 'input', source: 'json', codec: strict('SearchInput', searchInputSchema) }], strict('SearchResult[]', z.array(searchResultSchema)), true),
|
|
78
74
|
descriptor('health', [], strict('Health', healthSchema), true),
|
|
75
|
+
descriptor('quickHealth', [], strict('Health', healthSchema), true),
|
|
79
76
|
descriptor('profiles', [], strict('BrowserProfile[]', z.array(browserProfileSchema)), true),
|
|
80
77
|
descriptor('discoverOpenCli', [], strict('OpenCliDiscovery', openCliDiscoverySchema), true),
|
|
81
78
|
descriptor('installOpenCli', [], strict('OpenCliDiscovery', openCliDiscoverySchema), true),
|
|
@@ -84,6 +81,7 @@ export const REFERENCE_ANYTHING_INVOCATIONS = [
|
|
|
84
81
|
descriptor('updateStatus', [], strict('PackageUpdateStatus', packageUpdateStatusSchema), true),
|
|
85
82
|
descriptor('checkUpdate', [], strict('PackageUpdateStatus', packageUpdateStatusSchema), true),
|
|
86
83
|
descriptor('installUpdate', [], strict('PackageUpdateResult', packageUpdateResultSchema), true),
|
|
84
|
+
descriptor('switchReferenceUiMode', [{ name: 'input', wire: 'input', source: 'json', codec: strict('ReferenceUiModeInput', referenceUiModeInputSchema) }], strict('ReferenceUiSwitchResult', referenceUiSwitchResultSchema), true),
|
|
87
85
|
descriptor('stats', [], strict('ProviderStats[]', z.array(providerStatsSchema))),
|
|
88
86
|
descriptor('syncStart', [{ name: 'input', wire: 'input', source: 'json', codec: strict('SyncStart', syncStartSchema) }], strict('JobId', z.string())),
|
|
89
87
|
descriptor('syncStatus', [{ name: 'input', wire: 'input', source: 'json', codec: strict('JobInput', jobInputSchema) }], strict('SyncStatus?', syncStatusSchema.optional())),
|
package/lib/host.d.ts
CHANGED
|
@@ -1,26 +1,17 @@
|
|
|
1
1
|
import type { Context } from '@deepseek-ai/cordis';
|
|
2
2
|
import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
|
|
3
3
|
import type { ChatProvider, SettingsRecord } from './store/spec.ts';
|
|
4
|
+
import type { ReferenceUiMode } from './wire.ts';
|
|
4
5
|
import type { SyncMode } from './sync/index.ts';
|
|
5
|
-
import type { Agent } from '@deepseek-ai/dsh-agent';
|
|
6
6
|
export declare class ReferenceAnythingRemote extends TypertRemoteService {
|
|
7
7
|
constructor(ctx: Context);
|
|
8
|
-
workspaceSearch(agent: Agent, signal: AbortSignal): Promise<import("./workspace.ts").WorkspaceEntry[]>;
|
|
9
|
-
sessionSearch(agent: Agent, input: {
|
|
10
|
-
query: string;
|
|
11
|
-
limit: number;
|
|
12
|
-
}, signal: AbortSignal): Promise<{
|
|
13
|
-
sessionId: string;
|
|
14
|
-
label: string;
|
|
15
|
-
cwd?: string;
|
|
16
|
-
createdAt: number;
|
|
17
|
-
}[]>;
|
|
18
8
|
search(input: {
|
|
19
9
|
query: string;
|
|
20
10
|
provider?: ChatProvider;
|
|
21
11
|
limit: number;
|
|
22
12
|
}, signal: AbortSignal): Promise<import("./sources/web-chat/index.ts").ConversationSearchResult[]>;
|
|
23
13
|
health(signal: AbortSignal): Promise<import("./opencli.ts").OpenCliHealth>;
|
|
14
|
+
quickHealth(signal: AbortSignal): Promise<import("./opencli.ts").OpenCliHealth>;
|
|
24
15
|
profiles(signal: AbortSignal): Promise<import("./opencli.ts").BrowserProfile[]>;
|
|
25
16
|
discoverOpenCli(signal: AbortSignal): Promise<import("./opencli.ts").OpenCliDiscovery>;
|
|
26
17
|
installOpenCli(signal: AbortSignal): Promise<import("./opencli.ts").OpenCliDiscovery>;
|
|
@@ -29,6 +20,9 @@ export declare class ReferenceAnythingRemote extends TypertRemoteService {
|
|
|
29
20
|
updateStatus(signal: AbortSignal): Promise<import("./update.ts").PackageUpdateStatus>;
|
|
30
21
|
checkUpdate(signal: AbortSignal): Promise<import("./update.ts").PackageUpdateStatus>;
|
|
31
22
|
installUpdate(signal: AbortSignal): Promise<import("./update.ts").PackageUpdateResult>;
|
|
23
|
+
switchReferenceUiMode(input: {
|
|
24
|
+
mode: ReferenceUiMode;
|
|
25
|
+
}, signal: AbortSignal): Promise<import("./profile-mode.ts").ReferenceUiSwitchResult>;
|
|
32
26
|
stats(): import("./store/store.ts").ProviderStats[];
|
|
33
27
|
syncStart(input: {
|
|
34
28
|
providers: ChatProvider[];
|
|
@@ -52,31 +46,38 @@ export declare class ReferenceAnythingRemote extends TypertRemoteService {
|
|
|
52
46
|
enabledProviders: ("chatgpt" | "claude" | "gemini" | "deepseek" | "grok" | "kimi")[];
|
|
53
47
|
maxReadTurns: number;
|
|
54
48
|
inputRenderMode: "pill" | "raw-text";
|
|
49
|
+
referenceUiMode?: "plugin" | "official" | undefined;
|
|
55
50
|
picker?: {
|
|
51
|
+
displayMode: "collapse" | "native-scroll";
|
|
56
52
|
commands: {
|
|
57
53
|
enabled: boolean;
|
|
58
54
|
order: number;
|
|
59
55
|
limit: number;
|
|
56
|
+
maxCandidates: number;
|
|
60
57
|
};
|
|
61
58
|
skills: {
|
|
62
59
|
enabled: boolean;
|
|
63
60
|
order: number;
|
|
64
61
|
limit: number;
|
|
62
|
+
maxCandidates: number;
|
|
65
63
|
};
|
|
66
64
|
files: {
|
|
67
65
|
enabled: boolean;
|
|
68
66
|
order: number;
|
|
69
67
|
limit: number;
|
|
68
|
+
maxCandidates: number;
|
|
70
69
|
};
|
|
71
70
|
sessions: {
|
|
72
71
|
enabled: boolean;
|
|
73
72
|
order: number;
|
|
74
73
|
limit: number;
|
|
74
|
+
maxCandidates: number;
|
|
75
75
|
};
|
|
76
76
|
conversations: {
|
|
77
77
|
enabled: boolean;
|
|
78
78
|
order: number;
|
|
79
79
|
limit: number;
|
|
80
|
+
maxCandidates: number;
|
|
80
81
|
};
|
|
81
82
|
} | undefined;
|
|
82
83
|
}>;
|
package/lib/host.js
CHANGED
|
@@ -1,18 +1,13 @@
|
|
|
1
1
|
import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
|
|
2
|
-
import {
|
|
3
|
-
import { indexWorkspace } from "./workspace.js";
|
|
2
|
+
import { switchReferenceUiMode as switchProfileReferenceUiMode } from "./profile-mode.js";
|
|
4
3
|
export class ReferenceAnythingRemote extends TypertRemoteService {
|
|
5
4
|
constructor(ctx) { super(ctx, 'referenceAnything'); }
|
|
6
|
-
workspaceSearch(agent, signal) { return indexWorkspace(agent, signal); }
|
|
7
|
-
async sessionSearch(agent, input, signal) {
|
|
8
|
-
const rows = await this.ctx.sessionReferenceResolver.listCandidates(agent, input.query, input.limit, signal);
|
|
9
|
-
return rows.map(row => ({ ...row, sessionId: encodeSessionReferenceUri(row.sessionId) }));
|
|
10
|
-
}
|
|
11
5
|
search(input, signal) {
|
|
12
6
|
signal.throwIfAborted();
|
|
13
7
|
return this.ctx.referenceChatHistory.search(input.query, input.provider, input.limit, signal);
|
|
14
8
|
}
|
|
15
9
|
health(signal) { return this.ctx.referenceChatHistory.health(signal); }
|
|
10
|
+
quickHealth(signal) { return this.ctx.referenceChatHistory.quickHealth(signal); }
|
|
16
11
|
profiles(signal) { return this.ctx.referenceChatHistory.profiles(signal); }
|
|
17
12
|
discoverOpenCli(signal) { return this.ctx.referenceChatHistory.discoverOpenCli(signal); }
|
|
18
13
|
installOpenCli(signal) { return this.ctx.referenceChatHistory.installOpenCli(signal); }
|
|
@@ -21,6 +16,19 @@ export class ReferenceAnythingRemote extends TypertRemoteService {
|
|
|
21
16
|
updateStatus(signal) { return this.ctx.referenceChatHistory.updateStatus(signal); }
|
|
22
17
|
checkUpdate(signal) { return this.ctx.referenceChatHistory.checkUpdate(signal); }
|
|
23
18
|
installUpdate(signal) { return this.ctx.referenceChatHistory.installUpdate(signal); }
|
|
19
|
+
async switchReferenceUiMode(input, signal) {
|
|
20
|
+
const settings = this.ctx.referenceChatHistory.getSettings();
|
|
21
|
+
const previousMode = settings.referenceUiMode ?? 'plugin';
|
|
22
|
+
const result = await switchProfileReferenceUiMode({ mode: input.mode, signal });
|
|
23
|
+
try {
|
|
24
|
+
await this.ctx.referenceChatHistory.updateSettings({ ...settings, referenceUiMode: input.mode });
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
await switchProfileReferenceUiMode({ mode: previousMode }).catch(() => undefined);
|
|
28
|
+
throw error;
|
|
29
|
+
}
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
24
32
|
stats() { return this.ctx.referenceChatHistory.stats(); }
|
|
25
33
|
syncStart(input) {
|
|
26
34
|
return this.ctx.referenceChatHistory.sync.start(input.providers, input.mode);
|
package/lib/opencli.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ChatProvider } from './store/spec.ts';
|
|
2
2
|
import type { ProviderConversationRow, ProviderTurnRow } from './store/store.ts';
|
|
3
3
|
export declare const MIN_OPENCLI_VERSION = "1.8.6";
|
|
4
|
-
export declare const MIN_ADAPTER_VERSION = "0.2.
|
|
4
|
+
export declare const MIN_ADAPTER_VERSION = "0.2.2";
|
|
5
5
|
export declare const OPENCLI_NPM_PACKAGE = "@jackwener/opencli";
|
|
6
6
|
export type OpenCliErrorCode = 'EXTENSION_NOT_CONNECTED' | 'PROVIDER_TIMEOUT' | 'PROVIDER_NOT_LOGGED_IN' | 'PROVIDER_ACCOUNT_MISMATCH' | 'OPENCLI_CONFIGURATION' | 'OPENCLI_OUTPUT_TOO_LARGE' | 'OPENCLI_FAILED' | 'OPENCLI_INSTALL_FAILED';
|
|
7
7
|
export declare class OpenCliError extends Error {
|
|
@@ -32,6 +32,7 @@ export interface OpenCliHealth {
|
|
|
32
32
|
daemonVersion?: string;
|
|
33
33
|
daemonStale: boolean;
|
|
34
34
|
connectivityOk: boolean;
|
|
35
|
+
connectivityChecked: boolean;
|
|
35
36
|
pluginVersion?: string;
|
|
36
37
|
adapterCommandsReady: boolean;
|
|
37
38
|
adapterCompatible: boolean;
|
|
@@ -96,6 +97,9 @@ export declare class OpenCliRunner {
|
|
|
96
97
|
detail(provider: ChatProvider, id: string, signal?: AbortSignal, accountScope?: string): Promise<ProviderTurnRow[]>;
|
|
97
98
|
attachment(provider: ChatProvider, locator: string, output: string, maxBytes: number, signal?: AbortSignal): Promise<Record<string, unknown>>;
|
|
98
99
|
health(signal?: AbortSignal): Promise<OpenCliHealth>;
|
|
100
|
+
/** Inspect local OpenCLI, daemon, extension and plugin state without an active connectivity probe. */
|
|
101
|
+
quickHealth(signal?: AbortSignal): Promise<OpenCliHealth>;
|
|
102
|
+
private inspectHealth;
|
|
99
103
|
/** Lightweight executable validation used by automatic path discovery. */
|
|
100
104
|
version(signal?: AbortSignal): Promise<string>;
|
|
101
105
|
/** Confirm the executable also exposes OpenCLI's plugin command, not merely a semver-looking --version. */
|
package/lib/opencli.js
CHANGED
|
@@ -5,7 +5,7 @@ import { promisify } from 'node:util';
|
|
|
5
5
|
import { createHash } from 'node:crypto';
|
|
6
6
|
const execFile = promisify(nodeExecFile);
|
|
7
7
|
export const MIN_OPENCLI_VERSION = '1.8.6';
|
|
8
|
-
export const MIN_ADAPTER_VERSION = '0.2.
|
|
8
|
+
export const MIN_ADAPTER_VERSION = '0.2.2';
|
|
9
9
|
export const OPENCLI_NPM_PACKAGE = '@jackwener/opencli';
|
|
10
10
|
const SITE = {
|
|
11
11
|
chatgpt: 'dsh-chatgpt', claude: 'dsh-claude', gemini: 'dsh-gemini',
|
|
@@ -13,13 +13,6 @@ const SITE = {
|
|
|
13
13
|
};
|
|
14
14
|
const REQUIRED_ADAPTER_COMMANDS = ['chatgpt', 'claude', 'gemini', 'deepseek', 'grok', 'kimi'];
|
|
15
15
|
const ADAPTER_PLUGIN_NAME = 'dsh-chat-history';
|
|
16
|
-
/**
|
|
17
|
-
* A persistent OpenCLI site session owns one mutable browser tab. Serialize
|
|
18
|
-
* commands that target the same executable/profile/site across runner
|
|
19
|
-
* instances so concurrent detail workers cannot navigate that tab over one
|
|
20
|
-
* another. Different provider sites still run in parallel.
|
|
21
|
-
*/
|
|
22
|
-
const SITE_COMMAND_TAILS = new Map();
|
|
23
16
|
export class OpenCliError extends Error {
|
|
24
17
|
code;
|
|
25
18
|
constructor(message, code, options) {
|
|
@@ -119,9 +112,16 @@ export class OpenCliRunner {
|
|
|
119
112
|
return rows[0] ?? {};
|
|
120
113
|
}
|
|
121
114
|
async health(signal) {
|
|
115
|
+
return this.inspectHealth(true, signal);
|
|
116
|
+
}
|
|
117
|
+
/** Inspect local OpenCLI, daemon, extension and plugin state without an active connectivity probe. */
|
|
118
|
+
async quickHealth(signal) {
|
|
119
|
+
return this.inspectHealth(false, signal);
|
|
120
|
+
}
|
|
121
|
+
async inspectHealth(checkConnectivity, signal) {
|
|
122
122
|
const [version, daemon, plugins, doctor] = await Promise.all([
|
|
123
123
|
this.probe(['--version'], signal), this.probe(['daemon', 'status'], signal), this.probe(['plugin', 'list'], signal),
|
|
124
|
-
this.probe(['doctor'], signal),
|
|
124
|
+
checkConnectivity ? this.probe(['doctor'], signal) : Promise.resolve({ value: '', diagnostic: '' }),
|
|
125
125
|
]);
|
|
126
126
|
const status = parseDaemonStatus(daemon.value);
|
|
127
127
|
const cliVersion = normalizeVersion(version.value);
|
|
@@ -137,7 +137,7 @@ export class OpenCliRunner {
|
|
|
137
137
|
return {
|
|
138
138
|
version: cliVersion, daemon: daemon.value.trim(), pluginInstalled,
|
|
139
139
|
daemonRunning: status.daemonRunning, extensionConnected: status.extensionConnected, extensionState: status.extensionState,
|
|
140
|
-
opencliCompatible, daemonStale, connectivityOk,
|
|
140
|
+
opencliCompatible, daemonStale, connectivityOk, connectivityChecked: checkConnectivity,
|
|
141
141
|
...(status.extensionVersion ? { extensionVersion: status.extensionVersion } : {}),
|
|
142
142
|
...(status.profileCount !== undefined ? { profileCount: status.profileCount } : {}),
|
|
143
143
|
...(daemonVersion ? { daemonVersion: normalizeVersion(daemonVersion) } : {}),
|
|
@@ -147,7 +147,7 @@ export class OpenCliRunner {
|
|
|
147
147
|
...(version.error ? { versionError: version.error } : {}),
|
|
148
148
|
...(daemon.error ? { daemonError: daemon.error } : {}),
|
|
149
149
|
...(plugins.error || adapterLoadError ? { pluginError: plugins.error || adapterLoadError } : {}),
|
|
150
|
-
...(doctor.error ? { doctorError: doctor.error } : {}),
|
|
150
|
+
...('error' in doctor && doctor.error ? { doctorError: doctor.error } : {}),
|
|
151
151
|
};
|
|
152
152
|
}
|
|
153
153
|
/** Lightweight executable validation used by automatic path discovery. */
|
|
@@ -208,25 +208,21 @@ export class OpenCliRunner {
|
|
|
208
208
|
}
|
|
209
209
|
}
|
|
210
210
|
async json(site, operation, args, signal) {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
catch (error) {
|
|
227
|
-
throw new OpenCliError('OpenCLI returned malformed JSON', 'OPENCLI_CONFIGURATION', { cause: error });
|
|
228
|
-
}
|
|
229
|
-
});
|
|
211
|
+
// Match the sync-index lifecycle: every command gets its own temporary
|
|
212
|
+
// background tab, so providers and detail workers can run independently.
|
|
213
|
+
const stdout = await this.raw([
|
|
214
|
+
site, operation, ...args,
|
|
215
|
+
'--site-session', 'ephemeral', '--window', 'background', '-f', 'json',
|
|
216
|
+
], signal);
|
|
217
|
+
try {
|
|
218
|
+
const parsed = JSON.parse(stdout);
|
|
219
|
+
if (!Array.isArray(parsed) || parsed.some(row => !row || typeof row !== 'object' || Array.isArray(row)))
|
|
220
|
+
throw new Error('expected object array');
|
|
221
|
+
return parsed;
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
throw new OpenCliError('OpenCLI returned malformed JSON', 'OPENCLI_CONFIGURATION', { cause: error });
|
|
225
|
+
}
|
|
230
226
|
}
|
|
231
227
|
async raw(args, signal) {
|
|
232
228
|
return (await this.command(args, signal)).stdout;
|
|
@@ -263,19 +259,6 @@ function adapterPluginLoadError(diagnostic = '') {
|
|
|
263
259
|
.filter(line => /Plugin dsh-chat-history\//i.test(line));
|
|
264
260
|
return [...new Set(lines)].join('\n').slice(0, 2_000);
|
|
265
261
|
}
|
|
266
|
-
async function serializeSiteCommand(key, task) {
|
|
267
|
-
const previous = SITE_COMMAND_TAILS.get(key) ?? Promise.resolve();
|
|
268
|
-
const current = previous.then(task, task);
|
|
269
|
-
const settled = current.then(() => undefined, () => undefined);
|
|
270
|
-
SITE_COMMAND_TAILS.set(key, settled);
|
|
271
|
-
try {
|
|
272
|
-
return await current;
|
|
273
|
-
}
|
|
274
|
-
finally {
|
|
275
|
-
if (SITE_COMMAND_TAILS.get(key) === settled)
|
|
276
|
-
SITE_COMMAND_TAILS.delete(key);
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
262
|
/** Locate a working OpenCLI without asking a command-line newcomer for PATH details. */
|
|
280
263
|
export async function discoverOpenCli(configured = 'opencli', signal) {
|
|
281
264
|
const candidates = openCliCandidates(configured);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ReferenceUiMode } from './wire.ts';
|
|
2
|
+
export declare const OFFICIAL_REFERENCE_PATCH_BEGIN = "# BEGIN dsh-reference-anything managed official-reference override";
|
|
3
|
+
export declare const OFFICIAL_REFERENCE_PATCH_END = "# END dsh-reference-anything managed official-reference override";
|
|
4
|
+
export interface ReferenceUiSwitchResult {
|
|
5
|
+
mode: ReferenceUiMode;
|
|
6
|
+
restartRequired: false;
|
|
7
|
+
}
|
|
8
|
+
interface SwitchReferenceUiModeOptions {
|
|
9
|
+
mode: ReferenceUiMode;
|
|
10
|
+
packageRoot?: string;
|
|
11
|
+
dshHome?: string;
|
|
12
|
+
signal?: AbortSignal;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Switch only the visible @ implementation while keeping this package alive.
|
|
16
|
+
*
|
|
17
|
+
* The bundle patch remains untouched so updating or reinstalling the package
|
|
18
|
+
* cannot erase the user's choice. The plugin Host and settings entry remain
|
|
19
|
+
* active in both modes; the client separately registers or disposes its own
|
|
20
|
+
* picker sources.
|
|
21
|
+
*/
|
|
22
|
+
export declare function switchReferenceUiMode(options: SwitchReferenceUiModeOptions): Promise<ReferenceUiSwitchResult>;
|
|
23
|
+
/** Write the managed override without exposing a partially-written YAML file. */
|
|
24
|
+
export declare function writeReferenceUiModeOverride(path: string, mode: ReferenceUiMode, signal?: AbortSignal): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Preserve every user-owned row and append one idempotent block at the end,
|
|
27
|
+
* where Cordis' ordered patch semantics make it the effective override.
|
|
28
|
+
*/
|
|
29
|
+
export declare function withReferenceUiModeOverride(source: string, mode: ReferenceUiMode): string;
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { readFile, rename, rm, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { dirname, join } from 'node:path';
|
|
3
|
+
import { findOwningProfileDir } from "./update.js";
|
|
4
|
+
export const OFFICIAL_REFERENCE_PATCH_BEGIN = '# BEGIN dsh-reference-anything managed official-reference override';
|
|
5
|
+
export const OFFICIAL_REFERENCE_PATCH_END = '# END dsh-reference-anything managed official-reference override';
|
|
6
|
+
/**
|
|
7
|
+
* Switch only the visible @ implementation while keeping this package alive.
|
|
8
|
+
*
|
|
9
|
+
* The bundle patch remains untouched so updating or reinstalling the package
|
|
10
|
+
* cannot erase the user's choice. The plugin Host and settings entry remain
|
|
11
|
+
* active in both modes; the client separately registers or disposes its own
|
|
12
|
+
* picker sources.
|
|
13
|
+
*/
|
|
14
|
+
export async function switchReferenceUiMode(options) {
|
|
15
|
+
options.signal?.throwIfAborted();
|
|
16
|
+
const profileDir = await findOwningProfileDir(options.packageRoot, options.dshHome);
|
|
17
|
+
await writeReferenceUiModeOverride(join(profileDir, 'cordis.patch.yml'), options.mode, options.signal);
|
|
18
|
+
return { mode: options.mode, restartRequired: false };
|
|
19
|
+
}
|
|
20
|
+
/** Write the managed override without exposing a partially-written YAML file. */
|
|
21
|
+
export async function writeReferenceUiModeOverride(path, mode, signal) {
|
|
22
|
+
signal?.throwIfAborted();
|
|
23
|
+
let source = '';
|
|
24
|
+
try {
|
|
25
|
+
source = await readFile(path, { encoding: 'utf8', signal });
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
const code = error.code;
|
|
29
|
+
if (code !== 'ENOENT')
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
const next = withReferenceUiModeOverride(source, mode);
|
|
33
|
+
if (next === source)
|
|
34
|
+
return;
|
|
35
|
+
const temporary = join(dirname(path), `.cordis.patch.yml.dsh-reference-anything-${String(process.pid)}-${String(Date.now())}.tmp`);
|
|
36
|
+
try {
|
|
37
|
+
await writeFile(temporary, next, { encoding: 'utf8', signal });
|
|
38
|
+
signal?.throwIfAborted();
|
|
39
|
+
await rename(temporary, path);
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
await rm(temporary, { force: true }).catch(() => undefined);
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Preserve every user-owned row and append one idempotent block at the end,
|
|
48
|
+
* where Cordis' ordered patch semantics make it the effective override.
|
|
49
|
+
*/
|
|
50
|
+
export function withReferenceUiModeOverride(source, mode) {
|
|
51
|
+
const eol = source.includes('\r\n') ? '\r\n' : '\n';
|
|
52
|
+
const lines = source.split(/\r?\n/);
|
|
53
|
+
const beginRows = markerRows(lines, OFFICIAL_REFERENCE_PATCH_BEGIN);
|
|
54
|
+
const endRows = markerRows(lines, OFFICIAL_REFERENCE_PATCH_END);
|
|
55
|
+
if (beginRows.length > 1 || endRows.length > 1 || beginRows.length !== endRows.length) {
|
|
56
|
+
throw new Error('the managed official-reference block in cordis.patch.yml is malformed');
|
|
57
|
+
}
|
|
58
|
+
if (beginRows.length === 1) {
|
|
59
|
+
const begin = beginRows[0];
|
|
60
|
+
const end = endRows[0];
|
|
61
|
+
if (end < begin)
|
|
62
|
+
throw new Error('the managed official-reference block in cordis.patch.yml is malformed');
|
|
63
|
+
lines.splice(begin, end - begin + 1);
|
|
64
|
+
}
|
|
65
|
+
removeEmptyArrayDocument(lines);
|
|
66
|
+
while (lines.length > 0 && lines.at(-1)?.trim() === '')
|
|
67
|
+
lines.pop();
|
|
68
|
+
const block = [
|
|
69
|
+
OFFICIAL_REFERENCE_PATCH_BEGIN,
|
|
70
|
+
'# Switch only the visible @ implementation; Reference Anything stays loaded.',
|
|
71
|
+
'- id: ui-reference',
|
|
72
|
+
` disabled: ${mode === 'official' ? 'false' : 'true'}`,
|
|
73
|
+
OFFICIAL_REFERENCE_PATCH_END,
|
|
74
|
+
];
|
|
75
|
+
return [...lines, ...(lines.length > 0 ? [''] : []), ...block, ''].join(eol);
|
|
76
|
+
}
|
|
77
|
+
function markerRows(lines, marker) {
|
|
78
|
+
const rows = [];
|
|
79
|
+
lines.forEach((line, index) => { if (line.trim() === marker)
|
|
80
|
+
rows.push(index); });
|
|
81
|
+
return rows;
|
|
82
|
+
}
|
|
83
|
+
/** `[]` is the valid empty profile document, but cannot precede list rows. */
|
|
84
|
+
function removeEmptyArrayDocument(lines) {
|
|
85
|
+
const meaningful = lines
|
|
86
|
+
.map((line, index) => ({ index, text: line.trim() }))
|
|
87
|
+
.filter(row => row.text !== '' && !row.text.startsWith('#'));
|
|
88
|
+
if (meaningful.length === 1 && meaningful[0]?.text === '[]')
|
|
89
|
+
lines.splice(meaningful[0].index, 1);
|
|
90
|
+
}
|
package/lib/reference.d.ts
CHANGED
|
@@ -8,11 +8,9 @@
|
|
|
8
8
|
* the loop durably appends, so injected material is logged by construction and
|
|
9
9
|
* a replay reconstructs the request exactly.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
* is resolved through `ctx.references`.
|
|
13
|
-
*
|
|
14
|
-
* session-surface semantics — compaction folding, shadowed events, cited event
|
|
15
|
-
* seqs — that do not generalize to an outside conversation.
|
|
11
|
+
* This plugin owns only `dsh-ref:`, which names material outside the harness
|
|
12
|
+
* and is resolved through `ctx.references`. Native file and DSH-session
|
|
13
|
+
* references are owned end-to-end by their official DSH services.
|
|
16
14
|
*
|
|
17
15
|
* @module dsh-reference-anything/reference
|
|
18
16
|
*/
|
|
@@ -32,12 +30,6 @@ export interface Config {
|
|
|
32
30
|
* background, and the byte budget multiplies by the same factor.
|
|
33
31
|
*/
|
|
34
32
|
maxReferences?: number;
|
|
35
|
-
/**
|
|
36
|
-
* Also expand `dsh-session:` mentions. Deployments that deliberately do not
|
|
37
|
-
* mount the cross-session resolver set this false, so such a mention is
|
|
38
|
-
* refused as unsupported rather than probed for on every message.
|
|
39
|
-
*/
|
|
40
|
-
serveSessionScheme?: boolean;
|
|
41
33
|
}
|
|
42
34
|
/** Runtime schema for {@link Config}. */
|
|
43
35
|
export declare const Config: z<Config>;
|