@gh-symphony/cli 0.0.17 → 0.0.18
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 +25 -0
- package/dist/{chunk-IWR4UQEJ.js → chunk-5YLETHMR.js} +9 -358
- package/dist/chunk-62L6QQE6.js +362 -0
- package/dist/{chunk-JO3AXHQI.js → chunk-7UBUBSMH.js} +6 -2
- package/dist/chunk-C7G7RJ4G.js +146 -0
- package/dist/{chunk-EFMFGOWM.js → chunk-LZE6YUSB.js} +267 -53
- package/dist/{chunk-TF3QNWNC.js → chunk-OL73UN2X.js} +246 -212
- package/dist/{chunk-6HBZC3BE.js → chunk-XN5ABWZ6.js} +23 -5
- package/dist/{chunk-76QPITKI.js → chunk-Y6TYJMNT.js} +1 -1
- package/dist/{chunk-MHIWAIVD.js → chunk-ZYYY55WB.js} +70 -33
- package/dist/doctor-3QT5CZN4.js +532 -0
- package/dist/index.js +21 -9
- package/dist/{init-EZXQAXZM.js → init-E432UZ32.js} +3 -2
- package/dist/{logs-6LNGT2GF.js → logs-6JKKYDGJ.js} +1 -1
- package/dist/{project-557FE2GD.js → project-O57C32WF.js} +14 -12
- package/dist/{recover-LVBI2TGH.js → recover-UGUTQTWA.js} +3 -3
- package/dist/{run-WITYAYFZ.js → run-5H2R6CHB.js} +3 -3
- package/dist/{start-JUFKNL3N.js → start-5JGGJIMC.js} +5 -5
- package/dist/{status-3WK5BWRZ.js → status-QSCFVGRQ.js} +2 -2
- package/dist/{stop-AA3AP5M6.js → stop-7MFCBQVW.js} +2 -2
- package/dist/{version-YVM2A25J.js → version-N7YXKG6V.js} +1 -1
- package/dist/worker-entry.js +16 -10
- package/package.json +2 -2
- package/dist/chunk-TH5QPO3Y.js +0 -67
|
@@ -1,139 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
// ../core/dist/contracts/status-surface.js
|
|
4
|
-
var WORKFLOW_EXECUTION_PHASES = [
|
|
5
|
-
"planning",
|
|
6
|
-
"human-review",
|
|
7
|
-
"implementation",
|
|
8
|
-
"awaiting-merge",
|
|
9
|
-
"completed"
|
|
10
|
-
];
|
|
11
|
-
function isWorkflowExecutionPhase(value) {
|
|
12
|
-
return typeof value === "string" && WORKFLOW_EXECUTION_PHASES.includes(value);
|
|
13
|
-
}
|
|
14
|
-
var SESSION_EXIT_CLASSIFICATIONS = [
|
|
15
|
-
"completed",
|
|
16
|
-
"budget-exceeded",
|
|
17
|
-
"convergence-detected",
|
|
18
|
-
"max-turns-reached",
|
|
19
|
-
"user-input-required",
|
|
20
|
-
"timeout",
|
|
21
|
-
"error"
|
|
22
|
-
];
|
|
23
|
-
function isSessionExitClassification(value) {
|
|
24
|
-
return typeof value === "string" && SESSION_EXIT_CLASSIFICATIONS.includes(value);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// ../core/dist/contracts/run-attempt-phase.js
|
|
28
|
-
var RUN_ATTEMPT_PHASES = [
|
|
29
|
-
"preparing_workspace",
|
|
30
|
-
"building_prompt",
|
|
31
|
-
"launching_agent",
|
|
32
|
-
"initializing_session",
|
|
33
|
-
"streaming_turn",
|
|
34
|
-
"finishing",
|
|
35
|
-
"succeeded",
|
|
36
|
-
"failed",
|
|
37
|
-
"timed_out",
|
|
38
|
-
"stalled",
|
|
39
|
-
"canceled_by_reconciliation"
|
|
40
|
-
];
|
|
41
|
-
function isRunAttemptPhase(value) {
|
|
42
|
-
return typeof value === "string" && RUN_ATTEMPT_PHASES.includes(value);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// ../core/dist/contracts/orchestrator-channel.js
|
|
46
|
-
function isRecord(value) {
|
|
47
|
-
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
48
|
-
}
|
|
49
|
-
function isTokenUsage(value) {
|
|
50
|
-
if (!isRecord(value)) {
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
return typeof value.inputTokens === "number" && typeof value.outputTokens === "number" && typeof value.totalTokens === "number";
|
|
54
|
-
}
|
|
55
|
-
function isSessionInfo(value) {
|
|
56
|
-
if (!isRecord(value)) {
|
|
57
|
-
return false;
|
|
58
|
-
}
|
|
59
|
-
return (typeof value.threadId === "string" || value.threadId === null) && (typeof value.turnId === "string" || value.turnId === null) && typeof value.turnCount === "number" && (typeof value.sessionId === "string" || value.sessionId === null) && (!("exitClassification" in value) || value.exitClassification === void 0 || value.exitClassification === null || isSessionExitClassification(value.exitClassification));
|
|
60
|
-
}
|
|
61
|
-
function isNullableString(value) {
|
|
62
|
-
return typeof value === "string" || value === null;
|
|
63
|
-
}
|
|
64
|
-
function isTurnEventBase(value) {
|
|
65
|
-
return typeof value.startedAt === "string" && isNullableString(value.threadId) && isNullableString(value.turnId) && typeof value.turnCount === "number" && isNullableString(value.sessionId);
|
|
66
|
-
}
|
|
67
|
-
function isOrchestratorChannelEvent(value) {
|
|
68
|
-
if (!isRecord(value)) {
|
|
69
|
-
return false;
|
|
70
|
-
}
|
|
71
|
-
if (typeof value.issueId !== "string") {
|
|
72
|
-
return false;
|
|
73
|
-
}
|
|
74
|
-
if (value.type === "codex_update") {
|
|
75
|
-
if (typeof value.lastEventAt !== "string") {
|
|
76
|
-
return false;
|
|
77
|
-
}
|
|
78
|
-
if ("event" in value && value.event !== void 0 && typeof value.event !== "string") {
|
|
79
|
-
return false;
|
|
80
|
-
}
|
|
81
|
-
if ("tokenUsage" in value && value.tokenUsage !== void 0 && !isTokenUsage(value.tokenUsage)) {
|
|
82
|
-
return false;
|
|
83
|
-
}
|
|
84
|
-
if ("rateLimits" in value && value.rateLimits !== void 0 && !isRecord(value.rateLimits)) {
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
87
|
-
if ("sessionInfo" in value && value.sessionInfo !== void 0 && !isSessionInfo(value.sessionInfo)) {
|
|
88
|
-
return false;
|
|
89
|
-
}
|
|
90
|
-
if ("executionPhase" in value && value.executionPhase !== void 0 && value.executionPhase !== null && !isWorkflowExecutionPhase(value.executionPhase)) {
|
|
91
|
-
return false;
|
|
92
|
-
}
|
|
93
|
-
if ("runPhase" in value && value.runPhase !== void 0 && value.runPhase !== null && !isRunAttemptPhase(value.runPhase)) {
|
|
94
|
-
return false;
|
|
95
|
-
}
|
|
96
|
-
if ("lastError" in value && value.lastError !== void 0 && value.lastError !== null && typeof value.lastError !== "string") {
|
|
97
|
-
return false;
|
|
98
|
-
}
|
|
99
|
-
return true;
|
|
100
|
-
}
|
|
101
|
-
if (value.type === "heartbeat") {
|
|
102
|
-
if (value.lastEventAt !== null && typeof value.lastEventAt !== "string") {
|
|
103
|
-
return false;
|
|
104
|
-
}
|
|
105
|
-
if (!isTokenUsage(value.tokenUsage)) {
|
|
106
|
-
return false;
|
|
107
|
-
}
|
|
108
|
-
if (value.rateLimits !== null && !isRecord(value.rateLimits)) {
|
|
109
|
-
return false;
|
|
110
|
-
}
|
|
111
|
-
if (value.sessionInfo !== null && !isSessionInfo(value.sessionInfo)) {
|
|
112
|
-
return false;
|
|
113
|
-
}
|
|
114
|
-
if (value.executionPhase !== null && !isWorkflowExecutionPhase(value.executionPhase)) {
|
|
115
|
-
return false;
|
|
116
|
-
}
|
|
117
|
-
if (value.runPhase !== null && !isRunAttemptPhase(value.runPhase)) {
|
|
118
|
-
return false;
|
|
119
|
-
}
|
|
120
|
-
if (value.lastError !== null && typeof value.lastError !== "string") {
|
|
121
|
-
return false;
|
|
122
|
-
}
|
|
123
|
-
return true;
|
|
124
|
-
}
|
|
125
|
-
if (value.type === "turn_started") {
|
|
126
|
-
return isTurnEventBase(value);
|
|
127
|
-
}
|
|
128
|
-
if (value.type === "turn_completed") {
|
|
129
|
-
return isTurnEventBase(value) && typeof value.completedAt === "string" && typeof value.durationMs === "number" && isTokenUsage(value.tokenUsage);
|
|
130
|
-
}
|
|
131
|
-
if (value.type === "turn_failed") {
|
|
132
|
-
return isTurnEventBase(value) && typeof value.failedAt === "string" && typeof value.durationMs === "number" && isTokenUsage(value.tokenUsage) && isNullableString(value.error);
|
|
133
|
-
}
|
|
134
|
-
return false;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
3
|
// ../core/dist/workflow/lifecycle.js
|
|
138
4
|
var DEFAULT_WORKFLOW_LIFECYCLE = {
|
|
139
5
|
stateFieldName: "Status",
|
|
@@ -164,6 +30,7 @@ var DEFAULT_MAX_RETRY_BACKOFF_MS = 3e5;
|
|
|
164
30
|
var DEFAULT_MAX_DELAY_MS = DEFAULT_MAX_RETRY_BACKOFF_MS;
|
|
165
31
|
var DEFAULT_BASE_DELAY_MS = 1e4;
|
|
166
32
|
var DEFAULT_MAX_TURNS = 20;
|
|
33
|
+
var DEFAULT_MAX_FAILURE_RETRIES = 10;
|
|
167
34
|
var DEFAULT_READ_TIMEOUT_MS = 5e3;
|
|
168
35
|
var DEFAULT_TURN_TIMEOUT_MS = 36e5;
|
|
169
36
|
var DEFAULT_STALL_TIMEOUT_MS = 3e5;
|
|
@@ -194,6 +61,7 @@ var DEFAULT_WORKFLOW_AGENT = {
|
|
|
194
61
|
maxConcurrentAgents: DEFAULT_MAX_CONCURRENT_AGENTS,
|
|
195
62
|
maxRetryBackoffMs: DEFAULT_MAX_RETRY_BACKOFF_MS,
|
|
196
63
|
maxConcurrentAgentsByState: {},
|
|
64
|
+
maxFailureRetries: DEFAULT_MAX_FAILURE_RETRIES,
|
|
197
65
|
maxTurns: DEFAULT_MAX_TURNS,
|
|
198
66
|
retryBaseDelayMs: DEFAULT_BASE_DELAY_MS
|
|
199
67
|
};
|
|
@@ -282,6 +150,7 @@ function parseWorkflowMarkdown(markdown, env = process.env, options = {}) {
|
|
|
282
150
|
maxConcurrentAgents: readOptionalIntegerLike(agent, "max_concurrent_agents") ?? DEFAULT_MAX_CONCURRENT_AGENTS,
|
|
283
151
|
maxRetryBackoffMs: readOptionalIntegerLike(agent, "max_retry_backoff_ms") ?? DEFAULT_MAX_RETRY_BACKOFF_MS,
|
|
284
152
|
maxConcurrentAgentsByState,
|
|
153
|
+
maxFailureRetries: readOptionalIntegerLike(agent, "max_failure_retries") ?? DEFAULT_MAX_FAILURE_RETRIES,
|
|
285
154
|
maxTurns: readOptionalIntegerLike(agent, "max_turns") ?? DEFAULT_MAX_TURNS,
|
|
286
155
|
retryBaseDelayMs: readOptionalIntegerLike(agent, "retry_base_delay_ms") ?? DEFAULT_BASE_DELAY_MS
|
|
287
156
|
},
|
|
@@ -536,6 +405,207 @@ function matchOptionalSection(markdown, heading) {
|
|
|
536
405
|
return match?.[1]?.trim() ?? null;
|
|
537
406
|
}
|
|
538
407
|
|
|
408
|
+
// ../core/dist/contracts/status-surface.js
|
|
409
|
+
var WORKFLOW_EXECUTION_PHASES = [
|
|
410
|
+
"planning",
|
|
411
|
+
"human-review",
|
|
412
|
+
"implementation",
|
|
413
|
+
"awaiting-merge",
|
|
414
|
+
"completed"
|
|
415
|
+
];
|
|
416
|
+
function isWorkflowExecutionPhase(value) {
|
|
417
|
+
return typeof value === "string" && WORKFLOW_EXECUTION_PHASES.includes(value);
|
|
418
|
+
}
|
|
419
|
+
var SESSION_EXIT_CLASSIFICATIONS = [
|
|
420
|
+
"completed",
|
|
421
|
+
"budget-exceeded",
|
|
422
|
+
"convergence-detected",
|
|
423
|
+
"max-turns-reached",
|
|
424
|
+
"user-input-required",
|
|
425
|
+
"timeout",
|
|
426
|
+
"error"
|
|
427
|
+
];
|
|
428
|
+
function isSessionExitClassification(value) {
|
|
429
|
+
return typeof value === "string" && SESSION_EXIT_CLASSIFICATIONS.includes(value);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// ../core/dist/contracts/run-attempt-phase.js
|
|
433
|
+
var RUN_ATTEMPT_PHASES = [
|
|
434
|
+
"preparing_workspace",
|
|
435
|
+
"building_prompt",
|
|
436
|
+
"launching_agent",
|
|
437
|
+
"initializing_session",
|
|
438
|
+
"streaming_turn",
|
|
439
|
+
"finishing",
|
|
440
|
+
"succeeded",
|
|
441
|
+
"failed",
|
|
442
|
+
"timed_out",
|
|
443
|
+
"stalled",
|
|
444
|
+
"canceled_by_reconciliation"
|
|
445
|
+
];
|
|
446
|
+
function isRunAttemptPhase(value) {
|
|
447
|
+
return typeof value === "string" && RUN_ATTEMPT_PHASES.includes(value);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// ../core/dist/contracts/orchestrator-channel.js
|
|
451
|
+
function isRecord(value) {
|
|
452
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
453
|
+
}
|
|
454
|
+
function isTokenUsage(value) {
|
|
455
|
+
if (!isRecord(value)) {
|
|
456
|
+
return false;
|
|
457
|
+
}
|
|
458
|
+
return typeof value.inputTokens === "number" && typeof value.outputTokens === "number" && typeof value.totalTokens === "number";
|
|
459
|
+
}
|
|
460
|
+
function isSessionInfo(value) {
|
|
461
|
+
if (!isRecord(value)) {
|
|
462
|
+
return false;
|
|
463
|
+
}
|
|
464
|
+
return (typeof value.threadId === "string" || value.threadId === null) && (typeof value.turnId === "string" || value.turnId === null) && typeof value.turnCount === "number" && (typeof value.sessionId === "string" || value.sessionId === null) && (!("exitClassification" in value) || value.exitClassification === void 0 || value.exitClassification === null || isSessionExitClassification(value.exitClassification));
|
|
465
|
+
}
|
|
466
|
+
function isNullableString(value) {
|
|
467
|
+
return typeof value === "string" || value === null;
|
|
468
|
+
}
|
|
469
|
+
function isTurnEventBase(value) {
|
|
470
|
+
return typeof value.startedAt === "string" && isNullableString(value.threadId) && isNullableString(value.turnId) && typeof value.turnCount === "number" && isNullableString(value.sessionId);
|
|
471
|
+
}
|
|
472
|
+
function isOrchestratorChannelEvent(value) {
|
|
473
|
+
if (!isRecord(value)) {
|
|
474
|
+
return false;
|
|
475
|
+
}
|
|
476
|
+
if (typeof value.issueId !== "string") {
|
|
477
|
+
return false;
|
|
478
|
+
}
|
|
479
|
+
if (value.type === "codex_update") {
|
|
480
|
+
if (typeof value.lastEventAt !== "string") {
|
|
481
|
+
return false;
|
|
482
|
+
}
|
|
483
|
+
if ("event" in value && value.event !== void 0 && typeof value.event !== "string") {
|
|
484
|
+
return false;
|
|
485
|
+
}
|
|
486
|
+
if ("tokenUsage" in value && value.tokenUsage !== void 0 && !isTokenUsage(value.tokenUsage)) {
|
|
487
|
+
return false;
|
|
488
|
+
}
|
|
489
|
+
if ("rateLimits" in value && value.rateLimits !== void 0 && !isRecord(value.rateLimits)) {
|
|
490
|
+
return false;
|
|
491
|
+
}
|
|
492
|
+
if ("sessionInfo" in value && value.sessionInfo !== void 0 && !isSessionInfo(value.sessionInfo)) {
|
|
493
|
+
return false;
|
|
494
|
+
}
|
|
495
|
+
if ("executionPhase" in value && value.executionPhase !== void 0 && value.executionPhase !== null && !isWorkflowExecutionPhase(value.executionPhase)) {
|
|
496
|
+
return false;
|
|
497
|
+
}
|
|
498
|
+
if ("runPhase" in value && value.runPhase !== void 0 && value.runPhase !== null && !isRunAttemptPhase(value.runPhase)) {
|
|
499
|
+
return false;
|
|
500
|
+
}
|
|
501
|
+
if ("lastError" in value && value.lastError !== void 0 && value.lastError !== null && typeof value.lastError !== "string") {
|
|
502
|
+
return false;
|
|
503
|
+
}
|
|
504
|
+
return true;
|
|
505
|
+
}
|
|
506
|
+
if (value.type === "heartbeat") {
|
|
507
|
+
if (value.lastEventAt !== null && typeof value.lastEventAt !== "string") {
|
|
508
|
+
return false;
|
|
509
|
+
}
|
|
510
|
+
if (!isTokenUsage(value.tokenUsage)) {
|
|
511
|
+
return false;
|
|
512
|
+
}
|
|
513
|
+
if (value.rateLimits !== null && !isRecord(value.rateLimits)) {
|
|
514
|
+
return false;
|
|
515
|
+
}
|
|
516
|
+
if (value.sessionInfo !== null && !isSessionInfo(value.sessionInfo)) {
|
|
517
|
+
return false;
|
|
518
|
+
}
|
|
519
|
+
if (value.executionPhase !== null && !isWorkflowExecutionPhase(value.executionPhase)) {
|
|
520
|
+
return false;
|
|
521
|
+
}
|
|
522
|
+
if (value.runPhase !== null && !isRunAttemptPhase(value.runPhase)) {
|
|
523
|
+
return false;
|
|
524
|
+
}
|
|
525
|
+
if (value.lastError !== null && typeof value.lastError !== "string") {
|
|
526
|
+
return false;
|
|
527
|
+
}
|
|
528
|
+
return true;
|
|
529
|
+
}
|
|
530
|
+
if (value.type === "turn_started") {
|
|
531
|
+
return isTurnEventBase(value);
|
|
532
|
+
}
|
|
533
|
+
if (value.type === "turn_completed") {
|
|
534
|
+
return isTurnEventBase(value) && typeof value.completedAt === "string" && typeof value.durationMs === "number" && isTokenUsage(value.tokenUsage);
|
|
535
|
+
}
|
|
536
|
+
if (value.type === "turn_failed") {
|
|
537
|
+
return isTurnEventBase(value) && typeof value.failedAt === "string" && typeof value.durationMs === "number" && isTokenUsage(value.tokenUsage) && isNullableString(value.error);
|
|
538
|
+
}
|
|
539
|
+
return false;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
// ../core/dist/workflow/loader.js
|
|
543
|
+
import { createHash } from "crypto";
|
|
544
|
+
import { access, readFile, stat } from "fs/promises";
|
|
545
|
+
import { constants } from "fs";
|
|
546
|
+
var WorkflowConfigStore = class {
|
|
547
|
+
cache = /* @__PURE__ */ new Map();
|
|
548
|
+
async load(workflowPath, env = process.env) {
|
|
549
|
+
await access(workflowPath, constants.R_OK);
|
|
550
|
+
const fileStat = await stat(workflowPath);
|
|
551
|
+
const fingerprint = `${fileStat.mtimeMs}:${fileStat.size}`;
|
|
552
|
+
const cached = this.cache.get(workflowPath);
|
|
553
|
+
if (cached && cached.fingerprint === fingerprint) {
|
|
554
|
+
return toWorkflowResolution(workflowPath, cached.workflow, {
|
|
555
|
+
isValid: true,
|
|
556
|
+
usedLastKnownGood: false,
|
|
557
|
+
validationError: null
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
const markdown = await readFile(workflowPath, "utf8");
|
|
561
|
+
try {
|
|
562
|
+
const workflow = parseWorkflowMarkdown(markdown, env);
|
|
563
|
+
this.cache.set(workflowPath, {
|
|
564
|
+
fingerprint,
|
|
565
|
+
workflow,
|
|
566
|
+
loadedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
567
|
+
});
|
|
568
|
+
return toWorkflowResolution(workflowPath, workflow, {
|
|
569
|
+
isValid: true,
|
|
570
|
+
usedLastKnownGood: false,
|
|
571
|
+
validationError: null
|
|
572
|
+
});
|
|
573
|
+
} catch (error) {
|
|
574
|
+
if (cached) {
|
|
575
|
+
return toWorkflowResolution(workflowPath, cached.workflow, {
|
|
576
|
+
isValid: false,
|
|
577
|
+
usedLastKnownGood: true,
|
|
578
|
+
validationError: error instanceof Error ? error.message : "Invalid workflow definition."
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
throw error;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
};
|
|
585
|
+
function createDefaultWorkflowResolution() {
|
|
586
|
+
return createInvalidWorkflowResolution(null, "missing_workflow_file");
|
|
587
|
+
}
|
|
588
|
+
function createInvalidWorkflowResolution(workflowPath, validationError) {
|
|
589
|
+
return toWorkflowResolution(workflowPath, DEFAULT_WORKFLOW_DEFINITION, {
|
|
590
|
+
isValid: false,
|
|
591
|
+
usedLastKnownGood: false,
|
|
592
|
+
validationError
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
function toWorkflowResolution(workflowPath, workflow, metadata) {
|
|
596
|
+
return {
|
|
597
|
+
workflowPath,
|
|
598
|
+
workflow,
|
|
599
|
+
lifecycle: workflow.lifecycle,
|
|
600
|
+
promptTemplate: workflow.promptTemplate,
|
|
601
|
+
agentCommand: workflow.agentCommand,
|
|
602
|
+
hookPath: workflow.hookPath ?? "",
|
|
603
|
+
isValid: metadata.isValid,
|
|
604
|
+
usedLastKnownGood: metadata.usedLastKnownGood,
|
|
605
|
+
validationError: metadata.validationError
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
|
|
539
609
|
// ../core/dist/workflow/render.js
|
|
540
610
|
import { Liquid, ParseError, RenderError, TokenizationError, UndefinedVariableError } from "liquidjs";
|
|
541
611
|
function buildPromptVariables(issue, options) {
|
|
@@ -665,9 +735,12 @@ function readEnvFile(path) {
|
|
|
665
735
|
}, {});
|
|
666
736
|
}
|
|
667
737
|
|
|
738
|
+
// ../core/dist/workspace/safety.js
|
|
739
|
+
import { resolve } from "path";
|
|
740
|
+
|
|
668
741
|
// ../core/dist/workspace/identity.js
|
|
669
|
-
import { resolve, join } from "path";
|
|
670
|
-
import { createHash } from "crypto";
|
|
742
|
+
import { resolve as resolve2, join } from "path";
|
|
743
|
+
import { createHash as createHash2 } from "crypto";
|
|
671
744
|
function deriveIssueWorkspaceKey(identity, issueIdentifier) {
|
|
672
745
|
if (issueIdentifier) {
|
|
673
746
|
return deriveIssueWorkspaceKeyFromIdentifier(issueIdentifier);
|
|
@@ -687,11 +760,11 @@ function deriveLegacyIssueWorkspaceKey(identity) {
|
|
|
687
760
|
identity.adapter,
|
|
688
761
|
identity.issueSubjectId
|
|
689
762
|
].join(":");
|
|
690
|
-
return
|
|
763
|
+
return createHash2("sha256").update(input).digest("hex").slice(0, 16);
|
|
691
764
|
}
|
|
692
765
|
function resolveIssueWorkspaceDirectory(projectDirectory, workspaceKey) {
|
|
693
|
-
const normalizedProjectDirectory =
|
|
694
|
-
const candidate =
|
|
766
|
+
const normalizedProjectDirectory = resolve2(projectDirectory);
|
|
767
|
+
const candidate = resolve2(normalizedProjectDirectory, "issues", workspaceKey);
|
|
695
768
|
if (!candidate.startsWith(`${normalizedProjectDirectory}/`)) {
|
|
696
769
|
throw new Error("Issue workspace path escapes the configured project directory.");
|
|
697
770
|
}
|
|
@@ -836,6 +909,7 @@ function normalizeHookCommand(command) {
|
|
|
836
909
|
// ../core/dist/observability/snapshot-builder.js
|
|
837
910
|
function buildProjectSnapshot(input) {
|
|
838
911
|
const { project, activeRuns, allRuns, summary, lastTickAt, lastError, rateLimits } = input;
|
|
912
|
+
const cumulativeTokenUsageByIssue = aggregateTokenUsageByIssue(allRuns ?? activeRuns);
|
|
839
913
|
return {
|
|
840
914
|
projectId: project.projectId,
|
|
841
915
|
slug: project.slug,
|
|
@@ -867,7 +941,7 @@ function buildProjectSnapshot(input) {
|
|
|
867
941
|
lastEventAt: run.lastEventAt ?? null,
|
|
868
942
|
executionPhase: run.executionPhase ?? null,
|
|
869
943
|
runPhase: run.runPhase ?? null,
|
|
870
|
-
tokenUsage: run.tokenUsage
|
|
944
|
+
tokenUsage: attachCumulativeTokenUsage(run.tokenUsage, cumulativeTokenUsageByIssue.get(run.issueId))
|
|
871
945
|
})),
|
|
872
946
|
retryQueue: activeRuns.filter((run) => run.status === "retrying" && run.retryKind).map((run) => ({
|
|
873
947
|
runId: run.runId,
|
|
@@ -880,6 +954,35 @@ function buildProjectSnapshot(input) {
|
|
|
880
954
|
rateLimits: rateLimits ?? null
|
|
881
955
|
};
|
|
882
956
|
}
|
|
957
|
+
function aggregateTokenUsageByIssue(runs) {
|
|
958
|
+
const totals = /* @__PURE__ */ new Map();
|
|
959
|
+
for (const run of runs) {
|
|
960
|
+
if (!run.tokenUsage) {
|
|
961
|
+
continue;
|
|
962
|
+
}
|
|
963
|
+
const current = totals.get(run.issueId) ?? {
|
|
964
|
+
inputTokens: 0,
|
|
965
|
+
outputTokens: 0,
|
|
966
|
+
totalTokens: 0
|
|
967
|
+
};
|
|
968
|
+
current.inputTokens += run.tokenUsage.inputTokens;
|
|
969
|
+
current.outputTokens += run.tokenUsage.outputTokens;
|
|
970
|
+
current.totalTokens += run.tokenUsage.totalTokens;
|
|
971
|
+
totals.set(run.issueId, current);
|
|
972
|
+
}
|
|
973
|
+
return totals;
|
|
974
|
+
}
|
|
975
|
+
function attachCumulativeTokenUsage(tokenUsage, cumulative) {
|
|
976
|
+
if (!tokenUsage) {
|
|
977
|
+
return void 0;
|
|
978
|
+
}
|
|
979
|
+
return {
|
|
980
|
+
...tokenUsage,
|
|
981
|
+
cumulativeInputTokens: cumulative?.inputTokens ?? tokenUsage.inputTokens,
|
|
982
|
+
cumulativeOutputTokens: cumulative?.outputTokens ?? tokenUsage.outputTokens,
|
|
983
|
+
cumulativeTotalTokens: cumulative?.totalTokens ?? tokenUsage.totalTokens
|
|
984
|
+
};
|
|
985
|
+
}
|
|
883
986
|
function aggregateTokenUsage(runs, lastTickAt) {
|
|
884
987
|
let inputTokens = 0;
|
|
885
988
|
let outputTokens = 0;
|
|
@@ -908,10 +1011,10 @@ function aggregateTokenUsage(runs, lastTickAt) {
|
|
|
908
1011
|
}
|
|
909
1012
|
|
|
910
1013
|
// ../core/dist/observability/fs-reader.js
|
|
911
|
-
import { readFile, readdir } from "fs/promises";
|
|
1014
|
+
import { readFile as readFile2, readdir } from "fs/promises";
|
|
912
1015
|
async function readJsonFile(path) {
|
|
913
1016
|
try {
|
|
914
|
-
const raw = await
|
|
1017
|
+
const raw = await readFile2(path, "utf8");
|
|
915
1018
|
return JSON.parse(raw);
|
|
916
1019
|
} catch (error) {
|
|
917
1020
|
if (isFileMissing(error)) {
|
|
@@ -1020,82 +1123,13 @@ function mapIssueOrchestrationStateToStatus(state) {
|
|
|
1020
1123
|
}
|
|
1021
1124
|
}
|
|
1022
1125
|
|
|
1023
|
-
// ../core/dist/workflow/loader.js
|
|
1024
|
-
import { createHash as createHash2 } from "crypto";
|
|
1025
|
-
import { access, readFile as readFile2, stat } from "fs/promises";
|
|
1026
|
-
import { constants } from "fs";
|
|
1027
|
-
var WorkflowConfigStore = class {
|
|
1028
|
-
cache = /* @__PURE__ */ new Map();
|
|
1029
|
-
async load(workflowPath, env = process.env) {
|
|
1030
|
-
await access(workflowPath, constants.R_OK);
|
|
1031
|
-
const fileStat = await stat(workflowPath);
|
|
1032
|
-
const fingerprint = `${fileStat.mtimeMs}:${fileStat.size}`;
|
|
1033
|
-
const cached = this.cache.get(workflowPath);
|
|
1034
|
-
if (cached && cached.fingerprint === fingerprint) {
|
|
1035
|
-
return toWorkflowResolution(workflowPath, cached.workflow, {
|
|
1036
|
-
isValid: true,
|
|
1037
|
-
usedLastKnownGood: false,
|
|
1038
|
-
validationError: null
|
|
1039
|
-
});
|
|
1040
|
-
}
|
|
1041
|
-
const markdown = await readFile2(workflowPath, "utf8");
|
|
1042
|
-
try {
|
|
1043
|
-
const workflow = parseWorkflowMarkdown(markdown, env);
|
|
1044
|
-
this.cache.set(workflowPath, {
|
|
1045
|
-
fingerprint,
|
|
1046
|
-
workflow,
|
|
1047
|
-
loadedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1048
|
-
});
|
|
1049
|
-
return toWorkflowResolution(workflowPath, workflow, {
|
|
1050
|
-
isValid: true,
|
|
1051
|
-
usedLastKnownGood: false,
|
|
1052
|
-
validationError: null
|
|
1053
|
-
});
|
|
1054
|
-
} catch (error) {
|
|
1055
|
-
if (cached) {
|
|
1056
|
-
return toWorkflowResolution(workflowPath, cached.workflow, {
|
|
1057
|
-
isValid: false,
|
|
1058
|
-
usedLastKnownGood: true,
|
|
1059
|
-
validationError: error instanceof Error ? error.message : "Invalid workflow definition."
|
|
1060
|
-
});
|
|
1061
|
-
}
|
|
1062
|
-
throw error;
|
|
1063
|
-
}
|
|
1064
|
-
}
|
|
1065
|
-
};
|
|
1066
|
-
function createDefaultWorkflowResolution() {
|
|
1067
|
-
return createInvalidWorkflowResolution(null, "missing_workflow_file");
|
|
1068
|
-
}
|
|
1069
|
-
function createInvalidWorkflowResolution(workflowPath, validationError) {
|
|
1070
|
-
return toWorkflowResolution(workflowPath, DEFAULT_WORKFLOW_DEFINITION, {
|
|
1071
|
-
isValid: false,
|
|
1072
|
-
usedLastKnownGood: false,
|
|
1073
|
-
validationError
|
|
1074
|
-
});
|
|
1075
|
-
}
|
|
1076
|
-
function toWorkflowResolution(workflowPath, workflow, metadata) {
|
|
1077
|
-
return {
|
|
1078
|
-
workflowPath,
|
|
1079
|
-
workflow,
|
|
1080
|
-
lifecycle: workflow.lifecycle,
|
|
1081
|
-
promptTemplate: workflow.promptTemplate,
|
|
1082
|
-
agentCommand: workflow.agentCommand,
|
|
1083
|
-
hookPath: workflow.hookPath ?? "",
|
|
1084
|
-
isValid: metadata.isValid,
|
|
1085
|
-
usedLastKnownGood: metadata.usedLastKnownGood,
|
|
1086
|
-
validationError: metadata.validationError
|
|
1087
|
-
};
|
|
1088
|
-
}
|
|
1089
|
-
|
|
1090
|
-
// ../core/dist/workspace/safety.js
|
|
1091
|
-
import { resolve as resolve2 } from "path";
|
|
1092
|
-
|
|
1093
1126
|
export {
|
|
1094
1127
|
isOrchestratorChannelEvent,
|
|
1095
1128
|
DEFAULT_WORKFLOW_LIFECYCLE,
|
|
1096
1129
|
isStateActive,
|
|
1097
1130
|
isStateTerminal,
|
|
1098
1131
|
matchesWorkflowState,
|
|
1132
|
+
DEFAULT_MAX_FAILURE_RETRIES,
|
|
1099
1133
|
parseWorkflowMarkdown,
|
|
1100
1134
|
WorkflowConfigStore,
|
|
1101
1135
|
createDefaultWorkflowResolution,
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
import {
|
|
20
20
|
handleMissingManagedProjectConfig,
|
|
21
21
|
resolveManagedProjectConfig
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-C7G7RJ4G.js";
|
|
23
23
|
|
|
24
24
|
// src/commands/status.ts
|
|
25
25
|
import { readFile } from "fs/promises";
|
|
@@ -30,7 +30,7 @@ var COL_ID = 24;
|
|
|
30
30
|
var COL_STATUS = 14;
|
|
31
31
|
var COL_PID = 8;
|
|
32
32
|
var COL_AGE_TURN = 12;
|
|
33
|
-
var COL_TOKENS =
|
|
33
|
+
var COL_TOKENS = 17;
|
|
34
34
|
var COL_SESSION = 14;
|
|
35
35
|
var COL_ID_HEADER = COL_ID + 2;
|
|
36
36
|
var identity = (s) => s;
|
|
@@ -63,6 +63,11 @@ function compactSessionId(id) {
|
|
|
63
63
|
function fmtTokens(n) {
|
|
64
64
|
return n.toLocaleString("en-US");
|
|
65
65
|
}
|
|
66
|
+
function fmtTokenPair(delta, cumulative) {
|
|
67
|
+
const left = fmtTokens(delta ?? 0);
|
|
68
|
+
const right = fmtTokens(cumulative ?? delta ?? 0);
|
|
69
|
+
return `${left} / ${right}`;
|
|
70
|
+
}
|
|
66
71
|
function fmtAge(startedAt, now) {
|
|
67
72
|
if (!startedAt) return "0m";
|
|
68
73
|
const diffMs = now - new Date(startedAt).getTime();
|
|
@@ -173,7 +178,10 @@ function activeRunRow(run, now, evtWidth, c) {
|
|
|
173
178
|
const turn = run.turnCount ?? 0;
|
|
174
179
|
const ageTurn = pad(`${age}/${turn}`, COL_AGE_TURN);
|
|
175
180
|
const tokens = pad(
|
|
176
|
-
|
|
181
|
+
fmtTokenPair(
|
|
182
|
+
run.tokenUsage?.totalTokens,
|
|
183
|
+
run.tokenUsage?.cumulativeTotalTokens
|
|
184
|
+
),
|
|
177
185
|
COL_TOKENS,
|
|
178
186
|
"right"
|
|
179
187
|
);
|
|
@@ -260,6 +268,15 @@ function truncate(s, len) {
|
|
|
260
268
|
if (s.length <= len) return s;
|
|
261
269
|
return s.slice(0, len - 3) + "...";
|
|
262
270
|
}
|
|
271
|
+
function formatTokenPair(delta, cumulative) {
|
|
272
|
+
return `${delta.toLocaleString("en-US")} / ${cumulative.toLocaleString("en-US")}`;
|
|
273
|
+
}
|
|
274
|
+
function resolveProjectTokenDelta(snapshot) {
|
|
275
|
+
return snapshot.activeRuns.reduce(
|
|
276
|
+
(sum, run) => sum + (run.tokenUsage?.totalTokens ?? 0),
|
|
277
|
+
0
|
|
278
|
+
);
|
|
279
|
+
}
|
|
263
280
|
function renderLegacyStatus(snapshot, noColor) {
|
|
264
281
|
const apply = noColor ? (s) => stripAnsi(s) : (s) => s;
|
|
265
282
|
const lines = [];
|
|
@@ -326,12 +343,13 @@ function renderLegacyStatus(snapshot, noColor) {
|
|
|
326
343
|
lines.push("");
|
|
327
344
|
}
|
|
328
345
|
if (snapshot.codexTotals) {
|
|
346
|
+
const tokenDelta = resolveProjectTokenDelta(snapshot);
|
|
329
347
|
const tokenStr = apply(
|
|
330
|
-
`Tokens: ${
|
|
348
|
+
`Tokens: ${formatTokenPair(tokenDelta, snapshot.codexTotals.totalTokens)} total`
|
|
331
349
|
);
|
|
332
350
|
lines.push(` ${tokenStr}`);
|
|
333
351
|
} else {
|
|
334
|
-
lines.push(" Tokens: 0
|
|
352
|
+
lines.push(" Tokens: 0 / 0 total");
|
|
335
353
|
}
|
|
336
354
|
return lines.join("\n");
|
|
337
355
|
}
|