From 02f6341bf74be69c425a9a93b321c4186b565346 Mon Sep 17 00:00:00 2001 From: Surma Date: Sat, 7 Nov 2026 14:50:06 +0000 Subject: [PATCH] Expose canonical host chains and validate automation ancestry --- extensions/automations/README.md | 6 +- extensions/automations/scheduler.ts | 4 +- extensions/automations/server.ts | 5 +- host/js/automations-test-bundle.js | 936 +++++++++++++++------------- host/js/automations-test.ts | 26 +- host/js/bundle.js | 2 + host/js/core-ext-test-bundle.js | 179 +++--- host/js/events-test-bundle.js | 179 +++--- host/js/extensions-test-bundle.js | 179 +++--- host/js/extensions.ts | 5 +- host/js/messages-test-bundle.js | 106 ++-- host/js/p3-test-bundle.js | 179 +++--- host/js/plan-todos-test-bundle.js | 183 +++--- host/js/subagents-test-bundle.js | 106 ++-- 14 files changed, 1189 insertions(+), 906 deletions(-) diff --git a/extensions/automations/README.md b/extensions/automations/README.md index c7b83a0..1e9d989 100644 --- a/extensions/automations/README.md +++ b/extensions/automations/README.md @@ -32,8 +32,10 @@ External script effects can repeat after a crash. ## Credentials The conversation that creates an automation remains its execution conversation. -Every script launch uses that conversation's T44 chain. -The chain includes ownership, fork ancestry, and the optional branch starter. +Every script launch uses `host.chain(creator)`. +The host delegates to `conversationChains` in `host/js/environment.ts`. +The host appends the branch starter's chain after the ownership or fork ancestry. +The host removes duplicate ids without changing their order. Subscribe and unsubscribe change notification recipients only. They never change the execution conversation. Built-in automations without a creator use an empty chain. diff --git a/extensions/automations/scheduler.ts b/extensions/automations/scheduler.ts index 4c777cf..2e8235a 100644 --- a/extensions/automations/scheduler.ts +++ b/extensions/automations/scheduler.ts @@ -8,7 +8,7 @@ import { import type { ConversationId, Cursor, Tx } from '@earendil-works/pi-durable' type ExtensionHost = any import { SubagentsApi } from '../subagents/api.ts' -import { discover } from '../subagents/definitions.ts' +import { ModelsApi } from '../models/api.ts' import { nextAt } from './schedule.ts' import type { Automation, Run } from './types.ts' import { RUN_TASK } from './types.ts' @@ -26,7 +26,7 @@ const terminal = { } async function definition(host: ExtensionHost, name: string) { const found = ( - await discover(host) + await host.need(ModelsApi).discover('/src/sausage') ).definitions.find((d) => d.name === name) if (!found) throw new Error(`Unknown agent: ${name}`) return found diff --git a/extensions/automations/server.ts b/extensions/automations/server.ts index 97de93c..e29cf49 100644 --- a/extensions/automations/server.ts +++ b/extensions/automations/server.ts @@ -6,7 +6,6 @@ import { SubagentsApi } from '../subagents/api.ts' import { scheduler } from './scheduler.ts' import { triggers, TRIGGER_EVENTS } from './triggers.ts' import { parseSchedule } from './schedule.ts' -import { executionChain } from './chain.ts' import { fireText, doneText, trimLog } from './types.ts' import type { Args, Automation, Subscriber } from './types.ts' export type { Automation, Run } from './types.ts' @@ -62,7 +61,7 @@ export default function automations(host:any) { execute:async(task,runtime,ctx)=>{ const a = (await host.harness().snapshot(Automations,ctx))!.automations[task.input.id] if (!a?.enabled || !a.script || a.scheduler!==task.id) return runtime.commit(()=>terminal,ctx) - const conversations = await executionChain(host,a.executionConversation) + const conversations = a.executionConversation === undefined ? [] : await host.chain(a.executionConversation) let queue = Promise.resolve(), log='', done=false, sequence=0 const pending:Record = {stdout:'',stderr:''} function line(text:string,stream:string) { @@ -79,7 +78,7 @@ export default function automations(host:any) { receipts[key]=true },ctx)) } - const result=await host.exec(['sh',path(a.id)],{cwd:directory(a.id),conversations,timeout:3600,signal:runtime.signal,onOutput:(text:string,stream:string)=>{ + const result=await host.exec(['sh',path(a.id)],{cwd:directory(a.id),conversations,timeout:3600,signal:runtime.signal,task:task.id,onOutput:(text:string,stream:string)=>{ pending[stream]+=text const lines=pending[stream].split('\n'); pending[stream]=lines.pop()! for(const text of lines) line(text.replace(/\r$/,''),stream) diff --git a/host/js/automations-test-bundle.js b/host/js/automations-test-bundle.js index 164190c..cf12b21 100644 --- a/host/js/automations-test-bundle.js +++ b/host/js/automations-test-bundle.js @@ -40,7 +40,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge mod )); -// host/js/node_modules/@earendil-works/pi-telemetry/dist/metrics.js +// node_modules/@earendil-works/pi-telemetry/dist/metrics.js function createTypedMetrics(metrics, schemas) { const definitions = /* @__PURE__ */ new Map(); for (const schema of schemas) { @@ -54,17 +54,17 @@ function createTypedMetrics(metrics, schemas) { }; } var init_metrics = __esm({ - "host/js/node_modules/@earendil-works/pi-telemetry/dist/metrics.js"() { + "node_modules/@earendil-works/pi-telemetry/dist/metrics.js"() { } }); -// host/js/node_modules/@earendil-works/pi-telemetry/dist/noop.js +// node_modules/@earendil-works/pi-telemetry/dist/noop.js async function startNoopSpan(_options, callback) { return callback(noopTelemetrySpan); } var noopCounter, noopUpDownCounter, noopHistogram, NOOP_TELEMETRY_METRICS, NOOP_TELEMETRY_PROPAGATION, noopTelemetrySpan, NOOP_TELEMETRY_CONTEXT; var init_noop = __esm({ - "host/js/node_modules/@earendil-works/pi-telemetry/dist/noop.js"() { + "node_modules/@earendil-works/pi-telemetry/dist/noop.js"() { noopCounter = Object.freeze({ add: () => { } }); noopUpDownCounter = Object.freeze({ add: () => { @@ -98,14 +98,14 @@ var init_noop = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-telemetry/dist/memory.js +// node_modules/@earendil-works/pi-telemetry/dist/memory.js var init_memory = __esm({ - "host/js/node_modules/@earendil-works/pi-telemetry/dist/memory.js"() { + "node_modules/@earendil-works/pi-telemetry/dist/memory.js"() { init_noop(); } }); -// host/js/node_modules/@earendil-works/pi-telemetry/dist/index.js +// node_modules/@earendil-works/pi-telemetry/dist/index.js function defineTelemetrySchema(schema) { return schema; } @@ -117,14 +117,14 @@ function createTypedSpanStarter(telemetryContext, _schemas) { return bindTypedSpanStarter(telemetryContext); } var init_dist = __esm({ - "host/js/node_modules/@earendil-works/pi-telemetry/dist/index.js"() { + "node_modules/@earendil-works/pi-telemetry/dist/index.js"() { init_metrics(); init_noop(); init_memory(); } }); -// host/js/node_modules/@earendil-works/chord/dist/context/index.js +// node_modules/@earendil-works/chord/dist/context/index.js var context_exports = {}; __export(context_exports, { BACKGROUND_CONTEXT: () => BACKGROUND_CONTEXT, @@ -189,7 +189,7 @@ function abortError(signal) { } var ABORT_SIGNAL_CONTEXT_KEY, TELEMETRY_CONTEXT_KEY, BaseContext, EmptyContext, ContextValue, BACKGROUND_CONTEXT, TODO_CONTEXT; var init_context = __esm({ - "host/js/node_modules/@earendil-works/chord/dist/context/index.js"() { + "node_modules/@earendil-works/chord/dist/context/index.js"() { init_dist(); ABORT_SIGNAL_CONTEXT_KEY = Object.freeze({ token: /* @__PURE__ */ Symbol("chord.abortSignal") @@ -242,13 +242,13 @@ var init_context = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-ai/dist/utils/event-stream.js +// node_modules/@earendil-works/pi-ai/dist/utils/event-stream.js function createAssistantMessageEventStream() { return new AssistantMessageEventStream(); } var FifoQueue, EventStream, AssistantMessageEventStream; var init_event_stream = __esm({ - "host/js/node_modules/@earendil-works/pi-ai/dist/utils/event-stream.js"() { + "node_modules/@earendil-works/pi-ai/dist/utils/event-stream.js"() { FifoQueue = class { incoming = []; outgoing = []; @@ -358,7 +358,7 @@ var init_event_stream = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-ai/dist/api/lazy.js +// node_modules/@earendil-works/pi-ai/dist/api/lazy.js function createSetupErrorMessage(model2, error, timestamp) { return { role: "assistant", @@ -441,12 +441,12 @@ function lazyApi(load, capabilities) { return api; } var init_lazy = __esm({ - "host/js/node_modules/@earendil-works/pi-ai/dist/api/lazy.js"() { + "node_modules/@earendil-works/pi-ai/dist/api/lazy.js"() { init_event_stream(); } }); -// host/js/node_modules/@earendil-works/pi-ai/dist/auth/context.js +// node_modules/@earendil-works/pi-ai/dist/auth/context.js function getProcessEnv() { const proc = globalThis.process; return proc?.env; @@ -475,7 +475,7 @@ function defaultProviderAuthContext() { } var __rewriteRelativeImportExtension, importNodeModule; var init_context2 = __esm({ - "host/js/node_modules/@earendil-works/pi-ai/dist/auth/context.js"() { + "node_modules/@earendil-works/pi-ai/dist/auth/context.js"() { __rewriteRelativeImportExtension = function(path, preserveJsx) { if (typeof path === "string" && /^\.\.?\//.test(path)) { return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function(m, tsx, d, ext, cm) { @@ -488,7 +488,7 @@ var init_context2 = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-ai/dist/utils/abort.js +// node_modules/@earendil-works/pi-ai/dist/utils/abort.js function abortReason(signal) { if (signal.reason !== void 0) return signal.reason; @@ -534,14 +534,14 @@ function raceWithAbortSignal(operation, signal) { }); } var init_abort = __esm({ - "host/js/node_modules/@earendil-works/pi-ai/dist/utils/abort.js"() { + "node_modules/@earendil-works/pi-ai/dist/utils/abort.js"() { } }); -// host/js/node_modules/@earendil-works/pi-ai/dist/auth/credential-store.js +// node_modules/@earendil-works/pi-ai/dist/auth/credential-store.js var InMemoryCredentialStore; var init_credential_store = __esm({ - "host/js/node_modules/@earendil-works/pi-ai/dist/auth/credential-store.js"() { + "node_modules/@earendil-works/pi-ai/dist/auth/credential-store.js"() { init_abort(); InMemoryCredentialStore = class { credentials = /* @__PURE__ */ new Map(); @@ -592,7 +592,7 @@ var init_credential_store = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-ai/dist/utils/diagnostics.js +// node_modules/@earendil-works/pi-ai/dist/utils/diagnostics.js function formatThrownValue(value2) { if (value2 instanceof Error) return value2.message || value2.name; @@ -618,11 +618,11 @@ function appendAssistantMessageDiagnostic(message, diagnostic) { message.diagnostics = [...message.diagnostics ?? [], diagnostic]; } var init_diagnostics = __esm({ - "host/js/node_modules/@earendil-works/pi-ai/dist/utils/diagnostics.js"() { + "node_modules/@earendil-works/pi-ai/dist/utils/diagnostics.js"() { } }); -// host/js/node_modules/@earendil-works/pi-ai/dist/utils/models-error.js +// node_modules/@earendil-works/pi-ai/dist/utils/models-error.js function withCauseDetail(message, cause) { if (cause === void 0 || cause === null) return message; @@ -633,7 +633,7 @@ function withCauseDetail(message, cause) { } var ModelsError; var init_models_error = __esm({ - "host/js/node_modules/@earendil-works/pi-ai/dist/utils/models-error.js"() { + "node_modules/@earendil-works/pi-ai/dist/utils/models-error.js"() { init_diagnostics(); ModelsError = class extends Error { code; @@ -646,7 +646,7 @@ var init_models_error = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-ai/dist/auth/resolve.js +// node_modules/@earendil-works/pi-ai/dist/auth/resolve.js function resolveProviderAuth(provider2, credentials, authContext, overrides) { const signal = operationSignal(overrides?.signal); return raceWithAbortSignal(resolveProviderAuthWithSignal(provider2, credentials, authContext, overrides, signal), signal); @@ -746,7 +746,7 @@ async function readCredential(credentials, providerId, signal) { } var DEFAULT_OAUTH_MINIMUM_VALIDITY_MS, DEFAULT_OAUTH_REFRESH_TIMEOUT_MS; var init_resolve = __esm({ - "host/js/node_modules/@earendil-works/pi-ai/dist/auth/resolve.js"() { + "node_modules/@earendil-works/pi-ai/dist/auth/resolve.js"() { init_abort(); init_models_error(); init_models_error(); @@ -755,10 +755,10 @@ var init_resolve = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-ai/dist/models-store.js +// node_modules/@earendil-works/pi-ai/dist/models-store.js var InMemoryModelsStore; var init_models_store = __esm({ - "host/js/node_modules/@earendil-works/pi-ai/dist/models-store.js"() { + "node_modules/@earendil-works/pi-ai/dist/models-store.js"() { InMemoryModelsStore = class { entries = /* @__PURE__ */ new Map(); async read(providerId, options) { @@ -778,7 +778,7 @@ var init_models_store = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-ai/dist/utils/text.js +// node_modules/@earendil-works/pi-ai/dist/utils/text.js function contentText(content, separator = "\n") { if (typeof content === "string") return content; @@ -808,11 +808,11 @@ function ownedSlice(text, start, end = text.length) { return `${text.slice(start, end)} `.slice(0, -1); } var init_text = __esm({ - "host/js/node_modules/@earendil-works/pi-ai/dist/utils/text.js"() { + "node_modules/@earendil-works/pi-ai/dist/utils/text.js"() { } }); -// host/js/node_modules/@earendil-works/pi-ai/dist/telemetry.js +// node_modules/@earendil-works/pi-ai/dist/telemetry.js function createInstruments(adapter) { const metrics = createTypedMetrics(adapter, [AI_TELEMETRY_SCHEMA]); return { @@ -911,7 +911,7 @@ function observeModelRequest(requestedModel, options, poll) { } var provider, model, stop, request, AI_TELEMETRY_SCHEMA, instrumentCache; var init_telemetry = __esm({ - "host/js/node_modules/@earendil-works/pi-ai/dist/telemetry.js"() { + "node_modules/@earendil-works/pi-ai/dist/telemetry.js"() { init_dist(); init_text(); provider = { type: "string", description: "Provider identifier.", required: true }; @@ -1007,15 +1007,15 @@ var init_telemetry = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-ai/dist/utils/version.js +// node_modules/@earendil-works/pi-ai/dist/utils/version.js var PI_AI_VERSION; var init_version = __esm({ - "host/js/node_modules/@earendil-works/pi-ai/dist/utils/version.js"() { + "node_modules/@earendil-works/pi-ai/dist/utils/version.js"() { PI_AI_VERSION = "1.5.0"; } }); -// host/js/node_modules/@earendil-works/pi-ai/dist/utils/identity.js +// node_modules/@earendil-works/pi-ai/dist/utils/identity.js function mergeClientIdentity(...sources) { let merged; for (const source of sources) { @@ -1137,7 +1137,7 @@ function withClientIdentity(models2, identity) { } var PI_ATTRIBUTION, NVIDIA_NIM_HOST, OPENCODE_HOST; var init_identity = __esm({ - "host/js/node_modules/@earendil-works/pi-ai/dist/utils/identity.js"() { + "node_modules/@earendil-works/pi-ai/dist/utils/identity.js"() { init_version(); PI_ATTRIBUTION = { name: "pi", url: "https://pi.dev", categories: ["cli-agent"] }; NVIDIA_NIM_HOST = "integrate.api.nvidia.com"; @@ -1145,7 +1145,7 @@ var init_identity = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-ai/dist/utils/model-operations.js +// node_modules/@earendil-works/pi-ai/dist/utils/model-operations.js function getModelType(model2) { return model2.type ?? "chat"; } @@ -1195,12 +1195,12 @@ function classifierErrorResult(model2, error, aborted = false) { }; } var init_model_operations = __esm({ - "host/js/node_modules/@earendil-works/pi-ai/dist/utils/model-operations.js"() { + "node_modules/@earendil-works/pi-ai/dist/utils/model-operations.js"() { init_models_error(); } }); -// host/js/node_modules/@earendil-works/pi-ai/dist/utils/transcript.js +// node_modules/@earendil-works/pi-ai/dist/utils/transcript.js function createInitialSystemMessage(systemPrompt, tools) { const hasSystemPrompt = systemPrompt !== void 0 && systemPrompt.length > 0; const hasTools = tools !== void 0 && tools.length > 0; @@ -1359,12 +1359,12 @@ function resolveTranscriptTools(messages, support) { return { requestTools: getCurrentTools(systemMessages.slice(0, folded)), foldedSystemMessages: folded }; } var init_transcript = __esm({ - "host/js/node_modules/@earendil-works/pi-ai/dist/utils/transcript.js"() { + "node_modules/@earendil-works/pi-ai/dist/utils/transcript.js"() { init_text(); } }); -// host/js/node_modules/@earendil-works/pi-ai/dist/models.js +// node_modules/@earendil-works/pi-ai/dist/models.js var models_exports = {}; __export(models_exports, { AI_TELEMETRY_SCHEMA: () => AI_TELEMETRY_SCHEMA, @@ -1573,7 +1573,7 @@ function modelsAreEqual(a, b) { } var KNOWN_MODEL_TYPES, ModelsImpl, EXTENDED_THINKING_LEVELS; var init_models = __esm({ - "host/js/node_modules/@earendil-works/pi-ai/dist/models.js"() { + "node_modules/@earendil-works/pi-ai/dist/models.js"() { init_lazy(); init_context2(); init_credential_store(); @@ -2063,9 +2063,9 @@ var init_models = __esm({ } }); -// host/js/node_modules/partial-json/dist/options.js +// node_modules/partial-json/dist/options.js var require_options = __commonJS({ - "host/js/node_modules/partial-json/dist/options.js"(exports) { + "node_modules/partial-json/dist/options.js"(exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Allow = exports.ALL = exports.COLLECTION = exports.ATOM = exports.SPECIAL = exports.INF = exports._INFINITY = exports.INFINITY = exports.NAN = exports.BOOL = exports.NULL = exports.OBJ = exports.ARR = exports.NUM = exports.STR = void 0; @@ -2088,9 +2088,9 @@ var require_options = __commonJS({ } }); -// host/js/node_modules/partial-json/dist/index.js +// node_modules/partial-json/dist/index.js var require_dist = __commonJS({ - "host/js/node_modules/partial-json/dist/index.js"(exports) { + "node_modules/partial-json/dist/index.js"(exports) { "use strict"; var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) { if (k2 === void 0) k2 = k; @@ -2299,7 +2299,7 @@ var require_dist = __commonJS({ } }); -// host/js/node_modules/@earendil-works/pi-ai/dist/utils/json-parse.js +// node_modules/@earendil-works/pi-ai/dist/utils/json-parse.js function isControlCharacter(char) { const codePoint = char.codePointAt(0); return codePoint !== void 0 && codePoint >= 0 && codePoint <= 31; @@ -2415,13 +2415,13 @@ function parseStreamingJson(partialJson) { } var import_partial_json, VALID_JSON_ESCAPES; var init_json_parse = __esm({ - "host/js/node_modules/@earendil-works/pi-ai/dist/utils/json-parse.js"() { + "node_modules/@earendil-works/pi-ai/dist/utils/json-parse.js"() { import_partial_json = __toESM(require_dist(), 1); VALID_JSON_ESCAPES = /* @__PURE__ */ new Set(['"', "\\", "/", "b", "f", "n", "r", "t"]); } }); -// host/js/node_modules/@earendil-works/pi-ai/dist/utils/streaming-json.js +// node_modules/@earendil-works/pi-ai/dist/utils/streaming-json.js function isDelimiter(char) { return char === " " || char === " " || char === "\n" || char === "\r" || char === "," || char === ":" || char === "{" || char === "}" || char === "[" || char === "]" || char === '"'; } @@ -2458,7 +2458,7 @@ function setMember(members, key, value2) { } var MAX_REPORTED_DEPTH, ROOT_SLOT, CREDIT_PER_APPEND, CREDIT_PER_CHARACTER, MAX_PENDING_SCALAR_LENGTH, NUMBER, NUMBER_WITHOUT_EXPONENT_DIGITS, LITERALS, QUOTE, BACKSLASH, StreamingJsonParser, ToolCallArgumentsStream, SIMPLE_ESCAPES; var init_streaming_json = __esm({ - "host/js/node_modules/@earendil-works/pi-ai/dist/utils/streaming-json.js"() { + "node_modules/@earendil-works/pi-ai/dist/utils/streaming-json.js"() { init_json_parse(); MAX_REPORTED_DEPTH = 32; ROOT_SLOT = { kind: "root" }; @@ -2866,7 +2866,7 @@ var init_streaming_json = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-ai/dist/providers/faux.js +// node_modules/@earendil-works/pi-ai/dist/providers/faux.js function fauxText(text) { return { type: "text", text }; } @@ -3327,7 +3327,7 @@ function fauxProvider(options = {}) { } var DEFAULT_API, DEFAULT_PROVIDER, DEFAULT_MODEL_ID, DEFAULT_MODEL_NAME, DEFAULT_BASE_URL, DEFAULT_MIN_TOKEN_SIZE, DEFAULT_MAX_TOKEN_SIZE, DEFAULT_USAGE; var init_faux = __esm({ - "host/js/node_modules/@earendil-works/pi-ai/dist/providers/faux.js"() { + "node_modules/@earendil-works/pi-ai/dist/providers/faux.js"() { init_models(); init_event_stream(); init_streaming_json(); @@ -3350,7 +3350,7 @@ var init_faux = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/builders.js +// node_modules/@earendil-works/pi-schema/dist/builders.js function str(options = {}) { return { type: "string", ...options }; } @@ -3418,7 +3418,7 @@ function obj(properties, options = {}) { } var Optional; var init_builders = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/builders.js"() { + "node_modules/@earendil-works/pi-schema/dist/builders.js"() { Optional = class { schema; constructor(schema) { @@ -3428,7 +3428,7 @@ var init_builders = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/resolver.js +// node_modules/@earendil-works/pi-schema/dist/resolver.js function isSchemaObject(value2) { return typeof value2 === "object" && value2 !== null && !Array.isArray(value2); } @@ -3445,7 +3445,7 @@ function documentOf(uri) { } var DEFAULT_BASE, Resolver, SCHEMA_KEYWORDS, MAP_KEYWORDS, ARRAY_KEYWORDS; var init_resolver = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/resolver.js"() { + "node_modules/@earendil-works/pi-schema/dist/resolver.js"() { DEFAULT_BASE = "https://json-schema.invalid/root.json"; Resolver = class { draft; @@ -3620,7 +3620,7 @@ var init_resolver = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/shared.js +// node_modules/@earendil-works/pi-schema/dist/shared.js function sharedRegex(source) { const hit = regexes.get(source)?.deref(); if (hit !== void 0) @@ -3637,7 +3637,7 @@ function sharedRegex(source) { } var regexes, regexCleanup; var init_shared = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/shared.js"() { + "node_modules/@earendil-works/pi-schema/dist/shared.js"() { regexes = /* @__PURE__ */ new Map(); regexCleanup = new FinalizationRegistry((source) => { if (regexes.get(source)?.deref() === void 0) @@ -3646,7 +3646,7 @@ var init_shared = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/coerce.js +// node_modules/@earendil-works/pi-schema/dist/coerce.js function itemSchemaAt(schema, index) { if (Array.isArray(schema.items)) return schema.items[index]; @@ -3818,7 +3818,7 @@ function isPlainObject(value2) { } var Coercer, MAX_BIGINT, MIN_BIGINT; var init_coerce = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/coerce.js"() { + "node_modules/@earendil-works/pi-schema/dist/coerce.js"() { init_resolver(); init_shared(); Coercer = class { @@ -4177,7 +4177,7 @@ var init_coerce = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/checks.js +// node_modules/@earendil-works/pi-schema/dist/checks.js function isObject(v) { return typeof v === "object" && v !== null && !Array.isArray(v) && !(v instanceof Uint8Array); } @@ -4547,7 +4547,7 @@ function deepEqual(a, b) { } var ALWAYS, NEVER, IS_STRING, IS_NUMBER, IS_INTEGER, IS_BOOLEAN, IS_NULL, IS_ARRAY, IS_BYTES, IS_OBJECT, TYPE_CHECKS, LEAF_CODES, GUARD_NONE, GUARD_STRICT, GUARD_LOOSE, CODE, REQUIRED, INHERITED; var init_checks = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/checks.js"() { + "node_modules/@earendil-works/pi-schema/dist/checks.js"() { ALWAYS = () => true; NEVER = () => false; IS_STRING = (v) => typeof v === "string"; @@ -4585,7 +4585,7 @@ var init_checks = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/annotations.js +// node_modules/@earendil-works/pi-schema/dist/annotations.js function newAnnotations() { return { props: null, allProps: false, items: 0, allItems: false, indexes: null }; } @@ -4761,14 +4761,14 @@ function unevaluatedItems(check2) { } var ANNOTATING_TRUE, ANNOTATING_FALSE; var init_annotations = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/annotations.js"() { + "node_modules/@earendil-works/pi-schema/dist/annotations.js"() { init_checks(); ANNOTATING_TRUE = () => true; ANNOTATING_FALSE = () => false; } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/compiler.js +// node_modules/@earendil-works/pi-schema/dist/compiler.js function constUnion(branches, exactlyOne) { const values = []; for (const branch of branches) { @@ -4802,7 +4802,7 @@ function entries(value2) { } var RESTART, Compiler, NEUTRAL_KEYWORDS, OBJECT_EXTRAS, ANNOTATING; var init_compiler = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/compiler.js"() { + "node_modules/@earendil-works/pi-schema/dist/compiler.js"() { init_annotations(); init_checks(); init_resolver(); @@ -5270,7 +5270,7 @@ var init_compiler = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/explain.js +// node_modules/@earendil-works/pi-schema/dist/explain.js function listValues(values) { if (values.length <= LISTED_VALUES) return JSON.stringify(values); @@ -5300,7 +5300,7 @@ function typeName(v) { } var Explainer, LISTED_VALUES; var init_explain = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/explain.js"() { + "node_modules/@earendil-works/pi-schema/dist/explain.js"() { init_annotations(); init_checks(); init_resolver(); @@ -5641,7 +5641,7 @@ var init_explain = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/validator.js +// node_modules/@earendil-works/pi-schema/dist/validator.js function compile(schema, options = NO_OPTIONS) { const check2 = compileCheck(schema, options); return options.coerce === true ? new CoercingValidator(schema, options, check2) : new Validator(schema, options, check2); @@ -5662,7 +5662,7 @@ function compiler(schema, options) { } var NO_OPTIONS, Validator, CoercingValidator; var init_validator = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/validator.js"() { + "node_modules/@earendil-works/pi-schema/dist/validator.js"() { init_coerce(); init_compiler(); init_explain(); @@ -5710,7 +5710,7 @@ var init_validator = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/index.js +// node_modules/@earendil-works/pi-schema/dist/index.js var dist_exports = {}; __export(dist_exports, { CoercingValidator: () => CoercingValidator, @@ -5735,13 +5735,13 @@ __export(dist_exports, { unknown: () => unknown }); var init_dist2 = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/index.js"() { + "node_modules/@earendil-works/pi-schema/dist/index.js"() { init_builders(); init_validator(); } }); -// host/js/node_modules/@earendil-works/chord/dist/errors.js +// node_modules/@earendil-works/chord/dist/errors.js async function runAll(steps, message) { const errors = []; for (const step of steps) { @@ -5758,7 +5758,7 @@ async function runAll(steps, message) { } var CHORD_ERROR_CODES, RETRYABLE, ChordError, isChordError, forbidden, invalid, asChordError; var init_errors = __esm({ - "host/js/node_modules/@earendil-works/chord/dist/errors.js"() { + "node_modules/@earendil-works/chord/dist/errors.js"() { CHORD_ERROR_CODES = [ "aborted", "contract_mismatch", @@ -5799,7 +5799,7 @@ var init_errors = __esm({ } }); -// host/js/node_modules/@earendil-works/chord/dist/schema.js +// node_modules/@earendil-works/chord/dist/schema.js function canonicalJson(value2) { if (value2 === null || typeof value2 !== "object") return JSON.stringify(value2) ?? "null"; @@ -6110,7 +6110,7 @@ function functionFits(sub, sup) { } var asSchema, validators, isPlainObject2, isSchemaObject2, keepsUnknown, CONSTRAINTS, typesOf2, KNOWN, ANNOTATIONS, withoutAnnotations; var init_schema = __esm({ - "host/js/node_modules/@earendil-works/chord/dist/schema.js"() { + "node_modules/@earendil-works/chord/dist/schema.js"() { init_dist2(); init_errors(); asSchema = (schema) => schema !== null && typeof schema === "object" ? schema : schema === false ? { not: {} } : {}; @@ -6166,7 +6166,7 @@ var init_schema = __esm({ } }); -// host/js/node_modules/@earendil-works/chord/dist/contract.js +// node_modules/@earendil-works/chord/dist/contract.js function method(args, result) { return { [MEMBER]: "method", args, result }; } @@ -6332,7 +6332,7 @@ function takesNoArgs(contract, name) { } var MEMBER, opaque, placedOn, placementText, SchemaObject, MemberDescriptionSchema, LOCAL_VARIANT, PlacementSchema, DescriptionSchema, RESERVED_MEMBERS, samePlacement, placementOf; var init_contract = __esm({ - "host/js/node_modules/@earendil-works/chord/dist/contract.js"() { + "node_modules/@earendil-works/chord/dist/contract.js"() { init_dist2(); init_errors(); init_schema(); @@ -6382,7 +6382,7 @@ var init_contract = __esm({ } }); -// host/js/node_modules/@earendil-works/chord/dist/delta/diff.js +// node_modules/@earendil-works/chord/dist/delta/diff.js function diffArrayRegion(before, after, path, operations, beforeStart, beforeEnd, afterStart, afterEnd, outputStart) { if (overflowedBatches.has(operations)) return; @@ -6454,7 +6454,7 @@ function diffRevisions(before, after) { } var DEFAULT_OVERLAP_SCAN, MAX_DELTA_OPERATIONS, overflowedBatches, emitOperation, isContainer, emitSet, equalJson, permutation, emitString, MAX_IDENTITY_CANDIDATES, MAX_SEMANTIC_CELLS, sameValue, lcsMatches, semanticallyAligned, lowerBound, identitySubsequence, greedyIdentityAnchors, identityAnchors, processArrayMatches, diffArray, diffObject, diffValue, jsonCost, pathCost, operationCost; var init_diff = __esm({ - "host/js/node_modules/@earendil-works/chord/dist/delta/diff.js"() { + "node_modules/@earendil-works/chord/dist/delta/diff.js"() { init_delta(); DEFAULT_OVERLAP_SCAN = 65536; MAX_DELTA_OPERATIONS = 4096; @@ -6809,7 +6809,7 @@ var init_diff = __esm({ } }); -// host/js/node_modules/@earendil-works/chord/dist/json.js +// node_modules/@earendil-works/chord/dist/json.js function copyJson(value2, options) { return copy(value2, void 0, options?.omitUndefinedProperties === true); } @@ -6920,7 +6920,7 @@ function check(value2, ancestors) { } var DATA_DESCRIPTOR; var init_json = __esm({ - "host/js/node_modules/@earendil-works/chord/dist/json.js"() { + "node_modules/@earendil-works/chord/dist/json.js"() { DATA_DESCRIPTOR = { value: void 0, writable: true, @@ -6930,7 +6930,7 @@ var init_json = __esm({ } }); -// host/js/node_modules/@earendil-works/chord/dist/delta/apply-immutable-trusted.js +// node_modules/@earendil-works/chord/dist/delta/apply-immutable-trusted.js function applyImmutableTrusted(target, operations) { let root2 = target; const owned = /* @__PURE__ */ new WeakSet(); @@ -7047,7 +7047,7 @@ function isContainer2(value2) { } var DATA_DESCRIPTOR2; var init_apply_immutable_trusted = __esm({ - "host/js/node_modules/@earendil-works/chord/dist/delta/apply-immutable-trusted.js"() { + "node_modules/@earendil-works/chord/dist/delta/apply-immutable-trusted.js"() { DATA_DESCRIPTOR2 = { value: void 0, writable: true, @@ -7057,7 +7057,7 @@ var init_apply_immutable_trusted = __esm({ } }); -// host/js/node_modules/@earendil-works/chord/dist/delta/tracker.js +// node_modules/@earendil-works/chord/dist/delta/tracker.js function staleCompetitor(context, winner) { if (context === winner) return; @@ -8704,7 +8704,7 @@ function isContainer3(value2) { } var NODE, PREPARED, RELEASED, ARRAY_MUTATORS, MAX_DELTA_OPERATIONS2, MAX_SIMPLE_OBJECT_NODES, DATA_DESCRIPTOR3, PreparedImpl, ChangeImpl, TrackerImpl, sharedObjectHandler, sharedArrayHandler, arrayMutators, locatedDenseArray, locatedDenseIndex; var init_tracker = __esm({ - "host/js/node_modules/@earendil-works/chord/dist/delta/tracker.js"() { + "node_modules/@earendil-works/chord/dist/delta/tracker.js"() { init_json(); init_apply_immutable_trusted(); init_delta(); @@ -9113,7 +9113,7 @@ var init_tracker = __esm({ } }); -// host/js/node_modules/@earendil-works/chord/dist/delta/pending.js +// node_modules/@earendil-works/chord/dist/delta/pending.js function mergeLeaf(op2, folding) { const key = pathKey(op2[1]); const at2 = folding.leaves.get(key); @@ -9141,7 +9141,7 @@ function merge2(previous, next2) { } var MAX_PENDING_OPS, EMPTY, REPLACE, NO_OPS, REPLACE_TAKE, PendingOps, isPrimitive; var init_pending = __esm({ - "host/js/node_modules/@earendil-works/chord/dist/delta/pending.js"() { + "node_modules/@earendil-works/chord/dist/delta/pending.js"() { MAX_PENDING_OPS = 1e4; EMPTY = { kind: "empty" }; REPLACE = { kind: "replace" }; @@ -9150,27 +9150,27 @@ var init_pending = __esm({ PendingOps = class { #state = EMPTY; /** Queue the ops of one commit. */ - push(ops2) { - if (ops2.length === 0) + push(ops3) { + if (ops3.length === 0) return; const state = this.#state; - if (ops2[0][0] === "r") { - this.#state = { kind: "batch", ops: ops2 }; + if (ops3[0][0] === "r") { + this.#state = { kind: "batch", ops: ops3 }; return; } switch (state.kind) { case "empty": - this.#state = { kind: "batch", ops: ops2 }; + this.#state = { kind: "batch", ops: ops3 }; return; case "batch": { const folding = { kind: "folding", ops: [], leaves: /* @__PURE__ */ new Map() }; this.#state = folding; if (this.#fold(state.ops, folding)) - this.#fold(ops2, folding); + this.#fold(ops3, folding); return; } case "folding": - this.#fold(ops2, state); + this.#fold(ops3, state); return; case "replace": return; @@ -9201,8 +9201,8 @@ var init_pending = __esm({ } } /** Fold `ops` into `folding`; false once the queue overflowed into `replace`. */ - #fold(ops2, folding) { - for (const op2 of ops2) { + #fold(ops3, folding) { + for (const op2 of ops3) { switch (op2[0]) { case "r": folding.ops.length = 0; @@ -9236,7 +9236,7 @@ var init_pending = __esm({ } }); -// host/js/node_modules/@earendil-works/chord/dist/delta/index.js +// node_modules/@earendil-works/chord/dist/delta/index.js function overlap(a, b, scan2, probe = 64, maxCandidates = 8) { if (a.length === 0 || b.length === 0 || scan2 === 0) return 0; @@ -9428,12 +9428,12 @@ function assertIndexInRange(parent, index) { if (index > parent.length) throw new UnsafePathError(index); } -function apply(target, ops2) { - return applyOps(target, ops2); +function apply(target, ops3) { + return applyOps(target, ops3); } -function applyOps(target, ops2) { +function applyOps(target, ops3) { let root2 = target; - for (const op2 of ops2) { + for (const op2 of ops3) { assertValidOp(op2); if (op2[0] === "r") { root2 = op2[1]; @@ -9502,14 +9502,14 @@ function applyOps(target, ops2) { } return root2; } -function applyImmutable(target, ops2) { - return applyImmutableBatches(target, [ops2]); +function applyImmutable(target, ops3) { + return applyImmutableBatches(target, [ops3]); } function applyImmutableBatches(target, batches) { let root2 = target; const owned = /* @__PURE__ */ new WeakSet(); - for (const ops2 of batches) { - for (const op2 of ops2) { + for (const ops3 of batches) { + for (const op2 of ops3) { assertValidOp(op2); if (op2[0] === "r") { root2 = op2[1]; @@ -9622,10 +9622,10 @@ function encoder() { let nextId = 0; let previous; return { - encode(ops2) { + encode(ops3) { previous = void 0; const out = []; - for (const op2 of ops2) { + for (const op2 of ops3) { if (op2[0] === "r") { out.push(op2); seen.clear(); @@ -9765,7 +9765,7 @@ function decoder() { } var isObj, RESERVED_SEGMENTS, UnsafePathError, PathError, pathKey2; var init_delta = __esm({ - "host/js/node_modules/@earendil-works/chord/dist/delta/index.js"() { + "node_modules/@earendil-works/chord/dist/delta/index.js"() { init_diff(); init_tracker(); init_pending(); @@ -9793,7 +9793,7 @@ var init_delta = __esm({ } }); -// host/js/node_modules/@earendil-works/chord/dist/publish.js +// node_modules/@earendil-works/chord/dist/publish.js function enqueue(task) { queue.push(task); drain(); @@ -9820,22 +9820,22 @@ function drain() { } var queue, held, draining; var init_publish = __esm({ - "host/js/node_modules/@earendil-works/chord/dist/publish.js"() { + "node_modules/@earendil-works/chord/dist/publish.js"() { queue = []; held = 0; draining = false; } }); -// host/js/node_modules/@earendil-works/chord/dist/cell.js +// node_modules/@earendil-works/chord/dist/cell.js function hydrationOf(value2) { if (value2 === null || typeof value2 !== "object") return void 0; return value2[HYDRATION]; } -function unbox(ops2, value2) { +function unbox(ops3, value2) { const result = []; - for (const op2 of ops2) { + for (const op2 of ops3) { if (op2[0] === "r" || op2[1].length === 0) return [["r", value2]]; const path = op2[1].slice(1); @@ -9892,7 +9892,7 @@ function computeDependents(changed, value2, validate2 = true) { } var sequence, Fanout, HYDRATION, unhydrated, Source, Cell, isReadable, Derived, isSource, notReady; var init_cell = __esm({ - "host/js/node_modules/@earendil-works/chord/dist/cell.js"() { + "node_modules/@earendil-works/chord/dist/cell.js"() { init_delta(); init_errors(); init_publish(); @@ -10045,8 +10045,8 @@ var init_cell = __esm({ throw notReady(`state ${this.key} (its init has not run)`); const before = this.value; const diff = options.diff ?? sharesStructure(before, value2); - const ops2 = diff ? diffRevisions(before, value2) : void 0; - this.#publish(this.#tracker.prepareReplace({ v: value2 }), "ops", true, ops2); + const ops3 = diff ? diffRevisions(before, value2) : void 0; + this.#publish(this.#tracker.prepareReplace({ v: value2 }), "ops", true, ops3); } /** * Installs a migrated value and its schema (reload commit). The caller validated the value and the derivations @@ -10057,7 +10057,7 @@ var init_cell = __esm({ this.#publish(this.#tracker.prepareReplace({ v: value2 }), "reset", false); } /** Adopts this revision and every derived one, then queues all notifications (cell first, then derivations). */ - #publish(prepared, type, validate2 = true, ops2) { + #publish(prepared, type, validate2 = true, ops3) { if (prepared.ops.length === 0 && type === "ops") { this.#tracker.adopt(prepared); return; @@ -10074,7 +10074,7 @@ var init_cell = __esm({ } holdPublications(() => { this.#tracker.adopt(prepared); - const published = ops2 !== void 0 && ops2.length > 0 ? ops2 : unbox(prepared.ops, value2); + const published = ops3 !== void 0 && ops3.length > 0 ? ops3 : unbox(prepared.ops, value2); this.fanout.emit(type === "reset" ? { type, value: value2 } : { type, ops: published, value: value2 }); for (const [derived, next2] of candidates) derived.install(next2); @@ -10154,9 +10154,9 @@ var init_cell = __esm({ install(next2) { const before = this.#value; this.#value = next2; - const ops2 = before === void 0 || next2 === void 0 ? [["r", next2 ?? null]] : diffRevisions(before, next2); - if (ops2.length > 0) - this.fanout.emit({ type: "ops", ops: ops2, value: next2 }); + const ops3 = before === void 0 || next2 === void 0 ? [["r", next2 ?? null]] : diffRevisions(before, next2); + if (ops3.length > 0) + this.fanout.emit({ type: "ops", ops: ops3, value: next2 }); } }; isSource = (value2) => value2 instanceof Source; @@ -10164,7 +10164,7 @@ var init_cell = __esm({ } }); -// host/js/node_modules/@earendil-works/chord/dist/object.js +// node_modules/@earendil-works/chord/dist/object.js function checkLifetime(contract, options) { const lifetime = options.lifetime ?? "referenced"; if (lifetime !== "referenced" && lifetime !== "host") @@ -10295,7 +10295,7 @@ function validateImplementation(service, implementation) { } var noop, makeService, hostLifetime, ExposedImpl, ResourceImpl, ResourceFacade, facades, resourceOf, Decls, isStateInit, CtxImpl, REF_BASE, refsByProxy, refOf, MemberReadable, RefImpl, variantOf, sameSelect, ObjectImpl, isReadableLike, SelfImpl; var init_object = __esm({ - "host/js/node_modules/@earendil-works/chord/dist/object.js"() { + "node_modules/@earendil-works/chord/dist/object.js"() { init_cell(); init_contract(); init_errors(); @@ -11640,7 +11640,7 @@ var init_object = __esm({ } }); -// host/js/node_modules/@earendil-works/chord/dist/reload.js +// node_modules/@earendil-works/chord/dist/reload.js function dryRun(candidate) { const { run: run2, migrated, service, object } = candidate; const exposed = memberSchemas(service, run2.implementation); @@ -11720,7 +11720,7 @@ function until(host, ready, ms) { } var ABORTED_ROOTS_GRACE, Reload; var init_reload = __esm({ - "host/js/node_modules/@earendil-works/chord/dist/reload.js"() { + "node_modules/@earendil-works/chord/dist/reload.js"() { init_contract(); init_errors(); init_object(); @@ -12250,7 +12250,7 @@ var init_reload = __esm({ } }); -// host/js/node_modules/@earendil-works/chord/dist/wire.js +// node_modules/@earendil-works/chord/dist/wire.js function toWireError(error) { if (error instanceof ChordError) { return error.reason === void 0 ? { code: error.code, message: error.message } : { code: error.code, message: error.message, reason: error.reason }; @@ -12259,7 +12259,7 @@ function toWireError(error) { } var PROTOCOL_VERSION, Id, Name, Reload2, List, Open, RootRefSchema, WireErrorSchema, WireReloadOptionsSchema, WireReloadReportSchema, FrameSchema, isFrame, fromWireError; var init_wire = __esm({ - "host/js/node_modules/@earendil-works/chord/dist/wire.js"() { + "node_modules/@earendil-works/chord/dist/wire.js"() { init_dist2(); init_contract(); init_errors(); @@ -12399,7 +12399,7 @@ var init_wire = __esm({ } }); -// host/js/node_modules/@earendil-works/chord/dist/cluster.js +// node_modules/@earendil-works/chord/dist/cluster.js function awaitVote(connection, id, deadline) { let timer; const vote = new Promise((resolve2, reject2) => { @@ -12511,7 +12511,7 @@ async function reconcileChild(host, connection) { } var reloadSeq, modulesFor, ChildReloads; var init_cluster = __esm({ - "host/js/node_modules/@earendil-works/chord/dist/cluster.js"() { + "node_modules/@earendil-works/chord/dist/cluster.js"() { init_errors(); init_reload(); init_wire(); @@ -12599,7 +12599,7 @@ var init_cluster = __esm({ } }); -// host/js/node_modules/@earendil-works/chord/dist/link.js +// node_modules/@earendil-works/chord/dist/link.js function unpack(value2) { if (!(value2 instanceof Packed)) return value2; @@ -12702,7 +12702,7 @@ function memoryLinkPair() { } var BaseLink, PACK_THRESHOLD, zlib, Packed, PAYLOAD_FIELDS, encoder2, decoder2, MemoryLink, IpcLink, ipcLink, OPEN, WebSocketLink, webSocketLink; var init_link = __esm({ - "host/js/node_modules/@earendil-works/chord/dist/link.js"() { + "node_modules/@earendil-works/chord/dist/link.js"() { BaseLink = class { #handler; #queue = []; @@ -12912,7 +12912,7 @@ var init_link = __esm({ } }); -// host/js/node_modules/@earendil-works/chord/dist/connection.js +// node_modules/@earendil-works/chord/dist/connection.js async function relayCall(relay, frame, root2, signal, host) { const abortError2 = () => new ChordError("aborted", "call cancelled", { cause: signal.reason }); if (signal.aborted) @@ -12963,7 +12963,7 @@ function clientError(error) { } var DEFAULT_WINDOW, PENDING_WINDOWS, unavailable, RelayRef, RelayCall, Connection, stateKey, unitKey; var init_connection = __esm({ - "host/js/node_modules/@earendil-works/chord/dist/connection.js"() { + "node_modules/@earendil-works/chord/dist/connection.js"() { init_contract(); init_delta(); init_errors(); @@ -14060,7 +14060,7 @@ var init_connection = __esm({ } }); -// host/js/node_modules/@earendil-works/chord/dist/remote.js +// node_modules/@earendil-works/chord/dist/remote.js function deferred() { let resolve2 = noop2; let reject2 = noop2; @@ -14073,7 +14073,7 @@ function deferred() { } var noop2, RemoteBinding, ViewReadable, RemoteRef; var init_remote = __esm({ - "host/js/node_modules/@earendil-works/chord/dist/remote.js"() { + "node_modules/@earendil-works/chord/dist/remote.js"() { init_cell(); init_contract(); init_delta(); @@ -14274,10 +14274,10 @@ var init_remote = __esm({ const target = pending?.values.get(name) ?? this.members.get(name); if (target === void 0) return; - const ops2 = target.decoder.decode(frame.ops ?? []); - target.value = applyImmutable(target.value, ops2); + const ops3 = target.decoder.decode(frame.ops ?? []); + target.value = applyImmutable(target.value, ops3); if (target === this.members.get(name)) - this.#deliver(name, { type: "ops", ops: ops2, value: target.value }); + this.#deliver(name, { type: "ops", ops: ops3, value: target.value }); return; } const fresh = { value: frame.value, decoder: decoder() }; @@ -14649,7 +14649,7 @@ var init_remote = __esm({ } }); -// host/js/node_modules/@earendil-works/chord/dist/host.js +// node_modules/@earendil-works/chord/dist/host.js function createHost(options) { return new HostImpl(options); } @@ -14712,7 +14712,7 @@ function reaches(from, to) { } var defineFacet, isFacet, EMPTY_TABLE, HostImpl, matchesPattern, unknownType; var init_host = __esm({ - "host/js/node_modules/@earendil-works/chord/dist/host.js"() { + "node_modules/@earendil-works/chord/dist/host.js"() { init_cluster(); init_connection(); init_contract(); @@ -15610,10 +15610,10 @@ var init_host = __esm({ } }); -// host/js/node_modules/@earendil-works/chord/dist/registry.js +// node_modules/@earendil-works/chord/dist/registry.js var defineRegistry; var init_registry = __esm({ - "host/js/node_modules/@earendil-works/chord/dist/registry.js"() { + "node_modules/@earendil-works/chord/dist/registry.js"() { defineRegistry = (name, options = {}) => ({ name, conflict: options.conflict ?? "error" @@ -15621,7 +15621,7 @@ var init_registry = __esm({ } }); -// host/js/node_modules/@earendil-works/chord/dist/state.js +// node_modules/@earendil-works/chord/dist/state.js function attachReplicatedStateSource(source, options = {}) { const attachment = source.attach(); try { @@ -15662,7 +15662,7 @@ function isReplicatedStateSource(value2) { } var StateSubscriber, ReplicatedStatePublisher, MutableReplicatedStateImpl, AttachedReplicatedStateImpl; var init_state = __esm({ - "host/js/node_modules/@earendil-works/chord/dist/state.js"() { + "node_modules/@earendil-works/chord/dist/state.js"() { init_context(); init_delta(); StateSubscriber = class { @@ -15893,7 +15893,7 @@ var init_state = __esm({ } }); -// host/js/node_modules/@earendil-works/chord/dist/watch.js +// node_modules/@earendil-works/chord/dist/watch.js function toError2(error) { if (error instanceof Error) return error; @@ -15905,7 +15905,7 @@ function toError2(error) { } var STOPPED, ABORTED, ENDED, WatchLifecycle, Watch, MAX_PENDING_NATIVE_VALUES, NativeWatch; var init_watch = __esm({ - "host/js/node_modules/@earendil-works/chord/dist/watch.js"() { + "node_modules/@earendil-works/chord/dist/watch.js"() { init_context(); init_delta(); STOPPED = { kind: "stopped" }; @@ -16134,8 +16134,8 @@ var init_watch = __esm({ this.#retired = false; if (lone !== void 0) return lone; - const ops2 = batch.kind === "ops" ? batch.ops : [["r", value2]]; - return { kind: "value", value: value2, ops: ops2, retired }; + const ops3 = batch.kind === "ops" ? batch.ops : [["r", value2]]; + return { kind: "value", value: value2, ops: ops3, retired }; } /** The pending failure, or the value after one as a root replacement (no ops were kept since the failure). */ #nextAfterFailure() { @@ -16246,7 +16246,7 @@ var init_watch = __esm({ } }); -// host/js/node_modules/@earendil-works/chord/dist/websocket.js +// node_modules/@earendil-works/chord/dist/websocket.js function acceptWebSockets(server, host, options) { server.on("connection", (socket, request2) => { const link = webSocketLink(socket, { compress: true, acceptPacked: false }); @@ -16259,12 +16259,12 @@ function acceptWebSockets(server, host, options) { }); } var init_websocket = __esm({ - "host/js/node_modules/@earendil-works/chord/dist/websocket.js"() { + "node_modules/@earendil-works/chord/dist/websocket.js"() { init_link(); } }); -// host/js/node_modules/@earendil-works/chord/dist/index.js +// node_modules/@earendil-works/chord/dist/index.js var dist_exports2 = {}; __export(dist_exports2, { ChordError: () => ChordError, @@ -16296,7 +16296,7 @@ __export(dist_exports2, { webSocketLink: () => webSocketLink }); var init_dist3 = __esm({ - "host/js/node_modules/@earendil-works/chord/dist/index.js"() { + "node_modules/@earendil-works/chord/dist/index.js"() { init_contract(); init_errors(); init_host(); @@ -16310,7 +16310,7 @@ var init_dist3 = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/ids.js +// node_modules/@earendil-works/pi-durable/dist/ids.js function idFromNumber(value2) { return value2; } @@ -16318,11 +16318,11 @@ function seqFromNumber(value2) { return value2; } var init_ids = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/ids.js"() { + "node_modules/@earendil-works/pi-durable/dist/ids.js"() { } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/documents.js +// node_modules/@earendil-works/pi-durable/dist/documents.js function defineDoc(definition) { validateDefinition(definition); return { definition }; @@ -16406,13 +16406,13 @@ function materializeDocumentValue(definition, record2, version, value2) { return copyJson(definition.migrate(value2, version)); } var init_documents = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/documents.js"() { + "node_modules/@earendil-works/pi-durable/dist/documents.js"() { init_dist3(); init_ids(); } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/entries.js +// node_modules/@earendil-works/pi-durable/dist/entries.js function defineEntry(kind) { if (typeof kind !== "string" || kind.length === 0) throw new TypeError("Entry kind must be a non-empty string"); @@ -16423,7 +16423,7 @@ function defineEntry(kind) { } var UserEntry, AssistantEntry, SystemEntry, ToolResultEntry, ResetEntry, CompactionEntry; var init_entries = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/entries.js"() { + "node_modules/@earendil-works/pi-durable/dist/entries.js"() { UserEntry = defineEntry("pi.user"); AssistantEntry = defineEntry("pi.assistant"); SystemEntry = defineEntry("pi.system"); @@ -16433,7 +16433,7 @@ var init_entries = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/errors.js +// node_modules/@earendil-works/pi-durable/dist/errors.js function errorMessage(error) { if (error instanceof Error) return error.message; @@ -16445,7 +16445,7 @@ function errorMessage(error) { } var ReadAfterWrite, StorageRequestError, SessionFailed, ReadOnlySession, ConversationBusy, ConversationIdle; var init_errors2 = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/errors.js"() { + "node_modules/@earendil-works/pi-durable/dist/errors.js"() { ReadAfterWrite = class extends Error { /** `operation` names the call, such as `Tx.task()`. */ constructor(operation) { @@ -16490,7 +16490,7 @@ var init_errors2 = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/timers.js +// node_modules/@earendil-works/pi-durable/dist/timers.js function hostTimers(setTimer, report2) { const arm = setTimer ?? nativeTimer; let reported = false; @@ -16524,7 +16524,7 @@ function hostTimers(setTimer, report2) { } var MAX_TIMER_DELAY, inWorkers, nativeTimer; var init_timers = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/timers.js"() { + "node_modules/@earendil-works/pi-durable/dist/timers.js"() { MAX_TIMER_DELAY = 2147483647; inWorkers = typeof navigator !== "undefined" && navigator.userAgent === "Cloudflare-Workers"; nativeTimer = (callback, delayMs, options) => { @@ -16551,7 +16551,7 @@ var init_timers = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/session/cached-storage.js +// node_modules/@earendil-works/pi-durable/dist/session/cached-storage.js function scopeOf(storage2) { if (storage2.publishing === void 0) return void 0; @@ -16566,7 +16566,7 @@ function freeze(value2) { } var CachedStorage, Lru; var init_cached_storage = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/session/cached-storage.js"() { + "node_modules/@earendil-works/pi-durable/dist/session/cached-storage.js"() { CachedStorage = class { #storage; #conversations = new Lru(4096); @@ -16806,7 +16806,7 @@ var init_cached_storage = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/session/conversation-tails.js +// node_modules/@earendil-works/pi-durable/dist/session/conversation-tails.js function use(map2, key) { const value2 = map2.get(key); if (value2 === void 0) @@ -16830,7 +16830,7 @@ function freeze2(value2) { } var LATEST_CAPACITY, MARKER_CAPACITY, ConversationTails; var init_conversation_tails = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/session/conversation-tails.js"() { + "node_modules/@earendil-works/pi-durable/dist/session/conversation-tails.js"() { LATEST_CAPACITY = 4096; MARKER_CAPACITY = 256; ConversationTails = class { @@ -16897,7 +16897,7 @@ var init_conversation_tails = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/session/keys.js +// node_modules/@earendil-works/pi-durable/dist/session/keys.js function taskKey(id) { return `task:${id}`; } @@ -16958,7 +16958,7 @@ function tableKeys(writes, keys) { } var ROOTS_KEY, INTENT_KEY, ALL_KEYS, GatedStorage; var init_keys = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/session/keys.js"() { + "node_modules/@earendil-works/pi-durable/dist/session/keys.js"() { init_documents(); ROOTS_KEY = "roots"; INTENT_KEY = "intent"; @@ -17040,15 +17040,15 @@ var init_keys = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/types.js +// node_modules/@earendil-works/pi-durable/dist/types.js var ROOT_CONVERSATION_ID; var init_types = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/types.js"() { + "node_modules/@earendil-works/pi-durable/dist/types.js"() { ROOT_CONVERSATION_ID = 1; } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/session/forks.js +// node_modules/@earendil-works/pi-durable/dist/session/forks.js async function prepareForkDocumentCopies(storage2, parentConversationId, at2, childConversationId, context) { const entry2 = await storage2.entry(parentConversationId, at2, context); if (entry2 === void 0) @@ -17087,13 +17087,13 @@ async function collectCopies(storage2, scope, at2, policy, childConversationId, } var SCAN_PAGE_SIZE; var init_forks = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/session/forks.js"() { + "node_modules/@earendil-works/pi-durable/dist/session/forks.js"() { init_documents(); SCAN_PAGE_SIZE = 256; } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/session/transaction.js +// node_modules/@earendil-works/pi-durable/dist/session/transaction.js function applySubmissionChange(current, change) { if (current.status === "done" || current.status === "unanswered") return current; @@ -17161,7 +17161,7 @@ function describe(plan, record2) { const change = plan.change; if (change === void 0 || !publishes(plan)) return void 0; - const ops2 = change.loaded === void 0 ? EMPTY_OPERATIONS : change.prepared.ops; + const ops3 = change.loaded === void 0 ? EMPTY_OPERATIONS : change.prepared.ops; return { type: "document", kind: "change", @@ -17169,11 +17169,11 @@ function describe(plan, record2) { conversationId, version: change.version, value: change.prepared.value, - ops: ops2 + ops: ops3 }; } -function storeHeld(hold, ops2, value2, version) { - hold.pending.push(ops2); +function storeHeld(hold, ops3, value2, version) { + hold.pending.push(ops3); const taken = hold.pending.take(); if (taken.kind === "replace") return { content: { version, kind: "base", value: value2 }, ops: [["r", value2]] }; @@ -17186,7 +17186,7 @@ function publishes(plan) { } var INTERNAL_SCAN_PAGE_SIZE, EMPTY_OPERATIONS, TABLE_JSON_COPY_OPTIONS, Transaction; var init_transaction = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/session/transaction.js"() { + "node_modules/@earendil-works/pi-durable/dist/session/transaction.js"() { init_dist3(); init_context(); init_delta(); @@ -18042,7 +18042,7 @@ var init_transaction = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/session/writer.js +// node_modules/@earendil-works/pi-durable/dist/session/writer.js function hop() { if (typeof setImmediate === "function") return new Promise((resolve2) => setImmediate(resolve2)); @@ -18057,7 +18057,7 @@ function hop() { } var SESSION_FAILED, Writer; var init_writer = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/session/writer.js"() { + "node_modules/@earendil-works/pi-durable/dist/session/writer.js"() { init_context(); init_errors2(); SESSION_FAILED = { kind: "failed" }; @@ -18298,7 +18298,7 @@ var init_writer = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/session/session.js +// node_modules/@earendil-works/pi-durable/dist/session/session.js function createSession(storage2, options) { const retention = options?.documentRetentionMs; const within = options?.persistWithinMs; @@ -18412,7 +18412,7 @@ function cancellationError(signal) { } var NO_HOLDS, NO_OPERATIONS, NO_KEYS, MAX_OUTSTANDING, ignore, SETTLED, LISTENER, TELEMETRY, defaultRetention, DEFAULT_PERSIST_WITHIN_MS, SessionImpl, ENDED2, GuardedStorage; var init_session = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/session/session.js"() { + "node_modules/@earendil-works/pi-durable/dist/session/session.js"() { init_dist3(); init_context(); init_delta(); @@ -19233,7 +19233,7 @@ var init_session = __esm({ return { kind: "adoption", error }; } const deadline = this.#clock() + withinMs; - for (const { loaded, ops: ops2, base } of held2) { + for (const { loaded, ops: ops3, base } of held2) { const id = loaded.record.id; let hold = this.#holds.get(id); if (hold === void 0) { @@ -19241,7 +19241,7 @@ var init_session = __esm({ hold = { loaded, pending: new PendingOps(), base: false, deadline, unpin }; this.#holds.set(id, hold); } - hold.pending.push(ops2); + hold.pending.push(ops3); if (base) hold.base = true; if (deadline < hold.deadline) @@ -19824,7 +19824,7 @@ var init_session = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/harness/agent.js +// node_modules/@earendil-works/pi-durable/dist/harness/agent.js function restartLimit(limit2) { return typeof limit2 === "number" && limit2 >= 1 ? Math.floor(limit2) : DEFAULT_RESTART_LIMIT; } @@ -20058,7 +20058,7 @@ function applyWrap(items, target, wrap, nameOf, report2) { } var DEFAULT_RETRY_POLICY, DEFAULT_COMPACTION_POLICY, DEFAULT_PROGRESS_POLICY, INSTRUCTIONS_KEY, AgentDoc, DEFAULT_CONTEXT_RETENTION_MS, DEFAULT_RESTART_LIMIT; var init_agent = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/harness/agent.js"() { + "node_modules/@earendil-works/pi-durable/dist/harness/agent.js"() { init_dist3(); init_documents(); init_session(); @@ -20094,7 +20094,7 @@ var init_agent = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-ai/dist/utils/estimate.js +// node_modules/@earendil-works/pi-ai/dist/utils/estimate.js function calculateContextTokens(usage) { return usage.totalTokens || usage.input + usage.output + usage.cacheRead + usage.cacheWrite; } @@ -20146,14 +20146,14 @@ function estimateToolsTokens(tools) { } var CHARS_PER_TOKEN, ESTIMATED_IMAGE_CHARS; var init_estimate = __esm({ - "host/js/node_modules/@earendil-works/pi-ai/dist/utils/estimate.js"() { + "node_modules/@earendil-works/pi-ai/dist/utils/estimate.js"() { init_text(); CHARS_PER_TOKEN = 3.5; ESTIMATED_IMAGE_CHARS = 4800; } }); -// host/js/node_modules/@earendil-works/pi-ai/dist/utils/retry.js +// node_modules/@earendil-works/pi-ai/dist/utils/retry.js function buildProviderErrorPattern(patterns) { return new RegExp(patterns.join("|"), "i"); } @@ -20223,7 +20223,7 @@ function isRetryableAssistantError(message) { } var NON_RETRYABLE_PROVIDER_LIMIT_ERROR_PATTERN, RETRYABLE_PROVIDER_ERROR_PATTERN, DEFAULT_MAX_AGENT_RETRY_DELAY_MS, RetrySleepAbortError; var init_retry = __esm({ - "host/js/node_modules/@earendil-works/pi-ai/dist/utils/retry.js"() { + "node_modules/@earendil-works/pi-ai/dist/utils/retry.js"() { NON_RETRYABLE_PROVIDER_LIMIT_ERROR_PATTERN = buildProviderErrorPattern([ // OpenCode Go/free-tier limits returned as 429 JSON error types by OpenCode's // Zen API. These are subscription/account limits, not transient throttles. @@ -20339,16 +20339,16 @@ var init_retry = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/tasks.js +// node_modules/@earendil-works/pi-durable/dist/tasks.js function defineTask(definition) { return { definition }; } var init_tasks = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/tasks.js"() { + "node_modules/@earendil-works/pi-durable/dist/tasks.js"() { } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/harness/context.js +// node_modules/@earendil-works/pi-durable/dist/harness/context.js async function captureContextBounds(session, storage2, conversationId, context, at2, visible = false) { let tail; if (at2 === void 0) { @@ -20573,7 +20573,7 @@ function missingResult(call2, timestamp) { } var SCAN_PAGE_SIZE2, EXCLUDED_STOP_REASONS, MISSING_RESULT_TEXT, deeplyFrozen; var init_context3 = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/harness/context.js"() { + "node_modules/@earendil-works/pi-durable/dist/harness/context.js"() { init_entries(); init_ids(); SCAN_PAGE_SIZE2 = 256; @@ -20583,7 +20583,7 @@ var init_context3 = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-ai/dist/utils/overflow.js +// node_modules/@earendil-works/pi-ai/dist/utils/overflow.js function isContextOverflow(message, contextWindow) { if (message.stopReason === "error" && message.errorMessage) { const isNonOverflow = NON_OVERFLOW_PATTERNS.some((p) => p.test(message.errorMessage)); @@ -20618,7 +20618,7 @@ function getOverflowPatterns() { } var OVERFLOW_PATTERNS, CEREBRAS_BODYLESS_OVERFLOW_PATTERN, NON_OVERFLOW_PATTERNS; var init_overflow = __esm({ - "host/js/node_modules/@earendil-works/pi-ai/dist/utils/overflow.js"() { + "node_modules/@earendil-works/pi-ai/dist/utils/overflow.js"() { OVERFLOW_PATTERNS = [ /prompt (?:is )?too long/i, // Anthropic and z.ai token overflow @@ -20688,7 +20688,7 @@ var init_overflow = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/harness/inbox.js +// node_modules/@earendil-works/pi-durable/dist/harness/inbox.js async function prepareBoundary(tx, conversationId, modes, at2, now, incoming) { const head = (await tx.latestHeadMarker(conversationId))?.head; const inbox = await tx.doc(InboxDoc, conversationId); @@ -20784,7 +20784,7 @@ async function withdrawQueuedInputs(tx, conversationId, reason = "aborted") { } var InboxDoc; var init_inbox = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/harness/inbox.js"() { + "node_modules/@earendil-works/pi-durable/dist/harness/inbox.js"() { init_dist3(); init_documents(); init_entries(); @@ -20800,7 +20800,7 @@ var init_inbox = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/harness/json.js +// node_modules/@earendil-works/pi-durable/dist/harness/json.js function assignJson(target, key, value2, plan) { if (plan?.kind === "keep") return; @@ -20836,12 +20836,12 @@ function isRecord(value2) { return typeof value2 === "object" && value2 !== null && !Array.isArray(value2); } var init_json2 = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/harness/json.js"() { + "node_modules/@earendil-works/pi-durable/dist/harness/json.js"() { init_delta(); } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/harness/partial-changes.js +// node_modules/@earendil-works/pi-durable/dist/harness/partial-changes.js function applyChange2(block, change) { const key = change.path.at(-1); if (key === void 0) { @@ -20870,7 +20870,7 @@ function isRecord2(value2) { } var PartialChanges; var init_partial_changes = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/harness/partial-changes.js"() { + "node_modules/@earendil-works/pi-durable/dist/harness/partial-changes.js"() { init_delta(); init_streaming_json(); init_json2(); @@ -20988,7 +20988,7 @@ var init_partial_changes = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/harness/prompt.js +// node_modules/@earendil-works/pi-durable/dist/harness/prompt.js function replaySections(messages) { const shown = /* @__PURE__ */ new Map(); for (const message of messages) { @@ -21094,13 +21094,13 @@ function systemEntry(sections, tools, timestamp) { return { model: [message] }; } var init_prompt = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/harness/prompt.js"() { + "node_modules/@earendil-works/pi-durable/dist/harness/prompt.js"() { init_transcript(); init_entries(); } }); -// host/js/node_modules/@earendil-works/pi-ai/dist/utils/uuid.js +// node_modules/@earendil-works/pi-ai/dist/utils/uuid.js function uuidv7(timestampMs) { const requestedTimestamp = timestampMs ?? Date.now(); if (!Number.isInteger(requestedTimestamp) || requestedTimestamp < 0 || requestedTimestamp > MAX_UUID_V7_TIMESTAMP) { @@ -21133,14 +21133,14 @@ function uuidv7(timestampMs) { } var MAX_UUID_V7_TIMESTAMP, MAX_SEQUENCE, lastOrdinaryTimestamp, sequence2; var init_uuid = __esm({ - "host/js/node_modules/@earendil-works/pi-ai/dist/utils/uuid.js"() { + "node_modules/@earendil-works/pi-ai/dist/utils/uuid.js"() { MAX_UUID_V7_TIMESTAMP = 281474976710655; MAX_SEQUENCE = (1n << 41n) - 1n; lastOrdinaryTimestamp = -1; } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/harness/provider.js +// node_modules/@earendil-works/pi-durable/dist/harness/provider.js async function ensureProviderSessionId(runtime, context) { const existing = await runtime.snapshot(ProviderDoc, runtime.conversationId, context); if (existing !== void 0) @@ -21156,7 +21156,7 @@ async function ensureProviderSessionId(runtime, context) { } var ProviderDoc; var init_provider = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/harness/provider.js"() { + "node_modules/@earendil-works/pi-durable/dist/harness/provider.js"() { init_uuid(); init_documents(); ProviderDoc = defineDoc({ @@ -21171,10 +21171,10 @@ var init_provider = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/harness/telemetry.js +// node_modules/@earendil-works/pi-durable/dist/harness/telemetry.js var entry, reportAttributes, report, submission, DURABLE_TELEMETRY_SCHEMA; var init_telemetry2 = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/harness/telemetry.js"() { + "node_modules/@earendil-works/pi-durable/dist/harness/telemetry.js"() { init_dist(); entry = { description: "A transcript entry was committed; content remains in the transcript.", @@ -21312,7 +21312,7 @@ var init_telemetry2 = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/harness/util.js +// node_modules/@earendil-works/pi-durable/dist/harness/util.js async function scanAll(scan2) { const items = []; let cursor; @@ -21340,7 +21340,7 @@ function conversationEntries(conversationId, query) { } var Waiters; var init_util = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/harness/util.js"() { + "node_modules/@earendil-works/pi-durable/dist/harness/util.js"() { init_errors2(); Waiters = class { #sets = /* @__PURE__ */ new Map(); @@ -21384,7 +21384,7 @@ var init_util = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/harness/scheduler.js +// node_modules/@earendil-works/pi-durable/dist/harness/scheduler.js function blockedSubject(record2) { return { id: record2.id, @@ -21530,7 +21530,7 @@ function jsonEqual(left, right) { } var SCAN_PAGE_SIZE3, NO_KEYS2, LIVE_STATUSES, CONTINUE, PROGRESS, END, CASCADE, TaskScheduler, REGISTRY, SETTINGS, ON_WAKE, TELEMETRY2, endedByCrashesStates; var init_scheduler = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/harness/scheduler.js"() { + "node_modules/@earendil-works/pi-durable/dist/harness/scheduler.js"() { init_dist3(); init_context(); init_delta(); @@ -24029,7 +24029,7 @@ var init_scheduler = __esm({ } }); -// host/js/node_modules/@earendil-works/chord/dist/output.js +// node_modules/@earendil-works/chord/dist/output.js function sanitizeOutput(text) { return text.replace(ESCAPE_SEQUENCE, "").replace(INVALID_OUTPUT, ""); } @@ -24154,7 +24154,7 @@ function countNewlines(text) { } var NEWLINE, INVALID_OUTPUT, ESCAPE_SEQUENCE, encoder3, decoder3, OutputBuffer, runtimeBuffer, nonAsciiPattern, PROGRESS_BYTES_PER_SECOND, SYSTEM_CLOCK, Progress; var init_output = __esm({ - "host/js/node_modules/@earendil-works/chord/dist/output.js"() { + "node_modules/@earendil-works/chord/dist/output.js"() { NEWLINE = 10; INVALID_OUTPUT = /[\x00-\x08\x0b-\x1f\ufff9-\ufffb]/g; ESCAPE_SEQUENCE = /\x1b[\]PX^_][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b\[[\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e]|\x1b[\x20-\x2f]*[\x30-\x7e]/g; @@ -24353,7 +24353,7 @@ var init_output = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/date.js +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/date.js function IsLeapYear(year) { return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0); } @@ -24368,13 +24368,13 @@ function IsDate(value2) { } var DAYS, DATE; var init_date = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/date.js"() { + "node_modules/@earendil-works/pi-schema/dist/formats/typebox/date.js"() { DAYS = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; DATE = /^(\d\d\d\d)-(\d\d)-(\d\d)$/; } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/time.js +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/time.js function IsTime(value2, strictTimeZone = true) { const matches = TIME.exec(value2); if (!matches) @@ -24402,49 +24402,49 @@ function IsTime(value2, strictTimeZone = true) { } var TIME; var init_time = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/time.js"() { + "node_modules/@earendil-works/pi-schema/dist/formats/typebox/time.js"() { TIME = /^(\d\d):(\d\d):(\d\d)(?:\.\d+)?(?:([Zz])|([+-])(\d\d):(\d\d))?$/; } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/date_time.js +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/date_time.js function IsDateTime(value2) { const dateTime = value2.split(/T/i); return dateTime.length === 2 && IsDate(dateTime[0]) && IsTime(dateTime[1]); } var init_date_time = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/date_time.js"() { + "node_modules/@earendil-works/pi-schema/dist/formats/typebox/date_time.js"() { init_date(); init_time(); } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/duration.js +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/duration.js function IsDuration(value2) { return Duration.test(value2); } var Duration; var init_duration = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/duration.js"() { + "node_modules/@earendil-works/pi-schema/dist/formats/typebox/duration.js"() { Duration = /^P((\d+Y(\d+M(\d+D)?)?|\d+M(\d+D)?|\d+D)(T(\d+H(\d+M(\d+S)?)?|\d+M(\d+S)?|\d+S))?|T(\d+H(\d+M(\d+S)?)?|\d+M(\d+S)?|\d+S)|\d+W)$/; } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/email.js +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/email.js function IsEmail(value2) { return Email.test(value2); } var Email; var init_email = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/email.js"() { + "node_modules/@earendil-works/pi-schema/dist/formats/typebox/email.js"() { Email = /^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[^"\\]|\\[\x20-\x7e])*")@(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*|\[(?:IPv6:[a-f0-9:]+|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})\])$/i; } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/idna/pattern/pattern.js +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/idna/pattern/pattern.js var RE_RULE_HYPHEN_PLACEMENT, RE_RULE_NOT_RESERVED_ACE, RE_ASCII_LDH, RE_NON_ASCII, RE_ASCII_DIGIT, RE_ARABIC_INDIC_DIGIT, RE_EXT_ARABIC_INDIC_DIGIT, RE_COMMON_SEPARATOR, RE_EUROPEAN_SEPARATOR, RE_MARK_NONSPACING, RE_MARK_SPACING_COMBINING, RE_COMBINING_MARK, RE_LETTER, RE_NUMBER_DECIMAL, RE_SCRIPT_GREEK, RE_SCRIPT_HEBREW, RE_SCRIPT_JAPANESE, RE_SCRIPT_ARABIC_LETTER, RE_VIRAMA, RE_RFC5892_DISALLOWED, RE_CONTEXTO_EXCEPTIONS, RE_PVALID_EXCEPTIONS, RE_EUROPEAN_NUMBER, RE_PERMITTED_CATEGORY; var init_pattern = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/idna/pattern/pattern.js"() { + "node_modules/@earendil-works/pi-schema/dist/formats/typebox/idna/pattern/pattern.js"() { RE_RULE_HYPHEN_PLACEMENT = /^(?!-).*(? 63; } @@ -24741,14 +24741,14 @@ function IsUnicodeLabel(value2) { return true; } var init_unicode = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/idna/label/unicode.js"() { + "node_modules/@earendil-works/pi-schema/dist/formats/typebox/idna/label/unicode.js"() { init_bidi(); init_puny(); init_pattern(); } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/idna/label/puny.js +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/idna/label/puny.js function IsPunyLabel(value2) { if (!IsAcePrefixed(value2)) return false; @@ -24765,14 +24765,14 @@ function IsPunyLabel(value2) { } } var init_puny2 = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/idna/label/puny.js"() { + "node_modules/@earendil-works/pi-schema/dist/formats/typebox/idna/label/puny.js"() { init_puny(); init_pattern(); init_unicode(); } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/idna/hostname.js +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/idna/hostname.js function IsValidLabelLength(value2) { return value2.length > 0 && value2.length <= 63; } @@ -24787,13 +24787,13 @@ function IsHostname(value2) { return value2.split(".").every((label) => IsLabel(label)); } var init_hostname = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/idna/hostname.js"() { + "node_modules/@earendil-works/pi-schema/dist/formats/typebox/idna/hostname.js"() { init_ascii(); init_puny2(); } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/idna/idn-hostname.js +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/idna/idn-hostname.js function IsValidLabelLength2(value2) { return value2.length > 0 && value2.length <= 63; } @@ -24814,75 +24814,75 @@ function IsIdnHostname(value2) { return labels.every((label) => IsLabel2(label) && (!hasBidiChars || SatisfiesBidiRule(label))); } var init_idn_hostname = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/idna/idn-hostname.js"() { + "node_modules/@earendil-works/pi-schema/dist/formats/typebox/idna/idn-hostname.js"() { init_bidi(); init_puny2(); init_unicode(); } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/idna/index.js +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/idna/index.js var init_idna = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/idna/index.js"() { + "node_modules/@earendil-works/pi-schema/dist/formats/typebox/idna/index.js"() { init_hostname(); init_idn_hostname(); } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/hostname.js +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/hostname.js function IsHostname2(value2) { return IsHostname(value2); } var init_hostname2 = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/hostname.js"() { + "node_modules/@earendil-works/pi-schema/dist/formats/typebox/hostname.js"() { init_idna(); } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/idn_email.js +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/idn_email.js function IsIdnEmail(value2) { return IdnEmail.test(value2.normalize("NFC")); } var IdnEmail; var init_idn_email = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/idn_email.js"() { + "node_modules/@earendil-works/pi-schema/dist/formats/typebox/idn_email.js"() { IdnEmail = /^(?:[A-Za-z0-9!#$%&'*+/=?^_`{|}~\u{0080}-\u{10FFFF}-]+(?:\.[A-Za-z0-9!#$%&'*+/=?^_`{|}~\u{0080}-\u{10FFFF}-]+)*|"(?:[^"\\]|\\.)*")@[\p{L}\p{N}](?:[\p{L}\p{N}-]{0,62})(?^`{|}\\]/; @@ -24903,41 +24903,41 @@ var init_iri = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/iri_reference.js +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/iri_reference.js function IsIriReference(value2) { return !InvalidIriChars2.test(value2) && !MalformedScheme.test(value2) && URL.canParse(value2, "http://example.com"); } var InvalidIriChars2, MalformedScheme; var init_iri_reference = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/iri_reference.js"() { + "node_modules/@earendil-works/pi-schema/dist/formats/typebox/iri_reference.js"() { InvalidIriChars2 = /[\x00-\x20\x7F\\]|%(?![0-9a-fA-F]{2})/; MalformedScheme = /^[a-zA-Z][a-zA-Z0-9+\-.]*\/\//; } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/json_pointer.js +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/json_pointer.js function IsJsonPointer(value2) { return JsonPointer.test(value2); } var JsonPointer; var init_json_pointer = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/json_pointer.js"() { + "node_modules/@earendil-works/pi-schema/dist/formats/typebox/json_pointer.js"() { JsonPointer = /^(?:\/(?:[^~/]|~0|~1)*)*$/; } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/json_pointer_uri_fragment.js +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/json_pointer_uri_fragment.js function IsJsonPointerUriFragment(value2) { return JsonPointerUriFragment.test(value2); } var JsonPointerUriFragment; var init_json_pointer_uri_fragment = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/json_pointer_uri_fragment.js"() { + "node_modules/@earendil-works/pi-schema/dist/formats/typebox/json_pointer_uri_fragment.js"() { JsonPointerUriFragment = /^#(?:\/(?:[a-z0-9_\-.!$&'()*+,;:=@]|%[0-9a-f]{2}|~0|~1)*)*$/i; } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/regex.js +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/regex.js function IsRegex(value2) { try { new RegExp(value2, "u"); @@ -24947,78 +24947,78 @@ function IsRegex(value2) { } } var init_regex = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/regex.js"() { + "node_modules/@earendil-works/pi-schema/dist/formats/typebox/regex.js"() { } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/relative_json_pointer.js +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/relative_json_pointer.js function IsRelativeJsonPointer(value2) { return RelativeJsonPointer.test(value2); } var RelativeJsonPointer; var init_relative_json_pointer = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/relative_json_pointer.js"() { + "node_modules/@earendil-works/pi-schema/dist/formats/typebox/relative_json_pointer.js"() { RelativeJsonPointer = /^(?:0|[1-9][0-9]*)(?:#|(?:\/(?:[^~/]|~0|~1)*)*)$/; } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/uri.js +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/uri.js function IsUri(value2) { return Uri.test(value2); } var Uri; var init_uri = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/uri.js"() { + "node_modules/@earendil-works/pi-schema/dist/formats/typebox/uri.js"() { Uri = /^[a-z][a-z0-9+\-.]*:(?:\/\/(?:(?:[-a-z0-9._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:[\da-f]{1,4}:){6}(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|::(?:[\da-f]{1,4}:){5}(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:[\da-f]{1,4})?::(?:[\da-f]{1,4}:){4}(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:(?:[\da-f]{1,4}:){0,1}[\da-f]{1,4})?::(?:[\da-f]{1,4}:){3}(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:(?:[\da-f]{1,4}:){0,2}[\da-f]{1,4})?::(?:[\da-f]{1,4}:){2}(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:(?:[\da-f]{1,4}:){0,3}[\da-f]{1,4})?::[\da-f]{1,4}:(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:(?:[\da-f]{1,4}:){0,4}[\da-f]{1,4})?::(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:(?:[\da-f]{1,4}:){0,5}[\da-f]{1,4})?::[\da-f]{1,4}|(?:(?:[\da-f]{1,4}:){0,6}[\da-f]{1,4})?::)|v[0-9a-f]+\.[-a-z0-9._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)|(?:[-a-z0-9._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[-a-z0-9._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[-a-z0-9._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[-a-z0-9._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[-a-z0-9._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[-a-z0-9._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?(?:\?(?:[-a-z0-9._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[-a-z0-9._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i; } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/uri_reference.js +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/uri_reference.js function IsUriReference(value2) { return UriReference.test(value2); } var UriReference; var init_uri_reference = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/uri_reference.js"() { + "node_modules/@earendil-works/pi-schema/dist/formats/typebox/uri_reference.js"() { UriReference = /^(?:[a-z][a-z0-9+\-.]*:(?:\/\/(?:(?:[-a-z0-9._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:[\da-f]{1,4}:){6}(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|::(?:[\da-f]{1,4}:){5}(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:[\da-f]{1,4})?::(?:[\da-f]{1,4}:){4}(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:(?:[\da-f]{1,4}:){0,1}[\da-f]{1,4})?::(?:[\da-f]{1,4}:){3}(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:(?:[\da-f]{1,4}:){0,2}[\da-f]{1,4})?::(?:[\da-f]{1,4}:){2}(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:(?:[\da-f]{1,4}:){0,3}[\da-f]{1,4})?::[\da-f]{1,4}:(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:(?:[\da-f]{1,4}:){0,4}[\da-f]{1,4})?::(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:(?:[\da-f]{1,4}:){0,5}[\da-f]{1,4})?::[\da-f]{1,4}|(?:(?:[\da-f]{1,4}:){0,6}[\da-f]{1,4})?::)|v[0-9a-f]+\.[-a-z0-9._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)|(?:[-a-z0-9._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[-a-z0-9._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[-a-z0-9._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[-a-z0-9._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[-a-z0-9._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[-a-z0-9._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:\/\/(?:(?:[-a-z0-9._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:[\da-f]{1,4}:){6}(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|::(?:[\da-f]{1,4}:){5}(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:[\da-f]{1,4})?::(?:[\da-f]{1,4}:){4}(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:(?:[\da-f]{1,4}:){0,1}[\da-f]{1,4})?::(?:[\da-f]{1,4}:){3}(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:(?:[\da-f]{1,4}:){0,2}[\da-f]{1,4})?::(?:[\da-f]{1,4}:){2}(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:(?:[\da-f]{1,4}:){0,3}[\da-f]{1,4})?::[\da-f]{1,4}:(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:(?:[\da-f]{1,4}:){0,4}[\da-f]{1,4})?::(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:(?:[\da-f]{1,4}:){0,5}[\da-f]{1,4})?::[\da-f]{1,4}|(?:(?:[\da-f]{1,4}:){0,6}[\da-f]{1,4})?::)|v[0-9a-f]+\.[-a-z0-9._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)|(?:[-a-z0-9._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[-a-z0-9._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[-a-z0-9._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[-a-z0-9._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[-a-z0-9._~!$&'()*+,;=@]|%[0-9a-f]{2})+(?:\/(?:[-a-z0-9._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)(?:\?(?:[-a-z0-9._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[-a-z0-9._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i; } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/uri_template.js +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/uri_template.js function IsUriTemplate(value2) { return UriTemplate.test(value2); } var UriTemplate; var init_uri_template = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/uri_template.js"() { + "node_modules/@earendil-works/pi-schema/dist/formats/typebox/uri_template.js"() { UriTemplate = /^(?:(?:[^\x00-\x20"<>%\\^`{|}\x7f]|%[0-9a-f]{2})|\{[+#./;?&=,!@|]?(?:[a-z0-9_]|%[0-9a-f]{2})+(?:\.(?:[a-z0-9_]|%[0-9a-f]{2})+)*(?::[1-9]\d{0,3}|\*)?(?:,(?:[a-z0-9_]|%[0-9a-f]{2})+(?:\.(?:[a-z0-9_]|%[0-9a-f]{2})+)*(?::[1-9]\d{0,3}|\*)?)*\})*$/i; } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/url.js +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/url.js function IsUrl(value2) { return URL.canParse(value2); } var init_url = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/url.js"() { + "node_modules/@earendil-works/pi-schema/dist/formats/typebox/url.js"() { } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/uuid.js +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/uuid.js function IsUuid(value2) { return Uuid.test(value2); } var Uuid; var init_uuid2 = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/formats/typebox/uuid.js"() { + "node_modules/@earendil-works/pi-schema/dist/formats/typebox/uuid.js"() { Uuid = /^[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i; } }); -// host/js/node_modules/@earendil-works/pi-schema/dist/formats/index.js +// node_modules/@earendil-works/pi-schema/dist/formats/index.js var formats; var init_formats = __esm({ - "host/js/node_modules/@earendil-works/pi-schema/dist/formats/index.js"() { + "node_modules/@earendil-works/pi-schema/dist/formats/index.js"() { init_date(); init_date_time(); init_duration(); @@ -25066,7 +25066,7 @@ var init_formats = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-ai/dist/utils/validation.js +// node_modules/@earendil-works/pi-ai/dist/utils/validation.js function getValidator(schema) { const cached = validatorCache.get(schema); if (cached) { @@ -25106,14 +25106,14 @@ ${JSON.stringify(toolCall.arguments, null, 2)}`; } var validatorCache; var init_validation = __esm({ - "host/js/node_modules/@earendil-works/pi-ai/dist/utils/validation.js"() { + "node_modules/@earendil-works/pi-ai/dist/utils/validation.js"() { init_dist2(); init_formats(); validatorCache = /* @__PURE__ */ new WeakMap(); } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/truncate.js +// node_modules/@earendil-works/pi-durable/dist/truncate.js function splitLinesForCounting(content) { if (content.length === 0) return []; @@ -25201,14 +25201,14 @@ function truncateHeadOf(prefix, totals, options = {}) { } var DEFAULT_MAX_LINES, DEFAULT_MAX_BYTES; var init_truncate = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/truncate.js"() { + "node_modules/@earendil-works/pi-durable/dist/truncate.js"() { init_output(); DEFAULT_MAX_LINES = 2e3; DEFAULT_MAX_BYTES = 50 * 1024; } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/harness/usage.js +// node_modules/@earendil-works/pi-durable/dist/harness/usage.js async function recordUsage(tx, conversationId, bucket, key, usage) { const totals = (await tx.doc(UsageDoc, conversationId))[bucket]; const total = Object.hasOwn(totals, key) ? totals[key] : void 0; @@ -25250,7 +25250,7 @@ function addUsageState(sum, state) { } var UsageDoc; var init_usage = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/harness/usage.js"() { + "node_modules/@earendil-works/pi-durable/dist/harness/usage.js"() { init_dist3(); init_documents(); UsageDoc = defineDoc({ @@ -25265,7 +25265,7 @@ var init_usage = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/harness/tool.js +// node_modules/@earendil-works/pi-durable/dist/harness/tool.js async function endCutOff(runtime, task, call2, context) { const message = `Tool ${call2.name} was interrupted ${cutOffCount(task)}; it is not run again`; const ending = { status: "failed", message, reason: "restart_limit" }; @@ -25838,7 +25838,7 @@ function jsonEqual2(a, b) { } var MADE_NESTED_CALLS, NestedCallDoc, ToolTask, structuredValidators, COMPLETED, MAX_SUMMARY_ERROR_CHARS; var init_tool = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/harness/tool.js"() { + "node_modules/@earendil-works/pi-durable/dist/harness/tool.js"() { init_dist3(); init_context(); init_delta(); @@ -25966,7 +25966,7 @@ var init_tool = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/harness/generation.js +// node_modules/@earendil-works/pi-durable/dist/harness/generation.js async function readCalls(runtime, assistant, callIds, context) { const message = (await runtime.entry(AssistantEntry, assistant, context))?.model?.[0]; const calls = message?.role === "assistant" ? message.content.filter((content) => content.type === "toolCall") : []; @@ -26488,7 +26488,7 @@ function handOver(live, from, to) { } var DEFAULT_POLL_AFTER_MS, GenerationTask; var init_generation = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/harness/generation.js"() { + "node_modules/@earendil-works/pi-durable/dist/harness/generation.js"() { init_dist3(); init_overflow(); init_retry(); @@ -26751,7 +26751,7 @@ var init_generation = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/harness/live.js +// node_modules/@earendil-works/pi-durable/dist/harness/live.js function renameReason(value2) { return Object.fromEntries(Object.entries(value2).map(([key, field]) => [key === "reason" ? "trigger" : key, field])); } @@ -26898,7 +26898,7 @@ async function settleSchedulerOutcome(tx, record2, outcome) { } var LiveDoc, PROGRESS_COMMIT, RUN_TASK_KINDS, TOOL_TASK_KIND, COMPACTION_TASK_KIND, LIMITS_RESTARTS; var init_live = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/harness/live.js"() { + "node_modules/@earendil-works/pi-durable/dist/harness/live.js"() { init_documents(); init_generation(); LiveDoc = defineDoc({ @@ -26936,7 +26936,7 @@ var init_live = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/harness/submissions.js +// node_modules/@earendil-works/pi-durable/dist/harness/submissions.js function isSettled(record2) { return record2.status === "done" || record2.status === "unanswered"; } @@ -27032,7 +27032,7 @@ async function admitSubmission(tx, conversationId, draft, now, queueModes, span) } var Submissions, SubmissionHandle; var init_submissions = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/harness/submissions.js"() { + "node_modules/@earendil-works/pi-durable/dist/harness/submissions.js"() { init_dist3(); init_context(); init_dist(); @@ -27175,7 +27175,7 @@ var init_submissions = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/harness/compaction.js +// node_modules/@earendil-works/pi-durable/dist/harness/compaction.js async function createCompaction(tx, conversationId, input, owner) { const ownership = owner === void 0 ? { kind: "conversation" } : { kind: "task", taskId: owner }; const background = owner === void 0 && input.reason !== "manual"; @@ -27369,7 +27369,7 @@ async function failNoModel2(runtime, ref, context) { } var TOOL_RESULT_MAX_CHARS, SUMMARY_PREFIX, SUMMARY_SUFFIX, SUMMARIZATION_SYSTEM_PROMPT, SUMMARIZATION_PROMPT, CompactionTask; var init_compaction = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/harness/compaction.js"() { + "node_modules/@earendil-works/pi-durable/dist/harness/compaction.js"() { init_estimate(); init_retry(); init_entries(); @@ -27549,7 +27549,7 @@ Keep each section concise. Preserve exact file paths, function names, and error } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/harness/define.js +// node_modules/@earendil-works/pi-durable/dist/harness/define.js function defineExtension(extension) { return extension; } @@ -27572,11 +27572,11 @@ function wrapSection(key, wrapper) { return { section: key, wrap: wrapper }; } var init_define = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/harness/define.js"() { + "node_modules/@earendil-works/pi-durable/dist/harness/define.js"() { } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/harness/registry.js +// node_modules/@earendil-works/pi-durable/dist/harness/registry.js function validateExtension(extension) { const tools = /* @__PURE__ */ new Set(); for (const tool of extension.tools ?? []) { @@ -27600,7 +27600,7 @@ function createRegistry() { } var SECTION_KEY, BUILTIN_TASKS, RegistryState, RegistryImpl; var init_registry2 = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/harness/registry.js"() { + "node_modules/@earendil-works/pi-durable/dist/harness/registry.js"() { init_agent(); init_compaction(); init_generation(); @@ -27679,9 +27679,9 @@ var init_registry2 = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/harness/task-graph.js +// node_modules/@earendil-works/pi-durable/dist/harness/task-graph.js function advance(mount, publication, context, blocked, report2) { - const ops2 = []; + const ops3 = []; const changed = /* @__PURE__ */ new Map(); const node = (key) => changed.has(key) ? changed.get(key) : mount.value.tasks[key]; for (const change of publication.changes) { @@ -27694,7 +27694,7 @@ function advance(mount, publication, context, blocked, report2) { mount.records.delete(key); if (previous === void 0) continue; - ops2.push(["d", ["tasks", key]]); + ops3.push(["d", ["tasks", key]]); changed.set(key, void 0); continue; } @@ -27703,7 +27703,7 @@ function advance(mount, publication, context, blocked, report2) { const next2 = nodeOf2(record2, previous?.conversations ?? [], blocked(subject)); if (previous !== void 0 && JSON.stringify(next2) === JSON.stringify(previous)) continue; - ops2.push(["s", ["tasks", key], next2]); + ops3.push(["s", ["tasks", key], next2]); changed.set(key, next2); } const created = /* @__PURE__ */ new Map(); @@ -27716,16 +27716,16 @@ function advance(mount, publication, context, blocked, report2) { } for (const [key, ids] of created) { const conversations = [...node(key).conversations, ...ids].sort((a, b) => a - b); - ops2.push(["s", ["tasks", key, "conversations"], conversations]); + ops3.push(["s", ["tasks", key, "conversations"], conversations]); } - publish(mount, ops2, context, report2); + publish(mount, ops3, context, report2); } -function publish(mount, ops2, context, report2) { - if (ops2.length === 0) +function publish(mount, ops3, context, report2) { + if (ops3.length === 0) return; - mount.value = applyImmutable(mount.value, ops2); + mount.value = applyImmutable(mount.value, ops3); const frameContext = withoutAbortSignal(context); - const call2 = { kind: "value", value: mount.value, ops: ops2, retired: false }; + const call2 = { kind: "value", value: mount.value, ops: ops3, retired: false }; for (const observer of [...mount.observers]) contained(() => observer.advance(call2, frameContext), report2); } @@ -27763,7 +27763,7 @@ function phaseOf(checkpoint) { } var LIVE_STATUSES2, SCAN_PAGE_SIZE4, TaskGraphView; var init_task_graph = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/harness/task-graph.js"() { + "node_modules/@earendil-works/pi-durable/dist/harness/task-graph.js"() { init_dist3(); init_context(); init_delta(); @@ -27853,14 +27853,14 @@ var init_task_graph = __esm({ const mount = this.#mount; if (mount === void 0) return; - const ops2 = []; + const ops3 = []; for (const [key, record2] of mount.records) { const blocked = this.#blocking.blocked(record2); if (blocked === mount.value.tasks[key]?.blocked) continue; - ops2.push(blocked === void 0 ? ["d", ["tasks", key, "blocked"]] : ["s", ["tasks", key, "blocked"], blocked]); + ops3.push(blocked === void 0 ? ["d", ["tasks", key, "blocked"]] : ["s", ["tasks", key, "blocked"], blocked]); } - publish(mount, ops2, BACKGROUND_CONTEXT, (error) => this.#session.report(error)); + publish(mount, ops3, BACKGROUND_CONTEXT, (error) => this.#session.report(error)); }).catch(() => { }); } @@ -27886,7 +27886,7 @@ var init_task_graph = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/harness/view.js +// node_modules/@earendil-works/pi-durable/dist/harness/view.js function resolveWindow(window) { const min = window?.min ?? DEFAULT_WINDOW_MIN; if (!Number.isSafeInteger(min) || min < 1) @@ -27966,19 +27966,19 @@ function advance2(id, mount, publication, context, report2) { const previous = windowed.value; let entries2 = previous.entries; let before = previous.before; - let ops2 = docOps; + let ops3 = docOps; if (appended.length > 0) { - ops2 = [...docOps, ["p", ["entries"], entries2.length, 0, inserted]]; + ops3 = [...docOps, ["p", ["entries"], entries2.length, 0, inserted]]; entries2 = entries2.concat(appended); if (entries2.length > windowed.max) { const drop = entries2.length - windowed.min; before = entries2[drop - 1].id; entries2 = entries2.slice(drop); - ops2.push(["p", ["entries"], 0, drop, []], ["s", ["before"], before]); + ops3.push(["p", ["entries"], 0, drop, []], ["s", ["before"], before]); } } windowed.value = view(mount.conversation, entries2, before, mount.docs); - const call2 = { kind: "value", value: windowed.value, ops: ops2, retired: false }; + const call2 = { kind: "value", value: windowed.value, ops: ops3, retired: false }; contained(() => windowed.observer.advance(call2, frameContext), report2); } } @@ -28003,7 +28003,7 @@ function prefixed(op2, prefix) { } var DEFAULT_WINDOW_MIN, MOUNTED, MOUNTED_KINDS, SCAN_PAGE_SIZE5, VIEWS, ConversationViews; var init_view = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/harness/view.js"() { + "node_modules/@earendil-works/pi-durable/dist/harness/view.js"() { init_dist3(); init_context(); init_delta(); @@ -28127,7 +28127,7 @@ var init_view = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/harness/harness.js +// node_modules/@earendil-works/pi-durable/dist/harness/harness.js function currentModels(models2, identity) { const merged = mergeClientIdentity(DEFAULT_HARNESS_IDENTITY, identity) ?? DEFAULT_HARNESS_IDENTITY; if (typeof models2 === "function") @@ -28223,7 +28223,7 @@ function boundConversation(id, binding, submissions, tasks) { } var SCAN_PAGE_SIZE6, SCHEDULER_INDEX_SIZES, SCHEDULER_IDLE_STATE, ConversationImpl, DEFAULT_HARNESS_IDENTITY, HarnessImpl, Harness; var init_harness = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/harness/harness.js"() { + "node_modules/@earendil-works/pi-durable/dist/harness/harness.js"() { init_context(); init_identity(); init_dist(); @@ -28533,7 +28533,7 @@ var init_harness = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/harness/registry-reader.js +// node_modules/@earendil-works/pi-durable/dist/harness/registry-reader.js function registryReader(value2, context) { return { snapshot: () => value2.value, @@ -28551,11 +28551,11 @@ function registryReader(value2, context) { }; } var init_registry_reader = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/harness/registry-reader.js"() { + "node_modules/@earendil-works/pi-durable/dist/harness/registry-reader.js"() { } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/harness/transcript.js +// node_modules/@earendil-works/pi-durable/dist/harness/transcript.js function gapOf(after, upTo) { return Object.freeze({ kind: "gap", after: idFromNumber(after), upTo: idFromNumber(upTo) }); } @@ -28574,7 +28574,7 @@ function mergeById(left, right) { } var EARLIER, ConversationTranscript; var init_transcript2 = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/harness/transcript.js"() { + "node_modules/@earendil-works/pi-durable/dist/harness/transcript.js"() { init_ids(); EARLIER = Object.freeze({ kind: "earlier" }); ConversationTranscript = class { @@ -28793,7 +28793,7 @@ var init_transcript2 = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/storage/scan.js +// node_modules/@earendil-works/pi-durable/dist/storage/scan.js function scanStart(requested, cursor, fallback) { if (requested !== void 0 && requested !== "ascending" && requested !== "descending") { throw new StorageRequestError(`Invalid scan order: ${String(requested)}`); @@ -28816,12 +28816,12 @@ function nextCursor(id, order) { return { after: id, order }; } var init_scan = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/storage/scan.js"() { + "node_modules/@earendil-works/pi-durable/dist/storage/scan.js"() { init_errors2(); } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/storage/memory.js +// node_modules/@earendil-works/pi-durable/dist/storage/memory.js function* documentDeltaBatches(id, version, revisions, start) { for (let index = start; index < revisions.length; index++) { const revision = revisions[index]; @@ -28844,7 +28844,7 @@ function* scanIndexes(ids, start) { } var clone, freeze3, cursorId, lowerBound2, upperBound, insertSorted, removeSorted, insertMapId, scopeKey2, addressKey, recordAddressKey, isAliveAt, isCurrentOnly, tableContaining, page, MemoryStorage; var init_memory2 = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/storage/memory.js"() { + "node_modules/@earendil-works/pi-durable/dist/storage/memory.js"() { init_delta(); init_errors2(); init_ids(); @@ -29554,7 +29554,7 @@ var init_memory2 = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/index.js +// node_modules/@earendil-works/pi-durable/dist/index.js var dist_exports3 = {}; __export(dist_exports3, { AgentDoc: () => AgentDoc, @@ -29605,7 +29605,7 @@ __export(dist_exports3, { wrapTool: () => wrapTool }); var init_dist4 = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/index.js"() { + "node_modules/@earendil-works/pi-durable/dist/index.js"() { init_documents(); init_entries(); init_errors2(); @@ -29630,7 +29630,7 @@ var init_dist4 = __esm({ } }); -// host/js/node_modules/@earendil-works/chord/dist/sqlite/schema.js +// node_modules/@earendil-works/chord/dist/sqlite/schema.js function validateSqliteSchemaPrefix(prefix) { if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(prefix)) { throw new Error(`Invalid SQLite schema prefix ${JSON.stringify(prefix)}`); @@ -29640,11 +29640,11 @@ function validateSqliteSchemaPrefix(prefix) { } } var init_schema2 = __esm({ - "host/js/node_modules/@earendil-works/chord/dist/sqlite/schema.js"() { + "node_modules/@earendil-works/chord/dist/sqlite/schema.js"() { } }); -// host/js/node_modules/@earendil-works/chord/dist/sqlite/migrations.js +// node_modules/@earendil-works/chord/dist/sqlite/migrations.js async function applySqliteMigrations(database, migrations, options) { const { table } = options; validateSqliteSchemaPrefix(table); @@ -29676,20 +29676,20 @@ async function applySqliteMigrations(database, migrations, options) { }); } var init_migrations = __esm({ - "host/js/node_modules/@earendil-works/chord/dist/sqlite/migrations.js"() { + "node_modules/@earendil-works/chord/dist/sqlite/migrations.js"() { init_schema2(); } }); -// host/js/node_modules/@earendil-works/chord/dist/sqlite/index.js +// node_modules/@earendil-works/chord/dist/sqlite/index.js var init_sqlite = __esm({ - "host/js/node_modules/@earendil-works/chord/dist/sqlite/index.js"() { + "node_modules/@earendil-works/chord/dist/sqlite/index.js"() { init_migrations(); init_schema2(); } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/storage/sqlite/schema.js +// node_modules/@earendil-works/pi-durable/dist/storage/sqlite/schema.js function prefixIdentifiers(names2, prefix) { return Object.fromEntries(Object.entries(names2).map(([key, name]) => [key, `${prefix}${name}`])); } @@ -29704,7 +29704,7 @@ function createSqliteSchema(prefix) { } var TABLE_NAMES, INDEX_NAMES, DEFAULT_SQLITE_SCHEMA; var init_schema3 = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/storage/sqlite/schema.js"() { + "node_modules/@earendil-works/pi-durable/dist/storage/sqlite/schema.js"() { init_sqlite(); TABLE_NAMES = { durableSchema: "durable_schema", @@ -29739,7 +29739,7 @@ var init_schema3 = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/storage/sqlite/migrations.js +// node_modules/@earendil-works/pi-durable/dist/storage/sqlite/migrations.js function createSqliteMigrations(schema) { const { tables, indexes } = schema; const initialSchema = [ @@ -29850,7 +29850,7 @@ async function applySqliteMigrationsForSchema(database, schema, migrations = cre } var SQLITE_MIGRATIONS, CURRENT_SQLITE_SCHEMA_VERSION; var init_migrations2 = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/storage/sqlite/migrations.js"() { + "node_modules/@earendil-works/pi-durable/dist/storage/sqlite/migrations.js"() { init_sqlite(); init_schema3(); SQLITE_MIGRATIONS = createSqliteMigrations(DEFAULT_SQLITE_SCHEMA); @@ -29858,7 +29858,7 @@ var init_migrations2 = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/storage/sqlite/storage.js +// node_modules/@earendil-works/pi-durable/dist/storage/sqlite/storage.js function watchCalls(executor, calls) { const watched = async (call2) => { try { @@ -29878,7 +29878,7 @@ function watchCalls(executor, calls) { } var parseJson, encodeJson, encodeIndexedString, cursorId2, page2, scanSql, scopeColumns, addressParts, addressKey2, isAliveAt2, isCurrentOnly2, writeId, SqliteStorage; var init_storage = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/storage/sqlite/storage.js"() { + "node_modules/@earendil-works/pi-durable/dist/storage/sqlite/storage.js"() { init_delta(); init_errors2(); init_ids(); @@ -30570,14 +30570,14 @@ var init_storage = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/storage/sqlite/index.js +// node_modules/@earendil-works/pi-durable/dist/storage/sqlite/index.js var init_sqlite2 = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/storage/sqlite/index.js"() { + "node_modules/@earendil-works/pi-durable/dist/storage/sqlite/index.js"() { init_storage(); } }); -// host/js/sqlite.ts +// sqlite.ts async function openStorage(path) { op("open", path); let tail = Promise.resolve(); @@ -30618,24 +30618,24 @@ async function openStorage(path) { } var op; var init_sqlite3 = __esm({ - "host/js/sqlite.ts"() { + "sqlite.ts"() { init_sqlite2(); op = (kind, sql = "", params = []) => Deno.core.ops.op_sql(kind, sql, params.map((p) => p instanceof Uint8Array ? Array.from(p) : typeof p === "bigint" ? Number(p) : p)); } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/tools/env.js +// node_modules/@earendil-works/pi-durable/dist/tools/env.js function requireEnv(api) { if (api.env === void 0) throw new Error("No execution environment is configured"); return api.env; } var init_env = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/tools/env.js"() { + "node_modules/@earendil-works/pi-durable/dist/tools/env.js"() { } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/tools/bash.js +// node_modules/@earendil-works/pi-durable/dist/tools/bash.js function validateTimeout(timeout) { if (timeout === void 0) return; @@ -30736,7 +30736,7 @@ ${execution.command}`; } var MAX_TIMEOUT_SECONDS, bashSchema, powershellSchema, shellStructuredOutputSchema, UTF8_OUTPUT, POWERSHELL_ARGS; var init_bash = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/tools/bash.js"() { + "node_modules/@earendil-works/pi-durable/dist/tools/bash.js"() { init_dist2(); init_define(); init_truncate(); @@ -30761,10 +30761,10 @@ var init_bash = __esm({ } }); -// host/js/node_modules/diff/libesm/diff/base.js +// node_modules/diff/libesm/diff/base.js var Diff; var init_base = __esm({ - "host/js/node_modules/diff/libesm/diff/base.js"() { + "node_modules/diff/libesm/diff/base.js"() { Diff = class { diff(oldStr, newStr, options = {}) { let callback; @@ -30968,7 +30968,7 @@ var init_base = __esm({ } }); -// host/js/node_modules/diff/libesm/diff/line.js +// node_modules/diff/libesm/diff/line.js function diffLines(oldStr, newStr, options) { return lineDiff.diff(oldStr, newStr, options); } @@ -30992,7 +30992,7 @@ function tokenize(value2, options) { } var LineDiff, lineDiff; var init_line = __esm({ - "host/js/node_modules/diff/libesm/diff/line.js"() { + "node_modules/diff/libesm/diff/line.js"() { init_base(); LineDiff = class extends Diff { constructor() { @@ -31022,7 +31022,7 @@ var init_line = __esm({ } }); -// host/js/node_modules/diff/libesm/patch/create.js +// node_modules/diff/libesm/patch/create.js function structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) { let optionsObj; if (!options) { @@ -31198,7 +31198,7 @@ function splitLines(text) { } var INCLUDE_HEADERS, FILE_HEADERS_ONLY; var init_create = __esm({ - "host/js/node_modules/diff/libesm/patch/create.js"() { + "node_modules/diff/libesm/patch/create.js"() { init_line(); INCLUDE_HEADERS = { includeIndex: true, @@ -31213,15 +31213,15 @@ var init_create = __esm({ } }); -// host/js/node_modules/diff/libesm/index.js +// node_modules/diff/libesm/index.js var init_libesm = __esm({ - "host/js/node_modules/diff/libesm/index.js"() { + "node_modules/diff/libesm/index.js"() { init_line(); init_create(); } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/tools/edit-diff.js +// node_modules/@earendil-works/pi-durable/dist/tools/edit-diff.js function detectLineEnding(content) { const crlfIdx = content.indexOf("\r\n"); const lfIdx = content.indexOf("\n"); @@ -31530,12 +31530,12 @@ function generateDiffString(oldContent, newContent, contextLines = 4) { return { diff: output.join("\n"), firstChangedLine }; } var init_edit_diff = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/tools/edit-diff.js"() { + "node_modules/@earendil-works/pi-durable/dist/tools/edit-diff.js"() { init_libesm(); } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/env/decode.js +// node_modules/@earendil-works/pi-durable/dist/env/decode.js function rangeDecoder() { return new TextDecoder("utf-8", { ignoreBOM: true }); } @@ -31543,23 +31543,23 @@ function startsWithBom(firstBytes) { return firstBytes[0] === 239 && firstBytes[1] === 187 && firstBytes[2] === 191; } var init_decode = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/env/decode.js"() { + "node_modules/@earendil-works/pi-durable/dist/env/decode.js"() { } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/env/index.js +// node_modules/@earendil-works/pi-durable/dist/env/index.js function getOrThrow(result) { if (!result.ok) throw result.error; return result.value; } var init_env2 = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/env/index.js"() { + "node_modules/@earendil-works/pi-durable/dist/env/index.js"() { init_decode(); } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/tools/file-mutation-queue.js +// node_modules/@earendil-works/pi-durable/dist/tools/file-mutation-queue.js async function mutationKey(env, path, context) { const absolutePath = getOrThrow(await env.absolutePath(path, context)); return `${env.id}\0${await canonical(env, absolutePath, context)}`; @@ -31599,13 +31599,13 @@ async function withFileMutationQueue(env, path, fn, context) { } var queues; var init_file_mutation_queue = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/tools/file-mutation-queue.js"() { + "node_modules/@earendil-works/pi-durable/dist/tools/file-mutation-queue.js"() { init_env2(); queues = /* @__PURE__ */ new Map(); } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/tools/path-utils.js +// node_modules/@earendil-works/pi-durable/dist/tools/path-utils.js function normalizeToolPath(path) { const normalized = path.replace(UNICODE_SPACES, " "); return normalized.startsWith("@") ? normalized.slice(1) : normalized; @@ -31630,14 +31630,14 @@ async function resolveReadToolPath(env, path, context) { } var UNICODE_SPACES, NARROW_NO_BREAK_SPACE; var init_path_utils = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/tools/path-utils.js"() { + "node_modules/@earendil-works/pi-durable/dist/tools/path-utils.js"() { init_env2(); UNICODE_SPACES = /[\u00A0\u2000-\u200A\u202F\u205F\u3000]/g; NARROW_NO_BREAK_SPACE = "\u202F"; } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/tools/edit.js +// node_modules/@earendil-works/pi-durable/dist/tools/edit.js function isSingleEditInput(value2) { if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) return false; @@ -31730,7 +31730,7 @@ function createEditTool() { } var replaceEditSchema, editSchema; var init_edit = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/tools/edit.js"() { + "node_modules/@earendil-works/pi-durable/dist/tools/edit.js"() { init_dist2(); init_define(); init_edit_diff(); @@ -31752,7 +31752,7 @@ var init_edit = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/tools/image.js +// node_modules/@earendil-works/pi-durable/dist/tools/image.js async function detectSupportedImageMimeTypeOf(source) { const header = await source.read(0, HEADER_BYTES); if (!startsWith(header, PNG_SIGNATURE)) @@ -31910,14 +31910,14 @@ function startsWithAscii(buffer, offset, text) { } var PNG_SIGNATURE, HEADER_BYTES, BLOCK_BYTES; var init_image = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/tools/image.js"() { + "node_modules/@earendil-works/pi-durable/dist/tools/image.js"() { PNG_SIGNATURE = [137, 80, 78, 71, 13, 10, 26, 10]; HEADER_BYTES = 32; BLOCK_BYTES = 64 * 1024; } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/tools/image-processor.js +// node_modules/@earendil-works/pi-durable/dist/tools/image-processor.js function toBase64(bytes2) { const parts = []; for (let i = 0; i < bytes2.length; i += 8192) { @@ -31930,13 +31930,13 @@ function base64Length(byteLength) { } var DEFAULT_IMAGE_LIMITS, INLINE_IMAGE_TYPES; var init_image_processor = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/tools/image-processor.js"() { + "node_modules/@earendil-works/pi-durable/dist/tools/image-processor.js"() { DEFAULT_IMAGE_LIMITS = { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4.5 * 1024 * 1024 }; INLINE_IMAGE_TYPES = /* @__PURE__ */ new Set(["image/png", "image/jpeg", "image/gif", "image/webp"]); } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/tools/read.js +// node_modules/@earendil-works/pi-durable/dist/tools/read.js function sliceIndex(value2) { return Number.isNaN(value2) ? 0 : Math.trunc(value2); } @@ -32123,7 +32123,7 @@ async function readText(reader, path, offset, limit2, context) { } var readSchema, readStructuredOutputSchema, READ_CHUNK; var init_read = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/tools/read.js"() { + "node_modules/@earendil-works/pi-durable/dist/tools/read.js"() { init_output(); init_dist2(); init_env2(); @@ -32146,7 +32146,7 @@ var init_read = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/tools/write.js +// node_modules/@earendil-works/pi-durable/dist/tools/write.js function createWriteTool() { return defineTool({ name: "write", @@ -32169,7 +32169,7 @@ function createWriteTool() { } var writeSchema; var init_write = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/tools/write.js"() { + "node_modules/@earendil-works/pi-durable/dist/tools/write.js"() { init_dist2(); init_env2(); init_define(); @@ -32183,7 +32183,7 @@ var init_write = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-durable/dist/tools/index.js +// node_modules/@earendil-works/pi-durable/dist/tools/index.js var tools_exports = {}; __export(tools_exports, { CodingTools: () => CodingTools, @@ -32203,7 +32203,7 @@ function createCodingTools(options = {}) { } var CodingTools; var init_tools = __esm({ - "host/js/node_modules/@earendil-works/pi-durable/dist/tools/index.js"() { + "node_modules/@earendil-works/pi-durable/dist/tools/index.js"() { init_define(); init_bash(); init_edit(); @@ -32218,7 +32218,7 @@ var init_tools = __esm({ } }); -// host/js/node_modules/@earendil-works/pi-ai/dist/auth/helpers.js +// node_modules/@earendil-works/pi-ai/dist/auth/helpers.js function envApiKeyAuth(name, envVars) { return { name, @@ -32259,17 +32259,17 @@ function lazyOAuth(input) { }; } var init_helpers = __esm({ - "host/js/node_modules/@earendil-works/pi-ai/dist/auth/helpers.js"() { + "node_modules/@earendil-works/pi-ai/dist/auth/helpers.js"() { } }); -// host/js/node_modules/@earendil-works/pi-ai/dist/auth/types.js +// node_modules/@earendil-works/pi-ai/dist/auth/types.js var init_types2 = __esm({ - "host/js/node_modules/@earendil-works/pi-ai/dist/auth/types.js"() { + "node_modules/@earendil-works/pi-ai/dist/auth/types.js"() { } }); -// host/js/node_modules/@earendil-works/pi-ai/dist/session-resources.js +// node_modules/@earendil-works/pi-ai/dist/session-resources.js function registerSessionResourceCleanup(cleanup) { sessionResourceCleanups.add(cleanup); return () => { @@ -32291,18 +32291,18 @@ function cleanupSessionResources(sessionId) { } var sessionResourceCleanups; var init_session_resources = __esm({ - "host/js/node_modules/@earendil-works/pi-ai/dist/session-resources.js"() { + "node_modules/@earendil-works/pi-ai/dist/session-resources.js"() { sessionResourceCleanups = /* @__PURE__ */ new Set(); } }); -// host/js/node_modules/@earendil-works/pi-ai/dist/types.js +// node_modules/@earendil-works/pi-ai/dist/types.js var init_types3 = __esm({ - "host/js/node_modules/@earendil-works/pi-ai/dist/types.js"() { + "node_modules/@earendil-works/pi-ai/dist/types.js"() { } }); -// host/js/node_modules/@earendil-works/pi-ai/dist/utils/string-enum.js +// node_modules/@earendil-works/pi-ai/dist/utils/string-enum.js function StringEnum(values, options) { return { type: "string", @@ -32312,11 +32312,11 @@ function StringEnum(values, options) { }; } var init_string_enum = __esm({ - "host/js/node_modules/@earendil-works/pi-ai/dist/utils/string-enum.js"() { + "node_modules/@earendil-works/pi-ai/dist/utils/string-enum.js"() { } }); -// host/js/node_modules/@earendil-works/pi-ai/dist/index.js +// node_modules/@earendil-works/pi-ai/dist/index.js var dist_exports4 = {}; __export(dist_exports4, { AI_TELEMETRY_SCHEMA: () => AI_TELEMETRY_SCHEMA, @@ -32399,7 +32399,7 @@ __export(dist_exports4, { withoutInitialSystemMessage: () => withoutInitialSystemMessage }); var init_dist5 = __esm({ - "host/js/node_modules/@earendil-works/pi-ai/dist/index.js"() { + "node_modules/@earendil-works/pi-ai/dist/index.js"() { init_lazy(); init_context2(); init_credential_store(); @@ -32426,7 +32426,7 @@ var init_dist5 = __esm({ } }); -// host/js/events.ts +// events.ts var events_exports = {}; __export(events_exports, { EVENT_FEED: () => EVENT_FEED, @@ -32575,7 +32575,7 @@ function eventLog(harness2) { } var NoticeEvent, EVENT_FEED, EVENT_FEED_SIZE, EventLog, EventFeed, record; var init_events = __esm({ - "host/js/events.ts"() { + "events.ts"() { init_context(); init_dist4(); NoticeEvent = defineEvent("sausage.notice"); @@ -32603,22 +32603,72 @@ var init_events = __esm({ } }); -// host/js/extensions.ts +// environment.ts +function conversationChains(harness2, context) { + const cache = /* @__PURE__ */ new Map(); + const chain = (id) => { + let result = cache.get(id); + if (!result) { + result = (async () => { + const record2 = await harness2.commit((tx) => tx.conversation(id), context); + const up = record2?.owner?.conversationId ?? record2?.parent?.conversationId; + const starter = (await harness2.snapshot(Started, id, context))?.by; + return [.../* @__PURE__ */ new Set([ + String(id), + ...up === void 0 ? [] : await chain(up), + ...starter === void 0 ? [] : await chain(starter) + ])]; + })(); + cache.set(id, result); + } + return result; + }; + return chain; +} +var CodingTools2, Started, ops; +var init_environment = __esm({ + "environment.ts"() { + init_dist4(); + init_tools(); + CodingTools2 = { ...CodingTools, tools: CodingTools.tools.map((tool) => ({ + ...tool, + execute: (args, api, context) => tool.execute(args, { ...api, env: api.env.forTool(api.callId, tool.name) }, context) + })) }; + Started = defineDoc({ + kind: "board.started", + version: 1, + checkpointWhen: () => false, + scope: "conversation", + history: "latest", + fork: "initial", + initial: () => ({}) + }); + ops = Deno.core.ops; + } +}); + +// extensions.ts async function file(kind, path, bytes2 = []) { - const result = await ops.op_file(kind, path, bytes2); + const result = await ops2.op_file(kind, path, bytes2); if (!result.ok) throw Object.assign(new Error(result.error.message), result.error); return result.value; } async function exec(command, options) { options.signal?.throwIfAborted(); - const rid = ops.op_exec(command, options.cwd, options.timeout, void 0, options.env, options.conversations); + const tag = options.extension ? { + id: options.toolCall ?? `extension:${options.extension}:${options.task ?? crypto.randomUUID()}`, + pid: 0, + program: `extension:${options.extension}`, + conversations: options.conversations ?? [] + } : void 0; + const rid = ops2.op_exec(command, options.cwd, options.timeout, void 0, options.env, options.conversations, tag); const abort = () => Deno.core.close(rid); options.signal?.addEventListener("abort", abort, { once: true }); const decoders = { stdout: new TextDecoder(), stderr: new TextDecoder() }; const result = { code: 0, stdout: "", stderr: "" }; try { for (; ; ) { - const chunk = await ops.op_exec_next(rid); + const chunk = await ops2.op_exec_next(rid); if (!chunk.stream) { if (chunk.error) throw new Error(chunk.error); result.code = chunk.exitCode; @@ -32645,11 +32695,12 @@ async function git(cwd, ...args) { function registerModules() { const modules = { "@earendil-works/sausage-events": events_exports, "@earendil-works/pi-schema": dist_exports, "@earendil-works/pi-durable": dist_exports3, "@earendil-works/pi-durable/tools": tools_exports, "@earendil-works/pi-ai": dist_exports4, "@earendil-works/pi-ai/models": models_exports, "@earendil-works/chord": dist_exports2, "@earendil-works/chord/context": context_exports }; globalThis.__sausage = { modules }; - ops.op_modules(Object.fromEntries(Object.entries(modules).map(([name, value2]) => [name, Object.keys(value2)]))); + ops2.op_modules(Object.fromEntries(Object.entries(modules).map(([name, value2]) => [name, Object.keys(value2)]))); } async function loadExtensions(harness2, registry2, storage2, models2, context, builtins = []) { registerModules(); const eventService = eventLog(() => harness2); + const chain = conversationChains(harness2, context); const repo = "/src/sausage"; let providers = /* @__PURE__ */ new Map(); const resources = /* @__PURE__ */ new Map(); @@ -32660,7 +32711,7 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b let queue2 = Promise.resolve(); const publish2 = async () => { await harness2.commit(async (tx) => Object.assign(await tx.doc(ExtensionState), state), context); - ops.op_extension_status(JSON.stringify(state)); + ops2.op_extension_status(JSON.stringify(state)); await fs.write("/src/sausage/.git/sausage-last-good", state.good ?? ""); }; const dispose = async (entries2) => { @@ -32668,7 +32719,7 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b try { await cleanup(); } catch (error) { - ops.op_output(`Extension cleanup: ${String(error)} + ops2.op_output(`Extension cleanup: ${String(error)} `); } } @@ -32699,8 +32750,9 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b settings: () => settings, metadata: Metadata, fs, - exec, + exec: (command, options) => exec(command, { ...options, extension: name }), git, + chain, implement: (api, value2) => { staged.set(api.name, value2); }, @@ -32723,12 +32775,12 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b onClose: (cb) => close.push(cb), notice: (message) => { state.notice = `${name}: ${message}`; - ops.op_extension_status(JSON.stringify(state)); - ops.op_output(`${name}: ${message} + ops2.op_extension_status(JSON.stringify(state)); + ops2.op_output(`${name}: ${message} `); if (!notices.has(message)) { notices.add(message); - void harness2.commit((tx) => eventService.emit(tx, NoticeEvent, { extension: name, message, level: "warning" }), context).catch((error) => ops.op_output(`Recording a notice failed: ${String(error)} + void harness2.commit((tx) => eventService.emit(tx, NoticeEvent, { extension: name, message, level: "warning" }), context).catch((error) => ops2.op_output(`Recording a notice failed: ${String(error)} `)); } } @@ -32807,7 +32859,7 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b tip = await git(repo, "rev-parse", "refs/heads/main"); } catch (error) { state.error = String(error); - ops.op_extension_status(JSON.stringify(state)); + ops2.op_extension_status(JSON.stringify(state)); return; } try { @@ -32816,8 +32868,8 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b if (error.code === "not_found") settings = {}; else { state.notice = `Settings: ${String(error)}`; - ops.op_extension_status(JSON.stringify(state)); - ops.op_output(`${state.notice} + ops2.op_extension_status(JSON.stringify(state)); + ops2.op_output(`${state.notice} `); } } @@ -32833,11 +32885,11 @@ Last good: ${fallback}` : failed; await publish2(); }; const enqueue2 = () => queue2 = queue2.then(reload); - const rid = ops.op_watch([`${repo}/.git/refs/heads/main`, `${repo}/.git/packed-refs`, `${repo}/settings.json`]); + const rid = ops2.op_watch([`${repo}/.git/refs/heads/main`, `${repo}/.git/packed-refs`, `${repo}/settings.json`]); await enqueue2(); const pending = (async () => { while (active) { - await ops.op_watch_next(rid); + await ops2.op_watch_next(rid); if (active) await enqueue2(); } })(); @@ -32849,9 +32901,9 @@ Last good: ${fallback}` : failed; await dispose(facets); } }; } -var ops, encoder4, decoder4, ExtensionState, Metadata, fs; +var ops2, encoder4, decoder4, ExtensionState, Metadata, fs; var init_extensions = __esm({ - "host/js/extensions.ts"() { + "extensions.ts"() { init_dist4(); init_tools(); init_dist5(); @@ -32860,7 +32912,8 @@ var init_extensions = __esm({ init_context(); init_dist2(); init_events(); - ops = Deno.core.ops; + init_environment(); + ops2 = Deno.core.ops; encoder4 = new TextEncoder(); decoder4 = new TextDecoder(); ExtensionState = defineDoc({ kind: "sausage.extensions", version: 1, scope: "session", checkpointWhen: () => false, initial: () => ({ good: null, current: null, error: null }) }); @@ -32879,7 +32932,7 @@ var init_extensions = __esm({ } }); -// host/js/automations-test-support.ts +// automations-test-support.ts function expect(value2, negate = false) { const check2 = (ok) => assert(negate ? !ok : ok, `Expected ${String(value2)}${negate ? " not" : ""} to match`); const result = { @@ -32923,7 +32976,7 @@ async function until2(condition) { } var cases, it, describe2, assert, same, subset, setImmediate2; var init_automations_test_support = __esm({ - "host/js/automations-test-support.ts"() { + "automations-test-support.ts"() { cases = []; it = (name, run2) => cases.push({ name, run: run2 }); describe2 = (_name, run2) => run2(); @@ -32937,7 +32990,7 @@ var init_automations_test_support = __esm({ } }); -// host/js/automations-pause-fixture.ts +// automations-pause-fixture.ts async function fixture(home, retry = {}) { home ??= `${globalThis.storagePath}.pause-${++serial}`; const registry2 = createRegistry(), models2 = createModels(), faux2 = fauxProvider({ tokensPerSecond: 1e5 }); @@ -32990,7 +33043,7 @@ async function clean() { } var serial, hosts, streamTask; var init_automations_pause_fixture = __esm({ - "host/js/automations-pause-fixture.ts"() { + "automations-pause-fixture.ts"() { init_context(); init_dist2(); init_models(); @@ -33007,11 +33060,11 @@ var init_automations_pause_fixture = __esm({ } }); -// host/js/automations-schedule-cases.ts +// automations-schedule-cases.ts var automations_schedule_cases_exports = {}; var describeSchedule, nextAt, parseSchedule, time, next; var init_automations_schedule_cases = __esm({ - async "host/js/automations-schedule-cases.ts"() { + async "automations-schedule-cases.ts"() { init_automations_test_support(); ({ describeSchedule, nextAt, parseSchedule } = await import(`${globalThis.automationBase}/automations/schedule.ts`)); time = Date.parse("2026-01-05T08:00:00Z"); @@ -33079,11 +33132,11 @@ var init_automations_schedule_cases = __esm({ } }); -// host/js/automations-pause-cases.ts +// automations-pause-cases.ts var automations_pause_cases_exports = {}; var actions, autoPlay, passive, userActions, lasted, Standing, generations, limit, at; var init_automations_pause_cases = __esm({ - async "host/js/automations-pause-cases.ts"() { + async "automations-pause-cases.ts"() { init_automations_test_support(); init_automations_pause_fixture(); init_context(); @@ -33561,7 +33614,7 @@ var init_automations_pause_cases = __esm({ } }); -// host/js/automations-test.ts +// automations-test.ts init_context(); init_models(); init_faux(); @@ -33587,10 +33640,10 @@ var { Automations } = await import( /* @vite-ignore */ `${globalThis.automationBase}/automations/server.ts` ); -var call = async (args) => { +var call = async (args, conversation = root) => { faux.setResponses([fauxAssistantMessage([fauxToolCall("automation", args)], { stopReason: "toolUse" }), fauxAssistantMessage("done")]); - await (await root.submit({ type: "input", content: "Configure automation" }, BACKGROUND_CONTEXT)).wait(BACKGROUND_CONTEXT); - const result = (await root.context(BACKGROUND_CONTEXT)).entries.filter((entry2) => entry2.kind === "pi.tool-result").at(-1); + await (await conversation.submit({ type: "input", content: "Configure automation" }, BACKGROUND_CONTEXT)).wait(BACKGROUND_CONTEXT); + const result = (await conversation.context(BACKGROUND_CONTEXT)).entries.filter((entry2) => entry2.kind === "pi.tool-result").at(-1); assert(result && !result.model?.[0]?.isError, JSON.stringify(result)); }; harness.resume(); @@ -33634,29 +33687,44 @@ if (globalThis.automationMode === "prepare") { await storage.close(); } else if (globalThis.automationMode === "grant") { for (const path of ["/src/sausage/automations", "/src/sausage/automations/A1"]) await fs.mkdir(path); - await fs.write("/src/sausage/automations/A1/script.sh", `curl http://127.0.0.1:${globalThis.automationPort}/token + await fs.write("/src/sausage/automations/A1/script.sh", `curl http://host.sausage/whoami +printf '\\n' +curl http://127.0.0.1:${globalThis.automationPort}/token printf '\\nFIRE delivered\\n' printf 'FIRE ignored\\n' >&2 printf 'DONE\\n'`); const subscriber = await harness.createConversation({ ownership: { kind: "ownerless" } }, BACKGROUND_CONTEXT); await subscriber.configure({ model: { provider: "faux", modelId: "faux-1" } }, BACKGROUND_CONTEXT); - await call({ action: "create", name: "creator grant", ask: "Fetch and fire", subscribers: [subscriber.id] }); + const { Started: Started2 } = await import( + /* @vite-ignore */ + `${globalThis.automationBase}/messages/addresses.ts` + ); + const entry2 = await harness.commit((tx) => tx.appendEntry(subscriber.id, { kind: "automation.origin", data: {} }), BACKGROUND_CONTEXT); + const creatorRecord = await harness.commit(async (tx) => { + const fork = await tx.forkConversation(subscriber.id, entry2.id, { ownership: { kind: "ownerless" } }); + (await tx.doc(Started2, fork.id)).by = root.id; + return fork; + }, BACKGROUND_CONTEXT); + const creator = await harness.conversation(creatorRecord.id, BACKGROUND_CONTEXT); + await call({ action: "create", name: "creator grant", ask: "Fetch and fire", subscribers: [subscriber.id] }, creator); await until2(async () => (await harness.snapshot(Automations, BACKGROUND_CONTEXT))?.automations.A1?.script?.state === "done"); - await until2(async () => (await subscriber.context(BACKGROUND_CONTEXT)).entries.some((entry2) => entry2.model?.some((m) => typeof m.content === "string" && m.content.includes("[automation A1 fired]")))); + await until2(async () => (await subscriber.context(BACKGROUND_CONTEXT)).entries.some((entry3) => entry3.model?.some((m) => typeof m.content === "string" && m.content.includes("[automation A1 fired]")))); await harness.waitForIdle(BACKGROUND_CONTEXT); const ledger = await harness.snapshot(Automations, BACKGROUND_CONTEXT); assert(ledger.automations.A1.fires === 1, "Only stdout fires"); - assert(ledger.automations.A1.executionConversation === root.id, "The creator owns execution"); - assert((await fs.read("/src/sausage/automations/A1/log")).includes("accepted"), "The creator grant reaches curl"); - const entries2 = (await root.context(BACKGROUND_CONTEXT)).entries.filter((entry2) => entry2.model?.some((m) => m.role === "user" && typeof m.content === "string" && m.content.includes("[automation A1 fired]"))); + assert(ledger.automations.A1.executionConversation === creator.id, "The creator owns execution"); + const log = await fs.read("/src/sausage/automations/A1/log"); + assert(log.includes("accepted"), "The creator chain reaches the starter grant"); + assert(JSON.stringify(JSON.parse(log.split("\n")[0]).conversations) === JSON.stringify([String(creator.id), String(subscriber.id), String(root.id)]), "The host appends the starter after fork ancestry"); + const entries2 = (await root.context(BACKGROUND_CONTEXT)).entries.filter((entry3) => entry3.model?.some((m) => m.role === "user" && typeof m.content === "string" && m.content.includes("[automation A1 fired]"))); assert(entries2.length === 0, "The creator is not a subscriber"); - const delivered = (await subscriber.context(BACKGROUND_CONTEXT)).entries.filter((entry2) => entry2.model?.some((m) => m.role === "user" && typeof m.content === "string" && m.content.includes("[automation A1 fired]"))); + const delivered = (await subscriber.context(BACKGROUND_CONTEXT)).entries.filter((entry3) => entry3.model?.some((m) => m.role === "user" && typeof m.content === "string" && m.content.includes("[automation A1 fired]"))); assert(delivered.length === 1, "Exactly one script subscriber input"); const replacement = await harness.createConversation({ ownership: { kind: "ownerless" } }, BACKGROUND_CONTEXT); await call({ action: "subscribe", id: "A1", to: `#${replacement.id}` }); await call({ action: "unsubscribe", id: "A1", to: `#${subscriber.id}` }); const changed = (await harness.snapshot(Automations, BACKGROUND_CONTEXT)).automations.A1; - assert(changed.executionConversation === root.id, "Subscription changes retain the creator"); + assert(changed.executionConversation === creator.id, "Subscription changes retain the creator"); assert(JSON.stringify(changed.subscribers) === JSON.stringify([replacement.id]), "Subscription ids normalize"); await loader.close(); await harness.close(BACKGROUND_CONTEXT); diff --git a/host/js/automations-test.ts b/host/js/automations-test.ts index 14f68ff..cfd241a 100644 --- a/host/js/automations-test.ts +++ b/host/js/automations-test.ts @@ -16,10 +16,10 @@ const loader=await loadExtensions(harness,registry,storage,models,context) assert(!loader.state().error,loader.state().error) globalThis.automationBase=`file:///run/sausage/extensions/${loader.state().good}/extensions` const {Automations}=await import(/* @vite-ignore */ `${globalThis.automationBase}/automations/server.ts`) -const call=async(args:any)=>{ +const call=async(args:any,conversation=root)=>{ faux.setResponses([fauxAssistantMessage([fauxToolCall('automation',args)],{stopReason:'toolUse'}),fauxAssistantMessage('done')]) - await (await root.submit({type:'input',content:'Configure automation'},context)).wait(context) - const result=(await root.context(context)).entries.filter((entry:any)=>entry.kind==='pi.tool-result').at(-1) + await (await conversation.submit({type:'input',content:'Configure automation'},context)).wait(context) + const result=(await conversation.context(context)).entries.filter((entry:any)=>entry.kind==='pi.tool-result').at(-1) assert(result && !result.model?.[0]?.isError,JSON.stringify(result)) } harness.resume() @@ -55,17 +55,27 @@ if(globalThis.automationMode==='prepare') { await loader.close();await harness.close(context);await storage.close() } else if(globalThis.automationMode==='grant') { for(const path of ['/src/sausage/automations','/src/sausage/automations/A1']) await fs.mkdir(path) - await fs.write('/src/sausage/automations/A1/script.sh',`curl http://127.0.0.1:${globalThis.automationPort}/token\nprintf '\\nFIRE delivered\\n'\nprintf 'FIRE ignored\\n' >&2\nprintf 'DONE\\n'`) + await fs.write('/src/sausage/automations/A1/script.sh',`curl http://host.sausage/whoami\nprintf '\\n'\ncurl http://127.0.0.1:${globalThis.automationPort}/token\nprintf '\\nFIRE delivered\\n'\nprintf 'FIRE ignored\\n' >&2\nprintf 'DONE\\n'`) const subscriber=await harness.createConversation({ownership:{kind:'ownerless'}},context) await subscriber.configure({model:{provider:'faux',modelId:'faux-1'}},context) - await call({action:'create',name:'creator grant',ask:'Fetch and fire',subscribers:[subscriber.id]}) + const {Started}=await import(/* @vite-ignore */ `${globalThis.automationBase}/messages/addresses.ts`) + const entry=await harness.commit((tx:any)=>tx.appendEntry(subscriber.id,{kind:'automation.origin',data:{}}),context) + const creatorRecord=await harness.commit(async(tx:any)=>{ + const fork=await tx.forkConversation(subscriber.id,entry.id,{ownership:{kind:'ownerless'}}) + ;(await tx.doc(Started,fork.id)).by=root.id + return fork + },context) + const creator=await harness.conversation(creatorRecord.id,context) + await call({action:'create',name:'creator grant',ask:'Fetch and fire',subscribers:[subscriber.id]},creator) await until(async()=>(await harness.snapshot(Automations,context))?.automations.A1?.script?.state==='done') await until(async()=>(await subscriber.context(context)).entries.some((entry:any)=>entry.model?.some((m:any)=>typeof m.content==='string'&&m.content.includes('[automation A1 fired]')))) await harness.waitForIdle(context) const ledger=await harness.snapshot(Automations,context) assert(ledger.automations.A1.fires===1,'Only stdout fires') - assert(ledger.automations.A1.executionConversation===root.id,'The creator owns execution') - assert((await fs.read('/src/sausage/automations/A1/log')).includes('accepted'),'The creator grant reaches curl') + assert(ledger.automations.A1.executionConversation===creator.id,'The creator owns execution') + const log=await fs.read('/src/sausage/automations/A1/log') + assert(log.includes('accepted'),'The creator chain reaches the starter grant') + assert(JSON.stringify(JSON.parse(log.split('\n')[0]).conversations)===JSON.stringify([String(creator.id),String(subscriber.id),String(root.id)]),'The host appends the starter after fork ancestry') const entries=(await root.context(context)).entries.filter((entry:any)=>entry.model?.some((m:any)=>m.role==='user'&&typeof m.content==='string'&&m.content.includes('[automation A1 fired]'))) assert(entries.length===0,'The creator is not a subscriber') const delivered=(await subscriber.context(context)).entries.filter((entry:any)=>entry.model?.some((m:any)=>m.role==='user'&&typeof m.content==='string'&&m.content.includes('[automation A1 fired]'))) @@ -74,7 +84,7 @@ if(globalThis.automationMode==='prepare') { await call({action:'subscribe',id:'A1',to:`#${replacement.id}`}) await call({action:'unsubscribe',id:'A1',to:`#${subscriber.id}`}) const changed=(await harness.snapshot(Automations,context)).automations.A1 - assert(changed.executionConversation===root.id,'Subscription changes retain the creator') + assert(changed.executionConversation===creator.id,'Subscription changes retain the creator') assert(JSON.stringify(changed.subscribers)===JSON.stringify([replacement.id]),'Subscription ids normalize') await loader.close();await harness.close(context);await storage.close() } else { diff --git a/host/js/bundle.js b/host/js/bundle.js index 5a3799b..5c16795 100644 --- a/host/js/bundle.js +++ b/host/js/bundle.js @@ -54213,6 +54213,7 @@ function registerModules() { async function loadExtensions(harness2, registry2, storage2, models2, context, builtins = []) { registerModules(); const eventService = eventLog(() => harness2); + const chain2 = conversationChains(harness2, context); const repo = "/src/sausage"; let providers = /* @__PURE__ */ new Map(); const resources = /* @__PURE__ */ new Map(); @@ -54264,6 +54265,7 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b fs, exec: (command, options) => exec(command, { ...options, extension: name }), git, + chain: chain2, implement: (api, value2) => { staged.set(api.name, value2); }, diff --git a/host/js/core-ext-test-bundle.js b/host/js/core-ext-test-bundle.js index 503a983..fde554f 100644 --- a/host/js/core-ext-test-bundle.js +++ b/host/js/core-ext-test-bundle.js @@ -8946,27 +8946,27 @@ var REPLACE_TAKE = { kind: "replace" }; var PendingOps = class { #state = EMPTY; /** Queue the ops of one commit. */ - push(ops2) { - if (ops2.length === 0) + push(ops3) { + if (ops3.length === 0) return; const state = this.#state; - if (ops2[0][0] === "r") { - this.#state = { kind: "batch", ops: ops2 }; + if (ops3[0][0] === "r") { + this.#state = { kind: "batch", ops: ops3 }; return; } switch (state.kind) { case "empty": - this.#state = { kind: "batch", ops: ops2 }; + this.#state = { kind: "batch", ops: ops3 }; return; case "batch": { const folding = { kind: "folding", ops: [], leaves: /* @__PURE__ */ new Map() }; this.#state = folding; if (this.#fold(state.ops, folding)) - this.#fold(ops2, folding); + this.#fold(ops3, folding); return; } case "folding": - this.#fold(ops2, state); + this.#fold(ops3, state); return; case "replace": return; @@ -8997,8 +8997,8 @@ var PendingOps = class { } } /** Fold `ops` into `folding`; false once the queue overflowed into `replace`. */ - #fold(ops2, folding) { - for (const op2 of ops2) { + #fold(ops3, folding) { + for (const op2 of ops3) { switch (op2[0]) { case "r": folding.ops.length = 0; @@ -9267,12 +9267,12 @@ var PathError = class extends Error { this.name = "PathError"; } }; -function apply(target, ops2) { - return applyOps(target, ops2); +function apply(target, ops3) { + return applyOps(target, ops3); } -function applyOps(target, ops2) { +function applyOps(target, ops3) { let root = target; - for (const op2 of ops2) { + for (const op2 of ops3) { assertValidOp(op2); if (op2[0] === "r") { root = op2[1]; @@ -9341,14 +9341,14 @@ function applyOps(target, ops2) { } return root; } -function applyImmutable(target, ops2) { - return applyImmutableBatches(target, [ops2]); +function applyImmutable(target, ops3) { + return applyImmutableBatches(target, [ops3]); } function applyImmutableBatches(target, batches) { let root = target; const owned = /* @__PURE__ */ new WeakSet(); - for (const ops2 of batches) { - for (const op2 of ops2) { + for (const ops3 of batches) { + for (const op2 of ops3) { assertValidOp(op2); if (op2[0] === "r") { root = op2[1]; @@ -9462,10 +9462,10 @@ function encoder() { let nextId = 0; let previous; return { - encode(ops2) { + encode(ops3) { previous = void 0; const out = []; - for (const op2 of ops2) { + for (const op2 of ops3) { if (op2[0] === "r") { out.push(op2); seen.clear(); @@ -9715,9 +9715,9 @@ var Source = class { return []; } }; -function unbox(ops2, value2) { +function unbox(ops3, value2) { const result = []; - for (const op2 of ops2) { + for (const op2 of ops3) { if (op2[0] === "r" || op2[1].length === 0) return [["r", value2]]; const path = op2[1].slice(1); @@ -9811,8 +9811,8 @@ var Cell = class extends Source { throw notReady(`state ${this.key} (its init has not run)`); const before = this.value; const diff = options.diff ?? sharesStructure(before, value2); - const ops2 = diff ? diffRevisions(before, value2) : void 0; - this.#publish(this.#tracker.prepareReplace({ v: value2 }), "ops", true, ops2); + const ops3 = diff ? diffRevisions(before, value2) : void 0; + this.#publish(this.#tracker.prepareReplace({ v: value2 }), "ops", true, ops3); } /** * Installs a migrated value and its schema (reload commit). The caller validated the value and the derivations @@ -9823,7 +9823,7 @@ var Cell = class extends Source { this.#publish(this.#tracker.prepareReplace({ v: value2 }), "reset", false); } /** Adopts this revision and every derived one, then queues all notifications (cell first, then derivations). */ - #publish(prepared, type, validate2 = true, ops2) { + #publish(prepared, type, validate2 = true, ops3) { if (prepared.ops.length === 0 && type === "ops") { this.#tracker.adopt(prepared); return; @@ -9840,7 +9840,7 @@ var Cell = class extends Source { } holdPublications(() => { this.#tracker.adopt(prepared); - const published = ops2 !== void 0 && ops2.length > 0 ? ops2 : unbox(prepared.ops, value2); + const published = ops3 !== void 0 && ops3.length > 0 ? ops3 : unbox(prepared.ops, value2); this.fanout.emit(type === "reset" ? { type, value: value2 } : { type, ops: published, value: value2 }); for (const [derived, next] of candidates) derived.install(next); @@ -9953,9 +9953,9 @@ var Derived = class extends Source { install(next) { const before = this.#value; this.#value = next; - const ops2 = before === void 0 || next === void 0 ? [["r", next ?? null]] : diffRevisions(before, next); - if (ops2.length > 0) - this.fanout.emit({ type: "ops", ops: ops2, value: next }); + const ops3 = before === void 0 || next === void 0 ? [["r", next ?? null]] : diffRevisions(before, next); + if (ops3.length > 0) + this.fanout.emit({ type: "ops", ops: ops3, value: next }); } }; var isSource = (value2) => value2 instanceof Source; @@ -14008,10 +14008,10 @@ var RemoteBinding = class { const target = pending?.values.get(name) ?? this.members.get(name); if (target === void 0) return; - const ops2 = target.decoder.decode(frame.ops ?? []); - target.value = applyImmutable(target.value, ops2); + const ops3 = target.decoder.decode(frame.ops ?? []); + target.value = applyImmutable(target.value, ops3); if (target === this.members.get(name)) - this.#deliver(name, { type: "ops", ops: ops2, value: target.value }); + this.#deliver(name, { type: "ops", ops: ops3, value: target.value }); return; } const fresh = { value: frame.value, decoder: decoder() }; @@ -15835,8 +15835,8 @@ var Watch = class extends WatchLifecycle { this.#retired = false; if (lone !== void 0) return lone; - const ops2 = batch.kind === "ops" ? batch.ops : [["r", value2]]; - return { kind: "value", value: value2, ops: ops2, retired }; + const ops3 = batch.kind === "ops" ? batch.ops : [["r", value2]]; + return { kind: "value", value: value2, ops: ops3, retired }; } /** The pending failure, or the value after one as a root replacement (no ops were kept since the failure). */ #nextAfterFailure() { @@ -17601,7 +17601,7 @@ function describe(plan, record2) { const change = plan.change; if (change === void 0 || !publishes(plan)) return void 0; - const ops2 = change.loaded === void 0 ? EMPTY_OPERATIONS : change.prepared.ops; + const ops3 = change.loaded === void 0 ? EMPTY_OPERATIONS : change.prepared.ops; return { type: "document", kind: "change", @@ -17609,11 +17609,11 @@ function describe(plan, record2) { conversationId, version: change.version, value: change.prepared.value, - ops: ops2 + ops: ops3 }; } -function storeHeld(hold, ops2, value2, version) { - hold.pending.push(ops2); +function storeHeld(hold, ops3, value2, version) { + hold.pending.push(ops3); const taken = hold.pending.take(); if (taken.kind === "replace") return { content: { version, kind: "base", value: value2 }, ops: [["r", value2]] }; @@ -18694,7 +18694,7 @@ var SessionImpl = class { return { kind: "adoption", error }; } const deadline = this.#clock() + withinMs; - for (const { loaded, ops: ops2, base } of held2) { + for (const { loaded, ops: ops3, base } of held2) { const id = loaded.record.id; let hold = this.#holds.get(id); if (hold === void 0) { @@ -18702,7 +18702,7 @@ var SessionImpl = class { hold = { loaded, pending: new PendingOps(), base: false, deadline, unpin }; this.#holds.set(id, hold); } - hold.pending.push(ops2); + hold.pending.push(ops3); if (base) hold.base = true; if (deadline < hold.deadline) @@ -26917,14 +26917,14 @@ var TaskGraphView = class { const mount = this.#mount; if (mount === void 0) return; - const ops2 = []; + const ops3 = []; for (const [key, record2] of mount.records) { const blocked = this.#blocking.blocked(record2); if (blocked === mount.value.tasks[key]?.blocked) continue; - ops2.push(blocked === void 0 ? ["d", ["tasks", key, "blocked"]] : ["s", ["tasks", key, "blocked"], blocked]); + ops3.push(blocked === void 0 ? ["d", ["tasks", key, "blocked"]] : ["s", ["tasks", key, "blocked"], blocked]); } - publish(mount, ops2, BACKGROUND_CONTEXT, (error) => this.#session.report(error)); + publish(mount, ops3, BACKGROUND_CONTEXT, (error) => this.#session.report(error)); }).catch(() => { }); } @@ -26948,7 +26948,7 @@ var TaskGraphView = class { } }; function advance(mount, publication, context, blocked, report2) { - const ops2 = []; + const ops3 = []; const changed = /* @__PURE__ */ new Map(); const node = (key) => changed.has(key) ? changed.get(key) : mount.value.tasks[key]; for (const change of publication.changes) { @@ -26961,7 +26961,7 @@ function advance(mount, publication, context, blocked, report2) { mount.records.delete(key); if (previous === void 0) continue; - ops2.push(["d", ["tasks", key]]); + ops3.push(["d", ["tasks", key]]); changed.set(key, void 0); continue; } @@ -26970,7 +26970,7 @@ function advance(mount, publication, context, blocked, report2) { const next = nodeOf2(record2, previous?.conversations ?? [], blocked(subject)); if (previous !== void 0 && JSON.stringify(next) === JSON.stringify(previous)) continue; - ops2.push(["s", ["tasks", key], next]); + ops3.push(["s", ["tasks", key], next]); changed.set(key, next); } const created = /* @__PURE__ */ new Map(); @@ -26983,16 +26983,16 @@ function advance(mount, publication, context, blocked, report2) { } for (const [key, ids] of created) { const conversations = [...node(key).conversations, ...ids].sort((a, b) => a - b); - ops2.push(["s", ["tasks", key, "conversations"], conversations]); + ops3.push(["s", ["tasks", key, "conversations"], conversations]); } - publish(mount, ops2, context, report2); + publish(mount, ops3, context, report2); } -function publish(mount, ops2, context, report2) { - if (ops2.length === 0) +function publish(mount, ops3, context, report2) { + if (ops3.length === 0) return; - mount.value = applyImmutable(mount.value, ops2); + mount.value = applyImmutable(mount.value, ops3); const frameContext = withoutAbortSignal(context); - const call = { kind: "value", value: mount.value, ops: ops2, retired: false }; + const call = { kind: "value", value: mount.value, ops: ops3, retired: false }; for (const observer of [...mount.observers]) contained(() => observer.advance(call, frameContext), report2); } @@ -27218,19 +27218,19 @@ function advance2(id, mount, publication, context, report2) { const previous = windowed.value; let entries2 = previous.entries; let before = previous.before; - let ops2 = docOps; + let ops3 = docOps; if (appended.length > 0) { - ops2 = [...docOps, ["p", ["entries"], entries2.length, 0, inserted]]; + ops3 = [...docOps, ["p", ["entries"], entries2.length, 0, inserted]]; entries2 = entries2.concat(appended); if (entries2.length > windowed.max) { const drop = entries2.length - windowed.min; before = entries2[drop - 1].id; entries2 = entries2.slice(drop); - ops2.push(["p", ["entries"], 0, drop, []], ["s", ["before"], before]); + ops3.push(["p", ["entries"], 0, drop, []], ["s", ["before"], before]); } } windowed.value = view(mount.conversation, entries2, before, mount.docs); - const call = { kind: "value", value: windowed.value, ops: ops2, retired: false }; + const call = { kind: "value", value: windowed.value, ops: ops3, retired: false }; contained(() => windowed.observer.advance(call, frameContext), report2); } } @@ -31368,14 +31368,51 @@ function eventLog(harness2) { } } -// extensions.ts +// environment.ts +var CodingTools2 = { ...CodingTools, tools: CodingTools.tools.map((tool) => ({ + ...tool, + execute: (args, api, context) => tool.execute(args, { ...api, env: api.env.forTool(api.callId, tool.name) }, context) +})) }; +var Started = defineDoc({ + kind: "board.started", + version: 1, + checkpointWhen: () => false, + scope: "conversation", + history: "latest", + fork: "initial", + initial: () => ({}) +}); +function conversationChains(harness2, context) { + const cache = /* @__PURE__ */ new Map(); + const chain = (id) => { + let result = cache.get(id); + if (!result) { + result = (async () => { + const record2 = await harness2.commit((tx) => tx.conversation(id), context); + const up = record2?.owner?.conversationId ?? record2?.parent?.conversationId; + const starter = (await harness2.snapshot(Started, id, context))?.by; + return [.../* @__PURE__ */ new Set([ + String(id), + ...up === void 0 ? [] : await chain(up), + ...starter === void 0 ? [] : await chain(starter) + ])]; + })(); + cache.set(id, result); + } + return result; + }; + return chain; +} var ops = Deno.core.ops; + +// extensions.ts +var ops2 = Deno.core.ops; var encoder4 = new TextEncoder(); var decoder4 = new TextDecoder(); var ExtensionState = defineDoc({ kind: "sausage.extensions", version: 1, scope: "session", checkpointWhen: () => false, initial: () => ({ good: null, current: null, error: null }) }); var Metadata = defineDoc({ kind: "sausage.metadata", version: 1, scope: "conversation", history: "latest", fork: "current", initial: () => ({ label: "", title: "" }), checkpointWhen: () => false }); async function file(kind, path, bytes2 = []) { - const result = await ops.op_file(kind, path, bytes2); + const result = await ops2.op_file(kind, path, bytes2); if (!result.ok) throw Object.assign(new Error(result.error.message), result.error); return result.value; } @@ -31398,14 +31435,14 @@ async function exec(command, options) { program: `extension:${options.extension}`, conversations: options.conversations ?? [] } : void 0; - const rid = ops.op_exec(command, options.cwd, options.timeout, void 0, options.env, options.conversations, tag); + const rid = ops2.op_exec(command, options.cwd, options.timeout, void 0, options.env, options.conversations, tag); const abort = () => Deno.core.close(rid); options.signal?.addEventListener("abort", abort, { once: true }); const decoders = { stdout: new TextDecoder(), stderr: new TextDecoder() }; const result = { code: 0, stdout: "", stderr: "" }; try { for (; ; ) { - const chunk = await ops.op_exec_next(rid); + const chunk = await ops2.op_exec_next(rid); if (!chunk.stream) { if (chunk.error) throw new Error(chunk.error); result.code = chunk.exitCode; @@ -31432,11 +31469,12 @@ async function git(cwd, ...args) { function registerModules() { const modules = { "@earendil-works/sausage-events": events_exports, "@earendil-works/pi-schema": dist_exports, "@earendil-works/pi-durable": dist_exports3, "@earendil-works/pi-durable/tools": tools_exports, "@earendil-works/pi-ai": dist_exports4, "@earendil-works/pi-ai/models": models_exports, "@earendil-works/chord": dist_exports2, "@earendil-works/chord/context": context_exports }; globalThis.__sausage = { modules }; - ops.op_modules(Object.fromEntries(Object.entries(modules).map(([name, value2]) => [name, Object.keys(value2)]))); + ops2.op_modules(Object.fromEntries(Object.entries(modules).map(([name, value2]) => [name, Object.keys(value2)]))); } async function loadExtensions(harness2, registry2, storage2, models2, context, builtins = []) { registerModules(); const eventService = eventLog(() => harness2); + const chain = conversationChains(harness2, context); const repo = "/src/sausage"; let providers = /* @__PURE__ */ new Map(); const resources = /* @__PURE__ */ new Map(); @@ -31447,7 +31485,7 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b let queue2 = Promise.resolve(); const publish2 = async () => { await harness2.commit(async (tx) => Object.assign(await tx.doc(ExtensionState), state), context); - ops.op_extension_status(JSON.stringify(state)); + ops2.op_extension_status(JSON.stringify(state)); await fs.write("/src/sausage/.git/sausage-last-good", state.good ?? ""); }; const dispose = async (entries2) => { @@ -31455,7 +31493,7 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b try { await cleanup(); } catch (error) { - ops.op_output(`Extension cleanup: ${String(error)} + ops2.op_output(`Extension cleanup: ${String(error)} `); } } @@ -31488,6 +31526,7 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b fs, exec: (command, options) => exec(command, { ...options, extension: name }), git, + chain, implement: (api, value2) => { staged.set(api.name, value2); }, @@ -31510,12 +31549,12 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b onClose: (cb) => close.push(cb), notice: (message) => { state.notice = `${name}: ${message}`; - ops.op_extension_status(JSON.stringify(state)); - ops.op_output(`${name}: ${message} + ops2.op_extension_status(JSON.stringify(state)); + ops2.op_output(`${name}: ${message} `); if (!notices.has(message)) { notices.add(message); - void harness2.commit((tx) => eventService.emit(tx, NoticeEvent, { extension: name, message, level: "warning" }), context).catch((error) => ops.op_output(`Recording a notice failed: ${String(error)} + void harness2.commit((tx) => eventService.emit(tx, NoticeEvent, { extension: name, message, level: "warning" }), context).catch((error) => ops2.op_output(`Recording a notice failed: ${String(error)} `)); } } @@ -31594,7 +31633,7 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b tip = await git(repo, "rev-parse", "refs/heads/main"); } catch (error) { state.error = String(error); - ops.op_extension_status(JSON.stringify(state)); + ops2.op_extension_status(JSON.stringify(state)); return; } try { @@ -31603,8 +31642,8 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b if (error.code === "not_found") settings = {}; else { state.notice = `Settings: ${String(error)}`; - ops.op_extension_status(JSON.stringify(state)); - ops.op_output(`${state.notice} + ops2.op_extension_status(JSON.stringify(state)); + ops2.op_output(`${state.notice} `); } } @@ -31620,11 +31659,11 @@ Last good: ${fallback}` : failed; await publish2(); }; const enqueue2 = () => queue2 = queue2.then(reload); - const rid = ops.op_watch([`${repo}/.git/refs/heads/main`, `${repo}/.git/packed-refs`, `${repo}/settings.json`]); + const rid = ops2.op_watch([`${repo}/.git/refs/heads/main`, `${repo}/.git/packed-refs`, `${repo}/settings.json`]); await enqueue2(); const pending = (async () => { while (active) { - await ops.op_watch_next(rid); + await ops2.op_watch_next(rid); if (active) await enqueue2(); } })(); diff --git a/host/js/events-test-bundle.js b/host/js/events-test-bundle.js index 161a0d4..b8049a7 100644 --- a/host/js/events-test-bundle.js +++ b/host/js/events-test-bundle.js @@ -6190,27 +6190,27 @@ var REPLACE_TAKE = { kind: "replace" }; var PendingOps = class { #state = EMPTY; /** Queue the ops of one commit. */ - push(ops2) { - if (ops2.length === 0) + push(ops3) { + if (ops3.length === 0) return; const state = this.#state; - if (ops2[0][0] === "r") { - this.#state = { kind: "batch", ops: ops2 }; + if (ops3[0][0] === "r") { + this.#state = { kind: "batch", ops: ops3 }; return; } switch (state.kind) { case "empty": - this.#state = { kind: "batch", ops: ops2 }; + this.#state = { kind: "batch", ops: ops3 }; return; case "batch": { const folding = { kind: "folding", ops: [], leaves: /* @__PURE__ */ new Map() }; this.#state = folding; if (this.#fold(state.ops, folding)) - this.#fold(ops2, folding); + this.#fold(ops3, folding); return; } case "folding": - this.#fold(ops2, state); + this.#fold(ops3, state); return; case "replace": return; @@ -6241,8 +6241,8 @@ var PendingOps = class { } } /** Fold `ops` into `folding`; false once the queue overflowed into `replace`. */ - #fold(ops2, folding) { - for (const op2 of ops2) { + #fold(ops3, folding) { + for (const op2 of ops3) { switch (op2[0]) { case "r": folding.ops.length = 0; @@ -6511,12 +6511,12 @@ var PathError = class extends Error { this.name = "PathError"; } }; -function apply(target, ops2) { - return applyOps(target, ops2); +function apply(target, ops3) { + return applyOps(target, ops3); } -function applyOps(target, ops2) { +function applyOps(target, ops3) { let root = target; - for (const op2 of ops2) { + for (const op2 of ops3) { assertValidOp(op2); if (op2[0] === "r") { root = op2[1]; @@ -6585,14 +6585,14 @@ function applyOps(target, ops2) { } return root; } -function applyImmutable(target, ops2) { - return applyImmutableBatches(target, [ops2]); +function applyImmutable(target, ops3) { + return applyImmutableBatches(target, [ops3]); } function applyImmutableBatches(target, batches) { let root = target; const owned = /* @__PURE__ */ new WeakSet(); - for (const ops2 of batches) { - for (const op2 of ops2) { + for (const ops3 of batches) { + for (const op2 of ops3) { assertValidOp(op2); if (op2[0] === "r") { root = op2[1]; @@ -6706,10 +6706,10 @@ function encoder() { let nextId = 0; let previous; return { - encode(ops2) { + encode(ops3) { previous = void 0; const out = []; - for (const op2 of ops2) { + for (const op2 of ops3) { if (op2[0] === "r") { out.push(op2); seen.clear(); @@ -6959,9 +6959,9 @@ var Source = class { return []; } }; -function unbox(ops2, value2) { +function unbox(ops3, value2) { const result = []; - for (const op2 of ops2) { + for (const op2 of ops3) { if (op2[0] === "r" || op2[1].length === 0) return [["r", value2]]; const path = op2[1].slice(1); @@ -7055,8 +7055,8 @@ var Cell = class extends Source { throw notReady(`state ${this.key} (its init has not run)`); const before = this.value; const diff = options.diff ?? sharesStructure(before, value2); - const ops2 = diff ? diffRevisions(before, value2) : void 0; - this.#publish(this.#tracker.prepareReplace({ v: value2 }), "ops", true, ops2); + const ops3 = diff ? diffRevisions(before, value2) : void 0; + this.#publish(this.#tracker.prepareReplace({ v: value2 }), "ops", true, ops3); } /** * Installs a migrated value and its schema (reload commit). The caller validated the value and the derivations @@ -7067,7 +7067,7 @@ var Cell = class extends Source { this.#publish(this.#tracker.prepareReplace({ v: value2 }), "reset", false); } /** Adopts this revision and every derived one, then queues all notifications (cell first, then derivations). */ - #publish(prepared, type, validate2 = true, ops2) { + #publish(prepared, type, validate2 = true, ops3) { if (prepared.ops.length === 0 && type === "ops") { this.#tracker.adopt(prepared); return; @@ -7084,7 +7084,7 @@ var Cell = class extends Source { } holdPublications(() => { this.#tracker.adopt(prepared); - const published = ops2 !== void 0 && ops2.length > 0 ? ops2 : unbox(prepared.ops, value2); + const published = ops3 !== void 0 && ops3.length > 0 ? ops3 : unbox(prepared.ops, value2); this.fanout.emit(type === "reset" ? { type, value: value2 } : { type, ops: published, value: value2 }); for (const [derived, next] of candidates) derived.install(next); @@ -7197,9 +7197,9 @@ var Derived = class extends Source { install(next) { const before = this.#value; this.#value = next; - const ops2 = before === void 0 || next === void 0 ? [["r", next ?? null]] : diffRevisions(before, next); - if (ops2.length > 0) - this.fanout.emit({ type: "ops", ops: ops2, value: next }); + const ops3 = before === void 0 || next === void 0 ? [["r", next ?? null]] : diffRevisions(before, next); + if (ops3.length > 0) + this.fanout.emit({ type: "ops", ops: ops3, value: next }); } }; var isSource = (value2) => value2 instanceof Source; @@ -11252,10 +11252,10 @@ var RemoteBinding = class { const target = pending?.values.get(name) ?? this.members.get(name); if (target === void 0) return; - const ops2 = target.decoder.decode(frame.ops ?? []); - target.value = applyImmutable(target.value, ops2); + const ops3 = target.decoder.decode(frame.ops ?? []); + target.value = applyImmutable(target.value, ops3); if (target === this.members.get(name)) - this.#deliver(name, { type: "ops", ops: ops2, value: target.value }); + this.#deliver(name, { type: "ops", ops: ops3, value: target.value }); return; } const fresh = { value: frame.value, decoder: decoder() }; @@ -13079,8 +13079,8 @@ var Watch = class extends WatchLifecycle { this.#retired = false; if (lone !== void 0) return lone; - const ops2 = batch.kind === "ops" ? batch.ops : [["r", value2]]; - return { kind: "value", value: value2, ops: ops2, retired }; + const ops3 = batch.kind === "ops" ? batch.ops : [["r", value2]]; + return { kind: "value", value: value2, ops: ops3, retired }; } /** The pending failure, or the value after one as a root replacement (no ops were kept since the failure). */ #nextAfterFailure() { @@ -14845,7 +14845,7 @@ function describe(plan, record2) { const change = plan.change; if (change === void 0 || !publishes(plan)) return void 0; - const ops2 = change.loaded === void 0 ? EMPTY_OPERATIONS : change.prepared.ops; + const ops3 = change.loaded === void 0 ? EMPTY_OPERATIONS : change.prepared.ops; return { type: "document", kind: "change", @@ -14853,11 +14853,11 @@ function describe(plan, record2) { conversationId, version: change.version, value: change.prepared.value, - ops: ops2 + ops: ops3 }; } -function storeHeld(hold, ops2, value2, version) { - hold.pending.push(ops2); +function storeHeld(hold, ops3, value2, version) { + hold.pending.push(ops3); const taken = hold.pending.take(); if (taken.kind === "replace") return { content: { version, kind: "base", value: value2 }, ops: [["r", value2]] }; @@ -15938,7 +15938,7 @@ var SessionImpl = class { return { kind: "adoption", error }; } const deadline = this.#clock() + withinMs; - for (const { loaded, ops: ops2, base } of held2) { + for (const { loaded, ops: ops3, base } of held2) { const id = loaded.record.id; let hold = this.#holds.get(id); if (hold === void 0) { @@ -15946,7 +15946,7 @@ var SessionImpl = class { hold = { loaded, pending: new PendingOps(), base: false, deadline, unpin }; this.#holds.set(id, hold); } - hold.pending.push(ops2); + hold.pending.push(ops3); if (base) hold.base = true; if (deadline < hold.deadline) @@ -25033,14 +25033,14 @@ var TaskGraphView = class { const mount = this.#mount; if (mount === void 0) return; - const ops2 = []; + const ops3 = []; for (const [key, record2] of mount.records) { const blocked = this.#blocking.blocked(record2); if (blocked === mount.value.tasks[key]?.blocked) continue; - ops2.push(blocked === void 0 ? ["d", ["tasks", key, "blocked"]] : ["s", ["tasks", key, "blocked"], blocked]); + ops3.push(blocked === void 0 ? ["d", ["tasks", key, "blocked"]] : ["s", ["tasks", key, "blocked"], blocked]); } - publish(mount, ops2, BACKGROUND_CONTEXT, (error) => this.#session.report(error)); + publish(mount, ops3, BACKGROUND_CONTEXT, (error) => this.#session.report(error)); }).catch(() => { }); } @@ -25064,7 +25064,7 @@ var TaskGraphView = class { } }; function advance(mount, publication, context, blocked, report2) { - const ops2 = []; + const ops3 = []; const changed = /* @__PURE__ */ new Map(); const node = (key) => changed.has(key) ? changed.get(key) : mount.value.tasks[key]; for (const change of publication.changes) { @@ -25077,7 +25077,7 @@ function advance(mount, publication, context, blocked, report2) { mount.records.delete(key); if (previous === void 0) continue; - ops2.push(["d", ["tasks", key]]); + ops3.push(["d", ["tasks", key]]); changed.set(key, void 0); continue; } @@ -25086,7 +25086,7 @@ function advance(mount, publication, context, blocked, report2) { const next = nodeOf2(record2, previous?.conversations ?? [], blocked(subject)); if (previous !== void 0 && JSON.stringify(next) === JSON.stringify(previous)) continue; - ops2.push(["s", ["tasks", key], next]); + ops3.push(["s", ["tasks", key], next]); changed.set(key, next); } const created = /* @__PURE__ */ new Map(); @@ -25099,16 +25099,16 @@ function advance(mount, publication, context, blocked, report2) { } for (const [key, ids] of created) { const conversations = [...node(key).conversations, ...ids].sort((a, b) => a - b); - ops2.push(["s", ["tasks", key, "conversations"], conversations]); + ops3.push(["s", ["tasks", key, "conversations"], conversations]); } - publish(mount, ops2, context, report2); + publish(mount, ops3, context, report2); } -function publish(mount, ops2, context, report2) { - if (ops2.length === 0) +function publish(mount, ops3, context, report2) { + if (ops3.length === 0) return; - mount.value = applyImmutable(mount.value, ops2); + mount.value = applyImmutable(mount.value, ops3); const frameContext = withoutAbortSignal(context); - const call = { kind: "value", value: mount.value, ops: ops2, retired: false }; + const call = { kind: "value", value: mount.value, ops: ops3, retired: false }; for (const observer of [...mount.observers]) contained(() => observer.advance(call, frameContext), report2); } @@ -25334,19 +25334,19 @@ function advance2(id, mount, publication, context, report2) { const previous = windowed.value; let entries2 = previous.entries; let before = previous.before; - let ops2 = docOps; + let ops3 = docOps; if (appended.length > 0) { - ops2 = [...docOps, ["p", ["entries"], entries2.length, 0, inserted]]; + ops3 = [...docOps, ["p", ["entries"], entries2.length, 0, inserted]]; entries2 = entries2.concat(appended); if (entries2.length > windowed.max) { const drop = entries2.length - windowed.min; before = entries2[drop - 1].id; entries2 = entries2.slice(drop); - ops2.push(["p", ["entries"], 0, drop, []], ["s", ["before"], before]); + ops3.push(["p", ["entries"], 0, drop, []], ["s", ["before"], before]); } } windowed.value = view(mount.conversation, entries2, before, mount.docs); - const call = { kind: "value", value: windowed.value, ops: ops2, retired: false }; + const call = { kind: "value", value: windowed.value, ops: ops3, retired: false }; contained(() => windowed.observer.advance(call, frameContext), report2); } } @@ -31368,14 +31368,51 @@ function StringEnum(values, options) { }; } -// extensions.ts +// environment.ts +var CodingTools2 = { ...CodingTools, tools: CodingTools.tools.map((tool) => ({ + ...tool, + execute: (args, api, context) => tool.execute(args, { ...api, env: api.env.forTool(api.callId, tool.name) }, context) +})) }; +var Started = defineDoc({ + kind: "board.started", + version: 1, + checkpointWhen: () => false, + scope: "conversation", + history: "latest", + fork: "initial", + initial: () => ({}) +}); +function conversationChains(harness2, context) { + const cache = /* @__PURE__ */ new Map(); + const chain = (id) => { + let result = cache.get(id); + if (!result) { + result = (async () => { + const record2 = await harness2.commit((tx) => tx.conversation(id), context); + const up = record2?.owner?.conversationId ?? record2?.parent?.conversationId; + const starter = (await harness2.snapshot(Started, id, context))?.by; + return [.../* @__PURE__ */ new Set([ + String(id), + ...up === void 0 ? [] : await chain(up), + ...starter === void 0 ? [] : await chain(starter) + ])]; + })(); + cache.set(id, result); + } + return result; + }; + return chain; +} var ops = Deno.core.ops; + +// extensions.ts +var ops2 = Deno.core.ops; var encoder4 = new TextEncoder(); var decoder4 = new TextDecoder(); var ExtensionState = defineDoc({ kind: "sausage.extensions", version: 1, scope: "session", checkpointWhen: () => false, initial: () => ({ good: null, current: null, error: null }) }); var Metadata = defineDoc({ kind: "sausage.metadata", version: 1, scope: "conversation", history: "latest", fork: "current", initial: () => ({ label: "", title: "" }), checkpointWhen: () => false }); async function file(kind, path, bytes2 = []) { - const result = await ops.op_file(kind, path, bytes2); + const result = await ops2.op_file(kind, path, bytes2); if (!result.ok) throw Object.assign(new Error(result.error.message), result.error); return result.value; } @@ -31398,14 +31435,14 @@ async function exec(command, options) { program: `extension:${options.extension}`, conversations: options.conversations ?? [] } : void 0; - const rid = ops.op_exec(command, options.cwd, options.timeout, void 0, options.env, options.conversations, tag); + const rid = ops2.op_exec(command, options.cwd, options.timeout, void 0, options.env, options.conversations, tag); const abort = () => Deno.core.close(rid); options.signal?.addEventListener("abort", abort, { once: true }); const decoders = { stdout: new TextDecoder(), stderr: new TextDecoder() }; const result = { code: 0, stdout: "", stderr: "" }; try { for (; ; ) { - const chunk = await ops.op_exec_next(rid); + const chunk = await ops2.op_exec_next(rid); if (!chunk.stream) { if (chunk.error) throw new Error(chunk.error); result.code = chunk.exitCode; @@ -31432,11 +31469,12 @@ async function git(cwd, ...args) { function registerModules() { const modules = { "@earendil-works/sausage-events": events_exports, "@earendil-works/pi-schema": dist_exports, "@earendil-works/pi-durable": dist_exports3, "@earendil-works/pi-durable/tools": tools_exports, "@earendil-works/pi-ai": dist_exports4, "@earendil-works/pi-ai/models": models_exports, "@earendil-works/chord": dist_exports2, "@earendil-works/chord/context": context_exports }; globalThis.__sausage = { modules }; - ops.op_modules(Object.fromEntries(Object.entries(modules).map(([name, value2]) => [name, Object.keys(value2)]))); + ops2.op_modules(Object.fromEntries(Object.entries(modules).map(([name, value2]) => [name, Object.keys(value2)]))); } async function loadExtensions(harness2, registry2, storage2, models2, context, builtins = []) { registerModules(); const eventService = eventLog(() => harness2); + const chain = conversationChains(harness2, context); const repo = "/src/sausage"; let providers = /* @__PURE__ */ new Map(); const resources = /* @__PURE__ */ new Map(); @@ -31447,7 +31485,7 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b let queue2 = Promise.resolve(); const publish2 = async () => { await harness2.commit(async (tx) => Object.assign(await tx.doc(ExtensionState), state), context); - ops.op_extension_status(JSON.stringify(state)); + ops2.op_extension_status(JSON.stringify(state)); await fs.write("/src/sausage/.git/sausage-last-good", state.good ?? ""); }; const dispose = async (entries2) => { @@ -31455,7 +31493,7 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b try { await cleanup(); } catch (error) { - ops.op_output(`Extension cleanup: ${String(error)} + ops2.op_output(`Extension cleanup: ${String(error)} `); } } @@ -31488,6 +31526,7 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b fs, exec: (command, options) => exec(command, { ...options, extension: name }), git, + chain, implement: (api, value2) => { staged.set(api.name, value2); }, @@ -31510,12 +31549,12 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b onClose: (cb) => close.push(cb), notice: (message) => { state.notice = `${name}: ${message}`; - ops.op_extension_status(JSON.stringify(state)); - ops.op_output(`${name}: ${message} + ops2.op_extension_status(JSON.stringify(state)); + ops2.op_output(`${name}: ${message} `); if (!notices.has(message)) { notices.add(message); - void harness2.commit((tx) => eventService.emit(tx, NoticeEvent, { extension: name, message, level: "warning" }), context).catch((error) => ops.op_output(`Recording a notice failed: ${String(error)} + void harness2.commit((tx) => eventService.emit(tx, NoticeEvent, { extension: name, message, level: "warning" }), context).catch((error) => ops2.op_output(`Recording a notice failed: ${String(error)} `)); } } @@ -31594,7 +31633,7 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b tip = await git(repo, "rev-parse", "refs/heads/main"); } catch (error) { state.error = String(error); - ops.op_extension_status(JSON.stringify(state)); + ops2.op_extension_status(JSON.stringify(state)); return; } try { @@ -31603,8 +31642,8 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b if (error.code === "not_found") settings = {}; else { state.notice = `Settings: ${String(error)}`; - ops.op_extension_status(JSON.stringify(state)); - ops.op_output(`${state.notice} + ops2.op_extension_status(JSON.stringify(state)); + ops2.op_output(`${state.notice} `); } } @@ -31620,11 +31659,11 @@ Last good: ${fallback}` : failed; await publish2(); }; const enqueue2 = () => queue2 = queue2.then(reload); - const rid = ops.op_watch([`${repo}/.git/refs/heads/main`, `${repo}/.git/packed-refs`, `${repo}/settings.json`]); + const rid = ops2.op_watch([`${repo}/.git/refs/heads/main`, `${repo}/.git/packed-refs`, `${repo}/settings.json`]); await enqueue2(); const pending = (async () => { while (active) { - await ops.op_watch_next(rid); + await ops2.op_watch_next(rid); if (active) await enqueue2(); } })(); diff --git a/host/js/extensions-test-bundle.js b/host/js/extensions-test-bundle.js index f6bde74..80783c1 100644 --- a/host/js/extensions-test-bundle.js +++ b/host/js/extensions-test-bundle.js @@ -8946,27 +8946,27 @@ var REPLACE_TAKE = { kind: "replace" }; var PendingOps = class { #state = EMPTY; /** Queue the ops of one commit. */ - push(ops2) { - if (ops2.length === 0) + push(ops3) { + if (ops3.length === 0) return; const state = this.#state; - if (ops2[0][0] === "r") { - this.#state = { kind: "batch", ops: ops2 }; + if (ops3[0][0] === "r") { + this.#state = { kind: "batch", ops: ops3 }; return; } switch (state.kind) { case "empty": - this.#state = { kind: "batch", ops: ops2 }; + this.#state = { kind: "batch", ops: ops3 }; return; case "batch": { const folding = { kind: "folding", ops: [], leaves: /* @__PURE__ */ new Map() }; this.#state = folding; if (this.#fold(state.ops, folding)) - this.#fold(ops2, folding); + this.#fold(ops3, folding); return; } case "folding": - this.#fold(ops2, state); + this.#fold(ops3, state); return; case "replace": return; @@ -8997,8 +8997,8 @@ var PendingOps = class { } } /** Fold `ops` into `folding`; false once the queue overflowed into `replace`. */ - #fold(ops2, folding) { - for (const op2 of ops2) { + #fold(ops3, folding) { + for (const op2 of ops3) { switch (op2[0]) { case "r": folding.ops.length = 0; @@ -9267,12 +9267,12 @@ var PathError = class extends Error { this.name = "PathError"; } }; -function apply(target, ops2) { - return applyOps(target, ops2); +function apply(target, ops3) { + return applyOps(target, ops3); } -function applyOps(target, ops2) { +function applyOps(target, ops3) { let root2 = target; - for (const op2 of ops2) { + for (const op2 of ops3) { assertValidOp(op2); if (op2[0] === "r") { root2 = op2[1]; @@ -9341,14 +9341,14 @@ function applyOps(target, ops2) { } return root2; } -function applyImmutable(target, ops2) { - return applyImmutableBatches(target, [ops2]); +function applyImmutable(target, ops3) { + return applyImmutableBatches(target, [ops3]); } function applyImmutableBatches(target, batches) { let root2 = target; const owned = /* @__PURE__ */ new WeakSet(); - for (const ops2 of batches) { - for (const op2 of ops2) { + for (const ops3 of batches) { + for (const op2 of ops3) { assertValidOp(op2); if (op2[0] === "r") { root2 = op2[1]; @@ -9462,10 +9462,10 @@ function encoder() { let nextId = 0; let previous; return { - encode(ops2) { + encode(ops3) { previous = void 0; const out = []; - for (const op2 of ops2) { + for (const op2 of ops3) { if (op2[0] === "r") { out.push(op2); seen.clear(); @@ -9715,9 +9715,9 @@ var Source = class { return []; } }; -function unbox(ops2, value2) { +function unbox(ops3, value2) { const result = []; - for (const op2 of ops2) { + for (const op2 of ops3) { if (op2[0] === "r" || op2[1].length === 0) return [["r", value2]]; const path = op2[1].slice(1); @@ -9811,8 +9811,8 @@ var Cell = class extends Source { throw notReady(`state ${this.key} (its init has not run)`); const before = this.value; const diff = options.diff ?? sharesStructure(before, value2); - const ops2 = diff ? diffRevisions(before, value2) : void 0; - this.#publish(this.#tracker.prepareReplace({ v: value2 }), "ops", true, ops2); + const ops3 = diff ? diffRevisions(before, value2) : void 0; + this.#publish(this.#tracker.prepareReplace({ v: value2 }), "ops", true, ops3); } /** * Installs a migrated value and its schema (reload commit). The caller validated the value and the derivations @@ -9823,7 +9823,7 @@ var Cell = class extends Source { this.#publish(this.#tracker.prepareReplace({ v: value2 }), "reset", false); } /** Adopts this revision and every derived one, then queues all notifications (cell first, then derivations). */ - #publish(prepared, type, validate2 = true, ops2) { + #publish(prepared, type, validate2 = true, ops3) { if (prepared.ops.length === 0 && type === "ops") { this.#tracker.adopt(prepared); return; @@ -9840,7 +9840,7 @@ var Cell = class extends Source { } holdPublications(() => { this.#tracker.adopt(prepared); - const published = ops2 !== void 0 && ops2.length > 0 ? ops2 : unbox(prepared.ops, value2); + const published = ops3 !== void 0 && ops3.length > 0 ? ops3 : unbox(prepared.ops, value2); this.fanout.emit(type === "reset" ? { type, value: value2 } : { type, ops: published, value: value2 }); for (const [derived, next] of candidates) derived.install(next); @@ -9953,9 +9953,9 @@ var Derived = class extends Source { install(next) { const before = this.#value; this.#value = next; - const ops2 = before === void 0 || next === void 0 ? [["r", next ?? null]] : diffRevisions(before, next); - if (ops2.length > 0) - this.fanout.emit({ type: "ops", ops: ops2, value: next }); + const ops3 = before === void 0 || next === void 0 ? [["r", next ?? null]] : diffRevisions(before, next); + if (ops3.length > 0) + this.fanout.emit({ type: "ops", ops: ops3, value: next }); } }; var isSource = (value2) => value2 instanceof Source; @@ -14008,10 +14008,10 @@ var RemoteBinding = class { const target = pending?.values.get(name) ?? this.members.get(name); if (target === void 0) return; - const ops2 = target.decoder.decode(frame.ops ?? []); - target.value = applyImmutable(target.value, ops2); + const ops3 = target.decoder.decode(frame.ops ?? []); + target.value = applyImmutable(target.value, ops3); if (target === this.members.get(name)) - this.#deliver(name, { type: "ops", ops: ops2, value: target.value }); + this.#deliver(name, { type: "ops", ops: ops3, value: target.value }); return; } const fresh = { value: frame.value, decoder: decoder() }; @@ -15835,8 +15835,8 @@ var Watch = class extends WatchLifecycle { this.#retired = false; if (lone !== void 0) return lone; - const ops2 = batch.kind === "ops" ? batch.ops : [["r", value2]]; - return { kind: "value", value: value2, ops: ops2, retired }; + const ops3 = batch.kind === "ops" ? batch.ops : [["r", value2]]; + return { kind: "value", value: value2, ops: ops3, retired }; } /** The pending failure, or the value after one as a root replacement (no ops were kept since the failure). */ #nextAfterFailure() { @@ -17601,7 +17601,7 @@ function describe(plan, record2) { const change = plan.change; if (change === void 0 || !publishes(plan)) return void 0; - const ops2 = change.loaded === void 0 ? EMPTY_OPERATIONS : change.prepared.ops; + const ops3 = change.loaded === void 0 ? EMPTY_OPERATIONS : change.prepared.ops; return { type: "document", kind: "change", @@ -17609,11 +17609,11 @@ function describe(plan, record2) { conversationId, version: change.version, value: change.prepared.value, - ops: ops2 + ops: ops3 }; } -function storeHeld(hold, ops2, value2, version) { - hold.pending.push(ops2); +function storeHeld(hold, ops3, value2, version) { + hold.pending.push(ops3); const taken = hold.pending.take(); if (taken.kind === "replace") return { content: { version, kind: "base", value: value2 }, ops: [["r", value2]] }; @@ -18694,7 +18694,7 @@ var SessionImpl = class { return { kind: "adoption", error }; } const deadline = this.#clock() + withinMs; - for (const { loaded, ops: ops2, base } of held2) { + for (const { loaded, ops: ops3, base } of held2) { const id = loaded.record.id; let hold = this.#holds.get(id); if (hold === void 0) { @@ -18702,7 +18702,7 @@ var SessionImpl = class { hold = { loaded, pending: new PendingOps(), base: false, deadline, unpin }; this.#holds.set(id, hold); } - hold.pending.push(ops2); + hold.pending.push(ops3); if (base) hold.base = true; if (deadline < hold.deadline) @@ -26917,14 +26917,14 @@ var TaskGraphView = class { const mount = this.#mount; if (mount === void 0) return; - const ops2 = []; + const ops3 = []; for (const [key, record2] of mount.records) { const blocked = this.#blocking.blocked(record2); if (blocked === mount.value.tasks[key]?.blocked) continue; - ops2.push(blocked === void 0 ? ["d", ["tasks", key, "blocked"]] : ["s", ["tasks", key, "blocked"], blocked]); + ops3.push(blocked === void 0 ? ["d", ["tasks", key, "blocked"]] : ["s", ["tasks", key, "blocked"], blocked]); } - publish(mount, ops2, BACKGROUND_CONTEXT, (error) => this.#session.report(error)); + publish(mount, ops3, BACKGROUND_CONTEXT, (error) => this.#session.report(error)); }).catch(() => { }); } @@ -26948,7 +26948,7 @@ var TaskGraphView = class { } }; function advance(mount, publication, context, blocked, report2) { - const ops2 = []; + const ops3 = []; const changed = /* @__PURE__ */ new Map(); const node = (key) => changed.has(key) ? changed.get(key) : mount.value.tasks[key]; for (const change of publication.changes) { @@ -26961,7 +26961,7 @@ function advance(mount, publication, context, blocked, report2) { mount.records.delete(key); if (previous === void 0) continue; - ops2.push(["d", ["tasks", key]]); + ops3.push(["d", ["tasks", key]]); changed.set(key, void 0); continue; } @@ -26970,7 +26970,7 @@ function advance(mount, publication, context, blocked, report2) { const next = nodeOf2(record2, previous?.conversations ?? [], blocked(subject)); if (previous !== void 0 && JSON.stringify(next) === JSON.stringify(previous)) continue; - ops2.push(["s", ["tasks", key], next]); + ops3.push(["s", ["tasks", key], next]); changed.set(key, next); } const created = /* @__PURE__ */ new Map(); @@ -26983,16 +26983,16 @@ function advance(mount, publication, context, blocked, report2) { } for (const [key, ids] of created) { const conversations = [...node(key).conversations, ...ids].sort((a, b) => a - b); - ops2.push(["s", ["tasks", key, "conversations"], conversations]); + ops3.push(["s", ["tasks", key, "conversations"], conversations]); } - publish(mount, ops2, context, report2); + publish(mount, ops3, context, report2); } -function publish(mount, ops2, context, report2) { - if (ops2.length === 0) +function publish(mount, ops3, context, report2) { + if (ops3.length === 0) return; - mount.value = applyImmutable(mount.value, ops2); + mount.value = applyImmutable(mount.value, ops3); const frameContext = withoutAbortSignal(context); - const call = { kind: "value", value: mount.value, ops: ops2, retired: false }; + const call = { kind: "value", value: mount.value, ops: ops3, retired: false }; for (const observer of [...mount.observers]) contained(() => observer.advance(call, frameContext), report2); } @@ -27218,19 +27218,19 @@ function advance2(id, mount, publication, context, report2) { const previous = windowed.value; let entries2 = previous.entries; let before = previous.before; - let ops2 = docOps; + let ops3 = docOps; if (appended.length > 0) { - ops2 = [...docOps, ["p", ["entries"], entries2.length, 0, inserted]]; + ops3 = [...docOps, ["p", ["entries"], entries2.length, 0, inserted]]; entries2 = entries2.concat(appended); if (entries2.length > windowed.max) { const drop = entries2.length - windowed.min; before = entries2[drop - 1].id; entries2 = entries2.slice(drop); - ops2.push(["p", ["entries"], 0, drop, []], ["s", ["before"], before]); + ops3.push(["p", ["entries"], 0, drop, []], ["s", ["before"], before]); } } windowed.value = view(mount.conversation, entries2, before, mount.docs); - const call = { kind: "value", value: windowed.value, ops: ops2, retired: false }; + const call = { kind: "value", value: windowed.value, ops: ops3, retired: false }; contained(() => windowed.observer.advance(call, frameContext), report2); } } @@ -31368,14 +31368,51 @@ function eventLog(harness2) { } } -// extensions.ts +// environment.ts +var CodingTools2 = { ...CodingTools, tools: CodingTools.tools.map((tool) => ({ + ...tool, + execute: (args, api, context) => tool.execute(args, { ...api, env: api.env.forTool(api.callId, tool.name) }, context) +})) }; +var Started = defineDoc({ + kind: "board.started", + version: 1, + checkpointWhen: () => false, + scope: "conversation", + history: "latest", + fork: "initial", + initial: () => ({}) +}); +function conversationChains(harness2, context) { + const cache = /* @__PURE__ */ new Map(); + const chain = (id) => { + let result = cache.get(id); + if (!result) { + result = (async () => { + const record2 = await harness2.commit((tx) => tx.conversation(id), context); + const up = record2?.owner?.conversationId ?? record2?.parent?.conversationId; + const starter = (await harness2.snapshot(Started, id, context))?.by; + return [.../* @__PURE__ */ new Set([ + String(id), + ...up === void 0 ? [] : await chain(up), + ...starter === void 0 ? [] : await chain(starter) + ])]; + })(); + cache.set(id, result); + } + return result; + }; + return chain; +} var ops = Deno.core.ops; + +// extensions.ts +var ops2 = Deno.core.ops; var encoder4 = new TextEncoder(); var decoder4 = new TextDecoder(); var ExtensionState = defineDoc({ kind: "sausage.extensions", version: 1, scope: "session", checkpointWhen: () => false, initial: () => ({ good: null, current: null, error: null }) }); var Metadata = defineDoc({ kind: "sausage.metadata", version: 1, scope: "conversation", history: "latest", fork: "current", initial: () => ({ label: "", title: "" }), checkpointWhen: () => false }); async function file(kind, path, bytes2 = []) { - const result = await ops.op_file(kind, path, bytes2); + const result = await ops2.op_file(kind, path, bytes2); if (!result.ok) throw Object.assign(new Error(result.error.message), result.error); return result.value; } @@ -31398,14 +31435,14 @@ async function exec(command, options) { program: `extension:${options.extension}`, conversations: options.conversations ?? [] } : void 0; - const rid = ops.op_exec(command, options.cwd, options.timeout, void 0, options.env, options.conversations, tag); + const rid = ops2.op_exec(command, options.cwd, options.timeout, void 0, options.env, options.conversations, tag); const abort = () => Deno.core.close(rid); options.signal?.addEventListener("abort", abort, { once: true }); const decoders = { stdout: new TextDecoder(), stderr: new TextDecoder() }; const result = { code: 0, stdout: "", stderr: "" }; try { for (; ; ) { - const chunk = await ops.op_exec_next(rid); + const chunk = await ops2.op_exec_next(rid); if (!chunk.stream) { if (chunk.error) throw new Error(chunk.error); result.code = chunk.exitCode; @@ -31432,11 +31469,12 @@ async function git(cwd, ...args) { function registerModules() { const modules = { "@earendil-works/sausage-events": events_exports, "@earendil-works/pi-schema": dist_exports, "@earendil-works/pi-durable": dist_exports3, "@earendil-works/pi-durable/tools": tools_exports, "@earendil-works/pi-ai": dist_exports4, "@earendil-works/pi-ai/models": models_exports, "@earendil-works/chord": dist_exports2, "@earendil-works/chord/context": context_exports }; globalThis.__sausage = { modules }; - ops.op_modules(Object.fromEntries(Object.entries(modules).map(([name, value2]) => [name, Object.keys(value2)]))); + ops2.op_modules(Object.fromEntries(Object.entries(modules).map(([name, value2]) => [name, Object.keys(value2)]))); } async function loadExtensions(harness2, registry2, storage2, models2, context, builtins = []) { registerModules(); const eventService = eventLog(() => harness2); + const chain = conversationChains(harness2, context); const repo = "/src/sausage"; let providers = /* @__PURE__ */ new Map(); const resources = /* @__PURE__ */ new Map(); @@ -31447,7 +31485,7 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b let queue2 = Promise.resolve(); const publish2 = async () => { await harness2.commit(async (tx) => Object.assign(await tx.doc(ExtensionState), state), context); - ops.op_extension_status(JSON.stringify(state)); + ops2.op_extension_status(JSON.stringify(state)); await fs.write("/src/sausage/.git/sausage-last-good", state.good ?? ""); }; const dispose = async (entries2) => { @@ -31455,7 +31493,7 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b try { await cleanup(); } catch (error) { - ops.op_output(`Extension cleanup: ${String(error)} + ops2.op_output(`Extension cleanup: ${String(error)} `); } } @@ -31488,6 +31526,7 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b fs, exec: (command, options) => exec(command, { ...options, extension: name }), git, + chain, implement: (api, value2) => { staged.set(api.name, value2); }, @@ -31510,12 +31549,12 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b onClose: (cb) => close.push(cb), notice: (message) => { state.notice = `${name}: ${message}`; - ops.op_extension_status(JSON.stringify(state)); - ops.op_output(`${name}: ${message} + ops2.op_extension_status(JSON.stringify(state)); + ops2.op_output(`${name}: ${message} `); if (!notices.has(message)) { notices.add(message); - void harness2.commit((tx) => eventService.emit(tx, NoticeEvent, { extension: name, message, level: "warning" }), context).catch((error) => ops.op_output(`Recording a notice failed: ${String(error)} + void harness2.commit((tx) => eventService.emit(tx, NoticeEvent, { extension: name, message, level: "warning" }), context).catch((error) => ops2.op_output(`Recording a notice failed: ${String(error)} `)); } } @@ -31594,7 +31633,7 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b tip = await git(repo, "rev-parse", "refs/heads/main"); } catch (error) { state.error = String(error); - ops.op_extension_status(JSON.stringify(state)); + ops2.op_extension_status(JSON.stringify(state)); return; } try { @@ -31603,8 +31642,8 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b if (error.code === "not_found") settings = {}; else { state.notice = `Settings: ${String(error)}`; - ops.op_extension_status(JSON.stringify(state)); - ops.op_output(`${state.notice} + ops2.op_extension_status(JSON.stringify(state)); + ops2.op_output(`${state.notice} `); } } @@ -31620,11 +31659,11 @@ Last good: ${fallback}` : failed; await publish2(); }; const enqueue2 = () => queue2 = queue2.then(reload); - const rid = ops.op_watch([`${repo}/.git/refs/heads/main`, `${repo}/.git/packed-refs`, `${repo}/settings.json`]); + const rid = ops2.op_watch([`${repo}/.git/refs/heads/main`, `${repo}/.git/packed-refs`, `${repo}/settings.json`]); await enqueue2(); const pending = (async () => { while (active) { - await ops.op_watch_next(rid); + await ops2.op_watch_next(rid); if (active) await enqueue2(); } })(); diff --git a/host/js/extensions.ts b/host/js/extensions.ts index a949848..2b51c5b 100644 --- a/host/js/extensions.ts +++ b/host/js/extensions.ts @@ -7,6 +7,7 @@ import * as chord from '@earendil-works/chord'; import * as contextApi from '@earendil-works/chord/context'; import * as schema from '@earendil-works/pi-schema'; import * as events from './events'; +import { conversationChains } from './environment'; const ops = Deno.core.ops; const encoder = new TextEncoder(); const decoder = new TextDecoder(); @@ -16,6 +17,7 @@ export type Host = events.EventHost & { harness(): durable.Harness; storage: Pick; models(): modelApi.Models; settings(): durable.JsonObject; metadata: typeof Metadata; fs: typeof fs; exec: typeof exec; git: typeof git; + chain(conversationId:number):Promise; implement(api: {name:string;readonly service?:S}, value:NoInfer):void; need(api:{name:string;readonly service?:S}):S; want(api:{name:string;readonly service?:S}):S|undefined; resource(key:string, create:()=>T):T; @@ -73,6 +75,7 @@ export function registerModules() { export async function loadExtensions(harness:any, registry:any, storage:any, models:any, context:any, builtins:any[]=[]) { registerModules(); const eventService = events.eventLog(()=>harness); + const chain = conversationChains(harness,context); const repo = '/src/sausage'; let providers = new Map(); const resources = new Map(); @@ -104,7 +107,7 @@ export async function loadExtensions(harness:any, registry:any, storage:any, mod }}); const host:Host = { harness:()=>harness, storage, models:()=>models, settings:()=>settings, metadata:Metadata, fs, - exec:(command,options)=>exec(command,{...options,extension:name}),git, + exec:(command,options)=>exec(command,{...options,extension:name}),git,chain, implement:(api,value)=>{staged.set(api.name,value);}, need:handle, want:(api)=>providers.has(api.name)?handle(api):undefined, resource:(key,create)=>{const id=`${name}/${key}`;if(!resources.has(id))resources.set(id,create());return resources.get(id);}, diff --git a/host/js/messages-test-bundle.js b/host/js/messages-test-bundle.js index 0c3f5f9..26b4f3d 100644 --- a/host/js/messages-test-bundle.js +++ b/host/js/messages-test-bundle.js @@ -30428,14 +30428,51 @@ function eventLog(harness2) { } } -// extensions.ts +// environment.ts +var CodingTools2 = { ...CodingTools, tools: CodingTools.tools.map((tool2) => ({ + ...tool2, + execute: (args, api, context) => tool2.execute(args, { ...api, env: api.env.forTool(api.callId, tool2.name) }, context) +})) }; +var Started = defineDoc({ + kind: "board.started", + version: 1, + checkpointWhen: () => false, + scope: "conversation", + history: "latest", + fork: "initial", + initial: () => ({}) +}); +function conversationChains(harness2, context) { + const cache = /* @__PURE__ */ new Map(); + const chain = (id) => { + let result = cache.get(id); + if (!result) { + result = (async () => { + const record2 = await harness2.commit((tx) => tx.conversation(id), context); + const up = record2?.owner?.conversationId ?? record2?.parent?.conversationId; + const starter = (await harness2.snapshot(Started, id, context))?.by; + return [.../* @__PURE__ */ new Set([ + String(id), + ...up === void 0 ? [] : await chain(up), + ...starter === void 0 ? [] : await chain(starter) + ])]; + })(); + cache.set(id, result); + } + return result; + }; + return chain; +} var ops = Deno.core.ops; + +// extensions.ts +var ops2 = Deno.core.ops; var encoder4 = new TextEncoder(); var decoder4 = new TextDecoder(); var ExtensionState = defineDoc({ kind: "sausage.extensions", version: 1, scope: "session", checkpointWhen: () => false, initial: () => ({ good: null, current: null, error: null }) }); var Metadata = defineDoc({ kind: "sausage.metadata", version: 1, scope: "conversation", history: "latest", fork: "current", initial: () => ({ label: "", title: "" }), checkpointWhen: () => false }); async function file(kind, path, bytes2 = []) { - const result = await ops.op_file(kind, path, bytes2); + const result = await ops2.op_file(kind, path, bytes2); if (!result.ok) throw Object.assign(new Error(result.error.message), result.error); return result.value; } @@ -30458,14 +30495,14 @@ async function exec(command, options) { program: `extension:${options.extension}`, conversations: options.conversations ?? [] } : void 0; - const rid = ops.op_exec(command, options.cwd, options.timeout, void 0, options.env, options.conversations, tag); + const rid = ops2.op_exec(command, options.cwd, options.timeout, void 0, options.env, options.conversations, tag); const abort = () => Deno.core.close(rid); options.signal?.addEventListener("abort", abort, { once: true }); const decoders = { stdout: new TextDecoder(), stderr: new TextDecoder() }; const result = { code: 0, stdout: "", stderr: "" }; try { for (; ; ) { - const chunk = await ops.op_exec_next(rid); + const chunk = await ops2.op_exec_next(rid); if (!chunk.stream) { if (chunk.error) throw new Error(chunk.error); result.code = chunk.exitCode; @@ -30492,11 +30529,12 @@ async function git(cwd, ...args) { function registerModules() { const modules = { "@earendil-works/sausage-events": events_exports, "@earendil-works/pi-schema": dist_exports, "@earendil-works/pi-durable": dist_exports3, "@earendil-works/pi-durable/tools": tools_exports, "@earendil-works/pi-ai": dist_exports4, "@earendil-works/pi-ai/models": models_exports, "@earendil-works/chord": dist_exports2, "@earendil-works/chord/context": context_exports }; globalThis.__sausage = { modules }; - ops.op_modules(Object.fromEntries(Object.entries(modules).map(([name, value2]) => [name, Object.keys(value2)]))); + ops2.op_modules(Object.fromEntries(Object.entries(modules).map(([name, value2]) => [name, Object.keys(value2)]))); } async function loadExtensions(harness2, registry2, storage2, models2, context, builtins = []) { registerModules(); const eventService = eventLog(() => harness2); + const chain = conversationChains(harness2, context); const repo = "/src/sausage"; let providers = /* @__PURE__ */ new Map(); const resources = /* @__PURE__ */ new Map(); @@ -30507,7 +30545,7 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b let queue2 = Promise.resolve(); const publish2 = async () => { await harness2.commit(async (tx) => Object.assign(await tx.doc(ExtensionState), state), context); - ops.op_extension_status(JSON.stringify(state)); + ops2.op_extension_status(JSON.stringify(state)); await fs.write("/src/sausage/.git/sausage-last-good", state.good ?? ""); }; const dispose = async (entries3) => { @@ -30515,7 +30553,7 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b try { await cleanup(); } catch (error) { - ops.op_output(`Extension cleanup: ${String(error)} + ops2.op_output(`Extension cleanup: ${String(error)} `); } } @@ -30548,6 +30586,7 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b fs, exec: (command, options) => exec(command, { ...options, extension: name }), git, + chain, implement: (api, value2) => { staged.set(api.name, value2); }, @@ -30570,12 +30609,12 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b onClose: (cb) => close.push(cb), notice: (message) => { state.notice = `${name}: ${message}`; - ops.op_extension_status(JSON.stringify(state)); - ops.op_output(`${name}: ${message} + ops2.op_extension_status(JSON.stringify(state)); + ops2.op_output(`${name}: ${message} `); if (!notices.has(message)) { notices.add(message); - void harness2.commit((tx) => eventService.emit(tx, NoticeEvent, { extension: name, message, level: "warning" }), context).catch((error) => ops.op_output(`Recording a notice failed: ${String(error)} + void harness2.commit((tx) => eventService.emit(tx, NoticeEvent, { extension: name, message, level: "warning" }), context).catch((error) => ops2.op_output(`Recording a notice failed: ${String(error)} `)); } } @@ -30654,7 +30693,7 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b tip = await git(repo, "rev-parse", "refs/heads/main"); } catch (error) { state.error = String(error); - ops.op_extension_status(JSON.stringify(state)); + ops2.op_extension_status(JSON.stringify(state)); return; } try { @@ -30663,8 +30702,8 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b if (error.code === "not_found") settings = {}; else { state.notice = `Settings: ${String(error)}`; - ops.op_extension_status(JSON.stringify(state)); - ops.op_output(`${state.notice} + ops2.op_extension_status(JSON.stringify(state)); + ops2.op_output(`${state.notice} `); } } @@ -30680,11 +30719,11 @@ Last good: ${fallback}` : failed; await publish2(); }; const enqueue2 = () => queue2 = queue2.then(reload); - const rid = ops.op_watch([`${repo}/.git/refs/heads/main`, `${repo}/.git/packed-refs`, `${repo}/settings.json`]); + const rid = ops2.op_watch([`${repo}/.git/refs/heads/main`, `${repo}/.git/packed-refs`, `${repo}/settings.json`]); await enqueue2(); const pending = (async () => { while (active) { - await ops.op_watch_next(rid); + await ops2.op_watch_next(rid); if (active) await enqueue2(); } })(); @@ -30697,43 +30736,6 @@ Last good: ${fallback}` : failed; } }; } -// environment.ts -var CodingTools2 = { ...CodingTools, tools: CodingTools.tools.map((tool2) => ({ - ...tool2, - execute: (args, api, context) => tool2.execute(args, { ...api, env: api.env.forTool(api.callId, tool2.name) }, context) -})) }; -var Started = defineDoc({ - kind: "board.started", - version: 1, - checkpointWhen: () => false, - scope: "conversation", - history: "latest", - fork: "initial", - initial: () => ({}) -}); -function conversationChains(harness2, context) { - const cache = /* @__PURE__ */ new Map(); - const chain = (id) => { - let result = cache.get(id); - if (!result) { - result = (async () => { - const record2 = await harness2.commit((tx) => tx.conversation(id), context); - const up = record2?.owner?.conversationId ?? record2?.parent?.conversationId; - const starter = (await harness2.snapshot(Started, id, context))?.by; - return [.../* @__PURE__ */ new Set([ - String(id), - ...up === void 0 ? [] : await chain(up), - ...starter === void 0 ? [] : await chain(starter) - ])]; - })(); - cache.set(id, result); - } - return result; - }; - return chain; -} -var ops2 = Deno.core.ops; - // node_modules/@earendil-works/chord/dist/sqlite/schema.js function validateSqliteSchemaPrefix(prefix) { if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(prefix)) { diff --git a/host/js/p3-test-bundle.js b/host/js/p3-test-bundle.js index a1fe2a6..a3dfa78 100644 --- a/host/js/p3-test-bundle.js +++ b/host/js/p3-test-bundle.js @@ -7915,27 +7915,27 @@ var REPLACE_TAKE = { kind: "replace" }; var PendingOps = class { #state = EMPTY; /** Queue the ops of one commit. */ - push(ops2) { - if (ops2.length === 0) + push(ops3) { + if (ops3.length === 0) return; const state = this.#state; - if (ops2[0][0] === "r") { - this.#state = { kind: "batch", ops: ops2 }; + if (ops3[0][0] === "r") { + this.#state = { kind: "batch", ops: ops3 }; return; } switch (state.kind) { case "empty": - this.#state = { kind: "batch", ops: ops2 }; + this.#state = { kind: "batch", ops: ops3 }; return; case "batch": { const folding = { kind: "folding", ops: [], leaves: /* @__PURE__ */ new Map() }; this.#state = folding; if (this.#fold(state.ops, folding)) - this.#fold(ops2, folding); + this.#fold(ops3, folding); return; } case "folding": - this.#fold(ops2, state); + this.#fold(ops3, state); return; case "replace": return; @@ -7966,8 +7966,8 @@ var PendingOps = class { } } /** Fold `ops` into `folding`; false once the queue overflowed into `replace`. */ - #fold(ops2, folding) { - for (const op2 of ops2) { + #fold(ops3, folding) { + for (const op2 of ops3) { switch (op2[0]) { case "r": folding.ops.length = 0; @@ -8236,12 +8236,12 @@ var PathError = class extends Error { this.name = "PathError"; } }; -function apply(target, ops2) { - return applyOps(target, ops2); +function apply(target, ops3) { + return applyOps(target, ops3); } -function applyOps(target, ops2) { +function applyOps(target, ops3) { let root = target; - for (const op2 of ops2) { + for (const op2 of ops3) { assertValidOp(op2); if (op2[0] === "r") { root = op2[1]; @@ -8310,14 +8310,14 @@ function applyOps(target, ops2) { } return root; } -function applyImmutable(target, ops2) { - return applyImmutableBatches(target, [ops2]); +function applyImmutable(target, ops3) { + return applyImmutableBatches(target, [ops3]); } function applyImmutableBatches(target, batches) { let root = target; const owned = /* @__PURE__ */ new WeakSet(); - for (const ops2 of batches) { - for (const op2 of ops2) { + for (const ops3 of batches) { + for (const op2 of ops3) { assertValidOp(op2); if (op2[0] === "r") { root = op2[1]; @@ -8431,10 +8431,10 @@ function encoder() { let nextId = 0; let previous; return { - encode(ops2) { + encode(ops3) { previous = void 0; const out = []; - for (const op2 of ops2) { + for (const op2 of ops3) { if (op2[0] === "r") { out.push(op2); seen.clear(); @@ -8684,9 +8684,9 @@ var Source = class { return []; } }; -function unbox(ops2, value2) { +function unbox(ops3, value2) { const result = []; - for (const op2 of ops2) { + for (const op2 of ops3) { if (op2[0] === "r" || op2[1].length === 0) return [["r", value2]]; const path = op2[1].slice(1); @@ -8780,8 +8780,8 @@ var Cell = class extends Source { throw notReady(`state ${this.key} (its init has not run)`); const before = this.value; const diff = options.diff ?? sharesStructure(before, value2); - const ops2 = diff ? diffRevisions(before, value2) : void 0; - this.#publish(this.#tracker.prepareReplace({ v: value2 }), "ops", true, ops2); + const ops3 = diff ? diffRevisions(before, value2) : void 0; + this.#publish(this.#tracker.prepareReplace({ v: value2 }), "ops", true, ops3); } /** * Installs a migrated value and its schema (reload commit). The caller validated the value and the derivations @@ -8792,7 +8792,7 @@ var Cell = class extends Source { this.#publish(this.#tracker.prepareReplace({ v: value2 }), "reset", false); } /** Adopts this revision and every derived one, then queues all notifications (cell first, then derivations). */ - #publish(prepared, type, validate2 = true, ops2) { + #publish(prepared, type, validate2 = true, ops3) { if (prepared.ops.length === 0 && type === "ops") { this.#tracker.adopt(prepared); return; @@ -8809,7 +8809,7 @@ var Cell = class extends Source { } holdPublications(() => { this.#tracker.adopt(prepared); - const published = ops2 !== void 0 && ops2.length > 0 ? ops2 : unbox(prepared.ops, value2); + const published = ops3 !== void 0 && ops3.length > 0 ? ops3 : unbox(prepared.ops, value2); this.fanout.emit(type === "reset" ? { type, value: value2 } : { type, ops: published, value: value2 }); for (const [derived, next] of candidates) derived.install(next); @@ -8922,9 +8922,9 @@ var Derived = class extends Source { install(next) { const before = this.#value; this.#value = next; - const ops2 = before === void 0 || next === void 0 ? [["r", next ?? null]] : diffRevisions(before, next); - if (ops2.length > 0) - this.fanout.emit({ type: "ops", ops: ops2, value: next }); + const ops3 = before === void 0 || next === void 0 ? [["r", next ?? null]] : diffRevisions(before, next); + if (ops3.length > 0) + this.fanout.emit({ type: "ops", ops: ops3, value: next }); } }; var isSource = (value2) => value2 instanceof Source; @@ -12977,10 +12977,10 @@ var RemoteBinding = class { const target = pending?.values.get(name) ?? this.members.get(name); if (target === void 0) return; - const ops2 = target.decoder.decode(frame.ops ?? []); - target.value = applyImmutable(target.value, ops2); + const ops3 = target.decoder.decode(frame.ops ?? []); + target.value = applyImmutable(target.value, ops3); if (target === this.members.get(name)) - this.#deliver(name, { type: "ops", ops: ops2, value: target.value }); + this.#deliver(name, { type: "ops", ops: ops3, value: target.value }); return; } const fresh = { value: frame.value, decoder: decoder() }; @@ -14804,8 +14804,8 @@ var Watch = class extends WatchLifecycle { this.#retired = false; if (lone !== void 0) return lone; - const ops2 = batch.kind === "ops" ? batch.ops : [["r", value2]]; - return { kind: "value", value: value2, ops: ops2, retired }; + const ops3 = batch.kind === "ops" ? batch.ops : [["r", value2]]; + return { kind: "value", value: value2, ops: ops3, retired }; } /** The pending failure, or the value after one as a root replacement (no ops were kept since the failure). */ #nextAfterFailure() { @@ -16570,7 +16570,7 @@ function describe(plan, record2) { const change = plan.change; if (change === void 0 || !publishes(plan)) return void 0; - const ops2 = change.loaded === void 0 ? EMPTY_OPERATIONS : change.prepared.ops; + const ops3 = change.loaded === void 0 ? EMPTY_OPERATIONS : change.prepared.ops; return { type: "document", kind: "change", @@ -16578,11 +16578,11 @@ function describe(plan, record2) { conversationId, version: change.version, value: change.prepared.value, - ops: ops2 + ops: ops3 }; } -function storeHeld(hold, ops2, value2, version) { - hold.pending.push(ops2); +function storeHeld(hold, ops3, value2, version) { + hold.pending.push(ops3); const taken = hold.pending.take(); if (taken.kind === "replace") return { content: { version, kind: "base", value: value2 }, ops: [["r", value2]] }; @@ -17663,7 +17663,7 @@ var SessionImpl = class { return { kind: "adoption", error }; } const deadline = this.#clock() + withinMs; - for (const { loaded, ops: ops2, base } of held2) { + for (const { loaded, ops: ops3, base } of held2) { const id = loaded.record.id; let hold = this.#holds.get(id); if (hold === void 0) { @@ -17671,7 +17671,7 @@ var SessionImpl = class { hold = { loaded, pending: new PendingOps(), base: false, deadline, unpin }; this.#holds.set(id, hold); } - hold.pending.push(ops2); + hold.pending.push(ops3); if (base) hold.base = true; if (deadline < hold.deadline) @@ -26442,14 +26442,14 @@ var TaskGraphView = class { const mount = this.#mount; if (mount === void 0) return; - const ops2 = []; + const ops3 = []; for (const [key, record2] of mount.records) { const blocked = this.#blocking.blocked(record2); if (blocked === mount.value.tasks[key]?.blocked) continue; - ops2.push(blocked === void 0 ? ["d", ["tasks", key, "blocked"]] : ["s", ["tasks", key, "blocked"], blocked]); + ops3.push(blocked === void 0 ? ["d", ["tasks", key, "blocked"]] : ["s", ["tasks", key, "blocked"], blocked]); } - publish(mount, ops2, BACKGROUND_CONTEXT, (error) => this.#session.report(error)); + publish(mount, ops3, BACKGROUND_CONTEXT, (error) => this.#session.report(error)); }).catch(() => { }); } @@ -26473,7 +26473,7 @@ var TaskGraphView = class { } }; function advance(mount, publication, context, blocked, report2) { - const ops2 = []; + const ops3 = []; const changed = /* @__PURE__ */ new Map(); const node = (key) => changed.has(key) ? changed.get(key) : mount.value.tasks[key]; for (const change of publication.changes) { @@ -26486,7 +26486,7 @@ function advance(mount, publication, context, blocked, report2) { mount.records.delete(key); if (previous === void 0) continue; - ops2.push(["d", ["tasks", key]]); + ops3.push(["d", ["tasks", key]]); changed.set(key, void 0); continue; } @@ -26495,7 +26495,7 @@ function advance(mount, publication, context, blocked, report2) { const next = nodeOf2(record2, previous?.conversations ?? [], blocked(subject)); if (previous !== void 0 && JSON.stringify(next) === JSON.stringify(previous)) continue; - ops2.push(["s", ["tasks", key], next]); + ops3.push(["s", ["tasks", key], next]); changed.set(key, next); } const created = /* @__PURE__ */ new Map(); @@ -26508,16 +26508,16 @@ function advance(mount, publication, context, blocked, report2) { } for (const [key, ids] of created) { const conversations = [...node(key).conversations, ...ids].sort((a, b) => a - b); - ops2.push(["s", ["tasks", key, "conversations"], conversations]); + ops3.push(["s", ["tasks", key, "conversations"], conversations]); } - publish(mount, ops2, context, report2); + publish(mount, ops3, context, report2); } -function publish(mount, ops2, context, report2) { - if (ops2.length === 0) +function publish(mount, ops3, context, report2) { + if (ops3.length === 0) return; - mount.value = applyImmutable(mount.value, ops2); + mount.value = applyImmutable(mount.value, ops3); const frameContext = withoutAbortSignal(context); - const call = { kind: "value", value: mount.value, ops: ops2, retired: false }; + const call = { kind: "value", value: mount.value, ops: ops3, retired: false }; for (const observer of [...mount.observers]) contained(() => observer.advance(call, frameContext), report2); } @@ -26743,19 +26743,19 @@ function advance2(id, mount, publication, context, report2) { const previous = windowed.value; let entries2 = previous.entries; let before = previous.before; - let ops2 = docOps; + let ops3 = docOps; if (appended.length > 0) { - ops2 = [...docOps, ["p", ["entries"], entries2.length, 0, inserted]]; + ops3 = [...docOps, ["p", ["entries"], entries2.length, 0, inserted]]; entries2 = entries2.concat(appended); if (entries2.length > windowed.max) { const drop = entries2.length - windowed.min; before = entries2[drop - 1].id; entries2 = entries2.slice(drop); - ops2.push(["p", ["entries"], 0, drop, []], ["s", ["before"], before]); + ops3.push(["p", ["entries"], 0, drop, []], ["s", ["before"], before]); } } windowed.value = view(mount.conversation, entries2, before, mount.docs); - const call = { kind: "value", value: windowed.value, ops: ops2, retired: false }; + const call = { kind: "value", value: windowed.value, ops: ops3, retired: false }; contained(() => windowed.observer.advance(call, frameContext), report2); } } @@ -30428,14 +30428,51 @@ function eventLog(harness) { } } -// extensions.ts +// environment.ts +var CodingTools2 = { ...CodingTools, tools: CodingTools.tools.map((tool) => ({ + ...tool, + execute: (args, api, context) => tool.execute(args, { ...api, env: api.env.forTool(api.callId, tool.name) }, context) +})) }; +var Started = defineDoc({ + kind: "board.started", + version: 1, + checkpointWhen: () => false, + scope: "conversation", + history: "latest", + fork: "initial", + initial: () => ({}) +}); +function conversationChains(harness, context) { + const cache = /* @__PURE__ */ new Map(); + const chain = (id) => { + let result = cache.get(id); + if (!result) { + result = (async () => { + const record2 = await harness.commit((tx) => tx.conversation(id), context); + const up = record2?.owner?.conversationId ?? record2?.parent?.conversationId; + const starter = (await harness.snapshot(Started, id, context))?.by; + return [.../* @__PURE__ */ new Set([ + String(id), + ...up === void 0 ? [] : await chain(up), + ...starter === void 0 ? [] : await chain(starter) + ])]; + })(); + cache.set(id, result); + } + return result; + }; + return chain; +} var ops = Deno.core.ops; + +// extensions.ts +var ops2 = Deno.core.ops; var encoder4 = new TextEncoder(); var decoder4 = new TextDecoder(); var ExtensionState = defineDoc({ kind: "sausage.extensions", version: 1, scope: "session", checkpointWhen: () => false, initial: () => ({ good: null, current: null, error: null }) }); var Metadata = defineDoc({ kind: "sausage.metadata", version: 1, scope: "conversation", history: "latest", fork: "current", initial: () => ({ label: "", title: "" }), checkpointWhen: () => false }); async function file(kind, path, bytes2 = []) { - const result = await ops.op_file(kind, path, bytes2); + const result = await ops2.op_file(kind, path, bytes2); if (!result.ok) throw Object.assign(new Error(result.error.message), result.error); return result.value; } @@ -30458,14 +30495,14 @@ async function exec(command, options) { program: `extension:${options.extension}`, conversations: options.conversations ?? [] } : void 0; - const rid = ops.op_exec(command, options.cwd, options.timeout, void 0, options.env, options.conversations, tag); + const rid = ops2.op_exec(command, options.cwd, options.timeout, void 0, options.env, options.conversations, tag); const abort = () => Deno.core.close(rid); options.signal?.addEventListener("abort", abort, { once: true }); const decoders = { stdout: new TextDecoder(), stderr: new TextDecoder() }; const result = { code: 0, stdout: "", stderr: "" }; try { for (; ; ) { - const chunk = await ops.op_exec_next(rid); + const chunk = await ops2.op_exec_next(rid); if (!chunk.stream) { if (chunk.error) throw new Error(chunk.error); result.code = chunk.exitCode; @@ -30492,11 +30529,12 @@ async function git(cwd, ...args) { function registerModules() { const modules = { "@earendil-works/sausage-events": events_exports, "@earendil-works/pi-schema": dist_exports, "@earendil-works/pi-durable": dist_exports3, "@earendil-works/pi-durable/tools": tools_exports, "@earendil-works/pi-ai": dist_exports4, "@earendil-works/pi-ai/models": models_exports, "@earendil-works/chord": dist_exports2, "@earendil-works/chord/context": context_exports }; globalThis.__sausage = { modules }; - ops.op_modules(Object.fromEntries(Object.entries(modules).map(([name, value2]) => [name, Object.keys(value2)]))); + ops2.op_modules(Object.fromEntries(Object.entries(modules).map(([name, value2]) => [name, Object.keys(value2)]))); } async function loadExtensions(harness, registry, storage, models, context, builtins = []) { registerModules(); const eventService = eventLog(() => harness); + const chain = conversationChains(harness, context); const repo = "/src/sausage"; let providers = /* @__PURE__ */ new Map(); const resources = /* @__PURE__ */ new Map(); @@ -30507,7 +30545,7 @@ async function loadExtensions(harness, registry, storage, models, context, built let queue2 = Promise.resolve(); const publish2 = async () => { await harness.commit(async (tx) => Object.assign(await tx.doc(ExtensionState), state), context); - ops.op_extension_status(JSON.stringify(state)); + ops2.op_extension_status(JSON.stringify(state)); await fs.write("/src/sausage/.git/sausage-last-good", state.good ?? ""); }; const dispose = async (entries2) => { @@ -30515,7 +30553,7 @@ async function loadExtensions(harness, registry, storage, models, context, built try { await cleanup(); } catch (error) { - ops.op_output(`Extension cleanup: ${String(error)} + ops2.op_output(`Extension cleanup: ${String(error)} `); } } @@ -30548,6 +30586,7 @@ async function loadExtensions(harness, registry, storage, models, context, built fs, exec: (command, options) => exec(command, { ...options, extension: name }), git, + chain, implement: (api, value2) => { staged.set(api.name, value2); }, @@ -30570,12 +30609,12 @@ async function loadExtensions(harness, registry, storage, models, context, built onClose: (cb) => close.push(cb), notice: (message) => { state.notice = `${name}: ${message}`; - ops.op_extension_status(JSON.stringify(state)); - ops.op_output(`${name}: ${message} + ops2.op_extension_status(JSON.stringify(state)); + ops2.op_output(`${name}: ${message} `); if (!notices.has(message)) { notices.add(message); - void harness.commit((tx) => eventService.emit(tx, NoticeEvent, { extension: name, message, level: "warning" }), context).catch((error) => ops.op_output(`Recording a notice failed: ${String(error)} + void harness.commit((tx) => eventService.emit(tx, NoticeEvent, { extension: name, message, level: "warning" }), context).catch((error) => ops2.op_output(`Recording a notice failed: ${String(error)} `)); } } @@ -30654,7 +30693,7 @@ async function loadExtensions(harness, registry, storage, models, context, built tip = await git(repo, "rev-parse", "refs/heads/main"); } catch (error) { state.error = String(error); - ops.op_extension_status(JSON.stringify(state)); + ops2.op_extension_status(JSON.stringify(state)); return; } try { @@ -30663,8 +30702,8 @@ async function loadExtensions(harness, registry, storage, models, context, built if (error.code === "not_found") settings = {}; else { state.notice = `Settings: ${String(error)}`; - ops.op_extension_status(JSON.stringify(state)); - ops.op_output(`${state.notice} + ops2.op_extension_status(JSON.stringify(state)); + ops2.op_output(`${state.notice} `); } } @@ -30680,11 +30719,11 @@ Last good: ${fallback}` : failed; await publish2(); }; const enqueue2 = () => queue2 = queue2.then(reload); - const rid = ops.op_watch([`${repo}/.git/refs/heads/main`, `${repo}/.git/packed-refs`, `${repo}/settings.json`]); + const rid = ops2.op_watch([`${repo}/.git/refs/heads/main`, `${repo}/.git/packed-refs`, `${repo}/settings.json`]); await enqueue2(); const pending = (async () => { while (active) { - await ops.op_watch_next(rid); + await ops2.op_watch_next(rid); if (active) await enqueue2(); } })(); diff --git a/host/js/plan-todos-test-bundle.js b/host/js/plan-todos-test-bundle.js index 79b8ba9..11ec026 100644 --- a/host/js/plan-todos-test-bundle.js +++ b/host/js/plan-todos-test-bundle.js @@ -8946,27 +8946,27 @@ var REPLACE_TAKE = { kind: "replace" }; var PendingOps = class { #state = EMPTY; /** Queue the ops of one commit. */ - push(ops2) { - if (ops2.length === 0) + push(ops3) { + if (ops3.length === 0) return; const state = this.#state; - if (ops2[0][0] === "r") { - this.#state = { kind: "batch", ops: ops2 }; + if (ops3[0][0] === "r") { + this.#state = { kind: "batch", ops: ops3 }; return; } switch (state.kind) { case "empty": - this.#state = { kind: "batch", ops: ops2 }; + this.#state = { kind: "batch", ops: ops3 }; return; case "batch": { const folding = { kind: "folding", ops: [], leaves: /* @__PURE__ */ new Map() }; this.#state = folding; if (this.#fold(state.ops, folding)) - this.#fold(ops2, folding); + this.#fold(ops3, folding); return; } case "folding": - this.#fold(ops2, state); + this.#fold(ops3, state); return; case "replace": return; @@ -8997,8 +8997,8 @@ var PendingOps = class { } } /** Fold `ops` into `folding`; false once the queue overflowed into `replace`. */ - #fold(ops2, folding) { - for (const op2 of ops2) { + #fold(ops3, folding) { + for (const op2 of ops3) { switch (op2[0]) { case "r": folding.ops.length = 0; @@ -9267,12 +9267,12 @@ var PathError = class extends Error { this.name = "PathError"; } }; -function apply(target, ops2) { - return applyOps(target, ops2); +function apply(target, ops3) { + return applyOps(target, ops3); } -function applyOps(target, ops2) { +function applyOps(target, ops3) { let root2 = target; - for (const op2 of ops2) { + for (const op2 of ops3) { assertValidOp(op2); if (op2[0] === "r") { root2 = op2[1]; @@ -9341,14 +9341,14 @@ function applyOps(target, ops2) { } return root2; } -function applyImmutable(target, ops2) { - return applyImmutableBatches(target, [ops2]); +function applyImmutable(target, ops3) { + return applyImmutableBatches(target, [ops3]); } function applyImmutableBatches(target, batches) { let root2 = target; const owned = /* @__PURE__ */ new WeakSet(); - for (const ops2 of batches) { - for (const op2 of ops2) { + for (const ops3 of batches) { + for (const op2 of ops3) { assertValidOp(op2); if (op2[0] === "r") { root2 = op2[1]; @@ -9462,10 +9462,10 @@ function encoder() { let nextId = 0; let previous; return { - encode(ops2) { + encode(ops3) { previous = void 0; const out = []; - for (const op2 of ops2) { + for (const op2 of ops3) { if (op2[0] === "r") { out.push(op2); seen.clear(); @@ -9715,9 +9715,9 @@ var Source = class { return []; } }; -function unbox(ops2, value2) { +function unbox(ops3, value2) { const result = []; - for (const op2 of ops2) { + for (const op2 of ops3) { if (op2[0] === "r" || op2[1].length === 0) return [["r", value2]]; const path = op2[1].slice(1); @@ -9811,8 +9811,8 @@ var Cell = class extends Source { throw notReady(`state ${this.key} (its init has not run)`); const before = this.value; const diff = options.diff ?? sharesStructure(before, value2); - const ops2 = diff ? diffRevisions(before, value2) : void 0; - this.#publish(this.#tracker.prepareReplace({ v: value2 }), "ops", true, ops2); + const ops3 = diff ? diffRevisions(before, value2) : void 0; + this.#publish(this.#tracker.prepareReplace({ v: value2 }), "ops", true, ops3); } /** * Installs a migrated value and its schema (reload commit). The caller validated the value and the derivations @@ -9823,7 +9823,7 @@ var Cell = class extends Source { this.#publish(this.#tracker.prepareReplace({ v: value2 }), "reset", false); } /** Adopts this revision and every derived one, then queues all notifications (cell first, then derivations). */ - #publish(prepared, type, validate2 = true, ops2) { + #publish(prepared, type, validate2 = true, ops3) { if (prepared.ops.length === 0 && type === "ops") { this.#tracker.adopt(prepared); return; @@ -9840,7 +9840,7 @@ var Cell = class extends Source { } holdPublications(() => { this.#tracker.adopt(prepared); - const published = ops2 !== void 0 && ops2.length > 0 ? ops2 : unbox(prepared.ops, value2); + const published = ops3 !== void 0 && ops3.length > 0 ? ops3 : unbox(prepared.ops, value2); this.fanout.emit(type === "reset" ? { type, value: value2 } : { type, ops: published, value: value2 }); for (const [derived, next] of candidates) derived.install(next); @@ -9953,9 +9953,9 @@ var Derived = class extends Source { install(next) { const before = this.#value; this.#value = next; - const ops2 = before === void 0 || next === void 0 ? [["r", next ?? null]] : diffRevisions(before, next); - if (ops2.length > 0) - this.fanout.emit({ type: "ops", ops: ops2, value: next }); + const ops3 = before === void 0 || next === void 0 ? [["r", next ?? null]] : diffRevisions(before, next); + if (ops3.length > 0) + this.fanout.emit({ type: "ops", ops: ops3, value: next }); } }; var isSource = (value2) => value2 instanceof Source; @@ -14008,10 +14008,10 @@ var RemoteBinding = class { const target = pending?.values.get(name) ?? this.members.get(name); if (target === void 0) return; - const ops2 = target.decoder.decode(frame.ops ?? []); - target.value = applyImmutable(target.value, ops2); + const ops3 = target.decoder.decode(frame.ops ?? []); + target.value = applyImmutable(target.value, ops3); if (target === this.members.get(name)) - this.#deliver(name, { type: "ops", ops: ops2, value: target.value }); + this.#deliver(name, { type: "ops", ops: ops3, value: target.value }); return; } const fresh = { value: frame.value, decoder: decoder() }; @@ -15835,8 +15835,8 @@ var Watch = class extends WatchLifecycle { this.#retired = false; if (lone !== void 0) return lone; - const ops2 = batch.kind === "ops" ? batch.ops : [["r", value2]]; - return { kind: "value", value: value2, ops: ops2, retired }; + const ops3 = batch.kind === "ops" ? batch.ops : [["r", value2]]; + return { kind: "value", value: value2, ops: ops3, retired }; } /** The pending failure, or the value after one as a root replacement (no ops were kept since the failure). */ #nextAfterFailure() { @@ -17601,7 +17601,7 @@ function describe(plan, record2) { const change = plan.change; if (change === void 0 || !publishes(plan)) return void 0; - const ops2 = change.loaded === void 0 ? EMPTY_OPERATIONS : change.prepared.ops; + const ops3 = change.loaded === void 0 ? EMPTY_OPERATIONS : change.prepared.ops; return { type: "document", kind: "change", @@ -17609,11 +17609,11 @@ function describe(plan, record2) { conversationId, version: change.version, value: change.prepared.value, - ops: ops2 + ops: ops3 }; } -function storeHeld(hold, ops2, value2, version) { - hold.pending.push(ops2); +function storeHeld(hold, ops3, value2, version) { + hold.pending.push(ops3); const taken = hold.pending.take(); if (taken.kind === "replace") return { content: { version, kind: "base", value: value2 }, ops: [["r", value2]] }; @@ -18694,7 +18694,7 @@ var SessionImpl = class { return { kind: "adoption", error }; } const deadline = this.#clock() + withinMs; - for (const { loaded, ops: ops2, base: base2 } of held2) { + for (const { loaded, ops: ops3, base: base2 } of held2) { const id = loaded.record.id; let hold = this.#holds.get(id); if (hold === void 0) { @@ -18702,7 +18702,7 @@ var SessionImpl = class { hold = { loaded, pending: new PendingOps(), base: false, deadline, unpin }; this.#holds.set(id, hold); } - hold.pending.push(ops2); + hold.pending.push(ops3); if (base2) hold.base = true; if (deadline < hold.deadline) @@ -26917,14 +26917,14 @@ var TaskGraphView = class { const mount = this.#mount; if (mount === void 0) return; - const ops2 = []; + const ops3 = []; for (const [key, record2] of mount.records) { const blocked = this.#blocking.blocked(record2); if (blocked === mount.value.tasks[key]?.blocked) continue; - ops2.push(blocked === void 0 ? ["d", ["tasks", key, "blocked"]] : ["s", ["tasks", key, "blocked"], blocked]); + ops3.push(blocked === void 0 ? ["d", ["tasks", key, "blocked"]] : ["s", ["tasks", key, "blocked"], blocked]); } - publish(mount, ops2, BACKGROUND_CONTEXT, (error) => this.#session.report(error)); + publish(mount, ops3, BACKGROUND_CONTEXT, (error) => this.#session.report(error)); }).catch(() => { }); } @@ -26948,7 +26948,7 @@ var TaskGraphView = class { } }; function advance(mount, publication, context, blocked, report2) { - const ops2 = []; + const ops3 = []; const changed = /* @__PURE__ */ new Map(); const node = (key) => changed.has(key) ? changed.get(key) : mount.value.tasks[key]; for (const change of publication.changes) { @@ -26961,7 +26961,7 @@ function advance(mount, publication, context, blocked, report2) { mount.records.delete(key); if (previous === void 0) continue; - ops2.push(["d", ["tasks", key]]); + ops3.push(["d", ["tasks", key]]); changed.set(key, void 0); continue; } @@ -26970,7 +26970,7 @@ function advance(mount, publication, context, blocked, report2) { const next = nodeOf2(record2, previous?.conversations ?? [], blocked(subject)); if (previous !== void 0 && JSON.stringify(next) === JSON.stringify(previous)) continue; - ops2.push(["s", ["tasks", key], next]); + ops3.push(["s", ["tasks", key], next]); changed.set(key, next); } const created = /* @__PURE__ */ new Map(); @@ -26983,16 +26983,16 @@ function advance(mount, publication, context, blocked, report2) { } for (const [key, ids] of created) { const conversations = [...node(key).conversations, ...ids].sort((a, b) => a - b); - ops2.push(["s", ["tasks", key, "conversations"], conversations]); + ops3.push(["s", ["tasks", key, "conversations"], conversations]); } - publish(mount, ops2, context, report2); + publish(mount, ops3, context, report2); } -function publish(mount, ops2, context, report2) { - if (ops2.length === 0) +function publish(mount, ops3, context, report2) { + if (ops3.length === 0) return; - mount.value = applyImmutable(mount.value, ops2); + mount.value = applyImmutable(mount.value, ops3); const frameContext = withoutAbortSignal(context); - const call2 = { kind: "value", value: mount.value, ops: ops2, retired: false }; + const call2 = { kind: "value", value: mount.value, ops: ops3, retired: false }; for (const observer of [...mount.observers]) contained(() => observer.advance(call2, frameContext), report2); } @@ -27218,19 +27218,19 @@ function advance2(id, mount, publication, context, report2) { const previous = windowed.value; let entries2 = previous.entries; let before = previous.before; - let ops2 = docOps; + let ops3 = docOps; if (appended.length > 0) { - ops2 = [...docOps, ["p", ["entries"], entries2.length, 0, inserted]]; + ops3 = [...docOps, ["p", ["entries"], entries2.length, 0, inserted]]; entries2 = entries2.concat(appended); if (entries2.length > windowed.max) { const drop = entries2.length - windowed.min; before = entries2[drop - 1].id; entries2 = entries2.slice(drop); - ops2.push(["p", ["entries"], 0, drop, []], ["s", ["before"], before]); + ops3.push(["p", ["entries"], 0, drop, []], ["s", ["before"], before]); } } windowed.value = view(mount.conversation, entries2, before, mount.docs); - const call2 = { kind: "value", value: windowed.value, ops: ops2, retired: false }; + const call2 = { kind: "value", value: windowed.value, ops: ops3, retired: false }; contained(() => windowed.observer.advance(call2, frameContext), report2); } } @@ -31368,14 +31368,51 @@ function eventLog(harness2) { } } -// extensions.ts +// environment.ts +var CodingTools2 = { ...CodingTools, tools: CodingTools.tools.map((tool) => ({ + ...tool, + execute: (args, api, context) => tool.execute(args, { ...api, env: api.env.forTool(api.callId, tool.name) }, context) +})) }; +var Started = defineDoc({ + kind: "board.started", + version: 1, + checkpointWhen: () => false, + scope: "conversation", + history: "latest", + fork: "initial", + initial: () => ({}) +}); +function conversationChains(harness2, context) { + const cache = /* @__PURE__ */ new Map(); + const chain = (id) => { + let result = cache.get(id); + if (!result) { + result = (async () => { + const record2 = await harness2.commit((tx) => tx.conversation(id), context); + const up = record2?.owner?.conversationId ?? record2?.parent?.conversationId; + const starter = (await harness2.snapshot(Started, id, context))?.by; + return [.../* @__PURE__ */ new Set([ + String(id), + ...up === void 0 ? [] : await chain(up), + ...starter === void 0 ? [] : await chain(starter) + ])]; + })(); + cache.set(id, result); + } + return result; + }; + return chain; +} var ops = Deno.core.ops; + +// extensions.ts +var ops2 = Deno.core.ops; var encoder4 = new TextEncoder(); var decoder4 = new TextDecoder(); var ExtensionState = defineDoc({ kind: "sausage.extensions", version: 1, scope: "session", checkpointWhen: () => false, initial: () => ({ good: null, current: null, error: null }) }); var Metadata = defineDoc({ kind: "sausage.metadata", version: 1, scope: "conversation", history: "latest", fork: "current", initial: () => ({ label: "", title: "" }), checkpointWhen: () => false }); async function file(kind, path, bytes2 = []) { - const result = await ops.op_file(kind, path, bytes2); + const result = await ops2.op_file(kind, path, bytes2); if (!result.ok) throw Object.assign(new Error(result.error.message), result.error); return result.value; } @@ -31398,14 +31435,14 @@ async function exec(command, options) { program: `extension:${options.extension}`, conversations: options.conversations ?? [] } : void 0; - const rid = ops.op_exec(command, options.cwd, options.timeout, void 0, options.env, options.conversations, tag); + const rid = ops2.op_exec(command, options.cwd, options.timeout, void 0, options.env, options.conversations, tag); const abort = () => Deno.core.close(rid); options.signal?.addEventListener("abort", abort, { once: true }); const decoders = { stdout: new TextDecoder(), stderr: new TextDecoder() }; const result = { code: 0, stdout: "", stderr: "" }; try { for (; ; ) { - const chunk = await ops.op_exec_next(rid); + const chunk = await ops2.op_exec_next(rid); if (!chunk.stream) { if (chunk.error) throw new Error(chunk.error); result.code = chunk.exitCode; @@ -31432,11 +31469,12 @@ async function git(cwd, ...args) { function registerModules() { const modules = { "@earendil-works/sausage-events": events_exports, "@earendil-works/pi-schema": dist_exports, "@earendil-works/pi-durable": dist_exports3, "@earendil-works/pi-durable/tools": tools_exports, "@earendil-works/pi-ai": dist_exports4, "@earendil-works/pi-ai/models": models_exports, "@earendil-works/chord": dist_exports2, "@earendil-works/chord/context": context_exports }; globalThis.__sausage = { modules }; - ops.op_modules(Object.fromEntries(Object.entries(modules).map(([name, value2]) => [name, Object.keys(value2)]))); + ops2.op_modules(Object.fromEntries(Object.entries(modules).map(([name, value2]) => [name, Object.keys(value2)]))); } async function loadExtensions(harness2, registry2, storage2, models2, context, builtins = []) { registerModules(); const eventService = eventLog(() => harness2); + const chain = conversationChains(harness2, context); const repo = "/src/sausage"; let providers = /* @__PURE__ */ new Map(); const resources = /* @__PURE__ */ new Map(); @@ -31447,7 +31485,7 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b let queue2 = Promise.resolve(); const publish2 = async () => { await harness2.commit(async (tx) => Object.assign(await tx.doc(ExtensionState), state), context); - ops.op_extension_status(JSON.stringify(state)); + ops2.op_extension_status(JSON.stringify(state)); await fs.write("/src/sausage/.git/sausage-last-good", state.good ?? ""); }; const dispose = async (entries2) => { @@ -31455,7 +31493,7 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b try { await cleanup(); } catch (error) { - ops.op_output(`Extension cleanup: ${String(error)} + ops2.op_output(`Extension cleanup: ${String(error)} `); } } @@ -31488,6 +31526,7 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b fs, exec: (command, options) => exec(command, { ...options, extension: name }), git, + chain, implement: (api, value2) => { staged.set(api.name, value2); }, @@ -31510,12 +31549,12 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b onClose: (cb) => close.push(cb), notice: (message) => { state.notice = `${name}: ${message}`; - ops.op_extension_status(JSON.stringify(state)); - ops.op_output(`${name}: ${message} + ops2.op_extension_status(JSON.stringify(state)); + ops2.op_output(`${name}: ${message} `); if (!notices.has(message)) { notices.add(message); - void harness2.commit((tx) => eventService.emit(tx, NoticeEvent, { extension: name, message, level: "warning" }), context).catch((error) => ops.op_output(`Recording a notice failed: ${String(error)} + void harness2.commit((tx) => eventService.emit(tx, NoticeEvent, { extension: name, message, level: "warning" }), context).catch((error) => ops2.op_output(`Recording a notice failed: ${String(error)} `)); } } @@ -31594,7 +31633,7 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b tip = await git(repo, "rev-parse", "refs/heads/main"); } catch (error) { state.error = String(error); - ops.op_extension_status(JSON.stringify(state)); + ops2.op_extension_status(JSON.stringify(state)); return; } try { @@ -31603,8 +31642,8 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b if (error.code === "not_found") settings = {}; else { state.notice = `Settings: ${String(error)}`; - ops.op_extension_status(JSON.stringify(state)); - ops.op_output(`${state.notice} + ops2.op_extension_status(JSON.stringify(state)); + ops2.op_output(`${state.notice} `); } } @@ -31620,11 +31659,11 @@ Last good: ${fallback}` : failed; await publish2(); }; const enqueue2 = () => queue2 = queue2.then(reload); - const rid = ops.op_watch([`${repo}/.git/refs/heads/main`, `${repo}/.git/packed-refs`, `${repo}/settings.json`]); + const rid = ops2.op_watch([`${repo}/.git/refs/heads/main`, `${repo}/.git/packed-refs`, `${repo}/settings.json`]); await enqueue2(); const pending = (async () => { while (active) { - await ops.op_watch_next(rid); + await ops2.op_watch_next(rid); if (active) await enqueue2(); } })(); @@ -31671,7 +31710,7 @@ var todosModule = await import( /* @vite-ignore */ `${base}/todos/server.ts` ); -var { Plan, TaskIndex, Branch, Started } = planModule; +var { Plan, TaskIndex, Branch, Started: Started2 } = planModule; var { Todos, Standing, add, mark, noteFor, DONE_LIMIT } = todosModule; var call = async (args, id = root.id, name = "plan") => { const conversation = await harness.conversation(id, BACKGROUND_CONTEXT); @@ -31776,7 +31815,7 @@ try { }, BACKGROUND_CONTEXT); assert(Object.keys((await harness.snapshot(Plan, branch.id, BACKGROUND_CONTEXT)).epics).length === 1, "Fork inherited plan"); equal(JSON.parse(text(await call({ action: "show" }, branch.id))), Plan.definition.initial()); - assert((await harness.snapshot(Started, branch.id, BACKGROUND_CONTEXT)).started, "Branch started"); + assert((await harness.snapshot(Started2, branch.id, BACKGROUND_CONTEXT)).started, "Branch started"); const ULTIMATE = 5; const fakeTx = () => { const docs = /* @__PURE__ */ new Map(); diff --git a/host/js/subagents-test-bundle.js b/host/js/subagents-test-bundle.js index dcc3029..d4092ed 100644 --- a/host/js/subagents-test-bundle.js +++ b/host/js/subagents-test-bundle.js @@ -30428,14 +30428,51 @@ function eventLog(harness2) { } } -// extensions.ts +// environment.ts +var CodingTools2 = { ...CodingTools, tools: CodingTools.tools.map((tool) => ({ + ...tool, + execute: (args, api, context) => tool.execute(args, { ...api, env: api.env.forTool(api.callId, tool.name) }, context) +})) }; +var Started = defineDoc({ + kind: "board.started", + version: 1, + checkpointWhen: () => false, + scope: "conversation", + history: "latest", + fork: "initial", + initial: () => ({}) +}); +function conversationChains(harness2, context) { + const cache = /* @__PURE__ */ new Map(); + const chain2 = (id) => { + let result = cache.get(id); + if (!result) { + result = (async () => { + const record2 = await harness2.commit((tx) => tx.conversation(id), context); + const up = record2?.owner?.conversationId ?? record2?.parent?.conversationId; + const starter = (await harness2.snapshot(Started, id, context))?.by; + return [.../* @__PURE__ */ new Set([ + String(id), + ...up === void 0 ? [] : await chain2(up), + ...starter === void 0 ? [] : await chain2(starter) + ])]; + })(); + cache.set(id, result); + } + return result; + }; + return chain2; +} var ops = Deno.core.ops; + +// extensions.ts +var ops2 = Deno.core.ops; var encoder4 = new TextEncoder(); var decoder4 = new TextDecoder(); var ExtensionState = defineDoc({ kind: "sausage.extensions", version: 1, scope: "session", checkpointWhen: () => false, initial: () => ({ good: null, current: null, error: null }) }); var Metadata = defineDoc({ kind: "sausage.metadata", version: 1, scope: "conversation", history: "latest", fork: "current", initial: () => ({ label: "", title: "" }), checkpointWhen: () => false }); async function file(kind, path, bytes2 = []) { - const result = await ops.op_file(kind, path, bytes2); + const result = await ops2.op_file(kind, path, bytes2); if (!result.ok) throw Object.assign(new Error(result.error.message), result.error); return result.value; } @@ -30458,14 +30495,14 @@ async function exec(command, options) { program: `extension:${options.extension}`, conversations: options.conversations ?? [] } : void 0; - const rid = ops.op_exec(command, options.cwd, options.timeout, void 0, options.env, options.conversations, tag); + const rid = ops2.op_exec(command, options.cwd, options.timeout, void 0, options.env, options.conversations, tag); const abort = () => Deno.core.close(rid); options.signal?.addEventListener("abort", abort, { once: true }); const decoders = { stdout: new TextDecoder(), stderr: new TextDecoder() }; const result = { code: 0, stdout: "", stderr: "" }; try { for (; ; ) { - const chunk = await ops.op_exec_next(rid); + const chunk = await ops2.op_exec_next(rid); if (!chunk.stream) { if (chunk.error) throw new Error(chunk.error); result.code = chunk.exitCode; @@ -30492,11 +30529,12 @@ async function git(cwd, ...args) { function registerModules() { const modules = { "@earendil-works/sausage-events": events_exports, "@earendil-works/pi-schema": dist_exports, "@earendil-works/pi-durable": dist_exports3, "@earendil-works/pi-durable/tools": tools_exports, "@earendil-works/pi-ai": dist_exports4, "@earendil-works/pi-ai/models": models_exports, "@earendil-works/chord": dist_exports2, "@earendil-works/chord/context": context_exports }; globalThis.__sausage = { modules }; - ops.op_modules(Object.fromEntries(Object.entries(modules).map(([name, value2]) => [name, Object.keys(value2)]))); + ops2.op_modules(Object.fromEntries(Object.entries(modules).map(([name, value2]) => [name, Object.keys(value2)]))); } async function loadExtensions(harness2, registry2, storage2, models2, context, builtins = []) { registerModules(); const eventService = eventLog(() => harness2); + const chain2 = conversationChains(harness2, context); const repo = "/src/sausage"; let providers = /* @__PURE__ */ new Map(); const resources = /* @__PURE__ */ new Map(); @@ -30507,7 +30545,7 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b let queue2 = Promise.resolve(); const publish2 = async () => { await harness2.commit(async (tx) => Object.assign(await tx.doc(ExtensionState), state), context); - ops.op_extension_status(JSON.stringify(state)); + ops2.op_extension_status(JSON.stringify(state)); await fs.write("/src/sausage/.git/sausage-last-good", state.good ?? ""); }; const dispose = async (entries2) => { @@ -30515,7 +30553,7 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b try { await cleanup(); } catch (error) { - ops.op_output(`Extension cleanup: ${String(error)} + ops2.op_output(`Extension cleanup: ${String(error)} `); } } @@ -30548,6 +30586,7 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b fs, exec: (command, options) => exec(command, { ...options, extension: name }), git, + chain: chain2, implement: (api, value2) => { staged.set(api.name, value2); }, @@ -30570,12 +30609,12 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b onClose: (cb) => close.push(cb), notice: (message) => { state.notice = `${name}: ${message}`; - ops.op_extension_status(JSON.stringify(state)); - ops.op_output(`${name}: ${message} + ops2.op_extension_status(JSON.stringify(state)); + ops2.op_output(`${name}: ${message} `); if (!notices.has(message)) { notices.add(message); - void harness2.commit((tx) => eventService.emit(tx, NoticeEvent, { extension: name, message, level: "warning" }), context).catch((error) => ops.op_output(`Recording a notice failed: ${String(error)} + void harness2.commit((tx) => eventService.emit(tx, NoticeEvent, { extension: name, message, level: "warning" }), context).catch((error) => ops2.op_output(`Recording a notice failed: ${String(error)} `)); } } @@ -30654,7 +30693,7 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b tip = await git(repo, "rev-parse", "refs/heads/main"); } catch (error) { state.error = String(error); - ops.op_extension_status(JSON.stringify(state)); + ops2.op_extension_status(JSON.stringify(state)); return; } try { @@ -30663,8 +30702,8 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b if (error.code === "not_found") settings = {}; else { state.notice = `Settings: ${String(error)}`; - ops.op_extension_status(JSON.stringify(state)); - ops.op_output(`${state.notice} + ops2.op_extension_status(JSON.stringify(state)); + ops2.op_output(`${state.notice} `); } } @@ -30680,11 +30719,11 @@ Last good: ${fallback}` : failed; await publish2(); }; const enqueue2 = () => queue2 = queue2.then(reload); - const rid = ops.op_watch([`${repo}/.git/refs/heads/main`, `${repo}/.git/packed-refs`, `${repo}/settings.json`]); + const rid = ops2.op_watch([`${repo}/.git/refs/heads/main`, `${repo}/.git/packed-refs`, `${repo}/settings.json`]); await enqueue2(); const pending = (async () => { while (active) { - await ops.op_watch_next(rid); + await ops2.op_watch_next(rid); if (active) await enqueue2(); } })(); @@ -30697,43 +30736,6 @@ Last good: ${fallback}` : failed; } }; } -// environment.ts -var CodingTools2 = { ...CodingTools, tools: CodingTools.tools.map((tool) => ({ - ...tool, - execute: (args, api, context) => tool.execute(args, { ...api, env: api.env.forTool(api.callId, tool.name) }, context) -})) }; -var Started = defineDoc({ - kind: "board.started", - version: 1, - checkpointWhen: () => false, - scope: "conversation", - history: "latest", - fork: "initial", - initial: () => ({}) -}); -function conversationChains(harness2, context) { - const cache = /* @__PURE__ */ new Map(); - const chain2 = (id) => { - let result = cache.get(id); - if (!result) { - result = (async () => { - const record2 = await harness2.commit((tx) => tx.conversation(id), context); - const up = record2?.owner?.conversationId ?? record2?.parent?.conversationId; - const starter = (await harness2.snapshot(Started, id, context))?.by; - return [.../* @__PURE__ */ new Set([ - String(id), - ...up === void 0 ? [] : await chain2(up), - ...starter === void 0 ? [] : await chain2(starter) - ])]; - })(); - cache.set(id, result); - } - return result; - }; - return chain2; -} -var ops2 = Deno.core.ops; - // node_modules/@earendil-works/chord/dist/sqlite/schema.js function validateSqliteSchemaPrefix(prefix) { if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(prefix)) {