@ryanfw/prompt-orchestration-pipeline 0.5.0 → 0.7.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 +14 -12
- package/src/components/JobDetail.jsx +54 -51
- package/src/components/JobTable.jsx +72 -23
- package/src/components/Layout.jsx +145 -42
- package/src/components/LiveText.jsx +47 -0
- package/src/components/PageSubheader.jsx +75 -0
- package/src/components/TaskDetailSidebar.jsx +216 -0
- package/src/components/TimerText.jsx +82 -0
- package/src/components/UploadSeed.jsx +0 -70
- package/src/components/ui/Logo.jsx +16 -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 +4 -34
- package/src/core/file-io.js +13 -28
- package/src/core/module-loader.js +54 -40
- package/src/core/pipeline-runner.js +65 -26
- package/src/core/status-writer.js +213 -58
- package/src/core/symlink-bridge.js +57 -0
- package/src/core/symlink-utils.js +94 -0
- package/src/core/task-runner.js +321 -437
- package/src/llm/index.js +258 -86
- package/src/pages/Code.jsx +351 -0
- package/src/pages/PipelineDetail.jsx +124 -15
- package/src/pages/PromptPipelineDashboard.jsx +20 -88
- package/src/providers/anthropic.js +83 -69
- package/src/providers/base.js +52 -0
- package/src/providers/deepseek.js +20 -21
- 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 +42 -28
- package/src/ui/client/api.js +134 -0
- package/src/ui/client/hooks/useJobDetailWithUpdates.js +65 -179
- package/src/ui/client/index.css +15 -0
- package/src/ui/client/index.html +2 -1
- package/src/ui/client/main.jsx +19 -14
- 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-CxcrauYR.js → index-DqkbzXZ1.js} +2132 -1086
- package/src/ui/dist/assets/style-DBF9NQGk.css +62 -0
- package/src/ui/dist/index.html +4 -3
- package/src/ui/job-reader.js +0 -108
- package/src/ui/public/favicon.svg +12 -0
- package/src/ui/server.js +252 -0
- package/src/ui/sse-enhancer.js +0 -1
- package/src/ui/transformers/list-transformer.js +32 -12
- package/src/ui/transformers/status-transformer.js +29 -42
- 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 +294 -0
- package/src/utils/ui.jsx +18 -20
- 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-D6K_oQ12.css +0 -62
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Creates an idempotent symlink, safely handling existing files/symlinks.
|
|
6
|
+
*
|
|
7
|
+
* @param {string} linkPath - Path where the symlink should be created
|
|
8
|
+
* @param {string} targetPath - Path that the symlink should point to
|
|
9
|
+
* @param {'file' | 'dir'} type - Type of symlink to create
|
|
10
|
+
* @throws {Error} If symlink creation fails on non-POSIX systems
|
|
11
|
+
*/
|
|
12
|
+
export async function ensureSymlink(linkPath, targetPath, type) {
|
|
13
|
+
try {
|
|
14
|
+
// Check if linkPath already exists
|
|
15
|
+
const stats = await fs.lstat(linkPath).catch(() => null);
|
|
16
|
+
|
|
17
|
+
if (stats) {
|
|
18
|
+
if (stats.isSymbolicLink()) {
|
|
19
|
+
// If it's already a symlink pointing to the correct target, we're done
|
|
20
|
+
const existingTarget = await fs.readlink(linkPath);
|
|
21
|
+
if (existingTarget === targetPath) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
// If it points to a different target, remove it
|
|
25
|
+
await fs.unlink(linkPath);
|
|
26
|
+
} else if (stats.isDirectory()) {
|
|
27
|
+
// If it's a directory, remove it recursively
|
|
28
|
+
await fs.rmdir(linkPath, { recursive: true });
|
|
29
|
+
} else {
|
|
30
|
+
// If it's a file, remove it
|
|
31
|
+
await fs.unlink(linkPath);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Ensure parent directory exists
|
|
36
|
+
const parentDir = path.dirname(linkPath);
|
|
37
|
+
await fs.mkdir(parentDir, { recursive: true });
|
|
38
|
+
|
|
39
|
+
// Create the symlink
|
|
40
|
+
await fs.symlink(targetPath, linkPath, type);
|
|
41
|
+
} catch (error) {
|
|
42
|
+
// Re-throw with more context
|
|
43
|
+
throw new Error(
|
|
44
|
+
`Failed to create symlink from ${linkPath} -> ${targetPath}: ${error.message}`
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Removes task symlinks from a completed job directory to avoid dangling links.
|
|
51
|
+
*
|
|
52
|
+
* @param {string} completedJobDir - Path to the completed job directory (e.g., COMPLETE_DIR/jobId)
|
|
53
|
+
*/
|
|
54
|
+
export async function cleanupTaskSymlinks(completedJobDir) {
|
|
55
|
+
const tasksDir = path.join(completedJobDir, "tasks");
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
// Check if tasks directory exists
|
|
59
|
+
const tasksStats = await fs.lstat(tasksDir).catch(() => null);
|
|
60
|
+
if (!tasksStats || !tasksStats.isDirectory()) {
|
|
61
|
+
return; // No tasks directory to clean up
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Get all task directories
|
|
65
|
+
const taskDirs = await fs.readdir(tasksDir, { withFileTypes: true });
|
|
66
|
+
|
|
67
|
+
for (const taskDir of taskDirs) {
|
|
68
|
+
if (!taskDir.isDirectory()) continue;
|
|
69
|
+
|
|
70
|
+
const taskPath = path.join(tasksDir, taskDir.name);
|
|
71
|
+
|
|
72
|
+
// Remove specific symlinks if they exist and are actually symlinks
|
|
73
|
+
const symlinksToRemove = ["node_modules", "project", "_task_root"];
|
|
74
|
+
|
|
75
|
+
for (const linkName of symlinksToRemove) {
|
|
76
|
+
const linkPath = path.join(taskPath, linkName);
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
const stats = await fs.lstat(linkPath);
|
|
80
|
+
if (stats.isSymbolicLink()) {
|
|
81
|
+
await fs.unlink(linkPath);
|
|
82
|
+
}
|
|
83
|
+
} catch {
|
|
84
|
+
// Ignore errors (file doesn't exist, permissions, etc.)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
} catch (error) {
|
|
89
|
+
// Log but don't fail - cleanup is optional
|
|
90
|
+
console.warn(
|
|
91
|
+
`Warning: Failed to cleanup task symlinks in ${completedJobDir}: ${error.message}`
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
}
|