devglide 0.1.1
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/LICENSE +21 -0
- package/README.md +338 -0
- package/bin/claude-md-template.js +94 -0
- package/bin/devglide.js +387 -0
- package/package.json +85 -0
- package/pnpm-workspace.yaml +3 -0
- package/src/apps/coder/.turbo/turbo-lint.log +5 -0
- package/src/apps/coder/package.json +16 -0
- package/src/apps/coder/public/favicon.svg +7 -0
- package/src/apps/coder/public/page.css +275 -0
- package/src/apps/coder/public/page.js +528 -0
- package/src/apps/coder/server.js +3 -0
- package/src/apps/documentation/public/page.css +597 -0
- package/src/apps/documentation/public/page.js +609 -0
- package/src/apps/kanban/.turbo/turbo-lint.log +97 -0
- package/src/apps/kanban/.turbo/turbo-typecheck.log +5 -0
- package/src/apps/kanban/package.json +32 -0
- package/src/apps/kanban/public/favicon.svg +7 -0
- package/src/apps/kanban/public/page.css +1010 -0
- package/src/apps/kanban/public/page.js +1730 -0
- package/src/apps/kanban/public/vendor/marked.min.js +6 -0
- package/src/apps/kanban/public/vendor/sortable.min.js +2 -0
- package/src/apps/kanban/src/db.ts +319 -0
- package/src/apps/kanban/src/index.ts +14 -0
- package/src/apps/kanban/src/mcp-helpers.test.ts +88 -0
- package/src/apps/kanban/src/mcp-helpers.ts +60 -0
- package/src/apps/kanban/src/mcp.ts +59 -0
- package/src/apps/kanban/src/routes/attachments.ts +161 -0
- package/src/apps/kanban/src/routes/features.ts +233 -0
- package/src/apps/kanban/src/routes/issues.ts +373 -0
- package/src/apps/kanban/src/tools/feature-tools.ts +164 -0
- package/src/apps/kanban/src/tools/item-tools.ts +307 -0
- package/src/apps/kanban/src/tools/versioned-entry-tools.ts +72 -0
- package/src/apps/kanban/tsconfig.check.json +9 -0
- package/src/apps/kanban/tsconfig.json +9 -0
- package/src/apps/keymap/.turbo/turbo-lint.log +5 -0
- package/src/apps/keymap/package.json +16 -0
- package/src/apps/keymap/public/page.css +275 -0
- package/src/apps/keymap/public/page.js +294 -0
- package/src/apps/keymap/server.js +25 -0
- package/src/apps/log/.turbo/turbo-build.log +5 -0
- package/src/apps/log/.turbo/turbo-lint.log +45 -0
- package/src/apps/log/.turbo/turbo-typecheck.log +5 -0
- package/src/apps/log/node_modules/.bin/tsc +21 -0
- package/src/apps/log/node_modules/.bin/tsserver +21 -0
- package/src/apps/log/node_modules/.bin/tsx +21 -0
- package/src/apps/log/package.json +36 -0
- package/src/apps/log/public/console-sniffer.js +221 -0
- package/src/apps/log/public/favicon.svg +7 -0
- package/src/apps/log/public/page.css +322 -0
- package/src/apps/log/public/page.js +463 -0
- package/src/apps/log/src/index.ts +9 -0
- package/src/apps/log/src/mcp.ts +122 -0
- package/src/apps/log/src/routes/log.ts +333 -0
- package/src/apps/log/src/routes/status.ts +25 -0
- package/src/apps/log/src/server-sniffer.ts +118 -0
- package/src/apps/log/src/services/file-patterns.ts +39 -0
- package/src/apps/log/src/services/file-tailer.ts +228 -0
- package/src/apps/log/src/services/line-parser.ts +94 -0
- package/src/apps/log/src/services/log-writer.ts +39 -0
- package/src/apps/log/tsconfig.json +8 -0
- package/src/apps/prompts/.turbo/turbo-build.log +5 -0
- package/src/apps/prompts/.turbo/turbo-lint.log +24 -0
- package/src/apps/prompts/.turbo/turbo-typecheck.log +5 -0
- package/src/apps/prompts/mcp.ts +175 -0
- package/src/apps/prompts/node_modules/.bin/tsc +21 -0
- package/src/apps/prompts/node_modules/.bin/tsserver +21 -0
- package/src/apps/prompts/node_modules/.bin/tsx +21 -0
- package/src/apps/prompts/package.json +25 -0
- package/src/apps/prompts/public/page.css +315 -0
- package/src/apps/prompts/public/page.js +541 -0
- package/src/apps/prompts/services/prompt-store.ts +212 -0
- package/src/apps/prompts/src/index.ts +9 -0
- package/src/apps/prompts/tsconfig.json +8 -0
- package/src/apps/prompts/types.ts +27 -0
- package/src/apps/shell/.turbo/turbo-build.log +5 -0
- package/src/apps/shell/.turbo/turbo-lint.log +34 -0
- package/src/apps/shell/.turbo/turbo-typecheck.log +5 -0
- package/src/apps/shell/package.json +35 -0
- package/src/apps/shell/public/favicon.svg +7 -0
- package/src/apps/shell/public/page.css +407 -0
- package/src/apps/shell/public/page.js +1577 -0
- package/src/apps/shell/src/index.ts +150 -0
- package/src/apps/shell/src/mcp.ts +398 -0
- package/src/apps/shell/src/shell-types.ts +41 -0
- package/src/apps/shell/tsconfig.json +8 -0
- package/src/apps/test/.turbo/turbo-build.log +5 -0
- package/src/apps/test/.turbo/turbo-lint.log +27 -0
- package/src/apps/test/.turbo/turbo-typecheck.log +5 -0
- package/src/apps/test/node_modules/.bin/tsc +21 -0
- package/src/apps/test/node_modules/.bin/tsserver +21 -0
- package/src/apps/test/node_modules/.bin/tsx +21 -0
- package/src/apps/test/node_modules/.bin/uuid +21 -0
- package/src/apps/test/package.json +35 -0
- package/src/apps/test/public/favicon.svg +7 -0
- package/src/apps/test/public/page.css +499 -0
- package/src/apps/test/public/page.js +417 -0
- package/src/apps/test/public/scenario-runner.js +450 -0
- package/src/apps/test/src/index.ts +9 -0
- package/src/apps/test/src/mcp.ts +192 -0
- package/src/apps/test/src/routes/trigger.ts +285 -0
- package/src/apps/test/src/services/scenario-broadcaster.ts +60 -0
- package/src/apps/test/src/services/scenario-manager.ts +361 -0
- package/src/apps/test/src/services/scenario-store.ts +145 -0
- package/src/apps/test/tsconfig.json +8 -0
- package/src/apps/vocabulary/.turbo/turbo-build.log +5 -0
- package/src/apps/vocabulary/.turbo/turbo-lint.log +25 -0
- package/src/apps/vocabulary/.turbo/turbo-typecheck.log +5 -0
- package/src/apps/vocabulary/mcp.ts +173 -0
- package/src/apps/vocabulary/node_modules/.bin/tsc +21 -0
- package/src/apps/vocabulary/node_modules/.bin/tsserver +21 -0
- package/src/apps/vocabulary/node_modules/.bin/tsx +21 -0
- package/src/apps/vocabulary/package.json +25 -0
- package/src/apps/vocabulary/public/page.css +247 -0
- package/src/apps/vocabulary/public/page.js +444 -0
- package/src/apps/vocabulary/services/vocabulary-store.ts +179 -0
- package/src/apps/vocabulary/src/index.ts +10 -0
- package/src/apps/vocabulary/tsconfig.json +8 -0
- package/src/apps/vocabulary/types.ts +22 -0
- package/src/apps/voice/.turbo/turbo-build.log +5 -0
- package/src/apps/voice/.turbo/turbo-lint.log +43 -0
- package/src/apps/voice/.turbo/turbo-typecheck.log +5 -0
- package/src/apps/voice/node_modules/.bin/openai +21 -0
- package/src/apps/voice/node_modules/.bin/tsc +21 -0
- package/src/apps/voice/node_modules/.bin/tsserver +21 -0
- package/src/apps/voice/node_modules/.bin/tsx +21 -0
- package/src/apps/voice/package.json +35 -0
- package/src/apps/voice/public/favicon.svg +7 -0
- package/src/apps/voice/public/page.css +388 -0
- package/src/apps/voice/public/page.js +718 -0
- package/src/apps/voice/src/index.ts +10 -0
- package/src/apps/voice/src/mcp.ts +70 -0
- package/src/apps/voice/src/providers/index.ts +85 -0
- package/src/apps/voice/src/providers/openai-compatible.ts +94 -0
- package/src/apps/voice/src/providers/types.ts +27 -0
- package/src/apps/voice/src/routes/config.ts +118 -0
- package/src/apps/voice/src/routes/transcribe.ts +90 -0
- package/src/apps/voice/src/services/config-store.ts +129 -0
- package/src/apps/voice/src/services/stats.ts +108 -0
- package/src/apps/voice/src/transcribe.ts +11 -0
- package/src/apps/voice/src/utils/mime.ts +16 -0
- package/src/apps/voice/tsconfig.json +8 -0
- package/src/apps/workflow/.turbo/turbo-build.log +5 -0
- package/src/apps/workflow/.turbo/turbo-lint.log +96 -0
- package/src/apps/workflow/.turbo/turbo-typecheck.log +5 -0
- package/src/apps/workflow/engine/executors/decision-executor.ts +87 -0
- package/src/apps/workflow/engine/executors/file-executor.ts +90 -0
- package/src/apps/workflow/engine/executors/git-executor.ts +137 -0
- package/src/apps/workflow/engine/executors/http-executor.ts +65 -0
- package/src/apps/workflow/engine/executors/index.ts +28 -0
- package/src/apps/workflow/engine/executors/kanban-executor.ts +154 -0
- package/src/apps/workflow/engine/executors/llm-executor.ts +46 -0
- package/src/apps/workflow/engine/executors/log-executor.ts +62 -0
- package/src/apps/workflow/engine/executors/loop-executor.ts +14 -0
- package/src/apps/workflow/engine/executors/shell-executor.ts +107 -0
- package/src/apps/workflow/engine/executors/sub-workflow-executor.ts +61 -0
- package/src/apps/workflow/engine/executors/test-executor.ts +73 -0
- package/src/apps/workflow/engine/executors/trigger-executor.ts +39 -0
- package/src/apps/workflow/engine/expression-evaluator.ts +117 -0
- package/src/apps/workflow/engine/graph-runner.ts +438 -0
- package/src/apps/workflow/engine/node-executor.ts +104 -0
- package/src/apps/workflow/engine/node-registry.ts +15 -0
- package/src/apps/workflow/engine/variable-resolver.ts +109 -0
- package/src/apps/workflow/mcp.ts +223 -0
- package/src/apps/workflow/node_modules/.bin/tsc +21 -0
- package/src/apps/workflow/node_modules/.bin/tsserver +21 -0
- package/src/apps/workflow/node_modules/.bin/tsx +21 -0
- package/src/apps/workflow/package.json +25 -0
- package/src/apps/workflow/public/editor/canvas.js +366 -0
- package/src/apps/workflow/public/editor/drag-manager.js +326 -0
- package/src/apps/workflow/public/editor/edge-renderer.js +235 -0
- package/src/apps/workflow/public/editor/history-manager.js +147 -0
- package/src/apps/workflow/public/editor/layout-engine.js +159 -0
- package/src/apps/workflow/public/editor/node-renderer.js +199 -0
- package/src/apps/workflow/public/editor/selection-manager.js +193 -0
- package/src/apps/workflow/public/favicon.svg +7 -0
- package/src/apps/workflow/public/models/node-types.js +300 -0
- package/src/apps/workflow/public/models/workflow-model.js +257 -0
- package/src/apps/workflow/public/page.css +406 -0
- package/src/apps/workflow/public/page.js +658 -0
- package/src/apps/workflow/public/panels/inspector.js +360 -0
- package/src/apps/workflow/public/panels/palette.js +106 -0
- package/src/apps/workflow/public/panels/run-view.js +275 -0
- package/src/apps/workflow/public/panels/toolbar.js +232 -0
- package/src/apps/workflow/public/panels/workflow-list.js +237 -0
- package/src/apps/workflow/public/state/store.js +47 -0
- package/src/apps/workflow/services/custom-node-loader.ts +48 -0
- package/src/apps/workflow/services/legacy-converter.ts +72 -0
- package/src/apps/workflow/services/run-manager.ts +190 -0
- package/src/apps/workflow/services/workflow-store.ts +424 -0
- package/src/apps/workflow/services/workflow-validator.test.ts +103 -0
- package/src/apps/workflow/services/workflow-validator.ts +98 -0
- package/src/apps/workflow/src/index.ts +10 -0
- package/src/apps/workflow/templates/ci-pipeline.json +18 -0
- package/src/apps/workflow/templates/code-review.json +22 -0
- package/src/apps/workflow/templates/kanban-testing.json +24 -0
- package/src/apps/workflow/tsconfig.json +8 -0
- package/src/apps/workflow/types.ts +268 -0
- package/src/packages/auth-middleware.ts +14 -0
- package/src/packages/design-tokens/.turbo/turbo-build.log +10 -0
- package/src/packages/design-tokens/STYLEGUIDE.md +414 -0
- package/src/packages/design-tokens/build.js +413 -0
- package/src/packages/design-tokens/demo/index.html +1367 -0
- package/src/packages/design-tokens/demo/proposition-a.html +717 -0
- package/src/packages/design-tokens/demo/proposition-b.html +1239 -0
- package/src/packages/design-tokens/demo/proposition-c.html +1049 -0
- package/src/packages/design-tokens/dist/tailwind-preset.js +115 -0
- package/src/packages/design-tokens/dist/tokens.css +345 -0
- package/src/packages/design-tokens/dist/tokens.d.ts +229 -0
- package/src/packages/design-tokens/dist/tokens.js +386 -0
- package/src/packages/design-tokens/package.json +25 -0
- package/src/packages/design-tokens/tokens.json +228 -0
- package/src/packages/devtools-middleware.ts +22 -0
- package/src/packages/eslint-config/index.js +63 -0
- package/src/packages/eslint-config/node_modules/.bin/eslint +21 -0
- package/src/packages/eslint-config/package.json +18 -0
- package/src/packages/json-file-store.ts +232 -0
- package/src/packages/mcp-utils/.turbo/turbo-build.log +5 -0
- package/src/packages/mcp-utils/dist/index.d.ts +33 -0
- package/src/packages/mcp-utils/dist/index.d.ts.map +1 -0
- package/src/packages/mcp-utils/dist/index.js +126 -0
- package/src/packages/mcp-utils/dist/index.js.map +1 -0
- package/src/packages/mcp-utils/node_modules/.bin/tsc +21 -0
- package/src/packages/mcp-utils/node_modules/.bin/tsserver +21 -0
- package/src/packages/mcp-utils/package.json +32 -0
- package/src/packages/mcp-utils/src/index.ts +171 -0
- package/src/packages/mcp-utils/tsconfig.json +9 -0
- package/src/packages/paths.ts +18 -0
- package/src/packages/project-context/index.js +55 -0
- package/src/packages/project-context/package.json +13 -0
- package/src/packages/project-store.ts +127 -0
- package/src/packages/server-sniffer.ts +132 -0
- package/src/packages/shared-assets/favicon.svg +7 -0
- package/src/packages/shared-assets/keymap-registry.js +512 -0
- package/src/packages/shared-assets/logo.svg +6 -0
- package/src/packages/shared-assets/package.json +11 -0
- package/src/packages/shared-assets/ui-utils.js +48 -0
- package/src/packages/shared-assets/voice-widget.d.ts +37 -0
- package/src/packages/shared-assets/voice-widget.js +695 -0
- package/src/packages/shared-types/.turbo/turbo-build.log +5 -0
- package/src/packages/shared-types/dist/index.d.ts +39 -0
- package/src/packages/shared-types/dist/index.d.ts.map +1 -0
- package/src/packages/shared-types/node_modules/.bin/tsc +21 -0
- package/src/packages/shared-types/node_modules/.bin/tsserver +21 -0
- package/src/packages/shared-types/package.json +25 -0
- package/src/packages/shared-types/src/index.ts +41 -0
- package/src/packages/shared-types/tsconfig.json +11 -0
- package/src/packages/tsconfig/base.json +15 -0
- package/src/packages/tsconfig/next.json +14 -0
- package/src/packages/tsconfig/node.json +11 -0
- package/src/packages/tsconfig/package.json +10 -0
- package/turbo.json +25 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { watch, type FSWatcher } from "chokidar";
|
|
2
|
+
import fsp from "fs/promises";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import crypto from "crypto";
|
|
5
|
+
import { LogWriter } from "./log-writer.js";
|
|
6
|
+
import { parseLine } from "./line-parser.js";
|
|
7
|
+
import { recordSession, getTargetPaths } from "../routes/log.js";
|
|
8
|
+
import {
|
|
9
|
+
INCLUDE_PATTERNS,
|
|
10
|
+
IGNORED_GLOBS,
|
|
11
|
+
MAX_DEPTH,
|
|
12
|
+
MAX_WATCHED_FILES,
|
|
13
|
+
MAX_FILE_SIZE,
|
|
14
|
+
} from "./file-patterns.js";
|
|
15
|
+
|
|
16
|
+
function fileSessionId(filePath: string): string {
|
|
17
|
+
const hash = crypto.createHash("md5").update(filePath).digest("hex").slice(0, 12);
|
|
18
|
+
return `file-${hash}`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function filetailTargetPath(projectPath: string, filePath: string): string {
|
|
22
|
+
const basename = path.basename(filePath, ".log");
|
|
23
|
+
return path.join(projectPath, `${basename}.filetail.log`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export class FileTailer {
|
|
27
|
+
private watcher: FSWatcher | null = null;
|
|
28
|
+
private offsets = new Map<string, number>();
|
|
29
|
+
private partials = new Map<string, string>();
|
|
30
|
+
private changeQueues = new Map<string, Promise<void>>();
|
|
31
|
+
private logWriter = new LogWriter();
|
|
32
|
+
private projectPath: string | null = null;
|
|
33
|
+
private watchedCount = 0;
|
|
34
|
+
|
|
35
|
+
async start(projectPath: string): Promise<void> {
|
|
36
|
+
this.stop();
|
|
37
|
+
this.projectPath = projectPath;
|
|
38
|
+
|
|
39
|
+
const globs = INCLUDE_PATTERNS.map((p) => path.join(projectPath, p));
|
|
40
|
+
|
|
41
|
+
this.watcher = watch(globs, {
|
|
42
|
+
ignored: IGNORED_GLOBS,
|
|
43
|
+
depth: MAX_DEPTH,
|
|
44
|
+
persistent: true,
|
|
45
|
+
ignoreInitial: false,
|
|
46
|
+
awaitWriteFinish: { stabilityThreshold: 100, pollInterval: 50 },
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
this.watcher.on("add", (filePath: string) => this.onAdd(filePath));
|
|
50
|
+
this.watcher.on("change", (filePath: string) => this.onChange(filePath));
|
|
51
|
+
this.watcher.on("unlink", (filePath: string) => this.onUnlink(filePath));
|
|
52
|
+
this.watcher.on("error", (err: unknown) => {
|
|
53
|
+
console.error("[file-tailer] watcher error:", (err as Error).message);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
console.log(`[file-tailer] Watching for log files in ${projectPath}`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
stop(): void {
|
|
60
|
+
if (this.watcher) {
|
|
61
|
+
this.watcher.close().catch(() => {});
|
|
62
|
+
this.watcher = null;
|
|
63
|
+
}
|
|
64
|
+
this.offsets.clear();
|
|
65
|
+
this.partials.clear();
|
|
66
|
+
this.changeQueues.clear();
|
|
67
|
+
this.watchedCount = 0;
|
|
68
|
+
if (this.projectPath) {
|
|
69
|
+
console.log(`[file-tailer] Stopped watching ${this.projectPath}`);
|
|
70
|
+
}
|
|
71
|
+
this.projectPath = null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
private async onAdd(filePath: string): Promise<void> {
|
|
75
|
+
if (this.watchedCount >= MAX_WATCHED_FILES) return;
|
|
76
|
+
|
|
77
|
+
// Skip files already managed by DevGlide sniffers (browser/server)
|
|
78
|
+
const absPath = path.resolve(filePath);
|
|
79
|
+
const managedPaths = getTargetPaths();
|
|
80
|
+
if (managedPaths.some((p) => path.resolve(p) === absPath)) {
|
|
81
|
+
console.log(`[file-tailer] Skipping managed file: ${filePath}`);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
const stat = await fsp.stat(filePath);
|
|
87
|
+
if (stat.size > MAX_FILE_SIZE) {
|
|
88
|
+
console.log(`[file-tailer] Skipping large file: ${filePath} (${(stat.size / 1024 / 1024).toFixed(1)}MB)`);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Peek at first line — skip if it looks like a DevGlide JSONL file
|
|
93
|
+
if (stat.size > 0 && (await this.isDevGlideJsonl(filePath))) {
|
|
94
|
+
console.log(`[file-tailer] Skipping DevGlide JSONL file: ${filePath}`);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Start from end of file — only tail new content
|
|
99
|
+
this.offsets.set(filePath, stat.size);
|
|
100
|
+
this.partials.set(filePath, "");
|
|
101
|
+
this.watchedCount++;
|
|
102
|
+
|
|
103
|
+
const sessionId = fileSessionId(filePath);
|
|
104
|
+
const targetPath = filetailTargetPath(this.projectPath!, filePath);
|
|
105
|
+
const basename = path.basename(filePath);
|
|
106
|
+
|
|
107
|
+
const entry = {
|
|
108
|
+
type: "FILE_SESSION_START",
|
|
109
|
+
session: sessionId,
|
|
110
|
+
ts: new Date().toISOString(),
|
|
111
|
+
message: `Tailing ${basename}`,
|
|
112
|
+
targetPath,
|
|
113
|
+
persistent: true,
|
|
114
|
+
source: filePath,
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
recordSession(entry);
|
|
118
|
+
await this.logWriter.append(targetPath, entry);
|
|
119
|
+
|
|
120
|
+
console.log(`[file-tailer] Tailing: ${filePath}`);
|
|
121
|
+
} catch (err) {
|
|
122
|
+
console.error(`[file-tailer] Failed to add ${filePath}:`, (err as Error).message);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** Serialize change processing per file to prevent duplicate reads from concurrent events */
|
|
127
|
+
private onChange(filePath: string): void {
|
|
128
|
+
const prev = this.changeQueues.get(filePath) || Promise.resolve();
|
|
129
|
+
const next = prev.then(() => this.processChange(filePath)).catch(() => {});
|
|
130
|
+
this.changeQueues.set(filePath, next);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
private async processChange(filePath: string): Promise<void> {
|
|
134
|
+
const prevOffset = this.offsets.get(filePath);
|
|
135
|
+
if (prevOffset === undefined) return;
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
const stat = await fsp.stat(filePath);
|
|
139
|
+
const currentSize = stat.size;
|
|
140
|
+
|
|
141
|
+
// File was truncated/rotated — reset to beginning
|
|
142
|
+
if (currentSize < prevOffset) {
|
|
143
|
+
this.offsets.set(filePath, 0);
|
|
144
|
+
this.partials.set(filePath, "");
|
|
145
|
+
return this.processChange(filePath);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// No new data
|
|
149
|
+
if (currentSize === prevOffset) return;
|
|
150
|
+
|
|
151
|
+
const bytesToRead = currentSize - prevOffset;
|
|
152
|
+
const buffer = Buffer.alloc(bytesToRead);
|
|
153
|
+
|
|
154
|
+
const fd = await fsp.open(filePath, "r");
|
|
155
|
+
try {
|
|
156
|
+
await fd.read(buffer, 0, bytesToRead, prevOffset);
|
|
157
|
+
} finally {
|
|
158
|
+
await fd.close();
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
this.offsets.set(filePath, currentSize);
|
|
162
|
+
|
|
163
|
+
const chunk = buffer.toString("utf-8");
|
|
164
|
+
const partial = this.partials.get(filePath) || "";
|
|
165
|
+
const combined = partial + chunk;
|
|
166
|
+
const lines = combined.split("\n");
|
|
167
|
+
|
|
168
|
+
// Last element is either empty (line ended with \n) or an incomplete line
|
|
169
|
+
this.partials.set(filePath, lines.pop()!);
|
|
170
|
+
|
|
171
|
+
if (lines.length === 0) return;
|
|
172
|
+
|
|
173
|
+
const sessionId = fileSessionId(filePath);
|
|
174
|
+
const targetPath = filetailTargetPath(this.projectPath!, filePath);
|
|
175
|
+
|
|
176
|
+
for (const line of lines) {
|
|
177
|
+
if (!line.trim()) continue;
|
|
178
|
+
|
|
179
|
+
const parsed = parseLine(line);
|
|
180
|
+
const entry: Record<string, unknown> = {
|
|
181
|
+
type: parsed.type,
|
|
182
|
+
session: sessionId,
|
|
183
|
+
ts: parsed.ts,
|
|
184
|
+
message: parsed.message,
|
|
185
|
+
targetPath,
|
|
186
|
+
source: filePath,
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
recordSession(entry);
|
|
190
|
+
await this.logWriter.append(targetPath, entry);
|
|
191
|
+
}
|
|
192
|
+
} catch (err) {
|
|
193
|
+
// File may have been deleted between stat and read
|
|
194
|
+
if ((err as NodeJS.ErrnoException).code !== "ENOENT") {
|
|
195
|
+
console.error(`[file-tailer] Error reading ${filePath}:`, (err as Error).message);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** Check if a file is a DevGlide JSONL log (has session + type fields on first line) */
|
|
201
|
+
private async isDevGlideJsonl(filePath: string): Promise<boolean> {
|
|
202
|
+
try {
|
|
203
|
+
const fd = await fsp.open(filePath, "r");
|
|
204
|
+
try {
|
|
205
|
+
const buf = Buffer.alloc(512);
|
|
206
|
+
const { bytesRead } = await fd.read(buf, 0, 512, 0);
|
|
207
|
+
if (bytesRead === 0) return false;
|
|
208
|
+
const firstLine = buf.toString("utf-8", 0, bytesRead).split("\n")[0].trim();
|
|
209
|
+
if (!firstLine.startsWith("{")) return false;
|
|
210
|
+
const obj = JSON.parse(firstLine);
|
|
211
|
+
return typeof obj.session === "string" && typeof obj.type === "string";
|
|
212
|
+
} finally {
|
|
213
|
+
await fd.close();
|
|
214
|
+
}
|
|
215
|
+
} catch {
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
private onUnlink(filePath: string): void {
|
|
221
|
+
if (this.offsets.has(filePath)) {
|
|
222
|
+
this.offsets.delete(filePath);
|
|
223
|
+
this.partials.delete(filePath);
|
|
224
|
+
this.watchedCount--;
|
|
225
|
+
console.log(`[file-tailer] Removed: ${filePath}`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// ── Parse raw log lines into structured entries ─────────────────────────────
|
|
2
|
+
|
|
3
|
+
export interface ParsedLine {
|
|
4
|
+
type: "FILE_LOG" | "FILE_WARN" | "FILE_ERROR" | "FILE_DEBUG";
|
|
5
|
+
message: string;
|
|
6
|
+
ts: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const LEVEL_MAP: Record<string, ParsedLine["type"]> = {
|
|
10
|
+
debug: "FILE_DEBUG",
|
|
11
|
+
info: "FILE_LOG",
|
|
12
|
+
log: "FILE_LOG",
|
|
13
|
+
notice: "FILE_LOG",
|
|
14
|
+
warn: "FILE_WARN",
|
|
15
|
+
warning: "FILE_WARN",
|
|
16
|
+
error: "FILE_ERROR",
|
|
17
|
+
err: "FILE_ERROR",
|
|
18
|
+
fatal: "FILE_ERROR",
|
|
19
|
+
critical: "FILE_ERROR",
|
|
20
|
+
crit: "FILE_ERROR",
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Regex for common log formats:
|
|
25
|
+
* [2024-01-15 10:30:45] ERROR: something happened
|
|
26
|
+
* 2024-01-15T10:30:45.123Z WARN something happened
|
|
27
|
+
* [ERROR] something happened
|
|
28
|
+
*/
|
|
29
|
+
const COMMON_RE =
|
|
30
|
+
/^\[?(\d{4}[-/]\d{2}[-/]\d{2}[T ]\d{2}:\d{2}:\d{2}[.\d]*Z?)\]?\s+(\w+):?\s+(.*)/;
|
|
31
|
+
const LEVEL_ONLY_RE = /^\[(\w+)\]:?\s+(.*)/;
|
|
32
|
+
|
|
33
|
+
function mapLevel(raw: string): ParsedLine["type"] {
|
|
34
|
+
return LEVEL_MAP[raw.toLowerCase()] || "FILE_LOG";
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function parseLine(raw: string): ParsedLine {
|
|
38
|
+
const trimmed = raw.trimEnd();
|
|
39
|
+
if (!trimmed) {
|
|
40
|
+
return { type: "FILE_LOG", message: "", ts: new Date().toISOString() };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Strategy 1: JSON line
|
|
44
|
+
if (trimmed.startsWith("{")) {
|
|
45
|
+
try {
|
|
46
|
+
const obj = JSON.parse(trimmed);
|
|
47
|
+
const level =
|
|
48
|
+
obj.level || obj.severity || obj.log_level || obj.loglevel || "";
|
|
49
|
+
const message =
|
|
50
|
+
obj.msg || obj.message || obj.text || obj.body || trimmed;
|
|
51
|
+
const ts =
|
|
52
|
+
obj.time ||
|
|
53
|
+
obj.timestamp ||
|
|
54
|
+
obj.ts ||
|
|
55
|
+
obj.datetime ||
|
|
56
|
+
obj.date ||
|
|
57
|
+
new Date().toISOString();
|
|
58
|
+
return {
|
|
59
|
+
type: mapLevel(String(level)),
|
|
60
|
+
message: String(message),
|
|
61
|
+
ts: String(ts),
|
|
62
|
+
};
|
|
63
|
+
} catch {
|
|
64
|
+
// Not valid JSON — fall through
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Strategy 2: Common timestamp + level format
|
|
69
|
+
const common = COMMON_RE.exec(trimmed);
|
|
70
|
+
if (common) {
|
|
71
|
+
return {
|
|
72
|
+
type: mapLevel(common[2]),
|
|
73
|
+
message: common[3],
|
|
74
|
+
ts: common[1],
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Strategy 2b: Level-only prefix [ERROR] message
|
|
79
|
+
const levelOnly = LEVEL_ONLY_RE.exec(trimmed);
|
|
80
|
+
if (levelOnly && LEVEL_MAP[levelOnly[1].toLowerCase()]) {
|
|
81
|
+
return {
|
|
82
|
+
type: mapLevel(levelOnly[1]),
|
|
83
|
+
message: levelOnly[2],
|
|
84
|
+
ts: new Date().toISOString(),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Strategy 3: Plain text fallback
|
|
89
|
+
return {
|
|
90
|
+
type: "FILE_LOG",
|
|
91
|
+
message: trimmed,
|
|
92
|
+
ts: new Date().toISOString(),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import fs from "fs/promises";
|
|
2
|
+
import path from "path";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Appends JSONL log entries to files on disk.
|
|
6
|
+
* Uses per-file write queues to ensure sequential writes without corruption.
|
|
7
|
+
*/
|
|
8
|
+
export class LogWriter {
|
|
9
|
+
private queues = new Map<string, Promise<void>>();
|
|
10
|
+
|
|
11
|
+
async append(targetPath: string, entry: Record<string, unknown>): Promise<void> {
|
|
12
|
+
const line = JSON.stringify(entry) + "\n";
|
|
13
|
+
await this.enqueue(targetPath, async () => {
|
|
14
|
+
const dir = path.dirname(targetPath);
|
|
15
|
+
await fs.mkdir(dir, { recursive: true });
|
|
16
|
+
await fs.appendFile(targetPath, line, "utf-8");
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async clear(targetPath: string): Promise<void> {
|
|
21
|
+
await this.enqueue(targetPath, async () => {
|
|
22
|
+
const dir = path.dirname(targetPath);
|
|
23
|
+
await fs.mkdir(dir, { recursive: true });
|
|
24
|
+
await fs.writeFile(targetPath, "", "utf-8");
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
private enqueue(key: string, fn: () => Promise<void>): Promise<void> {
|
|
29
|
+
const prev = this.queues.get(key) || Promise.resolve();
|
|
30
|
+
const next = prev.then(fn, fn).finally(() => {
|
|
31
|
+
// Delete queue entry once it drains to prevent unbounded growth
|
|
32
|
+
if (this.queues.get(key) === next) {
|
|
33
|
+
this.queues.delete(key);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
this.queues.set(key, next);
|
|
37
|
+
return next;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
WARN Issue while reading "/home/runner/_work/devglide/devglide/.npmrc". Failed to replace env in config: ${NODE_AUTH_TOKEN}
|
|
2
|
+
|
|
3
|
+
> @devglide/prompts@0.1.0 lint /home/runner/_work/devglide/devglide/src/apps/prompts
|
|
4
|
+
> eslint .
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
/home/runner/_work/devglide/devglide/src/apps/prompts/mcp.ts
|
|
8
|
+
2:1 warning There should be at least one empty line between import groups import/order
|
|
9
|
+
3:1 warning There should be at least one empty line between import groups import/order
|
|
10
|
+
4:1 warning `../../packages/mcp-utils/src/index.js` import should occur before import of `./services/prompt-store.js` import/order
|
|
11
|
+
|
|
12
|
+
/home/runner/_work/devglide/devglide/src/apps/prompts/services/prompt-store.ts
|
|
13
|
+
2:1 warning There should be at least one empty line between import groups import/order
|
|
14
|
+
4:1 warning `../../../project-context.js` import should occur before type import of `../types.js` import/order
|
|
15
|
+
5:1 warning `../../../packages/paths.js` import should occur before type import of `../types.js` import/order
|
|
16
|
+
6:1 warning `../../../packages/json-file-store.js` import should occur before type import of `../types.js` import/order
|
|
17
|
+
|
|
18
|
+
/home/runner/_work/devglide/devglide/src/apps/prompts/src/index.ts
|
|
19
|
+
2:1 warning There should be at least one empty line between import groups import/order
|
|
20
|
+
3:1 warning `@devglide/mcp-utils` import should occur before import of `../mcp.js` import/order
|
|
21
|
+
|
|
22
|
+
✖ 9 problems (0 errors, 9 warnings)
|
|
23
|
+
0 errors and 9 warnings potentially fixable with the `--fix` option.
|
|
24
|
+
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { PromptStore } from './services/prompt-store.js';
|
|
4
|
+
import { jsonResult, errorResult, createDevglideMcpServer } from '../../packages/mcp-utils/src/index.js';
|
|
5
|
+
|
|
6
|
+
export function createPromptsMcpServer(): McpServer {
|
|
7
|
+
const server = createDevglideMcpServer(
|
|
8
|
+
'devglide-prompts',
|
|
9
|
+
'0.1.0',
|
|
10
|
+
'Reusable prompt library with variable interpolation and ratings',
|
|
11
|
+
{
|
|
12
|
+
instructions: [
|
|
13
|
+
'## Prompts — Usage Conventions',
|
|
14
|
+
'',
|
|
15
|
+
'### Purpose',
|
|
16
|
+
'- The prompt library stores reusable LLM prompt templates with {{variable}} placeholders.',
|
|
17
|
+
'- Use it to avoid rewriting the same prompt from scratch in every conversation.',
|
|
18
|
+
'',
|
|
19
|
+
'### Managing prompts',
|
|
20
|
+
'- Use `prompts_list` and `prompts_render` to reuse existing prompts before writing new ones from scratch.',
|
|
21
|
+
'- Use `prompts_get` to retrieve the full prompt including content and variables.',
|
|
22
|
+
'- Use `prompts_add` to save a new reusable prompt template.',
|
|
23
|
+
'- Use `prompts_update` to refine content, adjust rating, or add evaluation notes.',
|
|
24
|
+
'- Use `prompts_remove` to delete a prompt by ID.',
|
|
25
|
+
'- Use `prompts_context` to get all prompts as compiled markdown for LLM context injection.',
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const store = PromptStore.getInstance();
|
|
31
|
+
|
|
32
|
+
// ── 1. prompts_list ───────────────────────────────────────────────────────
|
|
33
|
+
|
|
34
|
+
server.tool(
|
|
35
|
+
'prompts_list',
|
|
36
|
+
'List all prompts. Optionally filter by category, tags, or keyword search.',
|
|
37
|
+
{
|
|
38
|
+
category: z.string().optional().describe('Filter by category'),
|
|
39
|
+
tags: z.string().optional().describe('JSON array of tags to filter by (all must match)'),
|
|
40
|
+
search: z.string().optional().describe('Text search across title, description, category, and tags'),
|
|
41
|
+
},
|
|
42
|
+
async ({ category, tags, search }) => {
|
|
43
|
+
let parsedTags: string[] | undefined;
|
|
44
|
+
if (tags) {
|
|
45
|
+
try { parsedTags = JSON.parse(tags); } catch { return errorResult('Invalid JSON for tags'); }
|
|
46
|
+
}
|
|
47
|
+
const entries = await store.list({ category, tags: parsedTags, search });
|
|
48
|
+
return jsonResult(entries);
|
|
49
|
+
},
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
// ── 2. prompts_get ────────────────────────────────────────────────────────
|
|
53
|
+
|
|
54
|
+
server.tool(
|
|
55
|
+
'prompts_get',
|
|
56
|
+
'Get the full prompt by ID, including content and detected variables.',
|
|
57
|
+
{
|
|
58
|
+
id: z.string().describe('Prompt ID'),
|
|
59
|
+
},
|
|
60
|
+
async ({ id }) => {
|
|
61
|
+
const entry = await store.get(id);
|
|
62
|
+
if (!entry) return errorResult(`Prompt "${id}" not found`);
|
|
63
|
+
return jsonResult(entry);
|
|
64
|
+
},
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
// ── 3. prompts_render ─────────────────────────────────────────────────────
|
|
68
|
+
|
|
69
|
+
server.tool(
|
|
70
|
+
'prompts_render',
|
|
71
|
+
'Render a prompt template by substituting {{varName}} placeholders with provided values.',
|
|
72
|
+
{
|
|
73
|
+
id: z.string().describe('Prompt ID'),
|
|
74
|
+
vars: z.string().optional().describe('JSON object mapping variable names to values, e.g. {"name":"World"}'),
|
|
75
|
+
},
|
|
76
|
+
async ({ id, vars }) => {
|
|
77
|
+
let parsedVars: Record<string, string> = {};
|
|
78
|
+
if (vars) {
|
|
79
|
+
try { parsedVars = JSON.parse(vars); } catch { return errorResult('Invalid JSON for vars'); }
|
|
80
|
+
}
|
|
81
|
+
const rendered = await store.render(id, parsedVars);
|
|
82
|
+
if (rendered === null) return errorResult(`Prompt "${id}" not found`);
|
|
83
|
+
return { content: [{ type: 'text' as const, text: rendered }] };
|
|
84
|
+
},
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
// ── 4. prompts_add ────────────────────────────────────────────────────────
|
|
88
|
+
|
|
89
|
+
server.tool(
|
|
90
|
+
'prompts_add',
|
|
91
|
+
'Add a new prompt template to the library.',
|
|
92
|
+
{
|
|
93
|
+
title: z.string().describe('Human-readable name for this prompt'),
|
|
94
|
+
content: z.string().describe('Prompt text; use {{varName}} for variable placeholders'),
|
|
95
|
+
description: z.string().optional().describe('What this prompt does'),
|
|
96
|
+
category: z.string().optional().describe('Grouping category (e.g. "code-review", "refactor")'),
|
|
97
|
+
tags: z.string().optional().describe('JSON array of tag strings'),
|
|
98
|
+
model: z.string().optional().describe('Preferred model hint (e.g. "claude-opus-4-6")'),
|
|
99
|
+
temperature: z.number().min(0).max(2).optional().describe('Preferred temperature hint'),
|
|
100
|
+
rating: z.number().int().min(1).max(5).optional().describe('Quality rating 1–5'),
|
|
101
|
+
notes: z.string().optional().describe('Evaluation notes'),
|
|
102
|
+
scope: z.enum(['project', 'global']).optional().describe('Save as project-scoped or global (default: project if active, else global)'),
|
|
103
|
+
},
|
|
104
|
+
async ({ title, content, description, category, tags, model, temperature, rating, notes, scope }) => {
|
|
105
|
+
let parsedTags: string[] = [];
|
|
106
|
+
if (tags) {
|
|
107
|
+
try { parsedTags = JSON.parse(tags); } catch { return errorResult('Invalid JSON for tags'); }
|
|
108
|
+
}
|
|
109
|
+
const entry = await store.save({ title, content, description, category, tags: parsedTags, model, temperature, rating, notes, scope });
|
|
110
|
+
return jsonResult(entry);
|
|
111
|
+
},
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
// ── 5. prompts_update ─────────────────────────────────────────────────────
|
|
115
|
+
|
|
116
|
+
server.tool(
|
|
117
|
+
'prompts_update',
|
|
118
|
+
'Update an existing prompt by ID.',
|
|
119
|
+
{
|
|
120
|
+
id: z.string().describe('Prompt ID'),
|
|
121
|
+
title: z.string().optional().describe('New title'),
|
|
122
|
+
content: z.string().optional().describe('New prompt content'),
|
|
123
|
+
description: z.string().nullable().optional().describe('New description (null to clear)'),
|
|
124
|
+
category: z.string().nullable().optional().describe('New category (null to clear)'),
|
|
125
|
+
tags: z.string().nullable().optional().describe('JSON array of tag strings (null to clear)'),
|
|
126
|
+
model: z.string().nullable().optional().describe('Preferred model hint (null to clear)'),
|
|
127
|
+
temperature: z.number().min(0).max(2).nullable().optional().describe('Preferred temperature (null to clear)'),
|
|
128
|
+
rating: z.number().int().min(1).max(5).nullable().optional().describe('Quality rating 1–5 (null to clear)'),
|
|
129
|
+
notes: z.string().nullable().optional().describe('Evaluation notes (null to clear)'),
|
|
130
|
+
},
|
|
131
|
+
async ({ id, title, content, description, category, tags, model, temperature, rating, notes }) => {
|
|
132
|
+
let parsedTags: string[] | null | undefined;
|
|
133
|
+
if (tags === null) {
|
|
134
|
+
parsedTags = [];
|
|
135
|
+
} else if (tags) {
|
|
136
|
+
try { parsedTags = JSON.parse(tags); } catch { return errorResult('Invalid JSON for tags'); }
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const updated = await store.update(id, { title, content, description, category, tags: parsedTags, model, temperature, rating, notes });
|
|
140
|
+
if (!updated) return errorResult('Prompt not found');
|
|
141
|
+
return jsonResult(updated);
|
|
142
|
+
},
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
// ── 6. prompts_remove ─────────────────────────────────────────────────────
|
|
146
|
+
|
|
147
|
+
server.tool(
|
|
148
|
+
'prompts_remove',
|
|
149
|
+
'Delete a prompt by ID.',
|
|
150
|
+
{
|
|
151
|
+
id: z.string().describe('Prompt ID'),
|
|
152
|
+
},
|
|
153
|
+
async ({ id }) => {
|
|
154
|
+
const deleted = await store.delete(id);
|
|
155
|
+
if (!deleted) return errorResult('Prompt not found');
|
|
156
|
+
return jsonResult({ ok: true });
|
|
157
|
+
},
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
// ── 7. prompts_context ──────────────────────────────────────────────────
|
|
161
|
+
|
|
162
|
+
server.tool(
|
|
163
|
+
'prompts_context',
|
|
164
|
+
'Get all prompts as compiled markdown for LLM context injection.',
|
|
165
|
+
{},
|
|
166
|
+
async () => {
|
|
167
|
+
const markdown = await store.getCompiledContext();
|
|
168
|
+
return {
|
|
169
|
+
content: [{ type: 'text' as const, text: markdown || 'No prompts defined.' }],
|
|
170
|
+
};
|
|
171
|
+
},
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
return server;
|
|
175
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
+
|
|
4
|
+
case `uname` in
|
|
5
|
+
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
+
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
+
basedir=`cygpath -w "$basedir"`
|
|
8
|
+
fi
|
|
9
|
+
;;
|
|
10
|
+
esac
|
|
11
|
+
|
|
12
|
+
if [ -z "$NODE_PATH" ]; then
|
|
13
|
+
export NODE_PATH="/home/runner/_work/devglide/devglide/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/home/runner/_work/devglide/devglide/node_modules/.pnpm/typescript@5.9.3/node_modules:/home/runner/_work/devglide/devglide/node_modules/.pnpm/node_modules"
|
|
14
|
+
else
|
|
15
|
+
export NODE_PATH="/home/runner/_work/devglide/devglide/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/home/runner/_work/devglide/devglide/node_modules/.pnpm/typescript@5.9.3/node_modules:/home/runner/_work/devglide/devglide/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
+
fi
|
|
17
|
+
if [ -x "$basedir/node" ]; then
|
|
18
|
+
exec "$basedir/node" "$basedir/../typescript/bin/tsc" "$@"
|
|
19
|
+
else
|
|
20
|
+
exec node "$basedir/../typescript/bin/tsc" "$@"
|
|
21
|
+
fi
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
+
|
|
4
|
+
case `uname` in
|
|
5
|
+
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
+
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
+
basedir=`cygpath -w "$basedir"`
|
|
8
|
+
fi
|
|
9
|
+
;;
|
|
10
|
+
esac
|
|
11
|
+
|
|
12
|
+
if [ -z "$NODE_PATH" ]; then
|
|
13
|
+
export NODE_PATH="/home/runner/_work/devglide/devglide/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/home/runner/_work/devglide/devglide/node_modules/.pnpm/typescript@5.9.3/node_modules:/home/runner/_work/devglide/devglide/node_modules/.pnpm/node_modules"
|
|
14
|
+
else
|
|
15
|
+
export NODE_PATH="/home/runner/_work/devglide/devglide/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/home/runner/_work/devglide/devglide/node_modules/.pnpm/typescript@5.9.3/node_modules:/home/runner/_work/devglide/devglide/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
+
fi
|
|
17
|
+
if [ -x "$basedir/node" ]; then
|
|
18
|
+
exec "$basedir/node" "$basedir/../typescript/bin/tsserver" "$@"
|
|
19
|
+
else
|
|
20
|
+
exec node "$basedir/../typescript/bin/tsserver" "$@"
|
|
21
|
+
fi
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
+
|
|
4
|
+
case `uname` in
|
|
5
|
+
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
+
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
+
basedir=`cygpath -w "$basedir"`
|
|
8
|
+
fi
|
|
9
|
+
;;
|
|
10
|
+
esac
|
|
11
|
+
|
|
12
|
+
if [ -z "$NODE_PATH" ]; then
|
|
13
|
+
export NODE_PATH="/home/runner/_work/devglide/devglide/node_modules/.pnpm/tsx@4.21.0/node_modules/tsx/node_modules:/home/runner/_work/devglide/devglide/node_modules/.pnpm/tsx@4.21.0/node_modules:/home/runner/_work/devglide/devglide/node_modules/.pnpm/node_modules"
|
|
14
|
+
else
|
|
15
|
+
export NODE_PATH="/home/runner/_work/devglide/devglide/node_modules/.pnpm/tsx@4.21.0/node_modules/tsx/node_modules:/home/runner/_work/devglide/devglide/node_modules/.pnpm/tsx@4.21.0/node_modules:/home/runner/_work/devglide/devglide/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
+
fi
|
|
17
|
+
if [ -x "$basedir/node" ]; then
|
|
18
|
+
exec "$basedir/node" "$basedir/../tsx/dist/cli.mjs" "$@"
|
|
19
|
+
else
|
|
20
|
+
exec node "$basedir/../tsx/dist/cli.mjs" "$@"
|
|
21
|
+
fi
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@devglide/prompts",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Reusable prompt library with variable interpolation and ratings",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/src/index.js",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"dev": "tsx watch src/index.ts",
|
|
9
|
+
"build": "tsc",
|
|
10
|
+
"start": "node dist/src/index.js",
|
|
11
|
+
"clean": "rm -rf dist",
|
|
12
|
+
"typecheck": "tsc --noEmit",
|
|
13
|
+
"lint": "eslint ."
|
|
14
|
+
},
|
|
15
|
+
"private": true,
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@devglide/mcp-utils": "workspace:*",
|
|
18
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
19
|
+
"zod": "^3.25.49"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"tsx": "^4.19.4",
|
|
23
|
+
"typescript": "^5.8.0"
|
|
24
|
+
}
|
|
25
|
+
}
|