@north-light/cli 0.3.487 → 0.3.489
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/contract.d.ts +1 -1
- package/dist/api/contract.js +1 -1
- package/dist/api/index.d.ts +2 -1
- package/dist/build-root.js +1 -1
- package/dist/builtin-memory/crouter-sdk/release-notes.md +17 -0
- package/dist/builtin-memory/crouter-sdk/resources.md +2 -1
- package/dist/builtin-memory/internal/memory-loading.md +1 -1
- package/dist/builtin-memory/northlight-apps/cli.md +20 -6
- package/dist/builtin-memory/northlight-apps/coding-agents.md +9 -7
- package/dist/builtin-memory/northlight-apps/guides/manage-your-app.md +1 -0
- package/dist/builtin-memory/northlight-apps/quickstart.md +5 -3
- package/dist/clients/attach/viewer.js +505 -505
- package/dist/commands/doc/shared.js +2 -2
- package/dist/commands/profile/project.js +1 -1
- package/dist/core/canvas/recovery.d.ts +5 -0
- package/dist/core/canvas/recovery.js +2 -2
- package/dist/core/command-plugins/endpoint.js +1 -1
- package/dist/core/graph/repo-sync/sync.d.ts +4 -3
- package/dist/core/graph/repo-sync/sync.js +2 -2
- package/dist/core/graph/spaces/repo.d.ts +7 -7
- package/dist/core/graph/spaces/repo.js +1 -1
- package/dist/core/graph/types.d.ts +3 -2
- package/dist/core/human/page-errors.d.ts +4 -0
- package/dist/core/human/page-errors.js +1 -1
- package/dist/core/human/page.d.ts +10 -3
- package/dist/core/human/page.js +1 -1
- package/dist/core/peer/ingest.js +1 -1
- package/dist/core/peer/stubs.d.ts +4 -0
- package/dist/core/peer/stubs.js +1 -1
- package/dist/core/peer/version.d.ts +2 -2
- package/dist/core/peer/version.js +1 -1
- package/dist/core/render.js +1 -2
- package/dist/core/runtime/revive.js +2 -2
- package/dist/daemon/api/handlers/docs.js +1 -1
- package/dist/daemon/api/handlers/human-requests.js +1 -1
- package/dist/launcher/accepted-socket.d.ts +11 -0
- package/dist/launcher/accepted-socket.js +1 -0
- package/dist/launcher/main.js +3 -3
- package/dist/launcher/validate.js +1 -1
- package/docs/apps/cli.md +20 -6
- package/docs/apps/coding-agents.md +9 -7
- package/docs/apps/guides/manage-your-app.md +1 -0
- package/docs/apps/quickstart.md +5 -3
- package/docs/ci-runner.md +2 -1
- package/docs/sdk/release-notes.md +17 -0
- package/docs/sdk/resources.md +2 -1
- package/package.json +3 -3
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +12 -12
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var f=Object.defineProperty;var o=(e,t)=>f(e,"name",{value:t,configurable:!0});import{usage as m}from"../../core/errors.js";import{ApiError as w}from"../../api/errors.js";import{rethrowAsCliError as h}from"../api-client.js";import{RULE_ON as g,RULE_DELIVER as v,DOC_KINDS as y}from"../../api/dto/docs.js";import{PRIVACY_LEVELS_DTO as b}from"../../api/dto/objects.js";const j="A document name (with or without [[ ]]) or a raw object id.",p="node | user | profile | profile:<name> | app | repo | repo:<handle>";function O(e){return{kind:"flag",name:"owner",type:"string",required:!1,constraint:e,focusedHelp:{whenToUse:"Omit it for a document only this node and the nodes it points at need: the writing node owns it and it is deleted with the node, unless a kept document links to it. Give another owner when the document must outlive this node or reach other nodes by itself. A document worth another owner carries reusable current truth: a non-obvious procedure, a gotcha, a lasting preference, a convention across repos. Task notes, conversation summaries and facts the repo already records stay with the node or are not written. Before writing one, search for a document that already covers it (`crtr canvas search`) and revise that one with `crtr doc edit` instead of adding a near copy. When one document grows long, keep the most important content in it and move separate subjects into documents named under it (`topic/part`), each pointed at with a `[[link]]`. Choose the narrowest owner that still reaches the next agent who needs it.",value:`One of ${p}. \`node\` \u2014 the writing node; only this node loads it by rule, other nodes read it when pointed at it; deleted with the node. \`profile\` \u2014 the node's profile, or \`profile:<name>\`; loads for nodes running in that profile; stays on this runtime. \`app\` \u2014 the app that runs the node; kept until deleted; readable by that app's nodes. \`repo\` \u2014 the repo the node works in (from its working directory), or \`repo:<handle>\`; every clone and worktree of the repo shares it, and it syncs to collaborators over the repo's \`refs/crtr/docs\`. A repo owns only public documents: a private or friends document that should load in one repo is owned by \`user\` and carries a rule with \`if: {"repo": "<handle>"}\`. \`user\` \u2014 you, the person; loads for every node by its rules; readable by apps by privacy level. Default: the writing node; a person's own run (not a node) defaults to \`user\`. The owner becomes the start of the document's full name (\`<owner-handle>/<name>\`); \`crtr doc move --owner\` changes it later and keeps the id and every link.`,effects:["Decides who may read and change the document, where it syncs, and what deleting takes it with."]}}}o(O,"ownerParam");const k="`if` is a condition on the receiving node. Fields: `kind`, `mode`, `lifecycle`, `cwd`, `repo` (the handle of a repo the node is eligible for: those enclosing its cwd and those of its profile's projects; use `cwd` for where it works), `profile`, `depth`. A field map is ANDed across fields; dotted fields resolve nested values. A scalar matches by equality (a list value matches when any element is equal); a list matcher matches by membership or overlap; an object matcher takes `eq`, `ne`, `in`, `nin`, `exists`, `contains`, `containsAll`, `containsAny`, `matches`, `imatches`, `gt`, `gte`, `lt`, `lte`. `all`, `any` and `not` combine conditions; field matchers beside them are ANDed in. An empty condition always matches; an unknown operator never matches. `match_frontmatter` uses the same language against the read file's YAML frontmatter.";function S(e){return{kind:"flag",name:"rule",type:"string",required:!1,repeatable:!0,constraint:e,focusedHelp:{whenToUse:"Omit it for most documents: a document with no rule is read when a node is pointed at it (`[[name]]`), finds it with `crtr canvas search`, or sees it in a listing. Add a rule only when the document must load on its own because of what a node is doing; every rule costs context in every node it fires on. Prefer the narrowest trigger: a `file-read` rule with a real glob over `boot` for knowledge about specific code; `boot` for knowledge about a person or process with no file boundary. When the whole document is one sentence, deliver `content` \u2014 a preview line would be longer than the document.",value:`One JSON object per occurrence: \`{"on": \u2026, "match"?: [globs], "match_frontmatter"?: {\u2026}, "if"?: {\u2026}, "deliver": \u2026}\`. \`on\` is the node's activity: ${g.join(" | ")}. \`boot\` \u2014 every session start of the node. \`workspace-open\` \u2014 the node's first message when it works in the document's repo. \`file-read\` \u2014 the node reads the content of a file whose absolute path or basename matches a \`match\` glob, or whose frontmatter matches \`match_frontmatter\`; through the Read tool, or a bash segment of \`cat\`, \`sed\` (not \`-i\`), \`head\`, \`tail\` (not \`-f\`), \`nl\` or \`awk\` on a literal path (resolved after the command's own \`cd\`s; \`rg\`, \`grep\`, \`find\`, \`ls\`, \`wc\`, \`stat\` are searches, not reads, and never fire it). \`document-read\` \u2014 another document whose name matches is delivered at content, including an explicit read. \`command\` \u2014 a shell segment of a bash command matches (segments split on \`&&\`, \`||\`, \`;\`, \`|\` and newlines outside quotes, leading \`VAR=value\` dropped; \`*\` spans whole whitespace-separated tokens, \`?\` one character, quoted text is opaque). \`pre-command\` \u2014 as \`command\`, but runs before the command: when the node has not read the document, the command does not run and the document is returned instead; the node re-issues the command. \`slash-command\` \u2014 the document is a \`/<name>\` slash command whose body is the injected prompt. \`match\` is required on \`file-read\` (unless \`match_frontmatter\` is given), \`document-read\`, \`command\` and \`pre-command\`, and not allowed on \`boot\`, \`workspace-open\` and \`slash-command\`. `+k+` \`deliver\` is ${v.join(" | ")}: the bare name, the preview line, or the whole body. The flag set replaces the document's whole rule list; on \`crtr doc edit\`, \`--unset rules\` removes every rule.`,effects:["When several rules deliver one document to a node, the highest delivery wins: content over preview over name; content already in the node's context is not delivered again.","A document delivered at content is a read: it records the node as a watcher, so the node is pushed later edits.","The profile's delivery limit per owner caps what `boot` and `workspace-open` rules deliver for that owner.",'A rule that delivers at `preview` requires the preview in the shape "When <situation in the reader\'s work>, read this because <what the reader gains>"; `crtr doc lint` checks it. There the line alone decides whether a node that did not ask for the document opens it.']}}}o(S,"ruleParam");const N={preview:o(e=>({kind:"flag",name:"preview",type:"string",required:!1,constraint:e}),"preview"),kind:{kind:"flag",name:"kind",type:"enum",choices:[...y],required:!1,constraint:"knowledge is consulted for facts or procedures; preference directs behavior. Default knowledge."},summary:{kind:"flag",name:"summary",type:"string",required:!1,constraint:"A very short version of the content, shown in `crtr canvas list`."},privacy:o(e=>({kind:"flag",name:"privacy",type:"enum",choices:[...b],required:!1,constraint:e}),"privacy"),whyItExists:{kind:"flag",name:"why-it-exists",type:"string",required:!1,constraint:"The observed failure this document exists to prevent; shown only with `crtr canvas read --fields`."},unlisted:o(e=>({kind:"flag",name:"unlisted",type:"bool",required:!1,constraint:e}),"unlisted"),lintIgnore:{kind:"flag",name:"lint-ignore",type:"string",required:!1,repeatable:!0,constraint:"A `crtr doc lint` rule name to skip for this document."},extension:{kind:"flag",name:"extension",type:"string",required:!1,repeatable:!0,constraint:"One declared plugin field as `<plugin>.<field>=<json value>`."}};function c(e){return e===void 0?[]:Array.isArray(e)?e.map(String):[String(e)]}o(c,"list");function T(e){const t=[],n={};for(const[r,a]of[["preview","preview"],["kind","kind"],["summary","summary"],["privacy","privacy"],["whyItExists","why_it_exists"]])typeof e[r]=="string"&&(n[a]=e[r]);typeof n.preview=="string"&&/[\r\n]/.test(n.preview)&&t.push("--preview must be one line"),e.unlisted===!0&&(n.unlisted=!0);const i=c(e.lintIgnore);i.length>0&&(n.lint_ignore=i);const s=c(e.rule);if(s.length>0){const r=[];s.forEach((a,u)=>{try{const d=JSON.parse(a);typeof d!="object"||d===null||Array.isArray(d)?t.push(`--rule #${u+1} must be a JSON object`):r.push(d)}catch{t.push(`--rule #${u+1} is not valid JSON: ${a}`)}}),n.rules=r}const l={};for(const r of c(e.extension)){const a=/^([^.=]+)\.([^=]+)=(.*)$/s.exec(r);if(!a){t.push(`--extension ${r} is not <plugin>.<field>=<json value>`);continue}try{(l[a[1]]??={})[a[2]]=JSON.parse(a[3])}catch{t.push(`--extension ${r}: the value after = is not valid JSON`)}}if(Object.keys(l).length>0&&(n.extensions=l),t.length>0)throw m(t.join("; "),{next:"Fix every value above and rerun; `--rule -h` gives the rule grammar."});return n}o(T,"fieldsFromInput");function R(e){const t=e.owner;if(t===void 0)return{};const n=String(t);if(!/^(node|user|profile|app|repo)$|^(profile|repo):.+$/.test(n))throw m(`invalid --owner ${n}`,{field:"owner",next:`Pass one of ${p}.`});return{owner:n}}o(R,"ownerFromInput");function D(e,t){e instanceof w&&(e.code==="read_first"&&h(e,`Read it first with \`crtr canvas read ${t}\`, then rerun the edit.`),e.code==="stale_revision"&&h(e,`Someone edited it after your read. Read it again with \`crtr canvas read ${t}\`, make your change on the current text, and rerun the edit.`)),h(e)}o(D,"rethrowDocError");function I(e){const t=[],n=e.unresolved_links,i=e.remote_links;return n?.length&&t.push(`Unresolved links (no document by these names yet): ${n.map(s=>`[[${s}]]`).join(", ")}`),i?.length&&t.push(`Not on this runtime: ${i.map(s=>`[[${s}]]`).join(", ")} \u2014 each may be on another runtime, or the name may be misspelled.`),t.map(s=>`
|
|
2
|
-
${s}`).join("")}o(I,"renderLinkReport");export{N as FIELD_FLAGS,p as OWNER_VALUES,
|
|
1
|
+
var f=Object.defineProperty;var o=(e,t)=>f(e,"name",{value:t,configurable:!0});import{usage as m}from"../../core/errors.js";import{ApiError as w}from"../../api/errors.js";import{rethrowAsCliError as h}from"../api-client.js";import{RULE_ON as g,RULE_DELIVER as v,DOC_KINDS as y}from"../../api/dto/docs.js";import{PRIVACY_LEVELS_DTO as b}from"../../api/dto/objects.js";const q="A document name (with or without [[ ]]) or a raw object id.",p="node | user | profile | profile:<name> | app | repo | repo:<handle>";function O(e){return{kind:"flag",name:"owner",type:"string",required:!1,constraint:e,focusedHelp:{whenToUse:"Omit it for a document only this node and the nodes it points at need: the writing node owns it and it is deleted with the node, unless a kept document links to it. Give another owner when the document must outlive this node or reach other nodes by itself. A document worth another owner carries reusable current truth: a non-obvious procedure, a gotcha, a lasting preference, a convention across repos. Task notes, conversation summaries and facts the repo already records stay with the node or are not written. Before writing one, search for a document that already covers it (`crtr canvas search`) and revise that one with `crtr doc edit` instead of adding a near copy. When one document grows long, keep the most important content in it and move separate subjects into documents named under it (`topic/part`), each pointed at with a `[[link]]`. Choose the narrowest owner that still reaches the next agent who needs it.",value:`One of ${p}. \`node\` \u2014 the writing node; only this node loads it by rule, other nodes read it when pointed at it; deleted with the node. \`profile\` \u2014 the node's profile, or \`profile:<name>\`; loads for nodes running in that profile; stays on this runtime. \`app\` \u2014 the app that runs the node; kept until deleted; readable by that app's nodes. \`repo\` \u2014 the repo the node works in (from its working directory), or \`repo:<handle>\` for another repo whose checkout the node's file permissions let it write (such as a project of its profile); every clone and worktree of the repo shares it, and it syncs to collaborators over the repo's \`refs/crtr/docs\`. A repo owns only public documents: a private or friends document that should load in one repo is owned by \`user\` and carries a rule with \`if: {"repo": "<handle>"}\`. \`user\` \u2014 you, the person; loads for every node by its rules; readable by apps by privacy level. Default: the writing node; a person's own run (not a node) defaults to \`user\`. The owner becomes the start of the document's full name (\`<owner-handle>/<name>\`); \`crtr doc move --owner\` changes it later and keeps the id and every link.`,effects:["Decides who may read and change the document, where it syncs, and what deleting takes it with."]}}}o(O,"ownerParam");const k="`if` is a condition on the receiving node. Fields: `kind`, `mode`, `lifecycle`, `cwd`, `repo` (the handle of a repo the node is eligible for: those enclosing its cwd and those of its profile's projects; use `cwd` for where it works), `profile`, `depth`. A field map is ANDed across fields; dotted fields resolve nested values. A scalar matches by equality (a list value matches when any element is equal); a list matcher matches by membership or overlap; an object matcher takes `eq`, `ne`, `in`, `nin`, `exists`, `contains`, `containsAll`, `containsAny`, `matches`, `imatches`, `gt`, `gte`, `lt`, `lte`. `all`, `any` and `not` combine conditions; field matchers beside them are ANDed in. An empty condition always matches; an unknown operator never matches. `match_frontmatter` uses the same language against the read file's YAML frontmatter.";function S(e){return{kind:"flag",name:"rule",type:"string",required:!1,repeatable:!0,constraint:e,focusedHelp:{whenToUse:"Omit it for most documents: a document with no rule is read when a node is pointed at it (`[[name]]`), finds it with `crtr canvas search`, or sees it in a listing. Add a rule only when the document must load on its own because of what a node is doing; every rule costs context in every node it fires on. Prefer the narrowest trigger: a `file-read` rule with a real glob over `boot` for knowledge about specific code; `boot` for knowledge about a person or process with no file boundary. When the whole document is one sentence, deliver `content` \u2014 a preview line would be longer than the document.",value:`One JSON object per occurrence: \`{"on": \u2026, "match"?: [globs], "match_frontmatter"?: {\u2026}, "if"?: {\u2026}, "deliver": \u2026}\`. \`on\` is the node's activity: ${g.join(" | ")}. \`boot\` \u2014 every session start of the node. \`workspace-open\` \u2014 the node's first message when it works in the document's repo. \`file-read\` \u2014 the node reads the content of a file whose absolute path or basename matches a \`match\` glob, or whose frontmatter matches \`match_frontmatter\`; through the Read tool, or a bash segment of \`cat\`, \`sed\` (not \`-i\`), \`head\`, \`tail\` (not \`-f\`), \`nl\` or \`awk\` on a literal path (resolved after the command's own \`cd\`s; \`rg\`, \`grep\`, \`find\`, \`ls\`, \`wc\`, \`stat\` are searches, not reads, and never fire it). \`document-read\` \u2014 another document whose name matches is delivered at content, including an explicit read. \`command\` \u2014 a shell segment of a bash command matches (segments split on \`&&\`, \`||\`, \`;\`, \`|\` and newlines outside quotes, leading \`VAR=value\` dropped; \`*\` spans whole whitespace-separated tokens, \`?\` one character, quoted text is opaque). \`pre-command\` \u2014 as \`command\`, but runs before the command: when the node has not read the document, the command does not run and the document is returned instead; the node re-issues the command. \`slash-command\` \u2014 the document is a \`/<name>\` slash command whose body is the injected prompt. \`match\` is required on \`file-read\` (unless \`match_frontmatter\` is given), \`document-read\`, \`command\` and \`pre-command\`, and not allowed on \`boot\`, \`workspace-open\` and \`slash-command\`. `+k+` \`deliver\` is ${v.join(" | ")}: the bare name, the preview line, or the whole body. The flag set replaces the document's whole rule list; on \`crtr doc edit\`, \`--unset rules\` removes every rule.`,effects:["When several rules deliver one document to a node, the highest delivery wins: content over preview over name; content already in the node's context is not delivered again.","A document delivered at content is a read: it records the node as a watcher, so the node is pushed later edits.","The profile's delivery limit per owner caps what `boot` and `workspace-open` rules deliver for that owner.",'A rule that delivers at `preview` requires the preview in the shape "When <situation in the reader\'s work>, read this because <what the reader gains>"; `crtr doc lint` checks it. There the line alone decides whether a node that did not ask for the document opens it.']}}}o(S,"ruleParam");const N={preview:o(e=>({kind:"flag",name:"preview",type:"string",required:!1,constraint:e}),"preview"),kind:{kind:"flag",name:"kind",type:"enum",choices:[...y],required:!1,constraint:"knowledge is consulted for facts or procedures; preference directs behavior. Default knowledge."},summary:{kind:"flag",name:"summary",type:"string",required:!1,constraint:"A very short version of the content, shown in `crtr canvas list`."},privacy:o(e=>({kind:"flag",name:"privacy",type:"enum",choices:[...b],required:!1,constraint:e}),"privacy"),whyItExists:{kind:"flag",name:"why-it-exists",type:"string",required:!1,constraint:"The observed failure this document exists to prevent; shown only with `crtr canvas read --fields`."},unlisted:o(e=>({kind:"flag",name:"unlisted",type:"bool",required:!1,constraint:e}),"unlisted"),lintIgnore:{kind:"flag",name:"lint-ignore",type:"string",required:!1,repeatable:!0,constraint:"A `crtr doc lint` rule name to skip for this document."},extension:{kind:"flag",name:"extension",type:"string",required:!1,repeatable:!0,constraint:"One declared plugin field as `<plugin>.<field>=<json value>`."}};function c(e){return e===void 0?[]:Array.isArray(e)?e.map(String):[String(e)]}o(c,"list");function T(e){const t=[],n={};for(const[r,a]of[["preview","preview"],["kind","kind"],["summary","summary"],["privacy","privacy"],["whyItExists","why_it_exists"]])typeof e[r]=="string"&&(n[a]=e[r]);typeof n.preview=="string"&&/[\r\n]/.test(n.preview)&&t.push("--preview must be one line"),e.unlisted===!0&&(n.unlisted=!0);const i=c(e.lintIgnore);i.length>0&&(n.lint_ignore=i);const s=c(e.rule);if(s.length>0){const r=[];s.forEach((a,u)=>{try{const d=JSON.parse(a);typeof d!="object"||d===null||Array.isArray(d)?t.push(`--rule #${u+1} must be a JSON object`):r.push(d)}catch{t.push(`--rule #${u+1} is not valid JSON: ${a}`)}}),n.rules=r}const l={};for(const r of c(e.extension)){const a=/^([^.=]+)\.([^=]+)=(.*)$/s.exec(r);if(!a){t.push(`--extension ${r} is not <plugin>.<field>=<json value>`);continue}try{(l[a[1]]??={})[a[2]]=JSON.parse(a[3])}catch{t.push(`--extension ${r}: the value after = is not valid JSON`)}}if(Object.keys(l).length>0&&(n.extensions=l),t.length>0)throw m(t.join("; "),{next:"Fix every value above and rerun; `--rule -h` gives the rule grammar."});return n}o(T,"fieldsFromInput");function R(e){const t=e.owner;if(t===void 0)return{};const n=String(t);if(!/^(node|user|profile|app|repo)$|^(profile|repo):.+$/.test(n))throw m(`invalid --owner ${n}`,{field:"owner",next:`Pass one of ${p}.`});return{owner:n}}o(R,"ownerFromInput");function D(e,t){e instanceof w&&(e.code==="read_first"&&h(e,`Read it first with \`crtr canvas read ${t}\`, then rerun the edit.`),e.code==="stale_revision"&&h(e,`Someone edited it after your read. Read it again with \`crtr canvas read ${t}\`, make your change on the current text, and rerun the edit.`)),h(e)}o(D,"rethrowDocError");function I(e){const t=[],n=e.unresolved_links,i=e.remote_links;return n?.length&&t.push(`Unresolved links (no document by these names yet): ${n.map(s=>`[[${s}]]`).join(", ")}`),i?.length&&t.push(`Not on this runtime: ${i.map(s=>`[[${s}]]`).join(", ")} \u2014 each may be on another runtime, or the name may be misspelled.`),t.map(s=>`
|
|
2
|
+
${s}`).join("")}o(I,"renderLinkReport");export{N as FIELD_FLAGS,p as OWNER_VALUES,q as REF_CONSTRAINT,T as fieldsFromInput,R as ownerFromInput,O as ownerParam,I as renderLinkReport,D as rethrowDocError,S as ruleParam};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var p=Object.defineProperty;var t=(e,o)=>p(e,"name",{value:o,configurable:!0});import{defineLeaf as i,defineBranch as d}from"../../core/command.js";import{resolve as s}from"node:path";import{cliClient as
|
|
1
|
+
var p=Object.defineProperty;var t=(e,o)=>p(e,"name",{value:o,configurable:!0});import{defineLeaf as i,defineBranch as d}from"../../core/command.js";import{resolve as s}from"node:path";import{cliClient as n}from"../api-client.js";import{resolveProfileViaDaemon as a}from"./daemon-profiles.js";import{PROFILE_PROJECT_MEMORY_VALUES as l}from"../../api/dto/profiles.js";const c=i({name:"add",description:"add a project to a profile's purview",whenToUse:"a profile needs purview over another project directory \u2014 extend it after creation.",help:{name:"profile project add",summary:"add a project relationship to a profile, deduped by real path",params:[{kind:"positional",name:"profile",required:!0,constraint:"Profile id or manifest name; a close-enough name resolves to the nearest profile, reported on stderr."},{kind:"flag",name:"dir",type:"path",required:!0,constraint:"Directory to add. Must exist and be a directory; resolved to its absolute real path before storing. A path already on the profile keeps its position and nothing changes."}],output:[{name:"profile_id",type:"string",required:!0,constraint:"Stable directory id."},{name:"projects",type:"ProfileProject[]",required:!0,constraint:"The updated `{path}` relationships in profile order. `path` defines purview."}],outputKind:"object",effects:["Appends a new project relationship to the profile row. Purview follows `path` for config, and every repo enclosing `path` joins the view of every node of the profile: its documents are readable, listed, and delivered at boot and workspace-open. Each such repo starts at a `preview` delivery limit unless the profile already limits that handle (change it with `profile project limit`). Running brokers discover the updated projects on their next scope read."]},run:t(async e=>{const{id:o}=await a(e.profile),r=await n().updateProfile(o,{add_project:{path:s(e.dir)}});return{profile_id:r.id,projects:r.projects}},"run")}),h=i({name:"remove",description:"remove a project relationship from a profile's purview",whenToUse:"a profile no longer needs purview over one of its listed project directories \u2014 narrow it back. Works even if the directory itself was since deleted.",help:{name:"profile project remove",summary:"remove a project directory from a profile's manifest",params:[{kind:"positional",name:"profile",required:!0,constraint:"Profile id or manifest name; a close-enough name resolves to the nearest profile, reported on stderr."},{kind:"flag",name:"dir",type:"path",required:!0,constraint:"Directory to remove, matched against the stored project `path`. Does not require the directory to still exist on disk. The profile's app home does not change."}],output:[{name:"profile_id",type:"string",required:!0,constraint:"Stable directory id."},{name:"projects",type:"ProfileProject[]",required:!0,constraint:"The updated `{path}` relationships in profile order."}],outputKind:"object",effects:["Removes a project relationship from the profile row. This narrows purview and drops the path's repos from the view of the profile's nodes (unless a node's cwd is inside them); delivery limits are left in place. Running brokers discover the updated projects on their next scope read."]},run:t(async e=>{const{id:o}=await a(e.profile),r=await n().updateProfile(o,{remove_project:s(e.dir)});return{profile_id:r.id,projects:r.projects}},"run")}),m=i({name:"limit",description:"set how much of one owner's documents automatic delivery may disclose",whenToUse:"a profile's nodes should get less of one owner's documents (a repo, `user`, an app, a plugin) at boot and workspace-open \u2014 or that limit should be lifted.",help:{name:"profile project limit",summary:"set a profile's automatic delivery limit for one owner handle",params:[{kind:"positional",name:"profile",required:!0,constraint:"Profile id or manifest name; a close-enough name resolves to the nearest profile, reported on stderr."},{kind:"flag",name:"owner",type:"string",required:!0,constraint:"Owner the limit applies to. A bare handle (`crouter`, `user`) matches an owner of any type holding that handle. `<type>:<handle>` names one owner exactly \u2014 `repo:crouter`, `profile:work`, `app:terminal`, `person:user` \u2014 and wins over a bare key; use it when a repo and another owner share a handle. A profile's own documents are never capped, whichever key matches."},{kind:"flag",name:"level",type:"enum",choices:[...l],required:!0,constraint:"Maximum automatic delivery of this owner's documents at boot and workspace-open: `none`, `name`, `preview`, or `content`. `content` is no limit and removes the entry. Does not change explicit `crtr canvas read` access."}],output:[{name:"profile_id",type:"string",required:!0,constraint:"Stable directory id."},{name:"delivery_limits",type:"object",required:!0,constraint:"The profile\u2019s limits after the change, keyed by owner handle or `<type>:<handle>`; an owner not listed is not limited."}],outputKind:"object",effects:["Sets or removes one entry in the profile's `delivery_limits`. It caps only automatic `boot` and `workspace-open` delivery; a node's own documents and its own profile's documents are never capped. A `<type>:<handle>` key (for example `repo:crouter`) names one owner exactly and wins over a bare handle key."]},run:t(async e=>{const{id:o}=await a(e.profile),r=await n().updateProfile(o,{set_delivery_limit:{owner:e.owner,level:e.level}});return{profile_id:r.id,delivery_limits:r.delivery_limits}},"run")}),g=d({name:"project",description:"manage a profile's project purview and automatic delivery limits",whenToUse:"changing a profile\u2019s project purview after creation, or limiting how much of one owner's documents its nodes get automatically.",help:{name:"profile project",summary:"manage project purview and per-owner automatic delivery limits",model:"Each `{path}` relationship widens purview: the profile resolves config from `path`, and every node of the profile sees the repos enclosing `path` in addition to the repos enclosing its own cwd (cwd repos first, then projects in manifest order). Rule `if: {repo}` conditions hold for any of those repos (cwd repos and project repos); `--owner repo` stays with the cwd's repos, while a node may change a project repo's documents when its file permissions allow writing that checkout. `add` appends a new real path and starts its repos at a `preview` limit; `remove` narrows purview. `limit` sets the profile's `delivery_limits` entry for one owner handle, which caps automatic boot and workspace-open delivery of that owner's documents, whether the repo is in view through the cwd or the project list; explicit reads are not capped. Purview and delivery limits are both independent of a per-cwd default pin (`crtr profile default`)."},children:[c,h,m]});export{g as projectBranch};
|
|
@@ -47,6 +47,11 @@ export declare function readInterruptedTurn(nodeId: string): {
|
|
|
47
47
|
interrupted: boolean;
|
|
48
48
|
progressAt: string | null;
|
|
49
49
|
} | null;
|
|
50
|
+
/** Whether any execution of this node ever admitted a turn (agent_start recorded
|
|
51
|
+
* by the daemon). This, not the transcript, is the durable fact that a node's
|
|
52
|
+
* birth task was delivered: a session file holding only the bearings message
|
|
53
|
+
* exists before the kickoff is admitted. */
|
|
54
|
+
export declare function hasAdmittedTurn(nodeId: string): boolean;
|
|
50
55
|
export declare function recordFault(nodeId: string, input: FaultRecordInput): StoredFault | null;
|
|
51
56
|
export declare function clearFault(nodeId: string, opts?: {
|
|
52
57
|
link?: FaultLink;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var re=Object.defineProperty;var o=(e,n)=>re(e,"name",{value:n,configurable:!0});import{prepared as s}from"../sqlite-statements.js";import{randomUUID as b}from"node:crypto";import{existsSync as p,readdirSync as ie,readFileSync as oe,realpathSync as se,statSync as de}from"node:fs";import{join as N,resolve as ae}from"node:path";import{openDb as
|
|
1
|
+
var re=Object.defineProperty;var o=(e,n)=>re(e,"name",{value:n,configurable:!0});import{prepared as s}from"../sqlite-statements.js";import{randomUUID as b}from"node:crypto";import{existsSync as p,readdirSync as ie,readFileSync as oe,realpathSync as se,statSync as de}from"node:fs";import{join as N,resolve as ae}from"node:path";import{openDb as E,prepared as ue,withCanvasWrite as l}from"./db.js";import{jobDir as ce,nodesRoot as C}from"./paths.js";import{errorClassFromFault as w}from"../fault-classifier.js";import{parseProviderRateLimit as _e}from"../provider-failure.js";import{emitEvent as X}from"../events/emit.js";import{operationIdContext as j,validateOperationId as $}from"../events/operation-id.js";const We=5*6e4,le=500,B=["pi\u2192provider","viewer\u2194broker","relay\u2194broker","viewer\u2194crtrd","daemon\u2192node","crtr\u2192pi"],pe=[...B,"broker\u2194crtrd"],Ee=["rate-limit","overloaded","connection","auth","protocol","context-overflow","other","wedged","model-not-found"],fe=["auto","manual","fatal"],ye=["sdk","daemon","client"],Te=["pending","admitted","invalidated"];function c(){return new Date().toISOString()}o(c,"now");function J(e,n){return new Set(e.prepare(`PRAGMA table_info(${n})`).all().map(({name:t})=>t))}o(J,"tableColumns");function Ne(e){const n=J(e,"executions"),t=[["turn_open_at","TEXT"],["turn_progress_at","TEXT"],["turn_closed_at","TEXT"],["turn_end_reason","TEXT CHECK (turn_end_reason IS NULL OR turn_end_reason IN ('settled', 'teardown-aborted'))"],["exit_diagnostic_json","TEXT"]];for(const[r,i]of t)n.has(r)||e.exec(`ALTER TABLE executions ADD COLUMN ${r} ${i}`)}o(Ne,"addExecutionColumns");function ge(e){e.exec(`
|
|
2
2
|
CREATE TABLE IF NOT EXISTS node_faults (
|
|
3
3
|
fault_id TEXT PRIMARY KEY,
|
|
4
4
|
node_id TEXT NOT NULL REFERENCES nodes(node_id) ON DELETE CASCADE,
|
|
@@ -23,4 +23,4 @@ CREATE TABLE IF NOT EXISTS node_faults (
|
|
|
23
23
|
);
|
|
24
24
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_node_faults_active ON node_faults(node_id) WHERE active = 1;
|
|
25
25
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_node_faults_episode ON node_faults(node_id) WHERE episode_state IS NOT NULL;
|
|
26
|
-
`)}o(ge,"createFaultTable");function g(e,n){return typeof n=="string"&&e.includes(n)}o(g,"contains");function F(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}o(F,"isRecord");function K(e){if(!F(e)||typeof e.provider!="string"||e.provider===""||typeof e.model!="string"||e.model==="")return;const n=typeof e.status=="number"&&Number.isFinite(e.status)?e.status:void 0,t=typeof e.code=="string"||typeof e.code=="number"?e.code:void 0,r=typeof e.errno=="string"?e.errno:void 0,i=typeof e.body=="string"?e.body:void 0,d=_e(e.ratelimit),a=Array.isArray(e.causes)?e.causes.flatMap(u=>{if(!F(u))return[];const E={...typeof u.message=="string"?{message:u.message}:{},...typeof u.status=="number"&&Number.isFinite(u.status)?{status:u.status}:{},...typeof u.code=="string"||typeof u.code=="number"?{code:u.code}:{},...typeof u.errno=="string"?{errno:u.errno}:{},...typeof u.body=="string"?{body:u.body}:{}};return Object.keys(E).length===0?[]:[E]}):void 0;return{provider:e.provider,model:e.model,...n===void 0?{}:{status:n},...t===void 0?{}:{code:t},...r===void 0?{}:{errno:r},...i===void 0?{}:{body:i},...a===void 0||a.length===0?{}:{causes:a},...d===void 0?{}:{ratelimit:d}}}o(K,"parseProviderError");function Y(e){try{const n=JSON.parse(e);if(!g(pe,n.link)||typeof n.op!="string"||n.op===""||!g(Ee,n.kind)||typeof n.message!="string"||typeof n.since!="string")return null;const t=$(n.operation_id);if(!F(n.retry)||!g(fe,n.retry.disposition)||n.retry.by!==void 0&&!g(ye,n.retry.by)||n.retry.attempt!==void 0&&typeof n.retry.attempt!="number"||n.retry.max!==void 0&&typeof n.retry.max!="number"||n.retry.nextAt!==void 0&&typeof n.retry.nextAt!="string"||n.anchorEntryId!==void 0&&(typeof n.anchorEntryId!="string"||n.anchorEntryId===""))return null;const r=n.providerError===void 0?void 0:K(n.providerError);return n.providerError!==void 0&&r===void 0?null:{link:n.link,op:n.op,kind:n.kind,retry:{disposition:n.retry.disposition,...n.retry.by===void 0?{}:{by:n.retry.by},...n.retry.attempt===void 0?{}:{attempt:n.retry.attempt},...n.retry.max===void 0?{}:{max:n.retry.max},...n.retry.nextAt===void 0?{}:{nextAt:n.retry.nextAt}},message:n.message,since:n.since,operation_id:t,...n.anchorEntryId===void 0?{}:{anchorEntryId:n.anchorEntryId},...r===void 0?{}:{providerError:r}}}catch{return null}}o(Y,"parseLegacyFault");function Le(e){const n=ae(e);try{return se(n)}catch{return n}}o(Le,"canonicalPath");function me(e){try{const n=JSON.parse(e);if(!g(Te,n.state)||typeof n.sessionFile!="string"||n.sessionFile==="")return null;const t=JSON.stringify(n.fault),r=Y(t);if(r===null||r.link!=="pi\u2192provider"||r.retry.disposition!=="auto"||r.retry.by!=="daemon")return null;const i=n.anchorEntryId;return i!==null&&typeof i!="string"||(r.anchorEntryId??null)!==i?null:{state:n.state,sessionFile:Le(n.sessionFile),fault:r}}catch{return null}}o(me,"parseLegacyEpisode");function G(e){return e!==void 0?$(e):j.current()??j.fresh(t=>t)}o(G,"resolveOperationId");function Ae(e){return e.slice(0,le)}o(Ae,"clampMessage");function R(e){return e.link==="pi\u2192provider"&&e.retry.disposition==="auto"&&e.retry.by==="daemon"?3:e.retry.disposition==="fatal"?2:1}o(R,"faultPriority");function V(e){return{link:e.link,op:e.op,kind:e.kind,message:e.message,since:e.since,operationId:e.operation_id,anchorEntryId:e.anchorEntryId??null,retryDisposition:e.retry.disposition,retryBy:e.retry.by??null,retryAttempt:e.retry.attempt??null,retryMax:e.retry.max??null,retryNextAt:e.retry.nextAt??null,providerError:e.providerError===void 0?null:JSON.stringify(e.providerError)}}o(V,"encodeFault");function H(e){const n=e.provider_error_json,t=typeof n=="string"?K(JSON.parse(n)):void 0;if(typeof n=="string"&&t===void 0)throw new Error(`invalid provider error on stored fault ${e.fault_id}`);const r={disposition:e.retry_disposition,...e.retry_by===null?{}:{by:e.retry_by},...e.retry_attempt===null?{}:{attempt:e.retry_attempt},...e.retry_max===null?{}:{max:e.retry_max},...e.retry_next_at===null?{}:{nextAt:e.retry_next_at}};return{faultId:e.fault_id,link:e.link,op:e.op,kind:e.kind,message:e.message,since:e.since,operation_id:e.operation_id,retry:r,...e.anchor_entry_id===null?{}:{anchorEntryId:e.anchor_entry_id},...t===void 0?{}:{providerError:t}}}o(H,"hydrateFault");function L(e,n){const t=ue(e,"SELECT * FROM node_faults WHERE node_id = ? AND active = 1").get(n);return t===void 0?null:H(t)}o(L,"activeFault");function Q(e){if(!g(B,e.link))throw new Error(`fault link is not durable: ${e.link}`);return{link:e.link,op:e.op,kind:e.kind,retry:e.retry,message:Ae(e.message),since:e.since??c(),operation_id:G(e.operation_id),...typeof e.anchorEntryId=="string"&&e.anchorEntryId!==""?{anchorEntryId:e.anchorEntryId}:{},...e.providerError===void 0?{}:{providerError:e.providerError}}}o(Q,"storedFault");function q(e,n){X({level:n.retry.disposition==="fatal"?"error":"warn",event:"fault.recorded",operation_id:n.operation_id,node_id:e,error_class:M(n),fields:{link:n.link,op:n.op,kind:n.kind,retry:n.retry,message:n.message,...n.anchorEntryId===void 0?{}:{anchor_entry_id:n.anchorEntryId},...n.providerError===void 0?{}:{provider_error:n.providerError}}})}o(q,"emitRecordedFault");function W(e,n,t,r,i){const d=b(),a=V(t),u=c();return s(e,"INSERT INTO node_faults (fault_id, node_id, link, op, kind, message, since, operation_id, anchor_entry_id, retry_disposition, retry_by, retry_attempt, retry_max, retry_next_at, provider_error_json, active, episode_state, episode_binding_id, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)").run(d,n,a.link,a.op,a.kind,a.message,a.since,a.operationId,a.anchorEntryId,a.retryDisposition,a.retryBy,a.retryAttempt,a.retryMax,a.retryNextAt,a.providerError,r?1:0,i?.state??null,i?.bindingId??null,u,u),{...t,faultId:d}}o(W,"insertFault");function z(e,n,t,r){const i=V(t);return s(e,"UPDATE node_faults SET link = ?, op = ?, kind = ?, message = ?, since = ?, operation_id = ?, anchor_entry_id = ?, retry_disposition = ?, retry_by = ?, retry_attempt = ?, retry_max = ?, retry_next_at = ?, provider_error_json = ?, episode_state = COALESCE(?, episode_state), episode_binding_id = COALESCE(?, episode_binding_id), updated_at = ? WHERE fault_id = ?").run(i.link,i.op,i.kind,i.message,i.since,i.operationId,i.anchorEntryId,i.retryDisposition,i.retryBy,i.retryAttempt,i.retryMax,i.retryNextAt,i.providerError,r?.state??null,r?.bindingId??null,c(),n),{...t,faultId:n}}o(z,"updateFault");function D(e,n){s(e,"DELETE FROM node_faults WHERE fault_id = ? AND active = 0 AND episode_state IS NULL").run(n)}o(D,"deleteIfUnretained");function Z(e,n,t,r){const i=L(e,n);if(i===null){const d=s(e,"SELECT fault_id, link, kind, since, operation_id FROM node_faults WHERE node_id = ? AND active = 0 AND episode_state IS NOT NULL").get(n);return d!==void 0&&d.link===t.link&&d.kind===t.kind&&d.since===t.since&&d.operation_id===t.operation_id?(s(e,"UPDATE node_faults SET active = 1, updated_at = ? WHERE fault_id = ?").run(c(),d.fault_id),z(e,d.fault_id,t)):W(e,n,t,!0,r)}if(i.link===t.link&&i.kind===t.kind){const d={...i.retry,...t.retry};return t.retry.disposition==="fatal"&&!("nextAt"in t.retry)&&delete d.nextAt,z(e,i.faultId,{...t,since:i.since,anchorEntryId:i.anchorEntryId??t.anchorEntryId,retry:d},r)}return R(i)>R(t)?null:(s(e,"UPDATE node_faults SET active = 0, updated_at = ? WHERE fault_id = ?").run(c(),i.faultId),D(e,i.faultId),W(e,n,t,!0,r))}o(Z,"replaceActiveFault");function m(e,n,t){return s(e,"SELECT binding_id FROM sessions WHERE node_id = ? AND session_id = ? AND unbound_at IS NULL").get(n,t)?.binding_id??null}o(m,"liveBinding");function Pe(e,n){return l(t=>{const r=c();return s(t,"UPDATE executions SET turn_progress_at = ? WHERE execution_id = ? AND state != 'exited' AND turn_open_at IS NOT NULL AND turn_closed_at IS NULL").run(r,e).changes>0?!0:s(t,"UPDATE executions SET turn_open_at = ?, turn_progress_at = ?, turn_closed_at = NULL, turn_end_reason = NULL WHERE execution_id = ? AND state != 'exited'").run(r,r,e).changes>0})}o(Pe,"openTurn");function we(e){return l(n=>s(n,"UPDATE executions SET turn_progress_at = ? WHERE execution_id = ? AND state != 'exited' AND turn_open_at IS NOT NULL AND turn_closed_at IS NULL").run(c(),e).changes>0)}o(we,"recordTurnProgress");function Me(e,n){return l(t=>s(t,"UPDATE executions SET turn_closed_at = ?, turn_end_reason = ? WHERE execution_id = ? AND state != 'exited' AND turn_open_at IS NOT NULL AND turn_closed_at IS NULL").run(c(),n.endReason,e).changes>0)}o(Me,"closeTurn");function Xe(e,n){if(!Number.isInteger(n.consecutivePasses)||n.consecutivePasses<1||n.routes.length===0||!n.routes.every(t=>t!==""))throw new Error("invalid transport-poison verdict");return l(t=>s(t,"UPDATE executions SET exit_diagnostic_json = ? WHERE execution_id = ? AND state != 'exited'").run(JSON.stringify({schema:"crtr.execution-exit-diagnostic/v1",transport_poison:{consecutive_passes:n.consecutivePasses,routes:n.routes}}),e).changes>0)}o(Xe,"recordTransportPoisonVerdict");function je(e){const n=s(T(),"SELECT exit_diagnostic_json FROM executions WHERE node_id = ? ORDER BY rowid DESC LIMIT 1").get(e);if(n===void 0||n.exit_diagnostic_json===null)return null;try{const t=JSON.parse(n.exit_diagnostic_json),r=t.transport_poison;return t.schema!=="crtr.execution-exit-diagnostic/v1"||r===void 0||!Number.isInteger(r.consecutive_passes)||r.consecutive_passes<1||!Array.isArray(r.routes)||r.routes.length===0||!r.routes.every(i=>typeof i=="string"&&i!=="")?null:{consecutivePasses:r.consecutive_passes,routes:r.routes}}catch{return null}}o(je,"readTransportPoisonVerdict");function $e(e){const n=s(T(),"SELECT turn_open_at, turn_closed_at, turn_progress_at FROM executions WHERE node_id = ? AND state != 'exited'").get(e);return n===void 0?null:{busy:n.turn_open_at!==null&&n.turn_closed_at===null,progressAt:n.turn_progress_at}}o($e,"readLiveTurn");function Be(e){const n=T(),t=s(n,"SELECT turn_closed_at, turn_progress_at FROM executions WHERE node_id = ? AND turn_open_at IS NOT NULL ORDER BY rowid DESC LIMIT 1").get(e);if(t===void 0)return null;const r=s(n,"SELECT turn_end_reason FROM executions WHERE node_id = ? ORDER BY rowid DESC LIMIT 1").get(e);return{interrupted:t.turn_closed_at===null||r?.turn_end_reason==="teardown-aborted",progressAt:t.turn_progress_at}}o(Be,"readInterruptedTurn");function Je(e,n){const t=Q(n);return q(e,t),l(r=>Z(r,e,t))}o(Je,"recordFault");function Ke(e,n){const t=L(T(),e);return t===null||n?.link!==void 0&&t.link!==n.link?!1:l(r=>{const i=L(r,e);if(i===null||n?.link!==void 0&&i.link!==n.link)return!1;const d=s(r,"SELECT episode_state FROM node_faults WHERE fault_id = ?").get(i.faultId);s(r,"UPDATE node_faults SET active = 0, updated_at = ? WHERE fault_id = ?").run(c(),i.faultId),d.episode_state==="pending"&&n?.preserveEpisode!==!0&&s(r,"UPDATE node_faults SET episode_state = NULL, episode_binding_id = NULL, updated_at = ? WHERE fault_id = ?").run(c(),i.faultId),D(r,i.faultId);const a=G();return X({level:"info",event:"fault.cleared",operation_id:a,node_id:e,error_class:M(i),fields:{cleared_fault_operation_id:i.operation_id,link:i.link,op:i.op,kind:i.kind,retry:i.retry,message:i.message,since:i.since,...i.anchorEntryId===void 0?{}:{anchor_entry_id:i.anchorEntryId}}}),!0})}o(Ke,"clearFault");function ee(e){return L(T(),e)}o(ee,"readFault");function Ye(e,n){const t=Q(n.input);if(t.link!=="pi\u2192provider"||t.retry.disposition!=="auto"||t.retry.by!=="daemon")throw new Error("provider retry episode requires an automatic daemon provider fault");return q(e,t),l(r=>{const i=m(r,e,n.sessionId);if(i===null)return null;const d=L(r,e);if(d!==null&&(d.link!==t.link||d.kind!==t.kind)&&R(d)>R(t))return null;const a=s(r,"SELECT fault_id FROM node_faults WHERE node_id = ? AND episode_state IS NOT NULL").all(e);s(r,"UPDATE node_faults SET episode_state = NULL, episode_binding_id = NULL, updated_at = ? WHERE node_id = ? AND episode_state IS NOT NULL").run(c(),e);for(const E of a)D(r,E.fault_id);const u=Z(r,e,t,{state:"pending",bindingId:i});return u===null?null:(s(r,"UPDATE node_faults SET episode_state = ?, episode_binding_id = ?, updated_at = ? WHERE fault_id = ?").run("pending",i,c(),u.faultId),u)})}o(Ye,"recordPendingEpisode");function Ge(e,n){return l(t=>{if(s(t,"SELECT 1 FROM nodes WHERE node_id = ? AND intent IS 'refresh'").get(e)!==void 0)return!1;const r=m(t,e,n.sessionId);return r===null?!1:s(t,"UPDATE node_faults SET episode_state = 'admitted', retry_disposition = ?, retry_by = ?, retry_attempt = ?, retry_max = ?, retry_next_at = ?, updated_at = ? WHERE node_id = ? AND fault_id = ? AND episode_state = 'pending' AND episode_binding_id = ?").run(n.retry.disposition,n.retry.by??null,n.retry.attempt??null,n.retry.max??null,n.retry.nextAt??null,c(),e,n.faultId,r).changes>0})}o(Ge,"admitEpisode");function Ve(e,n){return l(t=>{const r=m(t,e,n.sessionId);return r===null?!1:s(t,"UPDATE node_faults SET episode_state = 'pending', updated_at = ? WHERE node_id = ? AND episode_state = 'admitted' AND episode_binding_id = ?").run(c(),e,r).changes>0})}o(Ve,"reopenEpisode");function Qe(e,n){return l(t=>{const r=m(t,e,n.sessionId);return r===null?!1:s(t,"UPDATE node_faults SET episode_state = 'invalidated', updated_at = ? WHERE node_id = ? AND episode_state != 'invalidated' AND episode_state IS NOT NULL AND episode_binding_id = ?").run(c(),e,r).changes>0})}o(Qe,"invalidateEpisode");function qe(e,n){return l(t=>{const r=m(t,e,n.sessionId);if(r===null)return!1;const i=s(t,"SELECT fault_id FROM node_faults WHERE node_id = ? AND episode_binding_id = ? AND episode_state IS NOT NULL").all(e,r);if(i.length===0)return!1;s(t,"UPDATE node_faults SET episode_state = NULL, episode_binding_id = NULL, updated_at = ? WHERE node_id = ? AND episode_binding_id = ? AND episode_state IS NOT NULL").run(c(),e,r);for(const d of i)D(t,d.fault_id);return!0})}o(qe,"clearEpisode");function ze(e){const n=s(T(),"SELECT f.*, s.session_id FROM node_faults f JOIN sessions s ON s.binding_id = f.episode_binding_id WHERE f.node_id = ? AND f.episode_state IS NOT NULL").get(e);return n===void 0?null:{state:n.episode_state,sessionId:n.session_id,fault:H(n)}}o(ze,"readEpisode");function Ze(){return s(T(),"SELECT f.*, s.session_id AS bound_session_id FROM node_faults f JOIN sessions s ON s.binding_id = f.episode_binding_id WHERE f.active = 1 AND f.episode_state = 'pending' AND s.unbound_at IS NULL AND s.session_id IS NOT NULL AND f.link = 'pi\u2192provider' AND f.retry_disposition = 'auto' AND f.retry_by = 'daemon' AND f.kind IN ('connection', 'rate-limit', 'overloaded')").all().map(n=>({nodeId:n.node_id,sessionId:n.bound_session_id,fault:H(n),updatedAt:n.updated_at}))}o(Ze,"listPendingProviderRetries");function en(e){const n=ee(e)===null;return{explanation(){if(!n)return null;const t=ee(e);if(t===null||t.link!=="crtr\u2192pi"||t.retry.disposition!=="fatal")return null;const r=t.op.trim(),i=t.message.trim();return r===""||i===""?null:`${r}: ${i}`}}}o(en,"beginBootFaultAttempt");function ne(e,n){try{return de(e).mtime.toISOString()}catch{return n}}o(ne,"markerMtime");function P(e,n){if(!p(e))return null;try{return oe(e,"utf8")}catch(t){if(!n)return null;throw new Error(`cannot import recovery input ${e}: ${t.message}`)}}o(P,"legacyFile");function Se(e,n){return s(e,"SELECT execution_id, started_at FROM executions WHERE node_id = ? ORDER BY rowid DESC LIMIT 1").get(n)??null}o(Se,"latestExecution");function xe(e,n){const r=J(e,"nodes").has("launched_at")?s(e,"SELECT COALESCE(launched_at, created) AS started_at FROM nodes WHERE node_id = ?").get(n):s(e,"SELECT created AS started_at FROM nodes WHERE node_id = ?").get(n);if(r===void 0)throw new Error(`cannot import recovery witness for unknown node ${n}`);const i=b();return s(e,"INSERT INTO executions (execution_id, node_id, daemon_epoch, pid, process_identity, state, started_at, ended_at, exit_reason) VALUES (?, ?, NULL, NULL, NULL, 'exited', ?, ?, 'pre-consolidation')").run(i,n,r.started_at,r.started_at),{execution_id:i,started_at:r.started_at}}o(xe,"syntheticExecution");function te(e,n,t,r,i){return W(e,n,t,r,i)}o(te,"insertMigratedFault");function Ie(e,n,t,r){const i=s(e,"SELECT binding_id, node_id FROM sessions WHERE transcript_path = ? AND unbound_at IS NULL").get(t);if(i!==void 0){if(i.node_id!==n)throw new Error(`cannot import provider retry ${r}: transcript is live-owned by ${i.node_id}`);return i.binding_id}const d=s(e,"SELECT binding_id FROM sessions WHERE node_id = ? AND transcript_path = ? ORDER BY rowid DESC LIMIT 1").get(n,t);if(d!==void 0)return d.binding_id;const a=s(e,"SELECT created FROM nodes WHERE node_id = ?").get(n);if(a===void 0)throw new Error(`cannot import provider retry ${r}: unknown node ${n}`);const u=b();return s(e,"INSERT INTO sessions (binding_id, session_id, node_id, transcript_path, source_session_id, fork_entry_id, created_at, bound_at, unbound_at) VALUES (?, NULL, ?, ?, NULL, NULL, ?, ?, ?)").run(u,n,t,a.created,a.created,c()),u}o(Ie,"migrationBinding");function nn(e){if(Ne(e),ge(e),!p(C()))return;const n=ie(C(),{withFileTypes:!0}).filter(r=>r.isDirectory()).sort((r,i)=>r.name.localeCompare(i.name)),t=s(e,"SELECT 1 FROM nodes WHERE node_id = ?");for(const r of n){const i=r.name,d=ce(i),a=N(d,"busy"),u=N(d,"clean-abort"),E=N(d,"transport-poison.json"),h=N(d,"fault"),A=N(d,"provider-retry"),O=p(a),U=p(u);if(!O&&!U&&!p(E)&&!p(h)&&!p(A)||!p(N(C(),i,"meta.json"))&&t.get(i)===void 0)continue;const k=P(E,!1),S=P(h,!0),x=P(A,!0);if(!O&&!U&&k===null&&S===null&&x===null)continue;let f=Se(e,i);if(f===null&&(f=xe(e,i)),O){const _=ne(a,f.started_at);s(e,"UPDATE executions SET turn_open_at = ?, turn_progress_at = ?, turn_closed_at = NULL, turn_end_reason = NULL WHERE execution_id = ?").run(_,_,f.execution_id)}else if(U){const _=ne(u,f.started_at);s(e,"UPDATE executions SET turn_open_at = ?, turn_progress_at = ?, turn_closed_at = ?, turn_end_reason = 'teardown-aborted' WHERE execution_id = ?").run(_,_,_,f.execution_id)}if(k!==null)try{const _=JSON.parse(k);Number.isInteger(_.consecutivePasses)&&_.consecutivePasses>=1&&Array.isArray(_.routes)&&_.routes.length>0&&_.routes.every(w=>typeof w=="string"&&w!=="")&&s(e,"UPDATE executions SET exit_diagnostic_json = ? WHERE execution_id = ?").run(JSON.stringify({schema:"crtr.execution-exit-diagnostic/v1",transport_poison:{consecutive_passes:_.consecutivePasses,routes:_.routes}}),f.execution_id)}catch{}const I=S===null?null:Y(S);if(S!==null&&I===null)throw new Error(`cannot import recovery fault ${h}`);const y=x===null?null:me(x);if(x!==null&&y===null)throw new Error(`cannot import provider retry ${A}`);let v=I===null||I.link==="broker\u2194crtrd"?null:te(e,i,I,!0);if(y!==null){const _=Ie(e,i,y.sessionFile,A);v!==null&&v.since===y.fault.since?s(e,"UPDATE node_faults SET episode_state = ?, episode_binding_id = ?, updated_at = ? WHERE fault_id = ?").run(y.state,_,c(),v.faultId):te(e,i,y.fault,!1,{state:y.state,bindingId:_})}}}o(nn,"migrateRecoveryWitnesses");export{We as FAULT_QUIET_MS,Ge as admitEpisode,en as beginBootFaultAttempt,qe as clearEpisode,Ke as clearFault,Me as closeTurn,H as hydrateFault,Qe as invalidateEpisode,Ze as listPendingProviderRetries,nn as migrateRecoveryWitnesses,Pe as openTurn,K as parseProviderError,ze as readEpisode,ee as readFault,Be as readInterruptedTurn,$e as readLiveTurn,je as readTransportPoisonVerdict,Je as recordFault,Ye as recordPendingEpisode,Xe as recordTransportPoisonVerdict,we as recordTurnProgress,Ve as reopenEpisode};
|
|
26
|
+
`)}o(ge,"createFaultTable");function g(e,n){return typeof n=="string"&&e.includes(n)}o(g,"contains");function F(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}o(F,"isRecord");function K(e){if(!F(e)||typeof e.provider!="string"||e.provider===""||typeof e.model!="string"||e.model==="")return;const n=typeof e.status=="number"&&Number.isFinite(e.status)?e.status:void 0,t=typeof e.code=="string"||typeof e.code=="number"?e.code:void 0,r=typeof e.errno=="string"?e.errno:void 0,i=typeof e.body=="string"?e.body:void 0,d=_e(e.ratelimit),a=Array.isArray(e.causes)?e.causes.flatMap(u=>{if(!F(u))return[];const f={...typeof u.message=="string"?{message:u.message}:{},...typeof u.status=="number"&&Number.isFinite(u.status)?{status:u.status}:{},...typeof u.code=="string"||typeof u.code=="number"?{code:u.code}:{},...typeof u.errno=="string"?{errno:u.errno}:{},...typeof u.body=="string"?{body:u.body}:{}};return Object.keys(f).length===0?[]:[f]}):void 0;return{provider:e.provider,model:e.model,...n===void 0?{}:{status:n},...t===void 0?{}:{code:t},...r===void 0?{}:{errno:r},...i===void 0?{}:{body:i},...a===void 0||a.length===0?{}:{causes:a},...d===void 0?{}:{ratelimit:d}}}o(K,"parseProviderError");function Y(e){try{const n=JSON.parse(e);if(!g(pe,n.link)||typeof n.op!="string"||n.op===""||!g(Ee,n.kind)||typeof n.message!="string"||typeof n.since!="string")return null;const t=$(n.operation_id);if(!F(n.retry)||!g(fe,n.retry.disposition)||n.retry.by!==void 0&&!g(ye,n.retry.by)||n.retry.attempt!==void 0&&typeof n.retry.attempt!="number"||n.retry.max!==void 0&&typeof n.retry.max!="number"||n.retry.nextAt!==void 0&&typeof n.retry.nextAt!="string"||n.anchorEntryId!==void 0&&(typeof n.anchorEntryId!="string"||n.anchorEntryId===""))return null;const r=n.providerError===void 0?void 0:K(n.providerError);return n.providerError!==void 0&&r===void 0?null:{link:n.link,op:n.op,kind:n.kind,retry:{disposition:n.retry.disposition,...n.retry.by===void 0?{}:{by:n.retry.by},...n.retry.attempt===void 0?{}:{attempt:n.retry.attempt},...n.retry.max===void 0?{}:{max:n.retry.max},...n.retry.nextAt===void 0?{}:{nextAt:n.retry.nextAt}},message:n.message,since:n.since,operation_id:t,...n.anchorEntryId===void 0?{}:{anchorEntryId:n.anchorEntryId},...r===void 0?{}:{providerError:r}}}catch{return null}}o(Y,"parseLegacyFault");function Le(e){const n=ae(e);try{return se(n)}catch{return n}}o(Le,"canonicalPath");function me(e){try{const n=JSON.parse(e);if(!g(Te,n.state)||typeof n.sessionFile!="string"||n.sessionFile==="")return null;const t=JSON.stringify(n.fault),r=Y(t);if(r===null||r.link!=="pi\u2192provider"||r.retry.disposition!=="auto"||r.retry.by!=="daemon")return null;const i=n.anchorEntryId;return i!==null&&typeof i!="string"||(r.anchorEntryId??null)!==i?null:{state:n.state,sessionFile:Le(n.sessionFile),fault:r}}catch{return null}}o(me,"parseLegacyEpisode");function G(e){return e!==void 0?$(e):j.current()??j.fresh(t=>t)}o(G,"resolveOperationId");function Ae(e){return e.slice(0,le)}o(Ae,"clampMessage");function R(e){return e.link==="pi\u2192provider"&&e.retry.disposition==="auto"&&e.retry.by==="daemon"?3:e.retry.disposition==="fatal"?2:1}o(R,"faultPriority");function V(e){return{link:e.link,op:e.op,kind:e.kind,message:e.message,since:e.since,operationId:e.operation_id,anchorEntryId:e.anchorEntryId??null,retryDisposition:e.retry.disposition,retryBy:e.retry.by??null,retryAttempt:e.retry.attempt??null,retryMax:e.retry.max??null,retryNextAt:e.retry.nextAt??null,providerError:e.providerError===void 0?null:JSON.stringify(e.providerError)}}o(V,"encodeFault");function H(e){const n=e.provider_error_json,t=typeof n=="string"?K(JSON.parse(n)):void 0;if(typeof n=="string"&&t===void 0)throw new Error(`invalid provider error on stored fault ${e.fault_id}`);const r={disposition:e.retry_disposition,...e.retry_by===null?{}:{by:e.retry_by},...e.retry_attempt===null?{}:{attempt:e.retry_attempt},...e.retry_max===null?{}:{max:e.retry_max},...e.retry_next_at===null?{}:{nextAt:e.retry_next_at}};return{faultId:e.fault_id,link:e.link,op:e.op,kind:e.kind,message:e.message,since:e.since,operation_id:e.operation_id,retry:r,...e.anchor_entry_id===null?{}:{anchorEntryId:e.anchor_entry_id},...t===void 0?{}:{providerError:t}}}o(H,"hydrateFault");function L(e,n){const t=ue(e,"SELECT * FROM node_faults WHERE node_id = ? AND active = 1").get(n);return t===void 0?null:H(t)}o(L,"activeFault");function Q(e){if(!g(B,e.link))throw new Error(`fault link is not durable: ${e.link}`);return{link:e.link,op:e.op,kind:e.kind,retry:e.retry,message:Ae(e.message),since:e.since??c(),operation_id:G(e.operation_id),...typeof e.anchorEntryId=="string"&&e.anchorEntryId!==""?{anchorEntryId:e.anchorEntryId}:{},...e.providerError===void 0?{}:{providerError:e.providerError}}}o(Q,"storedFault");function q(e,n){X({level:n.retry.disposition==="fatal"?"error":"warn",event:"fault.recorded",operation_id:n.operation_id,node_id:e,error_class:w(n),fields:{link:n.link,op:n.op,kind:n.kind,retry:n.retry,message:n.message,...n.anchorEntryId===void 0?{}:{anchor_entry_id:n.anchorEntryId},...n.providerError===void 0?{}:{provider_error:n.providerError}}})}o(q,"emitRecordedFault");function W(e,n,t,r,i){const d=b(),a=V(t),u=c();return s(e,"INSERT INTO node_faults (fault_id, node_id, link, op, kind, message, since, operation_id, anchor_entry_id, retry_disposition, retry_by, retry_attempt, retry_max, retry_next_at, provider_error_json, active, episode_state, episode_binding_id, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)").run(d,n,a.link,a.op,a.kind,a.message,a.since,a.operationId,a.anchorEntryId,a.retryDisposition,a.retryBy,a.retryAttempt,a.retryMax,a.retryNextAt,a.providerError,r?1:0,i?.state??null,i?.bindingId??null,u,u),{...t,faultId:d}}o(W,"insertFault");function z(e,n,t,r){const i=V(t);return s(e,"UPDATE node_faults SET link = ?, op = ?, kind = ?, message = ?, since = ?, operation_id = ?, anchor_entry_id = ?, retry_disposition = ?, retry_by = ?, retry_attempt = ?, retry_max = ?, retry_next_at = ?, provider_error_json = ?, episode_state = COALESCE(?, episode_state), episode_binding_id = COALESCE(?, episode_binding_id), updated_at = ? WHERE fault_id = ?").run(i.link,i.op,i.kind,i.message,i.since,i.operationId,i.anchorEntryId,i.retryDisposition,i.retryBy,i.retryAttempt,i.retryMax,i.retryNextAt,i.providerError,r?.state??null,r?.bindingId??null,c(),n),{...t,faultId:n}}o(z,"updateFault");function D(e,n){s(e,"DELETE FROM node_faults WHERE fault_id = ? AND active = 0 AND episode_state IS NULL").run(n)}o(D,"deleteIfUnretained");function Z(e,n,t,r){const i=L(e,n);if(i===null){const d=s(e,"SELECT fault_id, link, kind, since, operation_id FROM node_faults WHERE node_id = ? AND active = 0 AND episode_state IS NOT NULL").get(n);return d!==void 0&&d.link===t.link&&d.kind===t.kind&&d.since===t.since&&d.operation_id===t.operation_id?(s(e,"UPDATE node_faults SET active = 1, updated_at = ? WHERE fault_id = ?").run(c(),d.fault_id),z(e,d.fault_id,t)):W(e,n,t,!0,r)}if(i.link===t.link&&i.kind===t.kind){const d={...i.retry,...t.retry};return t.retry.disposition==="fatal"&&!("nextAt"in t.retry)&&delete d.nextAt,z(e,i.faultId,{...t,since:i.since,anchorEntryId:i.anchorEntryId??t.anchorEntryId,retry:d},r)}return R(i)>R(t)?null:(s(e,"UPDATE node_faults SET active = 0, updated_at = ? WHERE fault_id = ?").run(c(),i.faultId),D(e,i.faultId),W(e,n,t,!0,r))}o(Z,"replaceActiveFault");function m(e,n,t){return s(e,"SELECT binding_id FROM sessions WHERE node_id = ? AND session_id = ? AND unbound_at IS NULL").get(n,t)?.binding_id??null}o(m,"liveBinding");function Pe(e,n){return l(t=>{const r=c();return s(t,"UPDATE executions SET turn_progress_at = ? WHERE execution_id = ? AND state != 'exited' AND turn_open_at IS NOT NULL AND turn_closed_at IS NULL").run(r,e).changes>0?!0:s(t,"UPDATE executions SET turn_open_at = ?, turn_progress_at = ?, turn_closed_at = NULL, turn_end_reason = NULL WHERE execution_id = ? AND state != 'exited'").run(r,r,e).changes>0})}o(Pe,"openTurn");function Me(e){return l(n=>s(n,"UPDATE executions SET turn_progress_at = ? WHERE execution_id = ? AND state != 'exited' AND turn_open_at IS NOT NULL AND turn_closed_at IS NULL").run(c(),e).changes>0)}o(Me,"recordTurnProgress");function we(e,n){return l(t=>s(t,"UPDATE executions SET turn_closed_at = ?, turn_end_reason = ? WHERE execution_id = ? AND state != 'exited' AND turn_open_at IS NOT NULL AND turn_closed_at IS NULL").run(c(),n.endReason,e).changes>0)}o(we,"closeTurn");function Xe(e,n){if(!Number.isInteger(n.consecutivePasses)||n.consecutivePasses<1||n.routes.length===0||!n.routes.every(t=>t!==""))throw new Error("invalid transport-poison verdict");return l(t=>s(t,"UPDATE executions SET exit_diagnostic_json = ? WHERE execution_id = ? AND state != 'exited'").run(JSON.stringify({schema:"crtr.execution-exit-diagnostic/v1",transport_poison:{consecutive_passes:n.consecutivePasses,routes:n.routes}}),e).changes>0)}o(Xe,"recordTransportPoisonVerdict");function je(e){const n=s(E(),"SELECT exit_diagnostic_json FROM executions WHERE node_id = ? ORDER BY rowid DESC LIMIT 1").get(e);if(n===void 0||n.exit_diagnostic_json===null)return null;try{const t=JSON.parse(n.exit_diagnostic_json),r=t.transport_poison;return t.schema!=="crtr.execution-exit-diagnostic/v1"||r===void 0||!Number.isInteger(r.consecutive_passes)||r.consecutive_passes<1||!Array.isArray(r.routes)||r.routes.length===0||!r.routes.every(i=>typeof i=="string"&&i!=="")?null:{consecutivePasses:r.consecutive_passes,routes:r.routes}}catch{return null}}o(je,"readTransportPoisonVerdict");function $e(e){const n=s(E(),"SELECT turn_open_at, turn_closed_at, turn_progress_at FROM executions WHERE node_id = ? AND state != 'exited'").get(e);return n===void 0?null:{busy:n.turn_open_at!==null&&n.turn_closed_at===null,progressAt:n.turn_progress_at}}o($e,"readLiveTurn");function Be(e){const n=E(),t=s(n,"SELECT turn_closed_at, turn_progress_at FROM executions WHERE node_id = ? AND turn_open_at IS NOT NULL ORDER BY rowid DESC LIMIT 1").get(e);if(t===void 0)return null;const r=s(n,"SELECT turn_end_reason FROM executions WHERE node_id = ? ORDER BY rowid DESC LIMIT 1").get(e);return{interrupted:t.turn_closed_at===null||r?.turn_end_reason==="teardown-aborted",progressAt:t.turn_progress_at}}o(Be,"readInterruptedTurn");function Je(e){return s(E(),"SELECT 1 FROM executions WHERE node_id = ? AND turn_open_at IS NOT NULL LIMIT 1").get(e)!==void 0}o(Je,"hasAdmittedTurn");function Ke(e,n){const t=Q(n);return q(e,t),l(r=>Z(r,e,t))}o(Ke,"recordFault");function Ye(e,n){const t=L(E(),e);return t===null||n?.link!==void 0&&t.link!==n.link?!1:l(r=>{const i=L(r,e);if(i===null||n?.link!==void 0&&i.link!==n.link)return!1;const d=s(r,"SELECT episode_state FROM node_faults WHERE fault_id = ?").get(i.faultId);s(r,"UPDATE node_faults SET active = 0, updated_at = ? WHERE fault_id = ?").run(c(),i.faultId),d.episode_state==="pending"&&n?.preserveEpisode!==!0&&s(r,"UPDATE node_faults SET episode_state = NULL, episode_binding_id = NULL, updated_at = ? WHERE fault_id = ?").run(c(),i.faultId),D(r,i.faultId);const a=G();return X({level:"info",event:"fault.cleared",operation_id:a,node_id:e,error_class:w(i),fields:{cleared_fault_operation_id:i.operation_id,link:i.link,op:i.op,kind:i.kind,retry:i.retry,message:i.message,since:i.since,...i.anchorEntryId===void 0?{}:{anchor_entry_id:i.anchorEntryId}}}),!0})}o(Ye,"clearFault");function ee(e){return L(E(),e)}o(ee,"readFault");function Ge(e,n){const t=Q(n.input);if(t.link!=="pi\u2192provider"||t.retry.disposition!=="auto"||t.retry.by!=="daemon")throw new Error("provider retry episode requires an automatic daemon provider fault");return q(e,t),l(r=>{const i=m(r,e,n.sessionId);if(i===null)return null;const d=L(r,e);if(d!==null&&(d.link!==t.link||d.kind!==t.kind)&&R(d)>R(t))return null;const a=s(r,"SELECT fault_id FROM node_faults WHERE node_id = ? AND episode_state IS NOT NULL").all(e);s(r,"UPDATE node_faults SET episode_state = NULL, episode_binding_id = NULL, updated_at = ? WHERE node_id = ? AND episode_state IS NOT NULL").run(c(),e);for(const f of a)D(r,f.fault_id);const u=Z(r,e,t,{state:"pending",bindingId:i});return u===null?null:(s(r,"UPDATE node_faults SET episode_state = ?, episode_binding_id = ?, updated_at = ? WHERE fault_id = ?").run("pending",i,c(),u.faultId),u)})}o(Ge,"recordPendingEpisode");function Ve(e,n){return l(t=>{if(s(t,"SELECT 1 FROM nodes WHERE node_id = ? AND intent IS 'refresh'").get(e)!==void 0)return!1;const r=m(t,e,n.sessionId);return r===null?!1:s(t,"UPDATE node_faults SET episode_state = 'admitted', retry_disposition = ?, retry_by = ?, retry_attempt = ?, retry_max = ?, retry_next_at = ?, updated_at = ? WHERE node_id = ? AND fault_id = ? AND episode_state = 'pending' AND episode_binding_id = ?").run(n.retry.disposition,n.retry.by??null,n.retry.attempt??null,n.retry.max??null,n.retry.nextAt??null,c(),e,n.faultId,r).changes>0})}o(Ve,"admitEpisode");function Qe(e,n){return l(t=>{const r=m(t,e,n.sessionId);return r===null?!1:s(t,"UPDATE node_faults SET episode_state = 'pending', updated_at = ? WHERE node_id = ? AND episode_state = 'admitted' AND episode_binding_id = ?").run(c(),e,r).changes>0})}o(Qe,"reopenEpisode");function qe(e,n){return l(t=>{const r=m(t,e,n.sessionId);return r===null?!1:s(t,"UPDATE node_faults SET episode_state = 'invalidated', updated_at = ? WHERE node_id = ? AND episode_state != 'invalidated' AND episode_state IS NOT NULL AND episode_binding_id = ?").run(c(),e,r).changes>0})}o(qe,"invalidateEpisode");function ze(e,n){return l(t=>{const r=m(t,e,n.sessionId);if(r===null)return!1;const i=s(t,"SELECT fault_id FROM node_faults WHERE node_id = ? AND episode_binding_id = ? AND episode_state IS NOT NULL").all(e,r);if(i.length===0)return!1;s(t,"UPDATE node_faults SET episode_state = NULL, episode_binding_id = NULL, updated_at = ? WHERE node_id = ? AND episode_binding_id = ? AND episode_state IS NOT NULL").run(c(),e,r);for(const d of i)D(t,d.fault_id);return!0})}o(ze,"clearEpisode");function Ze(e){const n=s(E(),"SELECT f.*, s.session_id FROM node_faults f JOIN sessions s ON s.binding_id = f.episode_binding_id WHERE f.node_id = ? AND f.episode_state IS NOT NULL").get(e);return n===void 0?null:{state:n.episode_state,sessionId:n.session_id,fault:H(n)}}o(Ze,"readEpisode");function en(){return s(E(),"SELECT f.*, s.session_id AS bound_session_id FROM node_faults f JOIN sessions s ON s.binding_id = f.episode_binding_id WHERE f.active = 1 AND f.episode_state = 'pending' AND s.unbound_at IS NULL AND s.session_id IS NOT NULL AND f.link = 'pi\u2192provider' AND f.retry_disposition = 'auto' AND f.retry_by = 'daemon' AND f.kind IN ('connection', 'rate-limit', 'overloaded')").all().map(n=>({nodeId:n.node_id,sessionId:n.bound_session_id,fault:H(n),updatedAt:n.updated_at}))}o(en,"listPendingProviderRetries");function nn(e){const n=ee(e)===null;return{explanation(){if(!n)return null;const t=ee(e);if(t===null||t.link!=="crtr\u2192pi"||t.retry.disposition!=="fatal")return null;const r=t.op.trim(),i=t.message.trim();return r===""||i===""?null:`${r}: ${i}`}}}o(nn,"beginBootFaultAttempt");function ne(e,n){try{return de(e).mtime.toISOString()}catch{return n}}o(ne,"markerMtime");function P(e,n){if(!p(e))return null;try{return oe(e,"utf8")}catch(t){if(!n)return null;throw new Error(`cannot import recovery input ${e}: ${t.message}`)}}o(P,"legacyFile");function Se(e,n){return s(e,"SELECT execution_id, started_at FROM executions WHERE node_id = ? ORDER BY rowid DESC LIMIT 1").get(n)??null}o(Se,"latestExecution");function xe(e,n){const r=J(e,"nodes").has("launched_at")?s(e,"SELECT COALESCE(launched_at, created) AS started_at FROM nodes WHERE node_id = ?").get(n):s(e,"SELECT created AS started_at FROM nodes WHERE node_id = ?").get(n);if(r===void 0)throw new Error(`cannot import recovery witness for unknown node ${n}`);const i=b();return s(e,"INSERT INTO executions (execution_id, node_id, daemon_epoch, pid, process_identity, state, started_at, ended_at, exit_reason) VALUES (?, ?, NULL, NULL, NULL, 'exited', ?, ?, 'pre-consolidation')").run(i,n,r.started_at,r.started_at),{execution_id:i,started_at:r.started_at}}o(xe,"syntheticExecution");function te(e,n,t,r,i){return W(e,n,t,r,i)}o(te,"insertMigratedFault");function Ie(e,n,t,r){const i=s(e,"SELECT binding_id, node_id FROM sessions WHERE transcript_path = ? AND unbound_at IS NULL").get(t);if(i!==void 0){if(i.node_id!==n)throw new Error(`cannot import provider retry ${r}: transcript is live-owned by ${i.node_id}`);return i.binding_id}const d=s(e,"SELECT binding_id FROM sessions WHERE node_id = ? AND transcript_path = ? ORDER BY rowid DESC LIMIT 1").get(n,t);if(d!==void 0)return d.binding_id;const a=s(e,"SELECT created FROM nodes WHERE node_id = ?").get(n);if(a===void 0)throw new Error(`cannot import provider retry ${r}: unknown node ${n}`);const u=b();return s(e,"INSERT INTO sessions (binding_id, session_id, node_id, transcript_path, source_session_id, fork_entry_id, created_at, bound_at, unbound_at) VALUES (?, NULL, ?, ?, NULL, NULL, ?, ?, ?)").run(u,n,t,a.created,a.created,c()),u}o(Ie,"migrationBinding");function tn(e){if(Ne(e),ge(e),!p(C()))return;const n=ie(C(),{withFileTypes:!0}).filter(r=>r.isDirectory()).sort((r,i)=>r.name.localeCompare(i.name)),t=s(e,"SELECT 1 FROM nodes WHERE node_id = ?");for(const r of n){const i=r.name,d=ce(i),a=N(d,"busy"),u=N(d,"clean-abort"),f=N(d,"transport-poison.json"),h=N(d,"fault"),A=N(d,"provider-retry"),O=p(a),U=p(u);if(!O&&!U&&!p(f)&&!p(h)&&!p(A)||!p(N(C(),i,"meta.json"))&&t.get(i)===void 0)continue;const k=P(f,!1),S=P(h,!0),x=P(A,!0);if(!O&&!U&&k===null&&S===null&&x===null)continue;let y=Se(e,i);if(y===null&&(y=xe(e,i)),O){const _=ne(a,y.started_at);s(e,"UPDATE executions SET turn_open_at = ?, turn_progress_at = ?, turn_closed_at = NULL, turn_end_reason = NULL WHERE execution_id = ?").run(_,_,y.execution_id)}else if(U){const _=ne(u,y.started_at);s(e,"UPDATE executions SET turn_open_at = ?, turn_progress_at = ?, turn_closed_at = ?, turn_end_reason = 'teardown-aborted' WHERE execution_id = ?").run(_,_,_,y.execution_id)}if(k!==null)try{const _=JSON.parse(k);Number.isInteger(_.consecutivePasses)&&_.consecutivePasses>=1&&Array.isArray(_.routes)&&_.routes.length>0&&_.routes.every(M=>typeof M=="string"&&M!=="")&&s(e,"UPDATE executions SET exit_diagnostic_json = ? WHERE execution_id = ?").run(JSON.stringify({schema:"crtr.execution-exit-diagnostic/v1",transport_poison:{consecutive_passes:_.consecutivePasses,routes:_.routes}}),y.execution_id)}catch{}const I=S===null?null:Y(S);if(S!==null&&I===null)throw new Error(`cannot import recovery fault ${h}`);const T=x===null?null:me(x);if(x!==null&&T===null)throw new Error(`cannot import provider retry ${A}`);let v=I===null||I.link==="broker\u2194crtrd"?null:te(e,i,I,!0);if(T!==null){const _=Ie(e,i,T.sessionFile,A);v!==null&&v.since===T.fault.since?s(e,"UPDATE node_faults SET episode_state = ?, episode_binding_id = ?, updated_at = ? WHERE fault_id = ?").run(T.state,_,c(),v.faultId):te(e,i,T.fault,!1,{state:T.state,bindingId:_})}}}o(tn,"migrateRecoveryWitnesses");export{We as FAULT_QUIET_MS,Ve as admitEpisode,nn as beginBootFaultAttempt,ze as clearEpisode,Ye as clearFault,we as closeTurn,Je as hasAdmittedTurn,H as hydrateFault,qe as invalidateEpisode,en as listPendingProviderRetries,tn as migrateRecoveryWitnesses,Pe as openTurn,K as parseProviderError,Ze as readEpisode,ee as readFault,Be as readInterruptedTurn,$e as readLiveTurn,je as readTransportPoisonVerdict,Ke as recordFault,Ge as recordPendingEpisode,Xe as recordTransportPoisonVerdict,Me as recordTurnProgress,Qe as reopenEpisode};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var i=Object.defineProperty;var e=(t,n)=>i(t,"name",{value:n,configurable:!0});import{validateEnvVarName as p}from"../env-name.js";function h(t){return t==="localhost"||t.endsWith(".localhost")||t==="127.0.0.1"||t==="[::1]"||t==="::1"||t==="host.docker.internal"}e(h,"isLoopbackHostname");function l(t){const n=[];if(typeof t!="string")n.push("endpoint must be a string");else try{const o=new URL(t);(o.protocol!=="https:"&&!(o.protocol==="http:"&&h(o.hostname))||o.username||o.password||o.hash)&&n.push("endpoint must be an absolute https:// URL (http:// permitted for loopback and *.localhost hosts only; no credentials or fragment)")}catch{n.push("endpoint must be an absolute https:// URL (http:// permitted for loopback and *.localhost hosts only; no credentials or fragment)")}return{isValid:n.length===0,errors:n}}e(l,"validateEndpoint");function u(t){try{const n=new URL(t),o=n.pathname.endsWith("/")?n.pathname.slice(0,-1):n.pathname;return`${n.protocol}//${n.host}${o}${n.search}`}catch{return t}}e(u,"normalizeEndpoint");function c(t){const n=[];if(typeof t!="object"||t===null||Array.isArray(t))return{errors:["transport must be an object"]};const o=t,r=Object.keys(o).filter(a=>!["kind","endpoint","authEnv"].includes(a));r.length&&n.push(`transport has unknown keys: ${r.join(", ")}`),o.kind!=="http"&&n.push('transport.kind must be "http"');const s=l(o.endpoint);return n.push(...s.errors),o.authEnv!==void 0&&n.push(...p(o.authEnv).errors),n.length?{errors:n}:{transport:{kind:"http",endpoint:u(o.endpoint),...o.authEnv!==void 0?{authEnv:o.authEnv}:{}},errors:n}}e(c,"validateHttpPluginTransport");function k(t){if(typeof t=="object"&&t!==null&&!Array.isArray(t)&&t.kind==="machine"){const n=Object.keys(t).filter(o=>o!=="kind");return n.length?{errors:[`transport has unknown keys: ${n.join(", ")}`]}:{transport:{kind:"machine"},errors:[]}}return c(t)}e(k,"validateBundleTransport");export{h as isLoopbackHostname,u as normalizeEndpoint,k as validateBundleTransport,l as validateEndpoint,c as validateHttpPluginTransport};
|
|
@@ -31,9 +31,10 @@ export declare function noteNodeWorking(repos: ObjectRow[], cwd: string): Promis
|
|
|
31
31
|
* never fails a boot, and every failure is an event.
|
|
32
32
|
*/
|
|
33
33
|
export declare function noteNodeBooting(nodeId: string): Promise<void>;
|
|
34
|
-
/** A repo-owned document changed (write, edit, move at either end, delete). `
|
|
35
|
-
*
|
|
36
|
-
|
|
34
|
+
/** A repo-owned document changed (write, edit, move at either end, delete). `dirs`, the caller's
|
|
35
|
+
* cwd and the checkouts it reaches, record the fetch URL of any that is a checkout of the repo; the
|
|
36
|
+
* sync itself never depends on where the writer runs. */
|
|
37
|
+
export declare function noteRepoDocumentsChanged(repo: ObjectRow, dirs?: readonly string[]): void;
|
|
37
38
|
/**
|
|
38
39
|
* One sync: export canvas.db to a local commit, fetch the remote ref, fast-forward or merge,
|
|
39
40
|
* import the merged tree into canvas.db, push (never forced). A rejected push fetches again,
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var B=Object.defineProperty;var
|
|
2
|
-
`)}}
|
|
1
|
+
var B=Object.defineProperty;var c=(t,r)=>B(t,"name",{value:r,configurable:!0});import{prepared as v}from"../../sqlite-statements.js";import{existsSync as D}from"node:fs";import{readFile as K,writeFile as q}from"node:fs/promises";import{join as S}from"node:path";import{emitEvent as G}from"../../events/emit.js";import{exportRepo as J,importTree as Q,pendingPaths as V}from"./exchange.js";import{checkoutChain as X}from"./identity.js";import{checkoutsForCwd as Y,reposForCwd as Z}from"./repos.js";import{commitTree as k,fetchDocs as ee,FIRST_FETCH_MARKER as te,isAncestor as L,mergeBase as re,openMirror as _,pushDocs as ne,readTree as p,remoteDocsTip as oe,resolveRef as h,setRef as y}from"./mirror.js";import{mergeTrees as se}from"./ref-format.js";const ie=2e4,A=3,H="remote-url",m="refs/crtr/docs",ae="refs/crtr/remote-docs",g="refs/crtr/imported";function T(t){try{G(t)}catch{}}c(T,"emitEvent");let M=null;const b=new Map,O=new Set;function Se(t,r){M={lifecycle:t,db:r}}c(Se,"startRepoSync");function P(t,r){return r.type!=="repo"?!1:v(t,"SELECT 1 FROM identities WHERE object = ? AND scheme = 'git'").get(r.rowid)!==void 0}c(P,"gitScheme");async function U(t,r){const e=new Map;for(const f of r)for(const o of X(f))o.ok&&o.scheme==="git"&&e.set(o.externalId,o.remoteUrl);if(e.size===0)return;const a=M.db(),n=v(a,"SELECT external_id FROM identities WHERE object = ? AND scheme = 'git'");for(const f of t){const o=n.get(f.rowid),i=o&&e.get(o.external_id);if(!i)continue;const s=await _(f.id);await q(S(s.dir,H),`${i}
|
|
2
|
+
`)}}c(U,"recordRemoteUrls");async function ce(t,r){const a=E().db(),n=t.filter(s=>P(a,s));if(n.length===0)return;await U(n,[r]);const f=[];for(const s of n){const l=!O.has(s.id)&&!D(S((await _(s.id)).dir,te)),u=R(s);l&&u&&f.push(u)}if(f.length===0)return;let o;const i=new Promise(s=>{o=setTimeout(s,ie)});await Promise.race([Promise.all(f),i]),clearTimeout(o)}c(ce,"noteNodeWorking");async function ke(t){try{const r=E().db(),e=v(r,"SELECT cwd FROM nodes WHERE node_id = ?").get(t);if(!e)return;const a=fe(r,()=>Z(r,e.cwd));a.length>0&&await ce(a,e.cwd)}catch(r){T({level:"warn",event:"repo_sync.failed",outcome:"failed",error:r,node_id:t,fields:{step:"fetch",reason:`the boot trigger failed: ${r instanceof Error?r.message:String(r)}`}})}}c(ke,"noteNodeBooting");function fe(t,r){if(t.isTransaction)return r();t.exec("BEGIN IMMEDIATE");try{const e=r();return t.exec("COMMIT"),e}catch(e){throw t.exec("ROLLBACK"),e}}c(fe,"inWrite");function _e(t,r=[]){const e=E();if(!P(e.db(),t))return;if(r.length===0){R(t);return}const a=U([t],r).then(()=>{R(t)},n=>{T({level:"error",event:"repo_sync.failed",error:n,fields:{repo:t.name,step:"fetch",reason:"recording the remote URL failed"}})});e.lifecycle.registerDetached(a)}c(_e,"noteRepoDocumentsChanged");function E(){if(!M)throw new Error("repo sync is not started: crtrd must call startRepoSync first");return M}c(E,"requireEngine");function R(t){const r=E(),e=b.get(t.id)??{running:null,again:!1};if(b.set(t.id,e),e.running)return e.again=!0,e.running.then(()=>b.get(t.id)?.running??null).then(n=>n??{ok:!0,pushed:!1,imported:$()});if(!r.lifecycle.acceptsDetachedWork())return null;O.add(t.id);const a=de(t).then(n=>(W(t,n),n),n=>{const f={ok:!1,step:"export",reason:n instanceof Error?n.message:String(n)};return W(t,f),f}).finally(()=>{e.running=null,e.again&&(e.again=!1,R(t))});return e.running=a,r.lifecycle.registerDetached(a.then(()=>{})),a}c(R,"schedule");function W(t,r){if(r.ok){const e=r.imported;T({level:"info",event:"repo_sync.completed",outcome:"succeeded",fields:{repo:t.name,pushed:r.pushed,created:e.created,revisions:e.revisions,deleted:e.deleted,needs_merge:e.needsMerge,refused:e.refused}})}else T({level:"warn",event:"repo_sync.failed",outcome:"failed",fields:{repo:t.name,step:r.step,reason:r.reason}})}c(W,"report");function $(){return{created:0,revisions:0,deleted:0,needsMerge:[],refused:[]}}c($,"emptyImport");class x extends Error{static{c(this,"StepError")}step;constructor(r,e){super(e),this.step=r}}async function C(t,r){try{return await r()}catch(e){throw e instanceof x?e:new x(t,e instanceof Error?e.message:String(e))}}c(C,"step");async function de(t){const r=E();try{const e=await _(t.id),a=await ue(e);if(a===null)return{ok:!1,step:"fetch",reason:`no checkout of ${t.name} with an origin remote has been seen by this runtime`};let n=$();const f=c(()=>C("import",async()=>{const o=await h(e,m),i=await h(e,g);if(o===null||i===o)return;const s=i?await p(e,g):new Map,l=r.db(),u=await p(e,m),d=Q(l,t,s,u,w=>Y(l,w));n={created:n.created+d.created,revisions:n.revisions+d.revisions,deleted:n.deleted+d.deleted,needsMerge:[...new Set([...n.needsMerge,...d.needsMerge])],refused:[...n.refused,...d.refused]},await j(e,o,u,s,new Set(d.refused.map(w=>w.path)),i)}),"importLocal");await f(),await C("export",async()=>{const o=await h(e,m),i=o?await p(e,m):null,s=await h(e,g),l=s?await p(e,g):null,u=J(r.db(),t,i,l);if(o?z(i,u):u.size===0)return;const d=await k(e,u,o?[o]:[],`crtr: export ${t.name}`);await y(e,m,d,o),await j(e,d,u,l??new Map,new Set(V(i,l)),s)});for(let o=1;;o++){const i=await oe(e,a);if(!i.ok)return{ok:!1,step:"fetch",reason:i.reason};let s=await h(e,m);if(i.value!==null&&!(s&&await le(e,i.value)&&await L(e,i.value,s))){const u=await ee(e,a);if(!u.ok)return{ok:!1,step:"fetch",reason:u.reason};const d=u.value;s=await C("merge",async()=>{if(!s||await L(e,s,d))return await y(e,m,d,s),d;const w=await re(e,s,d),F=se(w?await p(e,w):new Map,await p(e,m),await p(e,ae));for(const N of F.refused)n.refused.push(N);const I=await k(e,F.tree,[s,d],`crtr: merge ${t.name}`);return await y(e,m,I,s),I})}if(await f(),s===null||s===i.value)return{ok:!0,pushed:!1,imported:n};const l=await ne(e,a,s);if(l.ok)return{ok:!0,pushed:!0,imported:n};if(l.reason!=="rejected")return{ok:!1,step:"push",reason:l.reason};if(o>=A)return{ok:!1,step:"push",reason:`push rejected ${A} times`}}}catch(e){if(e instanceof x)return{ok:!1,step:e.step,reason:e.message};throw e}}c(de,"syncRepo");async function j(t,r,e,a,n,f){if(n.size===0){await y(t,g,r,f);return}const o=new Map(e);for(const i of n)a.has(i)?o.set(i,a.get(i)):o.delete(i);f!==null&&z(a,o)||await y(t,g,await k(t,o,[],"crtr: imported baseline (some files pending)"),f)}c(j,"advanceImported");async function ue(t){const r=S(t.dir,H);return D(r)&&(await K(r,"utf8")).trim()||null}c(ue,"readUrl");async function le(t,r){return await h(t,r)!==null}c(le,"hasCommit");function z(t,r){if(t.size!==r.size)return!1;for(const[e,a]of t)if(r.get(e)!==a)return!1;return!0}c(z,"sameTree");export{ie as FIRST_FETCH_WAIT_MS,ke as noteNodeBooting,ce as noteNodeWorking,_e as noteRepoDocumentsChanged,Se as startRepoSync,de as syncRepo};
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import type { Reader } from '../types.js';
|
|
2
2
|
import type { Space } from './index.js';
|
|
3
|
-
/** Whether a node
|
|
4
|
-
*
|
|
5
|
-
* in, since a node may be started in any
|
|
6
|
-
*
|
|
7
|
-
*
|
|
3
|
+
/** Whether a node has a checkout of `repo` that its file permissions reach: read to read the
|
|
4
|
+
* repo's documents, rw to change them. A checkout is one enclosing the node's cwd or one of its
|
|
5
|
+
* profile's project paths; the cwd alone never lets a run in, since a node may be started in any
|
|
6
|
+
* directory. A repo's documents change iff its files do. A repo-owned custom object is inside its
|
|
7
|
+
* own repo. A Mac terminal node reaches every path. */
|
|
8
8
|
export declare function insideRepo(db: Parameters<Space['canRead']>[0], reader: Reader, repo: {
|
|
9
9
|
rowid: number;
|
|
10
10
|
}, access: 'read' | 'rw'): boolean;
|
|
11
|
-
/** A repo: read and changed by a run
|
|
12
|
-
* permissions reach (see `insideRepo`). It owns only public documents, so a
|
|
11
|
+
/** A repo: read and changed by a run with a checkout of it (enclosing its cwd or one of its
|
|
12
|
+
* profile's project paths) that its file permissions reach (see `insideRepo`). It owns only public documents, so a
|
|
13
13
|
* non-public one is never changed. */
|
|
14
14
|
export declare const repoSpace: Space;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var u=Object.defineProperty;var
|
|
1
|
+
var u=Object.defineProperty;var i=(t,o)=>u(t,"name",{value:o,configurable:!0});import{fileRoot as f}from"../../spaces/file-root.js";import{identityOf as c}from"./index.js";function p(t,o,e,r){if(o.class==="object")return o.repos.some(n=>n.rowid===e.rowid);if(o.class!=="node")return!1;const s=[...o.checkouts,...o.projectCheckouts].filter(n=>n.repo.rowid===e.rowid);if(s.length===0)return!1;const l={app:c(t,o.app).external_id,resolved:o.scopes??[],launched:null};return s.some(n=>"root"in f(l,n.root,r))}i(p,"insideRepo");const d={identity:c,sync:"repo-ref",canRead(t,o,e,r){return o.class==="person"||r.length===0?!0:p(t,o,e,"read")},canChange(t,o,e,r,s){return s.privacy!=="public"?!1:o.class==="person"?!0:p(t,o,e,"rw")}};export{p as insideRepo,d as repoSpace};
|
|
@@ -74,10 +74,11 @@ export type Reader = {
|
|
|
74
74
|
/** The launched `scopes` list as given (see the app reader); null/absent = the run was launched with no list. */
|
|
75
75
|
launched?: readonly string[] | null;
|
|
76
76
|
/** The repos enclosing `cwd`, nearest first; `checkouts` pairs each with its checkout root. Only these are repos the node
|
|
77
|
-
* "works in": `--owner repo`
|
|
77
|
+
* "works in": `--owner repo` follows them; rule `if: {repo}` follows these plus `projectRepos`; read and write access
|
|
78
|
+
* to a repo's documents follow `checkouts` plus `projectCheckouts`, each gated by the node's file permissions. */
|
|
78
79
|
repos: ObjectRow[];
|
|
79
80
|
checkouts: Checkout[];
|
|
80
|
-
/** The repos of the profile's project paths that do not enclose `cwd`, in manifest order: in the node's view and
|
|
81
|
+
/** The repos of the profile's project paths that do not enclose `cwd`, in manifest order: in the node's view, readable and, where its file permissions allow writing the checkout, changeable; not worked in. */
|
|
81
82
|
projectRepos: ObjectRow[];
|
|
82
83
|
projectCheckouts: Checkout[];
|
|
83
84
|
profile: ObjectRow | null;
|
|
@@ -2,3 +2,7 @@
|
|
|
2
2
|
export declare class PageAuthoringError extends Error {
|
|
3
3
|
constructor(message: string);
|
|
4
4
|
}
|
|
5
|
+
/** The page compiler itself failed; the page is not at fault, so callers must not report it as bad page input. */
|
|
6
|
+
export declare class PageCompilerError extends Error {
|
|
7
|
+
constructor(message: string);
|
|
8
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var s=Object.defineProperty;var o=(e,r)=>s(e,"name",{value:r,configurable:!0});class a extends Error{static{o(this,"PageAuthoringError")}constructor(r){super(r),this.name="PageAuthoringError"}}class n extends Error{static{o(this,"PageCompilerError")}constructor(r){super(r),this.name="PageCompilerError"}}export{a as PageAuthoringError,n as PageCompilerError};
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import type { ProductPageComponents } from '../../types.js';
|
|
2
2
|
import { type PageDelivery, type PageManifest, type PageSource } from './page-schema.js';
|
|
3
|
-
import { PageAuthoringError } from './page-errors.js';
|
|
4
|
-
export { PageAuthoringError };
|
|
3
|
+
import { PageAuthoringError, PageCompilerError } from './page-errors.js';
|
|
4
|
+
export { PageAuthoringError, PageCompilerError };
|
|
5
5
|
/** Compile one authored TSX page to the CommonJS module the Gateway evaluates.
|
|
6
|
-
* Registry names stay free identifiers; the Gateway supplies them at eval.
|
|
6
|
+
* Registry names stay free identifiers; the Gateway supplies them at eval.
|
|
7
|
+
*
|
|
8
|
+
* esbuild's sync API keeps one service child process for the life of the host, and the
|
|
9
|
+
* long-lived daemon outlives it: once that child dies every later transform throws "The
|
|
10
|
+
* service is no longer running". A page's own compile failure always carries a located
|
|
11
|
+
* `errors` list; an error without one is the service failing, so stop the handle (the next
|
|
12
|
+
* call starts a fresh service) and retry once. A failure that survives the retry is a
|
|
13
|
+
* PageCompilerError, never a PageAuthoringError, so it is not blamed on the page. */
|
|
7
14
|
export declare function compilePage(document: string): string;
|
|
8
15
|
/** Derive the transport manifest from one authored TSX page document. */
|
|
9
16
|
export declare function derivePageManifestFromDocument(document: string, productComponents?: ProductPageComponents, source?: PageSource, delivery?: PageDelivery): PageManifest;
|
package/dist/core/human/page.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var q=Object.defineProperty;var i=(t,e)=>q(t,"name",{value:e,configurable:!0});import{readFileSync as v}from"node:fs";import{createRequire as
|
|
1
|
+
var q=Object.defineProperty;var i=(t,e)=>q(t,"name",{value:e,configurable:!0});import{readFileSync as v}from"node:fs";import{createRequire as D}from"node:module";import{join as O}from"node:path";import{BUILTIN_KIND_BY_TAG as L,BUILTIN_PAGE_COMPONENT_TAGS as E,DISPLAY_PAGE_COMPONENT_TAGS as R,pageComponentTag as M}from"./page-catalog.js";import{isResponseBearingSlot as F,pageDeliverySchema as B,validateAuthoredPageManifest as G,validatePageManifest as J}from"./page-schema.js";import{evaluatePageTree as K,jsonProps as U}from"./page-eval.js";import{PageAuthoringError as s,PageCompilerError as $}from"./page-errors.js";const T=D(import.meta.url);let X,H;function k(){return X??=T("esbuild")}i(k,"esbuild");function A(){return H??=T("typescript")}i(A,"typescript");function Y(t){return t instanceof s?t:new s(t instanceof Error?t.message:String(t))}i(Y,"asPageAuthoringError");function j(t,e){try{const n=G(t,e),r=n.slots.filter(F);if(r.length>=2)for(const o of r){const a=o.config.label;if(typeof a!="string"||a==="")throw new s(`response-bearing slot "${o.id}" requires a nonempty config.label when the page has multiple response-bearing slots`)}return n}catch(n){throw Y(n)}}i(j,"validateAuthoredManifest");const z="a page is evaluated with React and every registry component already in scope, so it takes no imports \u2014 write `<Page>`, `<UserQuestion>`, `<Card>` and friends directly.";function Q(t){return k().transformSync(t,{loader:"tsx",format:"cjs",jsx:"transform",jsxFactory:"React.createElement",jsxFragment:"React.Fragment",target:"es2020",sourcefile:"page.tsx"}).code}i(Q,"transformPage");function V(t){let e;for(let n=0;n<2;n++)try{return Q(t)}catch(r){const o=r.errors?.[0];if(o!==void 0){const a=o.location==null?"":` (page.tsx:${o.location.line}:${o.location.column})`;throw new s(`page does not compile: ${o.text??"unknown error"}${a}`)}e=r,k().stop()}throw new $(`page compiler (esbuild) service failed and did not recover after a restart: ${e instanceof Error?e.message:String(e)}`)}i(V,"compilePage");function W(t){const e=A();return e.createSourceFile("page.tsx",t,e.ScriptTarget.ES2022,!0,e.ScriptKind.TSX)}i(W,"parseTsx");function I(t,e){e(t),t.forEachChild(n=>I(n,e))}i(I,"eachNode");function Z(t){const e=A();let n;if(I(t,r=>{n===void 0&&(e.isImportDeclaration(r)||e.isImportEqualsDeclaration(r)?n="import":e.isExportDeclaration(r)&&r.moduleSpecifier!==void 0?n="export \u2026 from":e.isCallExpression(r)&&(r.expression.kind===e.SyntaxKind.ImportKeyword?n="dynamic import()":e.isIdentifier(r.expression)&&r.expression.text==="require"&&(n="require()")))}),n!==void 0)throw new s(`page source uses ${n}: ${z}`)}i(Z,"rejectModulePlumbing");function N(t,e){const n=t[e];if(n!==void 0){if(typeof n!="string")throw new s(`<Page> prop ${e} must be a string; it is part of the page manifest`);return n}}i(N,"stringProp");function ee(t,e,n){Z(W(t));const r=[...E,...R,...n.map(l=>M(l.kind))],o=K(e,r),a=[],h=i(l=>{for(const c of l)c.kind!=="text"&&(c.tag==="Page"&&a.push(c),h(c.children))},"collectPages");if(h(o),a.length===0)throw new s('page default export must render exactly one <Page title="\u2026"> root; it rendered none');if(a.length>1)throw new s(`page default export renders ${a.length} <Page> elements; exactly one is allowed`);const f=a[0],w=(N(f.props,"title")??"").trim();if(w==="")throw new s("<Page> requires a nonempty title prop");const g=N(f.props,"subtitle")?.trim();if(f.props.placement!==void 0)throw new s("<Page> placement is not authored; choose --placement inline or --placement panel when sending the page.");const d=new Map;for(const l of n){const c=M(l.kind);if(E.has(c))throw new s(`product page component kind "${l.kind}" derives JSX tag "${c}", which collides with a built-in page component`);if(d.has(c))throw new s(`product page component kind "${l.kind}" derives JSX tag "${c}", which duplicates product page component kind "${d.get(c)}"`);d.set(c,l.kind)}const x=[];let y=0;const P=i((l,c)=>{for(const p of l){if(p.kind==="text")continue;const S=p.tag==="Step"?y++:c,m=L[p.tag],b=d.get(p.tag);if(m!==void 0||b!==void 0){const{id:u,...C}=U(p.props);if(u!==void 0&&typeof u!="string")throw new s(`<${p.tag}> id prop must be a string`);x.push({...u===void 0?{}:{id:u},kind:m??b,step:S,config:C,...m===void 0?{unvalidated:!0}:{}})}P(p.children,S)}},"collectSlots");return P(f.children,0),{title:w,...g===void 0||g===""?{}:{subtitle:g},steps:Math.max(y,1),slots:x}}i(ee,"scanPage");function te(t,e=[],n,r={placement:"inline",inbox:!1,reply:!1}){const o=ee(t,V(t),e);return j({schema:"crtr.page/v2",dialect:"jsx",title:o.title,...o.subtitle===void 0?{}:{subtitle:o.subtitle},delivery:r,document:"page.tsx",steps:o.steps,slots:o.slots,...n===void 0?{}:{source:n}},e)}i(te,"derivePageManifestFromDocument");function ne(t){const e=/<title\b[^>]*>([\s\S]*?)<\/title\s*>/i.exec(t)?.[1]?.replace(/<[^>]+>/g,"").trim();if(e===void 0||e==="")throw new s("HTML page requires a nonempty <title>.");const n=[...t.matchAll(/<meta\b[^>]*>/gi)].map(r=>r[0]).map(r=>{const o=new Map([...r.matchAll(/\b([^\s=/>]+)\s*=\s*(["'])([\s\S]*?)\2/g)].map(a=>[a[1].toLowerCase(),a[3]]));return o.get("name")?.toLowerCase()==="description"?o.get("content")?.trim():void 0}).find(r=>r!==void 0);return{title:e,...n===void 0||n===""?{}:{subtitle:n}}}i(ne,"htmlMetadata");function fe(t,e,n={placement:"inline",inbox:!1,reply:!1}){const r=ne(t);return j({schema:"crtr.page/v2",dialect:"html",...r,delivery:n,document:"page.html",steps:1,slots:[],...e===void 0?{}:{source:e}},[])}i(fe,"deriveHtmlPageManifest");function de(t,e=[],n,r){return te(v(t,"utf8"),e,n,r)}i(de,"derivePageManifest");function _(t){try{return JSON.parse(v(O(t,"page.json"),"utf8"))}catch{throw new s("page.json is not valid JSON")}}i(_,"readPageJson");function ue(t){return J(_(t))}i(ue,"parsePage");function ge(t){const e=_(t),n=B.safeParse(typeof e=="object"&&e!==null&&!Array.isArray(e)?e.delivery:void 0);if(!n.success)throw new s("page.json has an invalid delivery envelope");return n.data}i(ge,"parsePageDelivery");export{s as PageAuthoringError,$ as PageCompilerError,V as compilePage,fe as deriveHtmlPageManifest,de as derivePageManifest,te as derivePageManifestFromDocument,ue as parsePage,ge as parsePageDelivery};
|
package/dist/core/peer/ingest.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var g=Object.defineProperty;var c=(e,t)=>g(e,"name",{value:t,configurable:!0});import{prepared as d}from"../sqlite-statements.js";import{CrtrError as k}from"../errors.js";import{getById as S,getByRowid as
|
|
1
|
+
var g=Object.defineProperty;var c=(e,t)=>g(e,"name",{value:t,configurable:!0});import{prepared as d}from"../sqlite-statements.js";import{CrtrError as k}from"../errors.js";import{getById as S,getByRowid as O}from"../graph/objects.js";import{publish as L}from"../graph/events.js";import{markLinkWatch as h,recordWatch as A}from"../graph/watches.js";import{ackRows as x,claimRows as T}from"./outbox-store.js";import{ensureStub as E,localOwnerActor as w,stubOf as f}from"./stubs.js";const K=100,y=c((e,t)=>`peer:${e}:${t}`,"ingestKey");function $(e,t){return d(e,"SELECT 1 FROM peer_ingested WHERE key = ?").get(t)!==void 0?!0:d(e,"SELECT 1 FROM deliveries WHERE idempotency_key >= ? AND idempotency_key < ? LIMIT 1").get(`${t}:`,`${t};`)!==void 0}c($,"applied");const m=c((e,t,n)=>{d(e,"INSERT OR IGNORE INTO peer_ingested_destinations (key, ingested_at) VALUES (?, ?)").run(`${t}:${n}`,Date.now())},"markDestination");function N(e,t,n){return d(e,"SELECT 1 FROM peer_ingested_destinations WHERE key = ?").get(`${t}:${n}`)!==void 0||d(e,"SELECT 1 FROM deliveries WHERE idempotency_key = ?").get(`${t}:${n}`)!==void 0}c(N,"destinationDone");function I(e,t,n){return w(e,t)??E(e,t.id,t.type,n,void 0,t)}c(I,"actorFor");function _(e,t,n,r,i){const s=n.actor===null?null:I(e,n.actor,t),u=n.body_text,o=n.body===void 0&&u===void 0?void 0:{...n.body??{},...u===void 0?{}:{body:u}};L(e,{event:n.event,object:r,actor:s,level:n.level,attrs:n.attrs,...o===void 0?{}:{messageBody:o},idempotencyKey:y(t,n.message_id),...i===void 0?{}:{onlyWatchers:i}})}c(_,"apply");function C(e,t){const n=`ev:${t.message_id}:`;if(!t.key.startsWith(n)||t.key.length===n.length)return null;const r=S(e,t.key.slice(n.length));return r!==null&&r.type==="node"&&r.deleted_at===null&&f(e,r)===null?r:null}c(C,"localDestination");function P(e,t,n){const r={accepted:[],rejected:[]};for(const i of n){const s=y(t,i.message_id),u=$(e,s);e.exec("SAVEPOINT peer_event");try{const o=C(e,i);if(u&&o===null){e.exec("RELEASE peer_event"),r.accepted.push(i.key);continue}const l=E(e,i.object.id,i.object.type,t,void 0,i.object),a=i.linked===!0&&o!==null&&l.owner!==null?O(e,l.owner):null,p=a!==null&&a.type==="app"?a:null;if(o!==null&&d(e,"SELECT 1 FROM watches WHERE watcher = ? AND object = ?").get(o.rowid,l.rowid)===void 0?A(e,o,l,"act",{patterns:[">"],...p===null?{}:{linkApp:p}}):o!==null&&p!==null&&h(e,o,l,p),u)N(e,s,o.id)||_(e,t,i,l,[o.id]);else{_(e,t,i,l),d(e,"INSERT OR IGNORE INTO peer_ingested (key, ingested_at) VALUES (?, ?)").run(s,Date.now());for(const R of d(e,"SELECT destination_id FROM deliveries WHERE idempotency_key >= ? AND idempotency_key < ?").all(`${s}:`,`${s};`))m(e,s,R.destination_id)}o!==null&&m(e,s,o.id),e.exec("RELEASE peer_event"),r.accepted.push(i.key)}catch(o){e.exec("ROLLBACK TO peer_event"),e.exec("RELEASE peer_event");const l=o instanceof k?o.code:"invalid_event";r.rejected.push({key:i.key,code:l,message:o instanceof Error?o.message:String(o)})}}return r}c(P,"ingestPeerEvents");const v=c((e,t,n)=>f(e,t)?.home_machine===n,"isStubOf"),G=c((e,t,n)=>T(e,t,n),"claimFor"),U=c((e,t,n)=>x(e,t,n),"ackFor");export{K as MAX_EVENTS_PER_CALL,U as ackFor,G as claimFor,y as ingestKey,P as ingestPeerEvents,v as isStubOf};
|
|
@@ -52,6 +52,10 @@ export interface StubRecord {
|
|
|
52
52
|
export declare const identityOfEnvelope: (envelope: Envelope) => StubIdentity;
|
|
53
53
|
export declare function stubOf(db: DatabaseSync, object: ObjectRow | string): StubRecord | null;
|
|
54
54
|
export declare const isStub: (db: DatabaseSync, object: ObjectRow) => boolean;
|
|
55
|
+
/** The local object for an app or person the other machine names as an event's actor, or null for any other type. An app or person is an
|
|
56
|
+
* owner, not a thing that lives on one machine: it is the same object here as there, so it is never given a stub (a stub would collide
|
|
57
|
+
* with the local owner object of the same handle, as with an installed plugin's app). */
|
|
58
|
+
export declare function localOwnerActor(db: DatabaseSync, ref: ObjectRef): ObjectRow | null;
|
|
55
59
|
/**
|
|
56
60
|
* The stub of the object `id` that lives on `machine`, created on first sight. Idempotent: a second
|
|
57
61
|
* call returns the same row and, given an `envelope`, replaces the identity it stores. Refuses
|
package/dist/core/peer/stubs.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var x=Object.defineProperty;var o=(n,e)=>x(n,"name",{value:e,configurable:!0});import{prepared as i}from"../sqlite-statements.js";import{createObject as A,ensureOwner as
|
|
1
|
+
var x=Object.defineProperty;var o=(n,e)=>x(n,"name",{value:e,configurable:!0});import{prepared as i}from"../sqlite-statements.js";import{createObject as A,ensureOwner as h,getById as y,getByRowid as p}from"../graph/objects.js";import{upsertKind as b}from"../graph/custom.js";import{CrtrError as f}from"../errors.js";import{ExitCode as m}from"../../types.js";import{normalizeMachineId as H}from"./names.js";const W=["public","friends","private"],D=o(n=>{const e=n.act.act;return e===void 0?{sub:n.sub,app:null,node:null,node_scopes:null,place:null}:{sub:n.sub,app:e.sub,node:e.node,node_scopes:e.node_scopes,place:e.place}},"identityOfEnvelope");function S(n,e){const r=typeof e=="string"?y(n,e):e;if(r===null)return null;const t=i(n,"SELECT home_machine, envelope_json FROM peer_stubs WHERE object = ?").get(r.rowid);return t?{object:r,home_machine:t.home_machine,identity:t.envelope_json===null?null:JSON.parse(t.envelope_json)}:null}o(S,"stubOf");const I=o((n,e)=>i(n,"SELECT 1 FROM peer_stubs WHERE object = ?").get(e.rowid)!==void 0,"isStub");function E(n){return h(n,"person","local-user","user:local","user")}o(E,"localPerson");function w(n,e){return e==="user:local"?E(n):h(n,"app","app",e,e.replace(/^app:/,""))}o(w,"localApp");function F(n,e){return e.type==="app"?w(n,`app:${e.name}`):e.type==="person"?E(n):null}o(F,"localOwnerActor");function v(n,e,r){if(e!==null)return e.app===null?E(n):w(n,e.app);const t=r?.owner;return t?.type==="app"?w(n,t.external_id??`app:${t.handle}`):E(n)}o(v,"ownerFor");function N(n,e,r,t,_,u){const l=_===void 0?null:D(_),s=u?.privacy??"public";if(!W.includes(s))throw new f("invalid_event",`invalid privacy ${JSON.stringify(s)}`,m.GENERAL,{id:e});const c=y(n,e);if(c!==null){const d=S(n,c);if(d===null)throw new f("conflict",`${e} is a local ${c.type}, not a stub of ${t}`,m.GENERAL,{id:e});if(d.home_machine!==t)throw new f("conflict",`${e} is already a stub of ${d.home_machine}, not ${t}`,m.GENERAL,{id:e,home_machine:d.home_machine});return l!==null&&(i(n,"UPDATE peer_stubs SET envelope_json = ? WHERE object = ?").run(JSON.stringify(l),c.rowid),i(n,"UPDATE objects SET reception = 2 WHERE rowid = ?").run(c.rowid)),u!==void 0&&(R(n,r,u),u.privacy!==void 0&&c.privacy!==s)?(i(n,"UPDATE objects SET privacy = ? WHERE rowid = ?").run(s,c.rowid),p(n,c.rowid)):c}const O=v(n,l,u);R(n,r,u);const a=A(n,{id:e,type:r,kind:u?.kind??null,owner:O.rowid,privacy:s,name:u?.name??e,preview:u?.preview??""});return i(n,"UPDATE objects SET home_machine = ? WHERE rowid = ?").run(t,a.rowid),i(n,"INSERT INTO peer_stubs (object, home_machine, envelope_json, created_at) VALUES (?, ?, ?, ?)").run(a.rowid,t,l===null?null:JSON.stringify(l),new Date().toISOString()),l!==null&&i(n,"UPDATE objects SET reception = 2 WHERE rowid = ?").run(a.rowid),p(n,a.rowid)}o(N,"ensureStub");function R(n,e,r){const t=r?.kind_decl;t===void 0||t.name!==e||b(n,{name:t.name,owner:v(n,null,{...r,owner:t.owner}),description:t.description,events:t.events,read:null,source:"peer"})}o(R,"holdKind");function J(n,e,r){const t=N(n,e,"node",H(r));return i(n,"UPDATE objects SET reception = 2 WHERE rowid = ?").run(t.rowid),p(n,t.rowid)}o(J,"ensureNodeStub");function M(n,e,r){const t=S(n,e);t===null||t.home_machine===r||(i(n,"UPDATE peer_stubs SET home_machine = ? WHERE object = ?").run(r,t.object.rowid),i(n,"UPDATE objects SET home_machine = ? WHERE rowid = ?").run(r,t.object.rowid))}o(M,"rehomeStub");function G(n,e){const r=j(n,e.owner===null?null:p(n,e.owner)),t=T(n,e.type);return{id:e.id,type:e.type,kind:e.kind,name:e.name,preview:e.preview,owner:r,privacy:e.privacy,...t===null?{}:{kind_decl:t}}}o(G,"describeObject");function j(n,e){if(e===null||e.type!=="person"&&e.type!=="app"&&e.type!=="repo"&&e.type!=="profile")return null;const r=i(n,"SELECT scheme, external_id FROM identities WHERE object = ?").get(e.rowid);return{id:e.id,type:e.type,scheme:r?.scheme??null,external_id:r?.external_id??null,handle:e.name}}o(j,"ownerRefOf");function T(n,e){const r=i(n,"SELECT owner, description, events_json FROM object_kinds WHERE name = ?").get(e),t=r===void 0?null:j(n,p(n,r.owner));return r===void 0||t===null?null:{name:e,description:r.description,events:JSON.parse(r.events_json),owner:t}}o(T,"kindDeclarationOf");function K(n,e,r){const t=T(n,e.type);return t===null?r:{...r,kind_decl:t}}o(K,"withKindDecl");export{G as describeObject,J as ensureNodeStub,N as ensureStub,D as identityOfEnvelope,I as isStub,T as kindDeclarationOf,F as localOwnerActor,M as rehomeStub,S as stubOf,K as withKindDecl};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** Request header naming the sending machine's crtr release. */
|
|
2
2
|
export declare const PEER_VERSION_HEADER = "Crtr-Version";
|
|
3
|
-
/** The oldest crtr release that speaks the peer protocol.
|
|
4
|
-
export declare const PEER_VERSION_FLOOR = "0.3.
|
|
3
|
+
/** The oldest crtr release that speaks the peer protocol. 0.3.487 is the first release whose app listener verifies peer tokens with `verifyCallToken` (peer authority), so it can take tokens without `machine_id`/`grantee`. */
|
|
4
|
+
export declare const PEER_VERSION_FLOOR = "0.3.487";
|
|
5
5
|
export interface PeerVersionRefusal {
|
|
6
6
|
status: 426;
|
|
7
7
|
code: 'peer_version_too_old';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var n=Object.defineProperty;var i=(r,e)=>n(r,"name",{value:e,configurable:!0});import{compareReleaseVersions as a}from"../../api/runtime-version.js";import{crtrVersion as o}from"../../shared/crtr-version.js";const l="Crtr-Version",c="0.3.
|
|
1
|
+
var n=Object.defineProperty;var i=(r,e)=>n(r,"name",{value:e,configurable:!0});import{compareReleaseVersions as a}from"../../api/runtime-version.js";import{crtrVersion as o}from"../../shared/crtr-version.js";const l="Crtr-Version",c="0.3.487";function d(r,e=c,s=o()){const t=r?.trim()?r.trim():null;return t!==null&&a(t,e)>=0?null:{status:426,code:"peer_version_too_old",message:t===null?`The peer did not name its crtr version; machines below ${e} cannot take part (this machine is ${s}). Update it with \`crtr sys update\`.`:`The peer runs crtr ${t}; machines below ${e} cannot take part (this machine is ${s}). Update it with \`crtr sys update\`.`,details:{peer_version:t,floor:e,receiver_version:s}}}i(d,"peerVersionRefusal");export{c as PEER_VERSION_FLOOR,l as PEER_VERSION_HEADER,d as peerVersionRefusal};
|
package/dist/core/render.js
CHANGED
|
@@ -12,7 +12,6 @@ ${c}`}u(b,"renderArray");function O(e,n){const s=n.output.map(t=>t.name);for(con
|
|
|
12
12
|
`));const d=c.length>1;for(const{name:t,text:r}of c)i.push(d?`**${t}:** ${r}`:r);for(const t of o)i.push(t);return i.join(`
|
|
13
13
|
|
|
14
14
|
`)}u(O,"renderResult");function _(e){const n=[e.message];return e.received!==void 0&&e.received!==null&&e.received!==""&&n.push(`received: ${f(e.received)}`),e.field!==void 0&&n.push(`field: ${e.field}`),e.http_status!==void 0&&n.push(`http status: ${e.http_status}`),e.retry_after_s!==void 0&&n.push(`retry after: ${e.retry_after_s}s`),e.details!==void 0&&Object.keys(e.details).length>0&&n.push(O(e.details,{output:[]})),"primaryCompleted"in e&&e.primaryCompleted===!0&&(n.push("primaryCompleted: true"),n.push(`Primary result (the command already completed):
|
|
15
|
-
${m(e.result)}`)),n.push(`Next: ${e.next}`),`<error code="${$(e.error)}"
|
|
16
|
-
${n.join(`
|
|
15
|
+
${m(e.result)}`)),n.push(`Next: ${e.next}`),`<error code="${$(e.error)}">${n.join(`
|
|
17
16
|
`)}
|
|
18
17
|
</error>`}u(_,"renderError");export{_ as renderError,O as renderResult};
|