@ashlr/hub 2.2.0 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/README.md +95 -8
  3. package/dist/api/plugin.d.ts +1 -0
  4. package/dist/cli/backlog.js +2 -0
  5. package/dist/cli/backlog.js.map +1 -1
  6. package/dist/cli/digest.d.ts +6 -0
  7. package/dist/cli/digest.js +127 -2
  8. package/dist/cli/digest.js.map +1 -1
  9. package/dist/cli/eval-fixtures.d.ts +18 -0
  10. package/dist/cli/eval-fixtures.js +38 -0
  11. package/dist/cli/eval-fixtures.js.map +1 -0
  12. package/dist/cli/eval.d.ts +56 -0
  13. package/dist/cli/eval.js +283 -0
  14. package/dist/cli/eval.js.map +1 -0
  15. package/dist/cli/fleet.d.ts +27 -0
  16. package/dist/cli/fleet.js +222 -0
  17. package/dist/cli/fleet.js.map +1 -0
  18. package/dist/cli/goal.d.ts +15 -0
  19. package/dist/cli/goal.js +91 -0
  20. package/dist/cli/goal.js.map +1 -0
  21. package/dist/cli/help.js +10 -3
  22. package/dist/cli/help.js.map +1 -1
  23. package/dist/cli/inbox.d.ts +6 -0
  24. package/dist/cli/inbox.js +183 -8
  25. package/dist/cli/inbox.js.map +1 -1
  26. package/dist/cli/index.js +50 -0
  27. package/dist/cli/index.js.map +1 -1
  28. package/dist/cli/loop.d.ts +16 -0
  29. package/dist/cli/loop.js +66 -0
  30. package/dist/cli/loop.js.map +1 -0
  31. package/dist/cli/mcp.d.ts +12 -0
  32. package/dist/cli/mcp.js +148 -0
  33. package/dist/cli/mcp.js.map +1 -1
  34. package/dist/cli/onboard.d.ts +16 -0
  35. package/dist/cli/onboard.js +71 -0
  36. package/dist/cli/onboard.js.map +1 -1
  37. package/dist/cli/plugins.js +9 -8
  38. package/dist/cli/plugins.js.map +1 -1
  39. package/dist/cli/pulse.d.ts +10 -0
  40. package/dist/cli/pulse.js +261 -0
  41. package/dist/cli/pulse.js.map +1 -1
  42. package/dist/cli/run.js +21 -3
  43. package/dist/cli/run.js.map +1 -1
  44. package/dist/cli/stack.d.ts +34 -0
  45. package/dist/cli/stack.js +221 -0
  46. package/dist/cli/stack.js.map +1 -0
  47. package/dist/cli/update.js +12 -5
  48. package/dist/cli/update.js.map +1 -1
  49. package/dist/core/daemon/loop.d.ts +10 -5
  50. package/dist/core/daemon/loop.js +167 -37
  51. package/dist/core/daemon/loop.js.map +1 -1
  52. package/dist/core/env-bridge.js +3 -2
  53. package/dist/core/env-bridge.js.map +1 -1
  54. package/dist/core/fleet/automerge-pass.d.ts +33 -0
  55. package/dist/core/fleet/automerge-pass.js +61 -0
  56. package/dist/core/fleet/automerge-pass.js.map +1 -0
  57. package/dist/core/fleet/quota.d.ts +70 -0
  58. package/dist/core/fleet/quota.js +198 -0
  59. package/dist/core/fleet/quota.js.map +1 -0
  60. package/dist/core/fleet/router.d.ts +46 -0
  61. package/dist/core/fleet/router.js +121 -0
  62. package/dist/core/fleet/router.js.map +1 -0
  63. package/dist/core/fleet/self.d.ts +58 -0
  64. package/dist/core/fleet/self.js +187 -0
  65. package/dist/core/fleet/self.js.map +1 -0
  66. package/dist/core/fleet/status.d.ts +54 -0
  67. package/dist/core/fleet/status.js +157 -0
  68. package/dist/core/fleet/status.js.map +1 -0
  69. package/dist/core/foundry/provenance.d.ts +78 -0
  70. package/dist/core/foundry/provenance.js +172 -0
  71. package/dist/core/foundry/provenance.js.map +1 -0
  72. package/dist/core/git.d.ts +13 -0
  73. package/dist/core/git.js +26 -0
  74. package/dist/core/git.js.map +1 -1
  75. package/dist/core/inbox/merge.d.ts +151 -0
  76. package/dist/core/inbox/merge.js +858 -0
  77. package/dist/core/inbox/merge.js.map +1 -0
  78. package/dist/core/inbox/store.js +10 -1
  79. package/dist/core/inbox/store.js.map +1 -1
  80. package/dist/core/integrations/markdown.d.ts +66 -0
  81. package/dist/core/integrations/markdown.js +132 -0
  82. package/dist/core/integrations/markdown.js.map +1 -0
  83. package/dist/core/integrations/secrets.d.ts +37 -0
  84. package/dist/core/integrations/secrets.js +67 -0
  85. package/dist/core/integrations/secrets.js.map +1 -0
  86. package/dist/core/integrations/stack.d.ts +47 -0
  87. package/dist/core/integrations/stack.js +107 -0
  88. package/dist/core/integrations/stack.js.map +1 -0
  89. package/dist/core/mcp-native-engineer.d.ts +123 -0
  90. package/dist/core/mcp-native-engineer.js +936 -0
  91. package/dist/core/mcp-native-engineer.js.map +1 -0
  92. package/dist/core/mcp-native.js +20 -42
  93. package/dist/core/mcp-native.js.map +1 -1
  94. package/dist/core/mcp-registry.js +2 -0
  95. package/dist/core/mcp-registry.js.map +1 -1
  96. package/dist/core/observability/codex-source.d.ts +53 -0
  97. package/dist/core/observability/codex-source.js +390 -0
  98. package/dist/core/observability/codex-source.js.map +1 -0
  99. package/dist/core/observability/estimate.d.ts +12 -0
  100. package/dist/core/observability/estimate.js +26 -0
  101. package/dist/core/observability/estimate.js.map +1 -1
  102. package/dist/core/observability/limits.d.ts +52 -0
  103. package/dist/core/observability/limits.js +316 -0
  104. package/dist/core/observability/limits.js.map +1 -0
  105. package/dist/core/observability/usage-source.js +3 -1
  106. package/dist/core/observability/usage-source.js.map +1 -1
  107. package/dist/core/portfolio/scanners.d.ts +1 -0
  108. package/dist/core/portfolio/scanners.js +40 -1
  109. package/dist/core/portfolio/scanners.js.map +1 -1
  110. package/dist/core/providers.js +4 -0
  111. package/dist/core/providers.js.map +1 -1
  112. package/dist/core/quality/health.js +1 -0
  113. package/dist/core/quality/health.js.map +1 -1
  114. package/dist/core/run/agent-loop.d.ts +8 -0
  115. package/dist/core/run/agent-loop.js +24 -14
  116. package/dist/core/run/agent-loop.js.map +1 -1
  117. package/dist/core/run/engine-registry.d.ts +48 -0
  118. package/dist/core/run/engine-registry.js +190 -0
  119. package/dist/core/run/engine-registry.js.map +1 -0
  120. package/dist/core/run/engines.d.ts +17 -3
  121. package/dist/core/run/engines.js +63 -44
  122. package/dist/core/run/engines.js.map +1 -1
  123. package/dist/core/run/learned-router.d.ts +121 -0
  124. package/dist/core/run/learned-router.js +374 -0
  125. package/dist/core/run/learned-router.js.map +1 -0
  126. package/dist/core/run/model-manager.js +3 -3
  127. package/dist/core/run/model-manager.js.map +1 -1
  128. package/dist/core/run/model-profile.d.ts +67 -0
  129. package/dist/core/run/model-profile.js +132 -0
  130. package/dist/core/run/model-profile.js.map +1 -0
  131. package/dist/core/run/orchestrator.d.ts +1 -1
  132. package/dist/core/run/orchestrator.js +642 -510
  133. package/dist/core/run/orchestrator.js.map +1 -1
  134. package/dist/core/run/prompts/budget.d.ts +25 -0
  135. package/dist/core/run/prompts/budget.js +51 -0
  136. package/dist/core/run/prompts/budget.js.map +1 -0
  137. package/dist/core/run/prompts/index.d.ts +14 -0
  138. package/dist/core/run/prompts/index.js +59 -0
  139. package/dist/core/run/prompts/index.js.map +1 -0
  140. package/dist/core/run/prompts/layers.d.ts +26 -0
  141. package/dist/core/run/prompts/layers.js +73 -0
  142. package/dist/core/run/prompts/layers.js.map +1 -0
  143. package/dist/core/run/prompts/roles.d.ts +23 -0
  144. package/dist/core/run/prompts/roles.js +48 -0
  145. package/dist/core/run/prompts/roles.js.map +1 -0
  146. package/dist/core/run/prompts/types.d.ts +38 -0
  147. package/dist/core/run/prompts/types.js +5 -0
  148. package/dist/core/run/prompts/types.js.map +1 -0
  149. package/dist/core/run/provider-client.d.ts +6 -24
  150. package/dist/core/run/provider-client.js +125 -61
  151. package/dist/core/run/provider-client.js.map +1 -1
  152. package/dist/core/run/router.js +8 -0
  153. package/dist/core/run/router.js.map +1 -1
  154. package/dist/core/run/sandboxed-engine.d.ts +66 -0
  155. package/dist/core/run/sandboxed-engine.js +262 -0
  156. package/dist/core/run/sandboxed-engine.js.map +1 -0
  157. package/dist/core/run/verify-commands.d.ts +83 -0
  158. package/dist/core/run/verify-commands.js +234 -0
  159. package/dist/core/run/verify-commands.js.map +1 -0
  160. package/dist/core/run/verify.d.ts +31 -1
  161. package/dist/core/run/verify.js +48 -0
  162. package/dist/core/run/verify.js.map +1 -1
  163. package/dist/core/sandbox/audit.d.ts +27 -0
  164. package/dist/core/sandbox/audit.js +34 -0
  165. package/dist/core/sandbox/audit.js.map +1 -1
  166. package/dist/core/sandbox/confine.d.ts +134 -0
  167. package/dist/core/sandbox/confine.js +370 -0
  168. package/dist/core/sandbox/confine.js.map +1 -0
  169. package/dist/core/types.d.ts +227 -5
  170. package/dist/core/web/api.js +77 -28
  171. package/dist/core/web/api.js.map +1 -1
  172. package/dist/core/web/control.d.ts +116 -0
  173. package/dist/core/web/control.js +307 -0
  174. package/dist/core/web/control.js.map +1 -0
  175. package/dist/core/web/public/app.js +512 -6
  176. package/dist/core/web/public/styles.css +468 -0
  177. package/package.json +3 -2
@@ -0,0 +1,151 @@
1
+ /**
2
+ * core/inbox/merge.ts — M47: tiered-trust merge-to-main gate.
3
+ *
4
+ * ╔══════════════════════════════════════════════════════════════════════════╗
5
+ * ║ SECURITY MODEL — autonomous merge to the DEFAULT BRANCH (main). ║
6
+ * ║ ║
7
+ * ║ This is the ONLY module that may advance a proposal's diff onto the ║
8
+ * ║ repository's default branch WITHOUT an interactive human approve. Because ║
9
+ * ║ that is the highest-trust outward action in the system, autoMergeProposal ║
10
+ * ║ runs a STRICT chain of gates and refuses (mutating nothing) the instant ║
11
+ * ║ any gate fails. Gates, in order: ║
12
+ * ║ ║
13
+ * ║ 1. cfg.foundry.autoMerge.enabled === true (DEFAULT DISABLED). ║
14
+ * ║ 2. proposal exists, kind ∈ {patch,pr}, non-empty diff. ║
15
+ * ║ 3. kill switch OFF + assertMayMutate(repo) (enrollment). On refusal we ║
16
+ * ║ DO NOT burn proposal state — it stays approvable/pending. ║
17
+ * ║ 4. evaluateMergeAuthority: engineTier === 'frontier' AND {engine,model} ║
18
+ * ║ ∈ cfg.foundry.mergeAuthority. A ':default' engineModel (no concrete ║
19
+ * ║ model) is ALWAYS rejected — only pinned, vetted models may merge. ║
20
+ * ║ 5. classifyRisk(proposal) ≤ cfg.foundry.autoMerge.maxRisk (default low). ║
21
+ * ║ 6. verifyProposal: apply the diff to an ISOLATED temp worktree off the ║
22
+ * ║ default branch and run EVERY detected verify command — ALL must pass. ║
23
+ * ║ Verify commands are detected from the BASE tree BEFORE the diff is ║
24
+ * ║ applied, so a diff CANNOT rewrite which commands run (H1a). A diff ║
25
+ * ║ touching any build/CI/manifest path (package.json, lockfiles, ║
26
+ * ║ .github/*, Dockerfile, CI configs, .npmrc, Makefile, …) is REFUSED ║
27
+ * ║ outright — regardless of allowWithoutVerification (H1b). ║
28
+ * ║ No commands detected ⇒ fail-closed unless allowWithoutVerification. ║
29
+ * ║ ║
30
+ * ║ Only after ALL gates pass do we mutate. Mutation paths: ║
31
+ * ║ - REMOTE (preferred): open a PR to the default branch and best-effort ║
32
+ * ║ `gh pr merge --squash --admin`. Server-side branch protection / CI ║
33
+ * ║ remain the outer safety net. gh failures NEVER throw. ║
34
+ * ║ - LOCAL (fallback): merge the branch into the default branch via a ║
35
+ * ║ dedicated temp worktree (`git merge --no-ff`). We REFUSE the local ║
36
+ * ║ path when the default branch is the one checked out in the user's ║
37
+ * ║ working tree (would race their index/HEAD) — the branch is left for a ║
38
+ * ║ manual merge. ║
39
+ * ║ ║
40
+ * ║ RESIDUAL RISK (documented): the LOCAL merge path has no code-review or CI ║
41
+ * ║ gate beyond our own verifyProposal — it is the conservative fallback and ║
42
+ * ║ should be enabled only on trusted, enrolled repos. The REMOTE/PR path is ║
43
+ * ║ STRONGLY preferred because it inherits the host's branch protection and ║
44
+ * ║ required-checks. The filesystem is not jailed; verify commands run real ║
45
+ * ║ project scripts (npm/tsc) — only enable auto-merge where that is safe. ║
46
+ * ║ ║
47
+ * ║ PROVENANCE TRUST (H3, residual — tracked follow-up M47.1): the merge ║
48
+ * ║ authority gate (Gate 4) trusts proposal.engineTier / proposal.engineModel ║
49
+ * ║ as read from the on-disk proposal record. The agent MCP surface ║
50
+ * ║ (ashlr_inbox_propose) CANNOT set these fields (verified — they are stamped ║
51
+ * ║ server-side, not from agent input), so a remote agent cannot self-elevate. ║
52
+ * ║ A LOCAL / in-process writer with filesystem access to ~/.ashlr/inbox, ║
53
+ * ║ however, COULD forge a record claiming frontier authority. Full mitigation ║
54
+ * ║ is HMAC-signed provenance binding the {tier,model} to a hash of the diff ║
55
+ * ║ (so a forged record cannot be paired with an arbitrary diff); it is a ║
56
+ * ║ tracked follow-up (M47.1) and intentionally NOT implemented here. The ║
57
+ * ║ residual is bounded by the DEFAULT-DISABLED posture: auto-merge is off ║
58
+ * ║ unless an operator explicitly enables it on an enrolled, trusted repo. ║
59
+ * ║ ║
60
+ * ║ INVARIANTS: every public fn here NEVER throws; every refusal mutates ║
61
+ * ║ nothing (no branch, no status change); every outcome is audited; no ║
62
+ * ║ secrets are logged. Node builtins only. ║
63
+ * ╚══════════════════════════════════════════════════════════════════════════╝
64
+ */
65
+ import type { AshlrConfig, EngineTier, Proposal } from '../types.js';
66
+ import { defaultBranch } from '../git.js';
67
+ import { type VerifyCommand } from '../run/verify-commands.js';
68
+ export type RiskClass = 'low' | 'medium' | 'high';
69
+ /**
70
+ * Classify the merge risk of a proposal from its diff + kind. PURE.
71
+ *
72
+ * low — ONLY docs (*.md / LICENSE), lockfiles (*.lock / package-lock.json),
73
+ * and/or test-only files.
74
+ * medium — config files (*.json/*.yml/*.toml/.github/*) and/or small source
75
+ * changes (a single source file with a modest diff).
76
+ * high — any source change touching an auth/security path, a large diff
77
+ * (many files or many changed lines), or anything we can't classify
78
+ * as low/medium. Empty / unparsable diffs are treated as HIGH
79
+ * (fail-safe — an unknown change is the most dangerous kind).
80
+ */
81
+ export declare function classifyRisk(proposal: Proposal): RiskClass;
82
+ export interface MergeAuthorityVerdict {
83
+ authorized: boolean;
84
+ reason: string;
85
+ }
86
+ /**
87
+ * Decide whether a proposal carries frontier merge-authority. PURE.
88
+ *
89
+ * Authorized ONLY when BOTH hold:
90
+ * - proposal.engineTier === 'frontier'; AND
91
+ * - cfg.foundry.mergeAuthority contains an entry whose reconstructed
92
+ * `${engine}:${model}` exactly equals proposal.engineModel.
93
+ *
94
+ * REJECTS when:
95
+ * - engineModel is missing, or ends in ':default' (no concrete model pinned);
96
+ * - there is no mergeAuthority config / no matching entry;
97
+ * - the tier is not 'frontier'.
98
+ */
99
+ export declare function evaluateMergeAuthority(proposal: Proposal, cfg: AshlrConfig): MergeAuthorityVerdict;
100
+ /**
101
+ * M51 tri-tier policy seam (PURE). The farthest a fully-verified proposal of a
102
+ * given tier may auto-apply: `frontier → main`, `mid → branch` (a strong open
103
+ * model: branch/PR only, never main), everything else → `none` (proposal-only).
104
+ * Introduces NO new default behavior — it is the single source of truth a
105
+ * future, default-OFF, gated auto-apply pass consults so authority can never
106
+ * leak upward.
107
+ */
108
+ export type MergeTarget = 'main' | 'branch' | 'none';
109
+ export declare function mergeTargetForTier(tier?: EngineTier): MergeTarget;
110
+ /**
111
+ * M56: decide whether a MID-tier proposal may auto-apply to a BRANCH (never
112
+ * main). PURE. Authorized ONLY when ALL hold:
113
+ * - cfg.foundry.autoMerge.midToBranch === true (a separate, DEFAULT-OFF flag,
114
+ * so enabling main auto-merge does not implicitly enable the branch path); AND
115
+ * - mergeTargetForTier(engineTier) === 'branch' (i.e. engineTier === 'mid'); AND
116
+ * - engineModel is a concrete, vetted model (present, not ':default').
117
+ * Grants BRANCH authority only — a mid proposal can never reach main regardless
118
+ * of cfg.foundry.mergeAuthority contents.
119
+ */
120
+ export declare function evaluateBranchAuthority(proposal: Proposal, cfg: AshlrConfig): MergeAuthorityVerdict;
121
+ export { defaultBranch };
122
+ export interface VerifyProposalResult {
123
+ ok: boolean;
124
+ ran: VerifyCommand[];
125
+ detail: string;
126
+ }
127
+ /**
128
+ * Apply the proposal's diff to a THROWAWAY temp worktree branched off the
129
+ * default branch's head, then run every detected verify command (typecheck /
130
+ * test / lint). ALL must pass for ok:true. The worktree is always removed.
131
+ *
132
+ * Fail-closed on detection: when NO verify commands are found, returns ok:false
133
+ * UNLESS cfg.foundry.autoMerge.allowWithoutVerification === true.
134
+ *
135
+ * NEVER throws — any error resolves to ok:false with a detail.
136
+ */
137
+ export declare function verifyProposal(proposal: Proposal, cfg: AshlrConfig): Promise<VerifyProposalResult>;
138
+ export interface AutoMergeResult {
139
+ ok: boolean;
140
+ merged: boolean;
141
+ /** M56: true when a MID-tier proposal was applied to a BRANCH/PR (not main). */
142
+ branched?: boolean;
143
+ reason: string;
144
+ prUrl?: string;
145
+ }
146
+ /**
147
+ * Autonomously merge an approved frontier proposal to the default branch,
148
+ * subject to the full gate chain documented in the module header. NEVER throws;
149
+ * every refusal returns { ok:false, merged:false, reason } and mutates nothing.
150
+ */
151
+ export declare function autoMergeProposal(id: string, cfg: AshlrConfig): Promise<AutoMergeResult>;