@walwal-harness/cli 7.1.27 → 7.1.28
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 +1 -0
- package/apps/harness-dashboard/app/globals.css +138 -8
- package/apps/harness-dashboard/app/layout.tsx +1 -5
- package/apps/harness-dashboard/app/page.tsx +3 -7
- package/apps/harness-dashboard/components/Scene.tsx +1603 -601
- package/apps/harness-dashboard/lib/harness-state.ts +41 -10
- package/apps/harness-dashboard/lib/types.ts +12 -0
- package/apps/harness-dashboard/package-lock.json +1519 -53
- package/apps/harness-dashboard/package.json +2 -0
- package/package.json +1 -1
|
@@ -25,6 +25,7 @@ import type {
|
|
|
25
25
|
MeetingRecord,
|
|
26
26
|
MeetingsState,
|
|
27
27
|
GotchaEntry,
|
|
28
|
+
ConventionEntry,
|
|
28
29
|
MissionDoc,
|
|
29
30
|
OperationsDashboard,
|
|
30
31
|
OpsServiceHealth,
|
|
@@ -226,6 +227,7 @@ function emptySnapshot(banner: ErrorBanner | null = null, rootDir?: string): Har
|
|
|
226
227
|
missions: [],
|
|
227
228
|
ownerHistory: [],
|
|
228
229
|
gotchas: [],
|
|
230
|
+
conventions: [],
|
|
229
231
|
todos: [],
|
|
230
232
|
events: [],
|
|
231
233
|
};
|
|
@@ -1165,7 +1167,15 @@ function readMissions(rootDir: string, progress: RawProgress | null = null, limi
|
|
|
1165
1167
|
const reportAbs = path.join(missionPath, relDir, f);
|
|
1166
1168
|
const content = readMd(`${relDir}/${f}`) ?? "";
|
|
1167
1169
|
const statusMatch = content.match(/##\s*Status\s*\n+([A-Z_]+)/);
|
|
1168
|
-
|
|
1170
|
+
// Worker docs sometimes omit the "## Status" block but always carry a
|
|
1171
|
+
// docmeta frontmatter when the worker submitted its output. Treat the
|
|
1172
|
+
// presence of a docmeta block (or a non-empty body) as COMPLETE.
|
|
1173
|
+
const hasDocmeta = /^---[\s\S]*?docmeta:[\s\S]*?---/.test(content);
|
|
1174
|
+
const status: WorkerDocEntry["status"] = statusMatch
|
|
1175
|
+
? (statusMatch[1] as WorkerDocEntry["status"])
|
|
1176
|
+
: hasDocmeta
|
|
1177
|
+
? "COMPLETE"
|
|
1178
|
+
: "unknown";
|
|
1169
1179
|
const name = normalizeWorkerName(f);
|
|
1170
1180
|
const hired = hiredForMission(hiredWorkers, name, owner, rel);
|
|
1171
1181
|
let updatedAt: string | null = null;
|
|
@@ -1293,32 +1303,51 @@ function readOwnerHistory(rootDir: string, limit = 30): OwnerPromptEntry[] {
|
|
|
1293
1303
|
return entries.reverse().slice(0, limit);
|
|
1294
1304
|
}
|
|
1295
1305
|
|
|
1296
|
-
function
|
|
1297
|
-
|
|
1298
|
-
|
|
1306
|
+
function readKnowledgeDir<T extends GotchaEntry | ConventionEntry>(
|
|
1307
|
+
rootDir: string,
|
|
1308
|
+
relDir: string
|
|
1309
|
+
): T[] {
|
|
1310
|
+
const dir = path.join(rootDir, ".harness", relDir);
|
|
1311
|
+
if (!existsSync(dir)) return [];
|
|
1299
1312
|
let entries: Dirent[];
|
|
1300
|
-
try { entries = readdirSync(
|
|
1301
|
-
const results:
|
|
1313
|
+
try { entries = readdirSync(dir, { withFileTypes: true }); } catch { return []; }
|
|
1314
|
+
const results: T[] = [];
|
|
1302
1315
|
for (const entry of entries) {
|
|
1303
1316
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
1304
1317
|
if (entry.name === "README.md") continue;
|
|
1305
1318
|
const id = entry.name.replace(/\.md$/, "");
|
|
1319
|
+
const abs = path.join(dir, entry.name);
|
|
1306
1320
|
let content: string;
|
|
1307
|
-
try { content = readFileSync(
|
|
1308
|
-
// Extract title from first H1 after optional frontmatter
|
|
1321
|
+
try { content = readFileSync(abs, "utf8"); } catch { continue; }
|
|
1309
1322
|
const body = content.replace(/^---[\s\S]*?---\n+/, "");
|
|
1310
1323
|
const h1 = body.match(/^#\s+(.+)/m);
|
|
1311
1324
|
const title = h1 ? h1[1].trim() : id;
|
|
1312
|
-
// Extract tags from docmeta frontmatter
|
|
1313
1325
|
const tagsMatch = content.match(/^\s*tags:\s*\[([^\]]*)\]/m);
|
|
1314
1326
|
const tags = tagsMatch
|
|
1315
1327
|
? tagsMatch[1].split(",").map((t) => t.trim().replace(/^['"]|['"]$/g, "")).filter(Boolean)
|
|
1316
1328
|
: [];
|
|
1317
|
-
|
|
1329
|
+
let updatedAt: string | null = null;
|
|
1330
|
+
try { updatedAt = statSync(abs).mtime.toISOString(); } catch { /* ignore */ }
|
|
1331
|
+
results.push({
|
|
1332
|
+
id,
|
|
1333
|
+
title,
|
|
1334
|
+
content,
|
|
1335
|
+
tags,
|
|
1336
|
+
sourcePath: path.relative(rootDir, abs),
|
|
1337
|
+
updatedAt,
|
|
1338
|
+
} as T);
|
|
1318
1339
|
}
|
|
1319
1340
|
return results.sort((a, b) => a.id.localeCompare(b.id));
|
|
1320
1341
|
}
|
|
1321
1342
|
|
|
1343
|
+
function readGotchas(rootDir: string): GotchaEntry[] {
|
|
1344
|
+
return readKnowledgeDir<GotchaEntry>(rootDir, "gotchas");
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
function readConventions(rootDir: string): ConventionEntry[] {
|
|
1348
|
+
return readKnowledgeDir<ConventionEntry>(rootDir, "conventions");
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1322
1351
|
function normalizeTodoStatus(raw: unknown): CxxTodo["status"] {
|
|
1323
1352
|
const value = String(raw ?? "pending").toLowerCase();
|
|
1324
1353
|
if (["pending", "active", "paused", "blocked", "done"].includes(value)) return value;
|
|
@@ -1431,6 +1460,7 @@ export function readHarnessState(rootDir: string): HarnessSnapshot {
|
|
|
1431
1460
|
snapshot.missions = readMissions(rootDir, null);
|
|
1432
1461
|
snapshot.ownerHistory = readOwnerHistory(rootDir);
|
|
1433
1462
|
snapshot.gotchas = readGotchas(rootDir);
|
|
1463
|
+
snapshot.conventions = readConventions(rootDir);
|
|
1434
1464
|
snapshot.todos = readTodos(rootDir);
|
|
1435
1465
|
snapshot.events = readEvents(rootDir);
|
|
1436
1466
|
return snapshot;
|
|
@@ -1485,6 +1515,7 @@ export function readHarnessState(rootDir: string): HarnessSnapshot {
|
|
|
1485
1515
|
missions: readMissions(rootDir, progress),
|
|
1486
1516
|
ownerHistory: readOwnerHistory(rootDir),
|
|
1487
1517
|
gotchas: readGotchas(rootDir),
|
|
1518
|
+
conventions: readConventions(rootDir),
|
|
1488
1519
|
todos: readTodos(rootDir),
|
|
1489
1520
|
events: readEvents(rootDir),
|
|
1490
1521
|
};
|
|
@@ -292,6 +292,7 @@ export interface HarnessSnapshot {
|
|
|
292
292
|
missions: MissionDoc[];
|
|
293
293
|
ownerHistory: OwnerPromptEntry[];
|
|
294
294
|
gotchas: GotchaEntry[];
|
|
295
|
+
conventions: ConventionEntry[];
|
|
295
296
|
todos: CxxTodo[];
|
|
296
297
|
events: HarnessEvent[];
|
|
297
298
|
}
|
|
@@ -362,6 +363,17 @@ export interface GotchaEntry {
|
|
|
362
363
|
title: string;
|
|
363
364
|
content: string;
|
|
364
365
|
tags: string[];
|
|
366
|
+
sourcePath?: string | null;
|
|
367
|
+
updatedAt?: string | null;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export interface ConventionEntry {
|
|
371
|
+
id: string;
|
|
372
|
+
title: string;
|
|
373
|
+
content: string;
|
|
374
|
+
tags: string[];
|
|
375
|
+
sourcePath?: string | null;
|
|
376
|
+
updatedAt?: string | null;
|
|
365
377
|
}
|
|
366
378
|
|
|
367
379
|
export type OrgRole = "owner" | "ceo" | "coo" | "cdo" | "cto" | "cqo" | "ops";
|