jammincms 0.1.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.
@@ -0,0 +1,14 @@
1
+ import type { Job } from './types.js';
2
+ interface ClaudeCallbacks {
3
+ onProgress: (output: string, phase: 'thinking' | 'editing' | 'complete') => void;
4
+ onComplete: (success: boolean, filesChanged?: string[], error?: string) => void;
5
+ }
6
+ export declare function checkClaudeAvailable(): Promise<boolean>;
7
+ export declare function checkGitDirty(projectPath: string): {
8
+ isDirty: boolean;
9
+ changedFiles: string[];
10
+ };
11
+ export declare function spawnClaudeJob(job: Job, callbacks: ClaudeCallbacks): Promise<void>;
12
+ export declare function cancelJob(job: Job): void;
13
+ export {};
14
+ //# sourceMappingURL=claude.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../src/claude.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAGtC,UAAU,eAAe;IACvB,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,SAAS,GAAG,UAAU,KAAK,IAAI,CAAC;IACjF,UAAU,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CACjF;AAGD,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,OAAO,CAAC,CAO7D;AAGD,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,YAAY,EAAE,MAAM,EAAE,CAAA;CAAE,CAoB/F;AAkDD,wBAAsB,cAAc,CAClC,GAAG,EAAE,GAAG,EACR,SAAS,EAAE,eAAe,GACzB,OAAO,CAAC,IAAI,CAAC,CAuEf;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAYxC"}
package/dist/claude.js ADDED
@@ -0,0 +1,146 @@
1
+ import { spawn, execSync } from 'child_process';
2
+ import { buildPrompt } from './prompt.js';
3
+ // Check if Claude CLI is available
4
+ export async function checkClaudeAvailable() {
5
+ try {
6
+ execSync('which claude', { stdio: 'pipe' });
7
+ return true;
8
+ }
9
+ catch {
10
+ return false;
11
+ }
12
+ }
13
+ // Check if git repo has uncommitted changes
14
+ export function checkGitDirty(projectPath) {
15
+ try {
16
+ // Check if it's a git repo
17
+ execSync('git rev-parse --git-dir', { cwd: projectPath, stdio: 'pipe' });
18
+ // Get status of changed files
19
+ const status = execSync('git status --porcelain', { cwd: projectPath, stdio: 'pipe' }).toString();
20
+ const changedFiles = status
21
+ .split('\n')
22
+ .filter(line => line.trim())
23
+ .map(line => line.slice(3).trim());
24
+ return {
25
+ isDirty: changedFiles.length > 0,
26
+ changedFiles,
27
+ };
28
+ }
29
+ catch {
30
+ // Not a git repo or git not available - allow changes
31
+ return { isDirty: false, changedFiles: [] };
32
+ }
33
+ }
34
+ // Parse file changes from Claude output
35
+ function parseFilesChanged(output) {
36
+ const files = [];
37
+ // Look for common patterns in Claude's output indicating file changes
38
+ // Pattern: "Modified: path/to/file" or "Updated: path/to/file" or "Created: path/to/file"
39
+ const modifiedPattern = /(?:Modified|Updated|Created|Edited|Changed|Wrote to|Writing to):\s*[`"]?([^\s`"]+)[`"]?/gi;
40
+ let match;
41
+ while ((match = modifiedPattern.exec(output)) !== null) {
42
+ const file = match[1].trim();
43
+ if (file && !files.includes(file)) {
44
+ files.push(file);
45
+ }
46
+ }
47
+ // Also look for file paths in backticks that look like they were edited
48
+ const backtickPattern = /`([^`]+\.(tsx?|jsx?|mdx?|html?|css|json|yml|yaml))`/gi;
49
+ while ((match = backtickPattern.exec(output)) !== null) {
50
+ const file = match[1].trim();
51
+ if (file && !files.includes(file) && !file.includes(' ')) {
52
+ files.push(file);
53
+ }
54
+ }
55
+ return files;
56
+ }
57
+ // Detect current phase from output
58
+ function detectPhase(output) {
59
+ const lowerOutput = output.toLowerCase();
60
+ if (lowerOutput.includes('complete') || lowerOutput.includes('done') || lowerOutput.includes('finished')) {
61
+ return 'complete';
62
+ }
63
+ if (lowerOutput.includes('editing') ||
64
+ lowerOutput.includes('writing') ||
65
+ lowerOutput.includes('updating') ||
66
+ lowerOutput.includes('modifying') ||
67
+ lowerOutput.includes('creating')) {
68
+ return 'editing';
69
+ }
70
+ return 'thinking';
71
+ }
72
+ export async function spawnClaudeJob(job, callbacks) {
73
+ const prompt = buildPrompt(job);
74
+ const claudePath = job.claudePath || 'claude';
75
+ job.status = 'running';
76
+ return new Promise((resolve, reject) => {
77
+ // Spawn claude CLI with the prompt via stdin
78
+ // Using -p for print mode and --dangerously-skip-permissions to avoid prompts
79
+ const proc = spawn(claudePath, [
80
+ '-p',
81
+ '--dangerously-skip-permissions',
82
+ ], {
83
+ cwd: job.projectPath,
84
+ stdio: ['pipe', 'pipe', 'pipe'],
85
+ env: {
86
+ ...process.env,
87
+ // Ensure we get clean output
88
+ FORCE_COLOR: '0',
89
+ NO_COLOR: '1',
90
+ },
91
+ });
92
+ job.process = proc;
93
+ // Send prompt via stdin
94
+ proc.stdin?.write(prompt);
95
+ proc.stdin?.end();
96
+ let fullOutput = '';
97
+ let currentPhase = 'thinking';
98
+ const handleOutput = (data) => {
99
+ const text = data.toString();
100
+ fullOutput += text;
101
+ const newPhase = detectPhase(text);
102
+ if (newPhase !== currentPhase) {
103
+ currentPhase = newPhase;
104
+ }
105
+ callbacks.onProgress(text, currentPhase);
106
+ };
107
+ proc.stdout?.on('data', handleOutput);
108
+ proc.stderr?.on('data', handleOutput);
109
+ proc.on('error', (err) => {
110
+ job.status = 'error';
111
+ callbacks.onComplete(false, [], err.message);
112
+ reject(err);
113
+ });
114
+ proc.on('close', (code) => {
115
+ const filesChanged = parseFilesChanged(fullOutput);
116
+ if (code === 0) {
117
+ job.status = 'complete';
118
+ job.filesChanged = filesChanged;
119
+ callbacks.onComplete(true, filesChanged);
120
+ resolve();
121
+ }
122
+ else if (job.status === 'cancelled') {
123
+ callbacks.onComplete(false, [], 'Job cancelled');
124
+ resolve();
125
+ }
126
+ else {
127
+ job.status = 'error';
128
+ callbacks.onComplete(false, filesChanged, `Claude exited with code ${code}`);
129
+ resolve();
130
+ }
131
+ });
132
+ });
133
+ }
134
+ export function cancelJob(job) {
135
+ if (job.process && job.status === 'running') {
136
+ job.status = 'cancelled';
137
+ job.process.kill('SIGTERM');
138
+ // Force kill after 5 seconds if still running
139
+ setTimeout(() => {
140
+ if (job.process && !job.process.killed) {
141
+ job.process.kill('SIGKILL');
142
+ }
143
+ }, 5000);
144
+ }
145
+ }
146
+ //# sourceMappingURL=claude.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude.js","sourceRoot":"","sources":["../src/claude.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ type EditorType = 'cursor' | 'code' | 'auto';
2
+ export declare function openInEditor(projectPath: string, file?: string, editorType?: EditorType): Promise<void>;
3
+ export {};
4
+ //# sourceMappingURL=editor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../src/editor.ts"],"names":[],"mappings":"AAMA,KAAK,UAAU,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;AAsC7C,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,EACnB,IAAI,CAAC,EAAE,MAAM,EACb,UAAU,GAAE,UAAmB,GAC9B,OAAO,CAAC,IAAI,CAAC,CA0Cf"}
package/dist/editor.js ADDED
@@ -0,0 +1,74 @@
1
+ import { exec } from 'child_process';
2
+ import { promisify } from 'util';
3
+ import { existsSync } from 'fs';
4
+ const execAsync = promisify(exec);
5
+ // Check if an editor command is available
6
+ async function isEditorAvailable(command) {
7
+ try {
8
+ await execAsync(`which ${command}`);
9
+ return true;
10
+ }
11
+ catch {
12
+ return false;
13
+ }
14
+ }
15
+ // Detect available editor
16
+ async function detectEditor() {
17
+ // Check for Cursor first (preferred)
18
+ if (await isEditorAvailable('cursor')) {
19
+ return 'cursor';
20
+ }
21
+ // Check for VS Code
22
+ if (await isEditorAvailable('code')) {
23
+ return 'code';
24
+ }
25
+ // Check for common macOS editor locations
26
+ const cursorMacPath = '/Applications/Cursor.app/Contents/Resources/app/bin/cursor';
27
+ if (existsSync(cursorMacPath)) {
28
+ return cursorMacPath;
29
+ }
30
+ const codeMacPath = '/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code';
31
+ if (existsSync(codeMacPath)) {
32
+ return codeMacPath;
33
+ }
34
+ return null;
35
+ }
36
+ export async function openInEditor(projectPath, file, editorType = 'auto') {
37
+ let editorCommand = null;
38
+ if (editorType === 'auto') {
39
+ editorCommand = await detectEditor();
40
+ }
41
+ else {
42
+ editorCommand = editorType;
43
+ // Verify the specified editor is available
44
+ if (!(await isEditorAvailable(editorCommand))) {
45
+ throw new Error(`Editor '${editorCommand}' is not available`);
46
+ }
47
+ }
48
+ if (!editorCommand) {
49
+ throw new Error('No editor found. Please install Cursor or VS Code.');
50
+ }
51
+ // Build the path to open
52
+ const targetPath = file ? `${projectPath}/${file}` : projectPath;
53
+ // Verify the path exists
54
+ if (!existsSync(targetPath)) {
55
+ throw new Error(`Path does not exist: ${targetPath}`);
56
+ }
57
+ console.log(`Opening ${targetPath} in ${editorCommand}`);
58
+ // Open the editor
59
+ // Use -r to reuse existing window, -g to not focus the editor
60
+ const args = ['-r', targetPath];
61
+ try {
62
+ await execAsync(`"${editorCommand}" ${args.join(' ')}`);
63
+ }
64
+ catch (err) {
65
+ // Editor might return non-zero even on success (e.g., if already open)
66
+ // So we only throw if it's a clear failure
67
+ const error = err;
68
+ if (error.message?.includes('command not found')) {
69
+ throw new Error(`Editor '${editorCommand}' is not available`);
70
+ }
71
+ // Otherwise, assume success
72
+ }
73
+ }
74
+ //# sourceMappingURL=editor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editor.js","sourceRoot":"","sources":["../src/editor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAEhC,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;AAIlC,0CAA0C;AAC1C,KAAK,UAAU,iBAAiB,CAAC,OAAe;IAC9C,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,SAAS,OAAO,EAAE,CAAC,CAAC;QACpC,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,0BAA0B;AAC1B,KAAK,UAAU,YAAY;IACzB,qCAAqC;IACrC,IAAI,MAAM,iBAAiB,CAAC,QAAQ,CAAC,EAAE,CAAC;QACtC,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,oBAAoB;IACpB,IAAI,MAAM,iBAAiB,CAAC,MAAM,CAAC,EAAE,CAAC;QACpC,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,0CAA0C;IAC1C,MAAM,aAAa,GAAG,4DAA4D,CAAC;IACnF,IAAI,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QAC9B,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,MAAM,WAAW,GAAG,sEAAsE,CAAC;IAC3F,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC5B,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,WAAmB,EACnB,IAAa,EACb,aAAyB,MAAM;IAE/B,IAAI,aAAa,GAAkB,IAAI,CAAC;IAExC,IAAI,UAAU,KAAK,MAAM,EAAE,CAAC;QAC1B,aAAa,GAAG,MAAM,YAAY,EAAE,CAAC;IACvC,CAAC;SAAM,CAAC;QACN,aAAa,GAAG,UAAU,CAAC;QAC3B,2CAA2C;QAC3C,IAAI,CAAC,CAAC,MAAM,iBAAiB,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC;YAC9C,MAAM,IAAI,KAAK,CAAC,WAAW,aAAa,oBAAoB,CAAC,CAAC;QAChE,CAAC;IACH,CAAC;IAED,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACxE,CAAC;IAED,yBAAyB;IACzB,MAAM,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,WAAW,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC;IAEjE,yBAAyB;IACzB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,wBAAwB,UAAU,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,WAAW,UAAU,OAAO,aAAa,EAAE,CAAC,CAAC;IAEzD,kBAAkB;IAClB,8DAA8D;IAC9D,MAAM,IAAI,GAAG,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAEhC,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,IAAI,aAAa,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC1D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,uEAAuE;QACvE,2CAA2C;QAC3C,MAAM,KAAK,GAAG,GAA2B,CAAC;QAC1C,IAAI,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;YACjD,MAAM,IAAI,KAAK,CAAC,WAAW,aAAa,oBAAoB,CAAC,CAAC;QAChE,CAAC;QACD,4BAA4B;IAC9B,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { startServer } from './server.js';
4
+ import { checkClaudeAvailable } from './claude.js';
5
+ const program = new Command();
6
+ async function start(port) {
7
+ if (isNaN(port) || port < 1 || port > 65535) {
8
+ console.error('Invalid port number');
9
+ process.exit(1);
10
+ }
11
+ // Check if Claude CLI is available
12
+ const claudeAvailable = await checkClaudeAvailable();
13
+ if (!claudeAvailable) {
14
+ console.warn('Warning: Claude CLI not found in PATH');
15
+ console.warn('Install it with: npm install -g @anthropic-ai/claude-code');
16
+ console.warn('The server will start but edit jobs will fail.');
17
+ }
18
+ else {
19
+ console.log('Claude CLI: available');
20
+ }
21
+ // Start the server
22
+ const server = startServer(port);
23
+ // Handle graceful shutdown
24
+ const shutdown = () => {
25
+ console.log('\nShutting down...');
26
+ server.close(() => {
27
+ console.log('Server closed');
28
+ process.exit(0);
29
+ });
30
+ // Force exit after 5 seconds
31
+ setTimeout(() => {
32
+ console.log('Forcing exit');
33
+ process.exit(1);
34
+ }, 5000);
35
+ };
36
+ process.on('SIGINT', shutdown);
37
+ process.on('SIGTERM', shutdown);
38
+ }
39
+ program
40
+ .name('jammincms')
41
+ .description('Local bridge server for Jammin CMS Chrome extension')
42
+ .version('1.0.0')
43
+ .option('-p, --port <port>', 'Port to listen on', '9876')
44
+ .action(async (options) => {
45
+ const port = parseInt(options.port, 10);
46
+ await start(port);
47
+ });
48
+ program
49
+ .command('status')
50
+ .description('Check if the bridge server is running')
51
+ .option('-p, --port <port>', 'Port to check', '9876')
52
+ .action(async (options) => {
53
+ const port = parseInt(options.port, 10);
54
+ const WebSocket = (await import('ws')).default;
55
+ const ws = new WebSocket(`ws://localhost:${port}`);
56
+ const timeout = setTimeout(() => {
57
+ console.log('Bridge server: not running');
58
+ ws.close();
59
+ process.exit(1);
60
+ }, 2000);
61
+ ws.on('open', () => {
62
+ ws.send(JSON.stringify({ type: 'ping' }));
63
+ });
64
+ ws.on('message', (data) => {
65
+ clearTimeout(timeout);
66
+ try {
67
+ const response = JSON.parse(data.toString());
68
+ if (response.type === 'pong') {
69
+ console.log(`Bridge server: running (v${response.version})`);
70
+ console.log(`Claude CLI: ${response.claudeAvailable ? 'available' : 'not found'}`);
71
+ }
72
+ }
73
+ catch {
74
+ console.log('Bridge server: running (invalid response)');
75
+ }
76
+ ws.close();
77
+ process.exit(0);
78
+ });
79
+ ws.on('error', () => {
80
+ clearTimeout(timeout);
81
+ console.log('Bridge server: not running');
82
+ process.exit(1);
83
+ });
84
+ });
85
+ program.parse();
86
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Job } from './types.js';
2
+ export declare function buildPrompt(job: Job): string;
3
+ //# sourceMappingURL=prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAc,MAAM,YAAY,CAAC;AAkBlD,wBAAgB,WAAW,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAiC5C"}
package/dist/prompt.js ADDED
@@ -0,0 +1,47 @@
1
+ function formatChange(change, index) {
2
+ return `### Change ${index + 1}
3
+ **Location**: ${change.elementPath}
4
+ **Selector**: ${change.selector}
5
+
6
+ **Original content:**
7
+ \`\`\`html
8
+ ${change.originalContent}
9
+ \`\`\`
10
+
11
+ **New content (user edited):**
12
+ \`\`\`html
13
+ ${change.newContent}
14
+ \`\`\``;
15
+ }
16
+ export function buildPrompt(job) {
17
+ const { siteUrl, changes, customInstructions } = job;
18
+ const changesSection = changes
19
+ .map((change, index) => formatChange(change, index))
20
+ .join('\n\n');
21
+ const instructionsSection = customInstructions
22
+ ? `## Site-Specific Instructions
23
+ ${customInstructions}
24
+
25
+ `
26
+ : '';
27
+ return `# Website Content Update Request
28
+
29
+ The user has made inline edits to their website at: ${siteUrl}
30
+
31
+ ${instructionsSection}## Changes Made
32
+
33
+ ${changesSection}
34
+
35
+ ## Instructions
36
+ 1. Find the source files that generate this content
37
+ 2. Update the content to match the user's edits
38
+ 3. Preserve all existing formatting, structure, and code
39
+ 4. Briefly summarize what files were modified
40
+
41
+ Important:
42
+ - The content may come from markdown files, React components, or other templates
43
+ - Match the existing code style and patterns
44
+ - Only change the specific content that was edited
45
+ - Do not add comments or explanations to the code`;
46
+ }
47
+ //# sourceMappingURL=prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"AAEA,SAAS,YAAY,CAAC,MAAkB,EAAE,KAAa;IACrD,OAAO,cAAc,KAAK,GAAG,CAAC;gBAChB,MAAM,CAAC,WAAW;gBAClB,MAAM,CAAC,QAAQ;;;;EAI7B,MAAM,CAAC,eAAe;;;;;EAKtB,MAAM,CAAC,UAAU;OACZ,CAAC;AACR,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAQ;IAClC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAE,GAAG,GAAG,CAAC;IAErD,MAAM,cAAc,GAAG,OAAO;SAC3B,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;SACnD,IAAI,CAAC,MAAM,CAAC,CAAC;IAEhB,MAAM,mBAAmB,GAAG,kBAAkB;QAC5C,CAAC,CAAC;EACJ,kBAAkB;;CAEnB;QACG,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO;;sDAE6C,OAAO;;EAE3D,mBAAmB;;EAEnB,cAAc;;;;;;;;;;;;kDAYkC,CAAC;AACnD,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { WebSocketServer, WebSocket } from 'ws';
2
+ import type { BridgeMessage, Job } from './types.js';
3
+ export declare function broadcast(message: BridgeMessage): void;
4
+ export declare function sendToClient(client: WebSocket, message: BridgeMessage): void;
5
+ export declare function startServer(port?: number): WebSocketServer;
6
+ export declare function getJobs(): Map<string, Job>;
7
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAChD,OAAO,KAAK,EAEV,aAAa,EAIb,GAAG,EACJ,MAAM,YAAY,CAAC;AAapB,wBAAgB,SAAS,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,CAOtD;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,GAAG,IAAI,CAI5E;AAwKD,wBAAgB,WAAW,CAAC,IAAI,GAAE,MAAqB,GAAG,eAAe,CAwCxE;AAED,wBAAgB,OAAO,IAAI,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAE1C"}
package/dist/server.js ADDED
@@ -0,0 +1,202 @@
1
+ import { WebSocketServer, WebSocket } from 'ws';
2
+ import { spawnClaudeJob, cancelJob, checkClaudeAvailable, checkGitDirty } from './claude.js';
3
+ import { openInEditor } from './editor.js';
4
+ const VERSION = '1.0.0';
5
+ const DEFAULT_PORT = 9876;
6
+ // Active jobs tracked by job ID
7
+ const jobs = new Map();
8
+ // Connected clients
9
+ const clients = new Set();
10
+ export function broadcast(message) {
11
+ const data = JSON.stringify(message);
12
+ for (const client of clients) {
13
+ if (client.readyState === WebSocket.OPEN) {
14
+ client.send(data);
15
+ }
16
+ }
17
+ }
18
+ export function sendToClient(client, message) {
19
+ if (client.readyState === WebSocket.OPEN) {
20
+ client.send(JSON.stringify(message));
21
+ }
22
+ }
23
+ async function handleMessage(client, message) {
24
+ switch (message.type) {
25
+ case 'ping': {
26
+ const claudeAvailable = await checkClaudeAvailable();
27
+ sendToClient(client, {
28
+ type: 'pong',
29
+ version: VERSION,
30
+ claudeAvailable,
31
+ });
32
+ break;
33
+ }
34
+ case 'submit_edit': {
35
+ await handleSubmitEdit(client, message);
36
+ break;
37
+ }
38
+ case 'cancel_job': {
39
+ handleCancelJob(client, message);
40
+ break;
41
+ }
42
+ case 'open_editor': {
43
+ await handleOpenEditor(client, message);
44
+ break;
45
+ }
46
+ default: {
47
+ sendToClient(client, {
48
+ type: 'error',
49
+ message: `Unknown message type: ${message.type}`,
50
+ code: 'UNKNOWN_MESSAGE_TYPE',
51
+ });
52
+ }
53
+ }
54
+ }
55
+ async function handleSubmitEdit(client, message) {
56
+ const { jobId, projectPath, siteUrl, changes, customInstructions, claudePath, skipGitCheck } = message;
57
+ // Check if job already exists
58
+ if (jobs.has(jobId)) {
59
+ sendToClient(client, {
60
+ type: 'error',
61
+ message: `Job ${jobId} already exists`,
62
+ code: 'JOB_EXISTS',
63
+ });
64
+ return;
65
+ }
66
+ // Check for uncommitted git changes (unless skipped)
67
+ if (!skipGitCheck) {
68
+ const gitStatus = checkGitDirty(projectPath);
69
+ if (gitStatus.isDirty) {
70
+ sendToClient(client, {
71
+ type: 'git_dirty',
72
+ jobId,
73
+ changedFiles: gitStatus.changedFiles,
74
+ });
75
+ return;
76
+ }
77
+ }
78
+ // Create job
79
+ const job = {
80
+ id: jobId,
81
+ projectPath,
82
+ siteUrl,
83
+ changes,
84
+ customInstructions,
85
+ claudePath,
86
+ status: 'pending',
87
+ output: '',
88
+ filesChanged: [],
89
+ };
90
+ jobs.set(jobId, job);
91
+ // Acknowledge job
92
+ sendToClient(client, {
93
+ type: 'job_accepted',
94
+ jobId,
95
+ });
96
+ // Spawn Claude process
97
+ try {
98
+ await spawnClaudeJob(job, {
99
+ onProgress: (output, phase) => {
100
+ job.output += output;
101
+ broadcast({
102
+ type: 'job_progress',
103
+ jobId,
104
+ output,
105
+ phase,
106
+ });
107
+ },
108
+ onComplete: (success, filesChanged, error) => {
109
+ job.status = success ? 'complete' : 'error';
110
+ job.filesChanged = filesChanged || [];
111
+ broadcast({
112
+ type: 'job_complete',
113
+ jobId,
114
+ success,
115
+ filesChanged,
116
+ error,
117
+ });
118
+ // Clean up job after some time
119
+ setTimeout(() => jobs.delete(jobId), 60000);
120
+ },
121
+ });
122
+ }
123
+ catch (err) {
124
+ job.status = 'error';
125
+ sendToClient(client, {
126
+ type: 'job_complete',
127
+ jobId,
128
+ success: false,
129
+ error: err instanceof Error ? err.message : 'Unknown error',
130
+ });
131
+ }
132
+ }
133
+ function handleCancelJob(client, message) {
134
+ const { jobId } = message;
135
+ const job = jobs.get(jobId);
136
+ if (!job) {
137
+ sendToClient(client, {
138
+ type: 'error',
139
+ message: `Job ${jobId} not found`,
140
+ code: 'JOB_NOT_FOUND',
141
+ });
142
+ return;
143
+ }
144
+ cancelJob(job);
145
+ job.status = 'cancelled';
146
+ broadcast({
147
+ type: 'job_cancelled',
148
+ jobId,
149
+ });
150
+ }
151
+ async function handleOpenEditor(client, message) {
152
+ const { projectPath, file } = message;
153
+ try {
154
+ await openInEditor(projectPath, file);
155
+ }
156
+ catch (err) {
157
+ sendToClient(client, {
158
+ type: 'error',
159
+ message: err instanceof Error ? err.message : 'Failed to open editor',
160
+ code: 'EDITOR_ERROR',
161
+ });
162
+ }
163
+ }
164
+ export function startServer(port = DEFAULT_PORT) {
165
+ const wss = new WebSocketServer({ port });
166
+ console.log(`Jammin CMS Bridge v${VERSION}`);
167
+ console.log(`WebSocket server listening on ws://localhost:${port}`);
168
+ wss.on('connection', (ws) => {
169
+ console.log('Client connected');
170
+ clients.add(ws);
171
+ ws.on('message', async (data) => {
172
+ try {
173
+ const message = JSON.parse(data.toString());
174
+ await handleMessage(ws, message);
175
+ }
176
+ catch (err) {
177
+ console.error('Error handling message:', err);
178
+ sendToClient(ws, {
179
+ type: 'error',
180
+ message: err instanceof Error ? err.message : 'Invalid message',
181
+ code: 'INVALID_MESSAGE',
182
+ });
183
+ }
184
+ });
185
+ ws.on('close', () => {
186
+ console.log('Client disconnected');
187
+ clients.delete(ws);
188
+ });
189
+ ws.on('error', (err) => {
190
+ console.error('WebSocket error:', err);
191
+ clients.delete(ws);
192
+ });
193
+ });
194
+ wss.on('error', (err) => {
195
+ console.error('Server error:', err);
196
+ });
197
+ return wss;
198
+ }
199
+ export function getJobs() {
200
+ return jobs;
201
+ }
202
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ export interface PingMessage {
2
+ type: 'ping';
3
+ }
4
+ export interface SubmitEditMessage {
5
+ type: 'submit_edit';
6
+ jobId: string;
7
+ projectPath: string;
8
+ siteUrl: string;
9
+ changes: EditChange[];
10
+ customInstructions?: string;
11
+ claudePath?: string;
12
+ skipGitCheck?: boolean;
13
+ }
14
+ export interface CancelJobMessage {
15
+ type: 'cancel_job';
16
+ jobId: string;
17
+ }
18
+ export interface OpenEditorMessage {
19
+ type: 'open_editor';
20
+ projectPath: string;
21
+ file?: string;
22
+ }
23
+ export type ExtensionMessage = PingMessage | SubmitEditMessage | CancelJobMessage | OpenEditorMessage;
24
+ export interface PongMessage {
25
+ type: 'pong';
26
+ version: string;
27
+ claudeAvailable: boolean;
28
+ }
29
+ export interface JobAcceptedMessage {
30
+ type: 'job_accepted';
31
+ jobId: string;
32
+ }
33
+ export interface JobProgressMessage {
34
+ type: 'job_progress';
35
+ jobId: string;
36
+ output: string;
37
+ phase: 'thinking' | 'editing' | 'complete';
38
+ }
39
+ export interface JobCompleteMessage {
40
+ type: 'job_complete';
41
+ jobId: string;
42
+ success: boolean;
43
+ filesChanged?: string[];
44
+ error?: string;
45
+ }
46
+ export interface JobCancelledMessage {
47
+ type: 'job_cancelled';
48
+ jobId: string;
49
+ }
50
+ export interface ErrorMessage {
51
+ type: 'error';
52
+ message: string;
53
+ code: string;
54
+ }
55
+ export interface GitDirtyMessage {
56
+ type: 'git_dirty';
57
+ jobId: string;
58
+ changedFiles: string[];
59
+ }
60
+ export type BridgeMessage = PongMessage | JobAcceptedMessage | JobProgressMessage | JobCompleteMessage | JobCancelledMessage | ErrorMessage | GitDirtyMessage;
61
+ export interface EditChange {
62
+ elementPath: string;
63
+ selector: string;
64
+ originalContent: string;
65
+ newContent: string;
66
+ }
67
+ export interface Job {
68
+ id: string;
69
+ projectPath: string;
70
+ siteUrl: string;
71
+ changes: EditChange[];
72
+ customInstructions?: string;
73
+ claudePath?: string;
74
+ status: 'pending' | 'running' | 'complete' | 'cancelled' | 'error';
75
+ process?: import('child_process').ChildProcess;
76
+ output: string;
77
+ filesChanged: string[];
78
+ }
79
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AACA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,aAAa,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,gBAAgB,GACxB,WAAW,GACX,iBAAiB,GACjB,gBAAgB,GAChB,iBAAiB,CAAC;AAGtB,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,cAAc,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,cAAc,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,UAAU,GAAG,SAAS,GAAG,UAAU,CAAC;CAC5C;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,cAAc,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,eAAe,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,WAAW,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,MAAM,aAAa,GACrB,WAAW,GACX,kBAAkB,GAClB,kBAAkB,GAClB,kBAAkB,GAClB,mBAAmB,GACnB,YAAY,GACZ,eAAe,CAAC;AAGpB,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;CACpB;AAGD,MAAM,WAAW,GAAG;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,WAAW,GAAG,OAAO,CAAC;IACnE,OAAO,CAAC,EAAE,OAAO,eAAe,EAAE,YAAY,CAAC;IAC/C,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "jammincms",
3
+ "version": "0.1.0",
4
+ "description": "Local bridge server for Jammin CMS Chrome extension - connects to Claude Code CLI",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "jammincms": "./dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "dev": "tsc --watch",
16
+ "start": "node dist/index.js",
17
+ "typecheck": "tsc --noEmit",
18
+ "prepublishOnly": "npm run build"
19
+ },
20
+ "keywords": [
21
+ "cms",
22
+ "claude",
23
+ "claude-code",
24
+ "inline-editing",
25
+ "chrome-extension",
26
+ "ai"
27
+ ],
28
+ "author": "",
29
+ "license": "MIT",
30
+ "dependencies": {
31
+ "commander": "^12.1.0",
32
+ "ws": "^8.18.0"
33
+ },
34
+ "devDependencies": {
35
+ "@types/node": "^22.10.0",
36
+ "@types/ws": "^8.5.13",
37
+ "typescript": "^5.7.2"
38
+ },
39
+ "engines": {
40
+ "node": ">=18.0.0"
41
+ }
42
+ }