create-walle 0.9.3 → 0.9.4

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.
Files changed (75) hide show
  1. package/README.md +2 -1
  2. package/package.json +1 -1
  3. package/template/claude-task-manager/db.js +5 -1
  4. package/template/claude-task-manager/public/css/walle.css +317 -0
  5. package/template/claude-task-manager/public/index.html +404 -101
  6. package/template/claude-task-manager/public/js/walle.js +1256 -86
  7. package/template/claude-task-manager/server.js +189 -14
  8. package/template/docs/site/api/README.md +146 -0
  9. package/template/docs/site/skills/README.md +99 -5
  10. package/template/package.json +1 -1
  11. package/template/wall-e/agent.js +54 -0
  12. package/template/wall-e/api-walle.js +452 -3
  13. package/template/wall-e/brain.js +45 -1
  14. package/template/wall-e/channels/telegram-channel.js +96 -0
  15. package/template/wall-e/chat.js +61 -2
  16. package/template/wall-e/coding-context.js +252 -0
  17. package/template/wall-e/coding-orchestrator.js +625 -0
  18. package/template/wall-e/coding-review.js +189 -0
  19. package/template/wall-e/core-tasks.js +12 -3
  20. package/template/wall-e/deploy.sh +4 -4
  21. package/template/wall-e/fly.toml +2 -2
  22. package/template/wall-e/package.json +4 -1
  23. package/template/wall-e/skills/_bundled/coding-agent/SKILL.md +17 -0
  24. package/template/wall-e/skills/_bundled/coding-agent/run.js +142 -0
  25. package/template/wall-e/skills/_bundled/email-sync/SKILL.md +12 -7
  26. package/template/wall-e/skills/_bundled/email-sync/mail-reader.jxa +76 -46
  27. package/template/wall-e/skills/_bundled/email-sync/run.js +42 -2
  28. package/template/wall-e/skills/_bundled/glean-team-sync/SKILL.md +57 -0
  29. package/template/wall-e/skills/_bundled/glean-team-sync/run.js +254 -0
  30. package/template/wall-e/skills/_bundled/slack-mentions/SKILL.md +1 -1
  31. package/template/wall-e/skills/_bundled/slack-mentions/run.js +268 -121
  32. package/template/wall-e/skills/_templates/data-fetcher.md +27 -0
  33. package/template/wall-e/skills/_templates/manual-action.md +19 -0
  34. package/template/wall-e/skills/_templates/periodic-checker.md +29 -0
  35. package/template/wall-e/skills/_templates/script-runner.md +21 -0
  36. package/template/wall-e/skills/claude-code-reader.js +16 -4
  37. package/template/wall-e/skills/skill-executor.js +23 -1
  38. package/template/wall-e/skills/skill-validator.js +73 -0
  39. package/template/wall-e/tests/brain.test.js +3 -3
  40. package/template/wall-e/tests/coding-agent-integration.test.js +240 -0
  41. package/template/wall-e/tests/coding-context.test.js +212 -0
  42. package/template/wall-e/tests/coding-orchestrator.test.js +303 -0
  43. package/template/wall-e/tests/coding-review.test.js +141 -0
  44. package/template/claude-task-manager/package-lock.json +0 -1607
  45. package/template/claude-task-manager/tests/test-ai-search.js +0 -61
  46. package/template/claude-task-manager/tests/test-editor-ux.js +0 -76
  47. package/template/claude-task-manager/tests/test-editor-ux2.js +0 -51
  48. package/template/claude-task-manager/tests/test-features-v2.js +0 -127
  49. package/template/claude-task-manager/tests/test-insights-cached.js +0 -78
  50. package/template/claude-task-manager/tests/test-insights.js +0 -124
  51. package/template/claude-task-manager/tests/test-permissions-v2.js +0 -127
  52. package/template/claude-task-manager/tests/test-permissions.js +0 -122
  53. package/template/claude-task-manager/tests/test-pin.js +0 -51
  54. package/template/claude-task-manager/tests/test-prompts.js +0 -164
  55. package/template/claude-task-manager/tests/test-recent-sessions.js +0 -96
  56. package/template/claude-task-manager/tests/test-review.js +0 -104
  57. package/template/claude-task-manager/tests/test-send-dropdown.js +0 -76
  58. package/template/claude-task-manager/tests/test-send-final.js +0 -30
  59. package/template/claude-task-manager/tests/test-send-fixes.js +0 -76
  60. package/template/claude-task-manager/tests/test-send-integration.js +0 -107
  61. package/template/claude-task-manager/tests/test-send-visual.js +0 -34
  62. package/template/claude-task-manager/tests/test-session-create.js +0 -147
  63. package/template/claude-task-manager/tests/test-sidebar-ux.js +0 -83
  64. package/template/claude-task-manager/tests/test-url-hash.js +0 -68
  65. package/template/claude-task-manager/tests/test-ux-crop.js +0 -34
  66. package/template/claude-task-manager/tests/test-ux-review.js +0 -130
  67. package/template/claude-task-manager/tests/test-zoom-card.js +0 -76
  68. package/template/claude-task-manager/tests/test-zoom.js +0 -92
  69. package/template/claude-task-manager/tests/test-zoom2.js +0 -67
  70. package/template/docs/openclaw-vs-walle-comparison.md +0 -103
  71. package/template/docs/ux-improvement-plan.md +0 -84
  72. package/template/wall-e/docs/specs/2026-04-01-publish-plan.md +0 -112
  73. package/template/wall-e/docs/specs/SKILL-FORMAT.md +0 -326
  74. package/template/wall-e/package-lock.json +0 -533
  75. package/template/wall-e/skills/_bundled/slack-mentions/.watermark.json +0 -4
@@ -1,76 +0,0 @@
1
- #!/usr/bin/env node
2
- const puppeteer = require('puppeteer');
3
- const TOKEN = process.env.CTM_TEST_TOKEN || 'test-token-placeholder';
4
- const BASE = `http://localhost:3456/prompts.html?token=${TOKEN}`;
5
-
6
- async function runTest() {
7
- const browser = await puppeteer.launch({ headless: true, args: ['--no-sandbox'] });
8
- const page = await browser.newPage();
9
- page.on('pageerror', err => console.error('[PAGE ERROR]', err.message));
10
- await page.setViewport({ width: 1920, height: 1080 });
11
-
12
- await page.goto(BASE + '#prompt=3', { waitUntil: 'networkidle2', timeout: 15000 });
13
- await new Promise(r => setTimeout(r, 2000));
14
-
15
- // Test 1: Send button guard - clicking multiple times should not create multiple sessions
16
- // Simulate clicking Send twice quickly
17
- const sendBtn = await page.$('.send-dropdown-wrap .btn-main');
18
- console.log('=== Fix 1: Debounce Send ===');
19
-
20
- // First click — should go through
21
- await sendBtn.click();
22
- await new Promise(r => setTimeout(r, 200));
23
- const btnText1 = await page.$eval('.send-dropdown-wrap .btn-main', el => el.textContent);
24
- const btnDisabled1 = await page.$eval('.send-dropdown-wrap .btn-main', el => el.disabled);
25
- console.log('1. After first click - button text:', btnText1.trim());
26
- console.log(' Button disabled:', btnDisabled1);
27
-
28
- // Second click — should be blocked by guard
29
- await sendBtn.click();
30
- await new Promise(r => setTimeout(r, 200));
31
- // Check pendingPromptSend is still set (not reset/replaced)
32
- const pending = await page.evaluate(() => !!state.pendingPromptSend);
33
- console.log('2. Pending prompt send exists:', pending);
34
-
35
- // Wait for the safety timeout or session creation, then check button resets
36
- // (We won't wait 15s, just verify the guard works)
37
-
38
- // Reset for next test
39
- await page.evaluate(() => { state.pendingPromptSend = null; resetSendButton(); });
40
-
41
- // Test 2: Image in plain text
42
- console.log('\n=== Fix 2: Images in Copy ===');
43
-
44
- // Insert a fake image into the editor
45
- await page.evaluate(() => {
46
- const editor = document.getElementById('editor');
47
- const img = document.createElement('img');
48
- img.src = '/api/images/file/test-image-abc123.png?token=xyz';
49
- img.dataset.imageId = '99';
50
- editor.appendChild(img);
51
- });
52
-
53
- const plainText = await page.evaluate(() => getPromptPlainText());
54
- console.log('3. Plain text includes image ref:', plainText.includes('[Image: test-image-abc123.png]'));
55
- console.log(' Image ref text:', plainText.match(/\[Image: [^\]]+\]/)?.[0] || '(not found)');
56
-
57
- // Test markdown copy
58
- const mdResult = await page.evaluate(() => {
59
- const editor = document.getElementById('editor');
60
- return htmlToMarkdown(editor.innerHTML);
61
- });
62
- console.log('4. Markdown includes image:', mdResult.includes('![Image]'));
63
- console.log(' Image md:', mdResult.match(/!\[Image\]\([^)]+\)/)?.[0] || '(not found)');
64
-
65
- // Clean up the fake image
66
- await page.evaluate(() => {
67
- const editor = document.getElementById('editor');
68
- const img = editor.querySelector('img[data-image-id="99"]');
69
- if (img) img.remove();
70
- });
71
-
72
- await browser.close();
73
- console.log('\nAll fix tests complete.');
74
- }
75
-
76
- runTest();
@@ -1,107 +0,0 @@
1
- #!/usr/bin/env node
2
- const puppeteer = require('puppeteer');
3
- const TOKEN = process.env.CTM_TEST_TOKEN || 'test-token-placeholder';
4
- const BASE_PROMPTS = `http://localhost:3456/prompts.html?token=${TOKEN}`;
5
- const BASE_MAIN = `http://localhost:3456/?token=${TOKEN}`;
6
-
7
- async function runTest() {
8
- const browser = await puppeteer.launch({ headless: true, args: ['--no-sandbox'] });
9
-
10
- // --- Test 1: API - Track prompt usage ---
11
- console.log('=== API Tests ===');
12
- const http = require('http');
13
- const testSessionId = 'test-session-' + Date.now();
14
-
15
- // Track usage for prompt 3
16
- const trackRes = await fetch(`http://localhost:3456/api/prompts/3/usage?token=${TOKEN}`, {
17
- method: 'POST',
18
- headers: { 'Content-Type': 'application/json' },
19
- body: JSON.stringify({ session_id: testSessionId }),
20
- });
21
- const trackData = await trackRes.json();
22
- console.log('1. Track usage:', trackData);
23
-
24
- // Get usage stats
25
- const statsRes = await fetch(`http://localhost:3456/api/prompts/3/usage?token=${TOKEN}`);
26
- const stats = await statsRes.json();
27
- console.log('2. Usage stats:', stats);
28
- console.log(' use_count > 0:', stats.use_count > 0);
29
-
30
- // Get usage sessions
31
- const sessionsRes = await fetch(`http://localhost:3456/api/prompts/3/usage/sessions?token=${TOKEN}`);
32
- const sessions = await sessionsRes.json();
33
- console.log('3. Usage sessions:', sessions.length, 'entries');
34
- console.log(' Latest session:', sessions[0]?.session_id);
35
-
36
- // Get session prompts (reverse lookup)
37
- const sessionPromptsRes = await fetch(`http://localhost:3456/api/session-prompts?session_id=${testSessionId}&token=${TOKEN}`);
38
- const sessionPrompts = await sessionPromptsRes.json();
39
- console.log('4. Session prompts:', sessionPrompts.length, 'entries');
40
- console.log(' First prompt title:', sessionPrompts[0]?.title);
41
-
42
- // --- Test 2: UI - Dropdown on prompts page ---
43
- console.log('\n=== UI Tests ===');
44
- const page = await browser.newPage();
45
- page.on('pageerror', err => console.error('[PAGE ERROR]', err.message));
46
- await page.setViewport({ width: 1920, height: 1080 });
47
- await page.goto(BASE_PROMPTS, { waitUntil: 'networkidle2', timeout: 15000 });
48
- await new Promise(r => setTimeout(r, 1500));
49
-
50
- // Open prompt 3
51
- await page.goto(BASE_PROMPTS + '#prompt=3', { waitUntil: 'networkidle2', timeout: 15000 });
52
- await new Promise(r => setTimeout(r, 1500));
53
-
54
- // Check usage badge appears (since we just tracked usage)
55
- const badgeText = await page.$eval('#usage-badge-wrap', el => el.textContent.trim()).catch(() => '');
56
- console.log('5. Usage badge text:', badgeText || '(empty)');
57
- console.log(' Badge shows usage:', badgeText.includes('Used'));
58
-
59
- // Open dropdown and screenshot
60
- const caret = await page.$('.send-dropdown-wrap .btn-caret');
61
- if (caret) await caret.click();
62
- await new Promise(r => setTimeout(r, 300));
63
-
64
- // Crop screenshot of just the dropdown area
65
- const dropWrap = await page.$('.send-dropdown-wrap');
66
- if (dropWrap) {
67
- await dropWrap.screenshot({ path: 'tests/screenshots/send-04-dropdown-detail.png' });
68
- }
69
- await page.screenshot({ path: 'tests/screenshots/send-05-with-badge.png' });
70
-
71
- // Test copy as text
72
- // We can't easily verify clipboard in headless, but we can verify the function exists
73
- const hasCopyFn = await page.evaluate(() => typeof copyPromptText === 'function');
74
- console.log('6. copyPromptText function exists:', hasCopyFn);
75
-
76
- const hasCopyMdFn = await page.evaluate(() => typeof copyPromptMarkdown === 'function');
77
- console.log('7. copyPromptMarkdown function exists:', hasCopyMdFn);
78
-
79
- // Test htmlToMarkdown
80
- const md = await page.evaluate(() => htmlToMarkdown('<h1>Title</h1><p>Hello <strong>world</strong></p><ul><li>Item 1</li><li>Item 2</li></ul>'));
81
- console.log('8. HTML to Markdown:', JSON.stringify(md));
82
-
83
- // --- Test 3: Main page shows linked prompts ---
84
- console.log('\n=== Main Page Tests ===');
85
- const mainPage = await browser.newPage();
86
- mainPage.on('pageerror', err => console.error('[MAIN PAGE ERROR]', err.message));
87
- await mainPage.setViewport({ width: 1920, height: 1080 });
88
- await mainPage.goto(BASE_MAIN, { waitUntil: 'networkidle2', timeout: 15000 });
89
- await new Promise(r => setTimeout(r, 2000));
90
-
91
- // Check that refreshSessionPrompts and openPromptInEditor functions exist
92
- const hasRefresh = await mainPage.evaluate(() => typeof refreshSessionPrompts === 'function');
93
- console.log('9. refreshSessionPrompts exists:', hasRefresh);
94
- const hasOpenPrompt = await mainPage.evaluate(() => typeof openPromptInEditor === 'function');
95
- console.log('10. openPromptInEditor exists:', hasOpenPrompt);
96
-
97
- // Check hash routing function exists
98
- const hasHashCheck = await mainPage.evaluate(() => typeof checkHashSession === 'function');
99
- console.log('11. checkHashSession exists:', hasHashCheck);
100
-
101
- await mainPage.screenshot({ path: 'tests/screenshots/send-06-main-page.png' });
102
-
103
- await browser.close();
104
- console.log('\nAll integration tests complete.');
105
- }
106
-
107
- runTest();
@@ -1,34 +0,0 @@
1
- #!/usr/bin/env node
2
- const puppeteer = require('puppeteer');
3
- const TOKEN = process.env.CTM_TEST_TOKEN || 'test-token-placeholder';
4
- const BASE = `http://localhost:3456/prompts.html?token=${TOKEN}`;
5
-
6
- async function runTest() {
7
- const browser = await puppeteer.launch({ headless: true, args: ['--no-sandbox'] });
8
- const page = await browser.newPage();
9
- await page.setViewport({ width: 1920, height: 1080 });
10
-
11
- // Open prompt 3 directly
12
- await page.goto(BASE + '#prompt=3', { waitUntil: 'networkidle2', timeout: 15000 });
13
- await new Promise(r => setTimeout(r, 2000));
14
-
15
- // Screenshot the meta-bar area showing the Send button and usage badge
16
- const metaBar = await page.$('#meta-bar');
17
- if (metaBar) await metaBar.screenshot({ path: 'tests/screenshots/send-07-metabar.png' });
18
-
19
- // Open the dropdown
20
- const caret = await page.$('.send-dropdown-wrap .btn-caret');
21
- if (caret) await caret.click();
22
- await new Promise(r => setTimeout(r, 300));
23
-
24
- // Screenshot the top-right area with dropdown open
25
- await page.screenshot({
26
- path: 'tests/screenshots/send-08-dropdown-cropped.png',
27
- clip: { x: 800, y: 0, width: 600, height: 400 }
28
- });
29
-
30
- await browser.close();
31
- console.log('Visual screenshots saved.');
32
- }
33
-
34
- runTest();
@@ -1,147 +0,0 @@
1
- #!/usr/bin/env node
2
- const puppeteer = require('puppeteer');
3
- const path = require('path');
4
-
5
- const TOKEN = process.env.CTM_TEST_TOKEN || 'test-token-placeholder';
6
- const BASE_URL = `http://localhost:3456/?token=${TOKEN}`;
7
- const SCREENSHOT_DIR = path.join(__dirname, 'screenshots');
8
-
9
- const fs = require('fs');
10
- if (!fs.existsSync(SCREENSHOT_DIR)) fs.mkdirSync(SCREENSHOT_DIR, { recursive: true });
11
-
12
- async function screenshot(page, name) {
13
- const filePath = path.join(SCREENSHOT_DIR, `${name}.png`);
14
- await page.screenshot({ path: filePath, fullPage: false });
15
- console.log(` Screenshot: ${filePath}`);
16
- }
17
-
18
- async function runTest() {
19
- const browser = await puppeteer.launch({
20
- headless: true,
21
- args: ['--no-sandbox', '--disable-setuid-sandbox'],
22
- });
23
-
24
- const page = await browser.newPage();
25
- await page.setViewport({ width: 1920, height: 1080 });
26
-
27
- // Capture console messages
28
- page.on('console', msg => {
29
- console.log(` [BROWSER ${msg.type()}] ${msg.text()}`);
30
- });
31
-
32
- page.on('pageerror', err => {
33
- console.error(` [PAGE ERROR] ${err.message}`);
34
- });
35
-
36
- try {
37
- // Step 1: Load the page
38
- console.log('Step 1: Loading page...');
39
- await page.goto(BASE_URL, { waitUntil: 'networkidle2', timeout: 15000 });
40
- await screenshot(page, '01-page-loaded');
41
-
42
- // Check welcome screen is visible
43
- const welcomeText = await page.$eval('#welcome h2', el => el.textContent);
44
- console.log(` Welcome text: "${welcomeText}"`);
45
- if (!welcomeText.includes('Welcome')) throw new Error('Welcome screen not found');
46
- console.log(' PASS: Welcome screen visible');
47
-
48
- // Step 2: Click "+ New Session" button
49
- console.log('\nStep 2: Clicking "+ New Session" button...');
50
- await page.click('.btn.primary');
51
- await new Promise(r => setTimeout(r, 500));
52
- await screenshot(page, '02-modal-opened');
53
-
54
- // Step 3: Verify modal appears
55
- console.log('\nStep 3: Verifying modal...');
56
- const modalVisible = await page.$eval('#new-session-modal', el => !el.classList.contains('hidden'));
57
- if (!modalVisible) throw new Error('Modal did not appear');
58
- console.log(' PASS: Modal is visible');
59
-
60
- // Step 4: Select "Shell" type
61
- console.log('\nStep 4: Selecting Shell type...');
62
- await page.select('#ns-type', 'shell');
63
- await new Promise(r => setTimeout(r, 300));
64
- await screenshot(page, '03-shell-selected');
65
- const selectedType = await page.$eval('#ns-type', el => el.value);
66
- console.log(` Selected type: ${selectedType}`);
67
- if (selectedType !== 'shell') throw new Error('Shell type not selected');
68
- console.log(' PASS: Shell type selected');
69
-
70
- // Step 5: Click "Create" button
71
- console.log('\nStep 5: Clicking Create...');
72
- // Find the Create button in the modal
73
- const createBtn = await page.evaluateHandle(() => {
74
- const buttons = Array.from(document.querySelectorAll('.modal .btn.primary'));
75
- return buttons.find(b => b.textContent.includes('Create'));
76
- });
77
- if (!createBtn) throw new Error('Create button not found');
78
- await createBtn.click();
79
-
80
- // Wait for WebSocket to create session and terminal to render
81
- console.log(' Waiting for session creation...');
82
- await new Promise(r => setTimeout(r, 3000));
83
- await screenshot(page, '04-after-create');
84
-
85
- // Step 6: Verify terminal session created
86
- console.log('\nStep 6: Verifying terminal session...');
87
-
88
- // Check modal is closed
89
- const modalHidden = await page.$eval('#new-session-modal', el => el.classList.contains('hidden'));
90
- console.log(` Modal hidden: ${modalHidden}`);
91
-
92
- // Check if a tab was created
93
- const tabs = await page.$$('#tabbar .tab');
94
- console.log(` Tabs found: ${tabs.length}`);
95
-
96
- // Check if terminal container exists and is active
97
- const activeTerms = await page.$$('.term-container.active');
98
- console.log(` Active terminal containers: ${activeTerms.length}`);
99
-
100
- // Check if xterm rendered
101
- const xtermExists = await page.$('.term-container.active .xterm');
102
- console.log(` xterm element exists: ${!!xtermExists}`);
103
-
104
- // Check sidebar session list
105
- const sessionItems = await page.$$('.session-item');
106
- console.log(` Session items in sidebar: ${sessionItems.length}`);
107
-
108
- // Check welcome is hidden
109
- const welcomeDisplay = await page.$eval('#welcome', el => getComputedStyle(el).display);
110
- console.log(` Welcome display: ${welcomeDisplay}`);
111
-
112
- await screenshot(page, '05-terminal-session');
113
-
114
- if (activeTerms.length > 0 && xtermExists) {
115
- console.log('\n PASS: Terminal session created and visible!');
116
- } else {
117
- // Dump more debug info
118
- const allContainers = await page.$$('.term-container');
119
- console.log(` Total term containers: ${allContainers.length}`);
120
- const html = await page.$eval('#terminal-area', el => el.innerHTML.substring(0, 2000));
121
- console.log(` terminal-area HTML: ${html}`);
122
-
123
- // Check WebSocket state
124
- const wsState = await page.evaluate(() => {
125
- return state.ws ? state.ws.readyState : 'no ws';
126
- });
127
- console.log(` WebSocket state: ${wsState}`);
128
-
129
- const sessionsMap = await page.evaluate(() => {
130
- return { size: state.sessions.size, tabs: state.tabOrder };
131
- });
132
- console.log(` Sessions map size: ${sessionsMap.size}, tabs: ${JSON.stringify(sessionsMap.tabs)}`);
133
-
134
- throw new Error('Terminal session not visible');
135
- }
136
-
137
- console.log('\n=== ALL TESTS PASSED ===');
138
- } catch (error) {
139
- console.error(`\n FAIL: ${error.message}`);
140
- await screenshot(page, 'error-state');
141
- process.exitCode = 1;
142
- } finally {
143
- await browser.close();
144
- }
145
- }
146
-
147
- runTest();
@@ -1,83 +0,0 @@
1
- #!/usr/bin/env node
2
- const puppeteer = require('puppeteer');
3
- const TOKEN = process.env.CTM_TEST_TOKEN || 'test-token-placeholder';
4
-
5
- async function runTest() {
6
- const browser = await puppeteer.launch({ headless: true, args: ['--no-sandbox'] });
7
- const page = await browser.newPage();
8
- page.on('pageerror', err => console.error('[PAGE ERROR]', err.message));
9
- await page.setViewport({ width: 1920, height: 1080 });
10
- await page.goto(`http://localhost:3456/prompts.html?token=${TOKEN}`, { waitUntil: 'networkidle2', timeout: 15000 });
11
- await new Promise(r => setTimeout(r, 1000));
12
-
13
- // Screenshot 1: Initial sidebar
14
- const sidebar = await page.$('#prompt-sidebar');
15
- if (sidebar) await sidebar.screenshot({ path: 'tests/screenshots/sidebar-01-initial.png' });
16
-
17
- // Click Email Cron v2
18
- const items = await page.$$('.prompt-item');
19
- for (const item of items) {
20
- const title = await item.$eval('.prompt-title', el => el.textContent.trim());
21
- if (title.includes('Email Cron')) { await item.click(); break; }
22
- }
23
- await new Promise(r => setTimeout(r, 500));
24
-
25
- // Screenshot 2: Sidebar with active prompt
26
- if (sidebar) await sidebar.screenshot({ path: 'tests/screenshots/sidebar-02-active.png' });
27
-
28
- // Hover over a prompt to show actions
29
- const firstItem = await page.$('.prompt-item');
30
- if (firstItem) {
31
- await firstItem.hover();
32
- await new Promise(r => setTimeout(r, 300));
33
- }
34
- if (sidebar) await sidebar.screenshot({ path: 'tests/screenshots/sidebar-03-hover.png' });
35
-
36
- // Test: Edit title in meta bar and check sidebar sync
37
- await page.evaluate(() => {
38
- const input = document.getElementById('prompt-title-input');
39
- input.value = 'Email Cron v2 - Updated';
40
- input.dispatchEvent(new Event('input'));
41
- });
42
- await new Promise(r => setTimeout(r, 300));
43
- if (sidebar) await sidebar.screenshot({ path: 'tests/screenshots/sidebar-04-title-sync.png' });
44
-
45
- // Restore title
46
- await page.evaluate(() => {
47
- const input = document.getElementById('prompt-title-input');
48
- input.value = 'Email Cron v2';
49
- input.dispatchEvent(new Event('input'));
50
- });
51
- await new Promise(r => setTimeout(r, 300));
52
-
53
- // Test: Click pin button
54
- const pinBtn = await page.$('.prompt-item .act-btn');
55
- if (pinBtn) {
56
- await page.evaluate(() => {
57
- // Hover on first prompt item to show actions
58
- const item = document.querySelector('.prompt-item');
59
- item.dispatchEvent(new MouseEvent('mouseenter', { bubbles: true }));
60
- });
61
- await new Promise(r => setTimeout(r, 300));
62
- }
63
-
64
- // Full page screenshot
65
- await page.screenshot({ path: 'tests/screenshots/sidebar-05-full.png' });
66
-
67
- // Check drag handles exist
68
- const handles = await page.$$('.drag-handle');
69
- console.log('Drag handles found:', handles.length);
70
-
71
- // Check action buttons exist
72
- const actionBtns = await page.$$('.prompt-actions .act-btn');
73
- console.log('Action buttons found:', actionBtns.length);
74
-
75
- // Check folder actions
76
- const folderActions = await page.$$('.folder-actions .act-btn');
77
- console.log('Folder action buttons found:', folderActions.length);
78
-
79
- await browser.close();
80
- console.log('\nScreenshots saved.');
81
- }
82
-
83
- runTest();
@@ -1,68 +0,0 @@
1
- #!/usr/bin/env node
2
- const puppeteer = require('puppeteer');
3
- const TOKEN = process.env.CTM_TEST_TOKEN || 'test-token-placeholder';
4
- const BASE = `http://localhost:3456/prompts.html?token=${TOKEN}`;
5
-
6
- async function runTest() {
7
- const browser = await puppeteer.launch({ headless: true, args: ['--no-sandbox'] });
8
- const page = await browser.newPage();
9
- page.on('pageerror', err => console.error('[PAGE ERROR]', err.message));
10
- await page.setViewport({ width: 1920, height: 1080 });
11
-
12
- // Test 1: Open page, click a prompt, check URL updates
13
- await page.goto(BASE, { waitUntil: 'networkidle2', timeout: 15000 });
14
- await new Promise(r => setTimeout(r, 1000));
15
- console.log('1. Initial URL:', page.url());
16
-
17
- // Click Email Cron v2
18
- const items = await page.$$('.prompt-item');
19
- for (const item of items) {
20
- const title = await item.$eval('.prompt-title', el => el.textContent.trim().replace(/^📌/, '').trim());
21
- if (title.includes('Email Cron')) { await item.click(); break; }
22
- }
23
- await new Promise(r => setTimeout(r, 500));
24
- console.log('2. After opening prompt:', page.url());
25
-
26
- // Test 2: Click a view tab
27
- await page.click('button[onclick="showView(\'chains\')"]');
28
- await new Promise(r => setTimeout(r, 500));
29
- console.log('3. After chains view:', page.url());
30
-
31
- // Test 3: Navigate to a deep link directly
32
- await page.goto(BASE + '#prompt=3', { waitUntil: 'networkidle2', timeout: 15000 });
33
- await new Promise(r => setTimeout(r, 1500));
34
- const title = await page.$eval('#prompt-title-input', el => el.value);
35
- console.log('4. Deep link to prompt=3:', page.url());
36
- console.log(' Loaded title:', title);
37
-
38
- // Take screenshot of deep-linked page
39
- await page.screenshot({ path: 'tests/screenshots/url-01-deeplink.png' });
40
-
41
- // Test 4: Navigate to a view deep link
42
- await page.goto(BASE + '#view=backups', { waitUntil: 'networkidle2', timeout: 15000 });
43
- await new Promise(r => setTimeout(r, 1500));
44
- const backupsVisible = await page.$eval('#view-backups', el => el.style.display);
45
- console.log('5. Deep link to view=backups:', page.url());
46
- console.log(' Backups view visible:', backupsVisible);
47
-
48
- // Test 5: Folder deep link
49
- await page.goto(BASE + '#folder=1', { waitUntil: 'networkidle2', timeout: 15000 });
50
- await new Promise(r => setTimeout(r, 1500));
51
- const activeFolder = await page.$eval('.folder-item.active .folder-name', el => el.textContent).catch(() => 'none');
52
- console.log('6. Deep link to folder=1:', page.url());
53
- console.log(' Active folder:', activeFolder);
54
-
55
- // Test 6: Select folder, then open prompt — URL has both
56
- await page.goto(BASE, { waitUntil: 'networkidle2', timeout: 15000 });
57
- await new Promise(r => setTimeout(r, 1000));
58
- // Click first prompt
59
- const items2 = await page.$$('.prompt-item');
60
- if (items2.length) await items2[0].click();
61
- await new Promise(r => setTimeout(r, 500));
62
- console.log('7. Prompt in folder:', page.url());
63
-
64
- await browser.close();
65
- console.log('\nAll URL hash tests passed.');
66
- }
67
-
68
- runTest();
@@ -1,34 +0,0 @@
1
- #!/usr/bin/env node
2
- const puppeteer = require('puppeteer');
3
- const TOKEN = process.env.CTM_TEST_TOKEN || 'test-token-placeholder';
4
-
5
- async function runTest() {
6
- const browser = await puppeteer.launch({ headless: true, args: ['--no-sandbox'] });
7
- const page = await browser.newPage();
8
- await page.setViewport({ width: 1920, height: 1080 });
9
- await page.goto(`http://localhost:3456/prompts.html?token=${TOKEN}`, { waitUntil: 'networkidle2', timeout: 15000 });
10
- await new Promise(r => setTimeout(r, 1000));
11
-
12
- const items = await page.$$('.prompt-item');
13
- for (const item of items) {
14
- const title = await item.$eval('.prompt-title', el => el.textContent.trim());
15
- if (title.includes('Email Cron')) { await item.click(); break; }
16
- }
17
- await new Promise(r => setTimeout(r, 800));
18
-
19
- // Crop just the document card area
20
- const editorDiv = await page.$('#editor');
21
- if (editorDiv) {
22
- const box = await editorDiv.boundingBox();
23
- const clip = {
24
- x: box.x - 10,
25
- y: box.y - 10,
26
- width: box.width + 20,
27
- height: Math.min(box.height + 20, 750),
28
- };
29
- await page.screenshot({ path: 'tests/screenshots/ux-08-document-card.png', clip });
30
- }
31
-
32
- await browser.close();
33
- }
34
- runTest();