@vercel/factory 0.0.16 → 0.0.18
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/CHANGELOG.md +52 -0
- package/dist/api-contracts.d.mts +665 -715
- package/dist/api-contracts.mjs +91 -4
- package/dist/api-contracts.mjs.map +1 -1
- package/dist/api-task-graph.mjs +14 -5
- package/dist/api-task-graph.mjs.map +1 -1
- package/dist/api.d.mts +58 -11
- package/dist/api.mjs +715 -399
- package/dist/api.mjs.map +1 -1
- package/dist/approval-access.d.mts +1 -1
- package/dist/approval-contracts.d.mts +3 -4
- package/dist/approval-contracts.mjs +1 -2
- package/dist/approval-contracts.mjs.map +1 -1
- package/dist/blob/index.d.mts +1 -1
- package/dist/budget.mjs +20 -3
- package/dist/budget.mjs.map +1 -1
- package/dist/change-verification/brief.d.mts +1 -1
- package/dist/change-verification/dispatch.mjs +8 -1
- package/dist/change-verification/dispatch.mjs.map +1 -1
- package/dist/changes/eve-record-change.mjs +4 -1
- package/dist/changes/eve-record-change.mjs.map +1 -1
- package/dist/client-stream.d.mts +19 -2
- package/dist/client-stream.mjs +115 -53
- package/dist/client-stream.mjs.map +1 -1
- package/dist/client-transcript.d.mts +25 -2
- package/dist/client-transcript.mjs +95 -13
- package/dist/client-transcript.mjs.map +1 -1
- package/dist/client.d.mts +145 -19
- package/dist/client.mjs +89 -16
- package/dist/client.mjs.map +1 -1
- package/dist/code-review/contracts.d.mts +1 -0
- package/dist/code-review/eve-post-review.d.mts +4 -2
- package/dist/code-review/eve-post-review.mjs +8 -0
- package/dist/code-review/eve-post-review.mjs.map +1 -1
- package/dist/code-review/github-reporter.d.mts +6 -2
- package/dist/code-review/github-reporter.mjs +86 -35
- package/dist/code-review/github-reporter.mjs.map +1 -1
- package/dist/code-review/preparation.d.mts +2 -1
- package/dist/code-review/preparation.mjs +2 -1
- package/dist/code-review/preparation.mjs.map +1 -1
- package/dist/code-review/stall.mjs +11 -2
- package/dist/code-review/stall.mjs.map +1 -1
- package/dist/connectors/github.d.mts +1 -1
- package/dist/connectors/index.d.mts +1 -1
- package/dist/connectors/slack.d.mts +1 -1
- package/dist/delivery-metrics/metrics.d.mts +1 -1
- package/dist/dispatch.mjs +3 -3
- package/dist/dispatch.mjs.map +1 -1
- package/dist/eve/index.d.mts +1 -1
- package/dist/eve/index.mjs +8 -1
- package/dist/eve/index.mjs.map +1 -1
- package/dist/eve/task-execution.d.mts +4 -4
- package/dist/eve/transcript.d.mts +3 -1
- package/dist/eve/transcript.mjs.map +1 -1
- package/dist/finding-remediation/admission.d.mts +1 -1
- package/dist/finding-remediation/brief.d.mts +1 -1
- package/dist/github-app.d.mts +1 -1
- package/dist/github-publication.d.mts +1 -1
- package/dist/github.d.mts +9 -1
- package/dist/github.mjs +29 -11
- package/dist/github.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/intake-contracts.d.mts +1 -0
- package/dist/intake-contracts.mjs +2 -1
- package/dist/intake-contracts.mjs.map +1 -1
- package/dist/integrations/github-issues.d.mts +53 -0
- package/dist/integrations/github-issues.mjs +170 -0
- package/dist/integrations/github-issues.mjs.map +1 -0
- package/dist/integrations/github.d.mts +2 -1
- package/dist/integrations/github.mjs +2 -1
- package/dist/multi-repository-changes/coordination.mjs +1 -1
- package/dist/planning/reconcile.mjs +15 -2
- package/dist/planning/reconcile.mjs.map +1 -1
- package/dist/postgres/index.d.mts +2 -1
- package/dist/postgres/index.mjs +11 -5
- package/dist/postgres/index.mjs.map +1 -1
- package/dist/postgres/indexed-codec.mjs +137 -0
- package/dist/postgres/indexed-codec.mjs.map +1 -0
- package/dist/postgres/indexed-schema.mjs +99 -0
- package/dist/postgres/indexed-schema.mjs.map +1 -0
- package/dist/postgres/indexed.d.mts +28 -0
- package/dist/postgres/indexed.mjs +277 -0
- package/dist/postgres/indexed.mjs.map +1 -0
- package/dist/postgres/record-predicates.mjs +23 -0
- package/dist/postgres/record-predicates.mjs.map +1 -0
- package/dist/presets/software-development/deepsec-brief.d.mts +1 -1
- package/dist/presets/software-development/dispatch.mjs +1 -1
- package/dist/presets/software-development/dispatch.mjs.map +1 -1
- package/dist/presets/software-development/recovery.mjs +9 -2
- package/dist/presets/software-development/recovery.mjs.map +1 -1
- package/dist/pull-requests/eve-fetch.d.mts +4 -1
- package/dist/pull-requests/eve-fetch.mjs +9 -0
- package/dist/pull-requests/eve-fetch.mjs.map +1 -1
- package/dist/pull-requests/github-publisher.d.mts +1 -1
- package/dist/pull-requests/github-publisher.mjs +19 -7
- package/dist/pull-requests/github-publisher.mjs.map +1 -1
- package/dist/repositories.mjs +20 -13
- package/dist/repositories.mjs.map +1 -1
- package/dist/sandbox/execution-run-ledger.d.mts +2 -2
- package/dist/sandbox/execution-run-ledger.mjs.map +1 -1
- package/dist/sandbox/execution.d.mts +2 -2
- package/dist/sandbox/execution.mjs.map +1 -1
- package/dist/schema/catalog.mjs +1 -1
- package/dist/schema/change.d.mts +1 -1
- package/dist/schema/communication.d.mts +2 -2
- package/dist/schema/factory-config.d.mts +1 -1
- package/dist/schema/outbox.d.mts +6 -6
- package/dist/schema/session-summary.d.mts +218 -0
- package/dist/schema/session-summary.mjs +68 -0
- package/dist/schema/session-summary.mjs.map +1 -0
- package/dist/schema/session.d.mts +39 -59
- package/dist/schema/session.mjs +6 -6
- package/dist/schema/session.mjs.map +1 -1
- package/dist/schema/task-graph.d.mts +24 -24
- package/dist/schema/transcript.d.mts +141 -3
- package/dist/schema/transcript.mjs +19 -3
- package/dist/schema/transcript.mjs.map +1 -1
- package/dist/schema/transitions.d.mts +1 -1
- package/dist/schema/transitions.mjs +1 -1
- package/dist/schema/transitions.mjs.map +1 -1
- package/dist/signals.d.mts +1 -1
- package/dist/stall.mjs +10 -2
- package/dist/stall.mjs.map +1 -1
- package/dist/storage.d.mts +10 -1
- package/dist/storage.mjs +7 -1
- package/dist/store/approvals.d.mts +14 -0
- package/dist/store/approvals.mjs +78 -0
- package/dist/store/approvals.mjs.map +1 -0
- package/dist/store/conversations.d.mts +59 -0
- package/dist/store/conversations.mjs +549 -0
- package/dist/store/conversations.mjs.map +1 -0
- package/dist/store/driver.d.mts +1 -1
- package/dist/store/driver.mjs.map +1 -1
- package/dist/store/engine.d.mts +38 -16
- package/dist/store/engine.mjs +229 -106
- package/dist/store/engine.mjs.map +1 -1
- package/dist/store/indexed-engine.d.mts +57 -0
- package/dist/store/indexed-engine.mjs +155 -0
- package/dist/store/indexed-engine.mjs.map +1 -0
- package/dist/store/indexed-memory.d.mts +7 -0
- package/dist/store/indexed-memory.mjs +200 -0
- package/dist/store/indexed-memory.mjs.map +1 -0
- package/dist/store/indexed-projections.d.mts +280 -0
- package/dist/store/indexed-projections.mjs +481 -0
- package/dist/store/indexed-projections.mjs.map +1 -0
- package/dist/store/indexed.d.mts +101 -0
- package/dist/store/indexed.mjs +19 -0
- package/dist/store/indexed.mjs.map +1 -0
- package/dist/store/iterate.d.mts +9 -0
- package/dist/store/iterate.mjs +23 -0
- package/dist/store/iterate.mjs.map +1 -0
- package/dist/store/query-scope.mjs +62 -0
- package/dist/store/query-scope.mjs.map +1 -0
- package/dist/store/query.d.mts +32 -0
- package/dist/store/query.mjs +103 -0
- package/dist/store/query.mjs.map +1 -0
- package/dist/store/session-history.mjs +24 -0
- package/dist/store/session-history.mjs.map +1 -0
- package/dist/store/slack-pr-notifications.d.mts +2 -2
- package/dist/store/slack-pr-notifications.mjs.map +1 -1
- package/dist/store/state.d.mts +26 -0
- package/dist/store/state.mjs +95 -0
- package/dist/store/state.mjs.map +1 -0
- package/dist/store/task-effects.d.mts +1 -1
- package/dist/store/task-graphs.d.mts +1 -1
- package/dist/store/task-messages.d.mts +1 -1
- package/dist/store/task-work.d.mts +1 -1
- package/dist/store/task-work.mjs +1 -1
- package/dist/store/transcripts.mjs +308 -0
- package/dist/store/transcripts.mjs.map +1 -0
- package/dist/sweep.d.mts +1 -1
- package/dist/sweep.mjs +12 -7
- package/dist/sweep.mjs.map +1 -1
- package/dist/task-communication.mjs +15 -1
- package/dist/task-communication.mjs.map +1 -1
- package/dist/task-protocols.d.mts +3 -3
- package/dist/tasks.d.mts +1 -1
- package/dist/vercel.d.mts +1 -1
- package/dist/work-triage/find-existing-work.d.mts +1 -1
- package/dist/work-triage/find-existing-work.mjs +12 -2
- package/dist/work-triage/find-existing-work.mjs.map +1 -1
- package/docs/index.md +4 -0
- package/docs/recipes/persistence-recovery.md +15 -9
- package/docs/recipes/postgres-indexed-engine.md +108 -0
- package/docs/recipes/postgres-indexed-storage.md +145 -0
- package/package.json +6 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transitions.mjs","names":[],"sources":["../../src/schema/transitions.ts"],"sourcesContent":["import type { ChangeState } from \"./change\";\nimport type { SignalOutcome, SignalTriage } from \"./signal\";\nimport type { TaskState } from \"./task\";\n\n/** Authority category responsible for advancing a state-machine edge. */\nexport type TransitionActor =\n | \"system\"\n | \"reconciler\"\n | \"foreman\"\n | \"operator\"\n | \"webhook\"\n | \"human\";\n\n/** Inspectable legal edge in a Factory state machine. */\nexport interface Transition<State extends string> {\n readonly from: State;\n readonly to: State;\n readonly trigger: string;\n readonly actor: TransitionActor;\n}\n\n/** Named source and destination states for a transition check. */\nexport interface TransitionInput<State extends string> {\n readonly from: NoInfer<State>;\n readonly to: NoInfer<State>;\n}\n\n/** Required lifecycle state assigned when a Task is admitted. */\nexport const taskInitialState = \"queued\" satisfies TaskState;\n\n/** Canonical legal Task lifecycle edges and their responsible authorities. */\nexport const taskTransitions: readonly Transition<TaskState>[] = [\n {\n from: \"queued\",\n to: \"running\",\n trigger: \"graph prerequisites succeeded, dependencies sealed, workflow admission approved\",\n actor: \"reconciler\",\n },\n { from: \"queued\", to: \"failed\", trigger: \"reservation refused\", actor: \"reconciler\" },\n {\n from: \"queued\",\n to: \"needs_human\",\n trigger: \"workflow presents a human question\",\n actor: \"system\",\n },\n { from: \"queued\", to: \"cancelled\", trigger: \"cancel or kill\", actor: \"operator\" },\n {\n from: \"running\",\n to: \"verifying\",\n trigger: \"workflow requests verification of its result\",\n actor: \"reconciler\",\n },\n {\n from: \"running\",\n to: \"queued\",\n trigger: \"launch or execution failed below attempt limit\",\n actor: \"reconciler\",\n },\n {\n from: \"running\",\n to: \"failed\",\n trigger: \"execution or launch failed at attempt limit\",\n actor: \"reconciler\",\n },\n {\n from: \"running\",\n to: \"needs_human\",\n trigger: \"an open QuestionTask requests human input or action\",\n actor: \"reconciler\",\n },\n { from: \"running\", to: \"cancelled\", trigger: \"cancel or kill\", actor: \"operator\" },\n {\n from: \"running\",\n to: \"stalled\",\n trigger: \"no progress within the stall window\",\n actor: \"reconciler\",\n },\n {\n from: \"running\",\n to: \"succeeded\",\n trigger: \"workflow completes with validated output\",\n actor: \"reconciler\",\n },\n {\n from: \"stalled\",\n to: \"queued\",\n trigger: \"replacement attempt below attempt limit, or operator retry\",\n actor: \"reconciler\",\n },\n { from: \"stalled\", to: \"failed\", trigger: \"attempt limit exhausted\", actor: \"reconciler\" },\n { from: \"stalled\", to: \"cancelled\", trigger: \"cancel or kill\", actor: \"operator\" },\n {\n from: \"verifying\",\n to: \"succeeded\",\n trigger: \"workflow verification completes with validated output\",\n actor: \"reconciler\",\n },\n {\n from: \"verifying\",\n to: \"running\",\n trigger: \"verification failed below attempt limit\",\n actor: \"reconciler\",\n },\n {\n from: \"verifying\",\n to: \"failed\",\n trigger: \"verification failed at attempt limit\",\n actor: \"reconciler\",\n },\n { from: \"verifying\", to: \"cancelled\", trigger: \"cancel or kill\", actor: \"operator\" },\n { from: \"needs_human\", to: \"succeeded\", trigger: \"question answered\", actor: \"operator\" },\n { from: \"needs_human\", to: \"queued\", trigger: \"operator retry\", actor: \"operator\" },\n { from: \"needs_human\", to: \"cancelled\", trigger: \"cancel or kill\", actor: \"operator\" },\n { from: \"failed\", to: \"queued\", trigger: \"operator retry\", actor: \"operator\" },\n];\n\n/** Required lifecycle state assigned when a Change is first recorded. */\nexport const changeInitialState = \"verifying\" satisfies ChangeState;\n\n/** Canonical legal Change lifecycle edges and their responsible authorities. */\nexport const changeTransitions: readonly Transition<ChangeState>[] = [\n {\n from: \"ready\",\n to: \"verifying\",\n trigger: \"a code_change task updated the existing pull request head\",\n actor: \"reconciler\",\n },\n {\n from: \"verifying\",\n to: \"ready\",\n trigger: \"configured verification policy completed, risk and confidence written\",\n actor: \"reconciler\",\n },\n {\n from: \"verifying\",\n to: \"closed\",\n trigger: \"verification failed at attempt limit or pr closed upstream\",\n actor: \"reconciler\",\n },\n { from: \"ready\", to: \"merged\", trigger: \"pr merged on github\", actor: \"webhook\" },\n { from: \"ready\", to: \"closed\", trigger: \"pr closed without merge\", actor: \"webhook\" },\n {\n from: \"merged\",\n to: \"deployed\",\n trigger: \"production deployment ready containing the merge sha\",\n actor: \"webhook\",\n },\n {\n from: \"deployed\",\n to: \"rolled_out\",\n trigger: \"no flag, or flag ramped to full and held\",\n actor: \"foreman\",\n },\n { from: \"deployed\", to: \"rolled_back\", trigger: \"rollback rule crossed\", actor: \"foreman\" },\n {\n from: \"rolled_out\",\n to: \"rolled_back\",\n trigger: \"rollback rule crossed or flag flipped off\",\n actor: \"foreman\",\n },\n { from: \"rolled_back\", to: \"deployed\", trigger: \"human retried the ramp\", actor: \"human\" },\n];\n\n/** Required outcome assigned when an inbound Signal is admitted. */\nexport const signalInitialOutcome = \"pending\" satisfies SignalOutcome;\n\n/** Canonical one-time Signal triage edges. */\nexport const signalOutcomeTransitions: readonly Transition<SignalOutcome>[] = [\n { from: \"pending\", to: \"accepted\", trigger: \"classified as actionable\", actor: \"reconciler\" },\n { from: \"pending\", to: \"duplicate\", trigger: \"classified as duplicate\", actor: \"reconciler\" },\n {\n from: \"pending\",\n to: \"unactionable\",\n trigger: \"classified as unactionable\",\n actor: \"reconciler\",\n },\n {\n from: \"pending\",\n to: \"low_confidence\",\n trigger: \"classified below confidence threshold\",\n actor: \"reconciler\",\n },\n { from: \"pending\", to: \"ignored\", trigger: \"classified as ignorable\", actor: \"reconciler\" },\n];\n\n/** Reports whether a state-machine table contains the requested directed edge. */\nexport function isTransitionAllowed<State extends string>(\n transitions: readonly Transition<State>[],\n input: TransitionInput<State>,\n): boolean {\n return transitions.some(\n (transition) => transition.from === input.from && transition.to === input.to,\n );\n}\n\n/** Returns the distinct states directly reachable from a given state. */\nexport function legalNextStates<State extends string>(\n transitions: readonly Transition<State>[],\n from: NoInfer<State>,\n): readonly State[] {\n return [\n ...new Set(transitions.filter((transition) => transition.from === from).map((t) => t.to)),\n ];\n}\n\n/** Error describing a refused state transition and every legal next state. */\nexport class InvalidTransitionError<State extends string> extends Error {\n readonly from: State;\n readonly to: State;\n readonly legalNextStates: readonly State[];\n\n constructor(from: State, to: State, legal: readonly State[]) {\n super(\n legal.length > 0\n ? `invalid transition from \"${from}\" to \"${to}\"; legal next states: ${legal\n .map((state) => `\"${state}\"`)\n .join(\", \")}`\n : `invalid transition from \"${from}\" to \"${to}\"; \"${from}\" is terminal`,\n );\n this.name = \"InvalidTransitionError\";\n this.from = from;\n this.to = to;\n this.legalNextStates = legal;\n }\n}\n\n/** Throws an {@link InvalidTransitionError} unless the requested edge is legal. */\nexport function assertTransition<State extends string>(\n transitions: readonly Transition<State>[],\n input: TransitionInput<State>,\n): void {\n if (!isTransitionAllowed(transitions, input)) {\n throw new InvalidTransitionError(\n input.from,\n input.to,\n legalNextStates(transitions, input.from),\n );\n }\n}\n\n/** Derives states with no outgoing edges from a transition table. */\nexport function terminalStates<State extends string>(\n transitions: readonly Transition<State>[],\n): readonly State[] {\n const states = new Set<State>();\n for (const transition of transitions) {\n states.add(transition.from);\n states.add(transition.to);\n }\n return [...states].filter(\n (state) => !transitions.some((transition) => transition.from === state),\n );\n}\n\n/** Canonical triage observation and explicit retry edges. */\nexport const signalTriageTransitions: readonly Transition<SignalTriage[\"state\"]>[] = [\n { from: \"running\", to: \"blocked\", trigger: \"provider stopped without deciding\", actor: \"system\" },\n { from: \"running\", to: \"uncertain\", trigger: \"launch response unavailable\", actor: \"system\" },\n { from: \"uncertain\", to: \"blocked\", trigger: \"provider confirmed stopped\", actor: \"system\" },\n { from: \"blocked\", to: \"running\", trigger: \"explicit operator retry\", actor: \"operator\" },\n];\n"],"mappings":";;AA4BA,MAAa,mBAAmB;;AAGhC,MAAa,kBAAoD;CAC/D;EACE,MAAM;EACN,IAAI;EACJ,SAAS;EACT,OAAO;CACT;CACA;EAAE,MAAM;EAAU,IAAI;EAAU,SAAS;EAAuB,OAAO;CAAa;CACpF;EACE,MAAM;EACN,IAAI;EACJ,SAAS;EACT,OAAO;CACT;CACA;EAAE,MAAM;EAAU,IAAI;EAAa,SAAS;EAAkB,OAAO;CAAW;CAChF;EACE,MAAM;EACN,IAAI;EACJ,SAAS;EACT,OAAO;CACT;CACA;EACE,MAAM;EACN,IAAI;EACJ,SAAS;EACT,OAAO;CACT;CACA;EACE,MAAM;EACN,IAAI;EACJ,SAAS;EACT,OAAO;CACT;CACA;EACE,MAAM;EACN,IAAI;EACJ,SAAS;EACT,OAAO;CACT;CACA;EAAE,MAAM;EAAW,IAAI;EAAa,SAAS;EAAkB,OAAO;CAAW;CACjF;EACE,MAAM;EACN,IAAI;EACJ,SAAS;EACT,OAAO;CACT;CACA;EACE,MAAM;EACN,IAAI;EACJ,SAAS;EACT,OAAO;CACT;CACA;EACE,MAAM;EACN,IAAI;EACJ,SAAS;EACT,OAAO;CACT;CACA;EAAE,MAAM;EAAW,IAAI;EAAU,SAAS;EAA2B,OAAO;CAAa;CACzF;EAAE,MAAM;EAAW,IAAI;EAAa,SAAS;EAAkB,OAAO;CAAW;CACjF;EACE,MAAM;EACN,IAAI;EACJ,SAAS;EACT,OAAO;CACT;CACA;EACE,MAAM;EACN,IAAI;EACJ,SAAS;EACT,OAAO;CACT;CACA;EACE,MAAM;EACN,IAAI;EACJ,SAAS;EACT,OAAO;CACT;CACA;EAAE,MAAM;EAAa,IAAI;EAAa,SAAS;EAAkB,OAAO;CAAW;CACnF;EAAE,MAAM;EAAe,IAAI;EAAa,SAAS;EAAqB,OAAO;CAAW;CACxF;EAAE,MAAM;EAAe,IAAI;EAAU,SAAS;EAAkB,OAAO;CAAW;CAClF;EAAE,MAAM;EAAe,IAAI;EAAa,SAAS;EAAkB,OAAO;CAAW;CACrF;EAAE,MAAM;EAAU,IAAI;EAAU,SAAS;EAAkB,OAAO;CAAW;AAC/E;;AAGA,MAAa,qBAAqB;;AAGlC,MAAa,oBAAwD;CACnE;EACE,MAAM;EACN,IAAI;EACJ,SAAS;EACT,OAAO;CACT;CACA;EACE,MAAM;EACN,IAAI;EACJ,SAAS;EACT,OAAO;CACT;CACA;EACE,MAAM;EACN,IAAI;EACJ,SAAS;EACT,OAAO;CACT;CACA;EAAE,MAAM;EAAS,IAAI;EAAU,SAAS;EAAuB,OAAO;CAAU;CAChF;EAAE,MAAM;EAAS,IAAI;EAAU,SAAS;EAA2B,OAAO;CAAU;CACpF;EACE,MAAM;EACN,IAAI;EACJ,SAAS;EACT,OAAO;CACT;CACA;EACE,MAAM;EACN,IAAI;EACJ,SAAS;EACT,OAAO;CACT;CACA;EAAE,MAAM;EAAY,IAAI;EAAe,SAAS;EAAyB,OAAO;CAAU;CAC1F;EACE,MAAM;EACN,IAAI;EACJ,SAAS;EACT,OAAO;CACT;CACA;EAAE,MAAM;EAAe,IAAI;EAAY,SAAS;EAA0B,OAAO;CAAQ;AAC3F;;AAGA,MAAa,uBAAuB;;AAGpC,MAAa,2BAAiE;CAC5E;EAAE,MAAM;EAAW,IAAI;EAAY,SAAS;EAA4B,OAAO;CAAa;CAC5F;EAAE,MAAM;EAAW,IAAI;EAAa,SAAS;EAA2B,OAAO;CAAa;CAC5F;EACE,MAAM;EACN,IAAI;EACJ,SAAS;EACT,OAAO;CACT;CACA;EACE,MAAM;EACN,IAAI;EACJ,SAAS;EACT,OAAO;CACT;CACA;EAAE,MAAM;EAAW,IAAI;EAAW,SAAS;EAA2B,OAAO;CAAa;AAC5F;;AAGA,SAAgB,oBACd,aACA,OACS;CACT,OAAO,YAAY,MAChB,eAAe,WAAW,SAAS,MAAM,QAAQ,WAAW,OAAO,MAAM,EAC5E;AACF;;AAGA,SAAgB,gBACd,aACA,MACkB;CAClB,OAAO,CACL,GAAG,IAAI,IAAI,YAAY,QAAQ,eAAe,WAAW,SAAS,IAAI,CAAC,CAAC,KAAK,MAAM,EAAE,EAAE,CAAC,CAC1F;AACF;;AAGA,IAAa,yBAAb,cAAkE,MAAM;CACtE;CACA;CACA;CAEA,YAAY,MAAa,IAAW,OAAyB;EAC3D,MACE,MAAM,SAAS,IACX,4BAA4B,KAAK,QAAQ,GAAG,wBAAwB,MACjE,KAAK,UAAU,IAAI,MAAM,EAAE,CAAC,CAC5B,KAAK,IAAI,MACZ,4BAA4B,KAAK,QAAQ,GAAG,MAAM,KAAK,cAC7D;EACA,KAAK,OAAO;EACZ,KAAK,OAAO;EACZ,KAAK,KAAK;EACV,KAAK,kBAAkB;CACzB;AACF;;AAGA,SAAgB,iBACd,aACA,OACM;CACN,IAAI,CAAC,oBAAoB,aAAa,KAAK,GACzC,MAAM,IAAI,uBACR,MAAM,MACN,MAAM,IACN,gBAAgB,aAAa,MAAM,IAAI,CACzC;AAEJ;;AAGA,SAAgB,eACd,aACkB;CAClB,MAAM,yBAAS,IAAI,IAAW;CAC9B,KAAK,MAAM,cAAc,aAAa;EACpC,OAAO,IAAI,WAAW,IAAI;EAC1B,OAAO,IAAI,WAAW,EAAE;CAC1B;CACA,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC,QAChB,UAAU,CAAC,YAAY,MAAM,eAAe,WAAW,SAAS,KAAK,CACxE;AACF;;AAGA,MAAa,0BAAwE;CACnF;EAAE,MAAM;EAAW,IAAI;EAAW,SAAS;EAAqC,OAAO;CAAS;CAChG;EAAE,MAAM;EAAW,IAAI;EAAa,SAAS;EAA+B,OAAO;CAAS;CAC5F;EAAE,MAAM;EAAa,IAAI;EAAW,SAAS;EAA8B,OAAO;CAAS;CAC3F;EAAE,MAAM;EAAW,IAAI;EAAW,SAAS;EAA2B,OAAO;CAAW;AAC1F"}
|
|
1
|
+
{"version":3,"file":"transitions.mjs","names":[],"sources":["../../src/schema/transitions.ts"],"sourcesContent":["import type { ChangeState } from \"./change\";\nimport type { SignalOutcome, SignalTriage } from \"./signal\";\nimport type { TaskState } from \"./task\";\n\n/** Authority category responsible for advancing a state-machine edge. */\nexport type TransitionActor =\n | \"system\"\n | \"reconciler\"\n | \"foreman\"\n | \"operator\"\n | \"webhook\"\n | \"human\";\n\n/** Inspectable legal edge in a Factory state machine. */\nexport interface Transition<State extends string> {\n readonly from: State;\n readonly to: State;\n readonly trigger: string;\n readonly actor: TransitionActor;\n}\n\n/** Named source and destination states for a transition check. */\nexport interface TransitionInput<State extends string> {\n readonly from: NoInfer<State>;\n readonly to: NoInfer<State>;\n}\n\n/** Required lifecycle state assigned when a Task is admitted. */\nexport const taskInitialState = \"queued\" satisfies TaskState;\n\n/** Canonical legal Task lifecycle edges and their responsible authorities. */\nexport const taskTransitions: readonly Transition<TaskState>[] = [\n {\n from: \"queued\",\n to: \"running\",\n trigger: \"graph prerequisites succeeded, dependencies sealed, workflow admission approved\",\n actor: \"reconciler\",\n },\n { from: \"queued\", to: \"failed\", trigger: \"reservation refused\", actor: \"reconciler\" },\n {\n from: \"queued\",\n to: \"needs_human\",\n trigger: \"workflow presents a human question\",\n actor: \"system\",\n },\n { from: \"queued\", to: \"cancelled\", trigger: \"cancel or kill\", actor: \"operator\" },\n {\n from: \"running\",\n to: \"verifying\",\n trigger: \"workflow requests verification of its result\",\n actor: \"reconciler\",\n },\n {\n from: \"running\",\n to: \"queued\",\n trigger: \"launch or execution failed below attempt limit\",\n actor: \"reconciler\",\n },\n {\n from: \"running\",\n to: \"failed\",\n trigger: \"execution or launch failed at attempt limit\",\n actor: \"reconciler\",\n },\n {\n from: \"running\",\n to: \"needs_human\",\n trigger: \"an open QuestionTask requests human input or action\",\n actor: \"reconciler\",\n },\n { from: \"running\", to: \"cancelled\", trigger: \"cancel or kill\", actor: \"operator\" },\n {\n from: \"running\",\n to: \"stalled\",\n trigger: \"no progress within the stall window or workflow pauses obsolete execution\",\n actor: \"reconciler\",\n },\n {\n from: \"running\",\n to: \"succeeded\",\n trigger: \"workflow completes with validated output\",\n actor: \"reconciler\",\n },\n {\n from: \"stalled\",\n to: \"queued\",\n trigger: \"replacement attempt below attempt limit, or operator retry\",\n actor: \"reconciler\",\n },\n { from: \"stalled\", to: \"failed\", trigger: \"attempt limit exhausted\", actor: \"reconciler\" },\n { from: \"stalled\", to: \"cancelled\", trigger: \"cancel or kill\", actor: \"operator\" },\n {\n from: \"verifying\",\n to: \"succeeded\",\n trigger: \"workflow verification completes with validated output\",\n actor: \"reconciler\",\n },\n {\n from: \"verifying\",\n to: \"running\",\n trigger: \"verification failed below attempt limit\",\n actor: \"reconciler\",\n },\n {\n from: \"verifying\",\n to: \"failed\",\n trigger: \"verification failed at attempt limit\",\n actor: \"reconciler\",\n },\n { from: \"verifying\", to: \"cancelled\", trigger: \"cancel or kill\", actor: \"operator\" },\n { from: \"needs_human\", to: \"succeeded\", trigger: \"question answered\", actor: \"operator\" },\n { from: \"needs_human\", to: \"queued\", trigger: \"operator retry\", actor: \"operator\" },\n { from: \"needs_human\", to: \"cancelled\", trigger: \"cancel or kill\", actor: \"operator\" },\n { from: \"failed\", to: \"queued\", trigger: \"operator retry\", actor: \"operator\" },\n];\n\n/** Required lifecycle state assigned when a Change is first recorded. */\nexport const changeInitialState = \"verifying\" satisfies ChangeState;\n\n/** Canonical legal Change lifecycle edges and their responsible authorities. */\nexport const changeTransitions: readonly Transition<ChangeState>[] = [\n {\n from: \"ready\",\n to: \"verifying\",\n trigger: \"a code_change task updated the existing pull request head\",\n actor: \"reconciler\",\n },\n {\n from: \"verifying\",\n to: \"ready\",\n trigger: \"configured verification policy completed, risk and confidence written\",\n actor: \"reconciler\",\n },\n {\n from: \"verifying\",\n to: \"closed\",\n trigger: \"verification failed at attempt limit or pr closed upstream\",\n actor: \"reconciler\",\n },\n { from: \"ready\", to: \"merged\", trigger: \"pr merged on github\", actor: \"webhook\" },\n { from: \"ready\", to: \"closed\", trigger: \"pr closed without merge\", actor: \"webhook\" },\n {\n from: \"merged\",\n to: \"deployed\",\n trigger: \"production deployment ready containing the merge sha\",\n actor: \"webhook\",\n },\n {\n from: \"deployed\",\n to: \"rolled_out\",\n trigger: \"no flag, or flag ramped to full and held\",\n actor: \"foreman\",\n },\n { from: \"deployed\", to: \"rolled_back\", trigger: \"rollback rule crossed\", actor: \"foreman\" },\n {\n from: \"rolled_out\",\n to: \"rolled_back\",\n trigger: \"rollback rule crossed or flag flipped off\",\n actor: \"foreman\",\n },\n { from: \"rolled_back\", to: \"deployed\", trigger: \"human retried the ramp\", actor: \"human\" },\n];\n\n/** Required outcome assigned when an inbound Signal is admitted. */\nexport const signalInitialOutcome = \"pending\" satisfies SignalOutcome;\n\n/** Canonical one-time Signal triage edges. */\nexport const signalOutcomeTransitions: readonly Transition<SignalOutcome>[] = [\n { from: \"pending\", to: \"accepted\", trigger: \"classified as actionable\", actor: \"reconciler\" },\n { from: \"pending\", to: \"duplicate\", trigger: \"classified as duplicate\", actor: \"reconciler\" },\n {\n from: \"pending\",\n to: \"unactionable\",\n trigger: \"classified as unactionable\",\n actor: \"reconciler\",\n },\n {\n from: \"pending\",\n to: \"low_confidence\",\n trigger: \"classified below confidence threshold\",\n actor: \"reconciler\",\n },\n { from: \"pending\", to: \"ignored\", trigger: \"classified as ignorable\", actor: \"reconciler\" },\n];\n\n/** Reports whether a state-machine table contains the requested directed edge. */\nexport function isTransitionAllowed<State extends string>(\n transitions: readonly Transition<State>[],\n input: TransitionInput<State>,\n): boolean {\n return transitions.some(\n (transition) => transition.from === input.from && transition.to === input.to,\n );\n}\n\n/** Returns the distinct states directly reachable from a given state. */\nexport function legalNextStates<State extends string>(\n transitions: readonly Transition<State>[],\n from: NoInfer<State>,\n): readonly State[] {\n return [\n ...new Set(transitions.filter((transition) => transition.from === from).map((t) => t.to)),\n ];\n}\n\n/** Error describing a refused state transition and every legal next state. */\nexport class InvalidTransitionError<State extends string> extends Error {\n readonly from: State;\n readonly to: State;\n readonly legalNextStates: readonly State[];\n\n constructor(from: State, to: State, legal: readonly State[]) {\n super(\n legal.length > 0\n ? `invalid transition from \"${from}\" to \"${to}\"; legal next states: ${legal\n .map((state) => `\"${state}\"`)\n .join(\", \")}`\n : `invalid transition from \"${from}\" to \"${to}\"; \"${from}\" is terminal`,\n );\n this.name = \"InvalidTransitionError\";\n this.from = from;\n this.to = to;\n this.legalNextStates = legal;\n }\n}\n\n/** Throws an {@link InvalidTransitionError} unless the requested edge is legal. */\nexport function assertTransition<State extends string>(\n transitions: readonly Transition<State>[],\n input: TransitionInput<State>,\n): void {\n if (!isTransitionAllowed(transitions, input)) {\n throw new InvalidTransitionError(\n input.from,\n input.to,\n legalNextStates(transitions, input.from),\n );\n }\n}\n\n/** Derives states with no outgoing edges from a transition table. */\nexport function terminalStates<State extends string>(\n transitions: readonly Transition<State>[],\n): readonly State[] {\n const states = new Set<State>();\n for (const transition of transitions) {\n states.add(transition.from);\n states.add(transition.to);\n }\n return [...states].filter(\n (state) => !transitions.some((transition) => transition.from === state),\n );\n}\n\n/** Canonical triage observation and explicit retry edges. */\nexport const signalTriageTransitions: readonly Transition<SignalTriage[\"state\"]>[] = [\n { from: \"running\", to: \"blocked\", trigger: \"provider stopped without deciding\", actor: \"system\" },\n { from: \"running\", to: \"uncertain\", trigger: \"launch response unavailable\", actor: \"system\" },\n { from: \"uncertain\", to: \"blocked\", trigger: \"provider confirmed stopped\", actor: \"system\" },\n { from: \"blocked\", to: \"running\", trigger: \"explicit operator retry\", actor: \"operator\" },\n];\n"],"mappings":"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"}
|
package/dist/signals.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import { DecidedSignal, PendingSignal, Signal, SignalOutcome, SignalSource, SignalTriage, signalOutcomeSchema, signalSchema, signalSourceSchema, signalTriageSchema, standardSignalSources } from "./schema/signal.mjs";
|
|
3
2
|
import { SignalId, signalIdSchema } from "./schema/id.mjs";
|
|
3
|
+
import { DecidedSignal, PendingSignal, Signal, SignalOutcome, SignalSource, SignalTriage, signalOutcomeSchema, signalSchema, signalSourceSchema, signalTriageSchema, standardSignalSources } from "./schema/signal.mjs";
|
|
4
4
|
import { CreateSignalInput, DecideSignalInput, FactoryStores } from "./store/engine.mjs";
|
|
5
5
|
import { signalInitialOutcome, signalOutcomeTransitions, signalTriageTransitions } from "./schema/transitions.mjs";
|
|
6
6
|
import { createSignalTriageHook, runSignalTriage, signalTriageHeaders, withSignalTriage } from "./signal-triage.mjs";
|
package/dist/stall.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { collectFactoryRecords } from "./store/iterate.mjs";
|
|
1
2
|
//#region src/stall.ts
|
|
2
3
|
/** Resolve the progress timeout for a Task kind from the configured execution policy. */
|
|
3
4
|
function stallWindowMinutes(policy, kind) {
|
|
@@ -20,7 +21,10 @@ async function sweepTaskStalls(stores, options) {
|
|
|
20
21
|
failed: [],
|
|
21
22
|
cancelled: []
|
|
22
23
|
};
|
|
23
|
-
const tasks = options.tasks ?? await stores.tasks.list
|
|
24
|
+
const tasks = options.tasks ?? await collectFactoryRecords(stores.tasks.list, {
|
|
25
|
+
limit: 100,
|
|
26
|
+
match: [{ state: "running" }, { state: "stalled" }]
|
|
27
|
+
});
|
|
24
28
|
const newlyStalled = [];
|
|
25
29
|
for (const task of tasks) {
|
|
26
30
|
if (task.waitingForMessages || task.state !== "running") continue;
|
|
@@ -45,11 +49,15 @@ async function sweepTaskStalls(stores, options) {
|
|
|
45
49
|
continue;
|
|
46
50
|
}
|
|
47
51
|
}
|
|
48
|
-
const stalledCandidates = options.tasks === void 0 ? await stores.tasks.list
|
|
52
|
+
const stalledCandidates = options.tasks === void 0 ? await collectFactoryRecords(stores.tasks.list, {
|
|
53
|
+
limit: 100,
|
|
54
|
+
match: [{ state: "running" }, { state: "stalled" }]
|
|
55
|
+
}) : [...tasks.filter((task) => task.state === "stalled"), ...newlyStalled];
|
|
49
56
|
for (const task of stalledCandidates) {
|
|
50
57
|
if (task.waitingForMessages || task.state !== "stalled") continue;
|
|
51
58
|
const cancellationReason = await options.cancelStalled?.(task, tasks) ?? null;
|
|
52
59
|
try {
|
|
60
|
+
if (await options.recoverResult?.(task)) continue;
|
|
53
61
|
if (cancellationReason !== null) {
|
|
54
62
|
await stores.tasks.transition(task.id, "cancelled", {
|
|
55
63
|
reason: cancellationReason,
|
package/dist/stall.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stall.mjs","names":[],"sources":["../src/stall.ts"],"sourcesContent":["import type { ExecutionPolicy } from \"./schema/factory-config\";\nimport type { DateClock, MaybePromise } from \"./schema/common\";\nimport type { TaskId } from \"./schema/id\";\nimport type { Task } from \"./schema/task\";\nimport type { FactoryStores } from \"./store/engine\";\n\n/** Execution policy, clock, snapshot, and optional workflow cancellation hook for stall recovery. */\nexport interface StallSweepOptions {\n policy: ExecutionPolicy;\n now?: DateClock;\n /** A dispatcher-wide snapshot avoids another complete task read. */\n tasks?: readonly Task[];\n /** Recover a saved result before marking work stalled; a throw defers stall recovery. */\n recoverResult?: (task: Task) => Promise<boolean>;\n /** Optional workflow policy that cancels a stalled task instead of retrying it. */\n cancelStalled?: (task: Task, tasks: readonly Task[]) => MaybePromise<string | null>;\n}\n\n/** Task IDs transitioned at each stage of one stall-recovery pass. */\nexport interface TaskStallSweepResult {\n readonly stalled: readonly TaskId[];\n readonly requeued: readonly TaskId[];\n readonly failed: readonly TaskId[];\n readonly cancelled: readonly TaskId[];\n}\n\n/** Task capability required to detect and recover stalled work. */\nexport type TaskStallSweepStores = Pick<FactoryStores, \"tasks\">;\n\n/** Resolve the progress timeout for a Task kind from the configured execution policy. */\nexport function stallWindowMinutes(policy: ExecutionPolicy, kind: Task[\"kind\"]): number {\n return policy.stallMinutesByKind[kind] ?? policy.stallMinutes;\n}\n\n/**\n * The reconciler's stall pass. A running task whose execution has not\n * progressed within its stall window is marked stalled; a stalled task is\n * re-queued for a replacement attempt while attempts remain, and failed once\n * they are exhausted. Only `running` tasks can stall: a task whose result has\n * already been recorded (verifying, or terminal) is never retried by this\n * pass. Workflows explicitly waiting for messages are skipped. Configured result recovery\n * runs before marking a Task stalled; an error defers that attempt to a later pass.\n */\nexport async function sweepTaskStalls(\n stores: TaskStallSweepStores,\n options: StallSweepOptions,\n): Promise<TaskStallSweepResult> {\n const nowMs = (options.now ?? (() => new Date()))().getTime();\n const result: {\n stalled: TaskId[];\n requeued: TaskId[];\n failed: TaskId[];\n cancelled: TaskId[];\n } = {\n stalled: [],\n requeued: [],\n failed: [],\n cancelled: [],\n };\n const tasks
|
|
1
|
+
{"version":3,"file":"stall.mjs","names":[],"sources":["../src/stall.ts"],"sourcesContent":["import { collectFactoryRecords } from \"./store/iterate\";\nimport type { ExecutionPolicy } from \"./schema/factory-config\";\nimport type { DateClock, MaybePromise } from \"./schema/common\";\nimport type { TaskId } from \"./schema/id\";\nimport type { Task } from \"./schema/task\";\nimport type { FactoryStores } from \"./store/engine\";\n\n/** Execution policy, clock, snapshot, and optional workflow cancellation hook for stall recovery. */\nexport interface StallSweepOptions {\n policy: ExecutionPolicy;\n now?: DateClock;\n /** A dispatcher-wide snapshot avoids another complete task read. */\n tasks?: readonly Task[];\n /** Recover a saved result before marking work stalled; a throw defers stall recovery. */\n recoverResult?: (task: Task) => Promise<boolean>;\n /** Optional workflow policy that cancels a stalled task instead of retrying it. */\n cancelStalled?: (task: Task, tasks: readonly Task[]) => MaybePromise<string | null>;\n}\n\n/** Task IDs transitioned at each stage of one stall-recovery pass. */\nexport interface TaskStallSweepResult {\n readonly stalled: readonly TaskId[];\n readonly requeued: readonly TaskId[];\n readonly failed: readonly TaskId[];\n readonly cancelled: readonly TaskId[];\n}\n\n/** Task capability required to detect and recover stalled work. */\nexport type TaskStallSweepStores = Pick<FactoryStores, \"tasks\">;\n\n/** Resolve the progress timeout for a Task kind from the configured execution policy. */\nexport function stallWindowMinutes(policy: ExecutionPolicy, kind: Task[\"kind\"]): number {\n return policy.stallMinutesByKind[kind] ?? policy.stallMinutes;\n}\n\n/**\n * The reconciler's stall pass. A running task whose execution has not\n * progressed within its stall window is marked stalled; a stalled task is\n * re-queued for a replacement attempt while attempts remain, and failed once\n * they are exhausted. Only `running` tasks can stall: a task whose result has\n * already been recorded (verifying, or terminal) is never retried by this\n * pass. Workflows explicitly waiting for messages are skipped. Configured result recovery\n * runs before marking a Task stalled; an error defers that attempt to a later pass.\n */\nexport async function sweepTaskStalls(\n stores: TaskStallSweepStores,\n options: StallSweepOptions,\n): Promise<TaskStallSweepResult> {\n const nowMs = (options.now ?? (() => new Date()))().getTime();\n const result: {\n stalled: TaskId[];\n requeued: TaskId[];\n failed: TaskId[];\n cancelled: TaskId[];\n } = {\n stalled: [],\n requeued: [],\n failed: [],\n cancelled: [],\n };\n const tasks =\n options.tasks ??\n (await collectFactoryRecords(stores.tasks.list, {\n limit: 100,\n match: [{ state: \"running\" }, { state: \"stalled\" }],\n }));\n const newlyStalled: Task[] = [];\n\n for (const task of tasks) {\n if (task.waitingForMessages || task.state !== \"running\") {\n continue;\n }\n const minutes = stallWindowMinutes(options.policy, task.kind);\n const sinceProgress = nowMs - Date.parse(task.lastProgressAt ?? task.updatedAt);\n if (sinceProgress < minutes * 60_000) {\n continue;\n }\n // A concurrent writer may have moved the task; skip rather than abort.\n try {\n if (await options.recoverResult?.(task)) continue;\n const stalled = await stores.tasks.transition(task.id, \"stalled\", {\n reason: `no progress for ${Math.floor(sinceProgress / 60_000)} minutes (window ${minutes})`,\n expectFrom: \"running\",\n expectAttempt: task.attempt,\n expectExecution: task.execution,\n });\n result.stalled.push(task.id);\n newlyStalled.push(stalled);\n } catch {\n if (options.tasks !== undefined) {\n const current = await stores.tasks.get(task.id).catch(() => null);\n if (current?.state === \"stalled\") newlyStalled.push(current);\n }\n continue;\n }\n }\n\n // Resolve every stalled task, including ones stalled by an earlier pass that\n // crashed before reaching this step.\n const stalledCandidates =\n options.tasks === undefined\n ? await collectFactoryRecords(stores.tasks.list, {\n limit: 100,\n match: [{ state: \"running\" }, { state: \"stalled\" }],\n })\n : [...tasks.filter((task) => task.state === \"stalled\"), ...newlyStalled];\n for (const task of stalledCandidates) {\n if (task.waitingForMessages || task.state !== \"stalled\") {\n continue;\n }\n const cancellationReason = (await options.cancelStalled?.(task, tasks)) ?? null;\n try {\n if (await options.recoverResult?.(task)) continue;\n if (cancellationReason !== null) {\n await stores.tasks.transition(task.id, \"cancelled\", {\n reason: cancellationReason,\n expectFrom: \"stalled\",\n });\n result.cancelled.push(task.id);\n } else if (task.attempt < options.policy.maxAttempts) {\n await stores.tasks.transition(task.id, \"queued\", {\n reason: `stalled on attempt ${task.attempt} of ${options.policy.maxAttempts}; replacing`,\n phase: \"retry\",\n expectFrom: \"stalled\",\n });\n result.requeued.push(task.id);\n } else {\n await stores.tasks.transition(task.id, \"failed\", {\n reason: `stalled on attempt ${task.attempt} of ${options.policy.maxAttempts}; attempts exhausted`,\n phase: \"retry\",\n expectFrom: \"stalled\",\n });\n result.failed.push(task.id);\n }\n } catch {\n continue;\n }\n }\n return result;\n}\n"],"mappings":";;;AA+BA,SAAgB,mBAAmB,QAAyB,MAA4B;CACtF,OAAO,OAAO,mBAAmB,SAAS,OAAO;AACnD;;;;;;;;;;AAWA,eAAsB,gBACpB,QACA,SAC+B;CAC/B,MAAM,SAAS,QAAQ,8BAAc,IAAI,KAAK,GAAA,CAAI,CAAC,CAAC,QAAQ;CAC5D,MAAM,SAKF;EACF,SAAS,CAAC;EACV,UAAU,CAAC;EACX,QAAQ,CAAC;EACT,WAAW,CAAC;CACd;CACA,MAAM,QACJ,QAAQ,SACP,MAAM,sBAAsB,OAAO,MAAM,MAAM;EAC9C,OAAO;EACP,OAAO,CAAC,EAAE,OAAO,UAAU,GAAG,EAAE,OAAO,UAAU,CAAC;CACpD,CAAC;CACH,MAAM,eAAuB,CAAC;CAE9B,KAAK,MAAM,QAAQ,OAAO;EACxB,IAAI,KAAK,sBAAsB,KAAK,UAAU,WAC5C;EAEF,MAAM,UAAU,mBAAmB,QAAQ,QAAQ,KAAK,IAAI;EAC5D,MAAM,gBAAgB,QAAQ,KAAK,MAAM,KAAK,kBAAkB,KAAK,SAAS;EAC9E,IAAI,gBAAgB,UAAU,KAC5B;EAGF,IAAI;GACF,IAAI,MAAM,QAAQ,gBAAgB,IAAI,GAAG;GACzC,MAAM,UAAU,MAAM,OAAO,MAAM,WAAW,KAAK,IAAI,WAAW;IAChE,QAAQ,mBAAmB,KAAK,MAAM,gBAAgB,GAAM,EAAE,mBAAmB,QAAQ;IACzF,YAAY;IACZ,eAAe,KAAK;IACpB,iBAAiB,KAAK;GACxB,CAAC;GACD,OAAO,QAAQ,KAAK,KAAK,EAAE;GAC3B,aAAa,KAAK,OAAO;EAC3B,QAAQ;GACN,IAAI,QAAQ,UAAU,KAAA,GAAW;IAC/B,MAAM,UAAU,MAAM,OAAO,MAAM,IAAI,KAAK,EAAE,CAAC,CAAC,YAAY,IAAI;IAChE,IAAI,SAAS,UAAU,WAAW,aAAa,KAAK,OAAO;GAC7D;GACA;EACF;CACF;CAIA,MAAM,oBACJ,QAAQ,UAAU,KAAA,IACd,MAAM,sBAAsB,OAAO,MAAM,MAAM;EAC7C,OAAO;EACP,OAAO,CAAC,EAAE,OAAO,UAAU,GAAG,EAAE,OAAO,UAAU,CAAC;CACpD,CAAC,IACD,CAAC,GAAG,MAAM,QAAQ,SAAS,KAAK,UAAU,SAAS,GAAG,GAAG,YAAY;CAC3E,KAAK,MAAM,QAAQ,mBAAmB;EACpC,IAAI,KAAK,sBAAsB,KAAK,UAAU,WAC5C;EAEF,MAAM,qBAAsB,MAAM,QAAQ,gBAAgB,MAAM,KAAK,KAAM;EAC3E,IAAI;GACF,IAAI,MAAM,QAAQ,gBAAgB,IAAI,GAAG;GACzC,IAAI,uBAAuB,MAAM;IAC/B,MAAM,OAAO,MAAM,WAAW,KAAK,IAAI,aAAa;KAClD,QAAQ;KACR,YAAY;IACd,CAAC;IACD,OAAO,UAAU,KAAK,KAAK,EAAE;GAC/B,OAAO,IAAI,KAAK,UAAU,QAAQ,OAAO,aAAa;IACpD,MAAM,OAAO,MAAM,WAAW,KAAK,IAAI,UAAU;KAC/C,QAAQ,sBAAsB,KAAK,QAAQ,MAAM,QAAQ,OAAO,YAAY;KAC5E,OAAO;KACP,YAAY;IACd,CAAC;IACD,OAAO,SAAS,KAAK,KAAK,EAAE;GAC9B,OAAO;IACL,MAAM,OAAO,MAAM,WAAW,KAAK,IAAI,UAAU;KAC/C,QAAQ,sBAAsB,KAAK,QAAQ,MAAM,QAAQ,OAAO,YAAY;KAC5E,OAAO;KACP,YAAY;IACd,CAAC;IACD,OAAO,OAAO,KAAK,KAAK,EAAE;GAC5B;EACF,QAAQ;GACN;EACF;CACF;CACA,OAAO;AACT"}
|
package/dist/storage.d.mts
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
|
+
import { FactoryRecordFieldFilter, FactoryRecordPage, FactoryRecordQuery } from "./store/query.mjs";
|
|
1
2
|
import { CollectionName, InsertStoreRecordInput, RecordExistsError, RecordNotFoundError, StoreDriver, StoredEntry, StoredRecord, TransientStoreError, UpdateStoreRecordInput, VersionConflictError } from "./store/driver.mjs";
|
|
3
|
+
import { IndexedStore, QueryStoreIndexInput, QueryStoreIndexResult, QueryStoreRecordsInput, QueryStoreRecordsResult, StoreIndexEntry, StoreIndexRecord, StoreOperationConflictError, WriteIndexedRecordInput, WriteIndexedRecordResult } from "./store/indexed.mjs";
|
|
2
4
|
import { CacheContinuationContextInput, CreateStoresOptions, FactoryStores, createStores } from "./store/engine.mjs";
|
|
5
|
+
import { ApprovalStore } from "./store/approvals.mjs";
|
|
6
|
+
import { ConversationProjectionOptions, ConversationQuery, ConversationStore } from "./store/conversations.mjs";
|
|
7
|
+
import { ConditionalStateStore, createIndexedStateStore } from "./store/state.mjs";
|
|
3
8
|
import { createInMemoryDriver } from "./store/memory.mjs";
|
|
4
|
-
|
|
9
|
+
import { createInMemoryIndexedStore } from "./store/indexed-memory.mjs";
|
|
10
|
+
import { FactoryIndexScope, FactoryRecordSummary, factoryIndexScopeSchema, factoryRecordSummarySchema } from "./store/indexed-projections.mjs";
|
|
11
|
+
import { CreateIndexedStoresOptions, FactoryIndexedEntry, FactoryIndexedPage, IndexedFactoryStores, createIndexedStores } from "./store/indexed-engine.mjs";
|
|
12
|
+
import { collectFactoryRecords, iterateFactoryRecords } from "./store/iterate.mjs";
|
|
13
|
+
export { type ApprovalStore, type CacheContinuationContextInput, type CollectionName, type ConditionalStateStore, type ConversationProjectionOptions, type ConversationQuery, type ConversationStore, type CreateIndexedStoresOptions, type CreateStoresOptions, type FactoryIndexScope, type FactoryIndexedEntry, type FactoryIndexedPage, type FactoryRecordFieldFilter, type FactoryRecordPage, type FactoryRecordQuery, type FactoryRecordSummary, type FactoryStores, type IndexedFactoryStores, type IndexedStore, type InsertStoreRecordInput, type QueryStoreIndexInput, type QueryStoreIndexResult, type QueryStoreRecordsInput, type QueryStoreRecordsResult, RecordExistsError, RecordNotFoundError, type StoreDriver, type StoreIndexEntry, type StoreIndexRecord, StoreOperationConflictError, type StoredEntry, type StoredRecord, TransientStoreError, type UpdateStoreRecordInput, VersionConflictError, type WriteIndexedRecordInput, type WriteIndexedRecordResult, collectFactoryRecords, createInMemoryDriver, createInMemoryIndexedStore, createIndexedStateStore, createIndexedStores, createStores, factoryIndexScopeSchema, factoryRecordSummarySchema, iterateFactoryRecords };
|
package/dist/storage.mjs
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
+
import { collectFactoryRecords, iterateFactoryRecords } from "./store/iterate.mjs";
|
|
1
2
|
import { RecordExistsError, RecordNotFoundError, TransientStoreError, VersionConflictError } from "./store/driver.mjs";
|
|
3
|
+
import { factoryIndexScopeSchema, factoryRecordSummarySchema } from "./store/indexed-projections.mjs";
|
|
2
4
|
import { createStores } from "./store/engine.mjs";
|
|
3
5
|
import { createInMemoryDriver } from "./store/memory.mjs";
|
|
4
|
-
|
|
6
|
+
import { StoreOperationConflictError } from "./store/indexed.mjs";
|
|
7
|
+
import { createInMemoryIndexedStore } from "./store/indexed-memory.mjs";
|
|
8
|
+
import { createIndexedStores } from "./store/indexed-engine.mjs";
|
|
9
|
+
import { createIndexedStateStore } from "./store/state.mjs";
|
|
10
|
+
export { RecordExistsError, RecordNotFoundError, StoreOperationConflictError, TransientStoreError, VersionConflictError, collectFactoryRecords, createInMemoryDriver, createInMemoryIndexedStore, createIndexedStateStore, createIndexedStores, createStores, factoryIndexScopeSchema, factoryRecordSummarySchema, iterateFactoryRecords };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { TaskId } from "../schema/id.mjs";
|
|
2
|
+
import { FactoryRecordPage, FactoryRecordQuery } from "./query.mjs";
|
|
3
|
+
import "./indexed.mjs";
|
|
4
|
+
import "./engine.mjs";
|
|
5
|
+
//#region src/store/approvals.d.ts
|
|
6
|
+
/** Indexed approval discovery; full authorized proposals are loaded only for the selected page. */
|
|
7
|
+
interface ApprovalStore {
|
|
8
|
+
list(query: FactoryRecordQuery & {
|
|
9
|
+
sort?: "created" | "priority" | "decided";
|
|
10
|
+
}): Promise<FactoryRecordPage<TaskId>>;
|
|
11
|
+
}
|
|
12
|
+
//#endregion
|
|
13
|
+
export { ApprovalStore };
|
|
14
|
+
//# sourceMappingURL=approvals.d.mts.map
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { taskIdSchema } from "../schema/id.mjs";
|
|
2
|
+
import { taskSchema } from "../schema/task.mjs";
|
|
3
|
+
import { findFindingForTask } from "../finding-remediation/brief.mjs";
|
|
4
|
+
import { randomUUID } from "node:crypto";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
//#region src/store/approvals.ts
|
|
7
|
+
function createApprovalStore(store) {
|
|
8
|
+
return { async list({ sort = "created", ...query }) {
|
|
9
|
+
const page = await store.queryRecords({
|
|
10
|
+
...query,
|
|
11
|
+
sources: [{
|
|
12
|
+
collection: "approvalRecords",
|
|
13
|
+
index: `approvals:${sort}`
|
|
14
|
+
}],
|
|
15
|
+
order: sort === "decided" ? "desc" : "asc"
|
|
16
|
+
});
|
|
17
|
+
return {
|
|
18
|
+
items: page.entries.map((entry) => taskIdSchema.parse(entry.id)),
|
|
19
|
+
nextCursor: page.nextCursor,
|
|
20
|
+
totalCount: page.totalCount
|
|
21
|
+
};
|
|
22
|
+
} };
|
|
23
|
+
}
|
|
24
|
+
async function projectApproval(store, stores, value) {
|
|
25
|
+
const task = taskSchema.parse(value);
|
|
26
|
+
if (task.approval === void 0) return;
|
|
27
|
+
const [finding, decision, repositories] = await Promise.all([
|
|
28
|
+
findFindingForTask(stores, task),
|
|
29
|
+
stores.tasks.approvalReceipt(task.id),
|
|
30
|
+
Promise.all(task.repositoryIds.map((id) => stores.repositories.get(id)))
|
|
31
|
+
]);
|
|
32
|
+
const record = {
|
|
33
|
+
id: task.id,
|
|
34
|
+
repositoryIds: task.repositoryIds,
|
|
35
|
+
status: task.approval === "required" && task.state === "queued" ? "pending" : task.approval !== "required" ? "decided" : "inactive",
|
|
36
|
+
searchText: [
|
|
37
|
+
task.id,
|
|
38
|
+
...repositories.map((repo) => repo?.slug),
|
|
39
|
+
finding?.title,
|
|
40
|
+
finding?.body,
|
|
41
|
+
finding?.category,
|
|
42
|
+
finding?.path,
|
|
43
|
+
decision?.decidedBy,
|
|
44
|
+
decision?.reason
|
|
45
|
+
].join(" ")
|
|
46
|
+
};
|
|
47
|
+
const previous = await store.get("approvalRecords", task.id);
|
|
48
|
+
const indexes = [
|
|
49
|
+
{
|
|
50
|
+
index: "approvals:created",
|
|
51
|
+
sortKey: task.createdAt,
|
|
52
|
+
summary: { id: task.id }
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
index: "approvals:priority",
|
|
56
|
+
sortKey: `${finding?.priority ?? "P4"}:${task.createdAt}`,
|
|
57
|
+
summary: { id: task.id }
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
index: "approvals:decided",
|
|
61
|
+
sortKey: decision?.recordedAt ?? task.createdAt,
|
|
62
|
+
summary: { id: task.id }
|
|
63
|
+
}
|
|
64
|
+
];
|
|
65
|
+
z.array(z.string()).parse(record.repositoryIds);
|
|
66
|
+
await store.write({
|
|
67
|
+
collection: "approvalRecords",
|
|
68
|
+
id: task.id,
|
|
69
|
+
operationId: randomUUID(),
|
|
70
|
+
expectedVersion: previous?.version ?? 0,
|
|
71
|
+
value: record,
|
|
72
|
+
indexes
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
76
|
+
export { createApprovalStore, projectApproval };
|
|
77
|
+
|
|
78
|
+
//# sourceMappingURL=approvals.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approvals.mjs","names":[],"sources":["../../src/store/approvals.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { z } from \"zod\";\nimport { findFindingForTask } from \"../finding-remediation/brief\";\nimport { taskIdSchema, type TaskId } from \"../schema/id\";\nimport { taskSchema } from \"../schema/task\";\nimport type { FactoryStores } from \"./engine\";\nimport type { IndexedStore } from \"./indexed\";\nimport type { FactoryRecordPage, FactoryRecordQuery } from \"./query\";\n\n/** Indexed approval discovery; full authorized proposals are loaded only for the selected page. */\nexport interface ApprovalStore {\n list(\n query: FactoryRecordQuery & { sort?: \"created\" | \"priority\" | \"decided\" },\n ): Promise<FactoryRecordPage<TaskId>>;\n}\nexport function createApprovalStore(store: IndexedStore): ApprovalStore {\n return {\n async list({ sort = \"created\", ...query }) {\n const page = await store.queryRecords({\n ...query,\n sources: [{ collection: \"approvalRecords\", index: `approvals:${sort}` }],\n order: sort === \"decided\" ? \"desc\" : \"asc\",\n });\n return {\n items: page.entries.map((entry) => taskIdSchema.parse(entry.id)),\n nextCursor: page.nextCursor,\n totalCount: page.totalCount,\n };\n },\n };\n}\nexport async function projectApproval(store: IndexedStore, stores: FactoryStores, value: unknown) {\n const task = taskSchema.parse(value);\n if (task.approval === undefined) return;\n const [finding, decision, repositories] = await Promise.all([\n findFindingForTask(stores, task),\n stores.tasks.approvalReceipt(task.id),\n Promise.all(task.repositoryIds.map((id) => stores.repositories.get(id))),\n ]);\n const record = {\n id: task.id,\n repositoryIds: task.repositoryIds,\n status:\n task.approval === \"required\" && task.state === \"queued\"\n ? \"pending\"\n : task.approval !== \"required\"\n ? \"decided\"\n : \"inactive\",\n searchText: [\n task.id,\n ...repositories.map((repo) => repo?.slug),\n finding?.title,\n finding?.body,\n finding?.category,\n finding?.path,\n decision?.decidedBy,\n decision?.reason,\n ].join(\" \"),\n };\n const previous = await store.get(\"approvalRecords\", task.id);\n const indexes = [\n { index: \"approvals:created\", sortKey: task.createdAt, summary: { id: task.id } },\n {\n index: \"approvals:priority\",\n sortKey: `${finding?.priority ?? \"P4\"}:${task.createdAt}`,\n summary: { id: task.id },\n },\n {\n index: \"approvals:decided\",\n sortKey: decision?.recordedAt ?? task.createdAt,\n summary: { id: task.id },\n },\n ];\n z.array(z.string()).parse(record.repositoryIds);\n await store.write({\n collection: \"approvalRecords\",\n id: task.id,\n operationId: randomUUID(),\n expectedVersion: previous?.version ?? 0,\n value: record,\n indexes,\n });\n}\n"],"mappings":";;;;;;AAeA,SAAgB,oBAAoB,OAAoC;CACtE,OAAO,EACL,MAAM,KAAK,EAAE,OAAO,WAAW,GAAG,SAAS;EACzC,MAAM,OAAO,MAAM,MAAM,aAAa;GACpC,GAAG;GACH,SAAS,CAAC;IAAE,YAAY;IAAmB,OAAO,aAAa;GAAO,CAAC;GACvE,OAAO,SAAS,YAAY,SAAS;EACvC,CAAC;EACD,OAAO;GACL,OAAO,KAAK,QAAQ,KAAK,UAAU,aAAa,MAAM,MAAM,EAAE,CAAC;GAC/D,YAAY,KAAK;GACjB,YAAY,KAAK;EACnB;CACF,EACF;AACF;AACA,eAAsB,gBAAgB,OAAqB,QAAuB,OAAgB;CAChG,MAAM,OAAO,WAAW,MAAM,KAAK;CACnC,IAAI,KAAK,aAAa,KAAA,GAAW;CACjC,MAAM,CAAC,SAAS,UAAU,gBAAgB,MAAM,QAAQ,IAAI;EAC1D,mBAAmB,QAAQ,IAAI;EAC/B,OAAO,MAAM,gBAAgB,KAAK,EAAE;EACpC,QAAQ,IAAI,KAAK,cAAc,KAAK,OAAO,OAAO,aAAa,IAAI,EAAE,CAAC,CAAC;CACzE,CAAC;CACD,MAAM,SAAS;EACb,IAAI,KAAK;EACT,eAAe,KAAK;EACpB,QACE,KAAK,aAAa,cAAc,KAAK,UAAU,WAC3C,YACA,KAAK,aAAa,aAChB,YACA;EACR,YAAY;GACV,KAAK;GACL,GAAG,aAAa,KAAK,SAAS,MAAM,IAAI;GACxC,SAAS;GACT,SAAS;GACT,SAAS;GACT,SAAS;GACT,UAAU;GACV,UAAU;EACZ,CAAC,CAAC,KAAK,GAAG;CACZ;CACA,MAAM,WAAW,MAAM,MAAM,IAAI,mBAAmB,KAAK,EAAE;CAC3D,MAAM,UAAU;EACd;GAAE,OAAO;GAAqB,SAAS,KAAK;GAAW,SAAS,EAAE,IAAI,KAAK,GAAG;EAAE;EAChF;GACE,OAAO;GACP,SAAS,GAAG,SAAS,YAAY,KAAK,GAAG,KAAK;GAC9C,SAAS,EAAE,IAAI,KAAK,GAAG;EACzB;EACA;GACE,OAAO;GACP,SAAS,UAAU,cAAc,KAAK;GACtC,SAAS,EAAE,IAAI,KAAK,GAAG;EACzB;CACF;CACA,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,OAAO,aAAa;CAC9C,MAAM,MAAM,MAAM;EAChB,YAAY;EACZ,IAAI,KAAK;EACT,aAAa,WAAW;EACxB,iBAAiB,UAAU,WAAW;EACtC,OAAO;EACP;CACF,CAAC;AACH"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { FactoryRecordPage, FactoryRecordQuery } from "./query.mjs";
|
|
2
|
+
import "./indexed.mjs";
|
|
3
|
+
import "../schema/task.mjs";
|
|
4
|
+
import { AgentRouteRegistry } from "../agent-routes.mjs";
|
|
5
|
+
import { AgentSessionId } from "../schema/session.mjs";
|
|
6
|
+
import "./engine.mjs";
|
|
7
|
+
import { ConversationSummary } from "../schema/session-summary.mjs";
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
//#region src/store/conversations.d.ts
|
|
10
|
+
/** Application-owned conversation routing and optional automatic-work workspace. */
|
|
11
|
+
interface ConversationProjectionOptions {
|
|
12
|
+
readonly routes: AgentRouteRegistry;
|
|
13
|
+
readonly continuationAgent?: string;
|
|
14
|
+
/** Explicit shared workspace receiving newly admitted external routed Tasks. */
|
|
15
|
+
readonly workspaceOwner?: string;
|
|
16
|
+
}
|
|
17
|
+
declare const conversationExecutionSchema: z.ZodObject<{
|
|
18
|
+
taskId: z.ZodOptional<z.ZodType<`task_${string}`, string, z.core.$ZodTypeInternals<`task_${string}`, string>>>;
|
|
19
|
+
agent: z.ZodString;
|
|
20
|
+
message: z.ZodString;
|
|
21
|
+
attachments: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodObject<{
|
|
22
|
+
id: z.ZodType<`img_${string}`, string, z.core.$ZodTypeInternals<`img_${string}`, string>>;
|
|
23
|
+
filename: z.ZodString;
|
|
24
|
+
mediaType: z.ZodEnum<{
|
|
25
|
+
"image/png": "image/png";
|
|
26
|
+
"image/jpeg": "image/jpeg";
|
|
27
|
+
"image/webp": "image/webp";
|
|
28
|
+
}>;
|
|
29
|
+
size: z.ZodNumber;
|
|
30
|
+
}, z.core.$strict>>>>;
|
|
31
|
+
execution: z.ZodObject<{
|
|
32
|
+
provider: z.ZodString;
|
|
33
|
+
sessionId: z.ZodString;
|
|
34
|
+
environmentId: z.ZodOptional<z.ZodString>;
|
|
35
|
+
harness: z.ZodOptional<z.ZodString>;
|
|
36
|
+
traceId: z.ZodOptional<z.ZodString>;
|
|
37
|
+
}, z.core.$strict>;
|
|
38
|
+
}, z.core.$strip>;
|
|
39
|
+
type ConversationExecution = z.infer<typeof conversationExecutionSchema>;
|
|
40
|
+
/** Authorized query of compact conversation records; never reads canonical Task payloads. */
|
|
41
|
+
interface ConversationQuery extends FactoryRecordQuery {
|
|
42
|
+
readonly owner: string;
|
|
43
|
+
readonly repositoryId?: string;
|
|
44
|
+
readonly attention?: boolean;
|
|
45
|
+
}
|
|
46
|
+
/** Compact conversation discovery and maintained exact-owner attention count. */
|
|
47
|
+
interface ConversationStore {
|
|
48
|
+
history(id: AgentSessionId, query: {
|
|
49
|
+
limit: number;
|
|
50
|
+
cursor?: string;
|
|
51
|
+
}): Promise<FactoryRecordPage<ConversationExecution>>;
|
|
52
|
+
execution(id: AgentSessionId, executionId: string): Promise<ConversationExecution | null>;
|
|
53
|
+
get(id: AgentSessionId): Promise<ConversationSummary | null>;
|
|
54
|
+
list(query: ConversationQuery): Promise<FactoryRecordPage<ConversationSummary>>;
|
|
55
|
+
count(owner: string, repositoryId?: string, attention?: boolean): Promise<number>;
|
|
56
|
+
}
|
|
57
|
+
//#endregion
|
|
58
|
+
export { ConversationProjectionOptions, ConversationQuery, ConversationStore };
|
|
59
|
+
//# sourceMappingURL=conversations.d.mts.map
|