@ryanfw/prompt-orchestration-pipeline 0.6.0 → 0.8.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/README.md +1 -2
- package/package.json +1 -2
- package/src/api/validators/json.js +39 -0
- package/src/components/DAGGrid.jsx +392 -303
- package/src/components/JobCard.jsx +13 -11
- package/src/components/JobDetail.jsx +41 -71
- package/src/components/JobTable.jsx +32 -22
- package/src/components/Layout.jsx +0 -21
- package/src/components/LiveText.jsx +47 -0
- package/src/components/TaskDetailSidebar.jsx +216 -0
- package/src/components/TimerText.jsx +82 -0
- package/src/components/ui/RestartJobModal.jsx +140 -0
- package/src/components/ui/toast.jsx +138 -0
- package/src/config/models.js +322 -0
- package/src/config/statuses.js +119 -0
- package/src/core/config.js +2 -164
- package/src/core/file-io.js +1 -1
- package/src/core/module-loader.js +54 -40
- package/src/core/pipeline-runner.js +52 -26
- package/src/core/status-writer.js +147 -3
- package/src/core/symlink-bridge.js +55 -0
- package/src/core/symlink-utils.js +94 -0
- package/src/core/task-runner.js +267 -443
- package/src/llm/index.js +167 -52
- package/src/pages/Code.jsx +57 -3
- package/src/pages/PipelineDetail.jsx +92 -22
- package/src/pages/PromptPipelineDashboard.jsx +15 -36
- package/src/providers/anthropic.js +83 -69
- package/src/providers/base.js +52 -0
- package/src/providers/deepseek.js +17 -34
- package/src/providers/gemini.js +226 -0
- package/src/providers/openai.js +36 -106
- package/src/providers/zhipu.js +136 -0
- package/src/ui/client/adapters/job-adapter.js +16 -26
- package/src/ui/client/api.js +134 -0
- package/src/ui/client/hooks/useJobDetailWithUpdates.js +65 -178
- package/src/ui/client/index.css +9 -0
- package/src/ui/client/index.html +1 -0
- package/src/ui/client/main.jsx +18 -15
- package/src/ui/client/time-store.js +161 -0
- package/src/ui/config-bridge.js +15 -24
- package/src/ui/config-bridge.node.js +15 -24
- package/src/ui/dist/assets/{index-WgJUlSmE.js → index-DqkbzXZ1.js} +1408 -771
- package/src/ui/dist/assets/style-DBF9NQGk.css +62 -0
- package/src/ui/dist/index.html +3 -2
- package/src/ui/public/favicon.svg +12 -0
- package/src/ui/server.js +231 -38
- package/src/ui/transformers/status-transformer.js +18 -31
- package/src/ui/watcher.js +5 -1
- package/src/utils/dag.js +8 -4
- package/src/utils/duration.js +13 -19
- package/src/utils/formatters.js +27 -0
- package/src/utils/geometry-equality.js +83 -0
- package/src/utils/pipelines.js +5 -1
- package/src/utils/time-utils.js +40 -0
- package/src/utils/token-cost-calculator.js +4 -7
- package/src/utils/ui.jsx +14 -16
- package/src/components/ui/select.jsx +0 -27
- package/src/lib/utils.js +0 -6
- package/src/ui/client/hooks/useTicker.js +0 -26
- package/src/ui/config-bridge.browser.js +0 -149
- package/src/ui/dist/assets/style-x0V-5m8e.css +0 -62
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global time store for efficient timer updates
|
|
3
|
+
* Provides a single source of truth for time-based updates with dynamic cadence
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Internal state
|
|
7
|
+
const offset = Date.now() - performance.now();
|
|
8
|
+
let currentNow = Math.floor(performance.now() + offset);
|
|
9
|
+
const listeners = new Set();
|
|
10
|
+
const cadenceHints = new Map();
|
|
11
|
+
let timerId = null;
|
|
12
|
+
let activeIntervalMs = 1000;
|
|
13
|
+
let isBackground = false;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Subscribe to time updates
|
|
17
|
+
* @param {Function} listener - Callback function called on each tick
|
|
18
|
+
* @returns {Function} Unsubscribe function
|
|
19
|
+
*/
|
|
20
|
+
function subscribe(listener) {
|
|
21
|
+
listeners.add(listener);
|
|
22
|
+
|
|
23
|
+
// If this is the first listener, start the timer
|
|
24
|
+
if (listeners.size === 1) {
|
|
25
|
+
startTimer();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Return unsubscribe function
|
|
29
|
+
return () => {
|
|
30
|
+
listeners.delete(listener);
|
|
31
|
+
|
|
32
|
+
// If no more listeners, stop the timer
|
|
33
|
+
if (listeners.size === 0) {
|
|
34
|
+
stopTimer();
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Get current time snapshot
|
|
41
|
+
* @returns {number} Current timestamp in milliseconds
|
|
42
|
+
*/
|
|
43
|
+
function getSnapshot() {
|
|
44
|
+
return currentNow;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Get server-side snapshot for SSR safety
|
|
49
|
+
* @returns {number} Current timestamp in milliseconds
|
|
50
|
+
*/
|
|
51
|
+
function getServerSnapshot() {
|
|
52
|
+
return Date.now();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Add cadence hint for timer frequency
|
|
57
|
+
* @param {string} id - Unique identifier for the hint
|
|
58
|
+
* @param {number} ms - Cadence in milliseconds
|
|
59
|
+
*/
|
|
60
|
+
function addCadenceHint(id, ms) {
|
|
61
|
+
cadenceHints.set(id, ms);
|
|
62
|
+
recalculateInterval();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Remove cadence hint
|
|
67
|
+
* @param {string} id - Unique identifier for the hint
|
|
68
|
+
*/
|
|
69
|
+
function removeCadenceHint(id) {
|
|
70
|
+
cadenceHints.delete(id);
|
|
71
|
+
recalculateInterval();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Recalculate the active interval based on current hints and visibility state
|
|
76
|
+
*/
|
|
77
|
+
function recalculateInterval() {
|
|
78
|
+
const minCadence = Math.min(...cadenceHints.values(), 1000);
|
|
79
|
+
const newIntervalMs = isBackground ? Math.max(minCadence, 60000) : minCadence;
|
|
80
|
+
|
|
81
|
+
if (newIntervalMs !== activeIntervalMs) {
|
|
82
|
+
activeIntervalMs = newIntervalMs;
|
|
83
|
+
|
|
84
|
+
// Restart timer if we have listeners
|
|
85
|
+
if (listeners.size > 0) {
|
|
86
|
+
stopTimer();
|
|
87
|
+
startTimer();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Start the timer interval with minute boundary alignment for >= 60s cadence
|
|
94
|
+
*/
|
|
95
|
+
function startTimer() {
|
|
96
|
+
if (timerId !== null) return;
|
|
97
|
+
|
|
98
|
+
const tick = () => {
|
|
99
|
+
currentNow = Math.floor(performance.now() + offset);
|
|
100
|
+
|
|
101
|
+
// Notify all listeners
|
|
102
|
+
listeners.forEach((listener) => {
|
|
103
|
+
try {
|
|
104
|
+
listener();
|
|
105
|
+
} catch (error) {
|
|
106
|
+
console.error("Error in time store listener:", error);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
// Align to minute boundary for >= 60s cadence
|
|
112
|
+
if (activeIntervalMs >= 60000) {
|
|
113
|
+
const now = Date.now();
|
|
114
|
+
const nextMinuteBoundary = Math.ceil(now / 60000) * 60000;
|
|
115
|
+
const initialDelay = nextMinuteBoundary - now;
|
|
116
|
+
|
|
117
|
+
// Initial delay to align to minute boundary, then regular intervals
|
|
118
|
+
timerId = setTimeout(() => {
|
|
119
|
+
tick();
|
|
120
|
+
timerId = setInterval(tick, 60000);
|
|
121
|
+
}, initialDelay);
|
|
122
|
+
} else {
|
|
123
|
+
// Immediate start for sub-minute cadences
|
|
124
|
+
timerId = setInterval(tick, activeIntervalMs);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Stop the timer interval
|
|
129
|
+
*/
|
|
130
|
+
function stopTimer() {
|
|
131
|
+
if (timerId !== null) {
|
|
132
|
+
clearTimeout(timerId);
|
|
133
|
+
clearInterval(timerId);
|
|
134
|
+
timerId = null;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Handle visibility change events
|
|
140
|
+
*/
|
|
141
|
+
function handleVisibilityChange() {
|
|
142
|
+
const wasBackground = isBackground;
|
|
143
|
+
isBackground = document.visibilityState === "hidden";
|
|
144
|
+
|
|
145
|
+
if (wasBackground !== isBackground) {
|
|
146
|
+
recalculateInterval();
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Set up visibility change listener
|
|
151
|
+
if (typeof document !== "undefined") {
|
|
152
|
+
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export {
|
|
156
|
+
subscribe,
|
|
157
|
+
getSnapshot,
|
|
158
|
+
getServerSnapshot,
|
|
159
|
+
addCadenceHint,
|
|
160
|
+
removeCadenceHint,
|
|
161
|
+
};
|
package/src/ui/config-bridge.js
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
* Universal configuration bridge for UI helpers.
|
|
3
3
|
* Works in both browser and Node environments.
|
|
4
4
|
*/
|
|
5
|
+
import {
|
|
6
|
+
TaskState,
|
|
7
|
+
JobStatus,
|
|
8
|
+
JobLocation,
|
|
9
|
+
deriveJobStatusFromTasks,
|
|
10
|
+
} from "../config/statuses.js";
|
|
5
11
|
|
|
6
12
|
/**
|
|
7
13
|
* Global constants and contracts for project data display system
|
|
@@ -18,19 +24,24 @@ export const Constants = {
|
|
|
18
24
|
* Valid task states
|
|
19
25
|
* @type {string[]}
|
|
20
26
|
*/
|
|
21
|
-
TASK_STATES:
|
|
27
|
+
TASK_STATES: Object.values(TaskState),
|
|
22
28
|
|
|
23
29
|
/**
|
|
24
30
|
* Valid job locations
|
|
25
31
|
* @type {string[]}
|
|
26
32
|
*/
|
|
27
|
-
JOB_LOCATIONS:
|
|
33
|
+
JOB_LOCATIONS: Object.values(JobLocation),
|
|
28
34
|
|
|
29
35
|
/**
|
|
30
36
|
* Status sort order (descending priority)
|
|
31
37
|
* @type {string[]}
|
|
32
38
|
*/
|
|
33
|
-
STATUS_ORDER: [
|
|
39
|
+
STATUS_ORDER: [
|
|
40
|
+
JobStatus.RUNNING,
|
|
41
|
+
JobStatus.FAILED,
|
|
42
|
+
JobStatus.PENDING,
|
|
43
|
+
JobStatus.COMPLETE,
|
|
44
|
+
],
|
|
34
45
|
|
|
35
46
|
/**
|
|
36
47
|
* File size limits for reading
|
|
@@ -104,27 +115,7 @@ export function getStatusPriority(status) {
|
|
|
104
115
|
* @returns {string} Job status
|
|
105
116
|
*/
|
|
106
117
|
export function determineJobStatus(tasks = {}) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (taskEntries.length === 0) {
|
|
110
|
-
return "pending";
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const taskStates = taskEntries.map(([_, task]) => task.state);
|
|
114
|
-
|
|
115
|
-
if (taskStates.includes("failed")) {
|
|
116
|
-
return "failed";
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if (taskStates.includes("running")) {
|
|
120
|
-
return "running";
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (taskStates.every((state) => state === "done")) {
|
|
124
|
-
return "complete";
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
return "pending";
|
|
118
|
+
return deriveJobStatusFromTasks(Object.values(tasks));
|
|
128
119
|
}
|
|
129
120
|
|
|
130
121
|
/**
|
|
@@ -7,6 +7,12 @@
|
|
|
7
7
|
import path from "node:path";
|
|
8
8
|
import { promises as fs } from "node:fs";
|
|
9
9
|
import { fileURLToPath } from "node:url";
|
|
10
|
+
import {
|
|
11
|
+
TaskState,
|
|
12
|
+
JobStatus,
|
|
13
|
+
JobLocation,
|
|
14
|
+
deriveJobStatusFromTasks,
|
|
15
|
+
} from "../config/statuses.js";
|
|
10
16
|
|
|
11
17
|
/**
|
|
12
18
|
* Global constants and contracts for project data display system
|
|
@@ -23,19 +29,24 @@ export const Constants = {
|
|
|
23
29
|
* Valid task states
|
|
24
30
|
* @type {string[]}
|
|
25
31
|
*/
|
|
26
|
-
TASK_STATES:
|
|
32
|
+
TASK_STATES: Object.values(TaskState),
|
|
27
33
|
|
|
28
34
|
/**
|
|
29
35
|
* Valid job locations
|
|
30
36
|
* @type {string[]}
|
|
31
37
|
*/
|
|
32
|
-
JOB_LOCATIONS:
|
|
38
|
+
JOB_LOCATIONS: Object.values(JobLocation),
|
|
33
39
|
|
|
34
40
|
/**
|
|
35
41
|
* Status sort order (descending priority)
|
|
36
42
|
* @type {string[]}
|
|
37
43
|
*/
|
|
38
|
-
STATUS_ORDER: [
|
|
44
|
+
STATUS_ORDER: [
|
|
45
|
+
JobStatus.RUNNING,
|
|
46
|
+
JobStatus.FAILED,
|
|
47
|
+
JobStatus.PENDING,
|
|
48
|
+
JobStatus.COMPLETE,
|
|
49
|
+
],
|
|
39
50
|
|
|
40
51
|
/**
|
|
41
52
|
* File size limits for reading
|
|
@@ -240,27 +251,7 @@ export function getStatusPriority(status) {
|
|
|
240
251
|
* @returns {string} Job status
|
|
241
252
|
*/
|
|
242
253
|
export function determineJobStatus(tasks = {}) {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
if (taskEntries.length === 0) {
|
|
246
|
-
return "pending";
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
const taskStates = taskEntries.map(([_, task]) => task.state);
|
|
250
|
-
|
|
251
|
-
if (taskStates.includes("failed")) {
|
|
252
|
-
return "failed";
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
if (taskStates.includes("running")) {
|
|
256
|
-
return "running";
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
if (taskStates.every((state) => state === "done")) {
|
|
260
|
-
return "complete";
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
return "pending";
|
|
254
|
+
return deriveJobStatusFromTasks(Object.values(tasks));
|
|
264
255
|
}
|
|
265
256
|
|
|
266
257
|
// Export helper to resolve paths lazily for server use
|