@opengsd/gsd-pi 1.5.0-dev.4fb2d460 → 1.5.0-dev.c4c8885f
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/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +114 -36
- package/dist/resources/extensions/gsd/activity-log.js +1 -1
- package/dist/resources/extensions/gsd/auto/orchestrator.js +16 -10
- package/dist/resources/extensions/gsd/auto-artifact-paths.js +2 -2
- package/dist/resources/extensions/gsd/auto-dispatch.js +53 -15
- package/dist/resources/extensions/gsd/auto-model-selection.js +28 -1
- package/dist/resources/extensions/gsd/auto-post-unit.js +4 -3
- package/dist/resources/extensions/gsd/auto-prompts.js +29 -117
- package/dist/resources/extensions/gsd/auto-start.js +53 -30
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +12 -2
- package/dist/resources/extensions/gsd/auto-timers.js +9 -2
- package/dist/resources/extensions/gsd/auto.js +97 -31
- package/dist/resources/extensions/gsd/compat/compat-marker.js +44 -0
- package/dist/resources/extensions/gsd/config-overlay.js +7 -2
- package/dist/resources/extensions/gsd/db/engine.js +33 -0
- package/dist/resources/extensions/gsd/db-adapter.js +30 -3
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +3 -3
- package/dist/resources/extensions/gsd/journal.js +1 -1
- package/dist/resources/extensions/gsd/markdown-renderer.js +34 -91
- package/dist/resources/extensions/gsd/metrics.js +2 -2
- package/dist/resources/extensions/gsd/paths.js +70 -49
- package/dist/resources/extensions/gsd/post-unit-hooks.js +27 -0
- package/dist/resources/extensions/gsd/preferences-models.js +66 -15
- package/dist/resources/extensions/gsd/preferences-validation.js +66 -10
- package/dist/resources/extensions/gsd/rule-registry.js +106 -10
- package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +1 -10
- package/dist/resources/extensions/gsd/state-reconciliation/drift/completion.js +3 -24
- package/dist/resources/extensions/gsd/state-reconciliation/index.js +10 -0
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +3 -5
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +16 -10
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +3 -8
- package/dist/resources/extensions/gsd/uat-dispatch.js +94 -0
- package/dist/resources/extensions/gsd/uok/audit-toggle.js +31 -2
- package/dist/resources/extensions/gsd/uok/audit.js +3 -0
- package/dist/resources/extensions/gsd/uok/gate-runner.js +22 -30
- package/dist/resources/extensions/gsd/uok/gitops.js +18 -15
- package/dist/resources/extensions/gsd/uok/kernel.js +120 -46
- package/dist/resources/extensions/gsd/uok/model-policy.js +17 -14
- package/dist/resources/extensions/gsd/workflow-event-ledger.js +1 -1
- package/dist/resources/extensions/gsd/workflow-logger.js +1 -1
- package/dist/resources/extensions/gsd/workflow-projections.js +9 -26
- package/dist/resources/extensions/gsd/workspace.js +5 -14
- package/dist/resources/extensions/shared/gsd-browser-cli.js +29 -0
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
- package/dist/web/standalone/.next/server/chunks/{1128.js → 1991.js} +1 -1
- package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/worktree-cli-create.d.ts +10 -0
- package/dist/worktree-cli-create.js +11 -0
- package/dist/worktree-cli-format.d.ts +12 -0
- package/dist/worktree-cli-format.js +38 -0
- package/dist/worktree-cli-plan.d.ts +16 -0
- package/dist/worktree-cli-plan.js +19 -0
- package/dist/worktree-cli-session.d.ts +13 -0
- package/dist/worktree-cli-session.js +18 -0
- package/dist/worktree-cli-status.d.ts +35 -0
- package/dist/worktree-cli-status.js +54 -0
- package/dist/worktree-cli.d.ts +1 -16
- package/dist/worktree-cli.js +28 -122
- package/integrations/hermes/open_gsd_hermes/gsd_client.py +1 -1
- package/integrations/hermes/pyproject.toml +1 -1
- package/package.json +1 -1
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/dist/orchestrator-agent.d.ts +21 -0
- package/packages/daemon/dist/orchestrator-agent.d.ts.map +1 -0
- package/packages/daemon/dist/orchestrator-agent.js +113 -0
- package/packages/daemon/dist/orchestrator-agent.js.map +1 -0
- package/packages/daemon/dist/orchestrator-tools.d.ts +12 -0
- package/packages/daemon/dist/orchestrator-tools.d.ts.map +1 -0
- package/packages/daemon/dist/orchestrator-tools.js +137 -0
- package/packages/daemon/dist/orchestrator-tools.js.map +1 -0
- package/packages/daemon/dist/orchestrator.d.ts +4 -56
- package/packages/daemon/dist/orchestrator.d.ts.map +1 -1
- package/packages/daemon/dist/orchestrator.js +13 -303
- package/packages/daemon/dist/orchestrator.js.map +1 -1
- package/packages/daemon/dist/orchestrator.test.js +11 -1
- package/packages/daemon/dist/orchestrator.test.js.map +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/package.json +4 -4
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/package.json +2 -2
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +146 -33
- package/src/resources/extensions/browser-tools/tests/gsd-browser-launch-config.test.mjs +25 -0
- package/src/resources/extensions/browser-tools/tests/managed-gsd-browser-tools.test.mjs +93 -0
- package/src/resources/extensions/gsd/activity-log.ts +1 -1
- package/src/resources/extensions/gsd/auto/orchestrator.ts +17 -11
- package/src/resources/extensions/gsd/auto-artifact-paths.ts +2 -1
- package/src/resources/extensions/gsd/auto-dispatch.ts +59 -14
- package/src/resources/extensions/gsd/auto-model-selection.ts +33 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +4 -2
- package/src/resources/extensions/gsd/auto-prompts.ts +53 -113
- package/src/resources/extensions/gsd/auto-start.ts +57 -28
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +12 -2
- package/src/resources/extensions/gsd/auto-timers.ts +9 -2
- package/src/resources/extensions/gsd/auto.ts +103 -30
- package/src/resources/extensions/gsd/compat/compat-marker.ts +47 -0
- package/src/resources/extensions/gsd/config-overlay.ts +7 -1
- package/src/resources/extensions/gsd/db/engine.ts +36 -0
- package/src/resources/extensions/gsd/db-adapter.ts +29 -3
- package/src/resources/extensions/gsd/docs/preferences-reference.md +3 -3
- package/src/resources/extensions/gsd/journal.ts +1 -1
- package/src/resources/extensions/gsd/markdown-renderer.ts +52 -103
- package/src/resources/extensions/gsd/metrics.ts +2 -2
- package/src/resources/extensions/gsd/paths.ts +87 -48
- package/src/resources/extensions/gsd/post-unit-hooks.ts +32 -0
- package/src/resources/extensions/gsd/preferences-models.ts +74 -20
- package/src/resources/extensions/gsd/preferences-types.ts +24 -1
- package/src/resources/extensions/gsd/preferences-validation.ts +77 -9
- package/src/resources/extensions/gsd/rule-registry.ts +111 -9
- package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +1 -9
- package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +2 -22
- package/src/resources/extensions/gsd/state-reconciliation/index.ts +14 -0
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +41 -2
- package/src/resources/extensions/gsd/tests/auto-post-unit-artifact-diagnostic.test.ts +48 -1
- package/src/resources/extensions/gsd/tests/auto-start-project-milestone-reconcile.test.ts +29 -1
- package/src/resources/extensions/gsd/tests/auto-timeout-recovery-supervisor-inflight-guard.test.ts +159 -0
- package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/compat-marker.test.ts +85 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/db-adapter.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/db-writable-probe.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/flat-phase-renderer.test.ts +22 -1
- package/src/resources/extensions/gsd/tests/flat-phase-validation-path.test.ts +72 -32
- package/src/resources/extensions/gsd/tests/integration/paths.test.ts +88 -1
- package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +0 -1
- package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +269 -0
- package/src/resources/extensions/gsd/tests/post-unit-retry-on-orchestrator-bridge.test.ts +8 -1
- package/src/resources/extensions/gsd/tests/read-uat-gate-verdict.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/reassess-handler.test.ts +49 -1
- package/src/resources/extensions/gsd/tests/rule-registry.test.ts +95 -1
- package/src/resources/extensions/gsd/tests/sibling-model-fallbacks.test.ts +189 -0
- package/src/resources/extensions/gsd/tests/single-field-model-thinking.test.ts +156 -0
- package/src/resources/extensions/gsd/tests/skipped-validation-db-atomicity.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/supervisor-model-swap-inflight-guard.test.ts +181 -0
- package/src/resources/extensions/gsd/tests/supervisor-model-swap-thinking-clamp.test.ts +122 -0
- package/src/resources/extensions/gsd/tests/uat-dispatch.test.ts +211 -0
- package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/uok-kernel-path.test.ts +226 -2
- package/src/resources/extensions/gsd/tests/uok-model-policy.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +213 -2
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +9 -5
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +19 -8
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +13 -9
- package/src/resources/extensions/gsd/types.ts +23 -4
- package/src/resources/extensions/gsd/uat-dispatch.ts +176 -0
- package/src/resources/extensions/gsd/uok/audit-toggle.ts +32 -2
- package/src/resources/extensions/gsd/uok/audit.ts +2 -0
- package/src/resources/extensions/gsd/uok/gate-runner.ts +26 -36
- package/src/resources/extensions/gsd/uok/gitops.ts +21 -18
- package/src/resources/extensions/gsd/uok/kernel.ts +169 -48
- package/src/resources/extensions/gsd/uok/model-policy.ts +20 -17
- package/src/resources/extensions/gsd/workflow-event-ledger.ts +1 -1
- package/src/resources/extensions/gsd/workflow-logger.ts +1 -1
- package/src/resources/extensions/gsd/workflow-projections.ts +9 -24
- package/src/resources/extensions/gsd/workspace.ts +5 -21
- package/src/resources/extensions/shared/gsd-browser-cli.ts +29 -0
- /package/dist/web/standalone/.next/static/{gXoWec4UNqcR0tkuHwYCr → NPMNi2HV8BuK3baQsEUhk}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{gXoWec4UNqcR0tkuHwYCr → NPMNi2HV8BuK3baQsEUhk}/_ssgManifest.js +0 -0
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
// Types consumed by state derivation, file parsing, and status display.
|
|
3
3
|
// Pure interfaces — no logic, no runtime dependencies.
|
|
4
4
|
|
|
5
|
+
// Type-only import (erased at compile time — no runtime dependency): sibling
|
|
6
|
+
// single-model fields share the phase-bucket object form so they honor
|
|
7
|
+
// `fallbacks[]` (#1229).
|
|
8
|
+
import type { GSDPhaseModelConfig } from "./preferences-types.js";
|
|
9
|
+
|
|
5
10
|
// ─── Enums & Literal Unions ────────────────────────────────────────────────
|
|
6
11
|
|
|
7
12
|
export type RiskLevel = "low" | "medium" | "high";
|
|
@@ -303,8 +308,13 @@ export interface PostUnitHookConfig {
|
|
|
303
308
|
prompt: string;
|
|
304
309
|
/** Max times this hook can fire for the same trigger unit. Default 1, max 10. */
|
|
305
310
|
max_cycles?: number;
|
|
306
|
-
/**
|
|
307
|
-
|
|
311
|
+
/**
|
|
312
|
+
* Model override for hook sessions. Accepts a bare model ID or the extended
|
|
313
|
+
* `{ model, provider?, fallbacks? }` object form so a transient trip of the
|
|
314
|
+
* primary provider falls back to the next entry instead of hard-failing the
|
|
315
|
+
* hook (#1229).
|
|
316
|
+
*/
|
|
317
|
+
model?: string | GSDPhaseModelConfig;
|
|
308
318
|
/** Expected output file name (relative to task/slice dir). Used for idempotency — skip if exists. */
|
|
309
319
|
artifact?: string;
|
|
310
320
|
/** Whether the hook is advisory or blocks unit advancement. Default advisory. */
|
|
@@ -505,6 +515,11 @@ export interface PreDispatchResult {
|
|
|
505
515
|
export interface PersistedHookState {
|
|
506
516
|
/** Cycle counts keyed as "hookName/triggerUnitType/triggerUnitId". */
|
|
507
517
|
cycleCounts: Record<string, number>;
|
|
518
|
+
/**
|
|
519
|
+
* Cycle keys already granted a one-shot re-dispatch after a lost/interrupted
|
|
520
|
+
* dispatch, so the refund is bounded to one per gate across resumes.
|
|
521
|
+
*/
|
|
522
|
+
redispatchedGateKeys?: string[];
|
|
508
523
|
/** In-flight hook, persisted so blocking gates cannot be skipped after resume. */
|
|
509
524
|
activeHook?: HookExecutionState | null;
|
|
510
525
|
/** Remaining hook queue by hook name and trigger unit. */
|
|
@@ -607,8 +622,12 @@ export interface ReactiveExecutionConfig {
|
|
|
607
622
|
max_parallel: number;
|
|
608
623
|
/** Isolation mode for parallel tasks within a slice. Currently only "same-tree" is supported. */
|
|
609
624
|
isolation_mode: "same-tree";
|
|
610
|
-
/**
|
|
611
|
-
|
|
625
|
+
/**
|
|
626
|
+
* Optional model override for subagents spawned during parallel execution.
|
|
627
|
+
* Accepts a bare model ID or the extended `{ model, provider?, fallbacks? }`
|
|
628
|
+
* object form for parity with phase buckets (#1229).
|
|
629
|
+
*/
|
|
630
|
+
subagent_model?: string | GSDPhaseModelConfig;
|
|
612
631
|
}
|
|
613
632
|
|
|
614
633
|
/** Per-slice reactive execution runtime state, persisted to disk. */
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
// Project/App: gsd-pi
|
|
2
|
+
// File Purpose: Resolve whether a completed slice needs run-uat dispatch.
|
|
3
|
+
|
|
4
|
+
import { loadFile } from "./files.js";
|
|
5
|
+
import type { GSDPreferences } from "./preferences.js";
|
|
6
|
+
import { resolveSliceFile } from "./paths.js";
|
|
7
|
+
import {
|
|
8
|
+
classifyUatContentForRun,
|
|
9
|
+
shouldDispatchUatForContent,
|
|
10
|
+
type UatType,
|
|
11
|
+
} from "./uat-policy.js";
|
|
12
|
+
import { hasVerdict } from "./verdict-parser.js";
|
|
13
|
+
import { logWarning } from "./workflow-logger.js";
|
|
14
|
+
|
|
15
|
+
export interface UatDispatchCandidate {
|
|
16
|
+
sliceId: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type RunUatDispatch = { sliceId: string; uatType: UatType };
|
|
20
|
+
|
|
21
|
+
async function loadSliceFileContent(
|
|
22
|
+
base: string,
|
|
23
|
+
milestoneId: string,
|
|
24
|
+
sliceId: string,
|
|
25
|
+
kind: "UAT" | "ASSESSMENT" | "SUMMARY",
|
|
26
|
+
): Promise<string> {
|
|
27
|
+
const filePath = resolveSliceFile(base, milestoneId, sliceId, kind);
|
|
28
|
+
return filePath ? ((await loadFile(filePath)) ?? "") : "";
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function resolveRunUatEffectiveType(
|
|
32
|
+
base: string,
|
|
33
|
+
milestoneId: string,
|
|
34
|
+
sliceId: string,
|
|
35
|
+
uatContent: string,
|
|
36
|
+
): Promise<UatType> {
|
|
37
|
+
let summaryContent = "";
|
|
38
|
+
try {
|
|
39
|
+
summaryContent = await loadSliceFileContent(
|
|
40
|
+
base,
|
|
41
|
+
milestoneId,
|
|
42
|
+
sliceId,
|
|
43
|
+
"SUMMARY",
|
|
44
|
+
);
|
|
45
|
+
} catch (err) {
|
|
46
|
+
logWarning(
|
|
47
|
+
"prompt",
|
|
48
|
+
`resolveRunUatEffectiveType SUMMARY load failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
return classifyUatContentForRun(uatContent, summaryContent).effectiveType;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function resolveCandidateRunUatDispatch(
|
|
55
|
+
base: string,
|
|
56
|
+
milestoneId: string,
|
|
57
|
+
candidate: UatDispatchCandidate,
|
|
58
|
+
prefs: GSDPreferences | undefined,
|
|
59
|
+
): Promise<RunUatDispatch | null> {
|
|
60
|
+
const uatContent = await loadSliceFileContent(
|
|
61
|
+
base,
|
|
62
|
+
milestoneId,
|
|
63
|
+
candidate.sliceId,
|
|
64
|
+
"UAT",
|
|
65
|
+
);
|
|
66
|
+
if (!uatContent) return null;
|
|
67
|
+
if (hasVerdict(uatContent)) return null;
|
|
68
|
+
|
|
69
|
+
const assessmentContent = await loadSliceFileContent(
|
|
70
|
+
base,
|
|
71
|
+
milestoneId,
|
|
72
|
+
candidate.sliceId,
|
|
73
|
+
"ASSESSMENT",
|
|
74
|
+
);
|
|
75
|
+
if (assessmentContent && hasVerdict(assessmentContent)) return null;
|
|
76
|
+
if (!shouldDispatchUatForContent(uatContent, prefs)) return null;
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
sliceId: candidate.sliceId,
|
|
80
|
+
uatType: await resolveRunUatEffectiveType(
|
|
81
|
+
base,
|
|
82
|
+
milestoneId,
|
|
83
|
+
candidate.sliceId,
|
|
84
|
+
uatContent,
|
|
85
|
+
),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async function getDbCompletedSliceCandidates(
|
|
90
|
+
milestoneId: string,
|
|
91
|
+
): Promise<UatDispatchCandidate[] | null> {
|
|
92
|
+
const { isDbAvailable, getMilestoneSlices } = await import("./gsd-db.js");
|
|
93
|
+
if (!isDbAvailable()) return null;
|
|
94
|
+
|
|
95
|
+
const slices = getMilestoneSlices(milestoneId);
|
|
96
|
+
// No DB slice rows for this milestone: the DB has no authoritative view, so
|
|
97
|
+
// return null to let the caller defer to the roadmap fallback.
|
|
98
|
+
if (slices.length === 0) return null;
|
|
99
|
+
|
|
100
|
+
// The DB has slice rows and is therefore authoritative for this milestone.
|
|
101
|
+
// Return a (possibly empty) array rather than null: an empty result must NOT
|
|
102
|
+
// fall through to the roadmap fallback, because the DB, not stale roadmap
|
|
103
|
+
// checkboxes, is the source of truth for which slices are complete.
|
|
104
|
+
return slices
|
|
105
|
+
.filter((slice) => slice.status === "complete")
|
|
106
|
+
.map((slice) => ({ sliceId: slice.id }))
|
|
107
|
+
.reverse();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export async function findRunUatDispatchFromCandidates(
|
|
111
|
+
base: string,
|
|
112
|
+
milestoneId: string,
|
|
113
|
+
candidates: readonly UatDispatchCandidate[],
|
|
114
|
+
prefs: GSDPreferences | undefined,
|
|
115
|
+
): Promise<RunUatDispatch | null> {
|
|
116
|
+
for (const candidate of candidates) {
|
|
117
|
+
const dispatch = await resolveCandidateRunUatDispatch(
|
|
118
|
+
base,
|
|
119
|
+
milestoneId,
|
|
120
|
+
candidate,
|
|
121
|
+
prefs,
|
|
122
|
+
);
|
|
123
|
+
if (dispatch) return dispatch;
|
|
124
|
+
}
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Check if the most recently completed slice needs a UAT run.
|
|
130
|
+
* Returns { sliceId, uatType } if UAT should be dispatched, null otherwise.
|
|
131
|
+
*
|
|
132
|
+
* When the DB has slice rows for the milestone it is authoritative: only its
|
|
133
|
+
* completed slices are considered and the `fallbackCandidates` (roadmap-derived)
|
|
134
|
+
* are ignored, even when no DB slice is complete. The fallback candidates are
|
|
135
|
+
* only consulted when the DB has no slice rows for the milestone, is
|
|
136
|
+
* unavailable, or errors.
|
|
137
|
+
*
|
|
138
|
+
* Skips when:
|
|
139
|
+
* - No completed slices exist in DB or the caller-provided fallback candidates
|
|
140
|
+
* - uat_dispatch is not enabled and the UAT spec does not require runtime/browser evidence
|
|
141
|
+
* - No UAT file exists for the slice
|
|
142
|
+
* - UAT result already exists in the UAT or ASSESSMENT file
|
|
143
|
+
*/
|
|
144
|
+
export async function checkNeedsRunUat(
|
|
145
|
+
base: string,
|
|
146
|
+
milestoneId: string,
|
|
147
|
+
prefs: GSDPreferences | undefined,
|
|
148
|
+
fallbackCandidates: readonly UatDispatchCandidate[] = [],
|
|
149
|
+
): Promise<RunUatDispatch | null> {
|
|
150
|
+
try {
|
|
151
|
+
const dbCandidates = await getDbCompletedSliceCandidates(milestoneId);
|
|
152
|
+
// A non-null result (including an empty array) means the DB is authoritative
|
|
153
|
+
// for this milestone; only fall through to the roadmap fallback when the DB
|
|
154
|
+
// has no slice rows at all (null).
|
|
155
|
+
if (dbCandidates !== null) {
|
|
156
|
+
return findRunUatDispatchFromCandidates(
|
|
157
|
+
base,
|
|
158
|
+
milestoneId,
|
|
159
|
+
dbCandidates,
|
|
160
|
+
prefs,
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
} catch (err) {
|
|
164
|
+
logWarning(
|
|
165
|
+
"prompt",
|
|
166
|
+
`checkNeedsRunUat DB lookup failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return findRunUatDispatchFromCandidates(
|
|
171
|
+
base,
|
|
172
|
+
milestoneId,
|
|
173
|
+
fallbackCandidates,
|
|
174
|
+
prefs,
|
|
175
|
+
);
|
|
176
|
+
}
|
|
@@ -1,9 +1,39 @@
|
|
|
1
1
|
const AUDIT_ENV_KEY = "GSD_UOK_AUDIT_UNIFIED";
|
|
2
|
+
const suppressedBasePaths = new Set<string>();
|
|
2
3
|
|
|
3
4
|
export function setUnifiedAuditEnabled(enabled: boolean): void {
|
|
4
5
|
process.env[AUDIT_ENV_KEY] = enabled ? "1" : "0";
|
|
5
6
|
}
|
|
6
7
|
|
|
7
|
-
export function
|
|
8
|
-
|
|
8
|
+
export function setUnifiedAuditSuppressedForBasePath(basePath: string, suppressed: boolean): void {
|
|
9
|
+
if (suppressed) {
|
|
10
|
+
suppressedBasePaths.add(basePath);
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
suppressedBasePaths.delete(basePath);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function isUnifiedAuditEnabled(basePath?: string): boolean {
|
|
17
|
+
if (basePath && suppressedBasePaths.has(basePath)) return false;
|
|
18
|
+
return process.env[AUDIT_ENV_KEY] !== "0";
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function getUnifiedAuditOverride(): boolean | undefined {
|
|
22
|
+
const raw = process.env[AUDIT_ENV_KEY];
|
|
23
|
+
if (raw === "0") return false;
|
|
24
|
+
if (raw === "1") return true;
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function restoreUnifiedAuditOverride(override: boolean | undefined): void {
|
|
29
|
+
if (override === undefined) {
|
|
30
|
+
delete process.env[AUDIT_ENV_KEY];
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
setUnifiedAuditEnabled(override);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function clearUnifiedAuditOverrideForTests(): void {
|
|
37
|
+
delete process.env[AUDIT_ENV_KEY];
|
|
38
|
+
suppressedBasePaths.clear();
|
|
9
39
|
}
|
|
@@ -9,6 +9,7 @@ import { withFileLockSync } from "../file-lock.js";
|
|
|
9
9
|
import { gsdRoot } from "../paths.js";
|
|
10
10
|
import { isDbAvailable, insertAuditEvent } from "../gsd-db.js";
|
|
11
11
|
import { CURRENT_UOK_CONTRACT_VERSION, validateAuditEvent, type AuditEventEnvelope } from "./contracts.js";
|
|
12
|
+
import { isUnifiedAuditEnabled } from "./audit-toggle.js";
|
|
12
13
|
|
|
13
14
|
function auditLogPath(basePath: string): string {
|
|
14
15
|
return join(gsdRoot(basePath), "audit", "events.jsonl");
|
|
@@ -42,6 +43,7 @@ export function buildAuditEnvelope(args: {
|
|
|
42
43
|
export function emitUokAuditEvent(basePath: string, event: AuditEventEnvelope): void {
|
|
43
44
|
// Drop writes from a turn superseded by timeout recovery / cancellation.
|
|
44
45
|
if (isStaleWrite("uok-audit")) return;
|
|
46
|
+
if (!isUnifiedAuditEnabled(basePath)) return;
|
|
45
47
|
const validation = validateAuditEvent(event);
|
|
46
48
|
if (!validation.ok) {
|
|
47
49
|
throw new Error(`Invalid UOK audit event: ${validation.issues.map((issue) => `${issue.path}: ${issue.message}`).join("; ")}`);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { FailureClass, GateResult } from "./contracts.js";
|
|
2
2
|
import { insertGateRun } from "../gsd-db.js";
|
|
3
3
|
import { buildAuditEnvelope, emitUokAuditEvent } from "./audit.js";
|
|
4
|
+
import { isUnifiedAuditEnabled } from "./audit-toggle.js";
|
|
4
5
|
|
|
5
6
|
export interface GateRunnerContext {
|
|
6
7
|
basePath: string;
|
|
@@ -38,6 +39,29 @@ const RETRY_MATRIX: Record<FailureClass, number> = {
|
|
|
38
39
|
unknown: 0,
|
|
39
40
|
};
|
|
40
41
|
|
|
42
|
+
function emitGateAuditIfEnabled(ctx: GateRunnerContext, result: GateResult): void {
|
|
43
|
+
if (!isUnifiedAuditEnabled(ctx.basePath)) return;
|
|
44
|
+
|
|
45
|
+
emitUokAuditEvent(
|
|
46
|
+
ctx.basePath,
|
|
47
|
+
buildAuditEnvelope({
|
|
48
|
+
traceId: ctx.traceId,
|
|
49
|
+
turnId: ctx.turnId,
|
|
50
|
+
category: "gate",
|
|
51
|
+
type: "gate-run",
|
|
52
|
+
payload: {
|
|
53
|
+
gateId: result.gateId,
|
|
54
|
+
gateType: result.gateType,
|
|
55
|
+
outcome: result.outcome,
|
|
56
|
+
failureClass: result.failureClass,
|
|
57
|
+
attempt: result.attempt,
|
|
58
|
+
maxAttempts: result.maxAttempts,
|
|
59
|
+
retryable: result.retryable,
|
|
60
|
+
},
|
|
61
|
+
}),
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
41
65
|
export class UokGateRunner {
|
|
42
66
|
private readonly registry = new Map<string, GateExecutionInput>();
|
|
43
67
|
|
|
@@ -85,24 +109,7 @@ export class UokGateRunner {
|
|
|
85
109
|
evaluatedAt: unknownResult.evaluatedAt,
|
|
86
110
|
});
|
|
87
111
|
|
|
88
|
-
|
|
89
|
-
ctx.basePath,
|
|
90
|
-
buildAuditEnvelope({
|
|
91
|
-
traceId: ctx.traceId,
|
|
92
|
-
turnId: ctx.turnId,
|
|
93
|
-
category: "gate",
|
|
94
|
-
type: "gate-run",
|
|
95
|
-
payload: {
|
|
96
|
-
gateId: unknownResult.gateId,
|
|
97
|
-
gateType: unknownResult.gateType,
|
|
98
|
-
outcome: unknownResult.outcome,
|
|
99
|
-
failureClass: unknownResult.failureClass,
|
|
100
|
-
attempt: unknownResult.attempt,
|
|
101
|
-
maxAttempts: unknownResult.maxAttempts,
|
|
102
|
-
retryable: unknownResult.retryable,
|
|
103
|
-
},
|
|
104
|
-
}),
|
|
105
|
-
);
|
|
112
|
+
emitGateAuditIfEnabled(ctx, unknownResult);
|
|
106
113
|
|
|
107
114
|
return unknownResult;
|
|
108
115
|
}
|
|
@@ -170,24 +177,7 @@ export class UokGateRunner {
|
|
|
170
177
|
evaluatedAt: final.evaluatedAt,
|
|
171
178
|
});
|
|
172
179
|
|
|
173
|
-
|
|
174
|
-
ctx.basePath,
|
|
175
|
-
buildAuditEnvelope({
|
|
176
|
-
traceId: ctx.traceId,
|
|
177
|
-
turnId: ctx.turnId,
|
|
178
|
-
category: "gate",
|
|
179
|
-
type: "gate-run",
|
|
180
|
-
payload: {
|
|
181
|
-
gateId: final.gateId,
|
|
182
|
-
gateType: final.gateType,
|
|
183
|
-
outcome: final.outcome,
|
|
184
|
-
failureClass: final.failureClass,
|
|
185
|
-
attempt: final.attempt,
|
|
186
|
-
maxAttempts: final.maxAttempts,
|
|
187
|
-
retryable: final.retryable,
|
|
188
|
-
},
|
|
189
|
-
}),
|
|
190
|
-
);
|
|
180
|
+
emitGateAuditIfEnabled(ctx, final);
|
|
191
181
|
|
|
192
182
|
if (!retryable) break;
|
|
193
183
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isDbAvailable, upsertTurnGitTransaction } from "../gsd-db.js";
|
|
2
2
|
import type { TurnCloseoutRecord } from "./contracts.js";
|
|
3
3
|
import { buildAuditEnvelope, emitUokAuditEvent } from "./audit.js";
|
|
4
|
+
import { isUnifiedAuditEnabled } from "./audit-toggle.js";
|
|
4
5
|
|
|
5
6
|
export type TurnGitStage = "turn-start" | "stage" | "checkpoint" | "publish" | "record";
|
|
6
7
|
|
|
@@ -34,24 +35,26 @@ export function writeTurnGitTransaction(args: GitTxArgs): void {
|
|
|
34
35
|
updatedAt: new Date().toISOString(),
|
|
35
36
|
});
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
38
|
+
if (isUnifiedAuditEnabled(args.basePath)) {
|
|
39
|
+
emitUokAuditEvent(
|
|
40
|
+
args.basePath,
|
|
41
|
+
buildAuditEnvelope({
|
|
42
|
+
traceId: args.traceId,
|
|
43
|
+
turnId: args.turnId,
|
|
44
|
+
category: "gitops",
|
|
45
|
+
type: `turn-git-${args.stage}`,
|
|
46
|
+
payload: {
|
|
47
|
+
unitType: args.unitType,
|
|
48
|
+
unitId: args.unitId,
|
|
49
|
+
action: args.action,
|
|
50
|
+
push: args.push,
|
|
51
|
+
status: args.status,
|
|
52
|
+
error: args.error,
|
|
53
|
+
...(args.metadata ?? {}),
|
|
54
|
+
},
|
|
55
|
+
}),
|
|
56
|
+
);
|
|
57
|
+
}
|
|
55
58
|
}
|
|
56
59
|
|
|
57
60
|
export function writeTurnCloseoutGitRecord(
|
|
@@ -8,10 +8,16 @@ import type { AutoSession } from "../auto/session.js";
|
|
|
8
8
|
import type { LoopDeps } from "../auto/loop-deps.js";
|
|
9
9
|
import { gsdRoot } from "../paths.js";
|
|
10
10
|
import { buildAuditEnvelope, emitUokAuditEvent } from "./audit.js";
|
|
11
|
-
import {
|
|
12
|
-
|
|
11
|
+
import {
|
|
12
|
+
getUnifiedAuditOverride,
|
|
13
|
+
restoreUnifiedAuditOverride,
|
|
14
|
+
setUnifiedAuditEnabled,
|
|
15
|
+
setUnifiedAuditSuppressedForBasePath,
|
|
16
|
+
} from "./audit-toggle.js";
|
|
17
|
+
import { resolveUokFlags, type UokFlags } from "./flags.js";
|
|
13
18
|
import { createTurnObserver } from "./loop-adapter.js";
|
|
14
19
|
import { incrementLegacyTelemetry } from "../legacy-telemetry.js";
|
|
20
|
+
import { logWarning } from "../workflow-logger.js";
|
|
15
21
|
|
|
16
22
|
interface RunAutoLoopWithUokArgs {
|
|
17
23
|
ctx: ExtensionContext;
|
|
@@ -45,80 +51,195 @@ function writeParityEvent(basePath: string, event: Record<string, unknown>): voi
|
|
|
45
51
|
}
|
|
46
52
|
}
|
|
47
53
|
|
|
54
|
+
type UokKernelPathLabel = "uok-kernel" | "legacy-wrapper" | "legacy-fallback";
|
|
55
|
+
|
|
56
|
+
interface UokKernelRunPlan {
|
|
57
|
+
flags: UokFlags;
|
|
58
|
+
pathLabel: UokKernelPathLabel;
|
|
59
|
+
traceId: string;
|
|
60
|
+
useKernel: boolean;
|
|
61
|
+
}
|
|
62
|
+
|
|
48
63
|
function resolveKernelPathLabel(
|
|
49
|
-
flags:
|
|
50
|
-
):
|
|
64
|
+
flags: UokFlags,
|
|
65
|
+
): UokKernelPathLabel {
|
|
51
66
|
if (flags.legacyFallback) return "legacy-fallback";
|
|
52
67
|
return flags.enabled ? "uok-kernel" : "legacy-wrapper";
|
|
53
68
|
}
|
|
54
69
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
70
|
+
function createUokKernelRunPlan(input: {
|
|
71
|
+
preferences: ReturnType<LoopDeps["loadEffectiveGSDPreferences"]> | undefined;
|
|
72
|
+
autoStartTime?: unknown;
|
|
73
|
+
}): UokKernelRunPlan {
|
|
74
|
+
const flags = resolveUokFlags(input.preferences?.preferences);
|
|
60
75
|
const pathLabel = resolveKernelPathLabel(flags);
|
|
61
|
-
|
|
62
|
-
incrementLegacyTelemetry("legacy.uokFallbackUsed");
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
writeParityEvent(s.basePath, {
|
|
66
|
-
ts: new Date().toISOString(),
|
|
67
|
-
path: pathLabel,
|
|
76
|
+
return {
|
|
68
77
|
flags,
|
|
69
|
-
|
|
70
|
-
|
|
78
|
+
pathLabel,
|
|
79
|
+
traceId: `session:${String(input.autoStartTime || Date.now())}`,
|
|
80
|
+
useKernel: flags.enabled,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
interface KernelAuditStateController {
|
|
85
|
+
apply(enabled: boolean): void;
|
|
86
|
+
restore(): void;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function createKernelAuditStateController(basePath: string): KernelAuditStateController {
|
|
90
|
+
const previousAuditOverride = getUnifiedAuditOverride();
|
|
91
|
+
return {
|
|
92
|
+
apply(enabled): void {
|
|
93
|
+
setUnifiedAuditSuppressedForBasePath(basePath, !enabled);
|
|
94
|
+
setUnifiedAuditEnabled(enabled);
|
|
95
|
+
},
|
|
96
|
+
restore(): void {
|
|
97
|
+
restoreUnifiedAuditOverride(previousAuditOverride);
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
71
101
|
|
|
72
|
-
|
|
102
|
+
function emitKernelEnterAudit(input: {
|
|
103
|
+
basePath: string;
|
|
104
|
+
plan: UokKernelRunPlan;
|
|
105
|
+
sessionId?: string;
|
|
106
|
+
}): boolean {
|
|
107
|
+
if (!input.plan.flags.auditUnified) return true;
|
|
108
|
+
|
|
109
|
+
try {
|
|
73
110
|
emitUokAuditEvent(
|
|
74
|
-
|
|
111
|
+
input.basePath,
|
|
75
112
|
buildAuditEnvelope({
|
|
76
|
-
traceId:
|
|
113
|
+
traceId: input.plan.traceId,
|
|
77
114
|
category: "orchestration",
|
|
78
115
|
type: "uok-kernel-enter",
|
|
79
116
|
payload: {
|
|
80
|
-
flags,
|
|
81
|
-
sessionId:
|
|
117
|
+
flags: input.plan.flags,
|
|
118
|
+
sessionId: input.sessionId,
|
|
82
119
|
},
|
|
83
120
|
}),
|
|
84
121
|
);
|
|
122
|
+
return true;
|
|
123
|
+
} catch (err) {
|
|
124
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
125
|
+
writeParityEvent(input.basePath, {
|
|
126
|
+
ts: new Date().toISOString(),
|
|
127
|
+
path: input.plan.pathLabel,
|
|
128
|
+
flags: input.plan.flags,
|
|
129
|
+
phase: "telemetry-error",
|
|
130
|
+
telemetry: "uok-kernel-enter",
|
|
131
|
+
error: errorMessage,
|
|
132
|
+
});
|
|
133
|
+
logWarning("db", `uok-kernel-enter audit emit failed (non-fatal): ${errorMessage}`);
|
|
134
|
+
return false;
|
|
85
135
|
}
|
|
136
|
+
}
|
|
86
137
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
138
|
+
function decorateLoopDepsForKernel(input: {
|
|
139
|
+
deps: LoopDeps;
|
|
140
|
+
basePath: string;
|
|
141
|
+
plan: UokKernelRunPlan;
|
|
142
|
+
auditHealthy: boolean;
|
|
143
|
+
}): LoopDeps {
|
|
144
|
+
if (!input.plan.useKernel) return input.deps;
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
...input.deps,
|
|
148
|
+
uokObserver: createTurnObserver({
|
|
149
|
+
basePath: input.basePath,
|
|
150
|
+
gitAction: input.plan.flags.gitopsTurnAction,
|
|
151
|
+
gitPush: input.plan.flags.gitopsTurnPush,
|
|
152
|
+
enableAudit: input.plan.flags.auditUnified && input.auditHealthy,
|
|
153
|
+
enableGitops: input.plan.flags.gitops,
|
|
154
|
+
}),
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
async function executeKernelRunPlan(input: {
|
|
159
|
+
plan: UokKernelRunPlan;
|
|
160
|
+
ctx: ExtensionContext;
|
|
161
|
+
pi: ExtensionAPI;
|
|
162
|
+
s: AutoSession;
|
|
163
|
+
deps: LoopDeps;
|
|
164
|
+
kernelDeps: LoopDeps;
|
|
165
|
+
runKernelLoop: RunAutoLoopWithUokArgs["runKernelLoop"];
|
|
166
|
+
runLegacyLoop: RunAutoLoopWithUokArgs["runLegacyLoop"];
|
|
167
|
+
}): Promise<void> {
|
|
168
|
+
if (input.plan.useKernel) {
|
|
169
|
+
await input.runKernelLoop(input.ctx, input.pi, input.s, input.kernelDeps);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
await input.runLegacyLoop(input.ctx, input.pi, input.s, input.deps);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export async function runAutoLoopWithUok(args: RunAutoLoopWithUokArgs): Promise<void> {
|
|
176
|
+
const { ctx, pi, s, deps, runKernelLoop, runLegacyLoop } = args;
|
|
177
|
+
const auditState = createKernelAuditStateController(s.basePath);
|
|
178
|
+
let plan: UokKernelRunPlan | null = null;
|
|
99
179
|
|
|
100
180
|
try {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
181
|
+
plan = createUokKernelRunPlan({
|
|
182
|
+
preferences: deps.loadEffectiveGSDPreferences(),
|
|
183
|
+
autoStartTime: s.autoStartTime,
|
|
184
|
+
});
|
|
185
|
+
auditState.apply(plan.flags.auditUnified);
|
|
186
|
+
|
|
187
|
+
if (plan.pathLabel !== "uok-kernel") {
|
|
188
|
+
incrementLegacyTelemetry("legacy.uokFallbackUsed");
|
|
105
189
|
}
|
|
190
|
+
|
|
106
191
|
writeParityEvent(s.basePath, {
|
|
107
192
|
ts: new Date().toISOString(),
|
|
108
|
-
path: pathLabel,
|
|
109
|
-
flags,
|
|
110
|
-
phase: "
|
|
111
|
-
status: "ok",
|
|
193
|
+
path: plan.pathLabel,
|
|
194
|
+
flags: plan.flags,
|
|
195
|
+
phase: "enter",
|
|
112
196
|
});
|
|
113
|
-
|
|
197
|
+
|
|
198
|
+
const auditHealthy = emitKernelEnterAudit({
|
|
199
|
+
basePath: s.basePath,
|
|
200
|
+
plan,
|
|
201
|
+
sessionId: ctx.sessionManager?.getSessionId?.(),
|
|
202
|
+
});
|
|
203
|
+
auditState.apply(plan.flags.auditUnified && auditHealthy);
|
|
204
|
+
|
|
205
|
+
const kernelDeps = decorateLoopDepsForKernel({
|
|
206
|
+
deps,
|
|
207
|
+
basePath: s.basePath,
|
|
208
|
+
plan,
|
|
209
|
+
auditHealthy,
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
await executeKernelRunPlan({
|
|
213
|
+
plan,
|
|
214
|
+
ctx,
|
|
215
|
+
pi,
|
|
216
|
+
s,
|
|
217
|
+
deps,
|
|
218
|
+
kernelDeps,
|
|
219
|
+
runKernelLoop,
|
|
220
|
+
runLegacyLoop,
|
|
221
|
+
});
|
|
222
|
+
|
|
114
223
|
writeParityEvent(s.basePath, {
|
|
115
224
|
ts: new Date().toISOString(),
|
|
116
|
-
path: pathLabel,
|
|
117
|
-
flags,
|
|
225
|
+
path: plan.pathLabel,
|
|
226
|
+
flags: plan.flags,
|
|
118
227
|
phase: "exit",
|
|
119
|
-
status: "
|
|
120
|
-
error: err instanceof Error ? err.message : String(err),
|
|
228
|
+
status: "ok",
|
|
121
229
|
});
|
|
230
|
+
} catch (err) {
|
|
231
|
+
if (plan) {
|
|
232
|
+
writeParityEvent(s.basePath, {
|
|
233
|
+
ts: new Date().toISOString(),
|
|
234
|
+
path: plan.pathLabel,
|
|
235
|
+
flags: plan.flags,
|
|
236
|
+
phase: "exit",
|
|
237
|
+
status: "error",
|
|
238
|
+
error: err instanceof Error ? err.message : String(err),
|
|
239
|
+
});
|
|
240
|
+
}
|
|
122
241
|
throw err;
|
|
242
|
+
} finally {
|
|
243
|
+
auditState.restore();
|
|
123
244
|
}
|
|
124
245
|
}
|