coding-agent-harness 1.0.8 → 1.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/CHANGELOG.md +10 -0
- package/CONTRIBUTING.md +8 -4
- package/README.md +12 -2
- package/README.zh-CN.md +10 -2
- package/SKILL.md +14 -3
- package/dist/build-dist.mjs +19 -6
- package/dist/check-dist-observation.mjs +57 -29
- package/dist/check-harness.mjs +0 -1
- package/dist/check-import-graph.mjs +44 -27
- package/dist/check-lite-forbidden-surfaces.mjs +121 -0
- package/dist/check-no-ts-nocheck.mjs +7 -7
- package/dist/check-runtime-emit.mjs +10 -3
- package/dist/check-type-boundaries.mjs +51 -9
- package/dist/commands/dashboard-command.mjs +52 -14
- package/dist/commands/migration-command.mjs +18 -8
- package/dist/commands/module-command.mjs +142 -0
- package/dist/commands/preset-command.mjs +51 -12
- package/dist/commands/registry.mjs +483 -0
- package/dist/commands/task-command.mjs +109 -52
- package/dist/harness.mjs +6 -304
- package/dist/lib/capability-registry.mjs +229 -53
- package/dist/lib/check-module-parallel.mjs +1 -6
- package/dist/lib/check-profiles.mjs +39 -46
- package/dist/lib/check-task-contracts.mjs +6 -4
- package/dist/lib/command-registry.mjs +248 -0
- package/dist/lib/core-shared.mjs +78 -3
- package/dist/lib/dashboard-data.mjs +203 -22
- package/dist/lib/dashboard-workbench.mjs +245 -21
- package/dist/lib/dashboard-writer.mjs +4 -1
- package/dist/lib/git-status-summary.mjs +0 -1
- package/dist/lib/governance-index-generator.mjs +7 -5
- package/dist/lib/governance-sync.mjs +46 -121
- package/dist/lib/governance-table-boundary.mjs +1 -14
- package/dist/lib/harness-core.mjs +4 -1
- package/dist/lib/harness-paths.mjs +115 -1
- package/dist/lib/impact-classifier.mjs +420 -0
- package/dist/lib/lesson-maintenance.mjs +1 -2
- package/dist/lib/markdown-utils.mjs +50 -1
- package/dist/lib/migration-planner.mjs +31 -16
- package/dist/lib/migration-support.mjs +5 -4
- package/dist/lib/module-registry.mjs +296 -0
- package/dist/lib/preset-audit-contracts.mjs +24 -1
- package/dist/lib/preset-engine.mjs +67 -29
- package/dist/lib/preset-registry.mjs +361 -71
- package/dist/lib/preset-runner.mjs +292 -26
- package/dist/lib/review-confirm-git-gate.mjs +73 -19
- package/dist/lib/status-builder.mjs +23 -8
- package/dist/lib/structure-migration.mjs +6 -4
- package/dist/lib/subagent-authorization-audit.mjs +8 -2
- package/dist/lib/task-archive-eligibility.mjs +65 -0
- package/dist/lib/task-audit-metadata.mjs +25 -11
- package/dist/lib/task-audit-migration.mjs +21 -14
- package/dist/lib/task-discovery-contract.mjs +32 -0
- package/dist/lib/task-index.mjs +3 -2
- package/dist/lib/task-lesson-candidates.mjs +1 -2
- package/dist/lib/task-lesson-sedimentation.mjs +310 -9
- package/dist/lib/task-lifecycle/create-task-helpers.mjs +6 -3
- package/dist/lib/task-lifecycle/phase-sync.mjs +0 -1
- package/dist/lib/task-lifecycle/preset-interop.mjs +16 -0
- package/dist/lib/task-lifecycle/review-confirm.mjs +34 -2
- package/dist/lib/task-lifecycle/review-gates.mjs +12 -5
- package/dist/lib/task-lifecycle/review-submission.mjs +1 -2
- package/dist/lib/task-lifecycle/scaffold-provenance.mjs +0 -1
- package/dist/lib/task-lifecycle/template-files.mjs +2 -5
- package/dist/lib/task-lifecycle.mjs +116 -160
- package/dist/lib/task-metadata.mjs +10 -5
- package/dist/lib/task-preset-contract-drift.mjs +45 -0
- package/dist/lib/task-repository.mjs +192 -0
- package/dist/lib/task-review-model.mjs +36 -17
- package/dist/lib/task-scanner.mjs +74 -23
- package/dist/lib/task-template-materials.mjs +131 -0
- package/dist/lib/task-tombstone-commands.mjs +186 -29
- package/dist/lib/types/check-profiles.js +1 -0
- package/dist/lib/types/impact.js +1 -0
- package/dist/lib/types/preset.js +1 -0
- package/dist/lib/types/task-lifecycle.js +1 -0
- package/dist/lib/types/task-scanner.js +1 -0
- package/dist/postinstall.mjs +2 -2
- package/dist/run-built-tests.mjs +10 -3
- package/docs-release/README.md +1 -0
- package/docs-release/architecture/document-contract-kernel/README.md +150 -0
- package/docs-release/architecture/document-contract-kernel/products/full-skill-overlay.md +29 -0
- package/docs-release/architecture/document-contract-kernel/products/lite-forbidden-surfaces.txt +26 -0
- package/docs-release/architecture/document-contract-kernel/products/lite-skill-overlay.md +37 -0
- package/docs-release/architecture/overview.md +2 -2
- package/docs-release/architecture/overview.zh-CN.md +2 -2
- package/docs-release/architecture/system-explainer/01-system-overview.md +11 -7
- package/docs-release/architecture/system-explainer/02-module-dependency.md +4 -4
- package/docs-release/architecture/system-explainer/03-task-lifecycle.md +17 -12
- package/docs-release/architecture/system-explainer/05-data-flow.md +6 -6
- package/docs-release/architecture/system-explainer/06-preset-and-migration.md +2 -2
- package/docs-release/architecture/system-explainer/README.md +1 -1
- package/docs-release/architecture/system-explainer/en-US/01-system-overview.md +12 -8
- package/docs-release/architecture/system-explainer/en-US/02-module-dependency.md +5 -5
- package/docs-release/architecture/system-explainer/en-US/03-task-lifecycle.md +19 -11
- package/docs-release/architecture/system-explainer/en-US/05-data-flow.md +5 -5
- package/docs-release/architecture/system-explainer/en-US/06-preset-and-migration.md +2 -2
- package/docs-release/architecture/system-explainer/en-US/README.md +1 -1
- package/docs-release/guides/agent-installation.en-US.md +4 -6
- package/docs-release/guides/agent-installation.md +11 -8
- package/docs-release/guides/contributing.md +10 -3
- package/docs-release/guides/contributing.zh-CN.md +10 -3
- package/docs-release/guides/legacy-migration-agent-prompt.md +1 -1
- package/docs-release/guides/legacy-migration-agent-prompt.zh-CN.md +1 -1
- package/docs-release/guides/migration-playbook.en-US.md +9 -6
- package/docs-release/guides/migration-playbook.md +9 -6
- package/docs-release/guides/preset-development.md +68 -2
- package/docs-release/guides/task-state-machine.en-US.md +8 -8
- package/docs-release/guides/task-state-machine.md +7 -7
- package/docs-release/guides/typescript-runtime-migration-closeout.md +17 -13
- package/package.json +16 -12
- package/postinstall.mjs +37 -0
- package/presets/legacy-migration/preset.yaml +5 -5
- package/presets/legacy-migration/templates/execution_strategy.append.md +1 -1
- package/presets/lesson-sedimentation/preset.yaml +3 -3
- package/presets/module/preset.yaml +2 -2
- package/presets/module/templates/execution_strategy.append.md +1 -1
- package/presets/module/templates/task_plan.append.md +3 -3
- package/presets/release-closeout/checks/check-release-package.mjs +6 -1
- package/presets/release-closeout/preset.yaml +9 -9
- package/presets/release-closeout/scripts/generate-release-package.mjs +387 -25
- package/presets/release-closeout/templates/task_plan.append.md +5 -5
- package/presets/standard-task/preset.yaml +2 -2
- package/references/agents-md-pattern.md +23 -17
- package/references/lessons-governance.md +2 -2
- package/references/module-parallel-standard.md +3 -6
- package/references/ssot-governance.md +2 -2
- package/references/taskr-gap-analysis.md +3 -3
- package/run-dist.mjs +34 -0
- package/skills/preset-creator/SKILL.md +40 -8
- package/skills/preset-creator/references/complex-task-skeleton/brief.md +32 -8
- package/skills/preset-creator/references/preset-package-skeleton.md +15 -5
- package/skills/preset-creator/references/structure-aware-paths.md +112 -0
- package/templates/AGENTS.md.template +28 -26
- package/templates/architecture/README.md +2 -2
- package/templates/architecture/service-catalog.md +2 -2
- package/templates/architecture/services/service-template.md +1 -1
- package/templates/dashboard/assets/app-src/00-state.js +5 -1
- package/templates/dashboard/assets/app-src/10-router.js +7 -0
- package/templates/dashboard/assets/app-src/20-overview.js +8 -8
- package/templates/dashboard/assets/app-src/30-tasks.js +132 -40
- package/templates/dashboard/assets/app-src/32-task-swimlane.js +314 -0
- package/templates/dashboard/assets/app-src/35-task-detail.js +35 -5
- package/templates/dashboard/assets/app-src/40-modules.js +257 -41
- package/templates/dashboard/assets/app-src/45-review.js +127 -1
- package/templates/dashboard/assets/app-src/90-bindings.js +185 -2
- package/templates/dashboard/assets/app.css +928 -53
- package/templates/dashboard/assets/app.css.manifest.json +2 -0
- package/templates/dashboard/assets/app.js +1071 -98
- package/templates/dashboard/assets/app.manifest.json +1 -0
- package/templates/dashboard/assets/css-src/00-foundation.css +12 -6
- package/templates/dashboard/assets/css-src/10-panels-flow.css +2 -2
- package/templates/dashboard/assets/css-src/30-task-index.css +21 -13
- package/templates/dashboard/assets/css-src/31-archive.css +94 -0
- package/templates/dashboard/assets/css-src/32-task-swimlane.css +487 -0
- package/templates/dashboard/assets/css-src/35-review-workspace.css +78 -0
- package/templates/dashboard/assets/css-src/40-detail-modules-migration.css +191 -14
- package/templates/dashboard/assets/css-src/50-responsive-overrides.css +23 -0
- package/templates/dashboard/assets/i18n.js +166 -2
- package/templates/development/README.md +9 -9
- package/templates/development/cross-repo-debugging.md +3 -3
- package/templates/development/external-context/service-template.md +1 -1
- package/templates/development/external-source-packs/README.md +2 -2
- package/templates/integrations/README.md +4 -4
- package/templates/integrations/api-contract.md +1 -1
- package/templates/integrations/event-contract.md +1 -1
- package/templates/integrations/third-party/vendor-template.md +1 -1
- package/templates/integrations/webhook-contract.md +1 -1
- package/templates/ledger/Harness-Ledger.md +1 -1
- package/templates/modules/module_brief.md +50 -0
- package/templates/modules/module_plan.md +49 -0
- package/templates/modules/registry_view.md +9 -0
- package/templates/modules/session_prompt_pack.md +55 -0
- package/templates/planning/brief.md +32 -8
- package/templates/planning/module_brief.md +28 -3
- package/templates/planning/module_plan.md +26 -11
- package/templates/planning/module_session_prompt.md +11 -2
- package/templates/planning/optional/slices/_slice-template/brief.md +28 -0
- package/templates/planning/review.md +1 -1
- package/templates/planning/visual_map.md +1 -1
- package/templates/reference/docs-library-standard.md +7 -7
- package/templates/reference/execution-workflow-standard.md +13 -0
- package/templates/reference/external-source-intake-standard.md +10 -10
- package/templates/reference/repo-governance-standard.md +1 -1
- package/templates/reference/review-routing-standard.md +4 -0
- package/templates/ssot/Module-Registry.md +4 -38
- package/templates/walkthrough/walkthrough-template.md +1 -1
- package/templates-zh-CN/AGENTS.md.template +27 -25
- package/templates-zh-CN/CLAUDE.md.template +1 -1
- package/templates-zh-CN/architecture/README.md +2 -2
- package/templates-zh-CN/architecture/service-catalog.md +2 -2
- package/templates-zh-CN/architecture/services/service-template.md +1 -1
- package/templates-zh-CN/development/README.md +9 -9
- package/templates-zh-CN/development/cross-repo-debugging.md +3 -3
- package/templates-zh-CN/development/external-context/service-template.md +1 -1
- package/templates-zh-CN/development/external-source-packs/README.md +2 -2
- package/templates-zh-CN/integrations/README.md +4 -4
- package/templates-zh-CN/integrations/api-contract.md +1 -1
- package/templates-zh-CN/integrations/event-contract.md +1 -1
- package/templates-zh-CN/integrations/third-party/vendor-template.md +1 -1
- package/templates-zh-CN/integrations/webhook-contract.md +1 -1
- package/templates-zh-CN/ledger/Harness-Ledger.md +1 -1
- package/templates-zh-CN/lessons/lesson-arch-process-change.md +1 -1
- package/templates-zh-CN/lessons/lesson-new-doc.md +3 -3
- package/templates-zh-CN/lessons/lesson-ref-change.md +4 -4
- package/templates-zh-CN/modules/module_brief.md +47 -0
- package/templates-zh-CN/modules/module_plan.md +48 -0
- package/templates-zh-CN/modules/registry_view.md +9 -0
- package/templates-zh-CN/modules/session_prompt_pack.md +50 -0
- package/templates-zh-CN/planning/INDEX.md +1 -0
- package/templates-zh-CN/planning/brief.md +26 -7
- package/templates-zh-CN/planning/module_brief.md +24 -2
- package/templates-zh-CN/planning/module_plan.md +35 -29
- package/templates-zh-CN/planning/module_session_prompt.md +15 -11
- package/templates-zh-CN/planning/optional/slices/_slice-template/brief.md +28 -11
- package/templates-zh-CN/planning/review.md +1 -1
- package/templates-zh-CN/reference/adversarial-review-standard.md +1 -1
- package/templates-zh-CN/reference/delivery-operating-model-standard.md +3 -3
- package/templates-zh-CN/reference/docs-library-standard.md +27 -27
- package/templates-zh-CN/reference/execution-workflow-standard.md +12 -2
- package/templates-zh-CN/reference/external-source-intake-standard.md +10 -10
- package/templates-zh-CN/reference/harness-ledger-standard.md +3 -3
- package/templates-zh-CN/reference/regression-ssot-governance.md +2 -2
- package/templates-zh-CN/reference/repo-governance-standard.md +1 -1
- package/templates-zh-CN/reference/review-routing-standard.md +3 -0
- package/templates-zh-CN/reference/walkthrough-standard.md +2 -2
- package/templates-zh-CN/reference/worktree-standard.md +1 -1
- package/templates-zh-CN/regression/Cadence-Ledger.md +2 -2
- package/templates-zh-CN/ssot/Delivery-SSoT.md +2 -2
- package/templates-zh-CN/ssot/Module-Registry.md +5 -44
- package/templates-zh-CN/ssot/Regression-SSoT.md +2 -2
- package/templates-zh-CN/walkthrough/walkthrough-template.md +4 -4
|
@@ -4,12 +4,26 @@ window.setModulePage = function(moduleKey, page) {
|
|
|
4
4
|
app();
|
|
5
5
|
};
|
|
6
6
|
|
|
7
|
+
function rerenderPreservingFieldFocus(field, selector) {
|
|
8
|
+
const shouldRestore = document.activeElement === field;
|
|
9
|
+
const selectionStart = typeof field.selectionStart === "number" ? field.selectionStart : null;
|
|
10
|
+
const selectionEnd = typeof field.selectionEnd === "number" ? field.selectionEnd : selectionStart;
|
|
11
|
+
app();
|
|
12
|
+
if (!shouldRestore) return;
|
|
13
|
+
const nextField = document.querySelector(selector);
|
|
14
|
+
if (!nextField || typeof nextField.focus !== "function") return;
|
|
15
|
+
nextField.focus({ preventScroll: true });
|
|
16
|
+
if (typeof nextField.setSelectionRange === "function" && selectionStart !== null) {
|
|
17
|
+
nextField.setSelectionRange(selectionStart, selectionEnd);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
7
21
|
function bind() {
|
|
8
22
|
document.querySelectorAll("[data-search]").forEach((input) => input.addEventListener("input", () => {
|
|
9
23
|
state.query = input.value;
|
|
10
24
|
state.taskPageByGroup = {};
|
|
11
25
|
state.taskGroupPage = 1;
|
|
12
|
-
|
|
26
|
+
rerenderPreservingFieldFocus(input, "[data-search]");
|
|
13
27
|
}));
|
|
14
28
|
document.querySelectorAll("[data-state-filter]").forEach((select) => select.addEventListener("change", () => {
|
|
15
29
|
state.taskState = select.value;
|
|
@@ -19,6 +33,7 @@ function bind() {
|
|
|
19
33
|
}));
|
|
20
34
|
document.querySelectorAll("[data-group-mode]").forEach((select) => select.addEventListener("change", () => {
|
|
21
35
|
state.taskGroupMode = select.value;
|
|
36
|
+
localStorage.setItem("harness.taskGroupMode", state.taskGroupMode);
|
|
22
37
|
state.taskPageByGroup = {};
|
|
23
38
|
state.taskGroupPage = 1;
|
|
24
39
|
app();
|
|
@@ -51,7 +66,7 @@ function bind() {
|
|
|
51
66
|
}));
|
|
52
67
|
document.querySelectorAll("[data-preset-search]").forEach((input) => input.addEventListener("input", () => {
|
|
53
68
|
state.presetQuery = input.value;
|
|
54
|
-
|
|
69
|
+
rerenderPreservingFieldFocus(input, "[data-preset-search]");
|
|
55
70
|
}));
|
|
56
71
|
document.querySelectorAll("[data-preset-source-filter]").forEach((button) => button.addEventListener("click", () => {
|
|
57
72
|
state.presetSourceFilter = button.dataset.presetSourceFilter || "all";
|
|
@@ -114,6 +129,9 @@ function bind() {
|
|
|
114
129
|
document.querySelectorAll("[data-review-queue-tab]").forEach((button) => button.addEventListener("click", () => {
|
|
115
130
|
state.reviewQueueTab = button.dataset.reviewQueueTab || "review";
|
|
116
131
|
state.reviewQueuePage = 1;
|
|
132
|
+
state.reviewBulkSelection = {};
|
|
133
|
+
state.reviewBulkResult = null;
|
|
134
|
+
state.lessonBulkResult = null;
|
|
117
135
|
app();
|
|
118
136
|
}));
|
|
119
137
|
document.querySelectorAll("[data-review-reason-filter]").forEach((select) => select.addEventListener("change", () => {
|
|
@@ -126,6 +144,51 @@ function bind() {
|
|
|
126
144
|
state.reviewQueuePage = 1;
|
|
127
145
|
app();
|
|
128
146
|
}));
|
|
147
|
+
document.querySelectorAll("[data-review-bulk-select]").forEach((input) => input.addEventListener("change", () => {
|
|
148
|
+
state.reviewBulkSelection = state.reviewBulkSelection || {};
|
|
149
|
+
state.reviewBulkSelection[input.dataset.reviewBulkSelect || ""] = input.checked;
|
|
150
|
+
state.reviewBulkResult = null;
|
|
151
|
+
app();
|
|
152
|
+
}));
|
|
153
|
+
document.querySelectorAll("[data-review-bulk-select-all]").forEach((input) => input.addEventListener("change", () => {
|
|
154
|
+
const activeTab = reviewQueueTabs().find((tab) => tab.id === state.reviewQueueTab) || reviewQueueTabs()[0];
|
|
155
|
+
const tasks = activeTab.id === "review" ? reviewFilteredTasks(reviewQueueBaseTasks(activeTab)).filter(taskCanBeHumanConfirmed) : [];
|
|
156
|
+
state.reviewBulkSelection = state.reviewBulkSelection || {};
|
|
157
|
+
tasks.forEach((task) => {
|
|
158
|
+
if (input.checked) state.reviewBulkSelection[task.id] = true;
|
|
159
|
+
else delete state.reviewBulkSelection[task.id];
|
|
160
|
+
});
|
|
161
|
+
state.reviewBulkResult = null;
|
|
162
|
+
app();
|
|
163
|
+
}));
|
|
164
|
+
document.querySelectorAll("[data-review-bulk-clear]").forEach((button) => button.addEventListener("click", () => {
|
|
165
|
+
state.reviewBulkSelection = {};
|
|
166
|
+
state.reviewBulkResult = null;
|
|
167
|
+
app();
|
|
168
|
+
}));
|
|
169
|
+
document.querySelectorAll("[data-review-bulk-confirm]").forEach((button) => button.addEventListener("click", () => confirmSelectedReviewsFromDashboard(button)));
|
|
170
|
+
document.querySelectorAll("[data-lesson-bulk-select]").forEach((input) => input.addEventListener("change", () => {
|
|
171
|
+
state.lessonBulkSelection = state.lessonBulkSelection || {};
|
|
172
|
+
state.lessonBulkSelection[input.dataset.lessonBulkSelect || ""] = input.checked;
|
|
173
|
+
state.lessonBulkResult = null;
|
|
174
|
+
app();
|
|
175
|
+
}));
|
|
176
|
+
document.querySelectorAll("[data-lesson-bulk-select-all]").forEach((input) => input.addEventListener("change", () => {
|
|
177
|
+
state.lessonBulkSelection = state.lessonBulkSelection || {};
|
|
178
|
+
lessonBulkActionableSelections().forEach((selection) => {
|
|
179
|
+
const key = lessonBulkSelectionKey(selection.taskId, selection.candidateId);
|
|
180
|
+
if (input.checked) state.lessonBulkSelection[key] = true;
|
|
181
|
+
else delete state.lessonBulkSelection[key];
|
|
182
|
+
});
|
|
183
|
+
state.lessonBulkResult = null;
|
|
184
|
+
app();
|
|
185
|
+
}));
|
|
186
|
+
document.querySelectorAll("[data-lesson-bulk-clear]").forEach((button) => button.addEventListener("click", () => {
|
|
187
|
+
state.lessonBulkSelection = {};
|
|
188
|
+
state.lessonBulkResult = null;
|
|
189
|
+
app();
|
|
190
|
+
}));
|
|
191
|
+
document.querySelectorAll("[data-lesson-bulk-create]").forEach((button) => button.addEventListener("click", () => createSelectedLessonSedimentationFromDashboard(button)));
|
|
129
192
|
document.querySelectorAll("[data-page-kind]").forEach((button) => button.addEventListener("click", () => {
|
|
130
193
|
const page = Math.max(1, Number(button.dataset.page) || 1);
|
|
131
194
|
if (button.dataset.pageKind === "warning") state.warningPage = page;
|
|
@@ -166,6 +229,7 @@ function bind() {
|
|
|
166
229
|
openLessonDrawer(lessonId);
|
|
167
230
|
}));
|
|
168
231
|
document.querySelectorAll("[data-review-complete]").forEach((button) => button.addEventListener("click", () => completeReviewFromDashboard(button.dataset.reviewComplete)));
|
|
232
|
+
document.querySelectorAll("[data-task-complete]").forEach((button) => button.addEventListener("click", () => completeTaskFromDashboard(button.dataset.taskComplete)));
|
|
169
233
|
const overlay = document.getElementById("drawer-overlay");
|
|
170
234
|
if (overlay) overlay.addEventListener("click", closeDrawer);
|
|
171
235
|
}
|
|
@@ -240,6 +304,90 @@ async function completeReviewFromDashboard(taskId) {
|
|
|
240
304
|
}
|
|
241
305
|
}
|
|
242
306
|
|
|
307
|
+
async function completeTaskFromDashboard(taskId) {
|
|
308
|
+
const result = document.querySelector(`[data-task-complete-result="${CSS.escape(taskId)}"]`);
|
|
309
|
+
if (result) result.textContent = t("taskCloseoutSubmitting");
|
|
310
|
+
try {
|
|
311
|
+
const response = await fetch("/api/tasks/task-complete", {
|
|
312
|
+
method: "POST",
|
|
313
|
+
headers: {
|
|
314
|
+
"content-type": "application/json",
|
|
315
|
+
"x-harness-csrf": state.runtime?.csrfToken || "",
|
|
316
|
+
},
|
|
317
|
+
body: JSON.stringify({
|
|
318
|
+
taskId,
|
|
319
|
+
message: "closed from dashboard workbench",
|
|
320
|
+
evidence: "dashboard:task-complete",
|
|
321
|
+
}),
|
|
322
|
+
});
|
|
323
|
+
const payload = await response.json();
|
|
324
|
+
if (!response.ok) throw new Error(payload.error || t("taskCloseoutFailed"));
|
|
325
|
+
if (result) result.textContent = t("taskCloseoutSuccess");
|
|
326
|
+
setTimeout(() => window.location.reload(), 500);
|
|
327
|
+
} catch (error) {
|
|
328
|
+
if (result) result.textContent = `${t("taskCloseoutFailed")}: ${error.message}`;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function dashboardActionErrorDetail(error, fallback) {
|
|
333
|
+
const direct = error?.error || error?.message;
|
|
334
|
+
if (direct) return direct;
|
|
335
|
+
const failedResults = Array.isArray(error?.results) ? error.results.filter((result) => result?.ok === false) : [];
|
|
336
|
+
if (failedResults.length > 0) {
|
|
337
|
+
const reasons = [];
|
|
338
|
+
for (const result of failedResults) {
|
|
339
|
+
const reason = result?.error || result?.message;
|
|
340
|
+
if (reason && !reasons.includes(reason)) reasons.push(reason);
|
|
341
|
+
}
|
|
342
|
+
if (reasons.length > 0) {
|
|
343
|
+
return formatMessage("bulkActionFailedWithReason", {
|
|
344
|
+
failed: error?.failed || failedResults.length,
|
|
345
|
+
reason: reasons.slice(0, 3).join("; "),
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
return formatMessage("bulkActionFailedSummary", { failed: error?.failed || failedResults.length });
|
|
349
|
+
}
|
|
350
|
+
return String(error || fallback);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
async function confirmSelectedReviewsFromDashboard(button) {
|
|
354
|
+
const taskIds = reviewBulkSelectedIds();
|
|
355
|
+
if (!taskIds.length) {
|
|
356
|
+
state.reviewBulkResult = { ok: false, message: t("reviewBulkNone") };
|
|
357
|
+
app();
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
button.disabled = true;
|
|
361
|
+
state.reviewBulkResult = { ok: true, message: t("reviewBulkSubmitting") };
|
|
362
|
+
app();
|
|
363
|
+
try {
|
|
364
|
+
const response = await fetch("/api/tasks/review-complete-bulk", {
|
|
365
|
+
method: "POST",
|
|
366
|
+
headers: {
|
|
367
|
+
"content-type": "application/json",
|
|
368
|
+
"x-harness-csrf": state.runtime?.csrfToken || "",
|
|
369
|
+
},
|
|
370
|
+
body: JSON.stringify({
|
|
371
|
+
taskIds,
|
|
372
|
+
reviewer: "Human Reviewer",
|
|
373
|
+
message: "bulk confirmed from dashboard workbench",
|
|
374
|
+
}),
|
|
375
|
+
});
|
|
376
|
+
const payload = await response.json();
|
|
377
|
+
if (!response.ok) throw payload;
|
|
378
|
+
state.reviewBulkSelection = {};
|
|
379
|
+
state.reviewBulkResult = {
|
|
380
|
+
ok: payload.failed === 0,
|
|
381
|
+
message: payload.failed ? formatMessage("reviewBulkPartial", { confirmed: payload.confirmed || 0, failed: payload.failed || 0 }) : formatMessage("reviewBulkSuccess", { confirmed: payload.confirmed || 0 }),
|
|
382
|
+
};
|
|
383
|
+
app();
|
|
384
|
+
if ((payload.confirmed || 0) > 0) setTimeout(() => window.location.reload(), 1500);
|
|
385
|
+
} catch (error) {
|
|
386
|
+
state.reviewBulkResult = { ok: false, message: `${t("reviewCompleteFailed")}: ${dashboardActionErrorDetail(error, t("reviewCompleteFailed"))}` };
|
|
387
|
+
app();
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
243
391
|
async function runPresetAction(action, body) {
|
|
244
392
|
state.presetActionResult = { ok: true, title: t("presetActionRunning"), message: action };
|
|
245
393
|
app();
|
|
@@ -338,6 +486,7 @@ function openDrawer(taskId) {
|
|
|
338
486
|
bindRepairPromptButtons(drawer);
|
|
339
487
|
bindLessonSedimentationButtons(drawer);
|
|
340
488
|
drawer.querySelectorAll("[data-review-complete]").forEach((button) => button.addEventListener("click", () => completeReviewFromDashboard(button.dataset.reviewComplete)));
|
|
489
|
+
drawer.querySelectorAll("[data-task-complete]").forEach((button) => button.addEventListener("click", () => completeTaskFromDashboard(button.dataset.taskComplete)));
|
|
341
490
|
}
|
|
342
491
|
|
|
343
492
|
function bindCopyTaskNameButtons(root) {
|
|
@@ -456,6 +605,40 @@ async function createLessonSedimentationFromDashboard(button) {
|
|
|
456
605
|
}
|
|
457
606
|
}
|
|
458
607
|
|
|
608
|
+
async function createSelectedLessonSedimentationFromDashboard(button) {
|
|
609
|
+
const selections = lessonBulkSelectedSelections();
|
|
610
|
+
if (!selections.length) {
|
|
611
|
+
state.lessonBulkResult = { ok: false, message: t("lessonBulkNone") };
|
|
612
|
+
app();
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
615
|
+
button.disabled = true;
|
|
616
|
+
state.lessonBulkResult = { ok: true, message: t("lessonBulkSubmitting") };
|
|
617
|
+
app();
|
|
618
|
+
try {
|
|
619
|
+
const response = await fetch("/api/tasks/lesson-sedimentation-bulk", {
|
|
620
|
+
method: "POST",
|
|
621
|
+
headers: {
|
|
622
|
+
"content-type": "application/json",
|
|
623
|
+
"x-harness-csrf": state.runtime?.csrfToken || "",
|
|
624
|
+
},
|
|
625
|
+
body: JSON.stringify({ selections }),
|
|
626
|
+
});
|
|
627
|
+
const payload = await response.json();
|
|
628
|
+
if (!response.ok) throw payload;
|
|
629
|
+
state.lessonBulkSelection = {};
|
|
630
|
+
state.lessonBulkResult = {
|
|
631
|
+
ok: payload.failed === 0,
|
|
632
|
+
message: payload.failed ? formatMessage("lessonBulkPartial", { created: payload.created || 0, failed: payload.failed || 0 }) : formatMessage("lessonBulkSuccess", { candidates: payload.candidates || selections.length }),
|
|
633
|
+
};
|
|
634
|
+
app();
|
|
635
|
+
if ((payload.created || 0) > 0) setTimeout(() => window.location.reload(), 1500);
|
|
636
|
+
} catch (error) {
|
|
637
|
+
state.lessonBulkResult = { ok: false, message: `${t("lessonTaskCreateFailed")}: ${error?.error || error?.message || String(error)}` };
|
|
638
|
+
app();
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
459
642
|
function lessonSedimentationSuccess(payload) {
|
|
460
643
|
const followUp = payload?.followUpTask || {};
|
|
461
644
|
const prompt = payload?.prompt || "";
|