@xingular/harness 1.2.0 → 1.3.1-unstable.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/CHANGELOG.md +63 -0
- package/README.md +26 -17
- package/builtin/skills/plugin-authoring/SKILL.md +34 -0
- package/dist/cli.js +7362 -6239
- package/dist/sdk/agents/builtin.js +3 -3
- package/dist/sdk/agents/planResearch.d.ts +23 -1
- package/dist/sdk/agents/planResearch.js +71 -8
- package/dist/sdk/agents/profiles.d.ts +16 -4
- package/dist/sdk/agents/profiles.js +75 -12
- package/dist/sdk/annotations/bridge.d.ts +2 -0
- package/dist/sdk/annotations/bridge.js +4 -0
- package/dist/sdk/annotations/capture.d.ts +44 -2
- package/dist/sdk/annotations/capture.js +104 -3
- package/dist/sdk/annotations/delivery.d.ts +24 -17
- package/dist/sdk/annotations/delivery.js +82 -49
- package/dist/sdk/annotations/inspect.js +7 -6
- package/dist/sdk/annotations/pageScript.js +4 -4
- package/dist/sdk/annotations/part.d.ts +0 -2
- package/dist/sdk/annotations/part.js +4 -33
- package/dist/sdk/annotations/queue.d.ts +2 -2
- package/dist/sdk/annotations/queue.js +12 -7
- package/dist/sdk/annotations/serverMethods.js +11 -7
- package/dist/sdk/annotations/store.d.ts +13 -21
- package/dist/sdk/annotations/store.js +47 -37
- package/dist/sdk/capabilities/runSnapshot.js +10 -4
- package/dist/sdk/commands/list.js +2 -0
- package/dist/sdk/commands/registry.d.ts +11 -3
- package/dist/sdk/commands/registry.js +3 -2
- package/dist/sdk/core/links.d.ts +51 -0
- package/dist/sdk/core/links.js +155 -0
- package/dist/sdk/core/shell.d.ts +20 -0
- package/dist/sdk/core/shell.js +73 -0
- package/dist/sdk/core/workspaceBashTool.d.ts +17 -1
- package/dist/sdk/core/workspaceBashTool.js +16 -2
- package/dist/sdk/core/workspaceSandbox.d.ts +10 -0
- package/dist/sdk/core/workspaceSandbox.js +52 -12
- package/dist/sdk/core/workspaceWriteOperations.d.ts +11 -0
- package/dist/sdk/core/workspaceWriteOperations.js +26 -8
- package/dist/sdk/doctor/checks.js +71 -12
- package/dist/sdk/harness.d.ts +5 -0
- package/dist/sdk/harness.js +11 -6
- package/dist/sdk/hub/hub.js +5 -3
- package/dist/sdk/index.d.ts +3 -2
- package/dist/sdk/index.js +2 -1
- package/dist/sdk/plugins/builtin.js +14 -9
- package/dist/sdk/plugins/builtinRegistry.d.ts +3 -1
- package/dist/sdk/plugins/builtinRegistry.js +9 -3
- package/dist/sdk/plugins/discover.d.ts +7 -1
- package/dist/sdk/plugins/discover.js +41 -2
- package/dist/sdk/plugins/identity.js +1 -1
- package/dist/sdk/plugins/install.d.ts +6 -2
- package/dist/sdk/plugins/install.js +29 -5
- package/dist/sdk/plugins/inventory.js +3 -3
- package/dist/sdk/plugins/manifest.d.ts +2 -0
- package/dist/sdk/plugins/manifest.js +21 -4
- package/dist/sdk/plugins/plugins.d.ts +2 -0
- package/dist/sdk/plugins/plugins.js +1 -0
- package/dist/sdk/plugins/proposals.d.ts +17 -0
- package/dist/sdk/plugins/proposals.js +147 -0
- package/dist/sdk/plugins/types.d.ts +1 -1
- package/dist/sdk/plugins/types.js +1 -1
- package/dist/sdk/prompt/compile.d.ts +13 -4
- package/dist/sdk/prompt/compile.js +46 -20
- package/dist/sdk/prompt/standard.d.ts +1 -1
- package/dist/sdk/prompt/standard.js +1 -1
- package/dist/sdk/server/methods.js +14 -2
- package/dist/sdk/sessions/compactionCheckpoint.d.ts +3 -3
- package/dist/sdk/sessions/compactionCheckpoint.js +12 -12
- package/dist/sdk/sessions/continuation.d.ts +4 -2
- package/dist/sdk/sessions/continuation.js +7 -6
- package/dist/sdk/sessions/contracts.d.ts +22 -4
- package/dist/sdk/sessions/contracts.js +12 -7
- package/dist/sdk/sessions/planMode.js +2 -2
- package/dist/sdk/sessions/runStore.js +3 -1
- package/dist/sdk/sessions/runner.js +2 -2
- package/dist/sdk/sessions/sessionState.d.ts +13 -0
- package/dist/sdk/sessions/sessionState.js +31 -0
- package/dist/sdk/sessions/sessions.d.ts +7 -0
- package/dist/sdk/sessions/sessions.js +73 -15
- package/dist/sdk/sessions/subagentService.d.ts +15 -0
- package/dist/sdk/sessions/subagentService.js +195 -55
- package/dist/sdk/sessions/subagents.d.ts +10 -1
- package/dist/sdk/sessions/subagents.js +4 -0
- package/dist/sdk/sessions/workSlice.d.ts +8 -5
- package/dist/sdk/sessions/workSlice.js +77 -45
- package/dist/sdk/terminal/controller.d.ts +20 -0
- package/dist/sdk/terminal/controller.js +43 -18
- package/dist/sdk/terminal/opentui/ansi.d.ts +25 -0
- package/dist/sdk/terminal/opentui/ansi.js +192 -0
- package/dist/sdk/terminal/opentui/model.d.ts +163 -0
- package/dist/sdk/terminal/opentui/model.js +482 -0
- package/dist/sdk/terminal/opentui/subagentsWidget.d.ts +3 -3
- package/dist/sdk/terminal/opentui/subagentsWidget.js +7 -5
- package/dist/sdk/terminal/opentui/theme.d.ts +2 -0
- package/dist/sdk/terminal/opentui/theme.js +2 -0
- package/dist/sdk/terminal/piExtension.js +98 -15
- package/dist/sdk/terminal/subagentMonitor.d.ts +17 -4
- package/dist/sdk/terminal/subagentMonitor.js +29 -8
- package/dist/sdk/terminal/terminals.d.ts +16 -0
- package/dist/sdk/terminal/terminals.js +130 -26
- package/dist/sdk/terminal/trajectory.d.ts +6 -1
- package/dist/sdk/terminal/trajectory.js +8 -0
- package/dist/sdk/terminal/tui/annotateCommand.d.ts +5 -1
- package/dist/sdk/terminal/tui/annotateCommand.js +21 -7
- package/dist/sdk/terminal/tui/annotateSend.d.ts +30 -0
- package/dist/sdk/terminal/tui/annotateSend.js +40 -0
- package/dist/sdk/terminal/tui/chrome.d.ts +4 -0
- package/dist/sdk/terminal/tui/chrome.js +13 -0
- package/dist/sdk/terminal/tui/commandPages.d.ts +1 -1
- package/dist/sdk/terminal/tui/commandPages.js +16 -11
- package/dist/sdk/terminal/tui/commands.d.ts +4 -0
- package/dist/sdk/terminal/tui/commands.js +12 -2
- package/dist/sdk/terminal/tui/dialogs.js +1 -0
- package/dist/sdk/terminal/tui/pageOverlay.d.ts +3 -0
- package/dist/sdk/terminal/tui/pageOverlay.js +25 -7
- package/dist/sdk/terminal/tui/pages/agentsPage.js +5 -2
- package/dist/sdk/terminal/tui/pages/annotatePage.d.ts +70 -16
- package/dist/sdk/terminal/tui/pages/annotatePage.js +349 -115
- package/dist/sdk/terminal/tui/pages/browserPage.js +5 -4
- package/dist/sdk/terminal/tui/pages/hubPage.d.ts +14 -1
- package/dist/sdk/terminal/tui/pages/hubPage.js +192 -28
- package/dist/sdk/terminal/tui/pages/pluginsPage.d.ts +14 -1
- package/dist/sdk/terminal/tui/pages/pluginsPage.js +295 -25
- package/dist/sdk/terminal/tui/pages/subagentsPage.js +8 -5
- package/dist/sdk/terminal/tui/pages/usagePage.d.ts +4 -2
- package/dist/sdk/terminal/tui/pages/usagePage.js +39 -12
- package/dist/sdk/terminal/tui/pluginCommands.d.ts +1 -1
- package/dist/sdk/terminal/tui/pluginCommands.js +13 -3
- package/dist/sdk/tools/defaultSkills.d.ts +4 -0
- package/dist/sdk/tools/defaultSkills.js +20 -0
- package/dist/sdk/tools/definitions.d.ts +3 -1
- package/dist/sdk/tools/definitions.js +17 -1
- package/dist/sdk/tools/dispatch.js +12 -0
- package/dist/sdk/tools/harnessTools.js +1 -1
- package/dist/sdk/tools/sessionName.d.ts +9 -0
- package/dist/sdk/tools/sessionName.js +58 -11
- package/dist/sdk/tools/spawnSubagent.js +9 -7
- package/dist/sdk/tools/todo.d.ts +15 -0
- package/dist/sdk/tools/todo.js +64 -0
- package/dist/sdk/world/world.d.ts +0 -2
- package/dist/terminal-opentui.js +3331 -1584
- package/dist/terminal-pi.js +421 -133
- package/docs/README.md +3 -0
- package/docs/architecture/00-overview.md +1 -1
- package/docs/architecture/01-extension-points.md +1 -1
- package/docs/architecture/02-sessions-and-runs.md +73 -36
- package/docs/architecture/03-variants.md +1 -3
- package/docs/architecture/04-prompt.md +24 -13
- package/docs/architecture/06-plugins-and-capabilities.md +46 -10
- package/docs/architecture/07-tools-and-gate.md +49 -8
- package/docs/architecture/09-accounts-and-connectors.md +8 -2
- package/docs/architecture/10-server-protocol.md +68 -16
- package/docs/architecture/11-terminal.md +94 -45
- package/docs/architecture/12-storage.md +1 -0
- package/docs/architecture/13-world-tools.md +8 -6
- package/docs/architecture/14-surfaces-and-parity.md +4 -1
- package/docs/architecture/README.md +20 -18
- package/docs/architecture/proposals/PROP-0006-run-checklist.md +2 -0
- package/docs/architecture/proposals/PROP-0018-annotation-queue-and-app-targets.md +6 -2
- package/docs/architecture/proposals/PROP-0041-bounded-work-slices.md +32 -21
- package/docs/architecture/proposals/PROP-0044-work-slice-defaults.md +93 -0
- package/docs/architecture/proposals/PROP-0045-rename-checklist-to-todo.md +132 -0
- package/docs/architecture/proposals/PROP-0046-progress-aware-stall-guards.md +82 -0
- package/docs/architecture/proposals/PROP-0047-plugins-hub-separation.md +122 -0
- package/docs/architecture/proposals/PROP-0048-simple-annotate.md +85 -0
- package/docs/architecture/proposals/README.md +11 -6
- package/docs/decisions/ADR-0039-progress-aware-stall-guards.md +39 -0
- package/docs/decisions/ADR-0040-architecture-change-workflow.md +31 -0
- package/docs/decisions/ADR-0041-plugins-hub-separation.md +41 -0
- package/docs/decisions/ADR-0042-windows-shell-without-sandbox.md +40 -0
- package/docs/decisions/ADR-0043-parents-continue-stopped-subagents.md +49 -0
- package/docs/decisions/ADR-0044-annotations-pending-or-sent.md +24 -0
- package/docs/decisions/ADR-0045-default-plugin-authoring-skill.md +9 -0
- package/docs/decisions/ADR-0046-hash-bound-plugin-proposals.md +20 -0
- package/docs/decisions/ADR-0047-links-open-with-the-os-handler.md +47 -0
- package/docs/doctor.md +14 -1
- package/docs/parity.md +16 -13
- package/docs/releases/1.3.0.md +21 -0
- package/docs/releases/1.3.1-unstable.1.md +8 -0
- package/docs/releases/README.md +9 -6
- package/docs/terminal-tui.md +127 -65
- package/package.json +1 -1
- package/dist/sdk/terminal/tui/pages/notesPage.d.ts +0 -75
- package/dist/sdk/terminal/tui/pages/notesPage.js +0 -201
- package/dist/sdk/tools/checklist.d.ts +0 -9
- package/dist/sdk/tools/checklist.js +0 -55
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `context` is an instruction file Pi reads on its own: `AGENTS.md`, `SYSTEM.md` and their kin.
|
|
3
3
|
* `hook` is a package's hooks file, which the harness runs itself; Pi never loads it.
|
|
4
|
+
* `agent` is a subagent profile a package brings; the harness reads it, Pi never does.
|
|
4
5
|
*/
|
|
5
|
-
export type FoundKind = 'extension' | 'skill' | 'prompt' | 'theme' | 'context' | 'hook';
|
|
6
|
+
export type FoundKind = 'extension' | 'skill' | 'prompt' | 'theme' | 'context' | 'hook' | 'agent';
|
|
6
7
|
/** Where a found item comes from. `builtin` is one of the Pi command's own extensions. */
|
|
7
8
|
export type FoundOrigin = 'shared' | 'package' | 'project' | 'home' | 'builtin';
|
|
8
9
|
export interface Found {
|
|
@@ -33,6 +34,11 @@ export type Resolver = (input: ResolveInput) => Promise<Found[]>;
|
|
|
33
34
|
/** The extensions built into the `pi` command. A terminal loads them; an SDK session has none. */
|
|
34
35
|
export declare const PI_BUILTINS: readonly ["llama.cpp", "codemode", "tool-search", "mcp"];
|
|
35
36
|
export declare const BUILTIN_PREFIX = "builtin:";
|
|
37
|
+
/**
|
|
38
|
+
* The subagent profiles in a package's agents folder: Markdown files whose frontmatter has a
|
|
39
|
+
* `name` and a `description`. Anything else there (notes, a README) is not a profile.
|
|
40
|
+
*/
|
|
41
|
+
export declare function packageProfiles(root: string, folder: string): string[];
|
|
36
42
|
/**
|
|
37
43
|
* Runs an install with the package manager's install scripts switched off, so fetching a
|
|
38
44
|
* package runs none of its code. A package that builds itself on install then fails to load,
|
|
@@ -1,14 +1,50 @@
|
|
|
1
1
|
// What Pi would load for a session, found with Pi's own resolver so the list matches Pi's
|
|
2
2
|
// rules. Resolving reads folders and manifests; it never runs an extension.
|
|
3
|
-
import { existsSync } from 'node:fs';
|
|
3
|
+
import { existsSync, lstatSync, readdirSync, readFileSync } from 'node:fs';
|
|
4
4
|
import { homedir } from 'node:os';
|
|
5
5
|
import { join, sep } from 'node:path';
|
|
6
6
|
import { log } from "../core/bus.js";
|
|
7
|
+
import * as frontmatter from "../core/frontmatter.js";
|
|
7
8
|
import { loadPi } from "../pi/runtime.js";
|
|
8
9
|
import { packageManifest } from "./manifest.js";
|
|
9
10
|
/** The extensions built into the `pi` command. A terminal loads them; an SDK session has none. */
|
|
10
11
|
export const PI_BUILTINS = ['llama.cpp', 'codemode', 'tool-search', 'mcp'];
|
|
11
12
|
export const BUILTIN_PREFIX = 'builtin:';
|
|
13
|
+
/** At most this many profiles are read from one package. */
|
|
14
|
+
const MAX_PACKAGE_PROFILES = 50;
|
|
15
|
+
/**
|
|
16
|
+
* The subagent profiles in a package's agents folder: Markdown files whose frontmatter has a
|
|
17
|
+
* `name` and a `description`. Anything else there (notes, a README) is not a profile.
|
|
18
|
+
*/
|
|
19
|
+
export function packageProfiles(root, folder) {
|
|
20
|
+
const dir = join(root, folder);
|
|
21
|
+
let names;
|
|
22
|
+
try {
|
|
23
|
+
if (!lstatSync(dir).isDirectory())
|
|
24
|
+
return [];
|
|
25
|
+
names = readdirSync(dir).filter((name) => name.endsWith('.md') && !name.startsWith('.')).sort();
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
const profiles = [];
|
|
31
|
+
for (const name of names) {
|
|
32
|
+
const path = join(dir, name);
|
|
33
|
+
try {
|
|
34
|
+
if (!lstatSync(path).isFile())
|
|
35
|
+
continue;
|
|
36
|
+
const front = frontmatter.parse(readFileSync(path, 'utf8'))?.front;
|
|
37
|
+
if (typeof front?.name === 'string' && front.name.trim() && typeof front.description === 'string' && front.description.trim())
|
|
38
|
+
profiles.push(path);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (profiles.length >= MAX_PACKAGE_PROFILES)
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
return profiles;
|
|
47
|
+
}
|
|
12
48
|
const inside = (path, parent) => path === parent || path.startsWith(parent.endsWith(sep) ? parent : `${parent}${sep}`);
|
|
13
49
|
function origin(path, metadata) {
|
|
14
50
|
if (path.startsWith(BUILTIN_PREFIX))
|
|
@@ -92,7 +128,10 @@ export const piResolver = async ({ cwd, agentDir, install, packages }) => {
|
|
|
92
128
|
for (const folder of packages ?? [])
|
|
93
129
|
roots.set(folder, folder);
|
|
94
130
|
for (const [root, source] of roots) {
|
|
95
|
-
const
|
|
131
|
+
const manifest = packageManifest(root);
|
|
132
|
+
for (const path of packageProfiles(root, manifest.agents))
|
|
133
|
+
found.push({ kind: 'agent', path, origin: 'package', project: false, packageRoot: root, source, enabled: true });
|
|
134
|
+
const hooks = manifest.hooks;
|
|
96
135
|
if (!hooks || !existsSync(join(root, hooks)))
|
|
97
136
|
continue;
|
|
98
137
|
found.push({ kind: 'hook', path: join(root, hooks), origin: 'package', project: false, packageRoot: root, source, enabled: true });
|
|
@@ -6,7 +6,7 @@ import * as frontmatter from "../core/frontmatter.js";
|
|
|
6
6
|
import { BUILTIN_PREFIX } from "./discover.js";
|
|
7
7
|
import { packageManifest } from "./manifest.js";
|
|
8
8
|
export { packageManifest } from "./manifest.js";
|
|
9
|
-
export const FOUND_KINDS = { extension: 'code', hook: 'code', skill: 'skill', prompt: 'command', theme: 'theme', context: 'instruction' };
|
|
9
|
+
export const FOUND_KINDS = { extension: 'code', hook: 'code', skill: 'skill', prompt: 'command', agent: 'agent', theme: 'theme', context: 'instruction' };
|
|
10
10
|
/** The id of the plugin a found item is listed under. */
|
|
11
11
|
export function pluginIdOf(item) {
|
|
12
12
|
if (item.origin === 'builtin')
|
|
@@ -10,11 +10,15 @@ export declare function normalizeSource(input: string): string;
|
|
|
10
10
|
export declare function install(harness: Harness, params: PluginScope & {
|
|
11
11
|
source: string;
|
|
12
12
|
}): Promise<Plugin[]>;
|
|
13
|
-
/** Removes an installed package
|
|
13
|
+
/** Removes an installed package without consulting Hub. Hub calls this while it owns the receipt transaction. */
|
|
14
|
+
export declare function removeDirect(harness: Harness, params: PluginScope & {
|
|
15
|
+
pluginId: string;
|
|
16
|
+
}): Promise<Plugin[]>;
|
|
17
|
+
/** Removes an installed package, delegating Hub-owned packages to their receipt owner. */
|
|
14
18
|
export declare function remove(harness: Harness, params: PluginScope & {
|
|
15
19
|
pluginId: string;
|
|
16
20
|
}): Promise<Plugin[]>;
|
|
17
|
-
/** Fetches
|
|
21
|
+
/** Fetches newer versions of local packages. Hub-owned packages remain pinned to catalog versions. */
|
|
18
22
|
export declare function update(harness: Harness, params: PluginScope & {
|
|
19
23
|
pluginId?: string | null;
|
|
20
24
|
}): Promise<Plugin[]>;
|
|
@@ -75,8 +75,8 @@ function installed(plugins, pluginId) {
|
|
|
75
75
|
throw invalid(`${plugin.title} was not installed as a package, so it cannot be removed or updated here.`);
|
|
76
76
|
return plugin;
|
|
77
77
|
}
|
|
78
|
-
/** Removes an installed package
|
|
79
|
-
export async function
|
|
78
|
+
/** Removes an installed package without consulting Hub. Hub calls this while it owns the receipt transaction. */
|
|
79
|
+
export async function removeDirect(harness, params) {
|
|
80
80
|
const plugin = installed(await list(harness, params), params.pluginId);
|
|
81
81
|
if (plugin.install.kind === 'folder') {
|
|
82
82
|
const trash = join(harness.env.root, 'trash', 'plugins');
|
|
@@ -98,13 +98,37 @@ export async function remove(harness, params) {
|
|
|
98
98
|
changed(harness);
|
|
99
99
|
return list(harness, params);
|
|
100
100
|
}
|
|
101
|
-
|
|
101
|
+
async function hubReceiptForPackage(harness, pluginId) {
|
|
102
|
+
const receipts = (await harness.hub.list()).installed.filter((receipt) => receipt.entry.delivery.kind === 'pi-package' && receipt.resourceIds.includes(pluginId));
|
|
103
|
+
if (receipts.length > 1)
|
|
104
|
+
throw invalid('More than one Hub receipt owns this package. Review the Hub receipts before changing it.');
|
|
105
|
+
return receipts[0];
|
|
106
|
+
}
|
|
107
|
+
/** Removes an installed package, delegating Hub-owned packages to their receipt owner. */
|
|
108
|
+
export async function remove(harness, params) {
|
|
109
|
+
const receipt = await hubReceiptForPackage(harness, params.pluginId);
|
|
110
|
+
if (receipt) {
|
|
111
|
+
await harness.hub.uninstall(receipt.entry.id, receipt.entry.version);
|
|
112
|
+
return list(harness, params);
|
|
113
|
+
}
|
|
114
|
+
return removeDirect(harness, params);
|
|
115
|
+
}
|
|
116
|
+
/** Fetches newer versions of local packages. Hub-owned packages remain pinned to catalog versions. */
|
|
102
117
|
export async function update(harness, params) {
|
|
103
|
-
const
|
|
118
|
+
const plugins = await list(harness, params);
|
|
119
|
+
const plugin = params.pluginId ? installed(plugins, params.pluginId) : null;
|
|
104
120
|
if (plugin?.install.kind === 'folder')
|
|
105
121
|
throw invalid(`${plugin.title} is a folder on this machine. Change its files to update it.`);
|
|
122
|
+
const receipts = (await harness.hub.list()).installed.filter((receipt) => receipt.entry.delivery.kind === 'pi-package');
|
|
123
|
+
const hubOwned = new Set(receipts.flatMap((receipt) => receipt.resourceIds));
|
|
124
|
+
if (plugin && hubOwned.has(plugin.id))
|
|
125
|
+
throw invalid(`${plugin.title} is managed by Hub. Uninstall its receipt before installing another exact catalog version.`);
|
|
126
|
+
const sources = plugin
|
|
127
|
+
? [plugin.install.source]
|
|
128
|
+
: [...new Set(plugins.filter((candidate) => candidate.install && candidate.install.kind !== 'folder' && !hubOwned.has(candidate.id)).map((candidate) => candidate.install.source))];
|
|
106
129
|
const { packages } = await manager(harness);
|
|
107
|
-
|
|
130
|
+
for (const source of sources)
|
|
131
|
+
await withoutInstallScripts(() => packages.update(source));
|
|
108
132
|
changed(harness);
|
|
109
133
|
return list(harness, params);
|
|
110
134
|
}
|
|
@@ -6,7 +6,7 @@ import { charCount } from "../core/text.js";
|
|
|
6
6
|
import { allowed } from "../mcp/connections.js";
|
|
7
7
|
import { BUILT_IN_DYNAMIC, compile, toolGroups } from "../prompt/compile.js";
|
|
8
8
|
import { ASK_USER } from "../tools/askUser.js";
|
|
9
|
-
import {
|
|
9
|
+
import { TODO_WRITE } from "../tools/todo.js";
|
|
10
10
|
import { DEFAULT_TOOL_NAMES } from "../tools/definitions.js";
|
|
11
11
|
import { VARIANT_PLUGIN } from "./builtin.js";
|
|
12
12
|
const size = (path) => {
|
|
@@ -68,7 +68,7 @@ export function inventory(input) {
|
|
|
68
68
|
}
|
|
69
69
|
const names = [...input.tools];
|
|
70
70
|
const extensionToolNames = new Set(input.plugins.filter((plugin) => ['project', 'package', 'shared', 'home'].includes(plugin.source)).flatMap((plugin) => plugin.contributions.filter((entry) => entry.kind === 'tool' && entry.state === 'on').map((entry) => entry.name)));
|
|
71
|
-
for (const name of [ASK_USER,
|
|
71
|
+
for (const name of [ASK_USER, TODO_WRITE, ...DEFAULT_TOOL_NAMES, ...(input.connections ? ['mcp_list_tools', 'mcp_call_tool'] : [])])
|
|
72
72
|
if (!names.includes(name))
|
|
73
73
|
names.push(name);
|
|
74
74
|
for (const name of names) {
|
|
@@ -86,7 +86,7 @@ export function inventory(input) {
|
|
|
86
86
|
}
|
|
87
87
|
// What the harness found on disk and lets load. The pi command's own extensions load in no
|
|
88
88
|
// Xingular session, so a terminal and a host have the same (PROP-0039).
|
|
89
|
-
const delivered = { code: 'code', skill: 'on-demand', command: 'on-demand', instruction: 'system', theme: 'code', tool: 'tool', connection: 'tool' };
|
|
89
|
+
const delivered = { code: 'code', skill: 'on-demand', command: 'on-demand', agent: 'on-demand', instruction: 'system', theme: 'code', tool: 'tool', connection: 'tool' };
|
|
90
90
|
const terminal = context.surface === 'cli';
|
|
91
91
|
for (const plugin of input.plugins) {
|
|
92
92
|
if (!['project', 'package', 'shared', 'home'].includes(plugin.source))
|
|
@@ -9,6 +9,8 @@ export interface PackageManifest {
|
|
|
9
9
|
commandPrefix: string | null;
|
|
10
10
|
/** The hooks file, inside the package, or `null` when it has none. */
|
|
11
11
|
hooks: string | null;
|
|
12
|
+
/** The folder of subagent profiles, inside the package. `agents` unless the manifest names another. */
|
|
13
|
+
agents: string;
|
|
12
14
|
/** Data-only remote connector forms. Invalid templates are ignored; none can carry credentials. */
|
|
13
15
|
connectorTemplates: ConnectorTemplate[];
|
|
14
16
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// What a package says about itself in its `package.json`: Pi's own fields, and under `harness`
|
|
2
|
-
// which part of the harness it extends, its command namespace
|
|
2
|
+
// which part of the harness it extends, its command namespace, the file of hooks it runs and the
|
|
3
|
+
// folder of subagent profiles it brings. A package written for other agent harnesses may have no
|
|
4
|
+
// `package.json`; its `plugin.json` then names and describes it.
|
|
3
5
|
import { basename, join } from 'node:path';
|
|
4
6
|
import { z } from 'zod';
|
|
5
7
|
import { readJsonOr, safeRelative } from "../core/fs.js";
|
|
@@ -39,16 +41,31 @@ function inside(path) {
|
|
|
39
41
|
return null;
|
|
40
42
|
}
|
|
41
43
|
}
|
|
44
|
+
/** The plugin manifests other agent harnesses read, in the order they are tried. */
|
|
45
|
+
const PLUGIN_MANIFESTS = ['plugin.json', '.claude-plugin/plugin.json', '.codex-plugin/plugin.json'];
|
|
46
|
+
const text = (value) => (typeof value === 'string' && value.trim() ? value.trim() : null);
|
|
47
|
+
function pluginJson(packageRoot) {
|
|
48
|
+
for (const file of PLUGIN_MANIFESTS) {
|
|
49
|
+
const found = readJsonOr(join(packageRoot, file), null);
|
|
50
|
+
if (found && typeof found === 'object' && !Array.isArray(found))
|
|
51
|
+
return found;
|
|
52
|
+
}
|
|
53
|
+
return {};
|
|
54
|
+
}
|
|
42
55
|
export function packageManifest(packageRoot) {
|
|
43
56
|
const manifest = readJsonOr(join(packageRoot, 'package.json'), {});
|
|
57
|
+
// Only a package without a name of its own is described by its plugin.json.
|
|
58
|
+
const plugin = text(manifest.name) ? {} : pluginJson(packageRoot);
|
|
44
59
|
const own = (manifest.harness && typeof manifest.harness === 'object' && !Array.isArray(manifest.harness) ? manifest.harness : {});
|
|
60
|
+
const pluginName = text(plugin.name);
|
|
45
61
|
return {
|
|
46
|
-
name:
|
|
47
|
-
description:
|
|
48
|
-
version:
|
|
62
|
+
name: text(manifest.name) ?? (pluginName && /^[a-z0-9][a-z0-9._-]*$/i.test(pluginName) ? pluginName : basename(packageRoot)),
|
|
63
|
+
description: text(manifest.description) ?? text(plugin.description) ?? '',
|
|
64
|
+
version: text(manifest.version) ?? text(plugin.version),
|
|
49
65
|
extends: (Array.isArray(own.extends) ? own.extends : typeof own.extends === 'string' ? [own.extends] : []).filter((id) => typeof id === 'string' && !!id),
|
|
50
66
|
commandPrefix: typeof own.commandPrefix === 'string' && /^[a-z][a-z0-9-]*$/i.test(own.commandPrefix) && !['plugin', 'skill'].includes(own.commandPrefix.toLowerCase()) ? own.commandPrefix.toLowerCase() : null,
|
|
51
67
|
hooks: inside(own.hooks),
|
|
68
|
+
agents: inside(own.agents) ?? 'agents',
|
|
52
69
|
connectorTemplates: (Array.isArray(own.connectors) ? own.connectors : []).flatMap((value) => {
|
|
53
70
|
const parsed = connectorTemplateSchema.safeParse(value);
|
|
54
71
|
return parsed.success ? [parsed.data] : [];
|
|
@@ -9,6 +9,8 @@ export interface Loading {
|
|
|
9
9
|
skillPaths: string[];
|
|
10
10
|
promptPaths: string[];
|
|
11
11
|
themePaths: string[];
|
|
12
|
+
/** Subagent profile files packages bring. The harness reads them; Pi is never given them. */
|
|
13
|
+
profilePaths: string[];
|
|
12
14
|
/** The `pi` command's own extensions left on, as `builtin:<name>`. Only a terminal has them. */
|
|
13
15
|
builtins: string[];
|
|
14
16
|
/** Hooks files the harness runs itself. Pi is never given them. */
|
|
@@ -87,6 +87,7 @@ export class Plugins {
|
|
|
87
87
|
skillPaths: paths('skill', false),
|
|
88
88
|
promptPaths: paths('prompt', false),
|
|
89
89
|
themePaths: paths('theme', false),
|
|
90
|
+
profilePaths: paths('agent', false),
|
|
90
91
|
builtins: paths('extension', true),
|
|
91
92
|
hooks: chosen.filter((item) => item.kind === 'hook' && item.packageRoot).map((item) => ({ path: item.path, packageRoot: item.packageRoot, hash: packageCodeState[item.packageRoot]?.hash ?? '' })),
|
|
92
93
|
found,
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Harness } from "../harness.js";
|
|
2
|
+
export interface Proposal {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
files: Record<string, string>;
|
|
7
|
+
manifest: string;
|
|
8
|
+
hash: string;
|
|
9
|
+
createdAt: string;
|
|
10
|
+
status: 'pending' | 'accepted' | 'rejected';
|
|
11
|
+
decidedAt?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function create(root: string, name: unknown, description: unknown, files: unknown): Proposal;
|
|
14
|
+
export declare function preview(root: string, id: string): Proposal;
|
|
15
|
+
export declare function list(root: string): Proposal[];
|
|
16
|
+
export declare function reject(root: string, id: string, hash: string): Proposal;
|
|
17
|
+
export declare function accept(harness: Harness, id: string, hash: string): Promise<Proposal>;
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
2
|
+
import { mkdirSync, readdirSync, renameSync, rmSync, rmdirSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { invalid, notFound } from "../core/errors.js";
|
|
5
|
+
import * as frontmatter from "../core/frontmatter.js";
|
|
6
|
+
import { now, readJson, safeId, safeRelative, writeJson } from "../core/fs.js";
|
|
7
|
+
import { ensureAdopted, list as listPlugins } from "./api.js";
|
|
8
|
+
import * as attachments from "./attachments.js";
|
|
9
|
+
import { packageCode } from "./trust.js";
|
|
10
|
+
const MAX_FILES = 100;
|
|
11
|
+
const MAX_FILE_BYTES = 256 * 1024;
|
|
12
|
+
const MAX_TOTAL_BYTES = 1024 * 1024;
|
|
13
|
+
const dir = (root) => join(root, 'plugin-proposals');
|
|
14
|
+
const pathOf = (root, id) => join(dir(root), `${safeId(id)}.json`);
|
|
15
|
+
function validate(name, description, input) {
|
|
16
|
+
if (typeof name !== 'string' || !/^[a-z0-9][a-z0-9_-]{0,63}$/.test(name))
|
|
17
|
+
throw invalid('Plugin name must be lowercase letters, digits, underscores or hyphens.');
|
|
18
|
+
if (typeof description !== 'string' || !description.trim() || Buffer.byteLength(description, 'utf8') > 4096 || /[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/u.test(description))
|
|
19
|
+
throw invalid('Description must be non-empty valid text of at most 4096 bytes.');
|
|
20
|
+
if (!input || typeof input !== 'object' || Array.isArray(input))
|
|
21
|
+
throw invalid('Files must be a path to text object.');
|
|
22
|
+
const entries = Object.entries(input);
|
|
23
|
+
if (!entries.length || entries.length > MAX_FILES)
|
|
24
|
+
throw invalid('A proposal must contain between 1 and 100 files.');
|
|
25
|
+
const files = Object.create(null);
|
|
26
|
+
let total = 0;
|
|
27
|
+
for (const [path, content] of entries) {
|
|
28
|
+
if (typeof content !== 'string' || /[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/u.test(content))
|
|
29
|
+
throw invalid('Each file must be valid UTF-8 text.');
|
|
30
|
+
if (path.includes('\\') || path.length > 240 || /[\x00-\x1f\x7f]/.test(path) || safeRelative(path) !== path || path.split('/').some((part) => part === 'node_modules' || part === '.git'))
|
|
31
|
+
throw invalid('Invalid proposal file path.');
|
|
32
|
+
if (!/^(?:README\.md|extensions\/[A-Za-z0-9_./-]+\.(?:ts|js|mjs)|skills\/[A-Za-z0-9_./-]+\.md|prompts\/[A-Za-z0-9_./-]+\.md|agents\/[A-Za-z0-9_./-]+\.md|themes\/[A-Za-z0-9_./-]+\.json)$/.test(path))
|
|
33
|
+
throw invalid('Unsupported proposal file type or location.');
|
|
34
|
+
if (path.startsWith('skills/') && path.endsWith('/SKILL.md')) {
|
|
35
|
+
if (!/^skills\/[A-Za-z0-9_-]+\/SKILL\.md$/.test(path))
|
|
36
|
+
throw invalid('Skill files must be in skills/<name>/SKILL.md.');
|
|
37
|
+
const front = frontmatter.parse(content)?.front;
|
|
38
|
+
if (front?.name !== path.split('/')[1] || typeof front.description !== 'string' || !front.description.trim())
|
|
39
|
+
throw invalid('Skill frontmatter needs a matching name and a non-empty description.');
|
|
40
|
+
}
|
|
41
|
+
const bytes = Buffer.byteLength(content, 'utf8');
|
|
42
|
+
if (bytes > MAX_FILE_BYTES || (total += bytes) > MAX_TOTAL_BYTES)
|
|
43
|
+
throw invalid('Proposal files exceed the size limit.');
|
|
44
|
+
files[path] = content;
|
|
45
|
+
}
|
|
46
|
+
for (const path of Object.keys(files))
|
|
47
|
+
if (Object.keys(files).some((other) => other.startsWith(`${path}/`)))
|
|
48
|
+
throw invalid('A file cannot also be a directory.');
|
|
49
|
+
const manifest = `${JSON.stringify({ name, version: '1.0.0', description }, null, 2)}\n`;
|
|
50
|
+
const hash = createHash('sha256').update(JSON.stringify([name, description, manifest, Object.entries(files).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)])).digest('hex');
|
|
51
|
+
return { name, description, files, manifest, hash };
|
|
52
|
+
}
|
|
53
|
+
export function create(root, name, description, files) {
|
|
54
|
+
const valid = validate(name, description, files);
|
|
55
|
+
const proposal = { id: randomUUID(), ...valid, createdAt: now(), status: 'pending' };
|
|
56
|
+
writeJson(pathOf(root, proposal.id), proposal);
|
|
57
|
+
return proposal;
|
|
58
|
+
}
|
|
59
|
+
export function preview(root, id) {
|
|
60
|
+
const proposal = readJson(pathOf(root, id));
|
|
61
|
+
if (!proposal)
|
|
62
|
+
throw notFound('Proposal');
|
|
63
|
+
const valid = validate(proposal.name, proposal.description, proposal.files);
|
|
64
|
+
if (proposal.id !== id || !['pending', 'accepted', 'rejected'].includes(proposal.status))
|
|
65
|
+
throw invalid('Invalid stored proposal.');
|
|
66
|
+
return { ...proposal, ...valid };
|
|
67
|
+
}
|
|
68
|
+
export function list(root) {
|
|
69
|
+
let names;
|
|
70
|
+
try {
|
|
71
|
+
names = readdirSync(dir(root));
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
if (error.code === 'ENOENT')
|
|
75
|
+
return [];
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
return names.filter((name) => /^[a-f0-9-]+\.json$/.test(name)).sort().map((name) => preview(root, name.slice(0, -5)));
|
|
79
|
+
}
|
|
80
|
+
function reviewed(proposal, hash) {
|
|
81
|
+
if (proposal.status !== 'pending')
|
|
82
|
+
throw invalid('Proposal is no longer pending.');
|
|
83
|
+
if (!/^[a-f0-9]{64}$/.test(hash) || proposal.hash !== hash)
|
|
84
|
+
throw invalid('Stale proposal review; preview it again.');
|
|
85
|
+
}
|
|
86
|
+
export function reject(root, id, hash) {
|
|
87
|
+
const proposal = preview(root, id);
|
|
88
|
+
reviewed(proposal, hash);
|
|
89
|
+
const rejected = { ...proposal, status: 'rejected', decidedAt: now() };
|
|
90
|
+
writeJson(pathOf(root, id), rejected);
|
|
91
|
+
return rejected;
|
|
92
|
+
}
|
|
93
|
+
export async function accept(harness, id, hash) {
|
|
94
|
+
const root = harness.env.root;
|
|
95
|
+
const initial = preview(root, id);
|
|
96
|
+
reviewed(initial, hash);
|
|
97
|
+
await ensureAdopted(harness);
|
|
98
|
+
const existing = await listPlugins(harness, {});
|
|
99
|
+
const proposal = preview(root, id);
|
|
100
|
+
reviewed(proposal, hash);
|
|
101
|
+
const pluginId = `package:${proposal.name}`;
|
|
102
|
+
if (existing.some((plugin) => plugin.id === pluginId))
|
|
103
|
+
throw invalid('A plugin with this name already exists.');
|
|
104
|
+
const parent = join(root, 'plugins');
|
|
105
|
+
const destination = join(parent, proposal.name);
|
|
106
|
+
mkdirSync(parent, { recursive: true });
|
|
107
|
+
const stage = join(parent, `.proposal-${randomUUID()}`);
|
|
108
|
+
mkdirSync(stage);
|
|
109
|
+
let reserved = false;
|
|
110
|
+
try {
|
|
111
|
+
for (const [path, content] of Object.entries(proposal.files)) {
|
|
112
|
+
const target = join(stage, path);
|
|
113
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
114
|
+
writeFileSync(target, content, { flag: 'wx' });
|
|
115
|
+
}
|
|
116
|
+
writeFileSync(join(stage, 'package.json'), proposal.manifest, { flag: 'wx' });
|
|
117
|
+
const found = { kind: 'extension', path: stage, origin: 'package', project: false, packageRoot: stage, source: stage, enabled: true };
|
|
118
|
+
const code = packageCode([found]).get(stage);
|
|
119
|
+
if (harness.plugins.trust.has(code.hash))
|
|
120
|
+
throw invalid('Identical package code is already trusted; change it before accepting.');
|
|
121
|
+
// Reserve the destination exclusively. Renaming over our empty directory publishes the whole package.
|
|
122
|
+
mkdirSync(destination);
|
|
123
|
+
reserved = true;
|
|
124
|
+
const choices = attachments.load(root);
|
|
125
|
+
for (const scope of [choices.global, ...Object.values(choices.agents), ...Object.values(choices.projects)]) {
|
|
126
|
+
scope.on = scope.on.filter((entry) => entry !== pluginId && !entry.startsWith(`${pluginId}/`));
|
|
127
|
+
scope.off = scope.off.filter((entry) => entry !== pluginId && !entry.startsWith(`${pluginId}/`));
|
|
128
|
+
}
|
|
129
|
+
attachments.set(choices, [pluginId], {}, false, true);
|
|
130
|
+
attachments.save(root, choices);
|
|
131
|
+
renameSync(stage, destination);
|
|
132
|
+
reserved = false;
|
|
133
|
+
const accepted = { ...proposal, status: 'accepted', decidedAt: now() };
|
|
134
|
+
writeJson(pathOf(root, id), accepted);
|
|
135
|
+
harness.bus.emit({ type: 'plugins.changed' });
|
|
136
|
+
return accepted;
|
|
137
|
+
}
|
|
138
|
+
finally {
|
|
139
|
+
rmSync(stage, { recursive: true, force: true });
|
|
140
|
+
if (reserved) {
|
|
141
|
+
try {
|
|
142
|
+
rmdirSync(destination);
|
|
143
|
+
}
|
|
144
|
+
catch { /* Do not remove another writer's files. */ }
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Attachment } from "./attachments.js";
|
|
2
2
|
import type { Registered } from "./plugins.js";
|
|
3
3
|
import type { ProjectCode } from "./trust.js";
|
|
4
|
-
export declare const CONTRIBUTION_KINDS: readonly ["instruction", "skill", "command", "tool", "connection", "code", "theme"];
|
|
4
|
+
export declare const CONTRIBUTION_KINDS: readonly ["instruction", "skill", "command", "agent", "tool", "connection", "code", "theme"];
|
|
5
5
|
export type ContributionKind = (typeof CONTRIBUTION_KINDS)[number];
|
|
6
6
|
/**
|
|
7
7
|
* Where a plugin comes from: the harness itself, the embedding application, Pi, a person's own
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const CONTRIBUTION_KINDS = ['instruction', 'skill', 'command', 'tool', 'connection', 'code', 'theme'];
|
|
1
|
+
export const CONTRIBUTION_KINDS = ['instruction', 'skill', 'command', 'agent', 'tool', 'connection', 'code', 'theme'];
|
|
2
2
|
/**
|
|
3
3
|
* Where a plugin comes from: the harness itself, the embedding application, Pi, a person's own
|
|
4
4
|
* registry, the folder every account shares, an installed package, the working folder, or the
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { type CallerContext } from "../core/caller.js";
|
|
2
2
|
import type { HarnessEnv } from "../core/env.js";
|
|
3
3
|
import type { Materialised } from "../variant/materialise.js";
|
|
4
|
-
import type {
|
|
4
|
+
import type { TodoItem } from "../sessions/contracts.js";
|
|
5
|
+
import type { SessionState } from "../sessions/sessionState.js";
|
|
5
6
|
import { type StandardSession } from "./standard.js";
|
|
6
7
|
export declare const REFERENCES_BUDGET = 12000;
|
|
7
8
|
/** Where the harness's own sections sit; an application's sections are placed among them by `order`. */
|
|
8
9
|
export declare const SECTION_ORDER: {
|
|
9
10
|
readonly harnessIdentity: 5;
|
|
10
11
|
readonly system: 25;
|
|
12
|
+
readonly sessionState: 30;
|
|
11
13
|
readonly guardrails: 40;
|
|
12
14
|
readonly memory: 45;
|
|
13
15
|
readonly references: 50;
|
|
@@ -24,7 +26,7 @@ export interface Source {
|
|
|
24
26
|
revision?: string | null;
|
|
25
27
|
}
|
|
26
28
|
export interface Section {
|
|
27
|
-
/** `harness-identity`, `identity`, `role`, `system`, `guardrails`, `memory`, `references`, `subagents`, `scripts`, `wiki`, `tools`, or an application's own. */
|
|
29
|
+
/** `harness-identity`, `identity`, `role`, `system`, `session-state`, `guardrails`, `memory`, `references`, `subagents`, `scripts`, `wiki`, `tools`, or an application's own. */
|
|
28
30
|
id: string;
|
|
29
31
|
title: string;
|
|
30
32
|
body: string;
|
|
@@ -103,6 +105,8 @@ export interface Launch {
|
|
|
103
105
|
connectionTools?: string[];
|
|
104
106
|
/** The tools switched on for the caller. The pack only describes tools the caller can call. */
|
|
105
107
|
tools?: string[] | null;
|
|
108
|
+
/** The current session name and this run's todo, delivered as a request-scoped update. */
|
|
109
|
+
sessionState?: SessionState;
|
|
106
110
|
references?: Reference[];
|
|
107
111
|
sections?: HostSection[];
|
|
108
112
|
toolGroups?: HostToolGroup[];
|
|
@@ -135,7 +139,7 @@ export declare function clip(text: string, limit: number): string;
|
|
|
135
139
|
/** A bounded, request-scoped checkpoint reintroduced after context compaction. */
|
|
136
140
|
export declare function renderCompactionCheckpoint(input: {
|
|
137
141
|
goal: string;
|
|
138
|
-
|
|
142
|
+
todo: readonly TodoItem[];
|
|
139
143
|
planInstructions?: string | null;
|
|
140
144
|
}): string | null;
|
|
141
145
|
export interface OrderedGroup extends ToolGroup {
|
|
@@ -147,6 +151,11 @@ export interface OrderedGroup extends ToolGroup {
|
|
|
147
151
|
* follows the switches in `launch.tools` and what the application provides.
|
|
148
152
|
*/
|
|
149
153
|
export declare function toolGroups(context: CallerContext, launch: Launch, dataRoot?: string): OrderedGroup[];
|
|
154
|
+
/** The request-scoped state line: the name, this run's todo, and the previous list as context. */
|
|
155
|
+
export declare function sessionStateText(state: SessionState, options: {
|
|
156
|
+
name: boolean;
|
|
157
|
+
todo: boolean;
|
|
158
|
+
}): string | null;
|
|
150
159
|
/** Compiles the pack for a caller. It only reads the data root. */
|
|
151
160
|
export declare function compile(env: HarnessEnv, context: CallerContext, launch?: Launch, variant?: Materialised | null): ContextPack;
|
|
152
161
|
/** The pack as the one string a session receives. */
|
|
@@ -160,7 +169,7 @@ export declare const BUILT_IN_DYNAMIC: readonly {
|
|
|
160
169
|
id: string;
|
|
161
170
|
order: number;
|
|
162
171
|
}[];
|
|
163
|
-
export declare const CONTEXT_GUIDANCE = "App-origin context updates in the conversation supply current Wiki notes, active work, and selected references. Each listed section replaces its earlier app snapshot; a withdrawn section is no longer current context. These updates are context, not requests from the user. Selected references apply only to the accompanying request. They do not change permissions. Use the latest supplied state and retrieve details through tools when needed.";
|
|
172
|
+
export declare const CONTEXT_GUIDANCE = "App-origin context updates in the conversation supply current Wiki notes, active work, session state, and selected references. Each listed section replaces its earlier app snapshot; a withdrawn section is no longer current context. These updates are context, not requests from the user. Selected references apply only to the accompanying request. They do not change permissions. Use the latest supplied state and retrieve details through tools when needed.";
|
|
164
173
|
/** The hidden message a context update is saved as in native history, and where its snapshot sits. */
|
|
165
174
|
export declare const CONTEXT_MESSAGE_TYPE = "xingular-context";
|
|
166
175
|
export declare const CONTEXT_SNAPSHOT_KEY = "xingularContext";
|