myagentmemory 0.4.16 → 0.4.17

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/LICENSE CHANGED
@@ -1,6 +1,7 @@
1
1
  MIT License
2
2
 
3
3
  Copyright (c) 2026 Jay Zeng
4
+ Copyright (c) 2026 jo-inc
4
5
 
5
6
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
7
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -28,9 +28,18 @@ Coding-agent sessions preserve activity. They do not decide which facts, decisio
28
28
 
29
29
  AgentMemory is free, open-source software under the MIT License. The core is a local Markdown store with a CLI, optional qmd search, and agent skills, and it remains fully usable without an account or commercial plugin. It does not automatically import every vendor transcript or silently decide what becomes durable. It is not a Python SDK, vector database, or knowledge graph. The Markdown files remain the source of truth.
30
30
 
31
- ### Optional official plugins
31
+ ### AgentMemory Pro preview
32
32
 
33
- The MIT-licensed core can discover and host separately distributed, signed first-party plugins while remaining fully useful on its own. Optional plugins may use their own license and distribution terms; their implementation and browser assets are not part of the `myagentmemory` package. `agent-memory plugin list` and `plugin status` report local state. In an interactive terminal, `agent-memory plugin install` opens a nonce-bound loopback page for an email address, resumes the waiting command, verifies signed release metadata and the downloaded bundle, and installs atomically. The free plan uses a configurable daily agent-session allowance keyed by normalized email. D1 stores bounded activation metadata, a credential hash, and opaque SessionStart usage operations; it never receives memory, session content, queries, repository paths, raw agent session identifiers, IP addresses, or user-agent strings. Authentication and payment can extend this free activation flow later. See the [official plugin bootstrap and host contract](docs/official-plugin-bootstrap.md).
33
+ **Core remembers what you save. Pro learns from what you do.** Core remains free, MIT-licensed, and useful forever. Pro is a separately distributed commercial bundle that recalls prior coding sessions, finds repeated corrections, and shows what it learned and why in a private local Memory Dashboard.
34
+
35
+ ```bash
36
+ agent-memory pro install
37
+ agent-memory recall "what did we decide about authentication?"
38
+ agent-memory learn
39
+ agent-memory dashboard
40
+ ```
41
+
42
+ The preview requires no account, email, or payment method. It includes 10 useful recalls and one learning scan per local day; local indexing and the Memory Dashboard remain available. Coding history, memories, queries, repository paths, and raw session identifiers stay on the device. Installation sends only a random installation identifier plus bounded compatibility metadata to obtain the signed release. Paying will remove limits; it will not unlock access to the user's own local data. Low-level `agent-memory plugin` commands remain available for administration and scripting. See [how local privacy, signing, installation, and capability enforcement work](docs/official-plugin-bootstrap.md).
34
43
 
35
44
  ## Installation
36
45
 
@@ -149,6 +158,10 @@ The memory directory defaults to `~/.agent-memory/`. Override with `AGENT_MEMORY
149
158
  | `agent-memory uninstall-hooks [--only <agents>]` | Remove only hooks managed by AgentMemory |
150
159
  | `agent-memory init` | Create dirs, detect qmd, setup collection |
151
160
  | `agent-memory status` | Show config, qmd status, file counts |
161
+ | `agent-memory pro <install\|status\|upgrade\|manage>` | Install and manage the no-account AgentMemory Pro preview |
162
+ | `agent-memory recall <query>` | Recall decisions and context from prior coding sessions with Pro |
163
+ | `agent-memory learn` | Find repeated corrections worth remembering with Pro |
164
+ | `agent-memory dashboard` | Open the private local Memory Dashboard |
152
165
  | `agent-memory plugin <list\|status\|install\|update\|uninstall\|manage>` | Discover and manage optional signed first-party plugins |
153
166
 
154
167
  Global flags: `--dir <path>` (override directory), `--json` (machine output)
@@ -284,7 +297,7 @@ agent-memory install-skills
284
297
 
285
298
  ## Publishing (maintainers)
286
299
 
287
- Publication is tag-driven through `.github/workflows/publish-npm.yml`. Configure `jayzeng/agentmemory` and `publish-npm.yml` as the npm trusted publisher for `myagentmemory`, merge a versioned changelog/package update, and push the matching `v<version>` tag. The workflow uses short-lived OIDC credentials, runs the complete release gate, and publishes the public package with provenance. Do not publish this package from the private plugin workspace.
300
+ Publication is tag-driven through `.github/workflows/publish-npm.yml`. Configure the repository's `NPM_TOKEN` secret with publish access to `myagentmemory`, merge a versioned changelog/package update, and push the matching `v<version>` tag. The workflow runs the complete release gate and publishes the public package. Do not publish this package from the private plugin workspace.
288
301
 
289
302
  ### Repository assets (maintainers)
290
303
 
@@ -294,7 +307,7 @@ Publication is tag-driven through `.github/workflows/publish-npm.yml`. Configure
294
307
 
295
308
  ## Acknowledgments
296
309
 
297
- Inspired by [skyfallsin/pi-mem](https://github.com/skyfallsin/pi-mem). Semantic search is powered by [qmd](https://github.com/tobi/qmd).
310
+ AgentMemory contains portions adapted from [pi-mem](https://github.com/jo-inc/pi-mem), used under its MIT License; the upstream copyright notice is preserved in [LICENSE](LICENSE). Semantic search is powered by [qmd](https://github.com/tobi/qmd).
298
311
 
299
312
  ## Changelog
300
313
 
@@ -6,7 +6,7 @@ export interface CliOptionSpec {
6
6
  kind: CliValueKind;
7
7
  };
8
8
  }
9
- export declare const COMMANDS: readonly ["context", "write", "read", "scratchpad", "search", "distil", "sync", "init", "status", "install-skills", "uninstall-skills", "install-hooks", "uninstall-hooks", "completion", "plugin", "version", "help"];
9
+ export declare const COMMANDS: readonly ["context", "write", "read", "scratchpad", "search", "distil", "sync", "init", "status", "install-skills", "uninstall-skills", "install-hooks", "uninstall-hooks", "completion", "pro", "recall", "learn", "dashboard", "plugin", "version", "help"];
10
10
  export declare const PLUGIN_COMMANDS: readonly ["list", "status", "install", "update", "uninstall", "manage"];
11
11
  export declare const WORKER_ACTIONS: readonly [];
12
12
  export declare const SCRATCHPAD_ACTIONS: readonly ["add", "done", "undo", "clear_done", "list"];
package/dist/cli-spec.js CHANGED
@@ -13,6 +13,10 @@ export const COMMANDS = [
13
13
  "install-hooks",
14
14
  "uninstall-hooks",
15
15
  "completion",
16
+ "pro",
17
+ "recall",
18
+ "learn",
19
+ "dashboard",
16
20
  "plugin",
17
21
  "version",
18
22
  "help",
@@ -35,9 +39,13 @@ export const COMMAND_DESCRIPTIONS = {
35
39
  "install-hooks": "install automatic SessionStart indexing and context hooks",
36
40
  "uninstall-hooks": "remove only SessionStart hooks managed by agent-memory",
37
41
  completion: "install or print Bash, Zsh, Fish, or PowerShell completion",
38
- plugin: "index, recall, learn from, and evaluate prior agent sessions",
42
+ pro: "install, inspect, or upgrade AgentMemory Pro",
43
+ recall: "recall decisions and context from prior coding sessions with Pro",
44
+ learn: "find repeated corrections worth remembering with Pro",
45
+ dashboard: "open the private local Memory Dashboard",
46
+ plugin: "discover, install, update, or remove optional official plugins",
39
47
  version: "print the installed agent-memory version",
40
- help: "show top-level, command, or nested plugin help",
48
+ help: "show this command overview",
41
49
  };
42
50
  export const PLUGIN_COMMAND_DESCRIPTIONS = {
43
51
  list: "list optional official plugins and local availability",
@@ -71,6 +79,10 @@ export const COMMAND_OPTIONS = {
71
79
  "install-hooks": ["--yes", "--all", "--only"],
72
80
  "uninstall-hooks": ["--only"],
73
81
  completion: ["--stdout"],
82
+ pro: [],
83
+ recall: ["--scope", "--cwd", "--limit", "--context"],
84
+ learn: [],
85
+ dashboard: ["--no-browser"],
74
86
  version: [],
75
87
  help: [],
76
88
  };
package/dist/cli.js CHANGED
@@ -23,6 +23,7 @@
23
23
  */
24
24
  import { spawn } from "node:child_process";
25
25
  import * as fs from "node:fs";
26
+ import { COMMAND_DESCRIPTIONS, COMMANDS } from "./cli-spec.js";
26
27
  import { detectCompletionShell, generateCompletion, installCompletion } from "./completions.js";
27
28
  import { _setBaseDir, buildMemoryContext, checkCollection, dailyPath, detectQmd, distilMemories, ensureDirs, ensureQmdAvailableForSync, ensureQmdAvailableForUpdate, getCollectionName, getDailyDir, getMemoryDir, getMemoryFile, getQmdEmbedMode, getQmdHealth, getQmdResultPath, getQmdResultText, getScratchpadFile, getTopicsDir, installSkills, memoryWrite, nowTimestamp, parseScratchpad, probeEmbeddings, readFileSafe, redactSecrets, runQmdEmbedDetached, runQmdSearch, runQmdSync, runQmdUpdateNow, scheduleQmdUpdate, searchRelevantMemories, serializeScratchpad, setupQmdCollection, slugifyTopic, todayStr, topicPath, uninstallSkills, } from "./core.js";
28
29
  import { detectHookAgents, installHooks, uninstallHooks } from "./hooks.js";
@@ -120,22 +121,24 @@ function openExternalUrl(url) {
120
121
  }
121
122
  function printProOverview(installed) {
122
123
  console.log("");
123
- console.log("AgentMemory Pro includes:");
124
- console.log(" Session Intelligence Recall decisions and context across Pi, Codex, and Claude Code sessions.");
125
- console.log(" Guided Learning Turn repeated corrections into reviewable, reversible memory.");
126
- console.log(" Local Web Console Inspect memories, activity, health, and settings in your browser.");
124
+ console.log("Core remembers what you save. Pro learns from what you do.");
127
125
  console.log("");
128
- console.log("Your session content stays on this device.");
126
+ console.log("AgentMemory Pro:");
127
+ console.log(" Recall coding history Find decisions and context across Pi, Codex, and Claude Code sessions.");
128
+ console.log(" Learn from corrections Turn repeated fixes into reviewable, reversible memory.");
129
+ console.log(" See and control learning Inspect what AgentMemory remembers and why in the Memory Dashboard.");
130
+ console.log("");
131
+ console.log("No account is required for the free preview. Your coding history stays on this device.");
129
132
  console.log("");
130
133
  if (installed) {
131
134
  console.log("Try it:");
132
135
  console.log(' agent-memory recall "what did we decide about authentication?"');
133
136
  console.log(" agent-memory learn");
134
- console.log(" agent-memory web");
137
+ console.log(" agent-memory dashboard");
135
138
  }
136
139
  else {
137
- console.log("Start your Pro beta:");
138
- console.log(" agent-memory plugin install");
140
+ console.log("Start your free Pro preview:");
141
+ console.log(" agent-memory pro install");
139
142
  }
140
143
  }
141
144
  function printPluginResult(result, json, allowBrowser) {
@@ -175,10 +178,10 @@ function printPluginResult(result, json, allowBrowser) {
175
178
  break;
176
179
  case "not_installed":
177
180
  console.log("AgentMemory Pro is not installed.");
178
- console.log("Run: agent-memory plugin install");
181
+ console.log("Run: agent-memory pro install");
179
182
  break;
180
183
  case "auth_required":
181
- console.log("Run this command in an interactive terminal to enter an email and activate free daily access.");
184
+ console.log("Run agent-memory pro install to activate the free preview.");
182
185
  break;
183
186
  case "renewal_required":
184
187
  console.log("Renew AgentMemory Pro to continue using paid capabilities.");
@@ -214,9 +217,23 @@ async function cmdContext(flags) {
214
217
  if (!noSearch && query)
215
218
  await ensureQmdAvailableForSync();
216
219
  const searchResults = noSearch ? "" : await searchRelevantMemories(query);
217
- const context = buildMemoryContext(searchResults);
220
+ const coreContext = buildMemoryContext(searchResults);
221
+ let pluginSections = [];
222
+ try {
223
+ pluginSections = await new InstalledPluginRuntimeV1({ coreVersion: VERSION }).provideContext({
224
+ host: "agent-memory-cli",
225
+ cwd: process.cwd(),
226
+ query: query || undefined,
227
+ signal: new AbortController().signal,
228
+ });
229
+ }
230
+ catch {
231
+ // Optional Pro context must never make public-core context unavailable.
232
+ }
233
+ const pluginContext = pluginSections.map((section) => `${section.label}\n\n${section.content}`).join("\n\n");
234
+ const context = [coreContext, pluginContext].filter(Boolean).join("\n\n");
218
235
  if (json) {
219
- output({ context, directory: getMemoryDir() }, true);
236
+ output({ context, directory: getMemoryDir(), ...(pluginSections.length ? { pluginSections } : {}) }, true);
220
237
  }
221
238
  else {
222
239
  if (context) {
@@ -709,8 +726,8 @@ async function cmdInit(flags) {
709
726
  const plugin = await createDefaultPluginBootstrap(VERSION).list();
710
727
  if (plugin.result === "not_installed") {
711
728
  console.log("");
712
- console.log("Optional: AgentMemory Pro adds session recall and a local Web Console.");
713
- console.log("Run: agent-memory plugin install");
729
+ console.log("Optional: Pro recalls coding history and learns from repeated corrections.");
730
+ console.log("Try it without an account: agent-memory pro install");
714
731
  }
715
732
  }
716
733
  catch {
@@ -853,8 +870,8 @@ async function cmdStatus(flags) {
853
870
  }
854
871
  if (!officialPlugin.installed) {
855
872
  console.log("");
856
- console.log("Optional official plugins: not installed");
857
- console.log(" run: agent-memory plugin install");
873
+ console.log("AgentMemory Pro: not installed");
874
+ console.log(" try without an account: agent-memory pro install");
858
875
  }
859
876
  }
860
877
  }
@@ -892,9 +909,10 @@ Usage:
892
909
  agent-memory plugin uninstall --yes
893
910
  agent-memory plugin manage [--no-browser]
894
911
 
895
- The public core remains fully usable without AgentMemory Pro. Interactive install
896
- opens a loopback website for email activation and a configurable free daily
897
- agent-session allowance. Memory and session content stay on this device.`);
912
+ The public core remains fully usable without AgentMemory Pro. Install uses a random
913
+ installation identifier and requires no account or email. The free preview includes
914
+ 10 recalls and one learning scan per local day; indexing and the Memory Dashboard
915
+ remain available. Memory and session content stay on this device.`);
898
916
  }
899
917
  function pluginCommandFailure(command, error) {
900
918
  return {
@@ -922,12 +940,13 @@ async function cmdPlugin(flags, positional) {
922
940
  const subcommand = positional[0] ?? "list";
923
941
  if (subcommand === "help" || hasFlag(flags, "help")) {
924
942
  printPluginUsage();
925
- return;
943
+ return null;
926
944
  }
927
945
  const channel = getFlag(flags, "channel") ?? "stable";
928
946
  if (channel !== "stable") {
929
- printPluginResult(pluginCommandFailure(subcommand, new PluginBootstrapFailure("channel_invalid", "--channel supports only 'stable'")), json, false);
930
- return;
947
+ const failure = pluginCommandFailure(subcommand, new PluginBootstrapFailure("channel_invalid", "--channel supports only 'stable'"));
948
+ printPluginResult(failure, json, false);
949
+ return failure;
931
950
  }
932
951
  const allowBrowser = !json && !hasFlag(flags, "no-browser") && Boolean(process.stdin.isTTY && process.stdout.isTTY);
933
952
  const manager = createDefaultPluginBootstrap(VERSION);
@@ -974,33 +993,73 @@ async function cmdPlugin(flags, positional) {
974
993
  result = pluginCommandFailure(subcommand, error);
975
994
  }
976
995
  printPluginResult(result, json, allowBrowser && (subcommand === "install" || subcommand === "manage"));
996
+ return result;
997
+ }
998
+ async function printFirstRunProof() {
999
+ try {
1000
+ const result = await new InstalledPluginRuntimeV1({ coreVersion: VERSION }).run("index", {
1001
+ args: [],
1002
+ flags: {},
1003
+ signal: new AbortController().signal,
1004
+ });
1005
+ if (!result?.ok || !result.data || typeof result.data !== "object")
1006
+ return;
1007
+ const stats = result.data.stats;
1008
+ if (!stats?.discovered)
1009
+ return;
1010
+ const hosts = [
1011
+ ["Claude Code", stats.discovered.claude ?? 0],
1012
+ ["Codex", stats.discovered.codex ?? 0],
1013
+ ["Pi", stats.discovered.pi ?? 0],
1014
+ ];
1015
+ console.log("");
1016
+ console.log("Found local coding history:");
1017
+ for (const [label, count] of hosts)
1018
+ console.log(` ${label.padEnd(13)} ${count} sessions`);
1019
+ console.log("");
1020
+ console.log(`${stats.selected ?? 0} sessions available for local recall. Nothing was uploaded.`);
1021
+ console.log("");
1022
+ console.log('Try: agent-memory recall "what did we decide about authentication?"');
1023
+ console.log("Open: agent-memory dashboard");
1024
+ }
1025
+ catch {
1026
+ // Personalized proof is helpful but must never turn a successful install into a failure.
1027
+ }
1028
+ }
1029
+ async function cmdPro(flags, positional) {
1030
+ const subcommand = positional[0];
1031
+ if (!subcommand) {
1032
+ await cmdPlugin(flags, ["list"]);
1033
+ return;
1034
+ }
1035
+ const mapped = subcommand === "upgrade" ? "update" : subcommand;
1036
+ if (!["install", "status", "update", "manage"].includes(mapped)) {
1037
+ const json = hasFlag(flags, "json");
1038
+ const message = `Unknown Pro command: ${subcommand}. Available commands: install, status, upgrade, manage.`;
1039
+ if (json)
1040
+ console.log(JSON.stringify({ error: message }));
1041
+ else
1042
+ console.error(`Error: ${message}`);
1043
+ process.exitCode = 1;
1044
+ return;
1045
+ }
1046
+ const result = await cmdPlugin(flags, [mapped]);
1047
+ if (!hasFlag(flags, "json") && mapped === "install" && ["installed", "upgraded"].includes(result?.result ?? ""))
1048
+ await printFirstRunProof();
977
1049
  }
978
1050
  // ---------------------------------------------------------------------------
979
1051
  // Usage
980
1052
  // ---------------------------------------------------------------------------
981
1053
  function printUsage() {
1054
+ const commandWidth = Math.max(...COMMANDS.map((command) => command.length));
1055
+ const commandList = COMMANDS.map((command) => ` ${command.padEnd(commandWidth)} ${COMMAND_DESCRIPTIONS[command]}`).join("\n");
982
1056
  console.log(`agent-memory — persistent memory for coding agents
983
1057
 
984
1058
  Usage:
985
1059
  agent-memory <command> [options]
986
1060
 
987
1061
  Commands:
988
- version Show binary version
989
- install-skills Install (or --uninstall) bundled skills
990
- uninstall-skills Uninstall bundled skills
991
- context Build context; optionally retrieve memories with --query
992
- write Write to memory files (default: daily; optional --source-uri)
993
- read Read memory files
994
- scratchpad Manage checklist items
995
- search Search across memory files (requires qmd)
996
- distil Generate compact MEMORY.md index from daily logs + topics
997
- sync Re-index and embed all files (requires qmd)
998
- init Initialize memory directory and qmd collection
999
- status Show configuration and status (--probe for a live embeddings check)
1000
- completion Install or print shell completion
1001
- install-hooks Install managed SessionStart hooks
1002
- uninstall-hooks Remove only managed SessionStart hooks
1003
- plugin Discover, install, update, or remove optional official plugins
1062
+ ${commandList}
1004
1063
 
1005
1064
  Global flags:
1006
1065
  --dir <path> Override memory directory
@@ -1026,8 +1085,10 @@ Examples:
1026
1085
  agent-memory status --json
1027
1086
  agent-memory completion zsh
1028
1087
  agent-memory install-hooks --yes
1029
- agent-memory plugin status
1030
- agent-memory plugin install`);
1088
+ agent-memory pro status
1089
+ agent-memory pro install
1090
+ agent-memory recall "what did we decide about authentication?"
1091
+ agent-memory dashboard`);
1031
1092
  }
1032
1093
  // ---------------------------------------------------------------------------
1033
1094
  // Main
@@ -1116,12 +1177,16 @@ async function main() {
1116
1177
  case "plugin":
1117
1178
  await cmdPlugin(flags, positional);
1118
1179
  break;
1180
+ case "pro":
1181
+ await cmdPro(flags, positional);
1182
+ break;
1119
1183
  default: {
1120
1184
  const controller = new AbortController();
1121
1185
  const abort = () => controller.abort();
1122
1186
  process.once("SIGINT", abort);
1123
1187
  try {
1124
- const result = await new InstalledPluginRuntimeV1({ coreVersion: VERSION }).run(command, {
1188
+ const pluginCommand = command === "dashboard" ? "web" : command;
1189
+ const result = await new InstalledPluginRuntimeV1({ coreVersion: VERSION }).run(pluginCommand, {
1125
1190
  args: positional,
1126
1191
  flags,
1127
1192
  signal: controller.signal,
@@ -1129,7 +1194,7 @@ async function main() {
1129
1194
  if (!result)
1130
1195
  exitError(`Unknown command: ${command}. Run 'agent-memory help' for usage.`, json);
1131
1196
  if (!result.ok)
1132
- exitError(result.error?.message ?? `Plugin command ${command} failed`, json);
1197
+ exitError(result.error?.message ?? `Plugin command ${pluginCommand} failed`, json);
1133
1198
  output(result.data ?? { ok: true }, json);
1134
1199
  }
1135
1200
  finally {
@@ -14,8 +14,8 @@ const MISSING_ENTITLEMENT = {
14
14
  reason: "No signed AgentMemory commercial entitlement is installed",
15
15
  };
16
16
  const OFFICIAL_PLUGINS = [
17
- { id: OFFICIAL_PLUGIN_IDS[0], name: "Session Intelligence" },
18
- { id: OFFICIAL_PLUGIN_IDS[1], name: "Web Console" },
17
+ { id: OFFICIAL_PLUGIN_IDS[0], name: "Coding History Recall" },
18
+ { id: OFFICIAL_PLUGIN_IDS[1], name: "Memory Dashboard" },
19
19
  ];
20
20
  const PACKAGE_MAX_BYTES = 64 * 1024 * 1024;
21
21
  const PACKAGE_MAX_EXPANDED_BYTES = 128 * 1024 * 1024;
@@ -103,11 +103,29 @@ export interface PluginStructuredErrorV1 {
103
103
  message: string;
104
104
  retryable?: boolean;
105
105
  }
106
+ export interface PluginContextSectionV1 {
107
+ id: string;
108
+ label: string;
109
+ content: string;
110
+ artifactPath?: string;
111
+ metadata?: Record<string, unknown>;
112
+ }
113
+ export interface PluginContextProviderV1 {
114
+ name: string;
115
+ requiredCapability: string;
116
+ provide(context: {
117
+ host: string;
118
+ cwd?: string;
119
+ query?: string;
120
+ signal: AbortSignal;
121
+ }): Promise<PluginContextSectionV1[]>;
122
+ }
106
123
  export interface AgentMemoryPluginHostV1 {
107
124
  apiVersion: 1;
108
125
  coreVersion: string;
109
126
  registerCommand(command: PluginCommandV1): void;
110
127
  registerSessionStartHook(hook: PluginSessionStartHookV1): void;
128
+ registerContextProvider?(provider: PluginContextProviderV1): void;
111
129
  getStateDirectory(): string;
112
130
  getMemoryDirectory(): string;
113
131
  getEntitlement(): Promise<PluginEntitlementStatusV1>;
@@ -1,5 +1,5 @@
1
1
  import { type PluginBootstrapBackendV1, type PluginInstallStoreV1, type PluginSessionUsageDecisionV1, type SignedPluginReleaseV1 } from "./plugin-bootstrap.js";
2
- import { type PluginCommandContextV1, type PluginCommandResultV1, type PluginSessionStartHookV1 } from "./plugin-host.js";
2
+ import { type PluginCommandContextV1, type PluginCommandResultV1, type PluginContextSectionV1, type PluginSessionStartHookV1 } from "./plugin-host.js";
3
3
  export interface PluginRuntimeOptionsV1 {
4
4
  coreVersion: string;
5
5
  store?: PluginInstallStoreV1;
@@ -11,11 +11,18 @@ export declare class InstalledPluginRuntimeV1 {
11
11
  private readonly backend;
12
12
  private readonly commands;
13
13
  private readonly hooks;
14
+ private readonly contextProviders;
14
15
  private loaded;
15
16
  constructor(options: PluginRuntimeOptionsV1);
16
17
  load(): Promise<boolean>;
17
18
  run(name: string, context: PluginCommandContextV1): Promise<PluginCommandResultV1 | null>;
18
19
  runSessionStart(context: Parameters<PluginSessionStartHookV1["run"]>[0]): Promise<PluginSessionUsageDecisionV1 | null>;
20
+ provideContext(context: {
21
+ host: string;
22
+ cwd?: string;
23
+ query?: string;
24
+ signal: AbortSignal;
25
+ }): Promise<PluginContextSectionV1[]>;
19
26
  private createHost;
20
27
  private refreshEntitlement;
21
28
  }
@@ -61,6 +61,7 @@ export class InstalledPluginRuntimeV1 {
61
61
  backend;
62
62
  commands = new Map();
63
63
  hooks = [];
64
+ contextProviders = [];
64
65
  loaded = false;
65
66
  constructor(options) {
66
67
  this.options = options;
@@ -132,6 +133,37 @@ export class InstalledPluginRuntimeV1 {
132
133
  throw error;
133
134
  }
134
135
  }
136
+ async provideContext(context) {
137
+ if (!(await this.load()) || this.contextProviders.length === 0)
138
+ return [];
139
+ const entitlement = await this.refreshEntitlement();
140
+ const sections = [];
141
+ for (const registered of this.contextProviders) {
142
+ if (!isPluginCapabilityEnabled(entitlement, registered.provider.requiredCapability))
143
+ continue;
144
+ const provided = await registered.provider.provide(context);
145
+ if (!Array.isArray(provided) || provided.length > 16)
146
+ throw new PluginBootstrapFailure("plugin_context_invalid", `Plugin ${registered.pluginId} returned invalid context sections`);
147
+ for (const section of provided) {
148
+ if (!section ||
149
+ typeof section.id !== "string" ||
150
+ section.id.length === 0 ||
151
+ section.id.length > 256 ||
152
+ typeof section.label !== "string" ||
153
+ section.label.length === 0 ||
154
+ section.label.length > 256 ||
155
+ typeof section.content !== "string" ||
156
+ Buffer.byteLength(section.content, "utf-8") > 64 * 1024 ||
157
+ (section.artifactPath !== undefined &&
158
+ (typeof section.artifactPath !== "string" || section.artifactPath.length > 4_096)) ||
159
+ (section.metadata !== undefined &&
160
+ (!section.metadata || typeof section.metadata !== "object" || Array.isArray(section.metadata))))
161
+ throw new PluginBootstrapFailure("plugin_context_invalid", `Plugin ${registered.pluginId} returned an invalid context section`);
162
+ sections.push(structuredClone(section));
163
+ }
164
+ }
165
+ return sections;
166
+ }
135
167
  createHost(manifest) {
136
168
  const descriptors = new Map(manifest.commands.map((command) => [command.name, command]));
137
169
  const stateRoot = path.join(this.store.root, "state");
@@ -165,6 +197,13 @@ export class InstalledPluginRuntimeV1 {
165
197
  throw new PluginBootstrapFailure("plugin_hook_invalid", `Plugin ${manifest.id} registered a hook with an undeclared capability`);
166
198
  this.hooks.push(hook);
167
199
  },
200
+ registerContextProvider: (provider) => {
201
+ if (!(manifest.capabilities ?? []).includes(provider.requiredCapability))
202
+ throw new PluginBootstrapFailure("plugin_context_invalid", `Plugin ${manifest.id} registered a context provider with an undeclared capability`);
203
+ if (!provider.name || this.contextProviders.some((item) => item.provider.name === provider.name))
204
+ throw new PluginBootstrapFailure("plugin_context_invalid", `Plugin context provider ${provider.name || "(unnamed)"} is invalid or already registered`);
205
+ this.contextProviders.push({ provider, pluginId: manifest.id });
206
+ },
168
207
  getStateDirectory: () => stateDirectory,
169
208
  getMemoryDirectory: () => {
170
209
  assertPermission(manifest, "memory:read");