feat: deliverable review gate, app lifecycle fixes, CI/CD pipeline
- Add deliverable review gate: pause workflow when agents produce important documents (PRDs, design docs, etc.) for human review before continuing - Add company-level reviewDeliverables setting with onboarding card selector - Block agent heartbeats when deliverable review is pending (agent + CEO) - Trigger review at document creation time in API server for reliability - Fix autoApproveHires vs reviewDeliverables conflict in approval-policy - Fix app quit: force-exit on all platforms (macOS Dock, Windows tray, Linux) - Add multi-platform CI/CD pipeline (macOS arm64/x64, Windows x64/arm64, Linux x64/arm64 with deb/AppImage/rpm/snap) with code signing support Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
9e2c19259a
commit
d52985f61e
24 files changed
+737
-48
No files matched your search
@@ -37,7 +37,10 @@ export function SettingsPane({ snapshot, secrets, companyId, onSaved }: { snapsh
|
||||
</div>
|
||||
{(() => { const company = snapshot.companies.find((c) => c.id === companyId); if (!company) return null; return (
|
||||
<div><div className="mb-3 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]">{t("exec.companyAutonomy")}</div>
|
||||
<div className="rounded-[8px] border border-[color:var(--line)] px-4 py-3"><label className="flex items-center gap-3"><input type="checkbox" checked={company.autoApproveHires} onChange={async (e) => { setActionError(null); try { unwrap(await window.agentCompany.saveCompany({ id: company.id, name: company.name, description: company.description, status: company.status, autoApproveHires: e.target.checked })); await onSaved() } catch (err) { setActionError(describeActionError(err)) } }} className="h-4 w-4 rounded accent-[color:var(--accent)]" /><div><div className="text-[13px] font-medium text-[color:var(--text)]">{t("exec.autoApproveLabel")}</div><div className="mt-0.5 text-[11px] text-[color:var(--muted)]">{t("exec.autoApproveDesc")}</div></div></label></div></div>) })()}
|
||||
<div className="space-y-3">
|
||||
<div className="rounded-[8px] border border-[color:var(--line)] px-4 py-3"><label className="flex items-center gap-3"><input type="checkbox" checked={company.autoApproveHires} onChange={async (e) => { setActionError(null); try { unwrap(await window.agentCompany.saveCompany({ id: company.id, name: company.name, description: company.description, status: company.status, autoApproveHires: e.target.checked, reviewDeliverables: company.reviewDeliverables })); await onSaved() } catch (err) { setActionError(describeActionError(err)) } }} className="h-4 w-4 rounded accent-[color:var(--accent)]" /><div><div className="text-[13px] font-medium text-[color:var(--text)]">{t("exec.autoApproveLabel")}</div><div className="mt-0.5 text-[11px] text-[color:var(--muted)]">{t("exec.autoApproveDesc")}</div></div></label></div>
|
||||
<div className="rounded-[8px] border border-[color:var(--line)] px-4 py-3"><label className="flex items-center gap-3"><input type="checkbox" checked={!company.reviewDeliverables} onChange={async (e) => { setActionError(null); try { unwrap(await window.agentCompany.saveCompany({ id: company.id, name: company.name, description: company.description, status: company.status, autoApproveHires: company.autoApproveHires, reviewDeliverables: !e.target.checked })); await onSaved() } catch (err) { setActionError(describeActionError(err)) } }} className="h-4 w-4 rounded accent-[color:var(--accent)]" /><div><div className="text-[13px] font-medium text-[color:var(--text)]">{t("exec.reviewDeliverablesLabel")}</div><div className="mt-0.5 text-[11px] text-[color:var(--muted)]">{t("exec.reviewDeliverablesDesc")}</div></div></label></div>
|
||||
</div></div>) })()}
|
||||
<div><div className="mb-3 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]">{t("exec.actions")}</div><div className="grid gap-3 md:grid-cols-2"><ActionButton label={t("exec.saveSettings")} tone="accent" onClick={() => void handleSaveSettings()} icon={CheckCircle} loading={loadingAction === "save"} /><ActionButton label={t("exec.checkForUpdates")} onClick={() => void handleCheckForUpdates()} icon={Download} loading={loadingAction === "check"} /><ActionButton label={t("exec.backupProfile")} onClick={() => void handleBackupProfile()} icon={ClockCounterClockwise} loading={loadingAction === "backup"} /><ActionButton label={t("exec.restoreProfile")} onClick={() => void handleRestoreProfile()} icon={ArrowClockwise} loading={loadingAction === "restore"} /></div></div>
|
||||
<div><div className="mb-3 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]">{t("exec.secretBackend")}</div><div className="border-y border-[color:var(--line)] py-3 text-[13px] text-[color:var(--muted-strong)]">{snapshot.backend.secretBackend}</div></div>
|
||||
<div><div className="mb-3 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]">{t("exec.secrets")} ({secrets.length})</div>{secrets.length === 0 ? <EmptyState title={t("exec.noSecretsStored")} /> : <div className="border-y border-[color:var(--line)] overflow-x-auto"><table className="w-full text-left text-[13px]"><thead><tr className="border-b border-[color:var(--line)]"><th className="px-4 py-3 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]">{t("exec.secretName")}</th><th className="px-4 py-3 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]">{t("exec.secretDescription")}</th><th className="px-4 py-3 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]">{t("exec.secretBackendCol")}</th><th className="px-4 py-3 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]">{t("exec.secretUpdated")}</th><th className="px-4 py-3 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]" /></tr></thead><tbody>{secrets.map((s) => <tr key={s.id} className="border-b border-[color:var(--line)] last:border-b-0"><td className="px-4 py-3 font-medium text-[color:var(--text)]">{s.name}</td><td className="px-4 py-3 text-[color:var(--muted)]">{s.description || "\u2014"}</td><td className="px-4 py-3 mono text-[color:var(--muted-strong)]">{s.backend}</td><td className="px-4 py-3 mono text-[color:var(--muted)]">{formatTime(s.updatedAt)}</td><td className="px-4 py-3"><ActionButton label="Delete" onClick={() => setConfirmDeleteSecretId(s.id)} icon={Trash} tone="danger" /></td></tr>)}</tbody></table></div>}</div>
|
||||
|
||||
Reference in new issue
Block a user