@oharness/engine 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/README.md +26 -0
  2. package/dist/agent/agent.d.ts +11 -0
  3. package/dist/agent/agent.js +30 -9
  4. package/dist/agent/agent.js.map +1 -1
  5. package/dist/agent/hooks.d.ts +2 -0
  6. package/dist/agent/hooks.js +11 -0
  7. package/dist/agent/hooks.js.map +1 -1
  8. package/dist/agent/memory.d.ts +10 -1
  9. package/dist/agent/memory.js +147 -49
  10. package/dist/agent/memory.js.map +1 -1
  11. package/dist/agent/permissions.js +21 -3
  12. package/dist/agent/permissions.js.map +1 -1
  13. package/dist/artifacts/publish.d.ts +2 -2
  14. package/dist/artifacts/publish.js +2 -2
  15. package/dist/auth/index.d.ts +1 -1
  16. package/dist/auth/index.js +1 -1
  17. package/dist/auth/index.js.map +1 -1
  18. package/dist/auth/manager.d.ts +14 -0
  19. package/dist/auth/manager.js +25 -5
  20. package/dist/auth/manager.js.map +1 -1
  21. package/dist/auth/providers/account.d.ts +10 -45
  22. package/dist/auth/providers/account.js +123 -233
  23. package/dist/auth/providers/account.js.map +1 -1
  24. package/dist/config-files.d.ts +27 -0
  25. package/dist/config-files.js +116 -0
  26. package/dist/config-files.js.map +1 -0
  27. package/dist/config.d.ts +5 -25
  28. package/dist/config.js +16 -2
  29. package/dist/config.js.map +1 -1
  30. package/dist/core/audit.d.ts +20 -0
  31. package/dist/core/audit.js +2 -0
  32. package/dist/core/audit.js.map +1 -0
  33. package/dist/harness.d.ts +35 -2
  34. package/dist/harness.js +162 -50
  35. package/dist/harness.js.map +1 -1
  36. package/dist/index.d.ts +1 -0
  37. package/dist/index.js +1 -0
  38. package/dist/index.js.map +1 -1
  39. package/dist/providers/registry.d.ts +42 -0
  40. package/dist/providers/registry.js +71 -9
  41. package/dist/providers/registry.js.map +1 -1
  42. package/dist/runtime-plugins/audit.d.ts +11 -0
  43. package/dist/runtime-plugins/audit.js +31 -0
  44. package/dist/runtime-plugins/audit.js.map +1 -0
  45. package/dist/runtime-plugins/builtin/jsonl-audit.d.ts +7 -0
  46. package/dist/runtime-plugins/builtin/jsonl-audit.js +24 -0
  47. package/dist/runtime-plugins/builtin/jsonl-audit.js.map +1 -0
  48. package/dist/runtime-plugins/builtin/memory.d.ts +70 -0
  49. package/dist/runtime-plugins/builtin/memory.js +360 -0
  50. package/dist/runtime-plugins/builtin/memory.js.map +1 -0
  51. package/dist/runtime-plugins/cloud-connector.d.ts +56 -0
  52. package/dist/runtime-plugins/cloud-connector.js +261 -0
  53. package/dist/runtime-plugins/cloud-connector.js.map +1 -0
  54. package/dist/runtime-plugins/composio/client.d.ts +65 -0
  55. package/dist/runtime-plugins/composio/client.js +190 -0
  56. package/dist/runtime-plugins/composio/client.js.map +1 -0
  57. package/dist/runtime-plugins/composio/index.d.ts +23 -0
  58. package/dist/runtime-plugins/composio/index.js +113 -0
  59. package/dist/runtime-plugins/composio/index.js.map +1 -0
  60. package/dist/runtime-plugins/connector.d.ts +15 -0
  61. package/dist/runtime-plugins/connector.js +17 -0
  62. package/dist/runtime-plugins/connector.js.map +1 -0
  63. package/dist/runtime-plugins/extensions.d.ts +21 -0
  64. package/dist/runtime-plugins/extensions.js +23 -0
  65. package/dist/runtime-plugins/extensions.js.map +1 -0
  66. package/dist/runtime-plugins/host.d.ts +34 -0
  67. package/dist/runtime-plugins/host.js +263 -0
  68. package/dist/runtime-plugins/host.js.map +1 -0
  69. package/dist/runtime-plugins/index.d.ts +12 -0
  70. package/dist/runtime-plugins/index.js +7 -0
  71. package/dist/runtime-plugins/index.js.map +1 -0
  72. package/dist/runtime-plugins/loader.d.ts +5 -0
  73. package/dist/runtime-plugins/loader.js +36 -0
  74. package/dist/runtime-plugins/loader.js.map +1 -0
  75. package/dist/runtime-plugins/tool-adapter.d.ts +3 -0
  76. package/dist/runtime-plugins/tool-adapter.js +13 -0
  77. package/dist/runtime-plugins/tool-adapter.js.map +1 -0
  78. package/dist/runtime-plugins/types.d.ts +81 -0
  79. package/dist/runtime-plugins/types.js +2 -0
  80. package/dist/runtime-plugins/types.js.map +1 -0
  81. package/dist/sync/settings.d.ts +2 -0
  82. package/dist/sync/settings.js +17 -1
  83. package/dist/sync/settings.js.map +1 -1
  84. package/dist/tools/registry.d.ts +2 -0
  85. package/dist/tools/registry.js +10 -0
  86. package/dist/tools/registry.js.map +1 -1
  87. package/dist/tools/types.d.ts +2 -0
  88. package/dist/tools/types.js.map +1 -1
  89. package/official.json +1 -2
  90. package/package.json +1 -1
package/dist/config.d.ts CHANGED
@@ -9,6 +9,7 @@ import type { ScheduleDefinition } from "./schedule/scheduler.ts";
9
9
  import type { ToolFilter } from "./tools/registry.ts";
10
10
  import type { LogLevel } from "./util/logger.ts";
11
11
  import type { PluginConfig } from "./plugins.ts";
12
+ import type { RuntimePluginConfig } from "./runtime-plugins/types.ts";
12
13
  export interface HarnessConfig {
13
14
  /** Default model alias, e.g. "sonnet" or "openai/gpt-4.1". */
14
15
  model?: string;
@@ -59,6 +60,8 @@ export interface HarnessConfig {
59
60
  memoryDir?: string;
60
61
  /** Declarative plugin bundles to discover and activate. */
61
62
  plugins?: PluginConfig;
63
+ /** Trusted runtime code: plugins.json or embedding API; legacy user config is read-only compatible. */
64
+ runtimePlugins?: RuntimePluginConfig[];
62
65
  /** Extra or overriding model specs, merged over the built-in catalog. */
63
66
  models?: ModelSpec[];
64
67
  /** Per-provider credentials and endpoints; env vars still apply as fallback. */
@@ -98,34 +101,11 @@ export interface HarnessConfig {
98
101
  };
99
102
  /** Where transcripts are mirrored so a second device can continue them. */
100
103
  sync?: SyncConfig;
101
- /**
102
- * The account system `auth login official` signs in to.
103
- *
104
- * User config only — see `projectSafe`. This is the setting a fork or a
105
- * self-hosted deployment uses to point the harness at its own Supabase
106
- * project without rebuilding anything, and it beats the ids a published
107
- * build was packaged with.
108
- */
104
+ /** @deprecated Read-only migration compatibility. Use cloud.json for the public site URL. */
109
105
  account?: AccountConfig;
110
106
  }
111
107
  export interface AccountConfig {
112
- /**
113
- * The Supabase project accounts live in, e.g.
114
- * `https://<project>.supabase.co`. Set this and `supabaseAnonKey` together;
115
- * one without the other is treated as neither.
116
- */
117
- supabaseUrl?: string;
118
- /**
119
- * The project's anon key. A publishable client credential — it grants
120
- * nothing beyond what an anonymous visitor has, and row level security is
121
- * what protects the data — so it is no more sensitive here than in the
122
- * browser bundle of the site it belongs to.
123
- */
124
- supabaseAnonKey?: string;
125
- /**
126
- * The website that owns those accounts, for the browser sign-in handoff.
127
- * Defaults to the official one.
128
- */
108
+ /** @deprecated Use cloud.json; Supabase fields in legacy files are no longer consumed. */
129
109
  siteUrl?: string;
130
110
  }
131
111
  export interface SyncConfig {
package/dist/config.js CHANGED
@@ -3,6 +3,7 @@ import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
3
3
  import path from "node:path";
4
4
  import { ConfigError } from "./core/errors.js";
5
5
  import { parseJson } from "./util/json.js";
6
+ import { readMcpFile, readPluginFile } from "./config-files.js";
6
7
  export const CONFIG_FILENAMES = ["oharness.config.json", ".oharness.json"];
7
8
  const DEFAULT_INSTRUCTIONS = ["AGENTS.md", "CLAUDE.md", ".oharness/instructions.md"];
8
9
  /**
@@ -14,8 +15,18 @@ const DEFAULT_INSTRUCTIONS = ["AGENTS.md", "CLAUDE.md", ".oharness/instructions.
14
15
  */
15
16
  export async function loadConfig(cwd = process.cwd()) {
16
17
  const user = await readConfigFile(userPath("config.json"));
18
+ // Account deployment data is read separately by the Cloud client, not exposed
19
+ // to the Harness or plugins through general configuration.
20
+ const { account: _legacyAccount, ...preferences } = user ?? {};
21
+ const plugins = readPluginFile();
22
+ const mcp = readMcpFile();
23
+ const effective = {
24
+ ...preferences,
25
+ ...(plugins ? { runtimePlugins: plugins.runtimePlugins ?? [], plugins: plugins.plugins ?? {} } : {}),
26
+ ...(mcp ? { mcpServers: mcp.mcpServers ?? {} } : {}),
27
+ };
17
28
  const project = await loadProjectConfig(cwd);
18
- return mergeConfig(user ?? {}, projectSafe(project ?? {}));
29
+ return mergeConfig(effective, projectSafe(project ?? {}));
19
30
  }
20
31
  /**
21
32
  * The project's own config file, unmerged.
@@ -36,6 +47,8 @@ export async function loadProjectConfig(cwd = process.cwd()) {
36
47
  }
37
48
  /**
38
49
  * A project config with the parts a repository may not decide removed.
50
+ * Runtime plugin modules/options are user-owned too: a repository may not
51
+ * introduce executable code or redirect the credentials/endpoints it uses.
39
52
  *
40
53
  * Applied here rather than inside `mergeConfig`, because this is the only
41
54
  * place that knows which side is the person and which is the repository —
@@ -55,7 +68,7 @@ export async function loadProjectConfig(cwd = process.cwd()) {
55
68
  * keep.
56
69
  */
57
70
  function projectSafe(project) {
58
- const { account: _account, ...rest } = project;
71
+ const { account: _account, runtimePlugins: _runtimePlugins, ...rest } = project;
59
72
  if (!rest.sync)
60
73
  return rest;
61
74
  const { url: _url, token: _token, team: _team, ...allowed } = rest.sync;
@@ -104,6 +117,7 @@ export function mergeConfig(base, override) {
104
117
  writableRoots: [...(base.writableRoots ?? []), ...(override.writableRoots ?? [])],
105
118
  readableRoots: [...(base.readableRoots ?? []), ...(override.readableRoots ?? [])],
106
119
  plugins: mergePlugins(base.plugins, override.plugins),
120
+ runtimePlugins: override.runtimePlugins ?? base.runtimePlugins,
107
121
  models: [...(base.models ?? []), ...(override.models ?? [])],
108
122
  providers: { ...base.providers, ...override.providers },
109
123
  openAiCompatible: [...(base.openAiCompatible ?? []), ...(override.openAiCompatible ?? [])],
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { AuditEntry } from "../agent/permissions.ts";
2
+ /** Observation only: sinks cannot authorize a call or rewrite its outcome. */
3
+ export type RuntimeAuditEvent = {
4
+ type: "permission";
5
+ timestamp: number;
6
+ sessionId: string;
7
+ entry: AuditEntry;
8
+ } | {
9
+ type: "tool_execution";
10
+ timestamp: number;
11
+ sessionId: string;
12
+ agentId: string;
13
+ toolCallId: string;
14
+ toolName: string;
15
+ pluginId?: string;
16
+ durationMs: number;
17
+ isError: boolean;
18
+ };
19
+ /** Inputs, outputs and credentials are deliberately excluded from execution events. */
20
+ export type AuditSink = (event: RuntimeAuditEvent) => void | Promise<void>;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/core/audit.ts"],"names":[],"mappings":""}
package/dist/harness.d.ts CHANGED
@@ -11,18 +11,23 @@ import { SubagentRegistry } from "./agent/subagent.ts";
11
11
  import { SkillRegistry } from "./agent/skills.ts";
12
12
  import { SettingsStore } from "./agent/settings.ts";
13
13
  import type { WorkspacePolicy } from "./agent/workspace.ts";
14
- import { MemoryStore } from "./agent/memory.ts";
14
+ import type { MemoryStore } from "./agent/memory.ts";
15
+ import { PluginExtensions } from "./runtime-plugins/extensions.ts";
16
+ import { MemoryService } from "./runtime-plugins/builtin/memory.ts";
15
17
  import type { HarnessConfig } from "./config.ts";
16
18
  import type { PluginDefinition } from "./plugins.ts";
17
19
  import { McpManager } from "./mcp/manager.ts";
18
20
  import { Scheduler } from "./schedule/scheduler.ts";
19
21
  import type { McpServerStatus } from "./mcp/manager.ts";
20
22
  import { ProviderRegistry } from "./providers/registry.ts";
23
+ import type { VerifyResult } from "./providers/registry.ts";
21
24
  import type { Catalog, CatalogProvider } from "./providers/catalog.ts";
22
25
  import type { ModelSpec } from "./providers/types.ts";
23
26
  import { ToolRegistry } from "./tools/registry.ts";
24
27
  import type { Tool } from "./tools/types.ts";
25
28
  import type { Logger, LogSink } from "./util/logger.ts";
29
+ import type { RuntimePluginRegistration, RuntimePluginStatus } from "./runtime-plugins/types.ts";
30
+ import { CloudConnectorService } from "./runtime-plugins/cloud-connector.ts";
26
31
  /** Whether decisions are recorded, where else, and whose call that is. */
27
32
  export interface AuditStatus {
28
33
  on: boolean;
@@ -40,6 +45,12 @@ export interface HarnessOptions {
40
45
  tools?: Tool[];
41
46
  /** Extra auth providers, e.g. a subscription vendor with your own client id. */
42
47
  authProviders?: AuthProvider[];
48
+ /** Explicitly trusted in-process plugins; separate from declarative resource bundles. */
49
+ runtimePlugins?: RuntimePluginRegistration[];
50
+ /** Platform connector tools; default on outside ephemeral/test Harness instances. */
51
+ cloudConnectors?: boolean;
52
+ /** Optional broker for embedders/tests; config files cannot inject a service. */
53
+ cloudConnectorService?: CloudConnectorService;
43
54
  logger?: Logger;
44
55
  /**
45
56
  * Where diagnostics go, when the default stderr is the wrong place.
@@ -68,7 +79,9 @@ export declare class Harness {
68
79
  readonly hooks: HookRegistry;
69
80
  readonly subagents: SubagentRegistry;
70
81
  readonly skills: SkillRegistry;
71
- readonly memory: MemoryStore;
82
+ readonly extensions: PluginExtensions;
83
+ memoryService?: MemoryService;
84
+ get memory(): MemoryStore | undefined;
72
85
  readonly settings: SettingsStore;
73
86
  readonly workspace: WorkspacePolicy;
74
87
  readonly mcp: McpManager;
@@ -85,8 +98,16 @@ export declare class Harness {
85
98
  readonly logger: Logger;
86
99
  private readonly options;
87
100
  private projectInstructions?;
101
+ private readonly pluginHost;
102
+ readonly cloudConnectors: CloudConnectorService;
103
+ private readonly runtimeAudit;
104
+ private readonly lifecycle;
105
+ private closing?;
106
+ private readonly activeRuns;
88
107
  private constructor();
89
108
  static create(opts?: HarnessOptions): Promise<Harness>;
109
+ /** Includes disabled/failed instances; contains neither config nor credentials. */
110
+ runtimePluginStatus(): RuntimePluginStatus[];
90
111
  /**
91
112
  * Begin mirroring, if this machine is configured and signed in for it.
92
113
  *
@@ -209,6 +230,17 @@ export declare class Harness {
209
230
  * the user catalog so the next run starts with a current list.
210
231
  */
211
232
  refreshModels(providerId?: string): Promise<ModelSpec[]>;
233
+ /**
234
+ * Check a provider's credential by asking it what it serves, and keep the
235
+ * answer.
236
+ *
237
+ * The one call does both halves of what a login needs afterwards: a key that
238
+ * cannot list models is a key that will not complete one either, and a key
239
+ * that can has just produced the roster the user is about to pick from. Done
240
+ * separately, the check is a wasted round trip and the roster is a second
241
+ * thing to remember to ask for.
242
+ */
243
+ verifyProvider(providerId: string): Promise<VerifyResult>;
212
244
  /** Merge discovered models into the user catalog on disk. */
213
245
  private saveDiscovered;
214
246
  /**
@@ -293,6 +325,7 @@ export declare class Harness {
293
325
  signal?: AbortSignal;
294
326
  }): AsyncGenerator<AgentEvent, void, void>;
295
327
  close(): Promise<void>;
328
+ private shutdown;
296
329
  /**
297
330
  * First model whose provider has credentials. Only the cheap synchronous
298
331
  * check runs here — a subscription-only provider is picked up once the
package/dist/harness.js CHANGED
@@ -9,7 +9,9 @@ import { BUILTIN_SUBAGENTS, SubagentRegistry, loadMarkdownSubagents } from "./ag
9
9
  import { SkillRegistry } from "./agent/skills.js";
10
10
  import { SettingsStore } from "./agent/settings.js";
11
11
  import { createPolicy } from "./agent/workspace.js";
12
- import { MemoryStore } from "./agent/memory.js";
12
+ import { PluginExtensions } from "./runtime-plugins/extensions.js";
13
+ import { createMemoryPlugin, MemoryService } from "./runtime-plugins/builtin/memory.js";
14
+ import { siteUrl } from "./auth/providers/account.js";
13
15
  import { loadConfig, loadProjectConfig, loadProjectInstructions, mergeConfig } from "./config.js";
14
16
  import { discoverPlugins, pluginContributions } from "./plugins.js";
15
17
  import { McpManager } from "./mcp/manager.js";
@@ -18,7 +20,7 @@ import { expandSecrets } from "./mcp/secrets.js";
18
20
  import { Scheduler } from "./schedule/scheduler.js";
19
21
  import { SyncClient } from "./sync/client.js";
20
22
  import { SessionMirror } from "./sync/mirror.js";
21
- import { isExcluded, resolveSync } from "./sync/settings.js";
23
+ import { isExcluded, resolveSync, resolveSyncUrl } from "./sync/settings.js";
22
24
  import { projectId } from "./storage/project.js";
23
25
  import { updateUserConfig } from "./config.js";
24
26
  import { ProviderRegistry } from "./providers/registry.js";
@@ -28,6 +30,9 @@ import { ToolRegistry } from "./tools/registry.js";
28
30
  import { appendFile, mkdir, readFile, writeFile } from "node:fs/promises";
29
31
  import path from "node:path";
30
32
  import { createLogger } from "./util/logger.js";
33
+ import { PluginHost } from "./runtime-plugins/host.js";
34
+ import { RuntimeAuditBus } from "./runtime-plugins/audit.js";
35
+ import { CloudConnectorService, createCloudConnectorPlugin } from "./runtime-plugins/cloud-connector.js";
31
36
  /**
32
37
  * Top-level facade: owns providers, tools, MCP connections, hooks and
33
38
  * subagents, and hands out `Agent` instances bound to a `Session`.
@@ -43,7 +48,9 @@ export class Harness {
43
48
  hooks;
44
49
  subagents;
45
50
  skills;
46
- memory;
51
+ extensions = new PluginExtensions();
52
+ memoryService;
53
+ get memory() { return this.memoryService?.store; }
47
54
  settings;
48
55
  workspace;
49
56
  mcp;
@@ -63,6 +70,12 @@ export class Harness {
63
70
  logger;
64
71
  options;
65
72
  projectInstructions;
73
+ pluginHost;
74
+ cloudConnectors;
75
+ runtimeAudit;
76
+ lifecycle = new AbortController();
77
+ closing;
78
+ activeRuns = new Set();
66
79
  constructor(opts, config, catalog, plugins = []) {
67
80
  this.options = opts;
68
81
  this.cwd = opts.cwd ?? process.cwd();
@@ -130,13 +143,25 @@ export class Harness {
130
143
  ],
131
144
  ...(config.readableRoots !== undefined ? { readableRoots: config.readableRoots } : {}),
132
145
  });
133
- this.memory = new MemoryStore(config.memoryDir
134
- ? path.resolve(this.cwd, config.memoryDir)
135
- : path.join(this.cwd, ".oharness", "memory"));
136
146
  this.mcp = new McpManager(this.logger, this.auth.store);
137
147
  this.store = new SessionStore(config.sessionDir);
138
148
  this.scheduler = new Scheduler(this, config.schedules ?? []);
139
149
  this.ephemeral = opts.ephemeral === true;
150
+ this.runtimeAudit = new RuntimeAuditBus(this.logger);
151
+ this.cloudConnectors = opts.cloudConnectorService ?? new CloudConnectorService({ token: async (origin) => {
152
+ // A still-valid access token must not leak to a newly configured Cloud,
153
+ // even when no refresh (which also verifies the origin) is necessary.
154
+ const credential = await this.auth.store.get("official");
155
+ if (credential?.type === "oauth" && credential.metadata?.cloudOrigin && credential.metadata.cloudOrigin !== origin) {
156
+ throw new Error("Cloud 地址已改变,请重新登录后连接应用。");
157
+ }
158
+ return this.accountToken();
159
+ } });
160
+ this.pluginHost = new PluginHost({
161
+ tools: this.tools, hooks: this.hooks, models: this.providers,
162
+ auth: this.auth, audit: this.runtimeAudit, logger: this.logger.child("plugins"),
163
+ extensions: this.extensions,
164
+ });
140
165
  }
141
166
  static async create(opts = {}) {
142
167
  const cwd = opts.cwd ?? process.cwd();
@@ -148,51 +173,82 @@ export class Harness {
148
173
  // The catalog is data on disk, so it can be updated without a release.
149
174
  const catalog = await loadCatalog(config.catalog ? [config.catalog] : []);
150
175
  const harness = new Harness(opts, config, catalog, plugins);
151
- harness.projectInstructions = await loadProjectInstructions(cwd, config.instructionsFile);
152
- // Rules the user approved in earlier sessions live in settings files, not
153
- // in the config the project checks in.
154
- const persisted = await harness.settings.readAll();
155
- harness.config.permissions = {
156
- allow: [...(config.permissions?.allow ?? []), ...(persisted.allow ?? [])],
157
- deny: [...(config.permissions?.deny ?? []), ...(persisted.deny ?? [])],
158
- ask: [...(config.permissions?.ask ?? []), ...(persisted.ask ?? [])],
159
- };
160
- // Best effort: reclaiming disk should never block or fail a session.
161
- if (config.sessionRetention && !opts.ephemeral) {
162
- harness.store
163
- .prune(config.sessionRetention)
164
- .then((removed) => {
165
- if (removed.length > 0) {
166
- harness.logger.info("pruned old sessions", { count: removed.length });
167
- }
168
- })
169
- .catch((err) => harness.logger.warn("session pruning failed", { error: String(err) }));
170
- }
171
- await harness.skills.discover(cwd, config.skillDirs ?? []);
172
- // Markdown definitions layer over the JSON ones, so a repo can drop in an
173
- // agent file without editing config.
174
- for (const definition of await loadMarkdownSubagents(cwd, config.agentDirs ?? [])) {
175
- harness.subagents.register(definition);
176
- }
177
- if (config.mcpServers && Object.keys(config.mcpServers).length > 0) {
178
- const statuses = await harness.mcp.connectAll(config.mcpServers);
179
- harness.tools.registerAll(harness.mcp.tools());
180
- for (const status of statuses) {
181
- if (status.error) {
182
- harness.logger.warn("MCP server unavailable", {
183
- server: status.name,
184
- error: status.error,
185
- });
176
+ try {
177
+ harness.projectInstructions = await loadProjectInstructions(cwd, config.instructionsFile);
178
+ // Rules the user approved in earlier sessions live in settings files, not
179
+ // in the config the project checks in.
180
+ const persisted = await harness.settings.readAll();
181
+ harness.config.permissions = {
182
+ allow: [...(config.permissions?.allow ?? []), ...(persisted.allow ?? [])],
183
+ deny: [...(config.permissions?.deny ?? []), ...(persisted.deny ?? [])],
184
+ ask: [...(config.permissions?.ask ?? []), ...(persisted.ask ?? [])],
185
+ };
186
+ // Best effort: reclaiming disk should never block or fail a session.
187
+ if (config.sessionRetention && !opts.ephemeral) {
188
+ harness.store
189
+ .prune(config.sessionRetention)
190
+ .then((removed) => {
191
+ if (removed.length > 0) {
192
+ harness.logger.info("pruned old sessions", { count: removed.length });
193
+ }
194
+ })
195
+ .catch((err) => harness.logger.warn("session pruning failed", { error: String(err) }));
196
+ }
197
+ await harness.skills.discover(cwd, config.skillDirs ?? []);
198
+ // Markdown definitions layer over the JSON ones, so a repo can drop in an
199
+ // agent file without editing config.
200
+ for (const definition of await loadMarkdownSubagents(cwd, config.agentDirs ?? [])) {
201
+ harness.subagents.register(definition);
202
+ }
203
+ if (config.mcpServers && Object.keys(config.mcpServers).length > 0) {
204
+ const statuses = await harness.mcp.connectAll(config.mcpServers);
205
+ harness.tools.registerAll(harness.mcp.tools());
206
+ for (const status of statuses) {
207
+ if (status.error) {
208
+ harness.logger.warn("MCP server unavailable", {
209
+ server: status.name,
210
+ error: status.error,
211
+ });
212
+ }
186
213
  }
187
214
  }
215
+ const platform = (opts.cloudConnectors ?? !opts.ephemeral)
216
+ ? [{ plugin: createCloudConnectorPlugin(harness.cloudConnectors), required: false }] : [];
217
+ const memory = createMemoryPlugin({ cwd, directory: config.memoryDir ? path.resolve(cwd, config.memoryDir) : path.join(cwd, ".oharness", "memory"),
218
+ identity: async () => {
219
+ const credential = await harness.auth.store.get("official");
220
+ if (credential?.type !== "oauth")
221
+ return undefined;
222
+ const origin = siteUrl();
223
+ if (credential.metadata?.cloudOrigin && credential.metadata.cloudOrigin !== origin)
224
+ return undefined;
225
+ // This claim is only a local account label/consent pin, never Cloud authorization.
226
+ try {
227
+ const payload = JSON.parse(Buffer.from(credential.access.split(".")[1] ?? "", "base64url").toString("utf8"));
228
+ return typeof payload.sub === "string" && /^[a-zA-Z0-9_-]{1,128}$/.test(payload.sub) ? { userId: payload.sub, origin } : undefined;
229
+ }
230
+ catch {
231
+ return undefined;
232
+ }
233
+ }, token: () => harness.accountToken(), syncUrl: () => resolveSyncUrl(harness.config.sync),
234
+ }, (service) => { harness.memoryService = service; });
235
+ await harness.pluginHost.boot([{ plugin: memory }, ...platform, ...(opts.runtimePlugins ?? [])], config.runtimePlugins);
236
+ // Awaited, though it touches no network: deciding whether to mirror reads
237
+ // config and asks git for the project id, and both are local. Leaving it
238
+ // unawaited made `syncStatus()` lie for the first few milliseconds of
239
+ // every process, which is exactly when a UI asks. The connecting happens
240
+ // inside the mirror and is not waited for.
241
+ await harness.startSync();
242
+ return harness;
188
243
  }
189
- // Awaited, though it touches no network: deciding whether to mirror reads
190
- // config and asks git for the project id, and both are local. Leaving it
191
- // unawaited made `syncStatus()` lie for the first few milliseconds of
192
- // every process, which is exactly when a UI asks. The connecting happens
193
- // inside the mirror and is not waited for.
194
- await harness.startSync();
195
- return harness;
244
+ catch (error) {
245
+ await harness.close();
246
+ throw error;
247
+ }
248
+ }
249
+ /** Includes disabled/failed instances; contains neither config nor credentials. */
250
+ runtimePluginStatus() {
251
+ return this.pluginHost.status();
196
252
  }
197
253
  /**
198
254
  * Begin mirroring, if this machine is configured and signed in for it.
@@ -479,6 +535,25 @@ export class Harness {
479
535
  }
480
536
  return discovered;
481
537
  }
538
+ /**
539
+ * Check a provider's credential by asking it what it serves, and keep the
540
+ * answer.
541
+ *
542
+ * The one call does both halves of what a login needs afterwards: a key that
543
+ * cannot list models is a key that will not complete one either, and a key
544
+ * that can has just produced the roster the user is about to pick from. Done
545
+ * separately, the check is a wasted round trip and the roster is a second
546
+ * thing to remember to ask for.
547
+ */
548
+ async verifyProvider(providerId) {
549
+ const result = await this.providers.verify(providerId);
550
+ if (result.status === "ok" && result.models.length > 0) {
551
+ await this.saveDiscovered(result.models).catch((err) => this.logger.warn("could not persist the discovered catalog", {
552
+ error: String(err),
553
+ }));
554
+ }
555
+ return result;
556
+ }
482
557
  /** Merge discovered models into the user catalog on disk. */
483
558
  async saveDiscovered(models) {
484
559
  const file = userCatalogPath();
@@ -520,6 +595,8 @@ export class Harness {
520
595
  }
521
596
  /** Start a fresh session. */
522
597
  createSession(overrides = {}) {
598
+ if (this.lifecycle.signal.aborted)
599
+ throw new ConfigError("Harness is closed");
523
600
  return this.equip(new Session({
524
601
  cwd: this.cwd,
525
602
  model: overrides.model ?? this.config.model ?? this.defaultModel(),
@@ -576,6 +653,7 @@ export class Harness {
576
653
  * path, not just louder.
577
654
  */
578
655
  record(sessionId, entry) {
656
+ this.runtimeAudit.publish({ type: "permission", timestamp: Date.now(), sessionId, entry });
579
657
  const configured = this.config.auditLog;
580
658
  this.auditQueue = this.auditQueue
581
659
  .then(async () => {
@@ -640,13 +718,15 @@ export class Harness {
640
718
  }
641
719
  /** Build an agent bound to a session, wired with everything the harness owns. */
642
720
  agent(session, overrides = {}) {
721
+ if (this.lifecycle.signal.aborted)
722
+ throw new ConfigError("Harness is closed");
643
723
  return new Agent({
644
724
  session,
645
725
  tools: this.tools,
646
726
  hooks: this.hooks,
647
727
  subagents: this.subagents,
648
728
  skills: this.skills,
649
- memory: this.memory,
729
+ promptSections: () => this.extensions.promptSections(),
650
730
  onSkillsChanged: () => this.reloadSkills(),
651
731
  mcp: this.mcp,
652
732
  permissionPrompt: this.options.permissionPrompt,
@@ -660,6 +740,15 @@ export class Harness {
660
740
  maxTurns: this.config.maxTurns,
661
741
  cache: this.config.cache,
662
742
  logger: this.logger,
743
+ lifecycleSignal: this.lifecycle.signal,
744
+ onRunStart: () => {
745
+ let finish;
746
+ const done = new Promise((resolve) => { finish = resolve; });
747
+ this.activeRuns.add(done);
748
+ return () => { this.activeRuns.delete(done); finish(); };
749
+ },
750
+ onAudit: (event) => { if (this.config.audit !== false)
751
+ this.runtimeAudit.publish(event); },
663
752
  ...overrides,
664
753
  });
665
754
  }
@@ -672,11 +761,34 @@ export class Harness {
672
761
  const agent = this.agent(session);
673
762
  yield* agent.run(prompt, { signal: opts.signal });
674
763
  }
675
- async close() {
764
+ close() {
765
+ return this.closing ??= this.shutdown();
766
+ }
767
+ async shutdown() {
768
+ this.lifecycle.abort();
769
+ this.cloudConnectors.close();
770
+ this.scheduler.stop();
676
771
  // Stopped before MCP, because it is the only thing here holding a socket
677
772
  // open on purpose — a long poll would otherwise keep the process alive for
678
773
  // up to thirty seconds after everything else had shut down.
679
774
  this.mirror?.stop();
775
+ let timer;
776
+ try {
777
+ await Promise.race([
778
+ Promise.all(this.activeRuns),
779
+ new Promise((resolve) => {
780
+ timer = setTimeout(() => {
781
+ this.logger.warn("Agent drain timed out during shutdown");
782
+ resolve();
783
+ }, 5000);
784
+ }),
785
+ ]);
786
+ }
787
+ finally {
788
+ clearTimeout(timer);
789
+ }
790
+ await this.pluginHost.close();
791
+ await this.auditQueue;
680
792
  await this.mcp.closeAll();
681
793
  }
682
794
  /**