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.
- package/.agents/plugins/marketplace.json +20 -0
- package/CONTRIBUTING.md +54 -0
- package/LICENSE +21 -0
- package/README.md +215 -0
- package/README.zh-CN.md +215 -0
- package/SECURITY.md +39 -0
- package/assets/brand/README.md +35 -0
- package/assets/brand/holo-codex-icon.svg +28 -0
- package/assets/brand/holo-codex-lockup.svg +49 -0
- package/assets/brand/holo-codex-mark.svg +33 -0
- package/assets/brand/holo-codex-plugin-card.png +0 -0
- package/assets/brand/holo-codex-plugin-card.svg +81 -0
- package/assets/brand/holo-codex-readme-hero.png +0 -0
- package/assets/brand/holo-codex-readme-hero.svg +140 -0
- package/assets/brand/holo-codex-social-preview.png +0 -0
- package/assets/brand/holo-codex-social-preview.svg +130 -0
- package/assets/brand/holo-codex-wordmark-options.svg +52 -0
- package/docs/checklists/agent-loop-first-delivery-audit.md +129 -0
- package/docs/examples/generic-loop-repo-hygiene.md +168 -0
- package/docs/install.md +190 -0
- package/docs/local-release-readiness.md +206 -0
- package/docs/release-checklist.md +144 -0
- package/docs/self-bootstrap.md +150 -0
- package/docs/trust-and-safety.md +45 -0
- package/package.json +83 -0
- package/plugins/autonomous-pr-loop/.codex-plugin/plugin.json +17 -0
- package/plugins/autonomous-pr-loop/.mcp.json +13 -0
- package/plugins/autonomous-pr-loop/bin/agent-loop.mjs +31 -0
- package/plugins/autonomous-pr-loop/core/artifacts.ts +164 -0
- package/plugins/autonomous-pr-loop/core/autonomy-policy.ts +206 -0
- package/plugins/autonomous-pr-loop/core/ci.ts +131 -0
- package/plugins/autonomous-pr-loop/core/cli-i18n.ts +123 -0
- package/plugins/autonomous-pr-loop/core/cli.ts +1413 -0
- package/plugins/autonomous-pr-loop/core/command-runner.ts +446 -0
- package/plugins/autonomous-pr-loop/core/command.ts +47 -0
- package/plugins/autonomous-pr-loop/core/config-editor.ts +140 -0
- package/plugins/autonomous-pr-loop/core/config.ts +293 -0
- package/plugins/autonomous-pr-loop/core/controller-host.ts +19 -0
- package/plugins/autonomous-pr-loop/core/dashboard-server.ts +536 -0
- package/plugins/autonomous-pr-loop/core/delivery-work-item.ts +217 -0
- package/plugins/autonomous-pr-loop/core/doctor.ts +335 -0
- package/plugins/autonomous-pr-loop/core/errors.ts +82 -0
- package/plugins/autonomous-pr-loop/core/gate-recovery.ts +176 -0
- package/plugins/autonomous-pr-loop/core/gates.ts +26 -0
- package/plugins/autonomous-pr-loop/core/generic-lifecycle.ts +399 -0
- package/plugins/autonomous-pr-loop/core/git.ts +213 -0
- package/plugins/autonomous-pr-loop/core/github.ts +269 -0
- package/plugins/autonomous-pr-loop/core/gitnexus.ts +90 -0
- package/plugins/autonomous-pr-loop/core/happy.ts +42 -0
- package/plugins/autonomous-pr-loop/core/hook-capture.ts +115 -0
- package/plugins/autonomous-pr-loop/core/hook-events.ts +22 -0
- package/plugins/autonomous-pr-loop/core/hook-installation.ts +85 -0
- package/plugins/autonomous-pr-loop/core/hook-observer.ts +84 -0
- package/plugins/autonomous-pr-loop/core/hook-policy.ts +423 -0
- package/plugins/autonomous-pr-loop/core/hook-router.ts +452 -0
- package/plugins/autonomous-pr-loop/core/index.ts +32 -0
- package/plugins/autonomous-pr-loop/core/local-install.ts +778 -0
- package/plugins/autonomous-pr-loop/core/locale.ts +60 -0
- package/plugins/autonomous-pr-loop/core/loop-shapes.ts +190 -0
- package/plugins/autonomous-pr-loop/core/mcp-controller.ts +1479 -0
- package/plugins/autonomous-pr-loop/core/notification-feed.ts +263 -0
- package/plugins/autonomous-pr-loop/core/plan-parser.ts +206 -0
- package/plugins/autonomous-pr-loop/core/plugin-paths.ts +32 -0
- package/plugins/autonomous-pr-loop/core/policy.ts +65 -0
- package/plugins/autonomous-pr-loop/core/pr-lifecycle.ts +464 -0
- package/plugins/autonomous-pr-loop/core/pr-selector.ts +284 -0
- package/plugins/autonomous-pr-loop/core/profiles.ts +439 -0
- package/plugins/autonomous-pr-loop/core/redaction.ts +17 -0
- package/plugins/autonomous-pr-loop/core/repo-root.ts +22 -0
- package/plugins/autonomous-pr-loop/core/review-comments.ts +77 -0
- package/plugins/autonomous-pr-loop/core/scope-guard.ts +179 -0
- package/plugins/autonomous-pr-loop/core/state-machine.ts +828 -0
- package/plugins/autonomous-pr-loop/core/state-types.ts +130 -0
- package/plugins/autonomous-pr-loop/core/storage.ts +2527 -0
- package/plugins/autonomous-pr-loop/core/types.ts +567 -0
- package/plugins/autonomous-pr-loop/core/worker-events.ts +412 -0
- package/plugins/autonomous-pr-loop/core/worker-policy.ts +72 -0
- package/plugins/autonomous-pr-loop/core/worker-prompts.ts +182 -0
- package/plugins/autonomous-pr-loop/core/worker.ts +809 -0
- package/plugins/autonomous-pr-loop/core/workflow-board.ts +1515 -0
- package/plugins/autonomous-pr-loop/hooks/dist/permission-request.js +2462 -0
- package/plugins/autonomous-pr-loop/hooks/dist/post-compact.js +2462 -0
- package/plugins/autonomous-pr-loop/hooks/dist/post-tool-use.js +2462 -0
- package/plugins/autonomous-pr-loop/hooks/dist/pre-compact.js +2462 -0
- package/plugins/autonomous-pr-loop/hooks/dist/pre-tool-use.js +3460 -0
- package/plugins/autonomous-pr-loop/hooks/dist/session-start.js +2462 -0
- package/plugins/autonomous-pr-loop/hooks/dist/stop.js +2462 -0
- package/plugins/autonomous-pr-loop/hooks/dist/user-prompt-submit.js +2462 -0
- package/plugins/autonomous-pr-loop/hooks/hooks.json +106 -0
- package/plugins/autonomous-pr-loop/hooks/observe-runner.ts +25 -0
- package/plugins/autonomous-pr-loop/hooks/permission-request.ts +4 -0
- package/plugins/autonomous-pr-loop/hooks/post-compact.ts +4 -0
- package/plugins/autonomous-pr-loop/hooks/post-tool-use.ts +4 -0
- package/plugins/autonomous-pr-loop/hooks/pre-compact.ts +4 -0
- package/plugins/autonomous-pr-loop/hooks/pre-tool-use.ts +44 -0
- package/plugins/autonomous-pr-loop/hooks/session-start.ts +4 -0
- package/plugins/autonomous-pr-loop/hooks/stop.ts +4 -0
- package/plugins/autonomous-pr-loop/hooks/user-prompt-submit.ts +4 -0
- package/plugins/autonomous-pr-loop/mcp-server/src/index.ts +87 -0
- package/plugins/autonomous-pr-loop/mcp-server/src/tools.ts +205 -0
- package/plugins/autonomous-pr-loop/package.json +9 -0
- package/plugins/autonomous-pr-loop/schemas/config.schema.json +74 -0
- package/plugins/autonomous-pr-loop/schemas/marketplace.schema.json +46 -0
- package/plugins/autonomous-pr-loop/schemas/plugin.schema.json +32 -0
- package/plugins/autonomous-pr-loop/schemas/state.schema.json +19 -0
- package/plugins/autonomous-pr-loop/schemas/worker-event.schema.json +19 -0
- package/plugins/autonomous-pr-loop/schemas/worker-result.schema.json +58 -0
- package/plugins/autonomous-pr-loop/scripts/agent-loop.ts +44 -0
- package/plugins/autonomous-pr-loop/skills/autonomous-pr-loop/SKILL.md +26 -0
- package/plugins/autonomous-pr-loop/skills/autonomous-pr-loop/agents/openai.yaml +6 -0
- package/plugins/autonomous-pr-loop/ui/index.html +26 -0
- package/plugins/autonomous-pr-loop/ui/public/favicon.svg +7 -0
- package/plugins/autonomous-pr-loop/ui/src/api.ts +639 -0
- package/plugins/autonomous-pr-loop/ui/src/app.tsx +238 -0
- package/plugins/autonomous-pr-loop/ui/src/components/ActivityBadge.tsx +31 -0
- package/plugins/autonomous-pr-loop/ui/src/components/BrandMark.tsx +36 -0
- package/plugins/autonomous-pr-loop/ui/src/components/Collapsible.tsx +6 -0
- package/plugins/autonomous-pr-loop/ui/src/components/CommandPreview.tsx +15 -0
- package/plugins/autonomous-pr-loop/ui/src/components/ConfigEditor.tsx +389 -0
- package/plugins/autonomous-pr-loop/ui/src/components/EmptyState.tsx +10 -0
- package/plugins/autonomous-pr-loop/ui/src/components/ErrorState.tsx +12 -0
- package/plugins/autonomous-pr-loop/ui/src/components/List.tsx +7 -0
- package/plugins/autonomous-pr-loop/ui/src/components/MetricRow.tsx +6 -0
- package/plugins/autonomous-pr-loop/ui/src/components/ResponsiveTable.tsx +65 -0
- package/plugins/autonomous-pr-loop/ui/src/components/RiskBadge.tsx +10 -0
- package/plugins/autonomous-pr-loop/ui/src/components/StatusBadge.tsx +29 -0
- package/plugins/autonomous-pr-loop/ui/src/components/TopMetric.tsx +10 -0
- package/plugins/autonomous-pr-loop/ui/src/fixtures.ts +1152 -0
- package/plugins/autonomous-pr-loop/ui/src/i18n.ts +1105 -0
- package/plugins/autonomous-pr-loop/ui/src/main.tsx +14 -0
- package/plugins/autonomous-pr-loop/ui/src/pages/CommandCenter.tsx +470 -0
- package/plugins/autonomous-pr-loop/ui/src/pages/CommandCenterParts.tsx +276 -0
- package/plugins/autonomous-pr-loop/ui/src/pages/agent-timeline/AgentTimelineView.tsx +73 -0
- package/plugins/autonomous-pr-loop/ui/src/pages/artifact-viewer/ArtifactViewer.tsx +44 -0
- package/plugins/autonomous-pr-loop/ui/src/pages/dry-run-preview/DryRunPreview.tsx +66 -0
- package/plugins/autonomous-pr-loop/ui/src/pages/event-ledger/EventLedger.tsx +17 -0
- package/plugins/autonomous-pr-loop/ui/src/pages/gate-center/GateCenter.tsx +34 -0
- package/plugins/autonomous-pr-loop/ui/src/pages/mission-control/MissionControl.tsx +104 -0
- package/plugins/autonomous-pr-loop/ui/src/pages/mission-control/WorkflowBoard.tsx +577 -0
- package/plugins/autonomous-pr-loop/ui/src/pages/notifications/NotificationsView.tsx +30 -0
- package/plugins/autonomous-pr-loop/ui/src/pages/plan-navigator/PlanNavigator.tsx +19 -0
- package/plugins/autonomous-pr-loop/ui/src/pages/policy-config/PolicyConfig.tsx +22 -0
- package/plugins/autonomous-pr-loop/ui/src/pages/pr-inbox/PrInbox.tsx +26 -0
- package/plugins/autonomous-pr-loop/ui/src/pages/recovery-center/RecoveryCenter.tsx +125 -0
- package/plugins/autonomous-pr-loop/ui/src/pages/scope-guard/ScopeGuard.tsx +16 -0
- package/plugins/autonomous-pr-loop/ui/src/pages/worker-runs/WorkerRuns.tsx +39 -0
- package/plugins/autonomous-pr-loop/ui/src/styles.css +2673 -0
- package/plugins/autonomous-pr-loop/ui/src/theme.ts +57 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { JSX } from "react";
|
|
2
|
+
import type { MissionControlData } from "../../api.js";
|
|
3
|
+
import { Collapsible } from "../../components/Collapsible.js";
|
|
4
|
+
import { MetricRow } from "../../components/MetricRow.js";
|
|
5
|
+
import { ResponsiveTable } from "../../components/ResponsiveTable.js";
|
|
6
|
+
import { StatusBadge, toneForStatus } from "../../components/StatusBadge.js";
|
|
7
|
+
import { displayValueLabel, t } from "../../i18n.js";
|
|
8
|
+
import { formatTime, type EffectiveLocale } from "../CommandCenterParts.js";
|
|
9
|
+
|
|
10
|
+
export function PrInbox({ data, locale }: { data: MissionControlData; locale: EffectiveLocale }): JSX.Element {
|
|
11
|
+
return (
|
|
12
|
+
<div className="two-stack">
|
|
13
|
+
<section className="pr-summary">
|
|
14
|
+
<MetricRow label={t(locale, "tablePullRequest")} value={data.pr ? `#${data.pr.prNumber} ${data.pr.state}` : t(locale, "none")} tone={data.pr ? "blue" : "muted"} />
|
|
15
|
+
<MetricRow label={t(locale, "tableDraft")} value={data.pr?.draft ? t(locale, "draft") : data.pr ? t(locale, "ready") : t(locale, "unknown")} tone={data.pr?.draft ? "yellow" : data.pr ? "green" : "muted"} />
|
|
16
|
+
<MetricRow label={t(locale, "tableBranch")} value={data.pr?.branch ?? t(locale, "notLinked")} tone={data.pr ? "blue" : "muted"} />
|
|
17
|
+
</section>
|
|
18
|
+
<Collapsible title={t(locale, "reviewComments")} chip={t(locale, "commentsChip", { count: data.reviewComments.length })} defaultOpen>
|
|
19
|
+
<ResponsiveTable columns={[t(locale, "tableComment"), t(locale, "tableAuthor"), t(locale, "tablePath"), t(locale, "tableStatus")]} rows={data.reviewComments.map((comment) => ({ key: comment.id, cells: [comment.body, comment.author, comment.path, <StatusBadge key={comment.id} value={displayValueLabel(locale, comment.status)} tone={toneForStatus(comment.status)} />], cardTitle: comment.body, cardMeta: comment.path, cardSummary: comment.author }))} empty={t(locale, "noReviewComments")} />
|
|
20
|
+
</Collapsible>
|
|
21
|
+
<Collapsible title={t(locale, "ciChecks")} chip={t(locale, "checksChip", { count: data.ci.length })} defaultOpen>
|
|
22
|
+
<ResponsiveTable columns={[t(locale, "tableCheck"), t(locale, "tableStatus"), t(locale, "tableConclusion"), t(locale, "tableObserved")]} rows={data.ci.map((check) => ({ key: check.id, cells: [check.name, check.status, check.conclusion ?? t(locale, "pending"), formatTime(check.observedAt)], cardTitle: check.name, cardMeta: formatTime(check.observedAt), cardSummary: check.conclusion ?? check.status }))} empty={t(locale, "noCiChecks")} />
|
|
23
|
+
</Collapsible>
|
|
24
|
+
</div>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import type { JSX } from "react";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import type { DashboardResult, GateReevaluationData, GateReevaluationResult, MissionControlData } from "../../api.js";
|
|
4
|
+
import { ActivityBadge, activityReasonLabel } from "../../components/ActivityBadge.js";
|
|
5
|
+
import { Collapsible } from "../../components/Collapsible.js";
|
|
6
|
+
import { List } from "../../components/List.js";
|
|
7
|
+
import { MetricRow } from "../../components/MetricRow.js";
|
|
8
|
+
import { t } from "../../i18n.js";
|
|
9
|
+
import { RawMessageDetails, summarizeRawMessage, workerScopeSummary, type EffectiveLocale } from "../CommandCenterParts.js";
|
|
10
|
+
|
|
11
|
+
export function RecoveryCenter({
|
|
12
|
+
data,
|
|
13
|
+
stale,
|
|
14
|
+
onRecover,
|
|
15
|
+
onReevaluateGate,
|
|
16
|
+
onMarkGateHandled,
|
|
17
|
+
locale
|
|
18
|
+
}: {
|
|
19
|
+
data: MissionControlData;
|
|
20
|
+
stale: boolean;
|
|
21
|
+
onRecover: () => void;
|
|
22
|
+
onReevaluateGate: (gateId: string) => Promise<DashboardResult<GateReevaluationData>>;
|
|
23
|
+
onMarkGateHandled: (gateId: string) => void;
|
|
24
|
+
locale: EffectiveLocale;
|
|
25
|
+
}): JSX.Element {
|
|
26
|
+
const run = data.current.run;
|
|
27
|
+
const historicalGates = data.gates.filter((gate) => gate.activity === "historical");
|
|
28
|
+
const staleWorkers = data.workers.filter((worker) => worker.activityReason === "stale_worker_failure");
|
|
29
|
+
const [results, setResults] = useState<Record<string, { result?: GateReevaluationResult; error?: string }>>({});
|
|
30
|
+
|
|
31
|
+
const reEvaluateGate = async (gateId: string): Promise<void> => {
|
|
32
|
+
const response = await onReevaluateGate(gateId);
|
|
33
|
+
const result = response.data?.result;
|
|
34
|
+
setResults((current) => ({
|
|
35
|
+
...current,
|
|
36
|
+
[gateId]: response.ok && isGateReevaluationResult(result)
|
|
37
|
+
? { result }
|
|
38
|
+
: { error: response.error?.message ?? t(locale, "reevaluateUnknownError") }
|
|
39
|
+
}));
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<div className="two-stack">
|
|
44
|
+
<section className="recovery-panel">
|
|
45
|
+
<MetricRow label={t(locale, "storageRun")} value={run?.id ?? t(locale, "none")} tone={run ? "blue" : "muted"} />
|
|
46
|
+
<MetricRow label={t(locale, "gitBranch")} value={run?.branch ?? t(locale, "unknown")} tone="blue" />
|
|
47
|
+
<MetricRow label={t(locale, "worktree")} value={run?.worktreeClean === false ? t(locale, "dirty") : t(locale, "clean")} tone={run?.worktreeClean === false ? "red" : "green"} />
|
|
48
|
+
<MetricRow label={t(locale, "freshness")} value={stale ? t(locale, "staleData") : t(locale, "fresh")} tone={stale ? "yellow" : "green"} />
|
|
49
|
+
</section>
|
|
50
|
+
<Collapsible title={t(locale, "recoveryWhyStopped")} chip={data.current.gate ? t(locale, "activityActive") : t(locale, "activityHistorical") } defaultOpen>
|
|
51
|
+
<List items={[recoveryExplanation(data, locale)]} locale={locale} />
|
|
52
|
+
</Collapsible>
|
|
53
|
+
{historicalGates.length ? (
|
|
54
|
+
<Collapsible title={t(locale, "historicalGates")} chip={t(locale, "gatesChip", { count: historicalGates.length })} defaultOpen>
|
|
55
|
+
<div className="compact-card-list">
|
|
56
|
+
{historicalGates.map((gate) => (
|
|
57
|
+
<article className="compact-data-card" key={gate.id}>
|
|
58
|
+
<div className="compact-data-card__head">
|
|
59
|
+
<strong>{gate.kind}</strong>
|
|
60
|
+
<ActivityBadge activity={gate.activity} reason={gate.activityReason} locale={locale} />
|
|
61
|
+
</div>
|
|
62
|
+
<p>{summarizeRawMessage(gate.message, locale)}</p>
|
|
63
|
+
<dl>
|
|
64
|
+
<div><dt>{t(locale, "gateId")}</dt><dd>{gate.id}</dd></div>
|
|
65
|
+
<div><dt>{t(locale, "reason")}</dt><dd>{activityReasonLabel(locale, gate.activityReason)}</dd></div>
|
|
66
|
+
<div><dt>{t(locale, "tableRawMessage")}</dt><dd><RawMessageDetails message={gate.message} locale={locale} /></dd></div>
|
|
67
|
+
</dl>
|
|
68
|
+
{results[gate.id] ? (
|
|
69
|
+
<div className={results[gate.id]?.error ? "action-result action-result--error" : "action-result"}>
|
|
70
|
+
<strong>{t(locale, "reevaluateResultTitle")}</strong>
|
|
71
|
+
<span>{results[gate.id]?.error ?? t(locale, `reevaluateResult.${results[gate.id]?.result}`)}</span>
|
|
72
|
+
</div>
|
|
73
|
+
) : null}
|
|
74
|
+
<div className="button-row">
|
|
75
|
+
<button className="ghost-button" type="button" onClick={() => void reEvaluateGate(gate.id)}>{t(locale, "actionReevaluate")}</button>
|
|
76
|
+
{gate.status === "open" ? (
|
|
77
|
+
<button className="ghost-button" type="button" onClick={() => onMarkGateHandled(gate.id)}>{t(locale, "actionMarkHandled")}</button>
|
|
78
|
+
) : null}
|
|
79
|
+
</div>
|
|
80
|
+
</article>
|
|
81
|
+
))}
|
|
82
|
+
</div>
|
|
83
|
+
</Collapsible>
|
|
84
|
+
) : null}
|
|
85
|
+
{staleWorkers.length ? (
|
|
86
|
+
<Collapsible title={t(locale, "staleWorkerFailures")} chip={workerScopeSummary(data.workers, locale)}>
|
|
87
|
+
<div className="compact-card-list compact-card-list--always">
|
|
88
|
+
{staleWorkers.map((worker) => (
|
|
89
|
+
<article className="compact-data-card" key={worker.id}>
|
|
90
|
+
<div className="compact-data-card__head">
|
|
91
|
+
<strong>{worker.id}</strong>
|
|
92
|
+
<ActivityBadge activity={worker.activity} reason={worker.activityReason} locale={locale} />
|
|
93
|
+
</div>
|
|
94
|
+
<p>{summarizeRawMessage(worker.error, locale) ?? activityReasonLabel(locale, worker.activityReason)}</p>
|
|
95
|
+
{worker.error ? <RawMessageDetails message={worker.error} locale={locale} /> : null}
|
|
96
|
+
</article>
|
|
97
|
+
))}
|
|
98
|
+
</div>
|
|
99
|
+
</Collapsible>
|
|
100
|
+
) : null}
|
|
101
|
+
{data.recoveryWarnings?.length ? <Collapsible title={t(locale, "recoveryWarnings")} chip={t(locale, "warningsChip", { count: data.recoveryWarnings.length })} defaultOpen><List items={data.recoveryWarnings} locale={locale} /></Collapsible> : null}
|
|
102
|
+
<button className="ghost-button" type="button" onClick={onRecover}>{t(locale, "actionRunRecovery")}</button>
|
|
103
|
+
</div>
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function recoveryExplanation(data: MissionControlData, locale: EffectiveLocale): string {
|
|
108
|
+
if (data.current.gate) {
|
|
109
|
+
return t(locale, "recoveryExplanationActive", { gate: data.current.gate.kind });
|
|
110
|
+
}
|
|
111
|
+
if (data.gates.some((gate) => gate.activity === "historical")) {
|
|
112
|
+
return t(locale, "recoveryExplanationHistorical");
|
|
113
|
+
}
|
|
114
|
+
if (data.current.status === "STOPPED") {
|
|
115
|
+
return t(locale, "recoveryExplanationStopped");
|
|
116
|
+
}
|
|
117
|
+
return t(locale, "recoveryExplanationClear");
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function isGateReevaluationResult(value: unknown): value is GateReevaluationResult {
|
|
121
|
+
return value === "still_historical" ||
|
|
122
|
+
value === "overridden_by_current_reality" ||
|
|
123
|
+
value === "active_again" ||
|
|
124
|
+
value === "manually_handled";
|
|
125
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { JSX } from "react";
|
|
2
|
+
import type { MissionControlData } from "../../api.js";
|
|
3
|
+
import { ResponsiveTable } from "../../components/ResponsiveTable.js";
|
|
4
|
+
import { t } from "../../i18n.js";
|
|
5
|
+
import type { EffectiveLocale } from "../CommandCenterParts.js";
|
|
6
|
+
|
|
7
|
+
export function ScopeGuard({ data, locale }: { data: MissionControlData; locale: EffectiveLocale }): JSX.Element {
|
|
8
|
+
const scopeEvents = data.events.filter((event) => event.kind.includes("scope") || event.kind.includes("gitnexus") || event.kind.includes("policy"));
|
|
9
|
+
return (
|
|
10
|
+
<ResponsiveTable
|
|
11
|
+
columns={[t(locale, "tableSeq"), t(locale, "tableEvent"), t(locale, "tableMessage"), t(locale, "tableState")]}
|
|
12
|
+
rows={scopeEvents.map((event) => ({ key: event.id, cells: [String(event.seq), event.kind, event.message, event.stateAfter ?? "-"], cardTitle: event.kind, cardMeta: `#${event.seq}`, cardSummary: event.message }))}
|
|
13
|
+
empty={t(locale, "noScopeEvidence")}
|
|
14
|
+
/>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { JSX } from "react";
|
|
2
|
+
import type { DashboardApi, WorkerSummary } from "../../api.js";
|
|
3
|
+
import { ActivityBadge, activityReasonLabel } from "../../components/ActivityBadge.js";
|
|
4
|
+
import { ResponsiveTable } from "../../components/ResponsiveTable.js";
|
|
5
|
+
import { StatusBadge, toneForStatus } from "../../components/StatusBadge.js";
|
|
6
|
+
import { displayValueLabel, t } from "../../i18n.js";
|
|
7
|
+
import { RawMessageDetails, WorkerEventDetails, formatTime, summarizeRawMessage, workerScopeSummary, type EffectiveLocale } from "../CommandCenterParts.js";
|
|
8
|
+
|
|
9
|
+
export function WorkerRuns({ workers, api, locale, scopeNote, hideScopeNote = false }: { workers: WorkerSummary[]; api: DashboardApi; locale: EffectiveLocale; scopeNote?: string; hideScopeNote?: boolean }): JSX.Element {
|
|
10
|
+
return (
|
|
11
|
+
<div className="two-stack">
|
|
12
|
+
{hideScopeNote ? null : <p className="scope-note">{scopeNote ?? workerScopeSummary(workers, locale)}</p>}
|
|
13
|
+
<ResponsiveTable
|
|
14
|
+
columns={[t(locale, "tableWorker"), t(locale, "tableActivity"), t(locale, "tableRole"), t(locale, "tableStatus"), t(locale, "tableStarted"), t(locale, "tableRawResultError")]}
|
|
15
|
+
rows={workers.map((worker) => {
|
|
16
|
+
const { error, ...workerForEvents } = worker;
|
|
17
|
+
return {
|
|
18
|
+
key: worker.id,
|
|
19
|
+
cells: [
|
|
20
|
+
worker.id.slice(0, 8),
|
|
21
|
+
<ActivityBadge key={`${worker.id}-activity`} activity={worker.activity} reason={worker.activityReason} locale={locale} />,
|
|
22
|
+
worker.type,
|
|
23
|
+
<StatusBadge key={worker.id} value={displayValueLabel(locale, worker.status)} tone={toneForStatus(worker.status)} />,
|
|
24
|
+
formatTime(worker.startedAt),
|
|
25
|
+
<>
|
|
26
|
+
{error ? <RawMessageDetails message={error} locale={locale} /> : null}
|
|
27
|
+
<WorkerEventDetails worker={workerForEvents} api={api} locale={locale} />
|
|
28
|
+
</>
|
|
29
|
+
],
|
|
30
|
+
cardTitle: `${worker.type} / ${worker.status}`,
|
|
31
|
+
cardMeta: `${worker.id} / ${activityReasonLabel(locale, worker.activityReason)} / ${formatTime(worker.startedAt)}`,
|
|
32
|
+
cardSummary: summarizeRawMessage(error, locale) ?? worker.resultArtifactId ?? t(locale, "workerEvents")
|
|
33
|
+
};
|
|
34
|
+
})}
|
|
35
|
+
empty={t(locale, "noWorkerRuns")}
|
|
36
|
+
/>
|
|
37
|
+
</div>
|
|
38
|
+
);
|
|
39
|
+
}
|