@walwal-harness/cli 7.1.33 → 7.1.34
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.md
CHANGED
|
@@ -283,6 +283,7 @@ harness-hiring → register and onboard worker
|
|
|
283
283
|
|
|
284
284
|
| Version | Summary |
|
|
285
285
|
|---|---|
|
|
286
|
+
| 7.1.34 | Fix dashboard 500 when `company_state.workers` is recorded as a keyed worker map instead of an array |
|
|
286
287
|
| 7.1.33 | Dashboard keeps recently written worker reports active even when docmeta is present, and CXX skills now record worker activity telemetry for live dashboard state |
|
|
287
288
|
| 7.1.31 | Persist dashboard heatmap activity to 7-day JSONL logs, load persisted samples in the dashboard, and backfill activity during migrate from existing mission docs/progress logs |
|
|
288
289
|
| 7.1.29 | Idempotent AGENTS/CLAUDE doc merge with marked harness sections, mission lifecycle backfill for init/migrate, completion closes todos and mission-state, and Layer Activity now lists CXX/worker rows sorted by remaining work |
|
|
@@ -407,4 +407,41 @@ describe("readHarnessState", () => {
|
|
|
407
407
|
active: true,
|
|
408
408
|
});
|
|
409
409
|
});
|
|
410
|
+
|
|
411
|
+
it("accepts keyed company_state.workers maps from manual CXX telemetry", () => {
|
|
412
|
+
const harnessDir = path.join(dir, ".harness");
|
|
413
|
+
const missionDir = path.join(harnessDir, "documents", "goal-1-dashboard");
|
|
414
|
+
mkdirSync(path.join(missionDir, "cqo", "workers"), { recursive: true });
|
|
415
|
+
writeFileSync(path.join(missionDir, "ceo.md"), "# Dashboard\n");
|
|
416
|
+
writeFileSync(
|
|
417
|
+
path.join(missionDir, "cqo", "workers", "evaluator.md"),
|
|
418
|
+
"---\ndocmeta:\n id: evaluator\n---\n\n# Worker Report\n"
|
|
419
|
+
);
|
|
420
|
+
writeFileSync(
|
|
421
|
+
path.join(harnessDir, "progress.json"),
|
|
422
|
+
JSON.stringify({
|
|
423
|
+
agent_status: "running",
|
|
424
|
+
company_state: {
|
|
425
|
+
active_workers: 1,
|
|
426
|
+
workers: {
|
|
427
|
+
"engineering-engineering-code-reviewer": {
|
|
428
|
+
owner: "cqo",
|
|
429
|
+
report: ".harness/documents/goal-1-dashboard/cqo/workers/evaluator.md",
|
|
430
|
+
status: "running",
|
|
431
|
+
},
|
|
432
|
+
},
|
|
433
|
+
},
|
|
434
|
+
})
|
|
435
|
+
);
|
|
436
|
+
|
|
437
|
+
const snap = readHarnessState(dir);
|
|
438
|
+
expect(snap.dashboard.workers[0]).toMatchObject({
|
|
439
|
+
agent: "engineering-engineering-code-reviewer",
|
|
440
|
+
status: "running",
|
|
441
|
+
});
|
|
442
|
+
expect(snap.missions[0].workers[0]).toMatchObject({
|
|
443
|
+
owner: "cqo",
|
|
444
|
+
active: true,
|
|
445
|
+
});
|
|
446
|
+
});
|
|
410
447
|
});
|
|
@@ -157,6 +157,18 @@ interface RawProgress {
|
|
|
157
157
|
spawn_status?: string;
|
|
158
158
|
status?: string;
|
|
159
159
|
pid?: number | null;
|
|
160
|
+
}> | Record<string, {
|
|
161
|
+
team?: number | string;
|
|
162
|
+
feature?: string;
|
|
163
|
+
agent?: string;
|
|
164
|
+
phase?: string;
|
|
165
|
+
prompt?: string | null;
|
|
166
|
+
log?: string | null;
|
|
167
|
+
spawn_status?: string;
|
|
168
|
+
status?: string;
|
|
169
|
+
pid?: number | null;
|
|
170
|
+
owner?: string;
|
|
171
|
+
report?: string | null;
|
|
160
172
|
}>;
|
|
161
173
|
last_dispatch?: Array<{
|
|
162
174
|
team?: number | string;
|
|
@@ -784,7 +796,19 @@ function readFeatureTitles(rootDir: string): Map<string, string> {
|
|
|
784
796
|
return map;
|
|
785
797
|
}
|
|
786
798
|
|
|
787
|
-
|
|
799
|
+
interface RawWorker {
|
|
800
|
+
team?: number | string;
|
|
801
|
+
feature?: string;
|
|
802
|
+
agent?: string;
|
|
803
|
+
phase?: string;
|
|
804
|
+
prompt?: string | null;
|
|
805
|
+
log?: string | null;
|
|
806
|
+
spawn_status?: string;
|
|
807
|
+
status?: string;
|
|
808
|
+
pid?: number | null;
|
|
809
|
+
owner?: string;
|
|
810
|
+
report?: string | null;
|
|
811
|
+
}
|
|
788
812
|
type WorkerOwner = WorkerDocEntry["owner"];
|
|
789
813
|
|
|
790
814
|
interface HiredWorkerEntry {
|
|
@@ -839,13 +863,28 @@ function deriveWorkerProgress(worker: RawWorker): number | null {
|
|
|
839
863
|
if (status === "blocked" || status === "failed") return 0.35;
|
|
840
864
|
if (status === "recorded") return 0.15;
|
|
841
865
|
if (status === "spawned" || status === "running") return 0.55;
|
|
842
|
-
if (status === "completed" || status === "done") return 1;
|
|
866
|
+
if (status === "complete" || status === "completed" || status === "done") return 1;
|
|
843
867
|
return null;
|
|
844
868
|
}
|
|
845
869
|
|
|
870
|
+
function normalizeRawWorkers(value: RawWorker[] | Record<string, RawWorker> | null | undefined): RawWorker[] {
|
|
871
|
+
if (Array.isArray(value)) return value;
|
|
872
|
+
if (!value || typeof value !== "object") return [];
|
|
873
|
+
return Object.entries(value).map(([name, worker], idx) => {
|
|
874
|
+
const w = worker && typeof worker === "object" ? worker : {};
|
|
875
|
+
return {
|
|
876
|
+
...w,
|
|
877
|
+
team: (w as RawWorker).team ?? idx + 1,
|
|
878
|
+
agent: (w as RawWorker).agent ?? name,
|
|
879
|
+
feature: (w as RawWorker).feature ?? name,
|
|
880
|
+
log: (w as RawWorker).log ?? (w as RawWorker & { report?: string | null }).report ?? null,
|
|
881
|
+
};
|
|
882
|
+
});
|
|
883
|
+
}
|
|
884
|
+
|
|
846
885
|
function buildWorkers(rootDir: string, progress: RawProgress | null): WorkerSnapshot[] {
|
|
847
886
|
const titles = readFeatureTitles(rootDir);
|
|
848
|
-
let workers = progress?.company_state?.workers
|
|
887
|
+
let workers = normalizeRawWorkers(progress?.company_state?.workers);
|
|
849
888
|
if (workers.length === 0) {
|
|
850
889
|
const queue = readJsonSafe<{
|
|
851
890
|
teams?: Record<string, {
|
|
@@ -996,12 +1035,12 @@ function activeWorkerNames(progress: RawProgress | null): Set<string> {
|
|
|
996
1035
|
const active = new Set<string>();
|
|
997
1036
|
if (isHarnessRuntimeIdle(progress)) return active;
|
|
998
1037
|
const workers = [
|
|
999
|
-
...(progress?.company_state?.workers
|
|
1038
|
+
...normalizeRawWorkers(progress?.company_state?.workers),
|
|
1000
1039
|
...(progress?.company_state?.last_dispatch ?? []),
|
|
1001
1040
|
];
|
|
1002
1041
|
for (const worker of workers) {
|
|
1003
1042
|
const rawStatus = (worker.status ?? worker.spawn_status ?? "").toLowerCase();
|
|
1004
|
-
if (["completed", "done", "idle"].includes(rawStatus)) continue;
|
|
1043
|
+
if (["complete", "completed", "done", "idle"].includes(rawStatus)) continue;
|
|
1005
1044
|
for (const value of [worker.agent, worker.feature]) {
|
|
1006
1045
|
const normalized = normalizeWorkerName(value);
|
|
1007
1046
|
if (normalized) active.add(normalized);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@walwal-harness/cli",
|
|
3
|
-
"version": "7.1.
|
|
3
|
+
"version": "7.1.34",
|
|
4
4
|
"description": "Company-style AI agent harness for Claude and Codex. Installs commands, CXX agents, skills, HR-Resource hiring pool, and project-local .harness runtime state.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"walwal-harness": "bin/init.js"
|