@walwal-harness/cli 7.1.14 → 7.1.16
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 +2 -0
- package/apps/harness-dashboard/components/Scene.tsx +1 -0
- package/apps/harness-dashboard/components/drawer/MissionDocTab.tsx +5 -1
- package/apps/harness-dashboard/components/drawer/MissionFlowTab.tsx +61 -5
- package/apps/harness-dashboard/lib/__tests__/state-mapping.test.ts +24 -0
- package/apps/harness-dashboard/lib/harness-state.ts +34 -0
- package/apps/harness-dashboard/lib/state-mapping.ts +31 -11
- package/apps/harness-dashboard/lib/types.ts +14 -0
- package/bin/init.js +8 -0
- package/package.json +1 -1
- package/scripts/harness-user-prompt-submit.sh +22 -0
package/README.md
CHANGED
|
@@ -223,6 +223,8 @@ harness-hiring → register and onboard worker
|
|
|
223
223
|
|
|
224
224
|
| Version | Summary |
|
|
225
225
|
|---|---|
|
|
226
|
+
| 7.1.16 | `migrate` now always fully replaces /goal, /submission, /hot-fix commands regardless of current state |
|
|
227
|
+
| 7.1.15 | Dashboard: reset embedded View Doc state when the selected mission or document target changes |
|
|
226
228
|
| 7.1.14 | Owner acceptance gate: Owner is final reviewer, not tester; dashboard org-node clicks initialize the detail pane |
|
|
227
229
|
| 7.1.13 | Dashboard: full-viewport split workspace, hidden pane scrollbars, and detail scroll reset on selection |
|
|
228
230
|
| 7.1.12 | Dashboard: split workspace panes now scroll independently |
|
|
@@ -155,6 +155,7 @@ export function Scene({ snapshot: initial, lang = "ko" }: SceneProps) {
|
|
|
155
155
|
<MissionFlowTab
|
|
156
156
|
mission={selectedMission ?? snapshot.missions?.[0] ?? null}
|
|
157
157
|
ownerHistory={snapshot.ownerHistory ?? []}
|
|
158
|
+
runtime={snapshot.runtime}
|
|
158
159
|
/>
|
|
159
160
|
)}
|
|
160
161
|
{drawerTab === "history" && (
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useState } from "react";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
3
|
import type { MissionDoc } from "@/lib/types";
|
|
4
4
|
import { MarkdownView } from "@/lib/markdown";
|
|
5
5
|
|
|
@@ -15,6 +15,10 @@ export function MissionDocTab({ missions, role, workerName, fromLabel, toLabel }
|
|
|
15
15
|
const [selectedIdx, setSelectedIdx] = useState(0);
|
|
16
16
|
const mission = missions[selectedIdx];
|
|
17
17
|
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
setSelectedIdx(0);
|
|
20
|
+
}, [role, workerName]);
|
|
21
|
+
|
|
18
22
|
if (!missions.length) {
|
|
19
23
|
return (
|
|
20
24
|
<div className="text-gray-500">
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useState } from "react";
|
|
3
|
-
import type { MissionDoc, OwnerPromptEntry } from "@/lib/types";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import type { MissionDoc, OwnerPromptEntry, RuntimeSnapshot } from "@/lib/types";
|
|
4
4
|
import { MarkdownView } from "@/lib/markdown";
|
|
5
5
|
|
|
6
6
|
type DocView = "overview" | "ceo" | "cto" | "cqo" | "coo" | "cdo" | "ops" | string;
|
|
@@ -8,6 +8,7 @@ type DocView = "overview" | "ceo" | "cto" | "cqo" | "coo" | "cdo" | "ops" | stri
|
|
|
8
8
|
interface Props {
|
|
9
9
|
mission: MissionDoc | null;
|
|
10
10
|
ownerHistory: OwnerPromptEntry[];
|
|
11
|
+
runtime: RuntimeSnapshot;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
// ---------------------------------------------------------------------------
|
|
@@ -222,13 +223,66 @@ function WorkerCard({
|
|
|
222
223
|
// ---------------------------------------------------------------------------
|
|
223
224
|
// Main component
|
|
224
225
|
// ---------------------------------------------------------------------------
|
|
225
|
-
|
|
226
|
+
function RuntimeStrip({ runtime }: { runtime: RuntimeSnapshot }) {
|
|
227
|
+
const isActive = runtime.agentStatus === "running";
|
|
228
|
+
const command = runtime.ownerPrompt?.command ?? "input";
|
|
229
|
+
const summary = runtime.ownerPrompt?.summary ?? null;
|
|
230
|
+
return (
|
|
231
|
+
<div
|
|
232
|
+
data-testid="runtime-strip"
|
|
233
|
+
data-current-agent={runtime.currentAgent ?? ""}
|
|
234
|
+
data-agent-status={runtime.agentStatus}
|
|
235
|
+
className={`rounded border px-2.5 py-2 ${
|
|
236
|
+
isActive
|
|
237
|
+
? "border-cyan-400/30 bg-cyan-400/10"
|
|
238
|
+
: runtime.agentStatus === "blocked" || runtime.agentStatus === "failed"
|
|
239
|
+
? "border-rose-400/30 bg-rose-400/10"
|
|
240
|
+
: "border-gray-700/60 bg-black/20"
|
|
241
|
+
}`}
|
|
242
|
+
>
|
|
243
|
+
<div className="flex flex-wrap items-center gap-1.5">
|
|
244
|
+
<span className="font-mono text-[9px] uppercase tracking-[0.18em] text-gray-500">
|
|
245
|
+
live runtime
|
|
246
|
+
</span>
|
|
247
|
+
<StepChip role={runtime.currentAgent ?? "worker"} label={runtime.currentAgent ?? "none"} />
|
|
248
|
+
<span
|
|
249
|
+
className={`font-mono text-[9px] ${
|
|
250
|
+
isActive ? "text-cyan-300" : "text-gray-400"
|
|
251
|
+
}`}
|
|
252
|
+
>
|
|
253
|
+
{runtime.agentStatus}
|
|
254
|
+
</span>
|
|
255
|
+
{runtime.nextAgent && (
|
|
256
|
+
<span className="font-mono text-[9px] text-gray-500">
|
|
257
|
+
next: {runtime.nextAgent}
|
|
258
|
+
</span>
|
|
259
|
+
)}
|
|
260
|
+
</div>
|
|
261
|
+
{summary && (
|
|
262
|
+
<p className="mt-1.5 text-[10px] leading-relaxed text-gray-400 line-clamp-2">
|
|
263
|
+
<span className="font-mono text-gray-500">{command}</span>
|
|
264
|
+
<span className="text-gray-600"> · </span>
|
|
265
|
+
{summary}
|
|
266
|
+
</p>
|
|
267
|
+
)}
|
|
268
|
+
</div>
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export function MissionFlowTab({ mission, ownerHistory, runtime }: Props) {
|
|
226
273
|
const [docView, setDocView] = useState<DocView>("overview");
|
|
227
274
|
|
|
275
|
+
useEffect(() => {
|
|
276
|
+
setDocView("overview");
|
|
277
|
+
}, [mission?.missionId]);
|
|
278
|
+
|
|
228
279
|
if (!mission) {
|
|
229
280
|
return (
|
|
230
|
-
<div className="
|
|
231
|
-
|
|
281
|
+
<div className="space-y-3">
|
|
282
|
+
<RuntimeStrip runtime={runtime} />
|
|
283
|
+
<div className="text-gray-500 text-xs">
|
|
284
|
+
No mission selected. Click a mission from the timeline below.
|
|
285
|
+
</div>
|
|
232
286
|
</div>
|
|
233
287
|
);
|
|
234
288
|
}
|
|
@@ -249,6 +303,7 @@ export function MissionFlowTab({ mission, ownerHistory }: Props) {
|
|
|
249
303
|
|
|
250
304
|
return (
|
|
251
305
|
<div className="space-y-3">
|
|
306
|
+
<RuntimeStrip runtime={runtime} />
|
|
252
307
|
<button
|
|
253
308
|
type="button"
|
|
254
309
|
onClick={() => setDocView("overview")}
|
|
@@ -335,6 +390,7 @@ export function MissionFlowTab({ mission, ownerHistory }: Props) {
|
|
|
335
390
|
|
|
336
391
|
return (
|
|
337
392
|
<div className="space-y-3">
|
|
393
|
+
<RuntimeStrip runtime={runtime} />
|
|
338
394
|
{/* Mission header */}
|
|
339
395
|
<div>
|
|
340
396
|
<div className="flex items-center gap-2 flex-wrap mb-1">
|
|
@@ -15,6 +15,30 @@ describe("deriveMinifigState", () => {
|
|
|
15
15
|
).toBe("typing");
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
+
it("maps v7 CEO alias to dispatcher and brainstormer", () => {
|
|
19
|
+
const progress = {
|
|
20
|
+
current_agent: "ceo",
|
|
21
|
+
agent_status: "running",
|
|
22
|
+
};
|
|
23
|
+
expect(deriveMinifigState("dispatcher", progress)).toBe("typing");
|
|
24
|
+
expect(deriveMinifigState("brainstormer", progress)).toBe("typing");
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("maps v7 CXX aliases to their dashboard departments", () => {
|
|
28
|
+
expect(
|
|
29
|
+
deriveMinifigState("generator-designer", {
|
|
30
|
+
current_agent: "cdo",
|
|
31
|
+
agent_status: "running",
|
|
32
|
+
})
|
|
33
|
+
).toBe("typing");
|
|
34
|
+
expect(
|
|
35
|
+
deriveMinifigState("service-ops", {
|
|
36
|
+
next_agent: "ops",
|
|
37
|
+
agent_status: "pending",
|
|
38
|
+
})
|
|
39
|
+
).toBe("queued");
|
|
40
|
+
});
|
|
41
|
+
|
|
18
42
|
it("does not return typing when agent_status is not running", () => {
|
|
19
43
|
expect(
|
|
20
44
|
deriveMinifigState("generator-backend", {
|
|
@@ -33,6 +33,7 @@ import type {
|
|
|
33
33
|
RoomId,
|
|
34
34
|
RoomMetrics,
|
|
35
35
|
RoomState,
|
|
36
|
+
RuntimeSnapshot,
|
|
36
37
|
TrackStatus,
|
|
37
38
|
WorkerDocEntry,
|
|
38
39
|
WorkerSnapshot,
|
|
@@ -50,6 +51,13 @@ interface RawProgress {
|
|
|
50
51
|
current_agent?: AgentId | null;
|
|
51
52
|
next_agent?: AgentId | null;
|
|
52
53
|
agent_status?: string;
|
|
54
|
+
updated_at?: string | null;
|
|
55
|
+
owner_prompt?: {
|
|
56
|
+
command?: string;
|
|
57
|
+
summary?: string;
|
|
58
|
+
received_at?: string | null;
|
|
59
|
+
status?: string;
|
|
60
|
+
} | null;
|
|
53
61
|
pipeline?: Pipeline;
|
|
54
62
|
failure?: { agent?: AgentId | null; message?: string | null; location?: string | null; retry_target?: AgentId | null } | null;
|
|
55
63
|
meetings?: {
|
|
@@ -205,6 +213,13 @@ function emptySnapshot(banner: ErrorBanner | null = null, rootDir?: string): Har
|
|
|
205
213
|
evalScores: null,
|
|
206
214
|
errorBanner: banner,
|
|
207
215
|
dashboard: { workers: [], features: [], recentMeetings: [], opsHealth: [], envFiles: [] },
|
|
216
|
+
runtime: {
|
|
217
|
+
currentAgent: null,
|
|
218
|
+
agentStatus: "unknown",
|
|
219
|
+
nextAgent: null,
|
|
220
|
+
updatedAt: null,
|
|
221
|
+
ownerPrompt: null,
|
|
222
|
+
},
|
|
208
223
|
missions: [],
|
|
209
224
|
ownerHistory: [],
|
|
210
225
|
gotchas: [],
|
|
@@ -953,6 +968,24 @@ function buildDashboard(rootDir: string, progress: RawProgress | null): Operatio
|
|
|
953
968
|
};
|
|
954
969
|
}
|
|
955
970
|
|
|
971
|
+
function buildRuntime(progress: RawProgress | null): RuntimeSnapshot {
|
|
972
|
+
const ownerPrompt = progress?.owner_prompt
|
|
973
|
+
? {
|
|
974
|
+
command: progress.owner_prompt.command ?? "input",
|
|
975
|
+
summary: progress.owner_prompt.summary ?? "",
|
|
976
|
+
receivedAt: progress.owner_prompt.received_at ?? null,
|
|
977
|
+
status: progress.owner_prompt.status ?? "unknown",
|
|
978
|
+
}
|
|
979
|
+
: null;
|
|
980
|
+
return {
|
|
981
|
+
currentAgent: progress?.current_agent ?? null,
|
|
982
|
+
agentStatus: progress?.agent_status ?? "unknown",
|
|
983
|
+
nextAgent: progress?.next_agent ?? null,
|
|
984
|
+
updatedAt: progress?.updated_at ?? null,
|
|
985
|
+
ownerPrompt,
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
|
|
956
989
|
function readMissions(rootDir: string, limit = 15): MissionDoc[] {
|
|
957
990
|
const docsDir = path.join(rootDir, ".harness", "documents");
|
|
958
991
|
if (!existsSync(docsDir)) return [];
|
|
@@ -1183,6 +1216,7 @@ export function readHarnessState(rootDir: string): HarnessSnapshot {
|
|
|
1183
1216
|
evalScores,
|
|
1184
1217
|
errorBanner: null,
|
|
1185
1218
|
dashboard,
|
|
1219
|
+
runtime: buildRuntime(progress),
|
|
1186
1220
|
missions: readMissions(rootDir),
|
|
1187
1221
|
ownerHistory: readOwnerHistory(rootDir),
|
|
1188
1222
|
gotchas: readGotchas(rootDir),
|
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
import type { AgentId, Dept, MinifigState } from "./types";
|
|
2
2
|
|
|
3
|
+
const AGENT_ALIASES: Record<string, AgentId[]> = {
|
|
4
|
+
ceo: ["dispatcher", "brainstormer"],
|
|
5
|
+
dispatcher: ["dispatcher"],
|
|
6
|
+
brainstormer: ["brainstormer"],
|
|
7
|
+
coo: ["planner", "coo-developer", "documentationer"],
|
|
8
|
+
planner: ["planner"],
|
|
9
|
+
cdo: ["generator-designer"],
|
|
10
|
+
cto: ["cto", "conductor", "generator-backend", "generator-frontend", "generator-designer", "generator-devops"],
|
|
11
|
+
cqo: ["cqo", "evaluator-functional", "evaluator-visual", "evaluator-code-quality", "evaluator-architecture", "evaluator-security"],
|
|
12
|
+
ops: ["service-ops"],
|
|
13
|
+
"service-ops": ["service-ops"],
|
|
14
|
+
};
|
|
15
|
+
|
|
3
16
|
export interface ProgressSlice {
|
|
4
|
-
current_agent?:
|
|
5
|
-
next_agent?:
|
|
17
|
+
current_agent?: string | null;
|
|
18
|
+
next_agent?: string | null;
|
|
6
19
|
agent_status?: string;
|
|
7
|
-
failure?: { agent?:
|
|
8
|
-
meetings?: { active?:
|
|
20
|
+
failure?: { agent?: string | null; message?: string | null } | null;
|
|
21
|
+
meetings?: { active?: string[] };
|
|
9
22
|
service_ops?: {
|
|
10
23
|
incident?: { open?: Array<{ id: string; dept?: string }> };
|
|
11
24
|
monitor?: { stream_active?: boolean; stream_target?: string | null };
|
|
@@ -42,6 +55,13 @@ export function parseSpawnAgent(action: string | null | undefined): string | nul
|
|
|
42
55
|
return m ? m[1].toLowerCase() : null;
|
|
43
56
|
}
|
|
44
57
|
|
|
58
|
+
function agentMatches(agentId: string, raw: string | null | undefined): boolean {
|
|
59
|
+
if (!raw) return false;
|
|
60
|
+
const key = raw.toLowerCase();
|
|
61
|
+
if (key === agentId) return true;
|
|
62
|
+
return AGENT_ALIASES[key]?.includes(agentId as AgentId) ?? false;
|
|
63
|
+
}
|
|
64
|
+
|
|
45
65
|
function isAgentRunningTrack(
|
|
46
66
|
agentId: string,
|
|
47
67
|
conductor: ProgressSlice["conductor"]
|
|
@@ -49,7 +69,7 @@ function isAgentRunningTrack(
|
|
|
49
69
|
const tracks = conductor?.tracks ?? [];
|
|
50
70
|
return tracks.some(
|
|
51
71
|
(t) =>
|
|
52
|
-
t.owner
|
|
72
|
+
agentMatches(agentId, t.owner) &&
|
|
53
73
|
(t.status === "running" || t.status === "in_progress" || t.status === "active")
|
|
54
74
|
);
|
|
55
75
|
}
|
|
@@ -59,7 +79,7 @@ function isAgentQueuedTrack(
|
|
|
59
79
|
conductor: ProgressSlice["conductor"]
|
|
60
80
|
): boolean {
|
|
61
81
|
const tracks = conductor?.tracks ?? [];
|
|
62
|
-
return tracks.some((t) => t.owner
|
|
82
|
+
return tracks.some((t) => agentMatches(agentId, t.owner) && t.status === "pending");
|
|
63
83
|
}
|
|
64
84
|
|
|
65
85
|
// Priority: red-alert > talking > typing > queued > idle.
|
|
@@ -76,18 +96,18 @@ export function deriveMinifigState(
|
|
|
76
96
|
ctx: DeriveContext = {}
|
|
77
97
|
): MinifigState {
|
|
78
98
|
if (!progress) return "idle";
|
|
79
|
-
if (progress.failure?.agent
|
|
99
|
+
if (agentMatches(agentId, progress.failure?.agent)) return "red-alert";
|
|
80
100
|
if (ctx.dept && ctx.incidentDepts && ctx.incidentDepts.size > 0) {
|
|
81
101
|
if (ctx.dept === "Operations" || ctx.incidentDepts.has(ctx.dept)) {
|
|
82
102
|
return "red-alert";
|
|
83
103
|
}
|
|
84
104
|
}
|
|
85
|
-
const inMeeting = progress.meetings?.active?.
|
|
105
|
+
const inMeeting = progress.meetings?.active?.some((id) => agentMatches(agentId, id)) ?? false;
|
|
86
106
|
if (inMeeting) return "talking";
|
|
87
107
|
|
|
88
108
|
// Parallel-typing signals (any one of these means the agent is working).
|
|
89
109
|
if (
|
|
90
|
-
progress.current_agent
|
|
110
|
+
agentMatches(agentId, progress.current_agent) &&
|
|
91
111
|
progress.agent_status === "running"
|
|
92
112
|
) {
|
|
93
113
|
return "typing";
|
|
@@ -95,7 +115,7 @@ export function deriveMinifigState(
|
|
|
95
115
|
if (isAgentRunningTrack(agentId, progress.conductor)) {
|
|
96
116
|
return "typing";
|
|
97
117
|
}
|
|
98
|
-
if (parseSpawnAgent(progress.conductor?.current_action)
|
|
118
|
+
if (agentMatches(agentId, parseSpawnAgent(progress.conductor?.current_action))) {
|
|
99
119
|
return "typing";
|
|
100
120
|
}
|
|
101
121
|
// G-006: service-ops co-spawned in monitor mode is actively streaming.
|
|
@@ -106,7 +126,7 @@ export function deriveMinifigState(
|
|
|
106
126
|
return "typing";
|
|
107
127
|
}
|
|
108
128
|
if (
|
|
109
|
-
progress.next_agent
|
|
129
|
+
agentMatches(agentId, progress.next_agent) &&
|
|
110
130
|
progress.agent_status !== "blocked" &&
|
|
111
131
|
progress.agent_status !== "failed"
|
|
112
132
|
) {
|
|
@@ -257,6 +257,19 @@ export interface OperationsDashboard {
|
|
|
257
257
|
envFiles: EnvFileSummary[];
|
|
258
258
|
}
|
|
259
259
|
|
|
260
|
+
export interface RuntimeSnapshot {
|
|
261
|
+
currentAgent: string | null;
|
|
262
|
+
agentStatus: string;
|
|
263
|
+
nextAgent: string | null;
|
|
264
|
+
updatedAt: string | null;
|
|
265
|
+
ownerPrompt: {
|
|
266
|
+
command: string;
|
|
267
|
+
summary: string;
|
|
268
|
+
receivedAt: string | null;
|
|
269
|
+
status: string;
|
|
270
|
+
} | null;
|
|
271
|
+
}
|
|
272
|
+
|
|
260
273
|
export interface HarnessSnapshot {
|
|
261
274
|
version: string;
|
|
262
275
|
ts: string;
|
|
@@ -275,6 +288,7 @@ export interface HarnessSnapshot {
|
|
|
275
288
|
evalScores: EvalScores | null;
|
|
276
289
|
errorBanner: ErrorBanner | null;
|
|
277
290
|
dashboard: OperationsDashboard;
|
|
291
|
+
runtime: RuntimeSnapshot;
|
|
278
292
|
missions: MissionDoc[];
|
|
279
293
|
ownerHistory: OwnerPromptEntry[];
|
|
280
294
|
gotchas: GotchaEntry[];
|
package/bin/init.js
CHANGED
|
@@ -1459,6 +1459,14 @@ function showMigrationProposal(flags) {
|
|
|
1459
1459
|
|
|
1460
1460
|
function runMigrate(opts = {}) {
|
|
1461
1461
|
const dryRun = opts.dryRun || false;
|
|
1462
|
+
|
|
1463
|
+
// Always refresh owner-facing commands (full replacement regardless of current state).
|
|
1464
|
+
if (dryRun) {
|
|
1465
|
+
log(' (dry-run) commands: /goal, /submission, /hot-fix 교체 예정');
|
|
1466
|
+
} else {
|
|
1467
|
+
installCommands();
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1462
1470
|
const flags = detectMigrationNeeded();
|
|
1463
1471
|
const gotchaMissingTotal = Object.values(flags.gotchaMissingEntries || {}).reduce((n, a) => n + a.length, 0);
|
|
1464
1472
|
const conventionMissingTotal = Object.values(flags.conventionMissingEntries || {}).reduce((n, a) => n + a.length, 0);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@walwal-harness/cli",
|
|
3
|
-
"version": "7.1.
|
|
3
|
+
"version": "7.1.16",
|
|
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"
|
|
@@ -71,6 +71,28 @@ if [ -n "$PROMPT" ] && [ -d "$CWD/.harness" ]; then
|
|
|
71
71
|
COMMAND_TYPE="hot-fix"
|
|
72
72
|
fi
|
|
73
73
|
echo "$(date +"%Y-%m-%d %H:%M") | user-prompt | ${COMMAND_TYPE} | ${PROMPT_SHORT}" >> "$PROGRESS_LOG"
|
|
74
|
+
if [ "$COMMAND_TYPE" = "goal" ] || [ "$COMMAND_TYPE" = "submission" ] || [ "$COMMAND_TYPE" = "hot-fix" ]; then
|
|
75
|
+
if [ -f "$CWD/.harness/progress.json" ] && command -v jq >/dev/null 2>&1; then
|
|
76
|
+
TMP_PROGRESS="${CWD}/.harness/progress.json.tmp.$$"
|
|
77
|
+
NOW_ISO=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
78
|
+
jq \
|
|
79
|
+
--arg now "$NOW_ISO" \
|
|
80
|
+
--arg command "$COMMAND_TYPE" \
|
|
81
|
+
--arg prompt "$PROMPT_SHORT" \
|
|
82
|
+
'
|
|
83
|
+
.current_agent = "ceo" |
|
|
84
|
+
.agent_status = "running" |
|
|
85
|
+
.next_agent = "ceo" |
|
|
86
|
+
.updated_at = $now |
|
|
87
|
+
.owner_prompt = {
|
|
88
|
+
command: $command,
|
|
89
|
+
summary: $prompt,
|
|
90
|
+
received_at: $now,
|
|
91
|
+
status: "routing"
|
|
92
|
+
}
|
|
93
|
+
' "$CWD/.harness/progress.json" > "$TMP_PROGRESS" && mv "$TMP_PROGRESS" "$CWD/.harness/progress.json"
|
|
94
|
+
fi
|
|
95
|
+
fi
|
|
74
96
|
fi
|
|
75
97
|
fi
|
|
76
98
|
|