@abaigram/abai-stub 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +22 -2
  3. package/dist/audit.d.ts +70 -0
  4. package/dist/audit.d.ts.map +1 -0
  5. package/dist/audit.js +166 -0
  6. package/dist/audit.js.map +1 -0
  7. package/dist/cells/fit.d.ts +6 -0
  8. package/dist/cells/fit.d.ts.map +1 -0
  9. package/dist/cells/fit.js +44 -0
  10. package/dist/cells/fit.js.map +1 -0
  11. package/dist/content.d.ts +17 -0
  12. package/dist/content.d.ts.map +1 -0
  13. package/dist/content.js +71 -0
  14. package/dist/content.js.map +1 -0
  15. package/dist/endpoint.d.ts +90 -0
  16. package/dist/endpoint.d.ts.map +1 -0
  17. package/dist/endpoint.js +789 -0
  18. package/dist/endpoint.js.map +1 -0
  19. package/dist/entry.d.ts +36 -0
  20. package/dist/entry.d.ts.map +1 -0
  21. package/dist/entry.js +409 -0
  22. package/dist/entry.js.map +1 -0
  23. package/dist/env.d.ts +38 -0
  24. package/dist/env.d.ts.map +1 -0
  25. package/dist/env.js +69 -0
  26. package/dist/env.js.map +1 -0
  27. package/dist/harness-binding.d.ts +223 -0
  28. package/dist/harness-binding.d.ts.map +1 -0
  29. package/dist/harness-binding.js +589 -0
  30. package/dist/harness-binding.js.map +1 -0
  31. package/dist/index.d.ts +17 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +17 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/manifest/index.d.ts +3 -0
  36. package/dist/manifest/index.d.ts.map +1 -0
  37. package/dist/manifest/index.js +3 -0
  38. package/dist/manifest/index.js.map +1 -0
  39. package/dist/manifest/manifest.d.ts +172 -0
  40. package/dist/manifest/manifest.d.ts.map +1 -0
  41. package/dist/manifest/manifest.js +443 -0
  42. package/dist/manifest/manifest.js.map +1 -0
  43. package/dist/manifest/render.d.ts +6 -0
  44. package/dist/manifest/render.d.ts.map +1 -0
  45. package/dist/manifest/render.js +39 -0
  46. package/dist/manifest/render.js.map +1 -0
  47. package/dist/null-harness.d.ts +32 -0
  48. package/dist/null-harness.d.ts.map +1 -0
  49. package/dist/null-harness.js +162 -0
  50. package/dist/null-harness.js.map +1 -0
  51. package/dist/program.d.ts +250 -0
  52. package/dist/program.d.ts.map +1 -0
  53. package/dist/program.js +877 -0
  54. package/dist/program.js.map +1 -0
  55. package/dist/region.d.ts +72 -0
  56. package/dist/region.d.ts.map +1 -0
  57. package/dist/region.js +92 -0
  58. package/dist/region.js.map +1 -0
  59. package/dist/registry.d.ts +57 -0
  60. package/dist/registry.d.ts.map +1 -0
  61. package/dist/registry.js +101 -0
  62. package/dist/registry.js.map +1 -0
  63. package/dist/wire/descriptor.d.ts +38 -0
  64. package/dist/wire/descriptor.d.ts.map +1 -0
  65. package/dist/wire/descriptor.js +144 -0
  66. package/dist/wire/descriptor.js.map +1 -0
  67. package/dist/wire/framing.d.ts +11 -0
  68. package/dist/wire/framing.d.ts.map +1 -0
  69. package/dist/wire/framing.js +42 -0
  70. package/dist/wire/framing.js.map +1 -0
  71. package/dist/wire/index.d.ts +4 -0
  72. package/dist/wire/index.d.ts.map +1 -0
  73. package/dist/wire/index.js +4 -0
  74. package/dist/wire/index.js.map +1 -0
  75. package/dist/wire/protocol.d.ts +255 -0
  76. package/dist/wire/protocol.d.ts.map +1 -0
  77. package/dist/wire/protocol.js +15 -0
  78. package/dist/wire/protocol.js.map +1 -0
  79. package/package.json +36 -5
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry.js","sourceRoot":"","sources":["../src/entry.ts"],"names":[],"mappings":"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","sourcesContent":["// The standard agent entry (abaigrammar section 4.4), the part the stub\n// provides itself: `<prog> abai manifest` prints the effective manifest and\n// `<prog> abai doctor` runs the offline conformance checks. The verbs that\n// need a harness (session, install, config, mcp, run) are delegated once a\n// harness binding exists; until then the usage says so. Never throws;\n// resolves to the exit code.\nimport { spawn } from \"node:child_process\";\nimport { accessSync, constants, existsSync, readFileSync, statSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { findRoot, MANIFEST_FILE } from \"./content.ts\";\nimport { ENV_HARNESS, ENV_MODE, expandHome } from \"./env.ts\";\nimport { validateManifest } from \"./manifest/manifest.ts\";\nimport { parseManifestYaml, renderManifestYaml } from \"./manifest/render.ts\";\nimport { type Abaigram, harnessBinary, importHarnessModule } from \"./program.ts\";\n\nexport const STUB_VERSION = \"0.1.0\";\n\nexport type CheckStatus = \"ok\" | \"fail\" | \"skip\";\n\nexport interface DoctorCheck {\n\tname: string;\n\tstatus: CheckStatus;\n\tdetail: string;\n}\n\nexport interface DoctorReport {\n\tok: boolean;\n\troot: string | null;\n\tchecks: DoctorCheck[];\n}\n\n/** Where the entry writes; injectable for tests. */\nexport interface EntryIo {\n\tout(text: string): void;\n\terr(text: string): void;\n\tenv: NodeJS.ProcessEnv;\n\tcwd: string;\n}\n\nexport const processIo: EntryIo = {\n\tout: (text) => {\n\t\tprocess.stdout.write(text);\n\t},\n\terr: (text) => {\n\t\tprocess.stderr.write(`${text}\\n`);\n\t},\n\tenv: process.env,\n\tget cwd() {\n\t\treturn process.cwd();\n\t},\n};\n\nfunction errorMessage(error: unknown): string {\n\treturn error instanceof Error ? error.message : String(error);\n}\n\nfunction usageLines(entry: string): string[] {\n\treturn [\n\t\t`usage: ${entry} open a session`,\n\t\t` ${entry} install run the install touchpoint`,\n\t\t` ${entry} manifest [--json] print the effective manifest`,\n\t\t` ${entry} doctor [--root <dir>] [--offline] [--json]`,\n\t\t` ${entry} config [set ...] the machine-level model configuration`,\n\t\t` ${entry} mcp serve the agent's tools to an MCP client over stdio`,\n\t\t` ${entry} run [--auto] -- ARGS the harness starts this program as its supervised child`,\n\t\t\"\",\n\t\t\"doctor offline conformance checks: the effective manifest, the checked-in\",\n\t\t` ${MANIFEST_FILE}, the identity content, the modes, the audit directory`,\n\t\t\"\",\n\t\t\"session and install attach a harness and return when none can attach; mcp needs no model,\",\n\t\t\"since the client's own agent is this program's; run is always sidecar launch, with the whole\",\n\t\t\"lifecycle channel and the program's output observed from outside.\",\n\t];\n}\n\ninterface Flags {\n\tjson: boolean;\n\troot: string | undefined;\n\toffline: boolean;\n}\n\n/** `--flag`, `--flag value` and `--flag=value`; anything else is a usage error. */\nfunction parseFlags(args: string[], allowed: readonly string[]): Flags | string {\n\tconst flags: Flags = { json: false, root: undefined, offline: false };\n\tfor (let i = 0; i < args.length; i++) {\n\t\tconst arg = args[i];\n\t\tconst eq = arg.indexOf(\"=\");\n\t\tconst name = eq === -1 ? arg : arg.slice(0, eq);\n\t\tif (!allowed.includes(name)) return `unknown option ${arg}`;\n\t\tconst takeValue = (): string | undefined => {\n\t\t\tif (eq !== -1) return arg.slice(eq + 1);\n\t\t\ti += 1;\n\t\t\treturn args[i];\n\t\t};\n\t\tswitch (name) {\n\t\t\tcase \"--json\":\n\t\t\t\tflags.json = true;\n\t\t\t\tbreak;\n\t\t\tcase \"--offline\":\n\t\t\t\tflags.offline = true;\n\t\t\t\tbreak;\n\t\t\tcase \"--root\": {\n\t\t\t\tconst value = takeValue();\n\t\t\t\tif (value === undefined || value === \"\") return \"--root needs a directory\";\n\t\t\t\tflags.root = value;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\treturn `unknown option ${arg}`;\n\t\t}\n\t}\n\treturn flags;\n}\n\n/** The first line at which two texts differ (1-based), or undefined when equal. */\nexport function firstDifferingLine(a: string, b: string): number | undefined {\n\tif (a === b) return undefined;\n\tconst linesA = a.split(\"\\n\");\n\tconst linesB = b.split(\"\\n\");\n\tconst n = Math.max(linesA.length, linesB.length);\n\tfor (let i = 0; i < n; i++) {\n\t\tif (linesA[i] !== linesB[i]) return i + 1;\n\t}\n\treturn n;\n}\n\n/** The first existing ancestor of a path (the path itself included). */\nfunction existingAncestor(path: string): string {\n\tlet current = path;\n\twhile (!existsSync(current)) {\n\t\tconst parent = dirname(current);\n\t\tif (parent === current) break;\n\t\tcurrent = parent;\n\t}\n\treturn current;\n}\n\n/** The offline half of `doctor` (section 4.4), plus the online half when the harness package is installed. Never throws. */\nexport async function runDoctor(\n\tapp: Abaigram,\n\toptions: { root?: string; io?: EntryIo; online?: boolean } = {},\n): Promise<DoctorReport> {\n\tconst io = options.io ?? processIo;\n\tconst checks: DoctorCheck[] = [];\n\tconst add = (name: string, status: CheckStatus, detail: string) => {\n\t\tchecks.push({ name, status, detail });\n\t};\n\tconst { manifest } = app;\n\n\tadd(\"entry\", \"ok\", `${manifest.entry} reached (abai stub ${STUB_VERSION})`);\n\n\tconst violations = validateManifest(manifest);\n\tlet rendered: string | undefined;\n\tif (violations.length === 0) {\n\t\trendered = renderManifestYaml(manifest);\n\t\tadd(\n\t\t\t\"manifest\",\n\t\t\t\"ok\",\n\t\t\t`the effective manifest validates (${manifest.cells.length} cells, ${manifest.events.length} events, ${manifest.capabilities.length} capabilities, ${manifest.decisions.length} decisions, ${manifest.turns.length} turns)`,\n\t\t);\n\t} else {\n\t\tadd(\"manifest\", \"fail\", `the effective manifest does not validate: ${violations.join(\"; \")}`);\n\t}\n\n\tconst root =\n\t\toptions.root !== undefined\n\t\t\t? resolve(io.cwd, options.root)\n\t\t\t: (findRoot(manifest.name, io.cwd) ??\n\t\t\t\t(existsSync(join(app.content.root, MANIFEST_FILE)) ? app.content.root : undefined));\n\tif (root === undefined) {\n\t\tadd(\"root\", \"skip\", `no checkout found (pass --root <dir> to check a checked-in ${MANIFEST_FILE})`);\n\t\tadd(MANIFEST_FILE, \"skip\", \"no checkout\");\n\t\tadd(\"identity\", \"skip\", \"no checkout\");\n\t} else {\n\t\tadd(\"root\", \"ok\", root);\n\t\tconst path = join(root, MANIFEST_FILE);\n\t\tif (!existsSync(path)) {\n\t\t\tadd(MANIFEST_FILE, \"fail\", `${path} is missing; run: ${manifest.entry} manifest > ${MANIFEST_FILE}`);\n\t\t} else {\n\t\t\tlet text: string | undefined;\n\t\t\ttry {\n\t\t\t\ttext = readFileSync(path, \"utf8\");\n\t\t\t} catch (error) {\n\t\t\t\tadd(MANIFEST_FILE, \"fail\", `${path} could not be read: ${errorMessage(error)}`);\n\t\t\t}\n\t\t\tif (text !== undefined) {\n\t\t\t\tlet parsed: unknown;\n\t\t\t\tlet parseError: string | undefined;\n\t\t\t\ttry {\n\t\t\t\t\tparsed = parseManifestYaml(text);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tparseError = errorMessage(error);\n\t\t\t\t}\n\t\t\t\tif (parseError !== undefined) {\n\t\t\t\t\tadd(MANIFEST_FILE, \"fail\", `${path} does not parse: ${parseError}`);\n\t\t\t\t} else {\n\t\t\t\t\tconst fileViolations = validateManifest(parsed);\n\t\t\t\t\tif (fileViolations.length > 0) {\n\t\t\t\t\t\tadd(MANIFEST_FILE, \"fail\", `${path} does not validate: ${fileViolations.join(\"; \")}`);\n\t\t\t\t\t} else if (rendered !== undefined && text !== rendered) {\n\t\t\t\t\t\tadd(\n\t\t\t\t\t\t\tMANIFEST_FILE,\n\t\t\t\t\t\t\t\"fail\",\n\t\t\t\t\t\t\t`${path} is stale: first difference at line ${firstDifferingLine(text, rendered)}; run: ${manifest.entry} manifest > ${MANIFEST_FILE}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t} else if (rendered !== undefined) {\n\t\t\t\t\t\tadd(MANIFEST_FILE, \"ok\", `${path} validates and agrees with the code`);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tadd(MANIFEST_FILE, \"fail\", `${path} validates but the effective manifest does not`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tconst identity = join(root, manifest.content.identity);\n\t\ttry {\n\t\t\tif (!existsSync(identity)) add(\"identity\", \"fail\", `${identity} is missing`);\n\t\t\telse if (readFileSync(identity, \"utf8\").trim() === \"\") add(\"identity\", \"fail\", `${identity} is empty`);\n\t\t\telse add(\"identity\", \"ok\", identity);\n\t\t} catch (error) {\n\t\t\tadd(\"identity\", \"fail\", `${identity} could not be read: ${errorMessage(error)}`);\n\t\t}\n\t}\n\n\tif (app.harnessSelectionError !== undefined) add(\"harness\", \"fail\", app.harnessSelectionError);\n\telse add(\"harness\", \"ok\", `${ENV_HARNESS}: ${app.harnessSelection}`);\n\n\tconst modes = manifest.modes as string[];\n\tconst selected = io.env[ENV_MODE]?.trim();\n\tif (selected === undefined || selected === \"\") {\n\t\tadd(\"modes\", \"ok\", `declared: ${modes.join(\", \")}; default ${modes[0]}`);\n\t} else if (modes.includes(selected)) {\n\t\tadd(\"modes\", \"ok\", `${ENV_MODE}=${selected} is declared (declared: ${modes.join(\", \")})`);\n\t} else {\n\t\tadd(\n\t\t\t\"modes\",\n\t\t\t\"fail\",\n\t\t\t`${ENV_MODE}=${selected} is not declared (declared: ${modes.join(\", \")}); a plain run falls back and counts it`,\n\t\t);\n\t}\n\n\tif (app.endpoint !== undefined) {\n\t\t// under sidecar the endpoint has been listening since startup; doctor says where, or why not\n\t\ttry {\n\t\t\tawait app.endpoint.ready;\n\t\t\tadd(\"endpoint\", \"ok\", `listening at ${app.endpoint.socketPath}`);\n\t\t} catch (error) {\n\t\t\tadd(\"endpoint\", \"fail\", `the endpoint could not listen: ${errorMessage(error)}`);\n\t\t}\n\t}\n\n\ttry {\n\t\tconst auditPath = expandHome(manifest.audit.path, io.env.HOME ?? \"\");\n\t\tconst ancestor = existingAncestor(dirname(resolve(io.cwd, auditPath)));\n\t\tif (!statSync(ancestor).isDirectory()) {\n\t\t\tadd(\"audit\", \"fail\", `${ancestor} is not a directory`);\n\t\t} else {\n\t\t\taccessSync(ancestor, constants.W_OK);\n\t\t\tadd(\"audit\", \"ok\", `${auditPath} (${ancestor} is writable)`);\n\t\t}\n\t} catch (error) {\n\t\tadd(\"audit\", \"fail\", `the audit directory is not writable: ${errorMessage(error)}`);\n\t}\n\n\tif (options.online === false) {\n\t\tadd(\"online\", \"skip\", \"not asked (--offline)\");\n\t} else {\n\t\tconst harness = await importHarnessModule(io.env, manifest);\n\t\tif (!harness?.doctorOnline) {\n\t\t\tadd(\"online\", \"skip\", \"no harness is installed to check the model\");\n\t\t} else {\n\t\t\ttry {\n\t\t\t\tfor (const check of await harness.doctorOnline(manifest, io.env))\n\t\t\t\t\tadd(check.name, check.status, check.detail);\n\t\t\t} catch (error) {\n\t\t\t\tadd(\"online\", \"fail\", `the harness's check failed: ${errorMessage(error)}`);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { ok: checks.every((check) => check.status !== \"fail\"), root: root ?? null, checks };\n}\n\nfunction printReport(report: DoctorReport, io: EntryIo): void {\n\tfor (const check of report.checks) io.out(`${check.status.padEnd(4)} ${check.name}: ${check.detail}\\n`);\n\tio.out(report.ok ? \"doctor: ok\\n\" : \"doctor: failed\\n\");\n}\n\n/**\n * `<prog> abai <verb> ...`. `args` are the arguments after the program's\n * own name; the first must be `abai`. Resolves to the exit code; -1 means\n * the arguments were not an abai entry at all.\n */\nexport async function runEntry(app: Abaigram, args: string[], io: EntryIo = processIo): Promise<number> {\n\tif (args[0] !== \"abai\") {\n\t\t// the entry is one of the five attach places (4.3): a launched program takes up its connection here,\n\t\t// before its own work, so its first touchpoint finds the agent present\n\t\tif (app.launched) await app.attach();\n\t\treturn -1;\n\t}\n\tconst { manifest } = app;\n\tconst usage = (problem?: string): number => {\n\t\tif (problem !== undefined) io.err(`${manifest.entry}: ${problem}`);\n\t\tfor (const line of usageLines(manifest.entry)) io.err(line);\n\t\treturn 2;\n\t};\n\ttry {\n\t\tconst verb = args[1];\n\t\tswitch (verb) {\n\t\t\tcase \"manifest\": {\n\t\t\t\tconst flags = parseFlags(args.slice(2), [\"--json\"]);\n\t\t\t\tif (typeof flags === \"string\") return usage(flags);\n\t\t\t\t// a selected mode the manifest does not declare is an error at the entry (section 4.4)\n\t\t\t\tconst selected = io.env[ENV_MODE]?.trim();\n\t\t\t\tif (selected !== undefined && selected !== \"\" && !(manifest.modes as string[]).includes(selected)) {\n\t\t\t\t\tio.err(\n\t\t\t\t\t\t`${manifest.entry}: ${ENV_MODE}=${selected} is not a declared mode (declared: ${manifest.modes.join(\", \")})`,\n\t\t\t\t\t);\n\t\t\t\t\treturn 2;\n\t\t\t\t}\n\t\t\t\tio.out(flags.json ? `${JSON.stringify(manifest, null, 2)}\\n` : renderManifestYaml(manifest));\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tcase \"doctor\": {\n\t\t\t\tconst flags = parseFlags(args.slice(2), [\"--json\", \"--root\", \"--offline\"]);\n\t\t\t\tif (typeof flags === \"string\") return usage(flags);\n\t\t\t\tconst report = await runDoctor(app, { root: flags.root, io, online: !flags.offline });\n\t\t\t\tif (flags.json) io.out(`${JSON.stringify(report, null, 2)}\\n`);\n\t\t\t\telse printReport(report, io);\n\t\t\t\treturn report.ok ? 0 : 1;\n\t\t\t}\n\t\t\tcase undefined:\n\t\t\tcase \"session\": {\n\t\t\t\tawait app.session();\n\t\t\t\tif (app.attached) return 0;\n\t\t\t\tio.err(`${manifest.entry}: no harness attached (${app.attachError ?? \"unknown reason\"})`);\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tcase \"install\": {\n\t\t\t\tawait app.install();\n\t\t\t\tif (app.attached) return 0;\n\t\t\t\tio.err(`${manifest.entry}: no harness attached (${app.attachError ?? \"unknown reason\"})`);\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tcase \"config\": {\n\t\t\t\tconst harness = await importHarnessModule(io.env, manifest);\n\t\t\t\tif (!harness?.runConfig) return usage(\"config needs the harness package, which is not installed\");\n\t\t\t\treturn await harness.runConfig(args.slice(2), io);\n\t\t\t}\n\t\t\tcase \"mcp\": {\n\t\t\t\t// the program at its entry serves an MCP client: under sidecar through the binary on this\n\t\t\t\t// process's stdio, otherwise in-process through the installed harness package (section 4.4).\n\t\t\t\t// ABAI_HARNESS is honoured like everywhere: off attaches nothing, a null harness is attached already\n\t\t\t\tif (app.harnessSelection === \"off\") {\n\t\t\t\t\tio.err(`${manifest.entry}: no harness attached (${ENV_HARNESS}=off)`);\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t\tif (app.attached) {\n\t\t\t\t\tio.err(`${manifest.entry}: ${manifest.name} already has a harness attached`);\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t\tif (app.endpoint !== undefined) {\n\t\t\t\t\tconst code = await app.serveMcpSidecar(app.endpoint);\n\t\t\t\t\tif (code >= 0) return code;\n\t\t\t\t\tio.err(`${manifest.entry}: no harness attached (${app.attachError ?? \"unknown reason\"})`);\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t\tconst harness = await importHarnessModule(io.env, manifest);\n\t\t\t\tif (!harness?.serveMcpEmbedded) return usage(\"mcp needs the harness package, which is not installed\");\n\t\t\t\tconst binding = app.bind(\"mcp\");\n\t\t\t\tbinding.enterSafepoint();\n\t\t\t\ttry {\n\t\t\t\t\treturn await harness.serveMcpEmbedded(binding);\n\t\t\t\t} finally {\n\t\t\t\t\tbinding.leaveSafepoint();\n\t\t\t\t}\n\t\t\t}\n\t\t\tcase \"run\": {\n\t\t\t\t// sidecar launch (4.4, 6.3): the harness binary starts this very program again as its child\n\t\t\t\tif (!(manifest.modes as string[]).includes(\"sidecar\")) {\n\t\t\t\t\tio.err(\n\t\t\t\t\t\t`${manifest.entry}: run is sidecar launch, and ${manifest.name} declares ${manifest.modes.join(\", \")}`,\n\t\t\t\t\t);\n\t\t\t\t\treturn 2;\n\t\t\t\t}\n\t\t\t\tconst separator = args.indexOf(\"--\");\n\t\t\t\tconst flags = args.slice(2, separator === -1 ? undefined : separator);\n\t\t\t\tconst programArgs = separator === -1 ? [] : args.slice(separator + 1);\n\t\t\t\tfor (const flag of flags) {\n\t\t\t\t\tif (flag !== \"--auto\" && flag !== \"--deny-mutate\" && flag !== \"--all-events\") {\n\t\t\t\t\t\treturn usage(`unknown option ${flag} (run takes --auto, --deny-mutate, --all-events)`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst binary = harnessBinary(io.env, app.content.root);\n\t\t\t\tconst script = process.argv[1];\n\t\t\t\tif (script === undefined) return usage(\"run cannot tell how this program was started\");\n\t\t\t\tconst command = [process.execPath, ...process.execArgv, script, ...programArgs];\n\t\t\t\tconst child = spawn(binary.command, [...binary.args, \"run\", ...flags, \"--\", ...command], {\n\t\t\t\t\tstdio: \"inherit\",\n\t\t\t\t\tenv: { ...process.env, ...io.env },\n\t\t\t\t});\n\t\t\t\t// whoever ends this process ends the launcher behind it, which ends the program it supervises\n\t\t\t\tconst forward = (signal: NodeJS.Signals): void => {\n\t\t\t\t\tif (child.exitCode === null && child.signalCode === null) child.kill(signal);\n\t\t\t\t};\n\t\t\t\tconst forwarded: NodeJS.Signals[] = [\"SIGTERM\", \"SIGINT\", \"SIGHUP\"];\n\t\t\t\tfor (const signal of forwarded) process.on(signal, forward);\n\t\t\t\ttry {\n\t\t\t\t\treturn await new Promise<number>((resolve) => {\n\t\t\t\t\t\tchild.once(\"error\", (error) => {\n\t\t\t\t\t\t\tio.err(`${manifest.entry}: the harness binary could not be started: ${errorMessage(error)}`);\n\t\t\t\t\t\t\tresolve(1);\n\t\t\t\t\t\t});\n\t\t\t\t\t\tchild.once(\"exit\", (code) => resolve(code ?? 1));\n\t\t\t\t\t});\n\t\t\t\t} finally {\n\t\t\t\t\tfor (const signal of forwarded) process.off(signal, forward);\n\t\t\t\t}\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\treturn usage(`unknown verb ${verb}`);\n\t\t}\n\t} catch (error) {\n\t\tio.err(`${manifest.entry}: ${errorMessage(error)}`);\n\t\treturn 2;\n\t}\n}\n"]}
package/dist/env.d.ts ADDED
@@ -0,0 +1,38 @@
1
+ import type { Mode } from "./manifest/manifest.ts";
2
+ export declare const ENV_MODE = "ABAI_MODE";
3
+ export declare const ENV_HARNESS = "ABAI_HARNESS";
4
+ /**
5
+ * Set by a harness that launched this program (section 6.3): the socket its
6
+ * endpoint must listen on, where the launcher is already waiting. Its
7
+ * presence is also what makes the full lifecycle channel available (5.5).
8
+ */
9
+ export declare const ENV_LAUNCH_SOCKET = "ABAI_LAUNCH_SOCKET";
10
+ /** Where a sidecar endpoint puts its socket and descriptor; default `<ABAI_HOME or ~/.abai>/run`, the harness's own default. */
11
+ export declare const ENV_RUN_DIR = "ABAI_RUN_DIR";
12
+ /** The harness binary the stub spawns at a touchpoint under sidecar; default: the program's `node_modules/.bin`, else PATH. */
13
+ export declare const ENV_HARNESS_BIN = "ABAI_HARNESS_BIN";
14
+ /** How long a sidecar attach waits for the spawned harness to connect, in milliseconds. */
15
+ export declare const ENV_ATTACH_WAIT_MS = "ABAI_ATTACH_WAIT_MS";
16
+ export declare const DEFAULT_ATTACH_WAIT_MS = 30000;
17
+ /** The run directory for this environment. With no home at all, a private directory under the machine's temp dir. */
18
+ export declare function runDirFrom(env?: NodeJS.ProcessEnv): string;
19
+ /** The attach wait for this environment; an unusable value means the default. */
20
+ export declare function attachWaitMsFrom(env?: NodeJS.ProcessEnv): number;
21
+ export type HarnessSelection = "real" | "off" | "null" | "exercise";
22
+ export interface ModeSelection {
23
+ mode: Mode;
24
+ /** The requested mode was not declared; the default applies and is counted. */
25
+ fallback: boolean;
26
+ /** What `ABAI_MODE` asked for, when set. */
27
+ requested?: string;
28
+ }
29
+ /** The mode for this run: the first declared, unless `ABAI_MODE` names a declared one. */
30
+ export declare function selectMode(modes: readonly Mode[], env?: NodeJS.ProcessEnv): ModeSelection;
31
+ /** The harness for this run. An unknown value selects the real harness and is reported, never thrown: the program runs. */
32
+ export declare function selectHarness(env?: NodeJS.ProcessEnv): {
33
+ selection: HarnessSelection;
34
+ error?: string;
35
+ };
36
+ /** `~` at the start of a path means the home directory. */
37
+ export declare function expandHome(path: string, home?: string): string;
38
+ //# sourceMappingURL=env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAEnD,eAAO,MAAM,QAAQ,cAAc,CAAC;AACpC,eAAO,MAAM,WAAW,iBAAiB,CAAC;AAC1C;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,uBAAuB,CAAC;AACtD,gIAAgI;AAChI,eAAO,MAAM,WAAW,iBAAiB,CAAC;AAC1C,+HAA+H;AAC/H,eAAO,MAAM,eAAe,qBAAqB,CAAC;AAClD,2FAA2F;AAC3F,eAAO,MAAM,kBAAkB,wBAAwB,CAAC;AACxD,eAAO,MAAM,sBAAsB,QAAS,CAAC;AAE7C,qHAAqH;AACrH,wBAAgB,UAAU,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAOvE;AAED,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAG7E;AAED,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,UAAU,CAAC;AAEpE,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,IAAI,CAAC;IACX,+EAA+E;IAC/E,QAAQ,EAAE,OAAO,CAAC;IAClB,4CAA4C;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,0FAA0F;AAC1F,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,aAAa,CAOtG;AAED,2HAA2H;AAC3H,wBAAgB,aAAa,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG;IAAE,SAAS,EAAE,gBAAgB,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAKnH;AAED,2DAA2D;AAC3D,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,SAAyB,GAAG,MAAM,CAI9E","sourcesContent":["// Mode and harness selection from the environment (abaigrammar section 4.4).\n// `ABAI_MODE` overrides the manifest's default mode; a value the manifest\n// does not declare falls back to the default and is counted. `ABAI_HARNESS`\n// is read only by check runs: unset means the real harness, `off` makes\n// every attach fail at once, `null` and `exercise` select the null harness\n// in its passive and active forms.\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { Mode } from \"./manifest/manifest.ts\";\n\nexport const ENV_MODE = \"ABAI_MODE\";\nexport const ENV_HARNESS = \"ABAI_HARNESS\";\n/**\n * Set by a harness that launched this program (section 6.3): the socket its\n * endpoint must listen on, where the launcher is already waiting. Its\n * presence is also what makes the full lifecycle channel available (5.5).\n */\nexport const ENV_LAUNCH_SOCKET = \"ABAI_LAUNCH_SOCKET\";\n/** Where a sidecar endpoint puts its socket and descriptor; default `<ABAI_HOME or ~/.abai>/run`, the harness's own default. */\nexport const ENV_RUN_DIR = \"ABAI_RUN_DIR\";\n/** The harness binary the stub spawns at a touchpoint under sidecar; default: the program's `node_modules/.bin`, else PATH. */\nexport const ENV_HARNESS_BIN = \"ABAI_HARNESS_BIN\";\n/** How long a sidecar attach waits for the spawned harness to connect, in milliseconds. */\nexport const ENV_ATTACH_WAIT_MS = \"ABAI_ATTACH_WAIT_MS\";\nexport const DEFAULT_ATTACH_WAIT_MS = 30_000;\n\n/** The run directory for this environment. With no home at all, a private directory under the machine's temp dir. */\nexport function runDirFrom(env: NodeJS.ProcessEnv = process.env): string {\n\tconst explicit = env[ENV_RUN_DIR]?.trim();\n\tif (explicit) return explicit;\n\tconst home = env.ABAI_HOME?.trim();\n\tif (home) return join(home, \"run\");\n\tconst user = env.HOME?.trim();\n\treturn user ? join(user, \".abai\", \"run\") : join(tmpdir(), \"abai-run\");\n}\n\n/** The attach wait for this environment; an unusable value means the default. */\nexport function attachWaitMsFrom(env: NodeJS.ProcessEnv = process.env): number {\n\tconst value = Number(env[ENV_ATTACH_WAIT_MS]);\n\treturn Number.isInteger(value) && value > 0 ? value : DEFAULT_ATTACH_WAIT_MS;\n}\n\nexport type HarnessSelection = \"real\" | \"off\" | \"null\" | \"exercise\";\n\nexport interface ModeSelection {\n\tmode: Mode;\n\t/** The requested mode was not declared; the default applies and is counted. */\n\tfallback: boolean;\n\t/** What `ABAI_MODE` asked for, when set. */\n\trequested?: string;\n}\n\n/** The mode for this run: the first declared, unless `ABAI_MODE` names a declared one. */\nexport function selectMode(modes: readonly Mode[], env: NodeJS.ProcessEnv = process.env): ModeSelection {\n\tconst requested = env[ENV_MODE]?.trim();\n\tconst first = modes[0];\n\tif (first === undefined) throw new Error(\"the manifest declares no modes\");\n\tif (requested === undefined || requested === \"\") return { mode: first, fallback: false };\n\tif ((modes as readonly string[]).includes(requested)) return { mode: requested as Mode, fallback: false, requested };\n\treturn { mode: first, fallback: true, requested };\n}\n\n/** The harness for this run. An unknown value selects the real harness and is reported, never thrown: the program runs. */\nexport function selectHarness(env: NodeJS.ProcessEnv = process.env): { selection: HarnessSelection; error?: string } {\n\tconst value = env[ENV_HARNESS]?.trim();\n\tif (value === undefined || value === \"\") return { selection: \"real\" };\n\tif (value === \"off\" || value === \"null\" || value === \"exercise\") return { selection: value };\n\treturn { selection: \"real\", error: `${ENV_HARNESS} must be unset, off, null or exercise (got ${value})` };\n}\n\n/** `~` at the start of a path means the home directory. */\nexport function expandHome(path: string, home = process.env.HOME ?? \"\"): string {\n\tif (path === \"~\") return home;\n\tif (path.startsWith(\"~/\")) return `${home}${path.slice(1)}`;\n\treturn path;\n}\n"]}
package/dist/env.js ADDED
@@ -0,0 +1,69 @@
1
+ // Mode and harness selection from the environment (abaigrammar section 4.4).
2
+ // `ABAI_MODE` overrides the manifest's default mode; a value the manifest
3
+ // does not declare falls back to the default and is counted. `ABAI_HARNESS`
4
+ // is read only by check runs: unset means the real harness, `off` makes
5
+ // every attach fail at once, `null` and `exercise` select the null harness
6
+ // in its passive and active forms.
7
+ import { tmpdir } from "node:os";
8
+ import { join } from "node:path";
9
+ export const ENV_MODE = "ABAI_MODE";
10
+ export const ENV_HARNESS = "ABAI_HARNESS";
11
+ /**
12
+ * Set by a harness that launched this program (section 6.3): the socket its
13
+ * endpoint must listen on, where the launcher is already waiting. Its
14
+ * presence is also what makes the full lifecycle channel available (5.5).
15
+ */
16
+ export const ENV_LAUNCH_SOCKET = "ABAI_LAUNCH_SOCKET";
17
+ /** Where a sidecar endpoint puts its socket and descriptor; default `<ABAI_HOME or ~/.abai>/run`, the harness's own default. */
18
+ export const ENV_RUN_DIR = "ABAI_RUN_DIR";
19
+ /** The harness binary the stub spawns at a touchpoint under sidecar; default: the program's `node_modules/.bin`, else PATH. */
20
+ export const ENV_HARNESS_BIN = "ABAI_HARNESS_BIN";
21
+ /** How long a sidecar attach waits for the spawned harness to connect, in milliseconds. */
22
+ export const ENV_ATTACH_WAIT_MS = "ABAI_ATTACH_WAIT_MS";
23
+ export const DEFAULT_ATTACH_WAIT_MS = 30_000;
24
+ /** The run directory for this environment. With no home at all, a private directory under the machine's temp dir. */
25
+ export function runDirFrom(env = process.env) {
26
+ const explicit = env[ENV_RUN_DIR]?.trim();
27
+ if (explicit)
28
+ return explicit;
29
+ const home = env.ABAI_HOME?.trim();
30
+ if (home)
31
+ return join(home, "run");
32
+ const user = env.HOME?.trim();
33
+ return user ? join(user, ".abai", "run") : join(tmpdir(), "abai-run");
34
+ }
35
+ /** The attach wait for this environment; an unusable value means the default. */
36
+ export function attachWaitMsFrom(env = process.env) {
37
+ const value = Number(env[ENV_ATTACH_WAIT_MS]);
38
+ return Number.isInteger(value) && value > 0 ? value : DEFAULT_ATTACH_WAIT_MS;
39
+ }
40
+ /** The mode for this run: the first declared, unless `ABAI_MODE` names a declared one. */
41
+ export function selectMode(modes, env = process.env) {
42
+ const requested = env[ENV_MODE]?.trim();
43
+ const first = modes[0];
44
+ if (first === undefined)
45
+ throw new Error("the manifest declares no modes");
46
+ if (requested === undefined || requested === "")
47
+ return { mode: first, fallback: false };
48
+ if (modes.includes(requested))
49
+ return { mode: requested, fallback: false, requested };
50
+ return { mode: first, fallback: true, requested };
51
+ }
52
+ /** The harness for this run. An unknown value selects the real harness and is reported, never thrown: the program runs. */
53
+ export function selectHarness(env = process.env) {
54
+ const value = env[ENV_HARNESS]?.trim();
55
+ if (value === undefined || value === "")
56
+ return { selection: "real" };
57
+ if (value === "off" || value === "null" || value === "exercise")
58
+ return { selection: value };
59
+ return { selection: "real", error: `${ENV_HARNESS} must be unset, off, null or exercise (got ${value})` };
60
+ }
61
+ /** `~` at the start of a path means the home directory. */
62
+ export function expandHome(path, home = process.env.HOME ?? "") {
63
+ if (path === "~")
64
+ return home;
65
+ if (path.startsWith("~/"))
66
+ return `${home}${path.slice(1)}`;
67
+ return path;
68
+ }
69
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"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","sourcesContent":["// Mode and harness selection from the environment (abaigrammar section 4.4).\n// `ABAI_MODE` overrides the manifest's default mode; a value the manifest\n// does not declare falls back to the default and is counted. `ABAI_HARNESS`\n// is read only by check runs: unset means the real harness, `off` makes\n// every attach fail at once, `null` and `exercise` select the null harness\n// in its passive and active forms.\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { Mode } from \"./manifest/manifest.ts\";\n\nexport const ENV_MODE = \"ABAI_MODE\";\nexport const ENV_HARNESS = \"ABAI_HARNESS\";\n/**\n * Set by a harness that launched this program (section 6.3): the socket its\n * endpoint must listen on, where the launcher is already waiting. Its\n * presence is also what makes the full lifecycle channel available (5.5).\n */\nexport const ENV_LAUNCH_SOCKET = \"ABAI_LAUNCH_SOCKET\";\n/** Where a sidecar endpoint puts its socket and descriptor; default `<ABAI_HOME or ~/.abai>/run`, the harness's own default. */\nexport const ENV_RUN_DIR = \"ABAI_RUN_DIR\";\n/** The harness binary the stub spawns at a touchpoint under sidecar; default: the program's `node_modules/.bin`, else PATH. */\nexport const ENV_HARNESS_BIN = \"ABAI_HARNESS_BIN\";\n/** How long a sidecar attach waits for the spawned harness to connect, in milliseconds. */\nexport const ENV_ATTACH_WAIT_MS = \"ABAI_ATTACH_WAIT_MS\";\nexport const DEFAULT_ATTACH_WAIT_MS = 30_000;\n\n/** The run directory for this environment. With no home at all, a private directory under the machine's temp dir. */\nexport function runDirFrom(env: NodeJS.ProcessEnv = process.env): string {\n\tconst explicit = env[ENV_RUN_DIR]?.trim();\n\tif (explicit) return explicit;\n\tconst home = env.ABAI_HOME?.trim();\n\tif (home) return join(home, \"run\");\n\tconst user = env.HOME?.trim();\n\treturn user ? join(user, \".abai\", \"run\") : join(tmpdir(), \"abai-run\");\n}\n\n/** The attach wait for this environment; an unusable value means the default. */\nexport function attachWaitMsFrom(env: NodeJS.ProcessEnv = process.env): number {\n\tconst value = Number(env[ENV_ATTACH_WAIT_MS]);\n\treturn Number.isInteger(value) && value > 0 ? value : DEFAULT_ATTACH_WAIT_MS;\n}\n\nexport type HarnessSelection = \"real\" | \"off\" | \"null\" | \"exercise\";\n\nexport interface ModeSelection {\n\tmode: Mode;\n\t/** The requested mode was not declared; the default applies and is counted. */\n\tfallback: boolean;\n\t/** What `ABAI_MODE` asked for, when set. */\n\trequested?: string;\n}\n\n/** The mode for this run: the first declared, unless `ABAI_MODE` names a declared one. */\nexport function selectMode(modes: readonly Mode[], env: NodeJS.ProcessEnv = process.env): ModeSelection {\n\tconst requested = env[ENV_MODE]?.trim();\n\tconst first = modes[0];\n\tif (first === undefined) throw new Error(\"the manifest declares no modes\");\n\tif (requested === undefined || requested === \"\") return { mode: first, fallback: false };\n\tif ((modes as readonly string[]).includes(requested)) return { mode: requested as Mode, fallback: false, requested };\n\treturn { mode: first, fallback: true, requested };\n}\n\n/** The harness for this run. An unknown value selects the real harness and is reported, never thrown: the program runs. */\nexport function selectHarness(env: NodeJS.ProcessEnv = process.env): { selection: HarnessSelection; error?: string } {\n\tconst value = env[ENV_HARNESS]?.trim();\n\tif (value === undefined || value === \"\") return { selection: \"real\" };\n\tif (value === \"off\" || value === \"null\" || value === \"exercise\") return { selection: value };\n\treturn { selection: \"real\", error: `${ENV_HARNESS} must be unset, off, null or exercise (got ${value})` };\n}\n\n/** `~` at the start of a path means the home directory. */\nexport function expandHome(path: string, home = process.env.HOME ?? \"\"): string {\n\tif (path === \"~\") return home;\n\tif (path.startsWith(\"~/\")) return `${home}${path.slice(1)}`;\n\treturn path;\n}\n"]}
@@ -0,0 +1,223 @@
1
+ import { type AuditTail } from "./audit.ts";
2
+ import { type DecisionDecl, type FieldSchema, type Manifest, type TurnDecl } from "./manifest/manifest.ts";
3
+ import type { Abaigram, AttachedHarness, CounterSnapshot } from "./program.ts";
4
+ import type { WireErrorCode } from "./wire/protocol.ts";
5
+ export interface DecisionRequest {
6
+ id: string;
7
+ name: string;
8
+ decision: DecisionDecl;
9
+ context: Record<string, unknown>;
10
+ /** Epoch milliseconds by which an answer must arrive. */
11
+ deadline: number;
12
+ }
13
+ export interface TurnRequest {
14
+ id: string;
15
+ name: string;
16
+ turn: TurnDecl;
17
+ deadline: number;
18
+ /** The content slot for this turn, when the program has one. */
19
+ content: string | undefined;
20
+ }
21
+ export type TouchpointKind = "install" | "session";
22
+ export interface TouchpointRequest {
23
+ id: string;
24
+ kind: TouchpointKind;
25
+ content: string | undefined;
26
+ }
27
+ export interface LiveEvent {
28
+ seq: number;
29
+ name: string;
30
+ payload: Record<string, unknown> | undefined;
31
+ truncated: boolean;
32
+ ts: number;
33
+ }
34
+ export interface EventBatch {
35
+ events: LiveEvent[];
36
+ /** Events overwritten before they were read; the harness synthesizes `abai.events.dropped` from it. */
37
+ dropped: number;
38
+ next: number;
39
+ }
40
+ export interface CellReading {
41
+ value: unknown;
42
+ version: number;
43
+ }
44
+ export interface KnobWriteOutcome {
45
+ value: unknown;
46
+ outcome: "done" | "failed";
47
+ error?: string;
48
+ /** Why it failed, in the capability error vocabulary (the endpoint sends it under `call_codes`). */
49
+ code?: CallErrorCode;
50
+ }
51
+ /**
52
+ * What the harness states about an act whose policy is `confirm` (section
53
+ * 10): a person approved it, the harness approved it without asking (auto
54
+ * mode, or the exercise form standing in for the abaigrammer), or it was
55
+ * denied. An act under `auto` policy needs none.
56
+ */
57
+ export type Consent = "approved" | "auto" | "denied";
58
+ /** Why a call failed: the one vocabulary, in process and on the wire. */
59
+ export type CallErrorCode = WireErrorCode;
60
+ export type LifecycleOutcome = {
61
+ ok: true;
62
+ data?: unknown;
63
+ } | {
64
+ ok: false;
65
+ code: CallErrorCode;
66
+ error: string;
67
+ };
68
+ /** A capability call that did not return a result. */
69
+ export declare class CallError extends Error {
70
+ readonly code: CallErrorCode;
71
+ constructor(code: CallErrorCode, message: string);
72
+ }
73
+ export interface BindingEvents {
74
+ event: (event: LiveEvent) => void;
75
+ decision: (request: DecisionRequest) => void;
76
+ /** The decision expired: the program applied the default. */
77
+ decision_timeout: (id: string, name: string) => void;
78
+ turn: (request: TurnRequest) => void;
79
+ touchpoint: (request: TouchpointRequest) => void;
80
+ detach: (reason: string) => void;
81
+ }
82
+ /**
83
+ * The harness's view of the stub, in-process. The optional trailing `conn`
84
+ * of the acting methods names the connection that acts, for a front end
85
+ * that multiplexes several (the sidecar endpoint); the audit record carries
86
+ * it. An in-process harness passes none and is audited under the binding's
87
+ * own label.
88
+ */
89
+ export interface HarnessBinding {
90
+ readonly manifest: Manifest;
91
+ readonly name: string;
92
+ readonly connection: string;
93
+ content(): {
94
+ identity: string;
95
+ install: string | undefined;
96
+ use: string | undefined;
97
+ turn(name: string): string | undefined;
98
+ };
99
+ readCells(names?: string[]): {
100
+ seq: number;
101
+ cells: Record<string, CellReading>;
102
+ };
103
+ readEvents(after: number): EventBatch;
104
+ writeKnob(name: string, value: unknown, reason: string, consent?: Consent, conn?: string): Promise<KnobWriteOutcome>;
105
+ call(name: string, params: Record<string, unknown> | undefined, reason: string, consent?: Consent, conn?: string): Promise<unknown>;
106
+ auditTail(limit: number): AuditTail;
107
+ /** Where the audit log is, and the error that latched it off, if any. */
108
+ auditInfo(): {
109
+ path: string;
110
+ failed: string | null;
111
+ };
112
+ takeCounters(): CounterSnapshot;
113
+ on<K extends keyof BindingEvents>(type: K, listener: BindingEvents[K]): () => void;
114
+ /** Answer a pending decision; `null` means "apply the default" with this reason. Throws when the answer is invalid. */
115
+ answerDecision(id: string, answer: unknown, reason: string, consent?: Consent, conn?: string): void;
116
+ /**
117
+ * Let a pending decision take its default now, for a cause of the front
118
+ * end's: `no_harness` when nobody holds it, `timeout` when a claim's own
119
+ * shorter wait ran out, `detached` when its claimant went away. Audited
120
+ * like every other settlement, and `decision_timeout` is notified for a
121
+ * timeout, so one path serves every cause.
122
+ */
123
+ defaultDecision(id: string, cause: string, conn?: string): void;
124
+ /** @internal Name the connection that was asked a pending decision, so its settlement is audited under it. */
125
+ assignDecision(id: string, conn: string): void;
126
+ pendingDecisions(): DecisionRequest[];
127
+ /** End a turn. `cause` says why the agent did nothing with it (the grammar's `budget`), and is audited. */
128
+ endTurn(id: string, conn?: string, cause?: string): void;
129
+ endTouchpoint(id: string): void;
130
+ /**
131
+ * A lifecycle operation of the program's own (section 5.5): `status`,
132
+ * `pause` and `resume` for a cooperative pause, `stop` for the declared
133
+ * stop handler. Policy and consent are checked here like any act of
134
+ * control, and the acts that change something are audited.
135
+ */
136
+ lifecycle(op: string, reason: string, consent?: Consent, conn?: string): LifecycleOutcome;
137
+ detach(reason: string): void;
138
+ readonly attached: boolean;
139
+ }
140
+ export interface BindingOptions {
141
+ /** Where the audit log goes; default: the manifest's path, `~` expanded, relative to the program's root. */
142
+ auditPath?: string;
143
+ connection?: string;
144
+ }
145
+ /**
146
+ * Check a value against a schema: an object with no undeclared field, whose
147
+ * every present field is of its declared type. A declared field may be
148
+ * absent (decided 2026-10-14: the schema language has no required marker,
149
+ * and a manifest's own defaults omit fields); `nullable` governs an
150
+ * explicit null. Nested objects and lists are checked by `matchesType`.
151
+ */
152
+ export declare function schemaProblem(schema: Record<string, FieldSchema>, value: unknown, what: string): string | undefined;
153
+ export declare class DirectBinding implements HarnessBinding, AttachedHarness {
154
+ readonly manifest: Manifest;
155
+ readonly name: string;
156
+ readonly connection: string;
157
+ private readonly app;
158
+ private readonly audit;
159
+ private readonly listeners;
160
+ private readonly decisions;
161
+ private readonly turns;
162
+ private readonly touchpoints;
163
+ private readonly capabilityIndex;
164
+ /** Touchpoints in progress: while one is open the program sits at a safepoint, so queued work runs at once (section 5.3). */
165
+ private openTouchpoints;
166
+ private nextId;
167
+ private _attached;
168
+ constructor(app: Abaigram, options?: BindingOptions);
169
+ get attached(): boolean;
170
+ /** @internal Called by the program once the binding is set: the counters go to the log first (section 10). */
171
+ flushCounters(): void;
172
+ /** Queue work for the program's next safepoint, or run it now when a touchpoint holds the program at one. */
173
+ private atSafepoint;
174
+ /**
175
+ * @internal The program is at a safepoint and will stay there (its entry
176
+ * serving an MCP client): safepoint-dispatched work runs at once rather
177
+ * than waiting for a safepoint the program would never reach. Paired
178
+ * with `leaveSafepoint`.
179
+ */
180
+ enterSafepoint(): void;
181
+ /** @internal */
182
+ leaveSafepoint(): void;
183
+ content(): {
184
+ identity: string;
185
+ install: string | undefined;
186
+ use: string | undefined;
187
+ turn(name: string): string | undefined;
188
+ };
189
+ readCells(names?: string[]): {
190
+ seq: number;
191
+ cells: Record<string, CellReading>;
192
+ };
193
+ readEvents(after: number): EventBatch;
194
+ private live;
195
+ writeKnob(name: string, value: unknown, reason: string, consent?: Consent, conn?: string): Promise<KnobWriteOutcome>;
196
+ call(name: string, params: Record<string, unknown> | undefined, reason: string, consent?: Consent, conn?: string): Promise<unknown>;
197
+ auditTail(limit: number): AuditTail;
198
+ auditInfo(): {
199
+ path: string;
200
+ failed: string | null;
201
+ };
202
+ takeCounters(): CounterSnapshot;
203
+ on<K extends keyof BindingEvents>(type: K, listener: BindingEvents[K]): () => void;
204
+ private notify;
205
+ answerDecision(id: string, answer: unknown, reason: string, consent?: Consent, conn?: string): void;
206
+ defaultDecision(id: string, cause: string, conn?: string): void;
207
+ assignDecision(id: string, conn: string): void;
208
+ pendingDecisions(): DecisionRequest[];
209
+ private settleDecision;
210
+ endTurn(id: string, conn?: string, cause?: string): void;
211
+ /** @internal Queue work for the program's next safepoint, running it now when one is held open. */
212
+ atNextSafepoint(work: () => void): void;
213
+ lifecycle(op: string, reason: string, consent?: Consent, conn?: string): LifecycleOutcome;
214
+ private settleTurn;
215
+ endTouchpoint(id: string): void;
216
+ detach(reason: string): void;
217
+ decide(decision: DecisionDecl, context: Record<string, unknown>, deadline: number): Promise<unknown>;
218
+ turn(turn: TurnDecl, deadline: number): Promise<void>;
219
+ /** @internal A program-initiated `install` or `session`; resolves when the harness ends it or detaches. */
220
+ touchpoint(kind: TouchpointKind): Promise<void>;
221
+ emitted(seq: number): void;
222
+ }
223
+ //# sourceMappingURL=harness-binding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harness-binding.d.ts","sourceRoot":"","sources":["../src/harness-binding.ts"],"names":[],"mappings":"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","sourcesContent":["// The direct face (abaigrammar section 4.1): what the stub hands a harness\n// that attaches in-process. One object serves both sides. To the program it\n// is the AttachedHarness that decisions, turns, touchpoints and emits reach;\n// to the harness it is the channels: cells and events to read, knobs to\n// write, capabilities to call, decisions and turns to answer, the audit log\n// to tail, the counters to take. Every act of control is audited here, on\n// the program side, as section 10 says, with the consent the harness states\n// for an act whose policy is `confirm`.\nimport { resolve } from \"node:path\";\nimport { AuditLog, type AuditOutcome, type AuditTail, capValue, summarizeAnswer } from \"./audit.ts\";\nimport { validateKnobValue } from \"./cells/fit.ts\";\nimport { expandHome } from \"./env.ts\";\nimport {\n\ttype CapabilityDecl,\n\ttype DecisionDecl,\n\tdurationMs,\n\ttype FieldSchema,\n\tfieldOf,\n\ttype Manifest,\n\tmatchesType,\n\ttype TurnDecl,\n} from \"./manifest/manifest.ts\";\nimport type { Abaigram, AttachedHarness, CounterSnapshot } from \"./program.ts\";\nimport type { EventSlot } from \"./region.ts\";\nimport type { WireErrorCode } from \"./wire/protocol.ts\";\n\nexport interface DecisionRequest {\n\tid: string;\n\tname: string;\n\tdecision: DecisionDecl;\n\tcontext: Record<string, unknown>;\n\t/** Epoch milliseconds by which an answer must arrive. */\n\tdeadline: number;\n}\n\nexport interface TurnRequest {\n\tid: string;\n\tname: string;\n\tturn: TurnDecl;\n\tdeadline: number;\n\t/** The content slot for this turn, when the program has one. */\n\tcontent: string | undefined;\n}\n\nexport type TouchpointKind = \"install\" | \"session\";\n\nexport interface TouchpointRequest {\n\tid: string;\n\tkind: TouchpointKind;\n\tcontent: string | undefined;\n}\n\nexport interface LiveEvent {\n\tseq: number;\n\tname: string;\n\tpayload: Record<string, unknown> | undefined;\n\ttruncated: boolean;\n\tts: number;\n}\n\nexport interface EventBatch {\n\tevents: LiveEvent[];\n\t/** Events overwritten before they were read; the harness synthesizes `abai.events.dropped` from it. */\n\tdropped: number;\n\tnext: number;\n}\n\nexport interface CellReading {\n\tvalue: unknown;\n\tversion: number;\n}\n\nexport interface KnobWriteOutcome {\n\tvalue: unknown;\n\toutcome: \"done\" | \"failed\";\n\terror?: string;\n\t/** Why it failed, in the capability error vocabulary (the endpoint sends it under `call_codes`). */\n\tcode?: CallErrorCode;\n}\n\n/**\n * What the harness states about an act whose policy is `confirm` (section\n * 10): a person approved it, the harness approved it without asking (auto\n * mode, or the exercise form standing in for the abaigrammer), or it was\n * denied. An act under `auto` policy needs none.\n */\nexport type Consent = \"approved\" | \"auto\" | \"denied\";\n\n/** Why a call failed: the one vocabulary, in process and on the wire. */\nexport type CallErrorCode = WireErrorCode;\n\nexport type LifecycleOutcome = { ok: true; data?: unknown } | { ok: false; code: CallErrorCode; error: string };\n\n/** A capability call that did not return a result. */\nexport class CallError extends Error {\n\treadonly code: CallErrorCode;\n\tconstructor(code: CallErrorCode, message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"CallError\";\n\t\tthis.code = code;\n\t}\n}\n\nexport interface BindingEvents {\n\tevent: (event: LiveEvent) => void;\n\tdecision: (request: DecisionRequest) => void;\n\t/** The decision expired: the program applied the default. */\n\tdecision_timeout: (id: string, name: string) => void;\n\tturn: (request: TurnRequest) => void;\n\ttouchpoint: (request: TouchpointRequest) => void;\n\tdetach: (reason: string) => void;\n}\n\n/**\n * The harness's view of the stub, in-process. The optional trailing `conn`\n * of the acting methods names the connection that acts, for a front end\n * that multiplexes several (the sidecar endpoint); the audit record carries\n * it. An in-process harness passes none and is audited under the binding's\n * own label.\n */\nexport interface HarnessBinding {\n\treadonly manifest: Manifest;\n\treadonly name: string;\n\treadonly connection: string;\n\tcontent(): {\n\t\tidentity: string;\n\t\tinstall: string | undefined;\n\t\tuse: string | undefined;\n\t\tturn(name: string): string | undefined;\n\t};\n\treadCells(names?: string[]): { seq: number; cells: Record<string, CellReading> };\n\treadEvents(after: number): EventBatch;\n\twriteKnob(name: string, value: unknown, reason: string, consent?: Consent, conn?: string): Promise<KnobWriteOutcome>;\n\tcall(\n\t\tname: string,\n\t\tparams: Record<string, unknown> | undefined,\n\t\treason: string,\n\t\tconsent?: Consent,\n\t\tconn?: string,\n\t): Promise<unknown>;\n\tauditTail(limit: number): AuditTail;\n\t/** Where the audit log is, and the error that latched it off, if any. */\n\tauditInfo(): { path: string; failed: string | null };\n\ttakeCounters(): CounterSnapshot;\n\ton<K extends keyof BindingEvents>(type: K, listener: BindingEvents[K]): () => void;\n\t/** Answer a pending decision; `null` means \"apply the default\" with this reason. Throws when the answer is invalid. */\n\tanswerDecision(id: string, answer: unknown, reason: string, consent?: Consent, conn?: string): void;\n\t/**\n\t * Let a pending decision take its default now, for a cause of the front\n\t * end's: `no_harness` when nobody holds it, `timeout` when a claim's own\n\t * shorter wait ran out, `detached` when its claimant went away. Audited\n\t * like every other settlement, and `decision_timeout` is notified for a\n\t * timeout, so one path serves every cause.\n\t */\n\tdefaultDecision(id: string, cause: string, conn?: string): void;\n\t/** @internal Name the connection that was asked a pending decision, so its settlement is audited under it. */\n\tassignDecision(id: string, conn: string): void;\n\tpendingDecisions(): DecisionRequest[];\n\t/** End a turn. `cause` says why the agent did nothing with it (the grammar's `budget`), and is audited. */\n\tendTurn(id: string, conn?: string, cause?: string): void;\n\tendTouchpoint(id: string): void;\n\t/**\n\t * A lifecycle operation of the program's own (section 5.5): `status`,\n\t * `pause` and `resume` for a cooperative pause, `stop` for the declared\n\t * stop handler. Policy and consent are checked here like any act of\n\t * control, and the acts that change something are audited.\n\t */\n\tlifecycle(op: string, reason: string, consent?: Consent, conn?: string): LifecycleOutcome;\n\tdetach(reason: string): void;\n\treadonly attached: boolean;\n}\n\ninterface Pending<T> {\n\tresolve: (value: T) => void;\n\treject: (error: Error) => void;\n\ttimer: NodeJS.Timeout | undefined;\n\tstartedAt: number;\n\t/** The connection this was asked of, when a front end named one. */\n\tconn?: string;\n}\n\n/**\n * A touchpoint has no timeout of its own, so nothing of the program's holds\n * its event loop open while a harness in another process holds the\n * touchpoint; this ref'd timer does, and never fires in practice (the\n * longest delay a timer takes). Cleared when the touchpoint ends.\n */\nconst TOUCHPOINT_KEEPALIVE_MS = 2 ** 31 - 1;\n\nexport interface BindingOptions {\n\t/** Where the audit log goes; default: the manifest's path, `~` expanded, relative to the program's root. */\n\tauditPath?: string;\n\tconnection?: string;\n}\n\n/**\n * Check a value against a schema: an object with no undeclared field, whose\n * every present field is of its declared type. A declared field may be\n * absent (decided 2026-10-14: the schema language has no required marker,\n * and a manifest's own defaults omit fields); `nullable` governs an\n * explicit null. Nested objects and lists are checked by `matchesType`.\n */\nexport function schemaProblem(schema: Record<string, FieldSchema>, value: unknown, what: string): string | undefined {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) return `${what} must be an object`;\n\tconst record = value as Record<string, unknown>;\n\tfor (const [key, field] of Object.entries(schema)) {\n\t\tconst item = record[key];\n\t\tif (item === undefined) continue;\n\t\tif (!matchesType(item, field)) return `${what}.${key} must be a ${fieldOf(field).type}`;\n\t}\n\tfor (const key of Object.keys(record)) {\n\t\tif (!(key in schema)) return `${what} has an undeclared field ${key}`;\n\t}\n\treturn undefined;\n}\n\nfunction errorMessage(error: unknown): string {\n\treturn error instanceof Error ? error.message : String(error);\n}\n\nfunction consentGranted(consent: Consent | undefined): boolean {\n\treturn consent === \"approved\" || consent === \"auto\";\n}\n\nexport class DirectBinding implements HarnessBinding, AttachedHarness {\n\treadonly manifest: Manifest;\n\treadonly name: string;\n\treadonly connection: string;\n\tprivate readonly app: Abaigram;\n\tprivate readonly audit: AuditLog;\n\tprivate readonly listeners: { [K in keyof BindingEvents]: Set<BindingEvents[K]> } = {\n\t\tevent: new Set(),\n\t\tdecision: new Set(),\n\t\tdecision_timeout: new Set(),\n\t\tturn: new Set(),\n\t\ttouchpoint: new Set(),\n\t\tdetach: new Set(),\n\t};\n\tprivate readonly decisions = new Map<string, Pending<unknown> & { request: DecisionRequest }>();\n\tprivate readonly turns = new Map<string, Pending<void> & { request: TurnRequest }>();\n\tprivate readonly touchpoints = new Map<string, Pending<void> & { request: TouchpointRequest }>();\n\tprivate readonly capabilityIndex = new Map<string, CapabilityDecl>();\n\t/** Touchpoints in progress: while one is open the program sits at a safepoint, so queued work runs at once (section 5.3). */\n\tprivate openTouchpoints = 0;\n\tprivate nextId = 1;\n\tprivate _attached = true;\n\n\tconstructor(app: Abaigram, options: BindingOptions = {}) {\n\t\tthis.app = app;\n\t\tthis.manifest = app.manifest;\n\t\tthis.name = app.manifest.name;\n\t\tthis.connection = options.connection ?? \"direct\";\n\t\tfor (const capability of this.manifest.capabilities) this.capabilityIndex.set(capability.name, capability);\n\t\tconst auditPath = options.auditPath ?? resolve(app.content.root, expandHome(this.manifest.audit.path));\n\t\tthis.audit = new AuditLog(auditPath, (error) => {\n\t\t\tapp.emitLibrary(\"abai.audit.failed\", { error });\n\t\t});\n\t}\n\n\tget attached(): boolean {\n\t\treturn this._attached;\n\t}\n\n\t/** @internal Called by the program once the binding is set: the counters go to the log first (section 10). */\n\tflushCounters(): void {\n\t\tconst counters = this.app.takeCounters();\n\t\tfor (const [name, count] of Object.entries(counters)) {\n\t\t\tif (count === 0) continue;\n\t\t\tconst cause = name === \"abai.mode_fallback\" ? \"mode_fallback\" : \"no_harness\";\n\t\t\tthis.audit.append({ act: \"counters\", name, outcome: \"default\", cause, count });\n\t\t}\n\t}\n\n\t/** Queue work for the program's next safepoint, or run it now when a touchpoint holds the program at one. */\n\tprivate atSafepoint(work: () => void): void {\n\t\tthis.app.enqueue(work);\n\t\tif (this.openTouchpoints > 0) this.app.drain();\n\t}\n\n\t/**\n\t * @internal The program is at a safepoint and will stay there (its entry\n\t * serving an MCP client): safepoint-dispatched work runs at once rather\n\t * than waiting for a safepoint the program would never reach. Paired\n\t * with `leaveSafepoint`.\n\t */\n\tenterSafepoint(): void {\n\t\tthis.openTouchpoints += 1;\n\t\tthis.app.drain();\n\t}\n\n\t/** @internal */\n\tleaveSafepoint(): void {\n\t\tif (this.openTouchpoints > 0) this.openTouchpoints -= 1;\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Harness side\n\t// -----------------------------------------------------------------------\n\n\tcontent(): {\n\t\tidentity: string;\n\t\tinstall: string | undefined;\n\t\tuse: string | undefined;\n\t\tturn(name: string): string | undefined;\n\t} {\n\t\tconst slots = this.app.content;\n\t\treturn {\n\t\t\tidentity: slots.identity(),\n\t\t\tinstall: slots.install(),\n\t\t\tuse: slots.use(),\n\t\t\tturn: (name) => slots.turn(name),\n\t\t};\n\t}\n\n\treadCells(names?: string[]): { seq: number; cells: Record<string, CellReading> } {\n\t\tconst all = this.app.readCells();\n\t\tconst cells: Record<string, CellReading> = {};\n\t\tfor (const name of names ?? Object.keys(all)) {\n\t\t\tif (!(name in all)) throw new Error(`unknown cell: ${name}`);\n\t\t\tcells[name] = { value: all[name], version: this.app.version(name) };\n\t\t}\n\t\treturn { seq: this.app.region.lastSeq, cells };\n\t}\n\n\treadEvents(after: number): EventBatch {\n\t\tconst read = this.app.region.readEvents(after);\n\t\treturn { events: read.slots.map((slot) => this.live(slot)), dropped: read.dropped, next: read.next };\n\t}\n\n\tprivate live(slot: EventSlot): LiveEvent {\n\t\treturn {\n\t\t\tseq: slot.seq,\n\t\t\tname: this.app.eventName(slot.event),\n\t\t\tpayload: slot.payload,\n\t\t\ttruncated: slot.truncated,\n\t\t\tts: slot.ts,\n\t\t};\n\t}\n\n\tasync writeKnob(\n\t\tname: string,\n\t\tvalue: unknown,\n\t\treason: string,\n\t\tconsent?: Consent,\n\t\tconn?: string,\n\t): Promise<KnobWriteOutcome> {\n\t\tconst decl = this.manifest.cells.find((cell) => cell.name === name);\n\t\tconst started = this.app.now();\n\t\tconst record = (\n\t\t\toutcome: AuditOutcome,\n\t\t\tlanded: unknown,\n\t\t\terror?: string,\n\t\t\tcause?: CallErrorCode,\n\t\t): KnobWriteOutcome => {\n\t\t\tthis.audit.append({\n\t\t\t\tconn: conn ?? this.connection,\n\t\t\t\tact: \"knob\",\n\t\t\t\tname,\n\t\t\t\tvalue: capValue(landed),\n\t\t\t\toutcome,\n\t\t\t\t...(cause === undefined ? {} : { cause }),\n\t\t\t\t...(consent === undefined ? {} : { consent }),\n\t\t\t\treason,\n\t\t\t\t...(error === undefined ? {} : { error }),\n\t\t\t\tms: this.app.now() - started,\n\t\t\t});\n\t\t\treturn outcome === \"ok\"\n\t\t\t\t? { value: landed, outcome: \"done\" }\n\t\t\t\t: { value: landed, outcome: \"failed\", error, ...(cause === undefined ? {} : { code: cause }) };\n\t\t};\n\t\tif (!decl) return record(\"error\", undefined, `unknown cell: ${name}`, \"unknown\");\n\t\tif (decl.access !== \"readwrite\") return record(\"error\", undefined, `${name} is read-only`, \"invalid\");\n\t\tif (decl.policy === \"confirm\" && !consentGranted(consent)) {\n\t\t\treturn record(\"error\", undefined, `${name} needs consent (its policy is confirm)`, \"denied\");\n\t\t}\n\t\tconst problem = validateKnobValue(decl, value);\n\t\tif (problem !== undefined) return record(\"error\", undefined, problem, \"invalid\");\n\t\tconst sized = decl.type === \"string\" || decl.type === \"object\" || decl.type === \"list\";\n\t\tif (!sized) {\n\t\t\tthis.app.knob(name).set(value);\n\t\t\treturn record(\"ok\", this.app.cell(name).get());\n\t\t}\n\t\t// a sized knob is delivered at the program's next safepoint, to its handler, within its delivery timeout (section 5.2)\n\t\tconst handler = this.app.knobHandler(name);\n\t\tif (!handler) {\n\t\t\treturn record(\"failed\", undefined, `no handler registered for ${name}: nothing can receive it`, \"error\");\n\t\t}\n\t\tconst timeoutMs = durationMs(decl.timeout ?? \"30s\");\n\t\treturn new Promise<KnobWriteOutcome>((done) => {\n\t\t\tlet settled = false;\n\t\t\tconst work = (): void => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tclearTimeout(timer);\n\t\t\t\tthis.app.cell(name).set(value);\n\t\t\t\tconst landed = this.app.cell(name).get();\n\t\t\t\ttry {\n\t\t\t\t\thandler(landed);\n\t\t\t\t\tdone(record(\"ok\", landed));\n\t\t\t\t} catch (error) {\n\t\t\t\t\tdone(record(\"error\", landed, errorMessage(error), \"error\"));\n\t\t\t\t}\n\t\t\t};\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tthis.app.dequeue(work);\n\t\t\t\tdone(\n\t\t\t\t\trecord(\n\t\t\t\t\t\t\"failed\",\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t`not delivered within ${decl.timeout ?? \"30s\"}: the program reached no safepoint`,\n\t\t\t\t\t\t\"timeout\",\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}, timeoutMs);\n\t\t\ttimer.unref();\n\t\t\tthis.atSafepoint(work);\n\t\t});\n\t}\n\n\tasync call(\n\t\tname: string,\n\t\tparams: Record<string, unknown> | undefined,\n\t\treason: string,\n\t\tconsent?: Consent,\n\t\tconn?: string,\n\t): Promise<unknown> {\n\t\tconst decl = this.capabilityIndex.get(name);\n\t\tconst started = this.app.now();\n\t\tconst record = (outcome: AuditOutcome, extra: { error?: string; cause?: string } = {}): void => {\n\t\t\tthis.audit.append({\n\t\t\t\tconn: conn ?? this.connection,\n\t\t\t\tact: \"capability\",\n\t\t\t\tname,\n\t\t\t\tparams: capValue(params),\n\t\t\t\toutcome,\n\t\t\t\t...(consent === undefined ? {} : { consent }),\n\t\t\t\treason,\n\t\t\t\t...extra,\n\t\t\t\tms: this.app.now() - started,\n\t\t\t});\n\t\t};\n\t\tconst fail = (code: CallErrorCode, message: string): CallError => {\n\t\t\trecord(code === \"forbidden\" ? \"forbidden\" : \"error\", { error: message, cause: code });\n\t\t\treturn new CallError(code, message);\n\t\t};\n\t\tif (!decl) throw fail(\"unknown\", `${this.name} declares no capability ${name}`);\n\t\tif (decl.policy === \"forbid\") throw fail(\"forbidden\", `the program's policy forbids ${name}`);\n\t\tif (decl.policy === \"confirm\" && !consentGranted(consent))\n\t\t\tthrow fail(\"denied\", `${name} needs consent (its policy is confirm)`);\n\t\tconst problem = schemaProblem(decl.params, params ?? {}, \"params\");\n\t\tif (problem !== undefined) throw fail(\"invalid\", problem);\n\t\tconst timeoutMs = durationMs(decl.timeout ?? \"30s\");\n\t\tconst result = await new Promise<unknown>((done, reject) => {\n\t\t\tlet settled = false;\n\t\t\tconst settle = (fn: () => void): void => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tclearTimeout(timer);\n\t\t\t\tfn();\n\t\t\t};\n\t\t\t// the handler is resolved at dispatch, so one registered after startup still serves\n\t\t\tconst run = (): void => {\n\t\t\t\tif (settled) return;\n\t\t\t\tconst handler = this.app.capabilityHandler(name);\n\t\t\t\tif (!handler) {\n\t\t\t\t\tsettle(() => reject(new CallError(\"error\", `${name} has no handler registered`)));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlet outcome: unknown;\n\t\t\t\ttry {\n\t\t\t\t\toutcome = handler(params ?? {}); // synchronous part runs inside the safepoint, on the program's thread\n\t\t\t\t} catch (error) {\n\t\t\t\t\tsettle(() => reject(new CallError(\"error\", errorMessage(error))));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tPromise.resolve(outcome).then(\n\t\t\t\t\t(value) => settle(() => done(value)),\n\t\t\t\t\t(error) => settle(() => reject(new CallError(\"error\", errorMessage(error)))),\n\t\t\t\t);\n\t\t\t};\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tthis.app.dequeue(run);\n\t\t\t\treject(new CallError(\"timeout\", `${name} did not answer within ${decl.timeout ?? \"30s\"}`));\n\t\t\t}, timeoutMs);\n\t\t\ttimer.unref();\n\t\t\tif (decl.dispatch === \"immediate\") run();\n\t\t\telse this.atSafepoint(run);\n\t\t}).catch((error: CallError) => {\n\t\t\trecord(\"error\", { error: error.message, cause: error.code });\n\t\t\tthrow error;\n\t\t});\n\t\trecord(\"ok\");\n\t\treturn result;\n\t}\n\n\tauditTail(limit: number): AuditTail {\n\t\treturn this.audit.tail(limit);\n\t}\n\n\tauditInfo(): { path: string; failed: string | null } {\n\t\treturn { path: this.audit.path, failed: this.audit.failed ?? null };\n\t}\n\n\ttakeCounters(): CounterSnapshot {\n\t\treturn this.app.takeCounters();\n\t}\n\n\ton<K extends keyof BindingEvents>(type: K, listener: BindingEvents[K]): () => void {\n\t\tconst set = this.listeners[type] as Set<BindingEvents[K]>;\n\t\tset.add(listener);\n\t\treturn () => {\n\t\t\tset.delete(listener);\n\t\t};\n\t}\n\n\tprivate notify<K extends keyof BindingEvents>(type: K, ...args: Parameters<BindingEvents[K]>): void {\n\t\tfor (const listener of this.listeners[type]) {\n\t\t\ttry {\n\t\t\t\t(listener as (...a: Parameters<BindingEvents[K]>) => void)(...args);\n\t\t\t} catch {\n\t\t\t\t// a harness listener's failure never reaches the program\n\t\t\t}\n\t\t}\n\t}\n\n\tanswerDecision(id: string, answer: unknown, reason: string, consent?: Consent, conn?: string): void {\n\t\tconst pending = this.decisions.get(id);\n\t\tif (!pending) throw new Error(`no pending decision ${id}`);\n\t\tif (reason.trim() === \"\") throw new Error(\"a decision needs a reason\");\n\t\tif (conn !== undefined) pending.conn = conn;\n\t\tconst { decision } = pending.request;\n\t\tif (answer !== null) {\n\t\t\tconst problem = decision.options\n\t\t\t\t? decision.options.includes(answer as string)\n\t\t\t\t\t? undefined\n\t\t\t\t\t: `answer must be one of: ${decision.options.join(\", \")}`\n\t\t\t\t: schemaProblem(decision.answer ?? {}, answer, \"answer\");\n\t\t\tif (problem !== undefined) {\n\t\t\t\tthis.settleDecision(id, { source: \"default\", cause: \"invalid\", reason, answer });\n\t\t\t\tthrow new Error(problem);\n\t\t\t}\n\t\t\tif (decision.policy === \"confirm\" && !consentGranted(consent)) {\n\t\t\t\tthis.settleDecision(id, { source: \"default\", cause: \"denied\", reason, consent });\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tthis.settleDecision(\n\t\t\tid,\n\t\t\tanswer === null\n\t\t\t\t? { source: \"default\", cause: \"answered\", reason }\n\t\t\t\t: { source: \"agent\", reason, answer, consent },\n\t\t);\n\t}\n\n\tdefaultDecision(id: string, cause: string, conn?: string): void {\n\t\tconst pending = this.decisions.get(id);\n\t\tif (!pending) return;\n\t\tif (conn !== undefined) pending.conn = conn;\n\t\tthis.settleDecision(id, { source: \"default\", cause });\n\t}\n\n\tassignDecision(id: string, conn: string): void {\n\t\tconst pending = this.decisions.get(id);\n\t\tif (pending) pending.conn = conn;\n\t}\n\n\tpendingDecisions(): DecisionRequest[] {\n\t\treturn [...this.decisions.values()].map((p) => p.request);\n\t}\n\n\tprivate settleDecision(\n\t\tid: string,\n\t\toutcome: { source: \"agent\" | \"default\"; cause?: string; reason?: string; answer?: unknown; consent?: Consent },\n\t): void {\n\t\tconst pending = this.decisions.get(id);\n\t\tif (!pending) return;\n\t\tthis.decisions.delete(id);\n\t\tif (pending.timer) clearTimeout(pending.timer);\n\t\tthis.openTouchpoints -= 1;\n\t\tconst { decision } = pending.request;\n\t\tthis.audit.append({\n\t\t\tconn: pending.conn ?? this.connection,\n\t\t\tact: \"decision\",\n\t\t\tname: decision.name,\n\t\t\tid,\n\t\t\tvalue: summarizeAnswer(decision, outcome.source === \"agent\" ? outcome.answer : decision.default),\n\t\t\toutcome: outcome.source,\n\t\t\t...(outcome.cause === undefined ? {} : { cause: outcome.cause }),\n\t\t\t...(outcome.consent === undefined ? {} : { consent: outcome.consent }),\n\t\t\t...(outcome.reason === undefined ? {} : { reason: outcome.reason }),\n\t\t\tms: this.app.now() - pending.startedAt,\n\t\t});\n\t\tif (outcome.source === \"agent\") pending.resolve(outcome.answer);\n\t\telse pending.reject(new Error(outcome.cause ?? \"default\"));\n\t\tif (outcome.cause === \"timeout\") this.notify(\"decision_timeout\", id, decision.name);\n\t}\n\n\tendTurn(id: string, conn?: string, cause?: string): void {\n\t\tconst pending = this.turns.get(id);\n\t\tif (!pending) return;\n\t\tif (conn !== undefined) pending.conn = conn;\n\t\t// a turn the agent did nothing with (held back by its budget) is a default, with the cause it names\n\t\tif (cause === undefined) this.settleTurn(id, \"ok\");\n\t\telse this.settleTurn(id, \"default\", cause);\n\t}\n\n\t/** @internal Queue work for the program's next safepoint, running it now when one is held open. */\n\tatNextSafepoint(work: () => void): void {\n\t\tthis.atSafepoint(work);\n\t}\n\n\tlifecycle(op: string, reason: string, consent?: Consent, conn?: string): LifecycleOutcome {\n\t\tconst declared = this.manifest.lifecycle;\n\t\tconst started = this.app.now();\n\t\tconst record = (outcome: AuditOutcome, extra: { cause?: string; error?: string } = {}): void => {\n\t\t\tthis.audit.append({\n\t\t\t\tconn: conn ?? this.connection,\n\t\t\t\tact: \"lifecycle\",\n\t\t\t\tname: op,\n\t\t\t\toutcome,\n\t\t\t\t...(consent === undefined ? {} : { consent }),\n\t\t\t\treason,\n\t\t\t\t...extra,\n\t\t\t\tms: this.app.now() - started,\n\t\t\t});\n\t\t};\n\t\tconst refuse = (code: CallErrorCode, error: string): LifecycleOutcome => {\n\t\t\trecord(code === \"forbidden\" ? \"forbidden\" : \"error\", { cause: code, error });\n\t\t\treturn { ok: false, code, error };\n\t\t};\n\t\tif (op === \"status\") return { ok: true, data: this.app.lifecycleStatus() };\n\t\tif (op !== \"pause\" && op !== \"resume\" && op !== \"stop\" && op !== \"restart\" && op !== \"start\") {\n\t\t\treturn { ok: false, code: \"unknown\", error: `unknown lifecycle operation: ${op}` };\n\t\t}\n\t\t// section 10: pause and resume are auto, stop and restart confirm, unless the manifest says otherwise\n\t\tconst policy =\n\t\t\tdeclared?.policy?.[op as \"pause\" | \"resume\" | \"stop\" | \"restart\"] ??\n\t\t\t(op === \"stop\" || op === \"restart\" ? \"confirm\" : \"auto\");\n\t\tif (policy === \"forbid\") return refuse(\"forbidden\", `the program's policy forbids lifecycle ${op}`);\n\t\tif (policy === \"confirm\" && !consentGranted(consent)) {\n\t\t\treturn refuse(\"denied\", `lifecycle ${op} needs consent (its policy is confirm)`);\n\t\t}\n\t\tswitch (op) {\n\t\t\tcase \"pause\":\n\t\t\t\tif (declared?.pause !== \"cooperative\") {\n\t\t\t\t\treturn refuse(\n\t\t\t\t\t\t\"invalid\",\n\t\t\t\t\t\tdeclared?.pause === \"os\"\n\t\t\t\t\t\t\t? \"this program declares os pause, which its launcher performs\"\n\t\t\t\t\t\t\t: \"this program declares no cooperative pause\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tthis.app.requestPause();\n\t\t\t\trecord(\"ok\");\n\t\t\t\treturn { ok: true };\n\t\t\tcase \"resume\":\n\t\t\t\tthis.app.resumeFromPause();\n\t\t\t\trecord(\"ok\");\n\t\t\t\treturn { ok: true };\n\t\t\tcase \"stop\": {\n\t\t\t\tif (!this.app.stopHandler) return refuse(\"invalid\", \"this program declares no stop handler\");\n\t\t\t\t// a stop supersedes a pause: a program held at a touchpoint goes on to the safepoint where the handler runs\n\t\t\t\tthis.app.resumeFromPause();\n\t\t\t\t// at the next safepoint, on the thread that reaches it (5.5); the program is expected to exit\n\t\t\t\tconst handler = this.app.stopHandler;\n\t\t\t\tthis.atNextSafepoint(() => {\n\t\t\t\t\t// on the thread that reached the safepoint; a failing handler is the program's own matter, and the\n\t\t\t\t\t// launcher's window runs either way\n\t\t\t\t\ttry {\n\t\t\t\t\t\tPromise.resolve(handler()).catch(() => {});\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// same\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\trecord(\"ok\");\n\t\t\t\treturn { ok: true, data: { op, requested: true } };\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\treturn refuse(\"invalid\", `lifecycle ${op} is the launcher's, not the program's`);\n\t\t}\n\t}\n\n\tprivate settleTurn(id: string, outcome: AuditOutcome, cause?: string): void {\n\t\tconst pending = this.turns.get(id);\n\t\tif (!pending) return;\n\t\tthis.turns.delete(id);\n\t\tif (pending.timer) clearTimeout(pending.timer);\n\t\tthis.openTouchpoints -= 1;\n\t\tthis.audit.append({\n\t\t\tconn: pending.conn ?? this.connection,\n\t\t\tact: \"turn\",\n\t\t\tname: pending.request.name,\n\t\t\tid,\n\t\t\toutcome,\n\t\t\t...(cause === undefined ? {} : { cause }),\n\t\t\tms: this.app.now() - pending.startedAt,\n\t\t});\n\t\tpending.resolve();\n\t}\n\n\tendTouchpoint(id: string): void {\n\t\tconst pending = this.touchpoints.get(id);\n\t\tif (!pending) return;\n\t\tthis.touchpoints.delete(id);\n\t\tif (pending.timer) clearInterval(pending.timer);\n\t\tthis.openTouchpoints -= 1;\n\t\tpending.resolve();\n\t}\n\n\tdetach(reason: string): void {\n\t\tif (!this._attached) return;\n\t\tthis._attached = false;\n\t\tfor (const id of [...this.decisions.keys()])\n\t\t\tthis.settleDecision(id, { source: \"default\", cause: \"detached\", reason });\n\t\tfor (const id of [...this.turns.keys()]) this.settleTurn(id, \"default\", \"detached\");\n\t\tfor (const id of [...this.touchpoints.keys()]) this.endTouchpoint(id);\n\t\tthis.notify(\"detach\", reason);\n\t\tthis.app.clearHarness(reason);\n\t\tthis.audit.close();\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Program side (AttachedHarness)\n\t// -----------------------------------------------------------------------\n\n\tdecide(decision: DecisionDecl, context: Record<string, unknown>, deadline: number): Promise<unknown> {\n\t\tif (decision.policy === \"forbid\") {\n\t\t\tthis.audit.append({\n\t\t\t\tconn: this.connection,\n\t\t\t\tact: \"decision\",\n\t\t\t\tname: decision.name,\n\t\t\t\toutcome: \"default\",\n\t\t\t\tcause: \"forbidden\",\n\t\t\t});\n\t\t\treturn Promise.reject(new Error(\"forbidden\"));\n\t\t}\n\t\tconst id = `d${this.nextId++}`;\n\t\tconst request: DecisionRequest = { id, name: decision.name, decision, context, deadline };\n\t\treturn new Promise<unknown>((resolve, reject) => {\n\t\t\t// this timer bounds the program's own wait: it keeps the process alive until the answer or the default\n\t\t\tconst timer = setTimeout(\n\t\t\t\t() => this.settleDecision(id, { source: \"default\", cause: \"timeout\" }),\n\t\t\t\tMath.max(0, deadline - this.app.now()),\n\t\t\t);\n\t\t\tthis.decisions.set(id, { request, resolve, reject, timer, startedAt: this.app.now() });\n\t\t\tthis.openTouchpoints += 1;\n\t\t\tthis.notify(\"decision\", request);\n\t\t});\n\t}\n\n\tturn(turn: TurnDecl, deadline: number): Promise<void> {\n\t\tconst id = `t${this.nextId++}`;\n\t\tconst request: TurnRequest = { id, name: turn.name, turn, deadline, content: this.app.content.turn(turn.name) };\n\t\treturn new Promise<void>((resolve, reject) => {\n\t\t\tconst timer = setTimeout(\n\t\t\t\t() => this.settleTurn(id, \"default\", \"timeout\"),\n\t\t\t\tMath.max(0, deadline - this.app.now()),\n\t\t\t);\n\t\t\tthis.turns.set(id, { request, resolve, reject, timer, startedAt: this.app.now() });\n\t\t\tthis.openTouchpoints += 1;\n\t\t\tthis.notify(\"turn\", request);\n\t\t});\n\t}\n\n\t/** @internal A program-initiated `install` or `session`; resolves when the harness ends it or detaches. */\n\ttouchpoint(kind: TouchpointKind): Promise<void> {\n\t\tconst id = `p${this.nextId++}`;\n\t\tconst content = kind === \"install\" ? this.app.content.install() : this.app.content.use();\n\t\tconst request: TouchpointRequest = { id, kind, content };\n\t\treturn new Promise<void>((resolve, reject) => {\n\t\t\tconst timer = setInterval(() => {}, TOUCHPOINT_KEEPALIVE_MS);\n\t\t\tthis.touchpoints.set(id, { request, resolve, reject, timer, startedAt: this.app.now() });\n\t\t\tthis.openTouchpoints += 1;\n\t\t\tthis.notify(\"touchpoint\", request);\n\t\t});\n\t}\n\n\temitted(seq: number): void {\n\t\tconst read = this.app.region.readEvents(seq - 1);\n\t\tconst slot = read.slots.find((s) => s.seq === seq);\n\t\tif (slot) this.notify(\"event\", this.live(slot));\n\t}\n}\n"]}