@kya-os/cli 1.8.1 → 1.8.3
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/commands/agent.d.ts +35 -0
- package/dist/commands/agent.d.ts.map +1 -0
- package/dist/commands/agent.js +321 -0
- package/dist/commands/agent.js.map +1 -0
- package/dist/commands/build.js +2 -2
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/check.js +3 -3
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/checkpoint-init.d.ts +1 -1
- package/dist/commands/checkpoint-init.d.ts.map +1 -1
- package/dist/commands/checkpoint-init.js +8 -41
- package/dist/commands/checkpoint-init.js.map +1 -1
- package/dist/commands/claim.js +2 -2
- package/dist/commands/claim.js.map +1 -1
- package/dist/commands/dco.d.ts +59 -0
- package/dist/commands/dco.d.ts.map +1 -1
- package/dist/commands/dco.js +280 -5
- package/dist/commands/dco.js.map +1 -1
- package/dist/commands/dev.js +1 -1
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +18 -24
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/env.js +6 -6
- package/dist/commands/env.js.map +1 -1
- package/dist/commands/identity.js +3 -3
- package/dist/commands/identity.js.map +1 -1
- package/dist/commands/init-stages.d.ts +141 -0
- package/dist/commands/init-stages.d.ts.map +1 -0
- package/dist/commands/init-stages.js +684 -0
- package/dist/commands/init-stages.js.map +1 -0
- package/dist/commands/init.d.ts +46 -16
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +229 -279
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/orchestrator.d.ts +18 -0
- package/dist/commands/orchestrator.d.ts.map +1 -0
- package/dist/commands/orchestrator.js +251 -0
- package/dist/commands/orchestrator.js.map +1 -0
- package/dist/commands/register.d.ts +1 -1
- package/dist/commands/register.d.ts.map +1 -1
- package/dist/commands/register.js +35 -7
- package/dist/commands/register.js.map +1 -1
- package/dist/commands/review.d.ts +48 -0
- package/dist/commands/review.d.ts.map +1 -0
- package/dist/commands/review.js +220 -0
- package/dist/commands/review.js.map +1 -0
- package/dist/commands/rotate.js +4 -4
- package/dist/commands/rotate.js.map +1 -1
- package/dist/commands/score.d.ts +15 -0
- package/dist/commands/score.d.ts.map +1 -0
- package/dist/commands/score.js +471 -0
- package/dist/commands/score.js.map +1 -0
- package/dist/commands/start.js +3 -3
- package/dist/commands/start.js.map +1 -1
- package/dist/commands/status.js +1 -1
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/verify.js +6 -6
- package/dist/commands/verify.js.map +1 -1
- package/dist/dco.d.ts +4 -0
- package/dist/dco.d.ts.map +1 -0
- package/dist/dco.js +23 -0
- package/dist/dco.js.map +1 -0
- package/dist/index.js +52 -9
- package/dist/orchestrator/daemon.d.ts +137 -0
- package/dist/orchestrator/daemon.d.ts.map +1 -0
- package/dist/orchestrator/daemon.js +242 -0
- package/dist/orchestrator/daemon.js.map +1 -0
- package/dist/orchestrator/db/dispatches.d.ts +108 -0
- package/dist/orchestrator/db/dispatches.d.ts.map +1 -0
- package/dist/orchestrator/db/dispatches.js +122 -0
- package/dist/orchestrator/db/dispatches.js.map +1 -0
- package/dist/orchestrator/db/index.d.ts +50 -0
- package/dist/orchestrator/db/index.d.ts.map +1 -0
- package/dist/orchestrator/db/index.js +116 -0
- package/dist/orchestrator/db/index.js.map +1 -0
- package/dist/orchestrator/db/journal.d.ts +93 -0
- package/dist/orchestrator/db/journal.d.ts.map +1 -0
- package/dist/orchestrator/db/journal.js +91 -0
- package/dist/orchestrator/db/journal.js.map +1 -0
- package/dist/orchestrator/db/liveness.d.ts +97 -0
- package/dist/orchestrator/db/liveness.d.ts.map +1 -0
- package/dist/orchestrator/db/liveness.js +105 -0
- package/dist/orchestrator/db/liveness.js.map +1 -0
- package/dist/orchestrator/db/mission.d.ts +78 -0
- package/dist/orchestrator/db/mission.d.ts.map +1 -0
- package/dist/orchestrator/db/mission.js +99 -0
- package/dist/orchestrator/db/mission.js.map +1 -0
- package/dist/orchestrator/db/schema.d.ts +14 -0
- package/dist/orchestrator/db/schema.d.ts.map +1 -0
- package/dist/orchestrator/db/schema.js +169 -0
- package/dist/orchestrator/db/schema.js.map +1 -0
- package/dist/orchestrator/db/tickets.d.ts +147 -0
- package/dist/orchestrator/db/tickets.d.ts.map +1 -0
- package/dist/orchestrator/db/tickets.js +238 -0
- package/dist/orchestrator/db/tickets.js.map +1 -0
- package/dist/orchestrator/db/verdicts.d.ts +187 -0
- package/dist/orchestrator/db/verdicts.d.ts.map +1 -0
- package/dist/orchestrator/db/verdicts.js +197 -0
- package/dist/orchestrator/db/verdicts.js.map +1 -0
- package/dist/orchestrator/events.d.ts +69 -0
- package/dist/orchestrator/events.d.ts.map +1 -0
- package/dist/orchestrator/events.js +20 -0
- package/dist/orchestrator/events.js.map +1 -0
- package/dist/orchestrator/github-credential-anchor-sender.d.ts +159 -0
- package/dist/orchestrator/github-credential-anchor-sender.d.ts.map +1 -0
- package/dist/orchestrator/github-credential-anchor-sender.js +313 -0
- package/dist/orchestrator/github-credential-anchor-sender.js.map +1 -0
- package/dist/orchestrator/hub-dispatch.d.ts +120 -0
- package/dist/orchestrator/hub-dispatch.d.ts.map +1 -0
- package/dist/orchestrator/hub-dispatch.js +257 -0
- package/dist/orchestrator/hub-dispatch.js.map +1 -0
- package/dist/orchestrator/hub-observer.d.ts +201 -0
- package/dist/orchestrator/hub-observer.d.ts.map +1 -0
- package/dist/orchestrator/hub-observer.js +474 -0
- package/dist/orchestrator/hub-observer.js.map +1 -0
- package/dist/orchestrator/journal-writer.d.ts +80 -0
- package/dist/orchestrator/journal-writer.d.ts.map +1 -0
- package/dist/orchestrator/journal-writer.js +113 -0
- package/dist/orchestrator/journal-writer.js.map +1 -0
- package/dist/orchestrator/mcp/server.d.ts +136 -0
- package/dist/orchestrator/mcp/server.d.ts.map +1 -0
- package/dist/orchestrator/mcp/server.js +582 -0
- package/dist/orchestrator/mcp/server.js.map +1 -0
- package/dist/orchestrator/mcp/stdio.d.ts +22 -0
- package/dist/orchestrator/mcp/stdio.d.ts.map +1 -0
- package/dist/orchestrator/mcp/stdio.js +51 -0
- package/dist/orchestrator/mcp/stdio.js.map +1 -0
- package/dist/orchestrator/review.d.ts +131 -0
- package/dist/orchestrator/review.d.ts.map +1 -0
- package/dist/orchestrator/review.js +322 -0
- package/dist/orchestrator/review.js.map +1 -0
- package/dist/tui/app.d.ts +33 -0
- package/dist/tui/app.d.ts.map +1 -0
- package/dist/tui/app.js +71 -0
- package/dist/tui/app.js.map +1 -0
- package/dist/tui/components.d.ts +110 -0
- package/dist/tui/components.d.ts.map +1 -0
- package/dist/tui/components.js +118 -0
- package/dist/tui/components.js.map +1 -0
- package/dist/tui/index.d.ts +30 -0
- package/dist/tui/index.d.ts.map +1 -0
- package/dist/tui/index.js +95 -0
- package/dist/tui/index.js.map +1 -0
- package/dist/tui/keymap.d.ts +33 -0
- package/dist/tui/keymap.d.ts.map +1 -0
- package/dist/tui/keymap.js +49 -0
- package/dist/tui/keymap.js.map +1 -0
- package/dist/tui/nav.d.ts +29 -0
- package/dist/tui/nav.d.ts.map +1 -0
- package/dist/tui/nav.js +39 -0
- package/dist/tui/nav.js.map +1 -0
- package/dist/tui/sanitize.d.ts +25 -0
- package/dist/tui/sanitize.d.ts.map +1 -0
- package/dist/tui/sanitize.js +36 -0
- package/dist/tui/sanitize.js.map +1 -0
- package/dist/tui/theme.d.ts +32 -0
- package/dist/tui/theme.d.ts.map +1 -0
- package/dist/tui/theme.js +63 -0
- package/dist/tui/theme.js.map +1 -0
- package/dist/tui/views/agents.d.ts +67 -0
- package/dist/tui/views/agents.d.ts.map +1 -0
- package/dist/tui/views/agents.js +231 -0
- package/dist/tui/views/agents.js.map +1 -0
- package/dist/tui/views/index.d.ts +93 -0
- package/dist/tui/views/index.d.ts.map +1 -0
- package/dist/tui/views/index.js +150 -0
- package/dist/tui/views/index.js.map +1 -0
- package/dist/tui/views/registry.d.ts +22 -0
- package/dist/tui/views/registry.d.ts.map +1 -0
- package/dist/tui/views/registry.js +110 -0
- package/dist/tui/views/registry.js.map +1 -0
- package/dist/utils/agent/backoff.d.ts +31 -0
- package/dist/utils/agent/backoff.d.ts.map +1 -0
- package/dist/utils/agent/backoff.js +51 -0
- package/dist/utils/agent/backoff.js.map +1 -0
- package/dist/utils/agent/markers.d.ts +87 -0
- package/dist/utils/agent/markers.d.ts.map +1 -0
- package/dist/utils/agent/markers.js +147 -0
- package/dist/utils/agent/markers.js.map +1 -0
- package/dist/utils/agent/review.d.ts +67 -0
- package/dist/utils/agent/review.d.ts.map +1 -0
- package/dist/utils/agent/review.js +305 -0
- package/dist/utils/agent/review.js.map +1 -0
- package/dist/utils/agent/spawn-agent.d.ts +117 -0
- package/dist/utils/agent/spawn-agent.d.ts.map +1 -0
- package/dist/utils/agent/spawn-agent.js +177 -0
- package/dist/utils/agent/spawn-agent.js.map +1 -0
- package/dist/utils/agent/task.d.ts +101 -0
- package/dist/utils/agent/task.d.ts.map +1 -0
- package/dist/utils/agent/task.js +357 -0
- package/dist/utils/agent/task.js.map +1 -0
- package/dist/utils/agent/verify.d.ts +47 -0
- package/dist/utils/agent/verify.d.ts.map +1 -0
- package/dist/utils/agent/verify.js +144 -0
- package/dist/utils/agent/verify.js.map +1 -0
- package/dist/utils/agent-detector.d.ts +48 -0
- package/dist/utils/agent-detector.d.ts.map +1 -0
- package/dist/utils/agent-detector.js +74 -0
- package/dist/utils/agent-detector.js.map +1 -0
- package/dist/utils/agent-profile-stage.d.ts +70 -0
- package/dist/utils/agent-profile-stage.d.ts.map +1 -0
- package/dist/utils/agent-profile-stage.js +153 -0
- package/dist/utils/agent-profile-stage.js.map +1 -0
- package/dist/utils/agent-profiles.d.ts +27 -0
- package/dist/utils/agent-profiles.d.ts.map +1 -0
- package/dist/utils/agent-profiles.js +61 -0
- package/dist/utils/agent-profiles.js.map +1 -0
- package/dist/utils/checkpoint-api.d.ts +1 -1
- package/dist/utils/checkpoint-api.js +1 -1
- package/dist/utils/checkpoint-env.d.ts +1 -1
- package/dist/utils/checkpoint-env.js +2 -2
- package/dist/utils/checkpoint-env.js.map +1 -1
- package/dist/utils/checkpoint-scaffold.d.ts +1 -1
- package/dist/utils/checkpoint-scaffold.js +1 -1
- package/dist/utils/cli-kit/browser.d.ts +24 -0
- package/dist/utils/cli-kit/browser.d.ts.map +1 -0
- package/dist/utils/cli-kit/browser.js +58 -0
- package/dist/utils/cli-kit/browser.js.map +1 -0
- package/dist/utils/cli-kit/claim-polling.d.ts +18 -0
- package/dist/utils/cli-kit/claim-polling.d.ts.map +1 -0
- package/dist/utils/{claim-polling.js → cli-kit/claim-polling.js} +19 -26
- package/dist/utils/cli-kit/claim-polling.js.map +1 -0
- package/dist/utils/cli-kit/diagnostics.d.ts +9 -0
- package/dist/utils/cli-kit/diagnostics.d.ts.map +1 -0
- package/dist/utils/cli-kit/diagnostics.js +11 -0
- package/dist/utils/cli-kit/diagnostics.js.map +1 -0
- package/dist/utils/cli-kit/fs-safe.d.ts +14 -0
- package/dist/utils/cli-kit/fs-safe.d.ts.map +1 -0
- package/dist/utils/cli-kit/fs-safe.js +20 -0
- package/dist/utils/cli-kit/fs-safe.js.map +1 -0
- package/dist/utils/cli-kit/index.d.ts +15 -0
- package/dist/utils/cli-kit/index.d.ts.map +1 -0
- package/dist/utils/cli-kit/index.js +10 -0
- package/dist/utils/cli-kit/index.js.map +1 -0
- package/dist/utils/cli-kit/json-file.d.ts +21 -0
- package/dist/utils/cli-kit/json-file.d.ts.map +1 -0
- package/dist/utils/cli-kit/json-file.js +51 -0
- package/dist/utils/cli-kit/json-file.js.map +1 -0
- package/dist/utils/cli-kit/marker-block.d.ts +26 -0
- package/dist/utils/cli-kit/marker-block.d.ts.map +1 -0
- package/dist/utils/cli-kit/marker-block.js +61 -0
- package/dist/utils/cli-kit/marker-block.js.map +1 -0
- package/dist/utils/cli-kit/paths.d.ts +15 -0
- package/dist/utils/cli-kit/paths.d.ts.map +1 -0
- package/dist/utils/cli-kit/paths.js +21 -0
- package/dist/utils/cli-kit/paths.js.map +1 -0
- package/dist/utils/cli-kit/secure-storage.d.ts +14 -0
- package/dist/utils/cli-kit/secure-storage.d.ts.map +1 -0
- package/dist/utils/cli-kit/secure-storage.js +20 -0
- package/dist/utils/cli-kit/secure-storage.js.map +1 -0
- package/dist/utils/cli-kit/step-report.d.ts +16 -0
- package/dist/utils/cli-kit/step-report.d.ts.map +1 -0
- package/dist/utils/cli-kit/step-report.js +36 -0
- package/dist/utils/cli-kit/step-report.js.map +1 -0
- package/dist/utils/dco/agent-metadata.d.ts +1 -1
- package/dist/utils/dco/agent-metadata.js +1 -1
- package/dist/utils/dco/agent-metadata.js.map +1 -1
- package/dist/utils/dco/claude-config.d.ts +18 -14
- package/dist/utils/dco/claude-config.d.ts.map +1 -1
- package/dist/utils/dco/claude-config.js +31 -97
- package/dist/utils/dco/claude-config.js.map +1 -1
- package/dist/utils/dco/dispatch.d.ts +134 -0
- package/dist/utils/dco/dispatch.d.ts.map +1 -0
- package/dist/utils/dco/dispatch.js +399 -0
- package/dist/utils/dco/dispatch.js.map +1 -0
- package/dist/utils/dco/fix.d.ts +122 -0
- package/dist/utils/dco/fix.d.ts.map +1 -0
- package/dist/utils/dco/fix.js +560 -0
- package/dist/utils/dco/fix.js.map +1 -0
- package/dist/utils/dco/git-config.d.ts.map +1 -1
- package/dist/utils/dco/git-config.js +5 -3
- package/dist/utils/dco/git-config.js.map +1 -1
- package/dist/utils/dco/github.d.ts +101 -0
- package/dist/utils/dco/github.d.ts.map +1 -1
- package/dist/utils/dco/github.js +133 -0
- package/dist/utils/dco/github.js.map +1 -1
- package/dist/utils/dco/paths.d.ts +1 -8
- package/dist/utils/dco/paths.d.ts.map +1 -1
- package/dist/utils/dco/paths.js +3 -12
- package/dist/utils/dco/paths.js.map +1 -1
- package/dist/utils/dco/render.d.ts +1 -1
- package/dist/utils/dco/render.d.ts.map +1 -1
- package/dist/utils/dco/render.js +4 -21
- package/dist/utils/dco/render.js.map +1 -1
- package/dist/utils/dco/resolve-agent.d.ts +54 -0
- package/dist/utils/dco/resolve-agent.d.ts.map +1 -0
- package/dist/utils/dco/resolve-agent.js +164 -0
- package/dist/utils/dco/resolve-agent.js.map +1 -0
- package/dist/utils/dco/setup.d.ts +10 -7
- package/dist/utils/dco/setup.d.ts.map +1 -1
- package/dist/utils/dco/setup.js +264 -200
- package/dist/utils/dco/setup.js.map +1 -1
- package/dist/utils/dco/signing-key-writer.d.ts +40 -0
- package/dist/utils/dco/signing-key-writer.d.ts.map +1 -0
- package/dist/utils/dco/signing-key-writer.js +76 -0
- package/dist/utils/dco/signing-key-writer.js.map +1 -0
- package/dist/utils/dco/ssh-key.d.ts +50 -0
- package/dist/utils/dco/ssh-key.d.ts.map +1 -1
- package/dist/utils/dco/ssh-key.js +129 -8
- package/dist/utils/dco/ssh-key.js.map +1 -1
- package/dist/utils/dco/status.d.ts +1 -1
- package/dist/utils/dco/status.d.ts.map +1 -1
- package/dist/utils/dco/status.js +3 -3
- package/dist/utils/dco/status.js.map +1 -1
- package/dist/utils/dco/verify.d.ts +170 -0
- package/dist/utils/dco/verify.d.ts.map +1 -0
- package/dist/utils/dco/verify.js +550 -0
- package/dist/utils/dco/verify.js.map +1 -0
- package/dist/utils/dependency-installer.d.ts +37 -0
- package/dist/utils/dependency-installer.d.ts.map +1 -0
- package/dist/utils/dependency-installer.js +32 -0
- package/dist/utils/dependency-installer.js.map +1 -0
- package/dist/utils/github-credential-stage.d.ts +87 -0
- package/dist/utils/github-credential-stage.d.ts.map +1 -0
- package/dist/utils/github-credential-stage.js +168 -0
- package/dist/utils/github-credential-stage.js.map +1 -0
- package/dist/utils/github-credential.d.ts +160 -0
- package/dist/utils/github-credential.d.ts.map +1 -0
- package/dist/utils/github-credential.js +308 -0
- package/dist/utils/github-credential.js.map +1 -0
- package/dist/utils/gitignore.d.ts +17 -0
- package/dist/utils/gitignore.d.ts.map +1 -0
- package/dist/utils/gitignore.js +40 -0
- package/dist/utils/gitignore.js.map +1 -0
- package/dist/utils/hub-config.d.ts +21 -0
- package/dist/utils/hub-config.d.ts.map +1 -0
- package/dist/utils/hub-config.js +28 -0
- package/dist/utils/hub-config.js.map +1 -0
- package/dist/utils/identity-heal.d.ts +16 -0
- package/dist/utils/identity-heal.d.ts.map +1 -0
- package/dist/utils/identity-heal.js +37 -0
- package/dist/utils/identity-heal.js.map +1 -0
- package/dist/utils/init/pipeline.d.ts +74 -0
- package/dist/utils/init/pipeline.d.ts.map +1 -0
- package/dist/utils/init/pipeline.js +96 -0
- package/dist/utils/init/pipeline.js.map +1 -0
- package/dist/utils/poll.d.ts +15 -1
- package/dist/utils/poll.d.ts.map +1 -1
- package/dist/utils/poll.js +6 -3
- package/dist/utils/poll.js.map +1 -1
- package/dist/utils/register-agent-identity.d.ts +67 -0
- package/dist/utils/register-agent-identity.d.ts.map +1 -0
- package/dist/utils/register-agent-identity.js +34 -0
- package/dist/utils/register-agent-identity.js.map +1 -0
- package/dist/utils/review/did-web-key.d.ts +34 -0
- package/dist/utils/review/did-web-key.d.ts.map +1 -0
- package/dist/utils/review/did-web-key.js +104 -0
- package/dist/utils/review/did-web-key.js.map +1 -0
- package/dist/utils/review/load-registry.d.ts +33 -0
- package/dist/utils/review/load-registry.d.ts.map +1 -0
- package/dist/utils/review/load-registry.js +62 -0
- package/dist/utils/review/load-registry.js.map +1 -0
- package/dist/utils/review/verdict-verify.d.ts +43 -0
- package/dist/utils/review/verdict-verify.d.ts.map +1 -0
- package/dist/utils/review/verdict-verify.js +53 -0
- package/dist/utils/review/verdict-verify.js.map +1 -0
- package/dist/utils/review-registry-writer.d.ts +52 -0
- package/dist/utils/review-registry-writer.d.ts.map +1 -0
- package/dist/utils/review-registry-writer.js +79 -0
- package/dist/utils/review-registry-writer.js.map +1 -0
- package/dist/utils/should-install-dependency.d.ts +17 -0
- package/dist/utils/should-install-dependency.d.ts.map +1 -0
- package/dist/utils/should-install-dependency.js +25 -0
- package/dist/utils/should-install-dependency.js.map +1 -0
- package/dist/utils/tool-readiness.d.ts +57 -0
- package/dist/utils/tool-readiness.d.ts.map +1 -0
- package/dist/utils/tool-readiness.js +114 -0
- package/dist/utils/tool-readiness.js.map +1 -0
- package/dist/utils/which.d.ts +2 -0
- package/dist/utils/which.d.ts.map +1 -0
- package/dist/utils/which.js +22 -0
- package/dist/utils/which.js.map +1 -0
- package/dist/version.d.ts +15 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +29 -0
- package/dist/version.js.map +1 -0
- package/package.json +19 -6
- package/dist/utils/claim-polling.d.ts +0 -21
- package/dist/utils/claim-polling.d.ts.map +0 -1
- package/dist/utils/claim-polling.js.map +0 -1
- package/dist/utils/dco/fs-safe.d.ts +0 -14
- package/dist/utils/dco/fs-safe.d.ts.map +0 -1
- package/dist/utils/dco/fs-safe.js +0 -20
- package/dist/utils/dco/fs-safe.js.map +0 -1
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verdict and quorum store.
|
|
3
|
+
*
|
|
4
|
+
* The point of this module is that both writes are idempotent by NATURAL key,
|
|
5
|
+
* not by a hash of the event that produced them:
|
|
6
|
+
*
|
|
7
|
+
* - a verdict is unique per (repo, pr, head_sha, reviewer_did)
|
|
8
|
+
* - quorum is unique per (repo, pr, head_sha)
|
|
9
|
+
*
|
|
10
|
+
* Those keys are what the review protocol already means, so "have we processed
|
|
11
|
+
* this?" is answered by asking whether the row exists. The previous approach
|
|
12
|
+
* derived a content hash of the hub event and stored a synthetic marker beside
|
|
13
|
+
* the ticket, which needed its own scoping, its own lookup path, and its own
|
|
14
|
+
* durability guarantees -- three review findings' worth of them. A UNIQUE
|
|
15
|
+
* constraint the schema already declared does the same job and cannot expire,
|
|
16
|
+
* collide across tickets, or be looked for in the wrong window.
|
|
17
|
+
*
|
|
18
|
+
* `verdicts` was in the schema from the start with exactly this shape and no
|
|
19
|
+
* reader; this is that reader.
|
|
20
|
+
*
|
|
21
|
+
* @module cli/orchestrator/db/verdicts
|
|
22
|
+
*/
|
|
23
|
+
import { z } from "zod";
|
|
24
|
+
export const VerdictKindSchema = z.enum(["approve", "request-changes", "comment"]);
|
|
25
|
+
export const VerdictRowSchema = z.object({
|
|
26
|
+
id: z.string(),
|
|
27
|
+
ticket_id: z.string().nullable(),
|
|
28
|
+
repo: z.string(),
|
|
29
|
+
pr_number: z.number(),
|
|
30
|
+
head_sha: z.string(),
|
|
31
|
+
reviewer_did: z.string(),
|
|
32
|
+
verdict: VerdictKindSchema,
|
|
33
|
+
findings: z.string().nullable(),
|
|
34
|
+
counted: z.number(),
|
|
35
|
+
received_at: z.string(),
|
|
36
|
+
});
|
|
37
|
+
/**
|
|
38
|
+
* Record one reviewer's verdict on one head SHA.
|
|
39
|
+
*
|
|
40
|
+
* Returns true when something CHANGED: the verdict is new, or the same reviewer
|
|
41
|
+
* revised it on the same head. False means this exact verdict was already
|
|
42
|
+
* recorded, which is a replay, a re-delivered event, or a boot reconcile of a
|
|
43
|
+
* window already processed.
|
|
44
|
+
*
|
|
45
|
+
* `received_at` is NEVER rewritten on conflict: it is the FIRST sighting of this
|
|
46
|
+
* head, which head ranking depends on, and letting a late revision move it
|
|
47
|
+
* contradicted the very function that reads it. A revision updates the verdict,
|
|
48
|
+
* not when the head was first seen.
|
|
49
|
+
*
|
|
50
|
+
* The mind-change case is why this is an upsert rather than INSERT OR IGNORE.
|
|
51
|
+
* The hub explicitly permits a reviewer to follow an approval with
|
|
52
|
+
* request-changes on the SAME head and emits a second review_verdict for it. On
|
|
53
|
+
* a plain OR IGNORE that second verdict is dropped as "already handled" and the
|
|
54
|
+
* ticket never goes back to in-progress -- a reviewer withdrawing approval would
|
|
55
|
+
* be silently overruled by a uniqueness constraint.
|
|
56
|
+
*
|
|
57
|
+
* The guarded UPDATE is what keeps false meaning "nothing to do": re-delivering
|
|
58
|
+
* an identical verdict fails the WHERE, changes no rows, and reports false.
|
|
59
|
+
* `findings` is part of that comparison so a revision that only changes its
|
|
60
|
+
* reasons is still stored -- otherwise the recorded findings silently went stale
|
|
61
|
+
* while the verdict itself looked current.
|
|
62
|
+
*
|
|
63
|
+
* The id is a readable composite of the natural key rather than a hash, so a row
|
|
64
|
+
* can be found by hand in a debugging session.
|
|
65
|
+
*/
|
|
66
|
+
export function recordVerdict(db, input) {
|
|
67
|
+
const id = `${input.repo}#${input.prNumber}#${input.headSha}#${input.reviewerDid}`;
|
|
68
|
+
const info = db
|
|
69
|
+
.prepare(`INSERT INTO verdicts
|
|
70
|
+
(id, ticket_id, repo, pr_number, head_sha, reviewer_did, verdict, findings, counted, received_at)
|
|
71
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
72
|
+
ON CONFLICT(repo, pr_number, head_sha, reviewer_did) DO UPDATE SET
|
|
73
|
+
verdict = excluded.verdict,
|
|
74
|
+
findings = excluded.findings,
|
|
75
|
+
counted = excluded.counted,
|
|
76
|
+
ticket_id = excluded.ticket_id
|
|
77
|
+
WHERE verdicts.verdict IS NOT excluded.verdict
|
|
78
|
+
OR verdicts.counted IS NOT excluded.counted
|
|
79
|
+
OR verdicts.findings IS NOT excluded.findings`)
|
|
80
|
+
.run(id, input.ticketId, input.repo, input.prNumber, input.headSha, input.reviewerDid, input.verdict, input.findings === undefined ? null : JSON.stringify(input.findings), input.counted ? 1 : 0, new Date(input.observedAt).toISOString());
|
|
81
|
+
return info.changes > 0;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Record that the hub declared quorum on one head SHA.
|
|
85
|
+
*
|
|
86
|
+
* Returns true when it was new. Quorum is stored rather than recomputed because
|
|
87
|
+
* the hub owns verdict validation, and a second implementation of the threshold
|
|
88
|
+
* here could disagree with the one that actually gated the decision.
|
|
89
|
+
*/
|
|
90
|
+
export function recordQuorum(db, input) {
|
|
91
|
+
const info = db
|
|
92
|
+
.prepare(`INSERT OR IGNORE INTO pr_quorum (repo, pr_number, head_sha, ticket_id, quorum_n, reached_at)
|
|
93
|
+
VALUES (?, ?, ?, ?, ?, ?)`)
|
|
94
|
+
.run(input.repo, input.prNumber, input.headSha, input.ticketId, input.quorumN ?? null, new Date(input.observedAt).toISOString());
|
|
95
|
+
return info.changes > 0;
|
|
96
|
+
}
|
|
97
|
+
/** Every verdict on one PR head, newest first. */
|
|
98
|
+
export function listVerdictsForPr(db, repo, prNumber, headSha) {
|
|
99
|
+
const rows = headSha
|
|
100
|
+
? db
|
|
101
|
+
.prepare(`SELECT * FROM verdicts WHERE repo = ? AND pr_number = ? AND head_sha = ?
|
|
102
|
+
ORDER BY received_at DESC, id`)
|
|
103
|
+
.all(repo, prNumber, headSha)
|
|
104
|
+
: db
|
|
105
|
+
.prepare(`SELECT * FROM verdicts WHERE repo = ? AND pr_number = ? ORDER BY received_at DESC, id`)
|
|
106
|
+
.all(repo, prNumber);
|
|
107
|
+
return z.array(VerdictRowSchema).parse(rows);
|
|
108
|
+
}
|
|
109
|
+
/** Has the hub already declared quorum on this head? */
|
|
110
|
+
export function quorumReached(db, repo, prNumber, headSha) {
|
|
111
|
+
return (db
|
|
112
|
+
.prepare(`SELECT 1 FROM pr_quorum WHERE repo = ? AND pr_number = ? AND head_sha = ?`)
|
|
113
|
+
.get(repo, prNumber, headSha) !== undefined);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* The most recently seen head SHA for a pull request.
|
|
117
|
+
*
|
|
118
|
+
* Which revision the ledger currently believes is live. A push invalidates every
|
|
119
|
+
* prior verdict (the review protocol's settled rule), so status has to be derived
|
|
120
|
+
* from the newest head rather than from whichever head the event in hand names --
|
|
121
|
+
* otherwise a late or replayed quorum for superseded code moves current work.
|
|
122
|
+
* `counted: false` marks a stale VERDICT; quorum has no such flag.
|
|
123
|
+
*
|
|
124
|
+
* Ranked by when each head was FIRST seen, not when it was last touched. This is
|
|
125
|
+
* the whole correctness of the function. Ranking by last-touched let any newly
|
|
126
|
+
* recorded row for an older SHA promote it to "latest" -- including an uncounted
|
|
127
|
+
* stale verdict kept purely as evidence. Historical quorum on that superseded
|
|
128
|
+
* head would then clear a live objection on the real one, defeating the
|
|
129
|
+
* uncounted guard this derivation depends on. A head's first sighting cannot be
|
|
130
|
+
* moved by a late arrival, because the upsert never rewrites `received_at`.
|
|
131
|
+
*
|
|
132
|
+
* "When" is PROTOCOL time -- the hub event's own timestamp, carried in on
|
|
133
|
+
* `observedAt` -- not the wall clock at insert. Insert time made this a coin
|
|
134
|
+
* flip in the one case that matters most: on a cold start, `reconcileReviewState`
|
|
135
|
+
* replays the window fast enough that consecutive better-sqlite3 inserts land in
|
|
136
|
+
* the same millisecond, so every head tied and the winner fell to the SHA
|
|
137
|
+
* tiebreak. Half the time that elected the OLD head, derived a historical quorum
|
|
138
|
+
* against it, and moved a ticket to `ready` straight past a live counted
|
|
139
|
+
* request-changes on the new one.
|
|
140
|
+
*
|
|
141
|
+
* Ties still break on head_sha, for genuinely simultaneous protocol timestamps:
|
|
142
|
+
* an arbitrary-but-stable answer beats a fresh coin flip per query, and truly
|
|
143
|
+
* simultaneous revisions are ambiguous under any rule.
|
|
144
|
+
*/
|
|
145
|
+
export function latestHeadForPr(db, repo, prNumber) {
|
|
146
|
+
const row = db
|
|
147
|
+
.prepare(`SELECT head_sha FROM (
|
|
148
|
+
SELECT head_sha, MIN(at) AS first_seen FROM (
|
|
149
|
+
SELECT head_sha, received_at AS at FROM verdicts WHERE repo = ? AND pr_number = ?
|
|
150
|
+
UNION ALL
|
|
151
|
+
SELECT head_sha, reached_at AS at FROM pr_quorum WHERE repo = ? AND pr_number = ?
|
|
152
|
+
)
|
|
153
|
+
GROUP BY head_sha
|
|
154
|
+
) ORDER BY first_seen DESC, head_sha DESC LIMIT 1`)
|
|
155
|
+
.get(repo, prNumber, repo, prNumber);
|
|
156
|
+
if (row === undefined || row === null)
|
|
157
|
+
return undefined;
|
|
158
|
+
return z.object({ head_sha: z.string() }).parse(row).head_sha;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* The same ranking as {@link latestHeadForPr}, blind to uncounted verdicts.
|
|
162
|
+
*
|
|
163
|
+
* `latestHeadForPr` deliberately ranks EVERY verdict, counted or not -- a
|
|
164
|
+
* verdict naming a stale or malformed SHA still proves the hub saw that SHA,
|
|
165
|
+
* which is what that function's contract promises. But "a SHA was mentioned"
|
|
166
|
+
* and "a SHA was genuinely reviewed" are different questions, and DERIVING
|
|
167
|
+
* status needs the second one: a verdict the hub itself flagged invalid must
|
|
168
|
+
* not be able to outrank a real counted verdict or quorum recorded on a
|
|
169
|
+
* different head just because it happened to arrive with a later protocol
|
|
170
|
+
* timestamp. Left unfiltered, that lets review noise on a throwaway SHA
|
|
171
|
+
* occlude a real objection sitting under the head that actually matters --
|
|
172
|
+
* the ticket keeps whatever status the occluded head implied, forever,
|
|
173
|
+
* because nothing ever asks about that head again.
|
|
174
|
+
*
|
|
175
|
+
* Quorum rows carry no `counted` column and are never filtered here, the same
|
|
176
|
+
* way {@link latestHeadForPr} treats them: the hub is the sole authority for
|
|
177
|
+
* quorum, so a recorded quorum is trusted unconditionally.
|
|
178
|
+
*
|
|
179
|
+
* Returns undefined when no head has ANY trusted evidence yet -- distinct
|
|
180
|
+
* from "no evidence at all," which only {@link latestHeadForPr} can answer.
|
|
181
|
+
*/
|
|
182
|
+
export function latestTrustedHeadForPr(db, repo, prNumber) {
|
|
183
|
+
const row = db
|
|
184
|
+
.prepare(`SELECT head_sha FROM (
|
|
185
|
+
SELECT head_sha, MIN(at) AS first_seen FROM (
|
|
186
|
+
SELECT head_sha, received_at AS at FROM verdicts WHERE repo = ? AND pr_number = ? AND counted = 1
|
|
187
|
+
UNION ALL
|
|
188
|
+
SELECT head_sha, reached_at AS at FROM pr_quorum WHERE repo = ? AND pr_number = ?
|
|
189
|
+
)
|
|
190
|
+
GROUP BY head_sha
|
|
191
|
+
) ORDER BY first_seen DESC, head_sha DESC LIMIT 1`)
|
|
192
|
+
.get(repo, prNumber, repo, prNumber);
|
|
193
|
+
if (row === undefined || row === null)
|
|
194
|
+
return undefined;
|
|
195
|
+
return z.object({ head_sha: z.string() }).parse(row).head_sha;
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=verdicts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verdicts.js","sourceRoot":"","sources":["../../../src/orchestrator/db/verdicts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* The slice of the coordination hub this package consumes (ORC-W1 PR-2).
|
|
4
|
+
*
|
|
5
|
+
* Declared structurally rather than imported from `@kya-os/compute`, matching
|
|
6
|
+
* how `review-coordinator.ts` declares `DispatchHub` in that same package and
|
|
7
|
+
* for the same reason: tests drive a lightweight fake instead of standing up a
|
|
8
|
+
* real hub, and the orchestrator stays decoupled from where the hub runs. It
|
|
9
|
+
* can be embedded locally today and remote later without this package moving.
|
|
10
|
+
*
|
|
11
|
+
* @module orchestrator/events
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* A hub event as observed by the daemon.
|
|
15
|
+
*
|
|
16
|
+
* `type` is a bare `string`, deliberately NOT the hub's union. The union
|
|
17
|
+
* widens over time (`review_verdict` and `pr_quorum_reached` arrived with
|
|
18
|
+
* xmcp-i#661) and this package must persist an event type it has never been
|
|
19
|
+
* taught rather than drop it. Narrowing here would mean a hub release could
|
|
20
|
+
* silently cost the ledger exactly the events worth having, and ORC-W3
|
|
21
|
+
* depends on that not happening.
|
|
22
|
+
*/
|
|
23
|
+
export interface HubEventLike {
|
|
24
|
+
type: string;
|
|
25
|
+
timestamp: number;
|
|
26
|
+
agentDid: string;
|
|
27
|
+
agentName: string;
|
|
28
|
+
data: Record<string, unknown>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Runtime shape check for a frame claiming to be a {@link HubEventLike}.
|
|
32
|
+
*
|
|
33
|
+
* `type` stays `z.string().min(1)` rather than an enum, for the identical
|
|
34
|
+
* reason the interface above does: the hub's event union widens over time and
|
|
35
|
+
* this must keep persisting a type it has never been taught. What this DOES
|
|
36
|
+
* reject is a frame missing the fields every event actually carries -- the gap
|
|
37
|
+
* an unchecked `as HubEventLike` cast over a WebSocket leaves wide open, since
|
|
38
|
+
* nothing on the wire guarantees the hub (or anything speaking its protocol)
|
|
39
|
+
* sent a well-formed frame.
|
|
40
|
+
*/
|
|
41
|
+
export declare const HubEventLikeSchema: z.ZodObject<{
|
|
42
|
+
type: z.ZodString;
|
|
43
|
+
timestamp: z.ZodNumber;
|
|
44
|
+
agentDid: z.ZodString;
|
|
45
|
+
agentName: z.ZodString;
|
|
46
|
+
data: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
47
|
+
}, "strip", z.ZodTypeAny, {
|
|
48
|
+
data: Record<string, unknown>;
|
|
49
|
+
type: string;
|
|
50
|
+
timestamp: number;
|
|
51
|
+
agentDid: string;
|
|
52
|
+
agentName: string;
|
|
53
|
+
}, {
|
|
54
|
+
data: Record<string, unknown>;
|
|
55
|
+
type: string;
|
|
56
|
+
timestamp: number;
|
|
57
|
+
agentDid: string;
|
|
58
|
+
agentName: string;
|
|
59
|
+
}>;
|
|
60
|
+
/** Subscription surface. `onEvent` returns its own unsubscribe, as the hub's does. */
|
|
61
|
+
export interface EventSource {
|
|
62
|
+
onEvent(handler: (event: HubEventLike) => void): () => void;
|
|
63
|
+
/**
|
|
64
|
+
* Recent events, used once on boot to reconcile what the daemon slept
|
|
65
|
+
* through. The hub's own signature defaults to 50.
|
|
66
|
+
*/
|
|
67
|
+
getRecentEvents(limit?: number): HubEventLike[];
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/orchestrator/events.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;GAUG;AAEH;;;;;;;;;GASG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;EAM7B,CAAC;AAEH,sFAAsF;AACtF,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAC5D;;;OAGG;IACH,eAAe,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,YAAY,EAAE,CAAC;CACjD"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Runtime shape check for a frame claiming to be a {@link HubEventLike}.
|
|
4
|
+
*
|
|
5
|
+
* `type` stays `z.string().min(1)` rather than an enum, for the identical
|
|
6
|
+
* reason the interface above does: the hub's event union widens over time and
|
|
7
|
+
* this must keep persisting a type it has never been taught. What this DOES
|
|
8
|
+
* reject is a frame missing the fields every event actually carries -- the gap
|
|
9
|
+
* an unchecked `as HubEventLike` cast over a WebSocket leaves wide open, since
|
|
10
|
+
* nothing on the wire guarantees the hub (or anything speaking its protocol)
|
|
11
|
+
* sent a well-formed frame.
|
|
12
|
+
*/
|
|
13
|
+
export const HubEventLikeSchema = z.object({
|
|
14
|
+
type: z.string().min(1),
|
|
15
|
+
timestamp: z.number(),
|
|
16
|
+
agentDid: z.string(),
|
|
17
|
+
agentName: z.string(),
|
|
18
|
+
data: z.record(z.string(), z.unknown()),
|
|
19
|
+
});
|
|
20
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/orchestrator/events.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAgCxB;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACvB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;IACpB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;CACxC,CAAC,CAAC"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anchoring a GitHub credential in the hub (review-loop P16, commit 3).
|
|
3
|
+
*
|
|
4
|
+
* Builds a signed `GithubCredentialAnchor` (see `@kya-os/contracts/handshake/
|
|
5
|
+
* github-credential-anchor.ts`) from a locally stored credential
|
|
6
|
+
* (`utils/github-credential.ts`) and delivers it to the configured hub over
|
|
7
|
+
* the SAME observer wire path `hub-observer.ts` speaks: `observe` hello,
|
|
8
|
+
* challenge, proof-of-possession -- see that file's module doc for why this
|
|
9
|
+
* package never imports `@kya-os/compute` and instead speaks the shared
|
|
10
|
+
* wire format directly. Unlike `HubObserver`, this is a ONE-SHOT
|
|
11
|
+
* connect/authenticate/submit/await-result/close, not a long-lived
|
|
12
|
+
* reconnecting subscription -- a different lifecycle for a different job,
|
|
13
|
+
* so it does not extend or wrap that class.
|
|
14
|
+
*
|
|
15
|
+
* The anchor is signed and the wire connection authenticated with the SAME
|
|
16
|
+
* key: the designated agent profile's signing key
|
|
17
|
+
* (`signingKeyPath(agentSlug)`, the exact file `dco setup`/`dco fix` already
|
|
18
|
+
* use -- see `ssh-key.ts`'s `parseEd25519SshPrivateKeyPem`). That is what
|
|
19
|
+
* lets the hub check "the anchor's proof verifies against the DID that
|
|
20
|
+
* authenticated this very connection" without a second key or a fresh
|
|
21
|
+
* resolution: the hub already knows this socket proved control of `did`
|
|
22
|
+
* before a single `credential_anchor` frame arrives.
|
|
23
|
+
*
|
|
24
|
+
* No hub configured, or the hub unreachable: the anchor is queued at
|
|
25
|
+
* `~/.mcpi/github/pending-anchor.json` (fingerprints and proof only -- by
|
|
26
|
+
* construction, since `GithubCredentialAnchorSchema` holds no secret) for a
|
|
27
|
+
* later `kya-os init` or P17's wrapper connection to deliver.
|
|
28
|
+
*
|
|
29
|
+
* @module cli/orchestrator/github-credential-anchor-sender
|
|
30
|
+
*/
|
|
31
|
+
import WebSocket from "ws";
|
|
32
|
+
import { type GithubCredentialAnchor } from "@kya-os/contracts/handshake";
|
|
33
|
+
import { type ObserverIdentity } from "./hub-observer.js";
|
|
34
|
+
import { type StoredGithubCredential } from "../utils/github-credential.js";
|
|
35
|
+
export interface BuildGithubCredentialAnchorParams {
|
|
36
|
+
/** The profile signing this anchor -- its DID goes on the wire; its slug locates `signingKeyPath`. */
|
|
37
|
+
agentDid: string;
|
|
38
|
+
agentSlug: string;
|
|
39
|
+
/** All profile DIDs authorized to use this credential, including the signer's. */
|
|
40
|
+
agentDids: string[];
|
|
41
|
+
/** Prior anchor's tokenFingerprint, when this anchor rotates one out. */
|
|
42
|
+
supersedes?: string;
|
|
43
|
+
now?: () => string;
|
|
44
|
+
/** Reads the profile's converted signing key PEM. Injectable for tests. */
|
|
45
|
+
readSigningKeyPemImpl?: (agentSlug: string) => string;
|
|
46
|
+
}
|
|
47
|
+
export interface BuiltGithubCredentialAnchor {
|
|
48
|
+
anchor: GithubCredentialAnchor;
|
|
49
|
+
/**
|
|
50
|
+
* The SAME key that signed the anchor, reused to authenticate the wire
|
|
51
|
+
* connection that delivers it (see the module doc for why one key does
|
|
52
|
+
* both jobs). Never anything but this key's DID + seed -- no secret from
|
|
53
|
+
* `credential` is ever in reach of this value.
|
|
54
|
+
*/
|
|
55
|
+
identity: ObserverIdentity;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Derive the `ObserverIdentity` (did + raw Ed25519 seed) an agent profile
|
|
59
|
+
* signs and authenticates with, from its converted signing key file
|
|
60
|
+
* (`signingKeyPath(agentSlug)`, the same file `dco setup`/`dco fix` use).
|
|
61
|
+
* Shared by {@link buildGithubCredentialAnchor} (a fresh anchor's signer)
|
|
62
|
+
* and `github-credential-stage.ts` (re-authenticating to deliver a
|
|
63
|
+
* previously queued anchor, where no new anchor is being built) so both
|
|
64
|
+
* paths derive the SAME identity for the same profile from one place.
|
|
65
|
+
*/
|
|
66
|
+
export declare function identityForAgentProfile(agentDid: string, agentSlug: string, readSigningKeyPemImpl?: (agentSlug: string) => string): ObserverIdentity;
|
|
67
|
+
/**
|
|
68
|
+
* Build and sign a `GithubCredentialAnchor` for `credential`. Signing stays
|
|
69
|
+
* entirely inside this module -- callers never touch key material, only the
|
|
70
|
+
* finished anchor and the identity derived alongside it (matching how
|
|
71
|
+
* `dco fix.ts` keeps its Ed25519 seed scoped to one function, extended here
|
|
72
|
+
* to the one extra byproduct -- the wire identity -- that a second read of
|
|
73
|
+
* the same file would otherwise require).
|
|
74
|
+
*/
|
|
75
|
+
export declare function buildGithubCredentialAnchor(credential: Pick<StoredGithubCredential, "githubLogin" | "token" | "webhookSecret" | "scopes">, fingerprints: {
|
|
76
|
+
tokenFingerprint: string;
|
|
77
|
+
webhookSecretFingerprint: string;
|
|
78
|
+
}, params: BuildGithubCredentialAnchorParams): BuiltGithubCredentialAnchor;
|
|
79
|
+
export type SendGithubCredentialAnchorResult = {
|
|
80
|
+
delivered: true;
|
|
81
|
+
} | {
|
|
82
|
+
delivered: false;
|
|
83
|
+
reason: string;
|
|
84
|
+
};
|
|
85
|
+
export interface SendGithubCredentialAnchorOptions {
|
|
86
|
+
endpoint: string;
|
|
87
|
+
identity: ObserverIdentity;
|
|
88
|
+
/** Ms to wait for the whole exchange (connect through result). Default 10s. */
|
|
89
|
+
timeoutMs?: number;
|
|
90
|
+
/** DI seam for tests -- default `new WebSocket(endpoint)`. */
|
|
91
|
+
wsFactory?: (endpoint: string) => WebSocket;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Connect to the hub as an authenticated observer, submit `anchor` once
|
|
95
|
+
* admitted, and resolve with whether the hub accepted it. Always settles
|
|
96
|
+
* (never hangs): a timeout, a socket error, or an early close all resolve
|
|
97
|
+
* `{ delivered: false, reason }` rather than rejecting -- the caller's
|
|
98
|
+
* fallback is "queue it locally," not "crash the init stage."
|
|
99
|
+
*/
|
|
100
|
+
export declare function sendGithubCredentialAnchor(anchor: GithubCredentialAnchor, options: SendGithubCredentialAnchorOptions): Promise<SendGithubCredentialAnchorResult>;
|
|
101
|
+
/** ~/.mcpi/github/pending-anchor.json -- fingerprints and proof only; no secrets by construction. */
|
|
102
|
+
export declare function pendingAnchorPath(): string;
|
|
103
|
+
/**
|
|
104
|
+
* A queued anchor, plus the DID of the profile that actually SIGNED it.
|
|
105
|
+
* Retrying delivery must re-authenticate as exactly that DID -- the hub
|
|
106
|
+
* checks the anchor's proof against the wire connection's own key, so
|
|
107
|
+
* anything else fails verification. `agentDids` (on the anchor itself)
|
|
108
|
+
* lists every profile AUTHORIZED to use the credential, not which one
|
|
109
|
+
* signed this particular anchor, so the signer has to be recorded
|
|
110
|
+
* separately rather than assumed from array position.
|
|
111
|
+
*/
|
|
112
|
+
export interface PendingGithubCredentialAnchor {
|
|
113
|
+
anchor: GithubCredentialAnchor;
|
|
114
|
+
signerDid: string;
|
|
115
|
+
}
|
|
116
|
+
/** The queued anchor and its signer, or undefined if none is pending (or the file is unreadable/corrupt). */
|
|
117
|
+
export declare function readPendingAnchor(): PendingGithubCredentialAnchor | undefined;
|
|
118
|
+
export declare function clearPendingAnchor(): void;
|
|
119
|
+
export type DeliverGithubCredentialAnchorResult = {
|
|
120
|
+
status: "delivered";
|
|
121
|
+
} | {
|
|
122
|
+
status: "pending";
|
|
123
|
+
reason: string;
|
|
124
|
+
};
|
|
125
|
+
export interface DeliverGithubCredentialAnchorOptions {
|
|
126
|
+
/** undefined means "not configured" -- resolved by the caller from --hub / DIDCOMM_HUB_ENDPOINT. */
|
|
127
|
+
hubEndpoint?: string;
|
|
128
|
+
sendImpl?: typeof sendGithubCredentialAnchor;
|
|
129
|
+
onNotice?: (message: string) => void;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Deliver `anchor` to the hub if one is configured and reachable; otherwise
|
|
133
|
+
* queue it at {@link pendingAnchorPath} and exit cleanly. Never throws --
|
|
134
|
+
* every failure mode degrades to "pending," which is exactly the offline
|
|
135
|
+
* path the init stage needs to complete without a hub.
|
|
136
|
+
*/
|
|
137
|
+
export declare function deliverGithubCredentialAnchor(anchor: GithubCredentialAnchor, identity: ObserverIdentity, options?: DeliverGithubCredentialAnchorOptions): Promise<DeliverGithubCredentialAnchorResult>;
|
|
138
|
+
/**
|
|
139
|
+
* Attempt delivery of a previously queued anchor (e.g. from a later
|
|
140
|
+
* `kya-os init`, or P17's wrapper connection). A no-op, reported distinctly,
|
|
141
|
+
* when nothing is queued.
|
|
142
|
+
*
|
|
143
|
+
* `resolveIdentity` maps the queued anchor's recorded `signerDid` to that
|
|
144
|
+
* profile's CURRENT identity -- never a caller-guessed one. `listProfiles()`
|
|
145
|
+
* has no defined order (`readdirSync`), so "the first profile on the
|
|
146
|
+
* machine" today is not reliably the profile that signed a PRIOR anchor;
|
|
147
|
+
* looking it up by the DID actually recorded at queue time is what makes
|
|
148
|
+
* this retry succeed instead of failing proof verification against the
|
|
149
|
+
* wrong key. Never throws, matching every other function in this module's
|
|
150
|
+
* "degrade to pending" contract: `resolveIdentity` typically ends up
|
|
151
|
+
* calling {@link identityForAgentProfile}, which reads a signing key file
|
|
152
|
+
* off disk and throws if it's missing or unreadable -- a real possibility
|
|
153
|
+
* (deleted, corrupted, permissions) that must fall through to "pending"
|
|
154
|
+
* exactly like a resolved-but-unusable identity, not crash the caller.
|
|
155
|
+
*/
|
|
156
|
+
export declare function deliverPendingGithubCredentialAnchor(resolveIdentity: (signerDid: string) => ObserverIdentity | undefined, options?: DeliverGithubCredentialAnchorOptions): Promise<DeliverGithubCredentialAnchorResult | {
|
|
157
|
+
status: "none";
|
|
158
|
+
}>;
|
|
159
|
+
//# sourceMappingURL=github-credential-anchor-sender.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-credential-anchor-sender.d.ts","sourceRoot":"","sources":["../../src/orchestrator/github-credential-anchor-sender.ts"],"names":[],"mappings":"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"}
|