patchwarden 0.6.4 → 1.5.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/README.en.md +54 -20
- package/README.md +48 -21
- package/dist/agents/agentRouter.d.ts +40 -0
- package/dist/agents/agentRouter.js +95 -0
- package/dist/config.d.ts +1 -1
- package/dist/config.js +6 -2
- package/dist/controlCenter.js +212 -3
- package/dist/direct/directSessionStore.d.ts +2 -0
- package/dist/direct/directVerification.js +7 -0
- package/dist/doctor.js +32 -1
- package/dist/goal/acceptanceEngine.d.ts +62 -0
- package/dist/goal/acceptanceEngine.js +103 -0
- package/dist/goal/acceptanceTemplate.d.ts +10 -0
- package/dist/goal/acceptanceTemplate.js +104 -0
- package/dist/goal/goalGraph.d.ts +58 -0
- package/dist/goal/goalGraph.js +189 -0
- package/dist/goal/goalProgress.d.ts +81 -0
- package/dist/goal/goalProgress.js +216 -0
- package/dist/goal/goalStatus.d.ts +60 -0
- package/dist/goal/goalStatus.js +137 -0
- package/dist/goal/goalStore.d.ts +79 -0
- package/dist/goal/goalStore.js +211 -0
- package/dist/goal/handoffExport.d.ts +34 -0
- package/dist/goal/handoffExport.js +183 -0
- package/dist/goal/subgoalSync.d.ts +40 -0
- package/dist/goal/subgoalSync.js +72 -0
- package/dist/goal/worktreeManager.d.ts +96 -0
- package/dist/goal/worktreeManager.js +292 -0
- package/dist/logging.d.ts +44 -0
- package/dist/logging.js +68 -0
- package/dist/policy/projectPolicy.d.ts +55 -0
- package/dist/policy/projectPolicy.js +286 -0
- package/dist/release/releaseGate.d.ts +99 -0
- package/dist/release/releaseGate.js +475 -0
- package/dist/runner/postTaskCleanup.d.ts +13 -0
- package/dist/runner/postTaskCleanup.js +147 -0
- package/dist/runner/runTask.js +50 -10
- package/dist/security/discoveryTokenStore.d.ts +62 -0
- package/dist/security/discoveryTokenStore.js +100 -0
- package/dist/security/toolInvocationGuard.d.ts +35 -0
- package/dist/security/toolInvocationGuard.js +153 -0
- package/dist/smoke-test.js +18 -10
- package/dist/taskRuntime.d.ts +17 -0
- package/dist/test/unit/acceptance-engine.test.d.ts +1 -0
- package/dist/test/unit/acceptance-engine.test.js +228 -0
- package/dist/test/unit/agent-router.test.d.ts +1 -0
- package/dist/test/unit/agent-router.test.js +287 -0
- package/dist/test/unit/audit-checks.test.d.ts +1 -0
- package/dist/test/unit/audit-checks.test.js +350 -0
- package/dist/test/unit/diagnose-task.test.d.ts +1 -0
- package/dist/test/unit/diagnose-task.test.js +457 -0
- package/dist/test/unit/discovery-token-store.test.d.ts +1 -0
- package/dist/test/unit/discovery-token-store.test.js +139 -0
- package/dist/test/unit/evidence-pack.test.d.ts +1 -0
- package/dist/test/unit/evidence-pack.test.js +130 -0
- package/dist/test/unit/goal-graph.test.d.ts +1 -0
- package/dist/test/unit/goal-graph.test.js +298 -0
- package/dist/test/unit/goal-progress.test.d.ts +1 -0
- package/dist/test/unit/goal-progress.test.js +381 -0
- package/dist/test/unit/goal-status.test.d.ts +1 -0
- package/dist/test/unit/goal-status.test.js +215 -0
- package/dist/test/unit/goal-store.test.d.ts +1 -0
- package/dist/test/unit/goal-store.test.js +253 -0
- package/dist/test/unit/goal-subgoal-task.test.d.ts +1 -0
- package/dist/test/unit/goal-subgoal-task.test.js +55 -0
- package/dist/test/unit/goal-tools-registry.test.d.ts +1 -0
- package/dist/test/unit/goal-tools-registry.test.js +190 -0
- package/dist/test/unit/handoff-export.test.d.ts +1 -0
- package/dist/test/unit/handoff-export.test.js +263 -0
- package/dist/test/unit/invoke-discovered-tool.test.d.ts +1 -0
- package/dist/test/unit/invoke-discovered-tool.test.js +167 -0
- package/dist/test/unit/logging.test.js +127 -5
- package/dist/test/unit/post-task-cleanup.test.d.ts +1 -0
- package/dist/test/unit/post-task-cleanup.test.js +48 -0
- package/dist/test/unit/project-policy-release-mode.test.d.ts +1 -0
- package/dist/test/unit/project-policy-release-mode.test.js +125 -0
- package/dist/test/unit/reconcile-tasks.test.d.ts +1 -0
- package/dist/test/unit/reconcile-tasks.test.js +456 -0
- package/dist/test/unit/release-gate.test.d.ts +1 -0
- package/dist/test/unit/release-gate.test.js +242 -0
- package/dist/test/unit/run-task-loop.test.d.ts +1 -0
- package/dist/test/unit/run-task-loop.test.js +380 -0
- package/dist/test/unit/safe-views.test.d.ts +1 -0
- package/dist/test/unit/safe-views.test.js +171 -0
- package/dist/test/unit/schema-drift-check.test.d.ts +1 -0
- package/dist/test/unit/schema-drift-check.test.js +176 -0
- package/dist/test/unit/subgoal-sync.test.d.ts +1 -0
- package/dist/test/unit/subgoal-sync.test.js +183 -0
- package/dist/test/unit/tool-invocation-guard.test.d.ts +1 -0
- package/dist/test/unit/tool-invocation-guard.test.js +432 -0
- package/dist/test/unit/tool-usage-stats.test.d.ts +1 -0
- package/dist/test/unit/tool-usage-stats.test.js +300 -0
- package/dist/test/unit/toolSearch.test.d.ts +1 -0
- package/dist/test/unit/toolSearch.test.js +571 -0
- package/dist/test/unit/worktree-manager.test.d.ts +1 -0
- package/dist/test/unit/worktree-manager.test.js +176 -0
- package/dist/tools/auditTask.d.ts +103 -1
- package/dist/tools/auditTask.js +461 -8
- package/dist/tools/cancelTask.js +1 -1
- package/dist/tools/checkReleaseGate.d.ts +21 -0
- package/dist/tools/checkReleaseGate.js +22 -0
- package/dist/tools/createTask.d.ts +18 -2
- package/dist/tools/createTask.js +29 -1
- package/dist/tools/diagnoseTask.d.ts +45 -0
- package/dist/tools/diagnoseTask.js +347 -0
- package/dist/tools/discardWorktree.d.ts +24 -0
- package/dist/tools/discardWorktree.js +27 -0
- package/dist/tools/discoverTools.d.ts +11 -0
- package/dist/tools/discoverTools.js +39 -0
- package/dist/tools/evidencePack.d.ts +39 -0
- package/dist/tools/evidencePack.js +168 -0
- package/dist/tools/explainTool.d.ts +11 -0
- package/dist/tools/explainTool.js +21 -0
- package/dist/tools/getTaskSummary.js +2 -1
- package/dist/tools/goalSubgoalTask.d.ts +51 -0
- package/dist/tools/goalSubgoalTask.js +110 -0
- package/dist/tools/healthCheck.d.ts +1 -0
- package/dist/tools/healthCheck.js +5 -1
- package/dist/tools/invokeDiscoveredTool.d.ts +37 -0
- package/dist/tools/invokeDiscoveredTool.js +112 -0
- package/dist/tools/listTasks.d.ts +3 -1
- package/dist/tools/listTasks.js +14 -1
- package/dist/tools/mergeWorktree.d.ts +24 -0
- package/dist/tools/mergeWorktree.js +27 -0
- package/dist/tools/recommendAgentForTask.d.ts +19 -0
- package/dist/tools/recommendAgentForTask.js +56 -0
- package/dist/tools/reconcileTasks.d.ts +41 -0
- package/dist/tools/reconcileTasks.js +352 -0
- package/dist/tools/registry.js +926 -2
- package/dist/tools/releaseMode.d.ts +50 -0
- package/dist/tools/releaseMode.js +370 -0
- package/dist/tools/runDirectVerificationBundle.d.ts +26 -0
- package/dist/tools/runDirectVerificationBundle.js +64 -0
- package/dist/tools/runTaskLoop.d.ts +57 -0
- package/dist/tools/runTaskLoop.js +417 -0
- package/dist/tools/runVerification.d.ts +4 -0
- package/dist/tools/runVerification.js +4 -0
- package/dist/tools/safeStatus.d.ts +31 -1
- package/dist/tools/safeStatus.js +43 -1
- package/dist/tools/safeViews.d.ts +262 -0
- package/dist/tools/safeViews.js +252 -0
- package/dist/tools/schemaDriftCheck.d.ts +46 -0
- package/dist/tools/schemaDriftCheck.js +80 -0
- package/dist/tools/taskLineage.d.ts +91 -0
- package/dist/tools/taskLineage.js +175 -0
- package/dist/tools/toolCatalog.d.ts +4 -3
- package/dist/tools/toolCatalog.js +39 -11
- package/dist/tools/toolRegistry.d.ts +61 -0
- package/dist/tools/toolRegistry.js +834 -0
- package/dist/tools/toolSearch.d.ts +110 -0
- package/dist/tools/toolSearch.js +331 -0
- package/dist/tools/toolUsageStats.d.ts +41 -0
- package/dist/tools/toolUsageStats.js +116 -0
- package/dist/tools/waitForTask.js +1 -0
- package/dist/version.d.ts +2 -2
- package/dist/version.js +2 -2
- package/dist/watcherStatus.d.ts +29 -0
- package/dist/watcherStatus.js +92 -1
- package/docs/chatgpt-usage.md +31 -0
- package/docs/control-center/README.md +9 -0
- package/package.json +3 -2
- package/scripts/checks/control-center-smoke.js +87 -0
- package/scripts/checks/control-smoke.js +2 -2
- package/scripts/checks/doctor-smoke.js +1 -0
- package/scripts/checks/lifecycle-smoke.js +13 -9
- package/scripts/checks/mcp-manifest-check.js +65 -6
- package/scripts/checks/mcp-smoke.js +60 -9
- package/scripts/checks/watcher-supervisor-smoke.js +2 -2
- package/src/agents/agentRouter.ts +149 -0
- package/src/config.ts +9 -3
- package/src/controlCenter.ts +215 -4
- package/src/direct/directSessionStore.ts +2 -0
- package/src/direct/directVerification.ts +7 -0
- package/src/doctor.ts +36 -1
- package/src/goal/acceptanceEngine.ts +160 -0
- package/src/goal/acceptanceTemplate.ts +121 -0
- package/src/goal/goalGraph.ts +225 -0
- package/src/goal/goalProgress.ts +301 -0
- package/src/goal/goalStatus.ts +234 -0
- package/src/goal/goalStore.ts +306 -0
- package/src/goal/handoffExport.ts +211 -0
- package/src/goal/subgoalSync.ts +82 -0
- package/src/goal/worktreeManager.ts +404 -0
- package/src/logging.ts +91 -0
- package/src/policy/projectPolicy.ts +344 -0
- package/src/release/releaseGate.ts +567 -0
- package/src/runner/postTaskCleanup.ts +154 -0
- package/src/runner/runTask.ts +49 -10
- package/src/security/discoveryTokenStore.ts +157 -0
- package/src/security/toolInvocationGuard.ts +251 -0
- package/src/smoke-test.ts +15 -7
- package/src/taskRuntime.ts +17 -0
- package/src/test/unit/acceptance-engine.test.ts +261 -0
- package/src/test/unit/agent-router.test.ts +342 -0
- package/src/test/unit/audit-checks.test.ts +567 -0
- package/src/test/unit/diagnose-task.test.ts +544 -0
- package/src/test/unit/discovery-token-store.test.ts +181 -0
- package/src/test/unit/evidence-pack.test.ts +142 -0
- package/src/test/unit/goal-graph.test.ts +347 -0
- package/src/test/unit/goal-progress.test.ts +538 -0
- package/src/test/unit/goal-status.test.ts +270 -0
- package/src/test/unit/goal-store.test.ts +318 -0
- package/src/test/unit/goal-subgoal-task.test.ts +72 -0
- package/src/test/unit/goal-tools-registry.test.ts +243 -0
- package/src/test/unit/handoff-export.test.ts +295 -0
- package/src/test/unit/invoke-discovered-tool.test.ts +216 -0
- package/src/test/unit/logging.test.ts +177 -5
- package/src/test/unit/post-task-cleanup.test.ts +53 -0
- package/src/test/unit/project-policy-release-mode.test.ts +156 -0
- package/src/test/unit/reconcile-tasks.test.ts +551 -0
- package/src/test/unit/release-gate.test.ts +314 -0
- package/src/test/unit/run-task-loop.test.ts +425 -0
- package/src/test/unit/safe-views.test.ts +184 -0
- package/src/test/unit/schema-drift-check.test.ts +260 -0
- package/src/test/unit/subgoal-sync.test.ts +236 -0
- package/src/test/unit/tool-invocation-guard.test.ts +542 -0
- package/src/test/unit/tool-usage-stats.test.ts +384 -0
- package/src/test/unit/toolSearch.test.ts +756 -0
- package/src/test/unit/worktree-manager.test.ts +247 -0
- package/src/tools/auditTask.ts +831 -402
- package/src/tools/cancelTask.ts +1 -1
- package/src/tools/checkReleaseGate.ts +45 -0
- package/src/tools/createTask.ts +64 -6
- package/src/tools/diagnoseTask.ts +460 -0
- package/src/tools/discardWorktree.ts +42 -0
- package/src/tools/discoverTools.ts +51 -0
- package/src/tools/evidencePack.ts +205 -0
- package/src/tools/explainTool.ts +26 -0
- package/src/tools/getTaskSummary.ts +2 -1
- package/src/tools/goalSubgoalTask.ts +170 -0
- package/src/tools/healthCheck.ts +4 -1
- package/src/tools/invokeDiscoveredTool.ts +163 -0
- package/src/tools/listTasks.ts +16 -2
- package/src/tools/listWorkspace.ts +71 -71
- package/src/tools/mergeWorktree.ts +42 -0
- package/src/tools/recommendAgentForTask.ts +79 -0
- package/src/tools/reconcileTasks.ts +464 -0
- package/src/tools/registry.ts +1093 -73
- package/src/tools/releaseMode.ts +450 -0
- package/src/tools/runDirectVerificationBundle.ts +98 -0
- package/src/tools/runTaskLoop.ts +526 -0
- package/src/tools/runVerification.ts +8 -0
- package/src/tools/safeStatus.ts +73 -2
- package/src/tools/safeViews.ts +273 -0
- package/src/tools/schemaDriftCheck.ts +120 -0
- package/src/tools/taskLineage.ts +300 -0
- package/src/tools/toolCatalog.ts +40 -11
- package/src/tools/toolRegistry.ts +896 -0
- package/src/tools/toolSearch.ts +464 -0
- package/src/tools/toolUsageStats.ts +151 -0
- package/src/tools/waitForTask.ts +1 -0
- package/src/version.ts +2 -2
- package/src/watcherStatus.ts +97 -1
- package/ui/pages/dashboard.html +143 -2
package/src/watcherStatus.ts
CHANGED
|
@@ -191,9 +191,105 @@ export function derivePendingReason(
|
|
|
191
191
|
if (watcher.status === "unreadable") return "queued_but_watcher_unreadable";
|
|
192
192
|
return "queued_waiting_for_watcher";
|
|
193
193
|
}
|
|
194
|
-
if (task.status !== "running") return null;
|
|
194
|
+
if (task.status !== "running" && task.status !== "collecting_artifacts") return null;
|
|
195
195
|
if (task.phase === "executing_agent") return "agent_running";
|
|
196
196
|
if (task.phase === "running_tests") return "verification_running";
|
|
197
197
|
if (task.phase === "collecting_artifacts") return "collecting_artifacts";
|
|
198
198
|
return "preparing";
|
|
199
199
|
}
|
|
200
|
+
|
|
201
|
+
// ── v0.7.0: Watcher ownership helpers ─────────────────────────────
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Read the current watcher's instance_id from the heartbeat file.
|
|
205
|
+
* Returns null when the heartbeat is missing or unreadable.
|
|
206
|
+
*
|
|
207
|
+
* This is the source of truth for "which watcher is currently alive".
|
|
208
|
+
* Tasks whose runtime.watcher_instance_id differs from this value are
|
|
209
|
+
* considered orphaned by the diagnosis layer.
|
|
210
|
+
*/
|
|
211
|
+
export function readWatcherInstanceId(
|
|
212
|
+
config: PatchWardenConfig = getConfig()
|
|
213
|
+
): string | null {
|
|
214
|
+
const heartbeatPath = getWatcherHeartbeatPath(config);
|
|
215
|
+
if (!existsSync(heartbeatPath)) return null;
|
|
216
|
+
try {
|
|
217
|
+
const raw = readFileSync(heartbeatPath, "utf-8");
|
|
218
|
+
const data = JSON.parse(raw.charCodeAt(0) === 0xfeff ? raw.slice(1) : raw);
|
|
219
|
+
return typeof data.instance_id === "string" ? data.instance_id : null;
|
|
220
|
+
} catch {
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* v0.7.0: Determine whether the current watcher still owns a task.
|
|
227
|
+
*
|
|
228
|
+
* Ownership is established by comparing the watcher_instance_id recorded in
|
|
229
|
+
* the task's runtime.json with the instance_id of the currently alive
|
|
230
|
+
* watcher. A task is considered "owned" only when:
|
|
231
|
+
* - the current watcher heartbeat is healthy, AND
|
|
232
|
+
* - the task runtime recorded a watcher_instance_id, AND
|
|
233
|
+
* - both instance IDs match.
|
|
234
|
+
*
|
|
235
|
+
* If the task has no recorded watcher_instance_id (legacy tasks created
|
|
236
|
+
* before v0.7.0), ownership cannot be confirmed and this returns false.
|
|
237
|
+
* The diagnosis layer treats "no owner" as a stale signal, not as active.
|
|
238
|
+
*/
|
|
239
|
+
export function isWatcherOwningTask(
|
|
240
|
+
taskDir: string,
|
|
241
|
+
config: PatchWardenConfig = getConfig()
|
|
242
|
+
): { owned: boolean; reason: "owned" | "no_runtime_record" | "watcher_missing" | "instance_mismatch" | "watcher_unhealthy"; task_watcher_instance_id: string | null; current_watcher_instance_id: string | null } {
|
|
243
|
+
const runtimePath = join(taskDir, "runtime.json");
|
|
244
|
+
let taskWatcherInstanceId: string | null = null;
|
|
245
|
+
if (existsSync(runtimePath)) {
|
|
246
|
+
try {
|
|
247
|
+
const runtime = JSON.parse(readFileSync(runtimePath, "utf-8"));
|
|
248
|
+
if (typeof runtime.watcher_instance_id === "string") {
|
|
249
|
+
taskWatcherInstanceId = runtime.watcher_instance_id;
|
|
250
|
+
}
|
|
251
|
+
} catch {
|
|
252
|
+
// corrupted runtime — treat as no record
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
if (!taskWatcherInstanceId) {
|
|
256
|
+
return {
|
|
257
|
+
owned: false,
|
|
258
|
+
reason: "no_runtime_record",
|
|
259
|
+
task_watcher_instance_id: null,
|
|
260
|
+
current_watcher_instance_id: null,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
const watcher = readWatcherStatus(config);
|
|
264
|
+
if (watcher.status !== "healthy") {
|
|
265
|
+
return {
|
|
266
|
+
owned: false,
|
|
267
|
+
reason: watcher.status === "missing" ? "watcher_missing" : "watcher_unhealthy",
|
|
268
|
+
task_watcher_instance_id: taskWatcherInstanceId,
|
|
269
|
+
current_watcher_instance_id: watcher.instance_id,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
const currentInstanceId = watcher.instance_id;
|
|
273
|
+
if (!currentInstanceId) {
|
|
274
|
+
return {
|
|
275
|
+
owned: false,
|
|
276
|
+
reason: "watcher_missing",
|
|
277
|
+
task_watcher_instance_id: taskWatcherInstanceId,
|
|
278
|
+
current_watcher_instance_id: null,
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
if (currentInstanceId !== taskWatcherInstanceId) {
|
|
282
|
+
return {
|
|
283
|
+
owned: false,
|
|
284
|
+
reason: "instance_mismatch",
|
|
285
|
+
task_watcher_instance_id: taskWatcherInstanceId,
|
|
286
|
+
current_watcher_instance_id: currentInstanceId,
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
return {
|
|
290
|
+
owned: true,
|
|
291
|
+
reason: "owned",
|
|
292
|
+
task_watcher_instance_id: taskWatcherInstanceId,
|
|
293
|
+
current_watcher_instance_id: currentInstanceId,
|
|
294
|
+
};
|
|
295
|
+
}
|
package/ui/pages/dashboard.html
CHANGED
|
@@ -304,6 +304,38 @@ html.dark {
|
|
|
304
304
|
<div id="suggestions-body" class="px-4 py-2"></div>
|
|
305
305
|
</div>
|
|
306
306
|
|
|
307
|
+
<!-- ===== V1.5 RELEASE / POLICY / LINEAGE / EVIDENCE OVERVIEW ===== -->
|
|
308
|
+
<div class="grid grid-cols-1 lg:grid-cols-4 gap-4 mb-6">
|
|
309
|
+
<div class="rounded-lg" style="background-color: var(--pw-bg-surface); border: 1px solid var(--pw-border);">
|
|
310
|
+
<div class="flex items-center justify-between px-4 py-3" style="border-bottom: 1px solid var(--pw-border);">
|
|
311
|
+
<h2 class="text-sm font-semibold truncate" style="color: var(--pw-text-primary);">Lineage</h2>
|
|
312
|
+
<span id="lineage-count" class="text-xs whitespace-nowrap" style="color: var(--pw-text-tertiary);">...</span>
|
|
313
|
+
</div>
|
|
314
|
+
<div id="lineage-overview-body" class="px-4 py-3 text-sm" style="color: var(--pw-text-tertiary);">Loading</div>
|
|
315
|
+
</div>
|
|
316
|
+
<div class="rounded-lg" style="background-color: var(--pw-bg-surface); border: 1px solid var(--pw-border);">
|
|
317
|
+
<div class="flex items-center justify-between px-4 py-3" style="border-bottom: 1px solid var(--pw-border);">
|
|
318
|
+
<h2 class="text-sm font-semibold truncate" style="color: var(--pw-text-primary);">Project Policy</h2>
|
|
319
|
+
<span id="policy-status" class="text-xs whitespace-nowrap" style="color: var(--pw-text-tertiary);">...</span>
|
|
320
|
+
</div>
|
|
321
|
+
<div id="policy-overview-body" class="px-4 py-3 text-sm" style="color: var(--pw-text-tertiary);">Loading</div>
|
|
322
|
+
</div>
|
|
323
|
+
<div class="rounded-lg" style="background-color: var(--pw-bg-surface); border: 1px solid var(--pw-border);">
|
|
324
|
+
<div class="flex items-center justify-between px-4 py-3" style="border-bottom: 1px solid var(--pw-border);">
|
|
325
|
+
<h2 class="text-sm font-semibold truncate" style="color: var(--pw-text-primary);">Release</h2>
|
|
326
|
+
<span id="release-status" class="text-xs whitespace-nowrap" style="color: var(--pw-text-tertiary);">...</span>
|
|
327
|
+
</div>
|
|
328
|
+
<div id="release-overview-body" class="px-4 py-3 text-sm" style="color: var(--pw-text-tertiary);">Loading</div>
|
|
329
|
+
</div>
|
|
330
|
+
<div id="evidence-pack-card" class="rounded-lg" style="background-color: var(--pw-bg-surface); border: 1px solid var(--pw-border);">
|
|
331
|
+
<div class="flex items-center justify-between px-4 py-3" style="border-bottom: 1px solid var(--pw-border);">
|
|
332
|
+
<h2 class="text-sm font-semibold truncate" style="color: var(--pw-text-primary);">Evidence Pack</h2>
|
|
333
|
+
<span id="evidence-pack-status" class="text-xs whitespace-nowrap" style="color: var(--pw-text-tertiary);">...</span>
|
|
334
|
+
</div>
|
|
335
|
+
<div id="evidence-pack-overview-body" class="px-4 py-3 text-sm" style="color: var(--pw-text-tertiary);">Loading</div>
|
|
336
|
+
</div>
|
|
337
|
+
</div>
|
|
338
|
+
|
|
307
339
|
<!-- ===== TWO-COLUMN LAYOUT ===== -->
|
|
308
340
|
<div class="grid grid-cols-1 lg:grid-cols-5 gap-4 mb-6">
|
|
309
341
|
|
|
@@ -1027,6 +1059,115 @@ html.dark {
|
|
|
1027
1059
|
+ '</details>';
|
|
1028
1060
|
}
|
|
1029
1061
|
|
|
1062
|
+
// ---------- V1.5 panels ----------
|
|
1063
|
+
async function refreshLineages() {
|
|
1064
|
+
const body = $('lineage-overview-body');
|
|
1065
|
+
const count = $('lineage-count');
|
|
1066
|
+
if (!body) return;
|
|
1067
|
+
try {
|
|
1068
|
+
const data = await fetchJson('/api/lineages');
|
|
1069
|
+
const lineages = Array.isArray(data.lineages) ? data.lineages : [];
|
|
1070
|
+
if (count) count.textContent = String(data.total || lineages.length);
|
|
1071
|
+
if (!lineages.length) {
|
|
1072
|
+
body.innerHTML = '<div class="text-xs" style="color: var(--pw-text-tertiary);">No loop lineage yet</div>';
|
|
1073
|
+
return;
|
|
1074
|
+
}
|
|
1075
|
+
const top = lineages[0];
|
|
1076
|
+
const directSessions = top.tasks && Array.isArray(top.tasks.direct_sessions) ? top.tasks.direct_sessions : [];
|
|
1077
|
+
const direct = directSessions.length ? directSessions[0] : null;
|
|
1078
|
+
const worktree = top.worktree || {};
|
|
1079
|
+
const directStatus = direct
|
|
1080
|
+
? ((direct.status || 'unknown') + ' / audit ' + (direct.audit_decision || 'not_run'))
|
|
1081
|
+
: 'not run';
|
|
1082
|
+
body.innerHTML =
|
|
1083
|
+
'<div class="flex items-center justify-between gap-2 mb-2">'
|
|
1084
|
+
+ '<span class="text-xs truncate" style="color: var(--pw-text-primary); font-family: var(--pw-font-mono);" title="' + escapeHtml(top.lineage_id || '') + '">' + escapeHtml(shortId(top.lineage_id)) + '</span>'
|
|
1085
|
+
+ badgeHtml(top.stop_reason || 'unknown', statusKind(top.final_status))
|
|
1086
|
+
+ '</div>'
|
|
1087
|
+
+ '<div class="text-xs truncate mb-1" style="color: var(--pw-text-secondary);" title="' + escapeHtml(top.goal || '') + '">' + escapeHtml(top.goal || 'No goal') + '</div>'
|
|
1088
|
+
+ '<div class="text-xs truncate mb-1" style="color: var(--pw-text-tertiary);">Isolation: ' + escapeHtml(worktree.isolation_mode || 'current_repo') + '</div>'
|
|
1089
|
+
+ '<div class="text-xs truncate mb-1" style="color: var(--pw-text-tertiary);" title="' + escapeHtml(direct && direct.session_id ? direct.session_id : '') + '">Direct: ' + escapeHtml(directStatus) + '</div>'
|
|
1090
|
+
+ '<div class="text-xs" style="color: var(--pw-text-tertiary);">Next: ' + escapeHtml(top.next_action || 'none') + '</div>';
|
|
1091
|
+
} catch (err) {
|
|
1092
|
+
if (count) count.textContent = 'error';
|
|
1093
|
+
body.innerHTML = '<div class="text-xs" style="color: var(--pw-state-error);">' + escapeHtml(err.message) + '</div>';
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
async function refreshProjectPolicy() {
|
|
1098
|
+
const body = $('policy-overview-body');
|
|
1099
|
+
const status = $('policy-status');
|
|
1100
|
+
if (!body) return;
|
|
1101
|
+
try {
|
|
1102
|
+
const data = await fetchJson('/api/project-policy?repo_path=.');
|
|
1103
|
+
const valid = data && data.valid !== false;
|
|
1104
|
+
if (status) status.textContent = valid ? 'valid' : 'issues';
|
|
1105
|
+
const issueCount = Array.isArray(data.issues) ? data.issues.length : 0;
|
|
1106
|
+
const policy = data.effective_policy || {};
|
|
1107
|
+
const release = (policy.release_mode || {});
|
|
1108
|
+
body.innerHTML =
|
|
1109
|
+
'<div class="flex items-center justify-between gap-2 mb-2">'
|
|
1110
|
+
+ '<span class="text-xs" style="color: var(--pw-text-secondary);">policy file</span>'
|
|
1111
|
+
+ badgeHtml(data.exists ? 'present' : 'defaults', data.exists ? 'success' : 'warning')
|
|
1112
|
+
+ '</div>'
|
|
1113
|
+
+ '<div class="text-xs mb-1" style="color: var(--pw-text-tertiary);">issues: ' + issueCount + '</div>'
|
|
1114
|
+
+ '<div class="text-xs truncate" style="color: var(--pw-text-tertiary);" title="' + escapeHtml(release.version_source || '') + '">version: ' + escapeHtml(release.version_source || 'package.json') + '</div>';
|
|
1115
|
+
} catch (err) {
|
|
1116
|
+
if (status) status.textContent = 'error';
|
|
1117
|
+
body.innerHTML = '<div class="text-xs" style="color: var(--pw-state-error);">' + escapeHtml(err.message) + '</div>';
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
async function refreshReleaseStatus() {
|
|
1122
|
+
const body = $('release-overview-body');
|
|
1123
|
+
const status = $('release-status');
|
|
1124
|
+
if (!body) return;
|
|
1125
|
+
try {
|
|
1126
|
+
const data = await fetchJson('/api/release/status?repo_path=.');
|
|
1127
|
+
const ready = data && data.policy_valid && data.release_readiness && data.release_readiness.version_consistent !== false;
|
|
1128
|
+
if (status) status.textContent = ready ? 'ready' : 'blocked';
|
|
1129
|
+
const readiness = data.release_readiness || {};
|
|
1130
|
+
const commands = Array.isArray(readiness.required_commands) ? readiness.required_commands : [];
|
|
1131
|
+
const blocked = commands.filter(function (entry) { return !entry.allowed; }).length;
|
|
1132
|
+
body.innerHTML =
|
|
1133
|
+
'<div class="flex items-center justify-between gap-2 mb-2">'
|
|
1134
|
+
+ '<span class="text-xs" style="color: var(--pw-text-secondary);">version</span>'
|
|
1135
|
+
+ '<span class="text-xs" style="color: var(--pw-text-primary); font-family: var(--pw-font-mono);">' + escapeHtml(readiness.version || 'unknown') + '</span>'
|
|
1136
|
+
+ '</div>'
|
|
1137
|
+
+ '<div class="text-xs mb-1" style="color: var(--pw-text-tertiary);">commands blocked: ' + blocked + ' / ' + commands.length + '</div>'
|
|
1138
|
+
+ '<div class="text-xs" style="color: var(--pw-text-tertiary);">' + escapeHtml(data.next_action || '') + '</div>';
|
|
1139
|
+
} catch (err) {
|
|
1140
|
+
if (status) status.textContent = 'error';
|
|
1141
|
+
body.innerHTML = '<div class="text-xs" style="color: var(--pw-state-error);">' + escapeHtml(err.message) + '</div>';
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
async function refreshEvidencePacks() {
|
|
1146
|
+
const body = $('evidence-pack-overview-body');
|
|
1147
|
+
const status = $('evidence-pack-status');
|
|
1148
|
+
if (!body) return;
|
|
1149
|
+
try {
|
|
1150
|
+
const data = await fetchJson('/api/evidence-packs');
|
|
1151
|
+
const packs = Array.isArray(data.evidence_packs) ? data.evidence_packs : [];
|
|
1152
|
+
if (status) status.textContent = String(data.total || packs.length);
|
|
1153
|
+
if (!packs.length) {
|
|
1154
|
+
body.innerHTML = '<div class="text-xs" style="color: var(--pw-text-tertiary);">No exported evidence pack yet</div>';
|
|
1155
|
+
return;
|
|
1156
|
+
}
|
|
1157
|
+
const top = packs[0];
|
|
1158
|
+
body.innerHTML =
|
|
1159
|
+
'<div class="flex items-center justify-between gap-2 mb-2">'
|
|
1160
|
+
+ '<span class="text-xs truncate" style="color: var(--pw-text-primary); font-family: var(--pw-font-mono);" title="' + escapeHtml(top.lineage_id || '') + '">' + escapeHtml(shortId(top.lineage_id)) + '</span>'
|
|
1161
|
+
+ badgeHtml(top.lineage && top.lineage.stop_reason ? top.lineage.stop_reason : 'unknown', statusKind(top.lineage && top.lineage.final_status))
|
|
1162
|
+
+ '</div>'
|
|
1163
|
+
+ '<div class="text-xs mb-1" style="color: var(--pw-text-tertiary);">policy issues: ' + escapeHtml(String(top.policy ? top.policy.issue_count : 0)) + '</div>'
|
|
1164
|
+
+ '<div class="text-xs truncate" style="color: var(--pw-text-tertiary);" title="' + escapeHtml(top.next_action || '') + '">Next: ' + escapeHtml(top.next_action || 'review') + '</div>';
|
|
1165
|
+
} catch (err) {
|
|
1166
|
+
if (status) status.textContent = 'error';
|
|
1167
|
+
body.innerHTML = '<div class="text-xs" style="color: var(--pw-state-error);">' + escapeHtml(err.message) + '</div>';
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1030
1171
|
// ---------- Refresh orchestrators ----------
|
|
1031
1172
|
async function refreshStatus() {
|
|
1032
1173
|
try {
|
|
@@ -1067,14 +1208,14 @@ html.dark {
|
|
|
1067
1208
|
}
|
|
1068
1209
|
|
|
1069
1210
|
async function refreshAll() {
|
|
1070
|
-
await Promise.all([refreshStatus(), refreshTasks(), refreshLogs(), refreshEvents()]);
|
|
1211
|
+
await Promise.all([refreshStatus(), refreshTasks(), refreshLogs(), refreshEvents(), refreshLineages(), refreshProjectPolicy(), refreshReleaseStatus(), refreshEvidencePacks()]);
|
|
1071
1212
|
}
|
|
1072
1213
|
|
|
1073
1214
|
// ---------- Actions ----------
|
|
1074
1215
|
async function handleAction(action, btnEl) {
|
|
1075
1216
|
try {
|
|
1076
1217
|
if (action === 'refresh') {
|
|
1077
|
-
await Promise.all([refreshStatus(), refreshTasks()]);
|
|
1218
|
+
await Promise.all([refreshStatus(), refreshTasks(), refreshLineages(), refreshProjectPolicy(), refreshReleaseStatus(), refreshEvidencePacks()]);
|
|
1078
1219
|
return;
|
|
1079
1220
|
}
|
|
1080
1221
|
|