holo-codex 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/.agents/plugins/marketplace.json +20 -0
  2. package/CONTRIBUTING.md +54 -0
  3. package/LICENSE +21 -0
  4. package/README.md +215 -0
  5. package/README.zh-CN.md +215 -0
  6. package/SECURITY.md +39 -0
  7. package/assets/brand/README.md +35 -0
  8. package/assets/brand/holo-codex-icon.svg +28 -0
  9. package/assets/brand/holo-codex-lockup.svg +49 -0
  10. package/assets/brand/holo-codex-mark.svg +33 -0
  11. package/assets/brand/holo-codex-plugin-card.png +0 -0
  12. package/assets/brand/holo-codex-plugin-card.svg +81 -0
  13. package/assets/brand/holo-codex-readme-hero.png +0 -0
  14. package/assets/brand/holo-codex-readme-hero.svg +140 -0
  15. package/assets/brand/holo-codex-social-preview.png +0 -0
  16. package/assets/brand/holo-codex-social-preview.svg +130 -0
  17. package/assets/brand/holo-codex-wordmark-options.svg +52 -0
  18. package/docs/checklists/agent-loop-first-delivery-audit.md +129 -0
  19. package/docs/examples/generic-loop-repo-hygiene.md +168 -0
  20. package/docs/install.md +190 -0
  21. package/docs/local-release-readiness.md +206 -0
  22. package/docs/release-checklist.md +144 -0
  23. package/docs/self-bootstrap.md +150 -0
  24. package/docs/trust-and-safety.md +45 -0
  25. package/package.json +83 -0
  26. package/plugins/autonomous-pr-loop/.codex-plugin/plugin.json +17 -0
  27. package/plugins/autonomous-pr-loop/.mcp.json +13 -0
  28. package/plugins/autonomous-pr-loop/bin/agent-loop.mjs +31 -0
  29. package/plugins/autonomous-pr-loop/core/artifacts.ts +164 -0
  30. package/plugins/autonomous-pr-loop/core/autonomy-policy.ts +206 -0
  31. package/plugins/autonomous-pr-loop/core/ci.ts +131 -0
  32. package/plugins/autonomous-pr-loop/core/cli-i18n.ts +123 -0
  33. package/plugins/autonomous-pr-loop/core/cli.ts +1413 -0
  34. package/plugins/autonomous-pr-loop/core/command-runner.ts +446 -0
  35. package/plugins/autonomous-pr-loop/core/command.ts +47 -0
  36. package/plugins/autonomous-pr-loop/core/config-editor.ts +140 -0
  37. package/plugins/autonomous-pr-loop/core/config.ts +293 -0
  38. package/plugins/autonomous-pr-loop/core/controller-host.ts +19 -0
  39. package/plugins/autonomous-pr-loop/core/dashboard-server.ts +536 -0
  40. package/plugins/autonomous-pr-loop/core/delivery-work-item.ts +217 -0
  41. package/plugins/autonomous-pr-loop/core/doctor.ts +335 -0
  42. package/plugins/autonomous-pr-loop/core/errors.ts +82 -0
  43. package/plugins/autonomous-pr-loop/core/gate-recovery.ts +176 -0
  44. package/plugins/autonomous-pr-loop/core/gates.ts +26 -0
  45. package/plugins/autonomous-pr-loop/core/generic-lifecycle.ts +399 -0
  46. package/plugins/autonomous-pr-loop/core/git.ts +213 -0
  47. package/plugins/autonomous-pr-loop/core/github.ts +269 -0
  48. package/plugins/autonomous-pr-loop/core/gitnexus.ts +90 -0
  49. package/plugins/autonomous-pr-loop/core/happy.ts +42 -0
  50. package/plugins/autonomous-pr-loop/core/hook-capture.ts +115 -0
  51. package/plugins/autonomous-pr-loop/core/hook-events.ts +22 -0
  52. package/plugins/autonomous-pr-loop/core/hook-installation.ts +85 -0
  53. package/plugins/autonomous-pr-loop/core/hook-observer.ts +84 -0
  54. package/plugins/autonomous-pr-loop/core/hook-policy.ts +423 -0
  55. package/plugins/autonomous-pr-loop/core/hook-router.ts +452 -0
  56. package/plugins/autonomous-pr-loop/core/index.ts +32 -0
  57. package/plugins/autonomous-pr-loop/core/local-install.ts +778 -0
  58. package/plugins/autonomous-pr-loop/core/locale.ts +60 -0
  59. package/plugins/autonomous-pr-loop/core/loop-shapes.ts +190 -0
  60. package/plugins/autonomous-pr-loop/core/mcp-controller.ts +1479 -0
  61. package/plugins/autonomous-pr-loop/core/notification-feed.ts +263 -0
  62. package/plugins/autonomous-pr-loop/core/plan-parser.ts +206 -0
  63. package/plugins/autonomous-pr-loop/core/plugin-paths.ts +32 -0
  64. package/plugins/autonomous-pr-loop/core/policy.ts +65 -0
  65. package/plugins/autonomous-pr-loop/core/pr-lifecycle.ts +464 -0
  66. package/plugins/autonomous-pr-loop/core/pr-selector.ts +284 -0
  67. package/plugins/autonomous-pr-loop/core/profiles.ts +439 -0
  68. package/plugins/autonomous-pr-loop/core/redaction.ts +17 -0
  69. package/plugins/autonomous-pr-loop/core/repo-root.ts +22 -0
  70. package/plugins/autonomous-pr-loop/core/review-comments.ts +77 -0
  71. package/plugins/autonomous-pr-loop/core/scope-guard.ts +179 -0
  72. package/plugins/autonomous-pr-loop/core/state-machine.ts +828 -0
  73. package/plugins/autonomous-pr-loop/core/state-types.ts +130 -0
  74. package/plugins/autonomous-pr-loop/core/storage.ts +2527 -0
  75. package/plugins/autonomous-pr-loop/core/types.ts +567 -0
  76. package/plugins/autonomous-pr-loop/core/worker-events.ts +412 -0
  77. package/plugins/autonomous-pr-loop/core/worker-policy.ts +72 -0
  78. package/plugins/autonomous-pr-loop/core/worker-prompts.ts +182 -0
  79. package/plugins/autonomous-pr-loop/core/worker.ts +809 -0
  80. package/plugins/autonomous-pr-loop/core/workflow-board.ts +1515 -0
  81. package/plugins/autonomous-pr-loop/hooks/dist/permission-request.js +2462 -0
  82. package/plugins/autonomous-pr-loop/hooks/dist/post-compact.js +2462 -0
  83. package/plugins/autonomous-pr-loop/hooks/dist/post-tool-use.js +2462 -0
  84. package/plugins/autonomous-pr-loop/hooks/dist/pre-compact.js +2462 -0
  85. package/plugins/autonomous-pr-loop/hooks/dist/pre-tool-use.js +3460 -0
  86. package/plugins/autonomous-pr-loop/hooks/dist/session-start.js +2462 -0
  87. package/plugins/autonomous-pr-loop/hooks/dist/stop.js +2462 -0
  88. package/plugins/autonomous-pr-loop/hooks/dist/user-prompt-submit.js +2462 -0
  89. package/plugins/autonomous-pr-loop/hooks/hooks.json +106 -0
  90. package/plugins/autonomous-pr-loop/hooks/observe-runner.ts +25 -0
  91. package/plugins/autonomous-pr-loop/hooks/permission-request.ts +4 -0
  92. package/plugins/autonomous-pr-loop/hooks/post-compact.ts +4 -0
  93. package/plugins/autonomous-pr-loop/hooks/post-tool-use.ts +4 -0
  94. package/plugins/autonomous-pr-loop/hooks/pre-compact.ts +4 -0
  95. package/plugins/autonomous-pr-loop/hooks/pre-tool-use.ts +44 -0
  96. package/plugins/autonomous-pr-loop/hooks/session-start.ts +4 -0
  97. package/plugins/autonomous-pr-loop/hooks/stop.ts +4 -0
  98. package/plugins/autonomous-pr-loop/hooks/user-prompt-submit.ts +4 -0
  99. package/plugins/autonomous-pr-loop/mcp-server/src/index.ts +87 -0
  100. package/plugins/autonomous-pr-loop/mcp-server/src/tools.ts +205 -0
  101. package/plugins/autonomous-pr-loop/package.json +9 -0
  102. package/plugins/autonomous-pr-loop/schemas/config.schema.json +74 -0
  103. package/plugins/autonomous-pr-loop/schemas/marketplace.schema.json +46 -0
  104. package/plugins/autonomous-pr-loop/schemas/plugin.schema.json +32 -0
  105. package/plugins/autonomous-pr-loop/schemas/state.schema.json +19 -0
  106. package/plugins/autonomous-pr-loop/schemas/worker-event.schema.json +19 -0
  107. package/plugins/autonomous-pr-loop/schemas/worker-result.schema.json +58 -0
  108. package/plugins/autonomous-pr-loop/scripts/agent-loop.ts +44 -0
  109. package/plugins/autonomous-pr-loop/skills/autonomous-pr-loop/SKILL.md +26 -0
  110. package/plugins/autonomous-pr-loop/skills/autonomous-pr-loop/agents/openai.yaml +6 -0
  111. package/plugins/autonomous-pr-loop/ui/index.html +26 -0
  112. package/plugins/autonomous-pr-loop/ui/public/favicon.svg +7 -0
  113. package/plugins/autonomous-pr-loop/ui/src/api.ts +639 -0
  114. package/plugins/autonomous-pr-loop/ui/src/app.tsx +238 -0
  115. package/plugins/autonomous-pr-loop/ui/src/components/ActivityBadge.tsx +31 -0
  116. package/plugins/autonomous-pr-loop/ui/src/components/BrandMark.tsx +36 -0
  117. package/plugins/autonomous-pr-loop/ui/src/components/Collapsible.tsx +6 -0
  118. package/plugins/autonomous-pr-loop/ui/src/components/CommandPreview.tsx +15 -0
  119. package/plugins/autonomous-pr-loop/ui/src/components/ConfigEditor.tsx +389 -0
  120. package/plugins/autonomous-pr-loop/ui/src/components/EmptyState.tsx +10 -0
  121. package/plugins/autonomous-pr-loop/ui/src/components/ErrorState.tsx +12 -0
  122. package/plugins/autonomous-pr-loop/ui/src/components/List.tsx +7 -0
  123. package/plugins/autonomous-pr-loop/ui/src/components/MetricRow.tsx +6 -0
  124. package/plugins/autonomous-pr-loop/ui/src/components/ResponsiveTable.tsx +65 -0
  125. package/plugins/autonomous-pr-loop/ui/src/components/RiskBadge.tsx +10 -0
  126. package/plugins/autonomous-pr-loop/ui/src/components/StatusBadge.tsx +29 -0
  127. package/plugins/autonomous-pr-loop/ui/src/components/TopMetric.tsx +10 -0
  128. package/plugins/autonomous-pr-loop/ui/src/fixtures.ts +1152 -0
  129. package/plugins/autonomous-pr-loop/ui/src/i18n.ts +1105 -0
  130. package/plugins/autonomous-pr-loop/ui/src/main.tsx +14 -0
  131. package/plugins/autonomous-pr-loop/ui/src/pages/CommandCenter.tsx +470 -0
  132. package/plugins/autonomous-pr-loop/ui/src/pages/CommandCenterParts.tsx +276 -0
  133. package/plugins/autonomous-pr-loop/ui/src/pages/agent-timeline/AgentTimelineView.tsx +73 -0
  134. package/plugins/autonomous-pr-loop/ui/src/pages/artifact-viewer/ArtifactViewer.tsx +44 -0
  135. package/plugins/autonomous-pr-loop/ui/src/pages/dry-run-preview/DryRunPreview.tsx +66 -0
  136. package/plugins/autonomous-pr-loop/ui/src/pages/event-ledger/EventLedger.tsx +17 -0
  137. package/plugins/autonomous-pr-loop/ui/src/pages/gate-center/GateCenter.tsx +34 -0
  138. package/plugins/autonomous-pr-loop/ui/src/pages/mission-control/MissionControl.tsx +104 -0
  139. package/plugins/autonomous-pr-loop/ui/src/pages/mission-control/WorkflowBoard.tsx +577 -0
  140. package/plugins/autonomous-pr-loop/ui/src/pages/notifications/NotificationsView.tsx +30 -0
  141. package/plugins/autonomous-pr-loop/ui/src/pages/plan-navigator/PlanNavigator.tsx +19 -0
  142. package/plugins/autonomous-pr-loop/ui/src/pages/policy-config/PolicyConfig.tsx +22 -0
  143. package/plugins/autonomous-pr-loop/ui/src/pages/pr-inbox/PrInbox.tsx +26 -0
  144. package/plugins/autonomous-pr-loop/ui/src/pages/recovery-center/RecoveryCenter.tsx +125 -0
  145. package/plugins/autonomous-pr-loop/ui/src/pages/scope-guard/ScopeGuard.tsx +16 -0
  146. package/plugins/autonomous-pr-loop/ui/src/pages/worker-runs/WorkerRuns.tsx +39 -0
  147. package/plugins/autonomous-pr-loop/ui/src/styles.css +2673 -0
  148. package/plugins/autonomous-pr-loop/ui/src/theme.ts +57 -0
  149. package/tsconfig.json +18 -0
@@ -0,0 +1,639 @@
1
+ export interface DashboardResult<T> {
2
+ ok: boolean;
3
+ data?: T;
4
+ error?: { code: string; message: string; details?: unknown };
5
+ gate?: string;
6
+ }
7
+
8
+ export type ActivityState = "active" | "historical";
9
+
10
+ export interface RunSummary {
11
+ id: string;
12
+ status: string;
13
+ currentState?: string;
14
+ branch?: string;
15
+ worktreeClean?: boolean;
16
+ updatedAt: string;
17
+ startedAt?: string;
18
+ }
19
+
20
+ export interface GateSummary {
21
+ id: string;
22
+ kind: string;
23
+ status: string;
24
+ message: string;
25
+ details?: unknown;
26
+ createdAt: string;
27
+ decisionNote?: string;
28
+ activity?: ActivityState;
29
+ activityReason?: string;
30
+ }
31
+
32
+ export type GateReevaluationResult =
33
+ | "still_historical"
34
+ | "overridden_by_current_reality"
35
+ | "active_again"
36
+ | "manually_handled";
37
+
38
+ export interface GateReevaluationData {
39
+ gate: GateSummary;
40
+ result: GateReevaluationResult;
41
+ reevaluated: true;
42
+ }
43
+
44
+ export interface EventSummary {
45
+ id: string;
46
+ seq: number;
47
+ kind: string;
48
+ message: string;
49
+ stateBefore?: string;
50
+ stateAfter?: string;
51
+ createdAt: string;
52
+ artifactIds?: string[];
53
+ }
54
+
55
+ export type AgentTimelineSource = "event" | "worker_event" | "worker" | "state" | "gate" | "artifact" | "decision";
56
+
57
+ export interface AgentTimelineEntry {
58
+ timelineSeq: number;
59
+ occurredAt: string;
60
+ cursor: string;
61
+ source: AgentTimelineSource;
62
+ kind: string;
63
+ runId?: string;
64
+ workerId?: string;
65
+ threadId?: string;
66
+ title: string;
67
+ summary: string;
68
+ status?: string;
69
+ artifactIds?: string[];
70
+ createdAt: string;
71
+ rawRef: { table: string; id: string; seq?: number };
72
+ }
73
+
74
+ export interface AgentTimelinePage {
75
+ entries: AgentTimelineEntry[];
76
+ nextCursor?: string;
77
+ }
78
+
79
+ export interface WorkerSummary {
80
+ id: string;
81
+ type: string;
82
+ status: string;
83
+ startedAt: string;
84
+ threadId?: string;
85
+ completedAt?: string;
86
+ resultArtifactId?: string;
87
+ error?: string;
88
+ activity?: ActivityState;
89
+ activityReason?: string;
90
+ }
91
+
92
+ export interface ArtifactSummary {
93
+ id: string;
94
+ kind: string;
95
+ name: string;
96
+ path: string;
97
+ createdAt: string;
98
+ }
99
+
100
+ export interface CiCheckSummary {
101
+ id: string;
102
+ name: string;
103
+ status: string;
104
+ conclusion?: string;
105
+ observedAt: string;
106
+ }
107
+
108
+ export interface ReviewCommentSummary {
109
+ id: string;
110
+ author: string;
111
+ path: string;
112
+ body: string;
113
+ actionable: boolean;
114
+ isResolved: boolean;
115
+ isOutdated: boolean;
116
+ status: string;
117
+ }
118
+
119
+ export interface AutonomyPosture {
120
+ autonomyMode: string;
121
+ mergeMode: string;
122
+ notifyMode: string;
123
+ reviewHandling: string;
124
+ summary: string;
125
+ notifyWhen: string[];
126
+ requiresConfirmation: string[];
127
+ allowConditionalMerge: boolean;
128
+ }
129
+
130
+ export interface MergeReadiness {
131
+ state: string;
132
+ ready: boolean;
133
+ missingConditions: string[];
134
+ evidence: string[];
135
+ carryoverRecords: string[];
136
+ }
137
+
138
+ export interface ProfileSummary {
139
+ loopShape: string;
140
+ workflowProfile: string;
141
+ workflowLabel: string;
142
+ workflowDescription: string;
143
+ roleProfile: string;
144
+ currentRole?: {
145
+ state: string;
146
+ alias: string;
147
+ workerType: string;
148
+ label: string;
149
+ sandbox: string;
150
+ };
151
+ roleMapping: Array<{
152
+ state: string;
153
+ alias: string;
154
+ workerType: string;
155
+ label: string;
156
+ sandbox: string;
157
+ }>;
158
+ autonomyBoundary: string;
159
+ handoffSummary: string;
160
+ validationPosture: string;
161
+ likelyGates: string[];
162
+ lifecycleKind?: string;
163
+ expectedDeliverable?: string;
164
+ allowedWriteRoots?: string[];
165
+ availableWorkflows: Array<{ id: string; label: string; description: string }>;
166
+ availableRoleProfiles: Array<{ id: string; label: string; description: string }>;
167
+ }
168
+
169
+ export interface WorkflowStageSummary {
170
+ state: string;
171
+ roleAlias?: string;
172
+ workerType?: string;
173
+ gateExpected: boolean;
174
+ sandbox?: string;
175
+ deliverable?: string;
176
+ }
177
+
178
+ export type WorkflowStageStatus = "pending" | "active" | "blocked" | "done" | "skipped" | "manual" | "failed";
179
+ export type WorkflowStageId = "work_item" | "plan" | "build" | "verify" | "pr" | "review" | "merge_readiness" | "cleanup";
180
+
181
+ export interface WorkflowEvidenceCounts {
182
+ events: number;
183
+ artifacts: number;
184
+ gates: number;
185
+ prComments: number;
186
+ gitnexus: number;
187
+ browser: number;
188
+ ci: number;
189
+ reports: number;
190
+ }
191
+
192
+ export interface WorkflowDrillDownTarget {
193
+ page: "Event Ledger" | "Gate Center" | "Worker Runs" | "Artifact Diff Viewer" | "PR Inbox" | "Scope Guard" | "Recovery Center";
194
+ }
195
+
196
+ export interface WorkflowEvidenceRef {
197
+ id: string;
198
+ kind: string;
199
+ label: string;
200
+ summary: string;
201
+ interaction: "popover" | "drill_down_link";
202
+ drillDownTarget?: WorkflowDrillDownTarget;
203
+ createdAt?: string;
204
+ source?: string;
205
+ }
206
+
207
+ export interface WorkflowActorChip {
208
+ actor: string;
209
+ label: string;
210
+ status: WorkflowStageStatus;
211
+ model?: string;
212
+ sessionId?: string;
213
+ }
214
+
215
+ export interface WorkflowBoardSubstage {
216
+ id: string;
217
+ label: string;
218
+ status: WorkflowStageStatus;
219
+ evidenceCounts: WorkflowEvidenceCounts;
220
+ latestEvidence: WorkflowEvidenceRef[];
221
+ requiredEvidence: Array<{
222
+ id: string;
223
+ label: string;
224
+ status: "pending" | "satisfied" | "blocked" | "skipped";
225
+ evidenceRefIds: string[];
226
+ skippedReason?: string;
227
+ blockedBy?: string;
228
+ }>;
229
+ }
230
+
231
+ export interface WorkflowBoardStage {
232
+ id: WorkflowStageId;
233
+ label: string;
234
+ status: WorkflowStageStatus;
235
+ actorChips: WorkflowActorChip[];
236
+ evidenceCounts: WorkflowEvidenceCounts;
237
+ substages: WorkflowBoardSubstage[];
238
+ latestAction?: { label: string; command?: string; safeToRunFromDashboard: boolean; requiresConfirmation: boolean };
239
+ blockers: Array<{
240
+ id: string;
241
+ severity: string;
242
+ title: string;
243
+ reason: string;
244
+ owner: string;
245
+ nextAction: string;
246
+ blockedBy?: string;
247
+ evidenceRefIds: string[];
248
+ }>;
249
+ nextAction?: string;
250
+ }
251
+
252
+ export interface WorkflowReviewReportRow {
253
+ id: string;
254
+ agent: string;
255
+ model?: string;
256
+ status: "pass" | "block" | "warn" | "pending" | "skipped" | "unknown";
257
+ prComment: "posted" | "missing" | "not_required" | "unknown";
258
+ severitySummary: string;
259
+ requirement?: "required" | "optional" | "not_required" | "unknown";
260
+ progress?: "requested" | "started" | "in_progress" | "incomplete" | "complete" | "skipped" | "unknown";
261
+ result?: "pass" | "block" | "warn" | "unknown";
262
+ commentUrl?: string;
263
+ commentId?: string;
264
+ sessionId?: string;
265
+ conversationId?: string;
266
+ reason?: string;
267
+ nextAction?: string;
268
+ followUp?: string;
269
+ evidenceRefIds: string[];
270
+ }
271
+
272
+ export interface WorkflowCheckRow {
273
+ id: string;
274
+ label: string;
275
+ status: "passed" | "failed" | "pending" | "blocked" | "skipped" | "unknown";
276
+ evidence: string;
277
+ owner: string;
278
+ blockedBy?: string;
279
+ }
280
+
281
+ export interface WorkflowBoard {
282
+ runId?: string | undefined;
283
+ mode: "empty" | "active" | "historical" | "unsupported" | "unknown_state";
284
+ activeStageId?: WorkflowStageId | undefined;
285
+ selectedStageId: WorkflowStageId;
286
+ stageSource?: "run_state" | "workflow_evidence" | "gate" | "historical";
287
+ stageSourceEvent?: { id: string; status: WorkflowStageStatus; createdAt: string };
288
+ hookCapture?: {
289
+ status: "captured" | "not_seen" | "stale" | "ambiguous" | "unavailable";
290
+ reason: string;
291
+ currentRepoBindings?: number;
292
+ sessionScopedBindings?: number;
293
+ activeBindings?: number;
294
+ lastSeenAt?: string;
295
+ latestHookEventAt?: string;
296
+ latestHookEventKind?: string;
297
+ runId?: string;
298
+ };
299
+ workItem: {
300
+ issueNumber?: number | undefined;
301
+ issueTitle?: string | undefined;
302
+ issueUrl?: string | undefined;
303
+ runId?: string | undefined;
304
+ branch?: string | undefined;
305
+ currentState?: string | undefined;
306
+ status?: string | undefined;
307
+ loopShape: string;
308
+ workflowProfile?: string | undefined;
309
+ prUrl?: string | undefined;
310
+ prNumber?: number | undefined;
311
+ lastUpdate?: string | undefined;
312
+ activeGate?: string | undefined;
313
+ readOnly: boolean;
314
+ };
315
+ stages: WorkflowBoardStage[];
316
+ evidenceRefs: WorkflowEvidenceRef[];
317
+ reviewReports: WorkflowReviewReportRow[];
318
+ verificationChecks: WorkflowCheckRow[];
319
+ mergeReadinessChecks: WorkflowCheckRow[];
320
+ cleanupChecks: WorkflowCheckRow[];
321
+ appendEvidenceEnabled: boolean;
322
+ message?: string | undefined;
323
+ }
324
+
325
+ export interface WorkflowEvidenceAppendInput {
326
+ runId?: string | undefined;
327
+ stageId: WorkflowStageId;
328
+ substageId?: string | undefined;
329
+ summary: string;
330
+ evidenceRefIds?: string[] | undefined;
331
+ artifactIds?: string[] | undefined;
332
+ actor?: string | undefined;
333
+ status?: WorkflowStageStatus | undefined;
334
+ source?: string | undefined;
335
+ review?: {
336
+ reviewer: "claude_acp" | "agy_gemini" | "internal_tester" | "internal_reviewer" | "github" | "human" | "custom";
337
+ requirement: "required" | "optional" | "not_required" | "unknown";
338
+ progress: "requested" | "started" | "in_progress" | "incomplete" | "complete" | "skipped" | "unknown";
339
+ result: "pass" | "block" | "warn" | "unknown";
340
+ severitySummary: "none" | "p3_only" | "p2_or_higher" | "unknown";
341
+ model?: string;
342
+ sessionId?: string;
343
+ conversationId?: string;
344
+ commentUrl?: string;
345
+ commentId?: string;
346
+ reason?: string;
347
+ } | undefined;
348
+ }
349
+
350
+ export interface LoopNotification {
351
+ id: string;
352
+ severity: "informational" | "attention" | "confirmation_required" | "blocked";
353
+ title: string;
354
+ reason: string;
355
+ source: string;
356
+ sourceId: string;
357
+ createdAt: string;
358
+ payload?: unknown;
359
+ }
360
+
361
+ export interface PlanItem {
362
+ id: string;
363
+ title: string;
364
+ status: string;
365
+ file: string;
366
+ dependsOn: string[];
367
+ issueRefs: string[];
368
+ whySelected?: string;
369
+ }
370
+
371
+ export interface PlanNavigatorData {
372
+ convention: string;
373
+ currentMilestone: string;
374
+ selectedNext?: PlanItem;
375
+ completed: PlanItem[];
376
+ candidates: PlanItem[];
377
+ ambiguous: boolean;
378
+ evidence: string[];
379
+ }
380
+
381
+ export interface PrSelectionData {
382
+ mode: "current_pr" | "next_spec" | "ambiguous" | "generic_loop";
383
+ ambiguous: boolean;
384
+ item?: PlanItem;
385
+ branchName?: string;
386
+ prNumber?: number;
387
+ prUrl?: string;
388
+ loopShape?: string;
389
+ workflowProfile?: string;
390
+ reason?: string;
391
+ candidates?: Array<Record<string, unknown>>;
392
+ evidence: string[];
393
+ }
394
+
395
+ export interface ConfigSnapshot {
396
+ path: string;
397
+ hash: string;
398
+ mtimeMs: number;
399
+ config: Record<string, unknown>;
400
+ }
401
+
402
+ export interface DryRunPreviewData {
403
+ nextPr?: PlanItem;
404
+ branchName?: string;
405
+ selection?: PrSelectionData;
406
+ profile?: ProfileSummary;
407
+ workflowStages?: WorkflowStageSummary[];
408
+ commandsPlanned: string[];
409
+ workerType: string;
410
+ possibleGates: string[];
411
+ missingConditions: string[];
412
+ filesLikelyTouched: string[];
413
+ autonomyForecast: AutonomyPosture;
414
+ mergeForecast?: MergeReadiness;
415
+ }
416
+
417
+ export interface MissionControlData {
418
+ current: {
419
+ status: string;
420
+ nextAction: string;
421
+ run?: RunSummary;
422
+ gate?: {
423
+ kind: string;
424
+ message: string;
425
+ details?: unknown;
426
+ };
427
+ };
428
+ gates: GateSummary[];
429
+ pr?: {
430
+ prNumber: number;
431
+ url: string;
432
+ branch: string;
433
+ state: string;
434
+ draft: boolean;
435
+ updatedAt: string;
436
+ };
437
+ ci: CiCheckSummary[];
438
+ reviewComments: ReviewCommentSummary[];
439
+ workers: WorkerSummary[];
440
+ artifacts: ArtifactSummary[];
441
+ events: EventSummary[];
442
+ decisions?: Array<{ id: string; kind: string; message: string; createdAt: string; details?: unknown }>;
443
+ timelineSummary?: {
444
+ latest?: AgentTimelineEntry;
445
+ lastFailure?: AgentTimelineEntry;
446
+ activeWorker?: { id: string; type: string; status: string; threadId?: string; startedAt: string };
447
+ hasObservationGap: boolean;
448
+ runId?: string;
449
+ };
450
+ autonomy?: AutonomyPosture;
451
+ mergeReadiness?: MergeReadiness;
452
+ profile?: ProfileSummary;
453
+ notifications?: LoopNotification[];
454
+ plan?: PlanNavigatorData;
455
+ selection?: PrSelectionData;
456
+ recoveryWarnings?: string[];
457
+ }
458
+
459
+ export interface DashboardApi {
460
+ dashboardMeta(): Promise<DashboardResult<DashboardMetaData>>;
461
+ missionControl(): Promise<DashboardResult<MissionControlData>>;
462
+ observe(options?: { limit?: number }): Promise<DashboardResult<ObserveData>>;
463
+ events(since?: number): Promise<DashboardResult<{ events: EventSummary[] }>>;
464
+ agentTimeline(options?: {
465
+ cursor?: string;
466
+ limit?: number;
467
+ sources?: AgentTimelineSource[];
468
+ runId?: string;
469
+ workerId?: string;
470
+ }): Promise<DashboardResult<AgentTimelinePage>>;
471
+ mutate(path: string, body?: unknown): Promise<DashboardResult<unknown>>;
472
+ artifact(id: string): Promise<DashboardResult<{ record: ArtifactSummary; contentBase64: string }>>;
473
+ plan(): Promise<DashboardResult<{ plan: PlanNavigatorData; selection?: PrSelectionData }>>;
474
+ policyConfig(): Promise<DashboardResult<ConfigSnapshot>>;
475
+ dryRunPreview(): Promise<DashboardResult<DryRunPreviewData>>;
476
+ notifications(): Promise<DashboardResult<{ notifications: LoopNotification[] }>>;
477
+ workflowBoard?(options?: { runId?: string }): Promise<DashboardResult<WorkflowBoard>>;
478
+ appendWorkflowEvidence?(input: WorkflowEvidenceAppendInput): Promise<DashboardResult<unknown>>;
479
+ auditExport(options: { runId: string; format: "markdown" | "json" }): Promise<DashboardResult<AuditExportData>>;
480
+ }
481
+
482
+ export interface ObserveData {
483
+ dashboard: { url: string; host: string; port: number; loopbackOnly: true };
484
+ happy: { installed: boolean; versionText?: string; supportsNotify: boolean };
485
+ current: MissionControlData["current"];
486
+ timeline: AgentTimelinePage;
487
+ }
488
+
489
+ export interface AuditExportData {
490
+ runId: string;
491
+ format: "markdown" | "json";
492
+ content: string | Record<string, unknown>;
493
+ }
494
+
495
+ export interface DashboardMetaData {
496
+ appName: string;
497
+ surface: string;
498
+ targetRepo?: {
499
+ root: string;
500
+ repoId: string;
501
+ };
502
+ }
503
+
504
+ export const DASHBOARD_TOKEN_STORAGE_KEY = "agent-loop-dashboard-token";
505
+ const DASHBOARD_RUNTIME_TOKEN_KEY = "__AGENT_LOOP_DASHBOARD_TOKEN__";
506
+
507
+ declare global {
508
+ interface Window {
509
+ __AGENT_LOOP_DASHBOARD_TOKEN__?: unknown;
510
+ }
511
+ }
512
+
513
+ export function createDashboardApi(token = storedDashboardToken()): DashboardApi {
514
+ return {
515
+ dashboardMeta: () => apiGet<DashboardMetaData>("/api/dashboard-meta"),
516
+ missionControl: () => apiGet<MissionControlData>("/api/mission-control"),
517
+ observe: (options) => apiGet<ObserveData>(`/api/observe${options?.limit === undefined ? "" : `?limit=${options.limit}`}`),
518
+ events: (since) => apiGet<{ events: EventSummary[] }>(`/api/events${since === undefined ? "" : `?since=${since}`}`),
519
+ agentTimeline: (options) => apiGet<AgentTimelinePage>(timelinePath(options)),
520
+ mutate: (path, body) => apiPost(path, token, body),
521
+ artifact: (id) => apiGet<{ record: ArtifactSummary; contentBase64: string }>(
522
+ `/api/artifacts/${encodeURIComponent(id)}`,
523
+ token
524
+ ),
525
+ plan: () => apiGet<{ plan: PlanNavigatorData }>("/api/plan"),
526
+ policyConfig: () => apiGet<ConfigSnapshot>("/api/policy-config"),
527
+ dryRunPreview: () => apiGet<DryRunPreviewData>("/api/dry-run-preview"),
528
+ notifications: () => apiGet<{ notifications: LoopNotification[] }>("/api/notifications"),
529
+ workflowBoard: (options) => apiGet<WorkflowBoard>(workflowBoardPath(options)),
530
+ appendWorkflowEvidence: (input) => apiPost("/api/workflow-board/evidence", token, input),
531
+ auditExport: (options) => apiGet<AuditExportData>(auditExportPath(options))
532
+ };
533
+ }
534
+
535
+ function workflowBoardPath(options?: { runId?: string }): string {
536
+ const params = new URLSearchParams();
537
+ if (options?.runId) params.set("runId", options.runId);
538
+ const query = params.toString();
539
+ return `/api/workflow-board${query ? `?${query}` : ""}`;
540
+ }
541
+
542
+ function timelinePath(options?: {
543
+ cursor?: string;
544
+ limit?: number;
545
+ sources?: AgentTimelineSource[];
546
+ runId?: string;
547
+ workerId?: string;
548
+ }): string {
549
+ const params = new URLSearchParams();
550
+ if (options?.cursor) params.set("cursor", options.cursor);
551
+ if (options?.limit !== undefined) params.set("limit", String(options.limit));
552
+ if (options?.runId) params.set("runId", options.runId);
553
+ if (options?.workerId) params.set("workerId", options.workerId);
554
+ for (const source of options?.sources ?? []) {
555
+ params.append("source", source);
556
+ }
557
+ const query = params.toString();
558
+ return `/api/agent-timeline${query ? `?${query}` : ""}`;
559
+ }
560
+
561
+ function tokenFromLocation(): string {
562
+ const url = new URL(window.location.href);
563
+ const token = url.searchParams.get("token") ?? "";
564
+ if (token) {
565
+ window.localStorage.setItem(DASHBOARD_TOKEN_STORAGE_KEY, token);
566
+ removeTokenFromLocation(url);
567
+ return token;
568
+ }
569
+ return "";
570
+ }
571
+
572
+ function removeTokenFromLocation(url = new URL(window.location.href)): void {
573
+ if (!url.searchParams.has("token")) {
574
+ return;
575
+ }
576
+ url.searchParams.delete("token");
577
+ window.history.replaceState(window.history.state, document.title, `${url.pathname}${url.search}${url.hash}`);
578
+ }
579
+
580
+ function tokenFromRuntimeBootstrap(): string {
581
+ const token = window[DASHBOARD_RUNTIME_TOKEN_KEY];
582
+ delete window[DASHBOARD_RUNTIME_TOKEN_KEY];
583
+ if (typeof token !== "string" || token.length === 0) {
584
+ return "";
585
+ }
586
+ removeTokenFromLocation();
587
+ window.localStorage.setItem(DASHBOARD_TOKEN_STORAGE_KEY, token);
588
+ return token;
589
+ }
590
+
591
+ export function storedDashboardToken(): string {
592
+ return tokenFromRuntimeBootstrap() || tokenFromLocation() || (window.localStorage.getItem(DASHBOARD_TOKEN_STORAGE_KEY) ?? "");
593
+ }
594
+
595
+ export function storeDashboardToken(token: string): void {
596
+ window.localStorage.setItem(DASHBOARD_TOKEN_STORAGE_KEY, token);
597
+ }
598
+
599
+ function auditExportPath(options: { runId: string; format: "markdown" | "json" }): string {
600
+ const params = new URLSearchParams();
601
+ params.set("runId", options.runId);
602
+ params.set("format", options.format);
603
+ return `/api/audit-export?${params.toString()}`;
604
+ }
605
+
606
+ async function apiGet<T>(path: string, token?: string): Promise<DashboardResult<T>> {
607
+ const headers: Record<string, string> = { accept: "application/json" };
608
+ if (token) {
609
+ headers["x-agent-loop-token"] = token;
610
+ }
611
+ return await fetchJson<T>(path, { headers });
612
+ }
613
+
614
+ async function apiPost(path: string, token: string, body?: unknown): Promise<DashboardResult<unknown>> {
615
+ return await fetchJson(path, {
616
+ method: "POST",
617
+ headers: {
618
+ accept: "application/json",
619
+ "content-type": "application/json",
620
+ "x-agent-loop-token": token
621
+ },
622
+ body: JSON.stringify(body ?? {})
623
+ });
624
+ }
625
+
626
+ async function fetchJson<T>(path: string, init: RequestInit): Promise<DashboardResult<T>> {
627
+ try {
628
+ const response = await fetch(path, init);
629
+ return await response.json() as DashboardResult<T>;
630
+ } catch (error) {
631
+ return {
632
+ ok: false,
633
+ error: {
634
+ code: "network_error",
635
+ message: error instanceof Error ? error.message : "Dashboard API request failed."
636
+ }
637
+ };
638
+ }
639
+ }