openkitt 0.1.2
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 +236 -0
- package/dist/ast/engine.d.ts +26 -0
- package/dist/ast/engine.js +130 -0
- package/dist/ast/engine.js.map +1 -0
- package/dist/ast/operations.d.ts +13 -0
- package/dist/ast/operations.js +329 -0
- package/dist/ast/operations.js.map +1 -0
- package/dist/ast/validator.d.ts +19 -0
- package/dist/ast/validator.js +281 -0
- package/dist/ast/validator.js.map +1 -0
- package/dist/audit/logger.d.ts +14 -0
- package/dist/audit/logger.js +102 -0
- package/dist/audit/logger.js.map +1 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.js +401 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/create-confirm.d.ts +13 -0
- package/dist/commands/create-confirm.js +38 -0
- package/dist/commands/create-confirm.js.map +1 -0
- package/dist/commands/create-infra.d.ts +20 -0
- package/dist/commands/create-infra.js +63 -0
- package/dist/commands/create-infra.js.map +1 -0
- package/dist/commands/create-manifest.d.ts +10 -0
- package/dist/commands/create-manifest.js +21 -0
- package/dist/commands/create-manifest.js.map +1 -0
- package/dist/commands/create-packages.d.ts +17 -0
- package/dist/commands/create-packages.js +69 -0
- package/dist/commands/create-packages.js.map +1 -0
- package/dist/commands/create-pipeline.d.ts +15 -0
- package/dist/commands/create-pipeline.js +57 -0
- package/dist/commands/create-pipeline.js.map +1 -0
- package/dist/commands/create-scaffolding.d.ts +12 -0
- package/dist/commands/create-scaffolding.js +137 -0
- package/dist/commands/create-scaffolding.js.map +1 -0
- package/dist/commands/create-staging.d.ts +13 -0
- package/dist/commands/create-staging.js +17 -0
- package/dist/commands/create-staging.js.map +1 -0
- package/dist/commands/create-transforms.d.ts +10 -0
- package/dist/commands/create-transforms.js +33 -0
- package/dist/commands/create-transforms.js.map +1 -0
- package/dist/commands/create.d.ts +2 -0
- package/dist/commands/create.js +155 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/delete.d.ts +2 -0
- package/dist/commands/delete.js +83 -0
- package/dist/commands/delete.js.map +1 -0
- package/dist/commands/deploy.d.ts +5 -0
- package/dist/commands/deploy.js +371 -0
- package/dist/commands/deploy.js.map +1 -0
- package/dist/commands/domain.d.ts +2 -0
- package/dist/commands/domain.js +90 -0
- package/dist/commands/domain.js.map +1 -0
- package/dist/commands/env.d.ts +2 -0
- package/dist/commands/env.js +153 -0
- package/dist/commands/env.js.map +1 -0
- package/dist/commands/help.d.ts +3 -0
- package/dist/commands/help.js +107 -0
- package/dist/commands/help.js.map +1 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +217 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/list.d.ts +2 -0
- package/dist/commands/list.js +142 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.js +235 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logs.d.ts +2 -0
- package/dist/commands/logs.js +90 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/publish.d.ts +2 -0
- package/dist/commands/publish.js +113 -0
- package/dist/commands/publish.js.map +1 -0
- package/dist/commands/run.d.ts +14 -0
- package/dist/commands/run.js +196 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/settings.d.ts +3 -0
- package/dist/commands/settings.js +278 -0
- package/dist/commands/settings.js.map +1 -0
- package/dist/commands/status.d.ts +2 -0
- package/dist/commands/status.js +88 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/versions.d.ts +2 -0
- package/dist/commands/versions.js +242 -0
- package/dist/commands/versions.js.map +1 -0
- package/dist/credentials/config.d.ts +12 -0
- package/dist/credentials/config.js +196 -0
- package/dist/credentials/config.js.map +1 -0
- package/dist/credentials/encryption.d.ts +9 -0
- package/dist/credentials/encryption.js +100 -0
- package/dist/credentials/encryption.js.map +1 -0
- package/dist/credentials/keychain.d.ts +8 -0
- package/dist/credentials/keychain.js +236 -0
- package/dist/credentials/keychain.js.map +1 -0
- package/dist/credentials/railway.d.ts +9 -0
- package/dist/credentials/railway.js +69 -0
- package/dist/credentials/railway.js.map +1 -0
- package/dist/llm/client.d.ts +59 -0
- package/dist/llm/client.js +530 -0
- package/dist/llm/client.js.map +1 -0
- package/dist/llm/operations.d.ts +39 -0
- package/dist/llm/operations.js +131 -0
- package/dist/llm/operations.js.map +1 -0
- package/dist/llm/rate-limiter.d.ts +20 -0
- package/dist/llm/rate-limiter.js +57 -0
- package/dist/llm/rate-limiter.js.map +1 -0
- package/dist/llm/scaffolding.d.ts +51 -0
- package/dist/llm/scaffolding.js +118 -0
- package/dist/llm/scaffolding.js.map +1 -0
- package/dist/manifest/drift.d.ts +6 -0
- package/dist/manifest/drift.js +45 -0
- package/dist/manifest/drift.js.map +1 -0
- package/dist/manifest/reader.d.ts +12 -0
- package/dist/manifest/reader.js +99 -0
- package/dist/manifest/reader.js.map +1 -0
- package/dist/manifest/types.d.ts +31 -0
- package/dist/manifest/types.js +2 -0
- package/dist/manifest/types.js.map +1 -0
- package/dist/manifest/writer.d.ts +9 -0
- package/dist/manifest/writer.js +142 -0
- package/dist/manifest/writer.js.map +1 -0
- package/dist/mcp/client.d.ts +21 -0
- package/dist/mcp/client.js +213 -0
- package/dist/mcp/client.js.map +1 -0
- package/dist/mcp/lifecycle.d.ts +12 -0
- package/dist/mcp/lifecycle.js +149 -0
- package/dist/mcp/lifecycle.js.map +1 -0
- package/dist/mcp/project-guard.d.ts +14 -0
- package/dist/mcp/project-guard.js +27 -0
- package/dist/mcp/project-guard.js.map +1 -0
- package/dist/prompts/operations.d.ts +1 -0
- package/dist/prompts/operations.js +160 -0
- package/dist/prompts/operations.js.map +1 -0
- package/dist/prompts/scaffolding.d.ts +1 -0
- package/dist/prompts/scaffolding.js +331 -0
- package/dist/prompts/scaffolding.js.map +1 -0
- package/dist/prompts/version.d.ts +2 -0
- package/dist/prompts/version.js +3 -0
- package/dist/prompts/version.js.map +1 -0
- package/dist/sandbox/command-allowlist.d.ts +6 -0
- package/dist/sandbox/command-allowlist.js +103 -0
- package/dist/sandbox/command-allowlist.js.map +1 -0
- package/dist/sandbox/package-allowlist.d.ts +6 -0
- package/dist/sandbox/package-allowlist.js +49 -0
- package/dist/sandbox/package-allowlist.js.map +1 -0
- package/dist/sandbox/scanner.d.ts +25 -0
- package/dist/sandbox/scanner.js +196 -0
- package/dist/sandbox/scanner.js.map +1 -0
- package/dist/sandbox/staging.d.ts +12 -0
- package/dist/sandbox/staging.js +107 -0
- package/dist/sandbox/staging.js.map +1 -0
- package/dist/scaffold/frameworks/express.d.ts +3 -0
- package/dist/scaffold/frameworks/express.js +242 -0
- package/dist/scaffold/frameworks/express.js.map +1 -0
- package/dist/scaffold/frameworks/hono.d.ts +3 -0
- package/dist/scaffold/frameworks/hono.js +238 -0
- package/dist/scaffold/frameworks/hono.js.map +1 -0
- package/dist/scaffold/frameworks/nextjs.d.ts +3 -0
- package/dist/scaffold/frameworks/nextjs.js +447 -0
- package/dist/scaffold/frameworks/nextjs.js.map +1 -0
- package/dist/scaffold/frameworks/tanstack-start.d.ts +3 -0
- package/dist/scaffold/frameworks/tanstack-start.js +280 -0
- package/dist/scaffold/frameworks/tanstack-start.js.map +1 -0
- package/dist/scaffold/index.d.ts +4 -0
- package/dist/scaffold/index.js +138 -0
- package/dist/scaffold/index.js.map +1 -0
- package/dist/scaffold/integrations/backend.d.ts +3 -0
- package/dist/scaffold/integrations/backend.js +403 -0
- package/dist/scaffold/integrations/backend.js.map +1 -0
- package/dist/scaffold/integrations/posthog.d.ts +2 -0
- package/dist/scaffold/integrations/posthog.js +21 -0
- package/dist/scaffold/integrations/posthog.js.map +1 -0
- package/dist/scaffold/integrations/sentry.d.ts +2 -0
- package/dist/scaffold/integrations/sentry.js +16 -0
- package/dist/scaffold/integrations/sentry.js.map +1 -0
- package/dist/scaffold/integrations/storybook.d.ts +2 -0
- package/dist/scaffold/integrations/storybook.js +79 -0
- package/dist/scaffold/integrations/storybook.js.map +1 -0
- package/dist/scaffold/integrations/vitest.d.ts +2 -0
- package/dist/scaffold/integrations/vitest.js +37 -0
- package/dist/scaffold/integrations/vitest.js.map +1 -0
- package/dist/scaffold/package-builder.d.ts +3 -0
- package/dist/scaffold/package-builder.js +136 -0
- package/dist/scaffold/package-builder.js.map +1 -0
- package/dist/scaffold/packages.d.ts +4 -0
- package/dist/scaffold/packages.js +144 -0
- package/dist/scaffold/packages.js.map +1 -0
- package/dist/scaffold/types.d.ts +20 -0
- package/dist/scaffold/types.js +2 -0
- package/dist/scaffold/types.js.map +1 -0
- package/dist/types.d.ts +11 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/auth-guard.d.ts +5 -0
- package/dist/utils/auth-guard.js +52 -0
- package/dist/utils/auth-guard.js.map +1 -0
- package/dist/utils/cleanup.d.ts +2 -0
- package/dist/utils/cleanup.js +37 -0
- package/dist/utils/cleanup.js.map +1 -0
- package/dist/utils/constraints.d.ts +11 -0
- package/dist/utils/constraints.js +162 -0
- package/dist/utils/constraints.js.map +1 -0
- package/dist/utils/display.d.ts +32 -0
- package/dist/utils/display.js +103 -0
- package/dist/utils/display.js.map +1 -0
- package/dist/utils/global-config.d.ts +8 -0
- package/dist/utils/global-config.js +39 -0
- package/dist/utils/global-config.js.map +1 -0
- package/dist/utils/pm.d.ts +4 -0
- package/dist/utils/pm.js +40 -0
- package/dist/utils/pm.js.map +1 -0
- package/dist/utils/prerequisites.d.ts +9 -0
- package/dist/utils/prerequisites.js +96 -0
- package/dist/utils/prerequisites.js.map +1 -0
- package/dist/utils/prompts.d.ts +25 -0
- package/dist/utils/prompts.js +148 -0
- package/dist/utils/prompts.js.map +1 -0
- package/dist/utils/validation.d.ts +9 -0
- package/dist/utils/validation.js +38 -0
- package/dist/utils/validation.js.map +1 -0
- package/dist/versions/compat.d.ts +13 -0
- package/dist/versions/compat.js +127 -0
- package/dist/versions/compat.js.map +1 -0
- package/dist/versions/integrity.d.ts +9 -0
- package/dist/versions/integrity.js +60 -0
- package/dist/versions/integrity.js.map +1 -0
- package/dist/versions/parser.d.ts +13 -0
- package/dist/versions/parser.js +106 -0
- package/dist/versions/parser.js.map +1 -0
- package/dist/versions/registry.d.ts +30 -0
- package/dist/versions/registry.js +165 -0
- package/dist/versions/registry.js.map +1 -0
- package/package.json +58 -0
- package/scripts/publish.sh +254 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { OPERATIONS_SYSTEM_PROMPT } from '../prompts/operations.js';
|
|
2
|
+
import { MAX_RETRIES } from './rate-limiter.js';
|
|
3
|
+
const MAX_TOOL_LOOP_ITERATIONS = MAX_RETRIES * 3 + 1;
|
|
4
|
+
function toLlmTools(tools) {
|
|
5
|
+
return tools.map((tool) => ({
|
|
6
|
+
name: tool.name,
|
|
7
|
+
description: tool.description,
|
|
8
|
+
inputSchema: tool.inputSchema,
|
|
9
|
+
}));
|
|
10
|
+
}
|
|
11
|
+
function isToolUseStopReason(stopReason) {
|
|
12
|
+
return stopReason === 'tool_use' || stopReason === 'tool_calls';
|
|
13
|
+
}
|
|
14
|
+
function formatToolResultContent(result) {
|
|
15
|
+
if (result.content.length === 0) {
|
|
16
|
+
return '';
|
|
17
|
+
}
|
|
18
|
+
return result.content.map((item) => item.text).join('\n');
|
|
19
|
+
}
|
|
20
|
+
function formatToolError(error) {
|
|
21
|
+
if (error instanceof Error) {
|
|
22
|
+
return error.message;
|
|
23
|
+
}
|
|
24
|
+
return String(error);
|
|
25
|
+
}
|
|
26
|
+
function toAssistantHistoryEntry(response) {
|
|
27
|
+
const entry = {
|
|
28
|
+
role: 'assistant',
|
|
29
|
+
content: response.content,
|
|
30
|
+
};
|
|
31
|
+
if (response.toolCalls.length > 0) {
|
|
32
|
+
entry.tool_calls = response.toolCalls.map((call) => ({
|
|
33
|
+
id: call.id,
|
|
34
|
+
type: 'function',
|
|
35
|
+
function: {
|
|
36
|
+
name: call.name,
|
|
37
|
+
arguments: JSON.stringify(call.arguments),
|
|
38
|
+
},
|
|
39
|
+
}));
|
|
40
|
+
}
|
|
41
|
+
return entry;
|
|
42
|
+
}
|
|
43
|
+
async function executeToolCall(options) {
|
|
44
|
+
const { toolCall, mcpClient, projectGuard } = options;
|
|
45
|
+
try {
|
|
46
|
+
const result = projectGuard
|
|
47
|
+
? await projectGuard.guardedCallTool(mcpClient, toolCall.name, toolCall.arguments)
|
|
48
|
+
: await mcpClient.callTool(toolCall.name, toolCall.arguments);
|
|
49
|
+
return {
|
|
50
|
+
toolCallId: toolCall.id,
|
|
51
|
+
content: formatToolResultContent(result),
|
|
52
|
+
...(result.isError ? { isError: true } : {}),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
return {
|
|
57
|
+
toolCallId: toolCall.id,
|
|
58
|
+
content: formatToolError(error),
|
|
59
|
+
isError: true,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
export function buildOperationsContext(command, args, manifest) {
|
|
64
|
+
const apps = Object.fromEntries(Object.entries(manifest.apps).map(([appName, app]) => [
|
|
65
|
+
appName,
|
|
66
|
+
{
|
|
67
|
+
type: app.type,
|
|
68
|
+
framework: app.framework,
|
|
69
|
+
integrations: app.integrations,
|
|
70
|
+
...(app.railway ? { railway: app.railway } : {}),
|
|
71
|
+
},
|
|
72
|
+
]));
|
|
73
|
+
const packages = Object.fromEntries(Object.entries(manifest.packages).map(([packageName, pkg]) => [
|
|
74
|
+
packageName,
|
|
75
|
+
{
|
|
76
|
+
active: pkg.active,
|
|
77
|
+
consumers: pkg.consumers,
|
|
78
|
+
...(pkg.clients ? { clients: pkg.clients } : {}),
|
|
79
|
+
},
|
|
80
|
+
]));
|
|
81
|
+
return {
|
|
82
|
+
command,
|
|
83
|
+
args,
|
|
84
|
+
workspace: {
|
|
85
|
+
name: manifest.workspace.name,
|
|
86
|
+
packageManager: manifest.workspace.packageManager,
|
|
87
|
+
...(manifest.workspace.railway ? { railway: manifest.workspace.railway } : {}),
|
|
88
|
+
apps,
|
|
89
|
+
packages,
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
export async function executeOperations(options) {
|
|
94
|
+
const { llmClient, mcpClient, context, projectGuard } = options;
|
|
95
|
+
const tools = toLlmTools(await mcpClient.listTools());
|
|
96
|
+
const userMessage = JSON.stringify(context, null, 2);
|
|
97
|
+
const conversationHistory = [{ role: 'user', content: userMessage }];
|
|
98
|
+
let response = await llmClient.sendMessageWithTools({
|
|
99
|
+
systemPrompt: OPERATIONS_SYSTEM_PROMPT,
|
|
100
|
+
userMessage,
|
|
101
|
+
tools,
|
|
102
|
+
});
|
|
103
|
+
for (let iteration = 0; iteration < MAX_TOOL_LOOP_ITERATIONS; iteration += 1) {
|
|
104
|
+
const hasToolCalls = response.toolCalls.length > 0;
|
|
105
|
+
const expectsToolCalls = isToolUseStopReason(response.stopReason);
|
|
106
|
+
if (!hasToolCalls && !expectsToolCalls) {
|
|
107
|
+
return response.content;
|
|
108
|
+
}
|
|
109
|
+
if (!hasToolCalls && expectsToolCalls) {
|
|
110
|
+
return response.content;
|
|
111
|
+
}
|
|
112
|
+
conversationHistory.push(toAssistantHistoryEntry(response));
|
|
113
|
+
const toolResults = [];
|
|
114
|
+
for (const toolCall of response.toolCalls) {
|
|
115
|
+
const result = await executeToolCall({
|
|
116
|
+
toolCall,
|
|
117
|
+
mcpClient,
|
|
118
|
+
projectGuard,
|
|
119
|
+
});
|
|
120
|
+
toolResults.push(result);
|
|
121
|
+
}
|
|
122
|
+
response = await llmClient.sendToolResults({
|
|
123
|
+
conversationHistory,
|
|
124
|
+
toolResults,
|
|
125
|
+
systemPrompt: OPERATIONS_SYSTEM_PROMPT,
|
|
126
|
+
tools,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
throw new Error(`Operations tool-use loop exceeded maximum iterations (${MAX_TOOL_LOOP_ITERATIONS}).`);
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=operations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operations.js","sourceRoot":"","sources":["../../src/llm/operations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare const MAX_RETRIES = 3;
|
|
2
|
+
export declare const WARN_THRESHOLD = 50;
|
|
3
|
+
export declare const BLOCK_THRESHOLD = 100;
|
|
4
|
+
export type RateLimitCheck = {
|
|
5
|
+
allowed: boolean;
|
|
6
|
+
reason?: string;
|
|
7
|
+
callCount: number;
|
|
8
|
+
};
|
|
9
|
+
export interface RateLimiter {
|
|
10
|
+
recordCall(estimatedTokens: number): void;
|
|
11
|
+
canMakeCall(): RateLimitCheck;
|
|
12
|
+
getCallCount(): number;
|
|
13
|
+
getEstimatedTokensUsed(): number;
|
|
14
|
+
shouldWarn(): boolean;
|
|
15
|
+
isBlocked(): boolean;
|
|
16
|
+
reset(): void;
|
|
17
|
+
}
|
|
18
|
+
export declare function calculateBackoff(attempt: number): number;
|
|
19
|
+
export declare function estimateTokens(systemPrompt: string, userMessage: string): number;
|
|
20
|
+
export declare function createRateLimiter(): RateLimiter;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { warn } from '../utils/display.js';
|
|
2
|
+
export const MAX_RETRIES = 3;
|
|
3
|
+
export const WARN_THRESHOLD = 50;
|
|
4
|
+
export const BLOCK_THRESHOLD = 100;
|
|
5
|
+
const BACKOFF_BASE_MS = 1_000;
|
|
6
|
+
const CHARS_PER_TOKEN = 4;
|
|
7
|
+
export function calculateBackoff(attempt) {
|
|
8
|
+
const normalizedAttempt = Math.max(1, Math.min(attempt, MAX_RETRIES));
|
|
9
|
+
return BACKOFF_BASE_MS * 4 ** (normalizedAttempt - 1);
|
|
10
|
+
}
|
|
11
|
+
export function estimateTokens(systemPrompt, userMessage) {
|
|
12
|
+
const totalChars = systemPrompt.length + userMessage.length;
|
|
13
|
+
return Math.ceil(totalChars / CHARS_PER_TOKEN);
|
|
14
|
+
}
|
|
15
|
+
export function createRateLimiter() {
|
|
16
|
+
let callCount = 0;
|
|
17
|
+
let estimatedTokensUsed = 0;
|
|
18
|
+
return {
|
|
19
|
+
recordCall(estimatedTokens) {
|
|
20
|
+
if (callCount >= BLOCK_THRESHOLD) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
callCount += 1;
|
|
24
|
+
estimatedTokensUsed += Math.max(0, estimatedTokens);
|
|
25
|
+
if (callCount === WARN_THRESHOLD) {
|
|
26
|
+
warn('50 LLM API calls made this session. Continue? (y/n)');
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
canMakeCall() {
|
|
30
|
+
if (callCount >= BLOCK_THRESHOLD) {
|
|
31
|
+
return {
|
|
32
|
+
allowed: false,
|
|
33
|
+
reason: 'LLM call limit reached for this session. Start a new session to continue.',
|
|
34
|
+
callCount,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
return { allowed: true, callCount };
|
|
38
|
+
},
|
|
39
|
+
getCallCount() {
|
|
40
|
+
return callCount;
|
|
41
|
+
},
|
|
42
|
+
getEstimatedTokensUsed() {
|
|
43
|
+
return estimatedTokensUsed;
|
|
44
|
+
},
|
|
45
|
+
shouldWarn() {
|
|
46
|
+
return callCount >= WARN_THRESHOLD && callCount < BLOCK_THRESHOLD;
|
|
47
|
+
},
|
|
48
|
+
isBlocked() {
|
|
49
|
+
return callCount >= BLOCK_THRESHOLD;
|
|
50
|
+
},
|
|
51
|
+
reset() {
|
|
52
|
+
callCount = 0;
|
|
53
|
+
estimatedTokensUsed = 0;
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=rate-limiter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../src/llm/rate-limiter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAE3C,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC;AAC7B,MAAM,CAAC,MAAM,cAAc,GAAG,EAAE,CAAC;AACjC,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,CAAC;AAEnC,MAAM,eAAe,GAAG,KAAK,CAAC;AAC9B,MAAM,eAAe,GAAG,CAAC,CAAC;AAc1B,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,MAAM,iBAAiB,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC;IACtE,OAAO,eAAe,GAAG,CAAC,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAC,CAAC;AACxD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,YAAoB,EAAE,WAAmB;IACtE,MAAM,UAAU,GAAG,YAAY,CAAC,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC;IAC5D,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,GAAG,eAAe,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,mBAAmB,GAAG,CAAC,CAAC;IAE5B,OAAO;QACL,UAAU,CAAC,eAAe;YACxB,IAAI,SAAS,IAAI,eAAe,EAAE,CAAC;gBACjC,OAAO;YACT,CAAC;YAED,SAAS,IAAI,CAAC,CAAC;YACf,mBAAmB,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC;YAEpD,IAAI,SAAS,KAAK,cAAc,EAAE,CAAC;gBACjC,IAAI,CAAC,qDAAqD,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC;QAED,WAAW;YACT,IAAI,SAAS,IAAI,eAAe,EAAE,CAAC;gBACjC,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,MAAM,EAAE,2EAA2E;oBACnF,SAAS;iBACV,CAAC;YACJ,CAAC;YAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;QACtC,CAAC;QAED,YAAY;YACV,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,sBAAsB;YACpB,OAAO,mBAAmB,CAAC;QAC7B,CAAC;QAED,UAAU;YACR,OAAO,SAAS,IAAI,cAAc,IAAI,SAAS,GAAG,eAAe,CAAC;QACpE,CAAC;QAED,SAAS;YACP,OAAO,SAAS,IAAI,eAAe,CAAC;QACtC,CAAC;QAED,KAAK;YACH,SAAS,GAAG,CAAC,CAAC;YACd,mBAAmB,GAAG,CAAC,CAAC;QAC1B,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { WorkspaceManifest } from '../manifest/types.js';
|
|
2
|
+
import type { LlmClient } from './client.js';
|
|
3
|
+
export interface ScaffoldingContext {
|
|
4
|
+
appName: string;
|
|
5
|
+
appType: 'frontend' | 'backend';
|
|
6
|
+
framework: string;
|
|
7
|
+
integrations: string[];
|
|
8
|
+
versions: Record<string, string>;
|
|
9
|
+
packageManager: 'bun' | 'npm' | 'pnpm' | 'yarn';
|
|
10
|
+
existingPackages: Record<string, {
|
|
11
|
+
active: boolean;
|
|
12
|
+
consumers: string[];
|
|
13
|
+
clients?: string[];
|
|
14
|
+
}>;
|
|
15
|
+
workspaceName: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ScaffoldingResponse {
|
|
18
|
+
commands: Array<{
|
|
19
|
+
command: string;
|
|
20
|
+
purpose: string;
|
|
21
|
+
}>;
|
|
22
|
+
newFiles: Array<{
|
|
23
|
+
path: string;
|
|
24
|
+
content: string;
|
|
25
|
+
}>;
|
|
26
|
+
astTransforms: Array<{
|
|
27
|
+
path: string;
|
|
28
|
+
operations: Array<Record<string, unknown>>;
|
|
29
|
+
}>;
|
|
30
|
+
}
|
|
31
|
+
export interface ScaffoldingDebugInfo {
|
|
32
|
+
durationMs: number;
|
|
33
|
+
inputTokens: number;
|
|
34
|
+
outputTokens: number;
|
|
35
|
+
}
|
|
36
|
+
export interface ScaffoldingResult {
|
|
37
|
+
scaffolding: ScaffoldingResponse;
|
|
38
|
+
debug: ScaffoldingDebugInfo;
|
|
39
|
+
}
|
|
40
|
+
interface BuildScaffoldingContextOptions {
|
|
41
|
+
appName: string;
|
|
42
|
+
appType: 'frontend' | 'backend';
|
|
43
|
+
framework: string;
|
|
44
|
+
integrations: string[];
|
|
45
|
+
versions: Record<string, string>;
|
|
46
|
+
manifest: WorkspaceManifest;
|
|
47
|
+
}
|
|
48
|
+
export declare function buildScaffoldingContext(options: BuildScaffoldingContextOptions): ScaffoldingContext;
|
|
49
|
+
export declare function parseScaffoldingResponse(raw: string): ScaffoldingResponse;
|
|
50
|
+
export declare function executeScaffolding(client: LlmClient, context: ScaffoldingContext, onChunk?: (chunkText: string, totalChars: number) => void): Promise<ScaffoldingResult>;
|
|
51
|
+
export {};
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { SCAFFOLDING_SYSTEM_PROMPT } from '../prompts/scaffolding.js';
|
|
2
|
+
import { MAX_RETRIES, calculateBackoff } from './rate-limiter.js';
|
|
3
|
+
function isRecord(value) {
|
|
4
|
+
return typeof value === 'object' && value !== null;
|
|
5
|
+
}
|
|
6
|
+
function isScaffoldingResponse(value) {
|
|
7
|
+
if (!isRecord(value)) {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
if (!Array.isArray(value.commands) || !Array.isArray(value.newFiles) || !Array.isArray(value.astTransforms)) {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
const commandsValid = value.commands.every((command) => {
|
|
14
|
+
if (!isRecord(command)) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
return typeof command.command === 'string' && typeof command.purpose === 'string';
|
|
18
|
+
});
|
|
19
|
+
const newFilesValid = value.newFiles.every((newFile) => {
|
|
20
|
+
if (!isRecord(newFile)) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
return typeof newFile.path === 'string' && typeof newFile.content === 'string';
|
|
24
|
+
});
|
|
25
|
+
const transformsValid = value.astTransforms.every((transform) => {
|
|
26
|
+
if (!isRecord(transform)) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
return typeof transform.path === 'string' && Array.isArray(transform.operations);
|
|
30
|
+
});
|
|
31
|
+
return commandsValid && newFilesValid && transformsValid;
|
|
32
|
+
}
|
|
33
|
+
const ANTHROPIC_SCAFFOLDING_MODEL = 'claude-haiku-4-5';
|
|
34
|
+
const SCAFFOLDING_MAX_TOKENS = 16000;
|
|
35
|
+
const OVERLOAD_RETRY_BASE_MS = 5_000;
|
|
36
|
+
const OVERLOAD_MAX_RETRY_MS = 30_000;
|
|
37
|
+
function createScaffoldingExecutor(client, onChunk) {
|
|
38
|
+
return {
|
|
39
|
+
async execute(context) {
|
|
40
|
+
const payload = {
|
|
41
|
+
...context,
|
|
42
|
+
appName: `<untrusted_user_input>${context.appName}</untrusted_user_input>`,
|
|
43
|
+
};
|
|
44
|
+
let lastError;
|
|
45
|
+
for (let attempt = 1; attempt <= MAX_RETRIES + 1; attempt += 1) {
|
|
46
|
+
try {
|
|
47
|
+
const startMs = Date.now();
|
|
48
|
+
const response = await client.sendMessage({
|
|
49
|
+
systemPrompt: SCAFFOLDING_SYSTEM_PROMPT,
|
|
50
|
+
userMessage: JSON.stringify(payload),
|
|
51
|
+
maxTokens: SCAFFOLDING_MAX_TOKENS,
|
|
52
|
+
modelOverride: client.getProvider() === 'anthropic' ? ANTHROPIC_SCAFFOLDING_MODEL : undefined,
|
|
53
|
+
onChunk,
|
|
54
|
+
});
|
|
55
|
+
const durationMs = Date.now() - startMs;
|
|
56
|
+
return {
|
|
57
|
+
scaffolding: parseScaffoldingResponse(response.content),
|
|
58
|
+
debug: {
|
|
59
|
+
durationMs,
|
|
60
|
+
inputTokens: response.usage?.inputTokens ?? 0,
|
|
61
|
+
outputTokens: response.usage?.outputTokens ?? 0,
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
67
|
+
if (attempt > MAX_RETRIES) {
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
const status = error.status;
|
|
71
|
+
const isOverloaded = status === 529;
|
|
72
|
+
const NON_RETRIABLE_STATUSES = new Set([400, 401, 403, 404, 422]);
|
|
73
|
+
if (status !== undefined && NON_RETRIABLE_STATUSES.has(status)) {
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
const delayMs = isOverloaded
|
|
77
|
+
? Math.min(OVERLOAD_RETRY_BASE_MS * 2 ** (attempt - 1), OVERLOAD_MAX_RETRY_MS) * (0.5 + Math.random() * 0.5)
|
|
78
|
+
: calculateBackoff(attempt);
|
|
79
|
+
await new Promise((resolve) => {
|
|
80
|
+
setTimeout(resolve, delayMs);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
throw lastError ?? new Error('Scaffolding request failed after retries.');
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
export function buildScaffoldingContext(options) {
|
|
89
|
+
return {
|
|
90
|
+
appName: options.appName,
|
|
91
|
+
appType: options.appType,
|
|
92
|
+
framework: options.framework,
|
|
93
|
+
integrations: [...options.integrations],
|
|
94
|
+
versions: { ...options.versions },
|
|
95
|
+
packageManager: options.manifest.workspace.packageManager,
|
|
96
|
+
existingPackages: { ...options.manifest.packages },
|
|
97
|
+
workspaceName: options.manifest.workspace.name,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
export function parseScaffoldingResponse(raw) {
|
|
101
|
+
let parsed;
|
|
102
|
+
const stripped = raw.replace(/^```(?:json)?\s*/i, '').replace(/\s*```\s*$/i, '').trim();
|
|
103
|
+
try {
|
|
104
|
+
parsed = JSON.parse(stripped);
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
throw new Error('Scaffolding response must be valid JSON.');
|
|
108
|
+
}
|
|
109
|
+
if (!isScaffoldingResponse(parsed)) {
|
|
110
|
+
throw new Error('Scaffolding response is missing required fields: commands, newFiles, astTransforms.');
|
|
111
|
+
}
|
|
112
|
+
return parsed;
|
|
113
|
+
}
|
|
114
|
+
export async function executeScaffolding(client, context, onChunk) {
|
|
115
|
+
const scaffoldingExecutor = createScaffoldingExecutor(client, onChunk);
|
|
116
|
+
return scaffoldingExecutor.execute(context);
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=scaffolding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scaffolding.js","sourceRoot":"","sources":["../../src/llm/scaffolding.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { existsSync, readdirSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
function listDirectories(parentDir) {
|
|
4
|
+
if (!existsSync(parentDir)) {
|
|
5
|
+
return [];
|
|
6
|
+
}
|
|
7
|
+
return readdirSync(parentDir, { withFileTypes: true })
|
|
8
|
+
.filter((entry) => entry.isDirectory())
|
|
9
|
+
.map((entry) => entry.name)
|
|
10
|
+
.sort((left, right) => left.localeCompare(right));
|
|
11
|
+
}
|
|
12
|
+
function detectSegmentDrift(options) {
|
|
13
|
+
const { workspaceDir, segment, manifestEntries } = options;
|
|
14
|
+
const segmentDir = join(workspaceDir, segment);
|
|
15
|
+
const diskDirectories = listDirectories(segmentDir);
|
|
16
|
+
const diskSet = new Set(diskDirectories);
|
|
17
|
+
const manifestNames = Object.keys(manifestEntries).sort((left, right) => left.localeCompare(right));
|
|
18
|
+
const orphanedDirectories = diskDirectories
|
|
19
|
+
.filter((dirName) => !Object.prototype.hasOwnProperty.call(manifestEntries, dirName))
|
|
20
|
+
.map((dirName) => `${segment}/${dirName}`);
|
|
21
|
+
const missingDirectories = manifestNames
|
|
22
|
+
.filter((entryName) => !diskSet.has(entryName))
|
|
23
|
+
.map((entryName) => `${segment}/${entryName}`);
|
|
24
|
+
return {
|
|
25
|
+
orphanedDirectories,
|
|
26
|
+
missingDirectories,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export function detectDrift(workspaceDir, manifest) {
|
|
30
|
+
const appsDrift = detectSegmentDrift({
|
|
31
|
+
workspaceDir,
|
|
32
|
+
segment: 'apps',
|
|
33
|
+
manifestEntries: manifest.apps,
|
|
34
|
+
});
|
|
35
|
+
const packagesDrift = detectSegmentDrift({
|
|
36
|
+
workspaceDir,
|
|
37
|
+
segment: 'packages',
|
|
38
|
+
manifestEntries: manifest.packages,
|
|
39
|
+
});
|
|
40
|
+
return {
|
|
41
|
+
orphanedDirectories: [...appsDrift.orphanedDirectories, ...packagesDrift.orphanedDirectories],
|
|
42
|
+
missingDirectories: [...appsDrift.missingDirectories, ...packagesDrift.missingDirectories],
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=drift.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drift.js","sourceRoot":"","sources":["../../src/manifest/drift.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AASjC,SAAS,eAAe,CAAC,SAAiB;IACxC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,WAAW,CAAC,SAAS,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;SACnD,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;SACtC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;SAC1B,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;AACtD,CAAC;AAED,SAAS,kBAAkB,CAAC,OAI3B;IACC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC;IAC3D,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IAC/C,MAAM,eAAe,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;IACpD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,CAAC;IACzC,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;IAEpG,MAAM,mBAAmB,GAAG,eAAe;SACxC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;SACpF,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,OAAO,IAAI,OAAO,EAAE,CAAC,CAAC;IAE7C,MAAM,kBAAkB,GAAG,aAAa;SACrC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;SAC9C,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,GAAG,OAAO,IAAI,SAAS,EAAE,CAAC,CAAC;IAEjD,OAAO;QACL,mBAAmB;QACnB,kBAAkB;KACnB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,YAAoB,EAAE,QAA2B;IAC3E,MAAM,SAAS,GAAG,kBAAkB,CAAC;QACnC,YAAY;QACZ,OAAO,EAAE,MAAM;QACf,eAAe,EAAE,QAAQ,CAAC,IAAI;KAC/B,CAAC,CAAC;IACH,MAAM,aAAa,GAAG,kBAAkB,CAAC;QACvC,YAAY;QACZ,OAAO,EAAE,UAAU;QACnB,eAAe,EAAE,QAAQ,CAAC,QAAQ;KACnC,CAAC,CAAC;IAEH,OAAO;QACL,mBAAmB,EAAE,CAAC,GAAG,SAAS,CAAC,mBAAmB,EAAE,GAAG,aAAa,CAAC,mBAAmB,CAAC;QAC7F,kBAAkB,EAAE,CAAC,GAAG,SAAS,CAAC,kBAAkB,EAAE,GAAG,aAAa,CAAC,kBAAkB,CAAC;KAC3F,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { WorkspaceManifest } from "./types.js";
|
|
2
|
+
export declare function getManifestPath(workspaceDir: string): string;
|
|
3
|
+
export declare function isKittWorkspace(dir: string): boolean;
|
|
4
|
+
export declare function findWorkspaceRoot(startDir: string): string | null;
|
|
5
|
+
export declare function readManifest(workspaceDir: string): WorkspaceManifest | null;
|
|
6
|
+
/**
|
|
7
|
+
* Read the manifest and silently purge any app entries whose `apps/<name>`
|
|
8
|
+
* directory no longer exists on disk. Writes the cleaned manifest back if
|
|
9
|
+
* any stale entries were found. Returns the up-to-date manifest, or null
|
|
10
|
+
* if the manifest could not be read.
|
|
11
|
+
*/
|
|
12
|
+
export declare function reconcileManifest(workspaceDir: string): WorkspaceManifest | null;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join, dirname, resolve } from "node:path";
|
|
3
|
+
import { getGlobalWorkspacePath } from '../utils/global-config.js';
|
|
4
|
+
import { removeApp, writeManifest } from './writer.js';
|
|
5
|
+
function isObjectRecord(value) {
|
|
6
|
+
return typeof value === "object" && value !== null;
|
|
7
|
+
}
|
|
8
|
+
function isValidWorkspaceManifest(value) {
|
|
9
|
+
if (!isObjectRecord(value)) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
if (typeof value.version !== "string") {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
if (!isObjectRecord(value.workspace)) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
if (typeof value.workspace.name !== "string") {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
const packageManager = value.workspace.packageManager;
|
|
22
|
+
if (packageManager !== "bun" && packageManager !== "npm" && packageManager !== "pnpm" && packageManager !== "yarn") {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
if (!isObjectRecord(value.apps)) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
if (!isObjectRecord(value.packages)) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
if (!isObjectRecord(value.settings)) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
export function getManifestPath(workspaceDir) {
|
|
37
|
+
return join(workspaceDir, ".kitt", "manifest.json");
|
|
38
|
+
}
|
|
39
|
+
export function isKittWorkspace(dir) {
|
|
40
|
+
return existsSync(getManifestPath(dir));
|
|
41
|
+
}
|
|
42
|
+
export function findWorkspaceRoot(startDir) {
|
|
43
|
+
// Walk up from startDir
|
|
44
|
+
let current = resolve(startDir);
|
|
45
|
+
while (true) {
|
|
46
|
+
if (isKittWorkspace(current))
|
|
47
|
+
return current;
|
|
48
|
+
const parent = dirname(current);
|
|
49
|
+
if (parent === current)
|
|
50
|
+
break; // reached filesystem root
|
|
51
|
+
current = parent;
|
|
52
|
+
}
|
|
53
|
+
// Fall back to globally registered workspace path
|
|
54
|
+
const globalPath = getGlobalWorkspacePath();
|
|
55
|
+
if (globalPath && isKittWorkspace(globalPath))
|
|
56
|
+
return globalPath;
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
export function readManifest(workspaceDir) {
|
|
60
|
+
const manifestPath = getManifestPath(workspaceDir);
|
|
61
|
+
if (!existsSync(manifestPath)) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
const raw = readFileSync(manifestPath, "utf-8").trim();
|
|
66
|
+
if (raw.length === 0) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
const parsed = JSON.parse(raw);
|
|
70
|
+
if (!isValidWorkspaceManifest(parsed)) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
return parsed;
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Read the manifest and silently purge any app entries whose `apps/<name>`
|
|
81
|
+
* directory no longer exists on disk. Writes the cleaned manifest back if
|
|
82
|
+
* any stale entries were found. Returns the up-to-date manifest, or null
|
|
83
|
+
* if the manifest could not be read.
|
|
84
|
+
*/
|
|
85
|
+
export function reconcileManifest(workspaceDir) {
|
|
86
|
+
const manifest = readManifest(workspaceDir);
|
|
87
|
+
if (!manifest)
|
|
88
|
+
return null;
|
|
89
|
+
const staleApps = Object.keys(manifest.apps).filter((name) => !existsSync(join(workspaceDir, 'apps', name)));
|
|
90
|
+
if (staleApps.length === 0)
|
|
91
|
+
return manifest;
|
|
92
|
+
let cleaned = manifest;
|
|
93
|
+
for (const name of staleApps) {
|
|
94
|
+
cleaned = removeApp(cleaned, name);
|
|
95
|
+
}
|
|
96
|
+
writeManifest(workspaceDir, cleaned);
|
|
97
|
+
return cleaned;
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=reader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reader.js","sourceRoot":"","sources":["../../src/manifest/reader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface RailwayInfo {
|
|
2
|
+
projectId: string;
|
|
3
|
+
linkedAt: string;
|
|
4
|
+
}
|
|
5
|
+
export interface AppRailway {
|
|
6
|
+
serviceId: string;
|
|
7
|
+
domain?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface AppEntry {
|
|
10
|
+
type: "frontend" | "backend";
|
|
11
|
+
framework: string;
|
|
12
|
+
integrations: string[];
|
|
13
|
+
railway?: AppRailway;
|
|
14
|
+
createdAt: string;
|
|
15
|
+
}
|
|
16
|
+
export interface PackageEntry {
|
|
17
|
+
active: boolean;
|
|
18
|
+
consumers: string[];
|
|
19
|
+
clients?: string[];
|
|
20
|
+
}
|
|
21
|
+
export interface WorkspaceManifest {
|
|
22
|
+
version: string;
|
|
23
|
+
workspace: {
|
|
24
|
+
name: string;
|
|
25
|
+
packageManager: "bun" | "npm" | "pnpm" | "yarn";
|
|
26
|
+
railway?: RailwayInfo;
|
|
27
|
+
};
|
|
28
|
+
settings: Record<string, unknown>;
|
|
29
|
+
apps: Record<string, AppEntry>;
|
|
30
|
+
packages: Record<string, PackageEntry>;
|
|
31
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/manifest/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { AppEntry, PackageEntry, RailwayInfo, WorkspaceManifest } from "./types.js";
|
|
2
|
+
export declare function writeManifest(workspaceDir: string, manifest: WorkspaceManifest): void;
|
|
3
|
+
export declare function createInitialManifest(workspaceName: string, packageManager: "bun" | "npm" | "pnpm" | "yarn", railway?: RailwayInfo): WorkspaceManifest;
|
|
4
|
+
export declare function addApp(manifest: WorkspaceManifest, name: string, app: AppEntry): WorkspaceManifest;
|
|
5
|
+
export declare function removeApp(manifest: WorkspaceManifest, name: string): WorkspaceManifest;
|
|
6
|
+
export declare function addPackage(manifest: WorkspaceManifest, name: string, pkg: PackageEntry): WorkspaceManifest;
|
|
7
|
+
export declare function addConsumer(manifest: WorkspaceManifest, packageName: string, appName: string): WorkspaceManifest;
|
|
8
|
+
export declare function removeConsumer(manifest: WorkspaceManifest, packageName: string, appName: string): WorkspaceManifest;
|
|
9
|
+
export declare function updateSettings(manifest: WorkspaceManifest, key: string, value: unknown): WorkspaceManifest;
|