dsh-reference-anything 0.2.5 → 0.3.1

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/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;
package/lib/contract.js CHANGED
@@ -1,9 +1,5 @@
1
1
  import { z } from 'zod';
2
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) } };
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();
@@ -72,10 +68,9 @@ export const providerSyncStateSchema = z.object({
72
68
  lastSyncAt: z.string(), lastCompleteScanAt: z.string(), error: z.string(),
73
69
  }).readonly();
74
70
  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
71
  descriptor('search', [{ name: 'input', wire: 'input', source: 'json', codec: strict('SearchInput', searchInputSchema) }], strict('SearchResult[]', z.array(searchResultSchema)), true),
78
72
  descriptor('health', [], strict('Health', healthSchema), true),
73
+ descriptor('quickHealth', [], strict('Health', healthSchema), true),
79
74
  descriptor('profiles', [], strict('BrowserProfile[]', z.array(browserProfileSchema)), true),
80
75
  descriptor('discoverOpenCli', [], strict('OpenCliDiscovery', openCliDiscoverySchema), true),
81
76
  descriptor('installOpenCli', [], strict('OpenCliDiscovery', openCliDiscoverySchema), true),
package/lib/host.d.ts CHANGED
@@ -2,25 +2,15 @@ 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
4
  import type { SyncMode } from './sync/index.ts';
5
- import type { Agent } from '@deepseek-ai/dsh-agent';
6
5
  export declare class ReferenceAnythingRemote extends TypertRemoteService {
7
6
  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
7
  search(input: {
19
8
  query: string;
20
9
  provider?: ChatProvider;
21
10
  limit: number;
22
11
  }, signal: AbortSignal): Promise<import("./sources/web-chat/index.ts").ConversationSearchResult[]>;
23
12
  health(signal: AbortSignal): Promise<import("./opencli.ts").OpenCliHealth>;
13
+ quickHealth(signal: AbortSignal): Promise<import("./opencli.ts").OpenCliHealth>;
24
14
  profiles(signal: AbortSignal): Promise<import("./opencli.ts").BrowserProfile[]>;
25
15
  discoverOpenCli(signal: AbortSignal): Promise<import("./opencli.ts").OpenCliDiscovery>;
26
16
  installOpenCli(signal: AbortSignal): Promise<import("./opencli.ts").OpenCliDiscovery>;
@@ -53,30 +43,36 @@ export declare class ReferenceAnythingRemote extends TypertRemoteService {
53
43
  maxReadTurns: number;
54
44
  inputRenderMode: "pill" | "raw-text";
55
45
  picker?: {
46
+ displayMode: "collapse" | "native-scroll";
56
47
  commands: {
57
48
  enabled: boolean;
58
49
  order: number;
59
50
  limit: number;
51
+ maxCandidates: number;
60
52
  };
61
53
  skills: {
62
54
  enabled: boolean;
63
55
  order: number;
64
56
  limit: number;
57
+ maxCandidates: number;
65
58
  };
66
59
  files: {
67
60
  enabled: boolean;
68
61
  order: number;
69
62
  limit: number;
63
+ maxCandidates: number;
70
64
  };
71
65
  sessions: {
72
66
  enabled: boolean;
73
67
  order: number;
74
68
  limit: number;
69
+ maxCandidates: number;
75
70
  };
76
71
  conversations: {
77
72
  enabled: boolean;
78
73
  order: number;
79
74
  limit: number;
75
+ maxCandidates: number;
80
76
  };
81
77
  } | undefined;
82
78
  }>;
package/lib/host.js CHANGED
@@ -1,18 +1,12 @@
1
1
  import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
2
- import { encodeSessionReferenceUri } from '@deepseek-ai/dsh-session-reference';
3
- import { indexWorkspace } from "./workspace.js";
4
2
  export class ReferenceAnythingRemote extends TypertRemoteService {
5
3
  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
4
  search(input, signal) {
12
5
  signal.throwIfAborted();
13
6
  return this.ctx.referenceChatHistory.search(input.query, input.provider, input.limit, signal);
14
7
  }
15
8
  health(signal) { return this.ctx.referenceChatHistory.health(signal); }
9
+ quickHealth(signal) { return this.ctx.referenceChatHistory.quickHealth(signal); }
16
10
  profiles(signal) { return this.ctx.referenceChatHistory.profiles(signal); }
17
11
  discoverOpenCli(signal) { return this.ctx.referenceChatHistory.discoverOpenCli(signal); }
18
12
  installOpenCli(signal) { return this.ctx.referenceChatHistory.installOpenCli(signal); }
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.1";
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.1';
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 lease. Serialize
18
- * commands that target the same executable/profile/site across runner
19
- * instances so concurrent detail workers cannot navigate or close each
20
- * other's active tab. 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
- const queueKey = [this.executable, ...this.prefixArgs, this.profile, site].join('\0');
212
- return serializeSiteCommand(queueKey, async () => {
213
- // Pin adapter traffic to one persistent background session. Persistence
214
- // suppresses OpenCLI's close-window action; the adapter closes only its
215
- // completed task tab and leaves the background container reusable.
216
- const stdout = await this.raw([
217
- site, operation, ...args,
218
- '--site-session', 'persistent', '--window', 'background', '-f', 'json',
219
- ], signal);
220
- try {
221
- const parsed = JSON.parse(stdout);
222
- if (!Array.isArray(parsed) || parsed.some(row => !row || typeof row !== 'object' || Array.isArray(row)))
223
- throw new Error('expected object array');
224
- return parsed;
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);
@@ -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
- * Two schemes are expanded. `dsh-ref:` names material outside the harness and
12
- * is resolved through `ctx.references`. `dsh-session:` names another harness
13
- * session and is delegated to `ctx.sessionReferenceResolver`, which owns
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>;
package/lib/reference.js CHANGED
@@ -8,21 +8,17 @@
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
- * Two schemes are expanded. `dsh-ref:` names material outside the harness and
12
- * is resolved through `ctx.references`. `dsh-session:` names another harness
13
- * session and is delegated to `ctx.sessionReferenceResolver`, which owns
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
  */
19
17
  import z from '@deepseek-ai/schemastery';
20
18
  import { boundContextSummary, createUserMessage, freezeMessage } from '@deepseek-ai/dsh-llm';
21
- import { SESSION_REFERENCE_SCHEME, parseSessionReferenceText, } from '@deepseek-ai/dsh-session-reference';
22
19
  import { ReferenceAnythingError } from "./errors.js";
23
20
  import { renderDeferredReferences } from "./render.js";
24
21
  import { mayContainReference, parseReferenceText } from "./uri.js";
25
- import { WORKSPACE_REFERENCE_SCHEME, parseWorkspaceReferenceText, renderWorkspaceReferences } from "./workspace.js";
26
22
  /** Cordis plugin name used by loader diagnostics. */
27
23
  export const name = 'reference-mention';
28
24
  /** The registry this expander reads through. */
@@ -32,7 +28,6 @@ export const MAX_REFERENCES = 3;
32
28
  /** Runtime schema for {@link Config}. */
33
29
  export const Config = z.object({
34
30
  maxReferences: z.number().step(1).min(1).max(MAX_REFERENCES).default(MAX_REFERENCES),
35
- serveSessionScheme: z.boolean().default(true),
36
31
  });
37
32
  /**
38
33
  * Register the pre-step mention expander.
@@ -41,7 +36,6 @@ export const Config = z.object({
41
36
  */
42
37
  export function apply(ctx, config = {}) {
43
38
  const maxReferences = Math.min(config.maxReferences ?? MAX_REFERENCES, MAX_REFERENCES);
44
- const serveSessionScheme = config.serveSessionScheme ?? true;
45
39
  ctx.on('agent/pre-step', async ({ agent, signal }, next) => {
46
40
  const decision = await next();
47
41
  if (decision.kind === 'reject' || signal.aborted)
@@ -49,7 +43,7 @@ export function apply(ctx, config = {}) {
49
43
  // The overwhelmingly common case is a prompt with no mentions at all, and
50
44
  // this runs on every step of every turn. Screening with substring scans
51
45
  // before any parsing keeps that case free.
52
- const target = decision.messages.findIndex(candidate => candidate.source.kind === 'user' && messageText(candidate).some(text => mentions(text, serveSessionScheme)));
46
+ const target = decision.messages.findIndex(candidate => candidate.source.kind === 'user' && messageText(candidate).some(mayContainReference));
53
47
  if (target < 0)
54
48
  return decision;
55
49
  const original = decision.messages[target];
@@ -57,7 +51,7 @@ export function apply(ctx, config = {}) {
57
51
  return decision;
58
52
  let parsed;
59
53
  try {
60
- parsed = parseMessage(original, serveSessionScheme);
54
+ parsed = parseMessage(original);
61
55
  }
62
56
  catch (error) {
63
57
  // A malformed URI inside an explicit mention is the user asking for
@@ -65,11 +59,11 @@ export function apply(ctx, config = {}) {
65
59
  // reference silently resolves to nothing.
66
60
  return entered(decision, target, [notice(describe(error))], original);
67
61
  }
68
- if (parsed.references.length === 0 && parsed.sessionReferences.length === 0 && parsed.workspaceReferences.length === 0)
62
+ if (parsed.references.length === 0)
69
63
  return decision;
70
64
  let contexts;
71
65
  try {
72
- contexts = await resolve(ctx, agent, parsed, { maxReferences, serveSessionScheme }, signal);
66
+ contexts = await resolve(ctx, agent, parsed, maxReferences, signal);
73
67
  }
74
68
  catch (error) {
75
69
  if (signal.aborted)
@@ -85,28 +79,13 @@ export function apply(ctx, config = {}) {
85
79
  * Authorize and render the named references without reading their bodies.
86
80
  * The agent decides whether the current request warrants `reference_read`.
87
81
  */
88
- async function resolve(ctx, agent, parsed, limits, signal) {
82
+ async function resolve(ctx, agent, parsed, maxReferences, signal) {
89
83
  const contexts = [];
90
- if (parsed.workspaceReferences.length > 0) {
91
- contexts.push(createUserMessage({
92
- content: [{ type: 'text', text: await renderWorkspaceReferences(agent, parsed.workspaceReferences) }],
93
- source: { kind: 'plugin', plugin: name, form: 'recall' },
94
- }));
95
- }
96
- if (parsed.sessionReferences.length > 0) {
97
- const resolver = ctx.get('sessionReferenceResolver');
98
- if (resolver === undefined) {
99
- throw new ReferenceAnythingError('this deployment cannot reference other harness sessions: the cross-session resolver is not mounted', 'SOURCE_UNAVAILABLE');
100
- }
101
- const prepared = await resolver.prepare(agent, contentOf(parsed.message), [...parsed.sessionReferences], signal);
102
- if (prepared.additionalContext !== undefined)
103
- contexts.push(prepared.additionalContext);
104
- }
105
84
  if (parsed.references.length > 0) {
106
85
  const inputs = dedupe(parsed.references);
107
- if (inputs.length > limits.maxReferences) {
108
- throw new ReferenceAnythingError(`a message may reference at most ${limits.maxReferences} outside conversation`
109
- + `${limits.maxReferences === 1 ? '' : 's'}; this one named ${inputs.length}`, 'REFERENCE_TOO_MANY');
86
+ if (inputs.length > maxReferences) {
87
+ throw new ReferenceAnythingError(`a message may reference at most ${maxReferences} outside conversation`
88
+ + `${maxReferences === 1 ? '' : 's'}; this one named ${inputs.length}`, 'REFERENCE_TOO_MANY');
110
89
  }
111
90
  for (const input of inputs)
112
91
  ctx.references.grant(String(agent.session.id), input.ref);
@@ -134,28 +113,16 @@ function entered(decision, target, contexts, message) {
134
113
  const replaced = decision.messages.with(target, message);
135
114
  return { kind: 'enter', messages: replaced.toSpliced(target, 0, ...contexts) };
136
115
  }
137
- /** Rewrite both schemes' mentions to readable text, preserving message identity. */
138
- function parseMessage(message, serveSessionScheme) {
116
+ /** Rewrite external-conversation mentions to readable text, preserving message identity. */
117
+ function parseMessage(message) {
139
118
  const references = [];
140
- const sessionReferences = [];
141
- const workspaceReferences = [];
142
119
  let changed = false;
143
120
  const content = message.content.map((block) => {
144
121
  if (block.type !== 'text')
145
122
  return block;
146
123
  const own = parseReferenceText(block.text);
147
124
  references.push(...own.references);
148
- let text = own.text;
149
- if (text.includes(WORKSPACE_REFERENCE_SCHEME)) {
150
- const workspace = parseWorkspaceReferenceText(text);
151
- workspaceReferences.push(...workspace.references);
152
- text = workspace.text;
153
- }
154
- if (serveSessionScheme && text.includes(SESSION_REFERENCE_SCHEME)) {
155
- const session = parseSessionReferenceText(text);
156
- sessionReferences.push(...session.references);
157
- text = session.text;
158
- }
125
+ const text = own.text;
159
126
  if (text === block.text)
160
127
  return block;
161
128
  changed = true;
@@ -166,8 +133,6 @@ function parseMessage(message, serveSessionScheme) {
166
133
  return {
167
134
  message: changed ? freezeMessage({ ...message, content }) : message,
168
135
  references,
169
- sessionReferences,
170
- workspaceReferences,
171
136
  };
172
137
  }
173
138
  /** First-appearance order, one entry per distinct reference. */
@@ -183,15 +148,9 @@ function dedupe(references) {
183
148
  }
184
149
  return unique;
185
150
  }
186
- function mentions(text, serveSessionScheme) {
187
- return mayContainReference(text) || text.includes(WORKSPACE_REFERENCE_SCHEME) || (serveSessionScheme && text.includes(SESSION_REFERENCE_SCHEME));
188
- }
189
151
  function messageText(message) {
190
152
  return message.content.flatMap(block => block.type === 'text' ? [block.text] : []);
191
153
  }
192
- function contentOf(message) {
193
- return message.content.map(block => ({ ...block }));
194
- }
195
154
  function notice(summary) {
196
155
  return createUserMessage({
197
156
  content: [{
@@ -94,6 +94,7 @@ export default class WebChatHistoryService extends Service implements ReferenceS
94
94
  installOpenCli(signal?: AbortSignal): Promise<OpenCliDiscovery>;
95
95
  updateSettings(value: unknown): Promise<SettingsRecord>;
96
96
  health(signal?: AbortSignal): Promise<import("../../opencli.ts").OpenCliHealth>;
97
+ quickHealth(signal?: AbortSignal): Promise<import("../../opencli.ts").OpenCliHealth>;
97
98
  profiles(signal?: AbortSignal): Promise<import("../../opencli.ts").BrowserProfile[]>;
98
99
  private runner;
99
100
  installAdapter(signal?: AbortSignal): Promise<boolean>;
@@ -229,6 +229,11 @@ export default class WebChatHistoryService extends Service {
229
229
  return new OpenCliRunner({ executable: settings.opencliPath, profile: settings.profile,
230
230
  timeoutMs: this.config.timeoutMs, maxStdoutBytes: this.config.maxStdoutBytes }).health(signal);
231
231
  }
232
+ quickHealth(signal) {
233
+ const settings = this.store.settings;
234
+ return new OpenCliRunner({ executable: settings.opencliPath, profile: settings.profile,
235
+ timeoutMs: this.config.timeoutMs, maxStdoutBytes: this.config.maxStdoutBytes }).quickHealth(signal);
236
+ }
232
237
  profiles(signal) {
233
238
  const settings = this.store.settings;
234
239
  return new OpenCliRunner({ executable: settings.opencliPath, profile: '',
@@ -193,30 +193,39 @@ export declare const referenceAnythingDomainSpec: {
193
193
  "raw-text": "raw-text";
194
194
  }>>;
195
195
  picker: z.ZodOptional<z.ZodObject<{
196
+ displayMode: z.ZodDefault<z.ZodEnum<{
197
+ collapse: "collapse";
198
+ "native-scroll": "native-scroll";
199
+ }>>;
196
200
  commands: z.ZodObject<{
197
201
  enabled: z.ZodBoolean;
198
202
  order: z.ZodNumber;
199
203
  limit: z.ZodNumber;
204
+ maxCandidates: z.ZodDefault<z.ZodNumber>;
200
205
  }, z.core.$strip>;
201
206
  skills: z.ZodObject<{
202
207
  enabled: z.ZodBoolean;
203
208
  order: z.ZodNumber;
204
209
  limit: z.ZodNumber;
210
+ maxCandidates: z.ZodDefault<z.ZodNumber>;
205
211
  }, z.core.$strip>;
206
212
  files: z.ZodObject<{
207
213
  enabled: z.ZodBoolean;
208
214
  order: z.ZodNumber;
209
215
  limit: z.ZodNumber;
216
+ maxCandidates: z.ZodDefault<z.ZodNumber>;
210
217
  }, z.core.$strip>;
211
218
  sessions: z.ZodObject<{
212
219
  enabled: z.ZodBoolean;
213
220
  order: z.ZodNumber;
214
221
  limit: z.ZodNumber;
222
+ maxCandidates: z.ZodDefault<z.ZodNumber>;
215
223
  }, z.core.$strip>;
216
224
  conversations: z.ZodObject<{
217
225
  enabled: z.ZodBoolean;
218
226
  order: z.ZodNumber;
219
227
  limit: z.ZodNumber;
228
+ maxCandidates: z.ZodDefault<z.ZodNumber>;
220
229
  }, z.core.$strip>;
221
230
  }, z.core.$strip>>;
222
231
  }, z.core.$strip>;
package/lib/sync/index.js CHANGED
@@ -109,9 +109,9 @@ export class ConversationSyncManager {
109
109
  const failures = new Map();
110
110
  let succeeded = 0;
111
111
  try {
112
- await Promise.all(job.providers.map(async (provider) => {
112
+ for (const provider of job.providers) {
113
113
  if (job.controller.signal.aborted)
114
- return;
114
+ break;
115
115
  const started = Date.now();
116
116
  try {
117
117
  await this.syncProvider(job, provider, mode, options);
@@ -123,11 +123,11 @@ export class ConversationSyncManager {
123
123
  // logged-out account would otherwise permanently starve every
124
124
  // provider after it in this list.
125
125
  if (job.controller.signal.aborted)
126
- return;
126
+ break;
127
127
  failures.set(provider, describe(error));
128
128
  this.logger?.warn(`reference sync: ${provider} failed: ${describe(error)}`);
129
129
  }
130
- }));
130
+ }
131
131
  job.status = job.controller.signal.aborted ? 'cancelled'
132
132
  : failures.size === 0 ? 'complete'
133
133
  : succeeded === 0 ? 'failed' : 'partial';
package/lib/typert.js CHANGED
@@ -5,10 +5,9 @@ export const TYPERT_MANIFEST = {
5
5
  key: 'referenceAnything', exportName: 'ReferenceAnythingRemote',
6
6
  description: 'Local conversation mirror, synchronization, and settings for @Conversation.', tags: [],
7
7
  members: [
8
- { kind: 'method', name: 'workspaceSearch', signature: 'workspaceSearch(agent: Agent, signal: AbortSignal): Promise<WorkspaceEntry[]>' },
9
- { kind: 'method', name: 'sessionSearch', signature: 'sessionSearch(agent: Agent, input: SessionSearchInput, signal: AbortSignal): Promise<SessionCandidate[]>' },
10
8
  { kind: 'method', name: 'search', signature: 'search(input: SearchInput): Promise<SearchResult[]>' },
11
9
  { kind: 'method', name: 'health', signature: 'health(signal: AbortSignal): Promise<Health>' },
10
+ { kind: 'method', name: 'quickHealth', signature: 'quickHealth(signal: AbortSignal): Promise<Health>' },
12
11
  { kind: 'method', name: 'profiles', signature: 'profiles(signal: AbortSignal): Promise<BrowserProfile[]>' },
13
12
  { kind: 'method', name: 'discoverOpenCli', signature: 'discoverOpenCli(signal: AbortSignal): Promise<OpenCliDiscovery>' },
14
13
  { kind: 'method', name: 'installOpenCli', signature: 'installOpenCli(signal: AbortSignal): Promise<OpenCliDiscovery>' },
package/lib/web.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { ReferenceAnythingRemote } from "./host.js";
2
2
  import { TYPERT_MANIFEST } from "./typert.js";
3
3
  export const name = 'reference-anything-web';
4
- export const inject = ['typert', 'referenceChatHistory', 'sessionReferenceResolver'];
4
+ export const inject = ['typert', 'referenceChatHistory'];
5
5
  export function apply(ctx) {
6
6
  new ReferenceAnythingRemote(ctx);
7
7
  ctx.effect(() => {