vibeman 0.0.0 → 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -0
- package/dist/index.js +116 -0
- package/dist/runtime/api/.tsbuildinfo +1 -0
- package/dist/runtime/api/agent/agent-service.d.ts +226 -0
- package/dist/runtime/api/agent/agent-service.js +901 -0
- package/dist/runtime/api/agent/ai-providers/claude-code-adapter.d.ts +61 -0
- package/dist/runtime/api/agent/ai-providers/claude-code-adapter.js +373 -0
- package/dist/runtime/api/agent/ai-providers/codex-cli-provider.d.ts +34 -0
- package/dist/runtime/api/agent/ai-providers/codex-cli-provider.js +281 -0
- package/dist/runtime/api/agent/ai-providers/index.d.ts +9 -0
- package/dist/runtime/api/agent/ai-providers/index.js +7 -0
- package/dist/runtime/api/agent/ai-providers/types.d.ts +180 -0
- package/dist/runtime/api/agent/ai-providers/types.js +5 -0
- package/dist/runtime/api/agent/codex-cli-provider.test.d.ts +1 -0
- package/dist/runtime/api/agent/codex-cli-provider.test.js +88 -0
- package/dist/runtime/api/agent/core-agent-service.d.ts +119 -0
- package/dist/runtime/api/agent/core-agent-service.js +267 -0
- package/dist/runtime/api/agent/parsers.d.ts +15 -0
- package/dist/runtime/api/agent/parsers.js +241 -0
- package/dist/runtime/api/agent/prompt-service.d.ts +17 -0
- package/dist/runtime/api/agent/prompt-service.js +340 -0
- package/dist/runtime/api/agent/routing-policy.d.ts +188 -0
- package/dist/runtime/api/agent/routing-policy.js +246 -0
- package/dist/runtime/api/api/router-helpers.d.ts +32 -0
- package/dist/runtime/api/api/router-helpers.js +31 -0
- package/dist/runtime/api/api/routers/ai.d.ts +188 -0
- package/dist/runtime/api/api/routers/ai.js +410 -0
- package/dist/runtime/api/api/routers/executions.d.ts +98 -0
- package/dist/runtime/api/api/routers/executions.js +103 -0
- package/dist/runtime/api/api/routers/git.d.ts +45 -0
- package/dist/runtime/api/api/routers/git.js +35 -0
- package/dist/runtime/api/api/routers/settings.d.ts +139 -0
- package/dist/runtime/api/api/routers/settings.js +113 -0
- package/dist/runtime/api/api/routers/tasks.d.ts +141 -0
- package/dist/runtime/api/api/routers/tasks.js +238 -0
- package/dist/runtime/api/api/routers/workflows.d.ts +268 -0
- package/dist/runtime/api/api/routers/workflows.js +308 -0
- package/dist/runtime/api/api/routers/worktrees.d.ts +102 -0
- package/dist/runtime/api/api/routers/worktrees.js +80 -0
- package/dist/runtime/api/api/trpc.d.ts +118 -0
- package/dist/runtime/api/api/trpc.js +34 -0
- package/dist/runtime/api/index.d.ts +9 -0
- package/dist/runtime/api/index.js +125 -0
- package/dist/runtime/api/lib/id-generator.d.ts +70 -0
- package/dist/runtime/api/lib/id-generator.js +123 -0
- package/dist/runtime/api/lib/image-paste-drop-extension.d.ts +26 -0
- package/dist/runtime/api/lib/image-paste-drop-extension.js +125 -0
- package/dist/runtime/api/lib/logger.d.ts +11 -0
- package/dist/runtime/api/lib/logger.js +188 -0
- package/dist/runtime/api/lib/markdown-utils.d.ts +8 -0
- package/dist/runtime/api/lib/markdown-utils.js +282 -0
- package/dist/runtime/api/lib/markdown-utils.test.d.ts +1 -0
- package/dist/runtime/api/lib/markdown-utils.test.js +348 -0
- package/dist/runtime/api/lib/server/agent-service-singleton.d.ts +6 -0
- package/dist/runtime/api/lib/server/agent-service-singleton.js +27 -0
- package/dist/runtime/api/lib/server/git-service-singleton.d.ts +6 -0
- package/dist/runtime/api/lib/server/git-service-singleton.js +47 -0
- package/dist/runtime/api/lib/server/project-root.d.ts +2 -0
- package/dist/runtime/api/lib/server/project-root.js +38 -0
- package/dist/runtime/api/lib/server/task-service-singleton.d.ts +7 -0
- package/dist/runtime/api/lib/server/task-service-singleton.js +58 -0
- package/dist/runtime/api/lib/server/vibing-orchestrator-singleton.d.ts +7 -0
- package/dist/runtime/api/lib/server/vibing-orchestrator-singleton.js +57 -0
- package/dist/runtime/api/lib/tiptap-utils.clamp-selection.test.d.ts +1 -0
- package/dist/runtime/api/lib/tiptap-utils.clamp-selection.test.js +27 -0
- package/dist/runtime/api/lib/tiptap-utils.d.ts +130 -0
- package/dist/runtime/api/lib/tiptap-utils.js +327 -0
- package/dist/runtime/api/lib/trpc/client.d.ts +1 -0
- package/dist/runtime/api/lib/trpc/client.js +5 -0
- package/dist/runtime/api/lib/trpc/server.d.ts +822 -0
- package/dist/runtime/api/lib/trpc/server.js +11 -0
- package/dist/runtime/api/lib/trpc/ws-server.d.ts +8 -0
- package/dist/runtime/api/lib/trpc/ws-server.js +33 -0
- package/dist/runtime/api/persistence/database-service.d.ts +14 -0
- package/dist/runtime/api/persistence/database-service.js +74 -0
- package/dist/runtime/api/persistence/execution-log-persistence.d.ts +90 -0
- package/dist/runtime/api/persistence/execution-log-persistence.js +410 -0
- package/dist/runtime/api/persistence/execution-log-persistence.test.d.ts +1 -0
- package/dist/runtime/api/persistence/execution-log-persistence.test.js +170 -0
- package/dist/runtime/api/router.d.ts +825 -0
- package/dist/runtime/api/router.js +56 -0
- package/dist/runtime/api/settings-service.d.ts +110 -0
- package/dist/runtime/api/settings-service.js +611 -0
- package/dist/runtime/api/tasks/file-watcher.d.ts +23 -0
- package/dist/runtime/api/tasks/file-watcher.js +88 -0
- package/dist/runtime/api/tasks/task-file-parser.d.ts +13 -0
- package/dist/runtime/api/tasks/task-file-parser.js +161 -0
- package/dist/runtime/api/tasks/task-service.d.ts +36 -0
- package/dist/runtime/api/tasks/task-service.js +173 -0
- package/dist/runtime/api/types/index.d.ts +179 -0
- package/dist/runtime/api/types/index.js +1 -0
- package/dist/runtime/api/types/settings.d.ts +81 -0
- package/dist/runtime/api/types/settings.js +2 -0
- package/dist/runtime/api/types.d.ts +2 -0
- package/dist/runtime/api/types.js +1 -0
- package/dist/runtime/api/utils/env.d.ts +6 -0
- package/dist/runtime/api/utils/env.js +12 -0
- package/dist/runtime/api/utils/stripNextEnv.d.ts +7 -0
- package/dist/runtime/api/utils/stripNextEnv.js +22 -0
- package/dist/runtime/api/utils/title-slug.d.ts +6 -0
- package/dist/runtime/api/utils/title-slug.js +77 -0
- package/dist/runtime/api/utils/url.d.ts +2 -0
- package/dist/runtime/api/utils/url.js +19 -0
- package/dist/runtime/api/vcs/git-history-service.d.ts +57 -0
- package/dist/runtime/api/vcs/git-history-service.js +228 -0
- package/dist/runtime/api/vcs/git-service.d.ts +127 -0
- package/dist/runtime/api/vcs/git-service.js +284 -0
- package/dist/runtime/api/vcs/worktree-service.d.ts +93 -0
- package/dist/runtime/api/vcs/worktree-service.js +506 -0
- package/dist/runtime/api/vcs/worktree-service.test.d.ts +1 -0
- package/dist/runtime/api/vcs/worktree-service.test.js +20 -0
- package/dist/runtime/api/workflows/quality-pipeline.d.ts +58 -0
- package/dist/runtime/api/workflows/quality-pipeline.js +400 -0
- package/dist/runtime/api/workflows/vibing-orchestrator.d.ts +313 -0
- package/dist/runtime/api/workflows/vibing-orchestrator.js +1861 -0
- package/dist/runtime/web/.next/BUILD_ID +1 -0
- package/dist/runtime/web/.next/app-build-manifest.json +59 -0
- package/dist/runtime/web/.next/app-path-routes-manifest.json +7 -0
- package/dist/runtime/web/.next/build-manifest.json +33 -0
- package/dist/runtime/web/.next/package.json +1 -0
- package/dist/runtime/web/.next/prerender-manifest.json +61 -0
- package/dist/runtime/web/.next/react-loadable-manifest.json +39 -0
- package/dist/runtime/web/.next/required-server-files.json +334 -0
- package/dist/runtime/web/.next/routes-manifest.json +62 -0
- package/dist/runtime/web/.next/server/app/_not-found/page.js +2 -0
- package/dist/runtime/web/.next/server/app/_not-found/page.js.nft.json +1 -0
- package/dist/runtime/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -0
- package/dist/runtime/web/.next/server/app/_not-found.html +7 -0
- package/dist/runtime/web/.next/server/app/_not-found.meta +8 -0
- package/dist/runtime/web/.next/server/app/_not-found.rsc +22 -0
- package/dist/runtime/web/.next/server/app/api/health/route.js +1 -0
- package/dist/runtime/web/.next/server/app/api/health/route.js.nft.json +1 -0
- package/dist/runtime/web/.next/server/app/api/health/route_client-reference-manifest.js +1 -0
- package/dist/runtime/web/.next/server/app/api/images/[...path]/route.js +1 -0
- package/dist/runtime/web/.next/server/app/api/images/[...path]/route.js.nft.json +1 -0
- package/dist/runtime/web/.next/server/app/api/images/[...path]/route_client-reference-manifest.js +1 -0
- package/dist/runtime/web/.next/server/app/api/upload/route.js +1 -0
- package/dist/runtime/web/.next/server/app/api/upload/route.js.nft.json +1 -0
- package/dist/runtime/web/.next/server/app/api/upload/route_client-reference-manifest.js +1 -0
- package/dist/runtime/web/.next/server/app/index.html +7 -0
- package/dist/runtime/web/.next/server/app/index.meta +7 -0
- package/dist/runtime/web/.next/server/app/index.rsc +27 -0
- package/dist/runtime/web/.next/server/app/page.js +147 -0
- package/dist/runtime/web/.next/server/app/page.js.nft.json +1 -0
- package/dist/runtime/web/.next/server/app/page_client-reference-manifest.js +1 -0
- package/dist/runtime/web/.next/server/app-paths-manifest.json +7 -0
- package/dist/runtime/web/.next/server/chunks/217.js +1 -0
- package/dist/runtime/web/.next/server/chunks/383.js +6 -0
- package/dist/runtime/web/.next/server/chunks/458.js +1 -0
- package/dist/runtime/web/.next/server/chunks/576.js +18 -0
- package/dist/runtime/web/.next/server/chunks/635.js +22 -0
- package/dist/runtime/web/.next/server/chunks/761.js +1 -0
- package/dist/runtime/web/.next/server/chunks/777.js +3 -0
- package/dist/runtime/web/.next/server/chunks/825.js +1 -0
- package/dist/runtime/web/.next/server/chunks/838.js +1 -0
- package/dist/runtime/web/.next/server/chunks/973.js +15 -0
- package/dist/runtime/web/.next/server/functions-config-manifest.json +4 -0
- package/dist/runtime/web/.next/server/middleware-build-manifest.js +1 -0
- package/dist/runtime/web/.next/server/middleware-manifest.json +6 -0
- package/dist/runtime/web/.next/server/middleware-react-loadable-manifest.js +1 -0
- package/dist/runtime/web/.next/server/next-font-manifest.js +1 -0
- package/dist/runtime/web/.next/server/next-font-manifest.json +1 -0
- package/dist/runtime/web/.next/server/pages/404.html +7 -0
- package/dist/runtime/web/.next/server/pages/500.html +1 -0
- package/dist/runtime/web/.next/server/pages/_app.js +1 -0
- package/dist/runtime/web/.next/server/pages/_app.js.nft.json +1 -0
- package/dist/runtime/web/.next/server/pages/_document.js +1 -0
- package/dist/runtime/web/.next/server/pages/_document.js.nft.json +1 -0
- package/dist/runtime/web/.next/server/pages/_error.js +19 -0
- package/dist/runtime/web/.next/server/pages/_error.js.nft.json +1 -0
- package/dist/runtime/web/.next/server/pages-manifest.json +6 -0
- package/dist/runtime/web/.next/server/server-reference-manifest.js +1 -0
- package/dist/runtime/web/.next/server/server-reference-manifest.json +1 -0
- package/dist/runtime/web/.next/server/webpack-runtime.js +1 -0
- package/dist/runtime/web/.next/static/1HR8N0rJkCvFRtbTPJMyH/_buildManifest.js +1 -0
- package/dist/runtime/web/.next/static/1HR8N0rJkCvFRtbTPJMyH/_ssgManifest.js +1 -0
- package/dist/runtime/web/.next/static/chunks/18-15c10d3288afef2e.js +1 -0
- package/dist/runtime/web/.next/static/chunks/1c0ca389.537bbe362e3ffbd9.js +3 -0
- package/dist/runtime/web/.next/static/chunks/22747d63-ad5da0c19f4cfe41.js +71 -0
- package/dist/runtime/web/.next/static/chunks/277-0142a939f08738c3.js +63 -0
- package/dist/runtime/web/.next/static/chunks/355.056c2645878a799a.js +1 -0
- package/dist/runtime/web/.next/static/chunks/420.a5ccf151c9e2b2f1.js +1 -0
- package/dist/runtime/web/.next/static/chunks/439.1be0c6242fd248d5.js +15 -0
- package/dist/runtime/web/.next/static/chunks/440.c52e7c0f797e22b2.js +1 -0
- package/dist/runtime/web/.next/static/chunks/575-e2478287c27da87b.js +1 -0
- package/dist/runtime/web/.next/static/chunks/691.920d88c115087314.js +1 -0
- package/dist/runtime/web/.next/static/chunks/765-e838910065b50c3d.js +1 -0
- package/dist/runtime/web/.next/static/chunks/87c73c54-09e1ba5c70e60a51.js +1 -0
- package/dist/runtime/web/.next/static/chunks/891cff7f.0f71fc028f87e683.js +1 -0
- package/dist/runtime/web/.next/static/chunks/8bb4d8db-3e2aa02b0a2384b9.js +1 -0
- package/dist/runtime/web/.next/static/chunks/9af238c7-271a911d4e99ab18.js +1 -0
- package/dist/runtime/web/.next/static/chunks/app/_not-found/page-1cb74d1cba27d0ab.js +1 -0
- package/dist/runtime/web/.next/static/chunks/app/api/health/route-105a61ae865ba536.js +1 -0
- package/dist/runtime/web/.next/static/chunks/app/api/images/[...path]/route-105a61ae865ba536.js +1 -0
- package/dist/runtime/web/.next/static/chunks/app/api/upload/route-105a61ae865ba536.js +1 -0
- package/dist/runtime/web/.next/static/chunks/app/layout-dc0cfd29075b2160.js +1 -0
- package/dist/runtime/web/.next/static/chunks/app/page-f34a8b196b18850b.js +1 -0
- package/dist/runtime/web/.next/static/chunks/cac567b0-5b77dd12911823cd.js +1 -0
- package/dist/runtime/web/.next/static/chunks/framework-2518f1345b5b2806.js +1 -0
- package/dist/runtime/web/.next/static/chunks/main-17665e5e39de9a8a.js +1 -0
- package/dist/runtime/web/.next/static/chunks/main-app-c0b0f5ba4f7f9d75.js +1 -0
- package/dist/runtime/web/.next/static/chunks/pages/_app-d6f6b3bbc3d81ee1.js +1 -0
- package/dist/runtime/web/.next/static/chunks/pages/_error-75a96cf1997cc3b9.js +1 -0
- package/dist/runtime/web/.next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- package/dist/runtime/web/.next/static/chunks/webpack-c8de37305b4635cf.js +1 -0
- package/dist/runtime/web/.next/static/css/08c950681f1a9a92.css +1 -0
- package/dist/runtime/web/.next/static/css/2728291c68f99cb1.css +3 -0
- package/dist/runtime/web/.next/static/css/521bd69cc298cd1a.css +1 -0
- package/dist/runtime/web/.next/static/css/537e22821e101b87.css +1 -0
- package/dist/runtime/web/.next/static/media/19cfc7226ec3afaa-s.woff2 +0 -0
- package/dist/runtime/web/.next/static/media/21350d82a1f187e9-s.woff2 +0 -0
- package/dist/runtime/web/.next/static/media/8e9860b6e62d6359-s.woff2 +0 -0
- package/dist/runtime/web/.next/static/media/ba9851c3c22cd980-s.woff2 +0 -0
- package/dist/runtime/web/.next/static/media/c5fe6dc8356a8c31-s.woff2 +0 -0
- package/dist/runtime/web/.next/static/media/df0a9ae256c0569c-s.woff2 +0 -0
- package/dist/runtime/web/.next/static/media/e4af272ccee01ff0-s.p.woff2 +0 -0
- package/dist/runtime/web/package.json +65 -0
- package/dist/runtime/web/server.js +44 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +80 -7
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { markdownToHtml, htmlToMarkdown } from './markdown-utils.js';
|
|
3
|
+
describe('markdown-utils', () => {
|
|
4
|
+
describe('markdownToHtml', () => {
|
|
5
|
+
it('should return empty string for empty input', () => {
|
|
6
|
+
expect(markdownToHtml('')).toBe('');
|
|
7
|
+
expect(markdownToHtml(' ')).toBe('');
|
|
8
|
+
expect(markdownToHtml(null)).toBe('');
|
|
9
|
+
expect(markdownToHtml(undefined)).toBe('');
|
|
10
|
+
});
|
|
11
|
+
it('should convert task item to HTML', () => {
|
|
12
|
+
const markdown = `- [ ] Task item
|
|
13
|
+
- [x] Checked task`;
|
|
14
|
+
const html = markdownToHtml(markdown);
|
|
15
|
+
// Check for proper TipTap TaskList structure
|
|
16
|
+
expect(html).toContain('data-type="taskList"');
|
|
17
|
+
expect(html).toContain('data-type="taskItem"');
|
|
18
|
+
expect(html).toContain('data-checked="false"');
|
|
19
|
+
expect(html).toContain('data-checked="true"');
|
|
20
|
+
expect(html).toContain('<label contenteditable="false">');
|
|
21
|
+
expect(html).toContain('<input type="checkbox" >');
|
|
22
|
+
expect(html).toContain('<input type="checkbox" checked>');
|
|
23
|
+
expect(html).toContain('<p>Task item</p>');
|
|
24
|
+
expect(html).toContain('<p>Checked task</p>');
|
|
25
|
+
});
|
|
26
|
+
it('should convert basic markdown to HTML', () => {
|
|
27
|
+
const markdown = '# Heading 1\n\nThis is a paragraph.\n\n**Bold text** and *italic text*.';
|
|
28
|
+
const html = markdownToHtml(markdown);
|
|
29
|
+
expect(html).toContain('<h1>Heading 1</h1>');
|
|
30
|
+
expect(html).toContain('<p>This is a paragraph.</p>');
|
|
31
|
+
expect(html).toContain('<strong>Bold text</strong>');
|
|
32
|
+
expect(html).toContain('<em>italic text</em>');
|
|
33
|
+
});
|
|
34
|
+
// it('should convert simple task lists to HTML with data-type attribute', () => {
|
|
35
|
+
// const markdown = '- [ ] Unchecked task\n- [x] Checked task';
|
|
36
|
+
// const html = markdownToHtml(markdown);
|
|
37
|
+
// expect(html).toContain('data-type="taskItem"');
|
|
38
|
+
// expect(html).toContain('<input type="checkbox" disabled>');
|
|
39
|
+
// expect(html).toContain('<input type="checkbox" checked disabled>');
|
|
40
|
+
// expect(html).toContain('Unchecked task');
|
|
41
|
+
// expect(html).toContain('Checked task');
|
|
42
|
+
// });
|
|
43
|
+
// it('should handle two-level nested task lists', () => {
|
|
44
|
+
// const markdown = `- [ ] Parent task
|
|
45
|
+
// - [ ] Child task 1
|
|
46
|
+
// - [x] Child task 2`;
|
|
47
|
+
// const html = markdownToHtml(markdown);
|
|
48
|
+
// expect(html).toContain('Parent task');
|
|
49
|
+
// expect(html).toContain('Child task 1');
|
|
50
|
+
// expect(html).toContain('Child task 2');
|
|
51
|
+
// expect(html).toMatch(/<ul>[\s\S]*<ul>/); // Nested ul elements
|
|
52
|
+
// });
|
|
53
|
+
// it('should handle three-level nested task lists', () => {
|
|
54
|
+
// const markdown = `- [ ] Level 1
|
|
55
|
+
// - [ ] Level 2
|
|
56
|
+
// - [x] Level 3`;
|
|
57
|
+
// const html = markdownToHtml(markdown);
|
|
58
|
+
// expect(html).toContain('Level 1');
|
|
59
|
+
// expect(html).toContain('Level 2');
|
|
60
|
+
// expect(html).toContain('Level 3');
|
|
61
|
+
// // Should have at least 3 ul elements for 3 levels
|
|
62
|
+
// const ulCount = (html.match(/<ul>/g) || []).length;
|
|
63
|
+
// expect(ulCount).toBeGreaterThanOrEqual(3);
|
|
64
|
+
// });
|
|
65
|
+
// it('should handle deeply nested task lists (5 levels)', () => {
|
|
66
|
+
// const markdown = `- [ ] Level 1
|
|
67
|
+
// - [ ] Level 2
|
|
68
|
+
// - [ ] Level 3
|
|
69
|
+
// - [ ] Level 4
|
|
70
|
+
// - [x] Level 5`;
|
|
71
|
+
// const html = markdownToHtml(markdown);
|
|
72
|
+
// expect(html).toContain('Level 1');
|
|
73
|
+
// expect(html).toContain('Level 5');
|
|
74
|
+
// const ulCount = (html.match(/<ul>/g) || []).length;
|
|
75
|
+
// expect(ulCount).toBeGreaterThanOrEqual(5);
|
|
76
|
+
// });
|
|
77
|
+
// it('should handle mixed task lists and regular lists', () => {
|
|
78
|
+
// const markdown = `- [ ] Task item
|
|
79
|
+
// - Regular nested item
|
|
80
|
+
// - [ ] Nested task
|
|
81
|
+
// - Another regular item`;
|
|
82
|
+
// const html = markdownToHtml(markdown);
|
|
83
|
+
// expect(html).toContain('Task item');
|
|
84
|
+
// expect(html).toContain('Regular nested item');
|
|
85
|
+
// expect(html).toContain('Nested task');
|
|
86
|
+
// expect(html).toContain('Another regular item');
|
|
87
|
+
// });
|
|
88
|
+
// it('should handle task lists with complex content', () => {
|
|
89
|
+
// const markdown = `- [ ] Task with **bold** and *italic*
|
|
90
|
+
// - [ ] Task with \`code\`
|
|
91
|
+
// - [ ] Task with [link](https://example.com)`;
|
|
92
|
+
// const html = markdownToHtml(markdown);
|
|
93
|
+
// // Complex markdown inside task items may not be parsed yet
|
|
94
|
+
// // This is a known limitation - task item text is not re-parsed for markdown
|
|
95
|
+
// expect(html).toContain('Task with **bold** and *italic*');
|
|
96
|
+
// expect(html).toContain('Task with `code`');
|
|
97
|
+
// expect(html).toContain('Task with [link](https://example.com)');
|
|
98
|
+
// });
|
|
99
|
+
it('should handle numbered lists', () => {
|
|
100
|
+
const markdown = '1. First item\n2. Second item\n3. Third item';
|
|
101
|
+
const html = markdownToHtml(markdown);
|
|
102
|
+
expect(html).toContain('<ol>');
|
|
103
|
+
expect(html).toContain('First item');
|
|
104
|
+
expect(html).toContain('Second item');
|
|
105
|
+
});
|
|
106
|
+
it('should handle code blocks', () => {
|
|
107
|
+
const markdown = '```javascript\nconst hello = "world";\n```';
|
|
108
|
+
const html = markdownToHtml(markdown);
|
|
109
|
+
expect(html).toContain('<pre>');
|
|
110
|
+
expect(html).toContain('<code');
|
|
111
|
+
expect(html).toContain('hello');
|
|
112
|
+
});
|
|
113
|
+
it('should handle blockquotes', () => {
|
|
114
|
+
const markdown = '> This is a quote';
|
|
115
|
+
const html = markdownToHtml(markdown);
|
|
116
|
+
expect(html).toContain('<blockquote>');
|
|
117
|
+
expect(html).toContain('This is a quote');
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
describe('htmlToMarkdown', () => {
|
|
121
|
+
it('should return empty string for empty input', () => {
|
|
122
|
+
expect(htmlToMarkdown('')).toBe('');
|
|
123
|
+
expect(htmlToMarkdown(' ')).toBe('');
|
|
124
|
+
expect(htmlToMarkdown(null)).toBe('');
|
|
125
|
+
expect(htmlToMarkdown(undefined)).toBe('');
|
|
126
|
+
});
|
|
127
|
+
it('should convert basic HTML to markdown', () => {
|
|
128
|
+
const html = '<h1>Heading 1</h1><p>This is a paragraph.</p><p><strong>Bold text</strong> and <em>italic text</em>.</p>';
|
|
129
|
+
const markdown = htmlToMarkdown(html);
|
|
130
|
+
expect(markdown).toContain('# Heading 1');
|
|
131
|
+
expect(markdown).toContain('This is a paragraph.');
|
|
132
|
+
expect(markdown).toContain('**Bold text**');
|
|
133
|
+
// Turndown uses underscore for italic by default
|
|
134
|
+
expect(markdown).toContain('_italic text_');
|
|
135
|
+
});
|
|
136
|
+
it('should convert task list HTML back to markdown', () => {
|
|
137
|
+
const html = `<ul>
|
|
138
|
+
<li data-type="taskItem"><input type="checkbox" disabled> Unchecked task</li>
|
|
139
|
+
<li data-type="taskItem"><input type="checkbox" checked disabled> Checked task</li>
|
|
140
|
+
</ul>`;
|
|
141
|
+
const markdown = htmlToMarkdown(html);
|
|
142
|
+
expect(markdown).toContain('- [ ] Unchecked task');
|
|
143
|
+
expect(markdown).toContain('- [x] Checked task');
|
|
144
|
+
});
|
|
145
|
+
it('should preserve two-level nested task list indentation', () => {
|
|
146
|
+
const html = `<ul>
|
|
147
|
+
<li data-type="taskItem"><input type="checkbox" disabled> Parent task
|
|
148
|
+
<ul>
|
|
149
|
+
<li data-type="taskItem"><input type="checkbox" disabled> Child task 1</li>
|
|
150
|
+
<li data-type="taskItem"><input type="checkbox" checked disabled> Child task 2</li>
|
|
151
|
+
</ul>
|
|
152
|
+
</li>
|
|
153
|
+
</ul>`;
|
|
154
|
+
const markdown = htmlToMarkdown(html);
|
|
155
|
+
expect(markdown).toContain('- [ ] Parent task');
|
|
156
|
+
expect(markdown).toContain(' - [ ] Child task 1');
|
|
157
|
+
expect(markdown).toContain(' - [x] Child task 2');
|
|
158
|
+
});
|
|
159
|
+
it('should preserve three-level nested task list indentation', () => {
|
|
160
|
+
const html = `<ul>
|
|
161
|
+
<li data-type="taskItem"><input type="checkbox" disabled> Level 1
|
|
162
|
+
<ul>
|
|
163
|
+
<li data-type="taskItem"><input type="checkbox" disabled> Level 2
|
|
164
|
+
<ul>
|
|
165
|
+
<li data-type="taskItem"><input type="checkbox" checked disabled> Level 3</li>
|
|
166
|
+
</ul>
|
|
167
|
+
</li>
|
|
168
|
+
</ul>
|
|
169
|
+
</li>
|
|
170
|
+
</ul>`;
|
|
171
|
+
const markdown = htmlToMarkdown(html);
|
|
172
|
+
expect(markdown).toContain('- [ ] Level 1');
|
|
173
|
+
expect(markdown).toContain(' - [ ] Level 2');
|
|
174
|
+
expect(markdown).toContain(' - [x] Level 3');
|
|
175
|
+
});
|
|
176
|
+
it('should handle regular nested lists', () => {
|
|
177
|
+
const html = `<ul>
|
|
178
|
+
<li>Parent item
|
|
179
|
+
<ul>
|
|
180
|
+
<li>Child item 1</li>
|
|
181
|
+
<li>Child item 2</li>
|
|
182
|
+
</ul>
|
|
183
|
+
</li>
|
|
184
|
+
</ul>`;
|
|
185
|
+
const markdown = htmlToMarkdown(html);
|
|
186
|
+
// Turndown may add extra spacing in lists
|
|
187
|
+
expect(markdown).toContain('Parent item');
|
|
188
|
+
expect(markdown).toContain('Child item 1');
|
|
189
|
+
expect(markdown).toContain('Child item 2');
|
|
190
|
+
// Check for proper nesting with indentation
|
|
191
|
+
expect(markdown).toMatch(/.*Child item 1/);
|
|
192
|
+
});
|
|
193
|
+
it('should handle numbered lists', () => {
|
|
194
|
+
const html = '<ol><li>First</li><li>Second</li><li>Third</li></ol>';
|
|
195
|
+
const markdown = htmlToMarkdown(html);
|
|
196
|
+
// Turndown may add extra spacing after the period
|
|
197
|
+
expect(markdown).toMatch(/1\.\s+First/);
|
|
198
|
+
expect(markdown).toMatch(/2\.\s+Second/);
|
|
199
|
+
expect(markdown).toMatch(/3\.\s+Third/);
|
|
200
|
+
});
|
|
201
|
+
it('should handle code blocks', () => {
|
|
202
|
+
const html = '<pre><code class="language-javascript">const hello = "world";</code></pre>';
|
|
203
|
+
const markdown = htmlToMarkdown(html);
|
|
204
|
+
expect(markdown).toContain('```');
|
|
205
|
+
expect(markdown).toContain('const hello = "world";');
|
|
206
|
+
});
|
|
207
|
+
it('should handle inline code', () => {
|
|
208
|
+
const html = '<p>Use <code>npm install</code> to install.</p>';
|
|
209
|
+
const markdown = htmlToMarkdown(html);
|
|
210
|
+
expect(markdown).toContain('`npm install`');
|
|
211
|
+
});
|
|
212
|
+
it('should handle links', () => {
|
|
213
|
+
const html = '<p>Visit <a href="https://example.com">example</a></p>';
|
|
214
|
+
const markdown = htmlToMarkdown(html);
|
|
215
|
+
expect(markdown).toContain('[example](https://example.com)');
|
|
216
|
+
});
|
|
217
|
+
it('should handle blockquotes', () => {
|
|
218
|
+
const html = '<blockquote><p>This is a quote</p></blockquote>';
|
|
219
|
+
const markdown = htmlToMarkdown(html);
|
|
220
|
+
expect(markdown).toContain('> This is a quote');
|
|
221
|
+
});
|
|
222
|
+
it('should handle horizontal rules', () => {
|
|
223
|
+
const html = '<hr>';
|
|
224
|
+
const markdown = htmlToMarkdown(html);
|
|
225
|
+
expect(markdown).toContain('---');
|
|
226
|
+
});
|
|
227
|
+
it('should render list item', () => {
|
|
228
|
+
const html = '<li>Test</li>';
|
|
229
|
+
const markdown = htmlToMarkdown(html);
|
|
230
|
+
expect(markdown).toContain('- Test');
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
// describe('Round-trip conversion', () => {
|
|
234
|
+
// it('should preserve simple task lists through round-trip conversion', () => {
|
|
235
|
+
// const original = '- [ ] Task 1\n- [x] Task 2';
|
|
236
|
+
// const html = markdownToHtml(original);
|
|
237
|
+
// const result = htmlToMarkdown(html);
|
|
238
|
+
// expect(result).toContain('- [ ] Task 1');
|
|
239
|
+
// expect(result).toContain('- [x] Task 2');
|
|
240
|
+
// });
|
|
241
|
+
// it('should preserve two-level nested task lists through round-trip conversion', () => {
|
|
242
|
+
// const original = `- [ ] Parent task
|
|
243
|
+
// - [ ] Child task 1
|
|
244
|
+
// - [x] Child task 2`;
|
|
245
|
+
// const html = markdownToHtml(original);
|
|
246
|
+
// const result = htmlToMarkdown(html);
|
|
247
|
+
// expect(result).toContain('- [ ] Parent task');
|
|
248
|
+
// expect(result).toContain(' - [ ] Child task 1');
|
|
249
|
+
// expect(result).toContain(' - [x] Child task 2');
|
|
250
|
+
// });
|
|
251
|
+
// it('should preserve three-level nested task lists through round-trip conversion', () => {
|
|
252
|
+
// const original = `- [ ] Level 1
|
|
253
|
+
// - [ ] Level 2
|
|
254
|
+
// - [x] Level 3`;
|
|
255
|
+
// const html = markdownToHtml(original);
|
|
256
|
+
// const result = htmlToMarkdown(html);
|
|
257
|
+
// expect(result).toContain('- [ ] Level 1');
|
|
258
|
+
// expect(result).toContain(' - [ ] Level 2');
|
|
259
|
+
// expect(result).toContain(' - [x] Level 3');
|
|
260
|
+
// });
|
|
261
|
+
// it('should preserve complex nested task list structure', () => {
|
|
262
|
+
// const original = `- [ ] Task 1
|
|
263
|
+
// - [ ] Task 1.1
|
|
264
|
+
// - [x] Task 1.2
|
|
265
|
+
// - [ ] Task 1.2.1
|
|
266
|
+
// - [ ] Task 1.2.2
|
|
267
|
+
// - [ ] Task 2
|
|
268
|
+
// - [ ] Task 2.1`;
|
|
269
|
+
// const html = markdownToHtml(original);
|
|
270
|
+
// const result = htmlToMarkdown(html);
|
|
271
|
+
// // Check all items are present
|
|
272
|
+
// expect(result).toContain('- [ ] Task 1');
|
|
273
|
+
// expect(result).toContain(' - [ ] Task 1.1');
|
|
274
|
+
// expect(result).toContain(' - [x] Task 1.2');
|
|
275
|
+
// expect(result).toContain(' - [ ] Task 1.2.1');
|
|
276
|
+
// expect(result).toContain(' - [ ] Task 1.2.2');
|
|
277
|
+
// expect(result).toContain('- [ ] Task 2');
|
|
278
|
+
// expect(result).toContain(' - [ ] Task 2.1');
|
|
279
|
+
// });
|
|
280
|
+
// it('should handle task list with description formatting', () => {
|
|
281
|
+
// const original = `- [ ] Add button to trigger task refinement
|
|
282
|
+
// - [ ] **Description**: Clear explanation
|
|
283
|
+
// - [ ] *Acceptance Criteria*: Tests pass
|
|
284
|
+
// - [ ] \`Technical Details\`: Use React`;
|
|
285
|
+
// const html = markdownToHtml(original);
|
|
286
|
+
// const result = htmlToMarkdown(html);
|
|
287
|
+
// expect(result).toContain('- [ ] Add button to trigger task refinement');
|
|
288
|
+
// // Markdown inside task items may not be preserved through round-trip
|
|
289
|
+
// // This is a known limitation of the current implementation
|
|
290
|
+
// expect(result).toContain('Description');
|
|
291
|
+
// expect(result).toContain('Acceptance Criteria');
|
|
292
|
+
// expect(result).toContain('Technical Details');
|
|
293
|
+
// });
|
|
294
|
+
// });
|
|
295
|
+
describe('Edge cases', () => {
|
|
296
|
+
it('should handle malformed task list syntax gracefully', () => {
|
|
297
|
+
const markdown = '- [] Invalid task\n-[x] Another invalid\n- [ ] Valid task';
|
|
298
|
+
const html = markdownToHtml(markdown);
|
|
299
|
+
// Should still parse what it can
|
|
300
|
+
expect(html).toContain('Valid task');
|
|
301
|
+
});
|
|
302
|
+
// it('should handle empty task descriptions', () => {
|
|
303
|
+
// const markdown = '- [ ] \n- [x] ';
|
|
304
|
+
// const html = markdownToHtml(markdown);
|
|
305
|
+
// expect(html).toContain('data-type="taskItem"');
|
|
306
|
+
// });
|
|
307
|
+
// it('should handle very deeply nested lists (10 levels)', () => {
|
|
308
|
+
// let markdown = '- [ ] L1';
|
|
309
|
+
// for (let i = 2; i <= 10; i++) {
|
|
310
|
+
// markdown += '\n' + ' '.repeat(i - 1) + `- [ ] L${i}`;
|
|
311
|
+
// }
|
|
312
|
+
// const html = markdownToHtml(markdown);
|
|
313
|
+
// const result = htmlToMarkdown(html);
|
|
314
|
+
// expect(result).toContain('- [ ] L1');
|
|
315
|
+
// expect(result).toContain(' '.repeat(9) + '- [ ] L10');
|
|
316
|
+
// });
|
|
317
|
+
it('should handle mixed content in list items', () => {
|
|
318
|
+
const html = `<ul>
|
|
319
|
+
<li data-type="taskItem"><input type="checkbox" disabled> Task with <strong>bold</strong> and <a href="#">link</a></li>
|
|
320
|
+
</ul>`;
|
|
321
|
+
const markdown = htmlToMarkdown(html);
|
|
322
|
+
expect(markdown).toContain('- [ ] Task with **bold** and [link](#)');
|
|
323
|
+
});
|
|
324
|
+
it('should strip extra whitespace properly', () => {
|
|
325
|
+
const html = `<ul>
|
|
326
|
+
<li data-type="taskItem"> <input type="checkbox" disabled> Task with spaces </li>
|
|
327
|
+
</ul>`;
|
|
328
|
+
const markdown = htmlToMarkdown(html);
|
|
329
|
+
expect(markdown.trim()).toBe('- [ ] Task with spaces');
|
|
330
|
+
});
|
|
331
|
+
it('should handle nested task lists properly', () => {
|
|
332
|
+
const nestedMarkdown = `- [ ] Parent task with nested items:
|
|
333
|
+
- [ ] Child task 1
|
|
334
|
+
- [x] Child task 2`;
|
|
335
|
+
const html = markdownToHtml(nestedMarkdown);
|
|
336
|
+
// Check that HTML contains proper nesting structure
|
|
337
|
+
expect(html).toContain('data-type="taskList"');
|
|
338
|
+
expect(html).toContain('data-type="taskItem"');
|
|
339
|
+
expect(html).toContain('data-checked="false"');
|
|
340
|
+
expect(html).toContain('data-checked="true"');
|
|
341
|
+
expect(html).toContain('Parent task with nested items:');
|
|
342
|
+
expect(html).toContain('Child task 1');
|
|
343
|
+
expect(html).toContain('Child task 2');
|
|
344
|
+
// Verify the nested structure is present in HTML
|
|
345
|
+
expect(html).toMatch(/<li[^>]*data-type="taskItem"[^>]*>.*<ul>.*<li[^>]*data-type="taskItem"/s);
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { AgentService } from '../../agent/agent-service.js';
|
|
2
|
+
import { getTaskService } from './task-service-singleton.js';
|
|
3
|
+
import { getSettingsService } from '../../settings-service.js';
|
|
4
|
+
import { getProjectRoot, getVibeDir } from './project-root.js';
|
|
5
|
+
export function getAgentService() {
|
|
6
|
+
if (!globalThis.__vibeman_agent_service__) {
|
|
7
|
+
const taskService = getTaskService();
|
|
8
|
+
const settingsVibeDir = (() => {
|
|
9
|
+
try {
|
|
10
|
+
const svc = getSettingsService();
|
|
11
|
+
const s = svc.getSettings();
|
|
12
|
+
return s?.development?.vibeDir;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
})();
|
|
18
|
+
const projectRoot = getProjectRoot();
|
|
19
|
+
const vibeDir = settingsVibeDir || getVibeDir();
|
|
20
|
+
globalThis.__vibeman_agent_service__ = new AgentService(taskService, projectRoot);
|
|
21
|
+
console.log(`🤖 Agent Service initialized (projectRoot=${projectRoot}, vibeDir=${vibeDir})`);
|
|
22
|
+
}
|
|
23
|
+
return globalThis.__vibeman_agent_service__;
|
|
24
|
+
}
|
|
25
|
+
export function resetAgentService() {
|
|
26
|
+
globalThis.__vibeman_agent_service__ = undefined;
|
|
27
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { GitService } from '../../vcs/git-service.js';
|
|
2
|
+
import { getSettingsService } from '../../settings-service.js';
|
|
3
|
+
import { getProjectRoot, getVibeDir } from './project-root.js';
|
|
4
|
+
export function getGitService(config) {
|
|
5
|
+
if (!globalThis.__vibeman_git_service__) {
|
|
6
|
+
// Resolve project root robustly (handles being launched from apps/api)
|
|
7
|
+
const projectRoot = getProjectRoot();
|
|
8
|
+
// Get vibeDir from settings, fallback to detected project .vibeman
|
|
9
|
+
const settingsVibeDir = (() => {
|
|
10
|
+
try {
|
|
11
|
+
const svc = getSettingsService();
|
|
12
|
+
const s = svc.getSettings();
|
|
13
|
+
return s?.development?.vibeDir;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
})();
|
|
19
|
+
const vibeDir = settingsVibeDir || getVibeDir();
|
|
20
|
+
// Prefer settings default branch; fall back to 'main'
|
|
21
|
+
const settingsDefaultBranch = (() => {
|
|
22
|
+
try {
|
|
23
|
+
const svc = getSettingsService();
|
|
24
|
+
// Best effort; initialize may not have been awaited here
|
|
25
|
+
// but service returns defaults if not yet loaded from disk
|
|
26
|
+
const s = svc.getSettings();
|
|
27
|
+
return s?.development?.git?.defaultBranch;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
})();
|
|
33
|
+
const envConfig = {
|
|
34
|
+
defaultBranch: settingsDefaultBranch || 'main',
|
|
35
|
+
};
|
|
36
|
+
globalThis.__vibeman_git_service__ = new GitService(projectRoot, {
|
|
37
|
+
...envConfig,
|
|
38
|
+
...config,
|
|
39
|
+
});
|
|
40
|
+
const settingsInfo = { defaultBranch: envConfig.defaultBranch };
|
|
41
|
+
console.log(`🔧 Git Service initialized (root=${projectRoot}, vibeDir=${vibeDir}, defaultBranch=${settingsInfo.defaultBranch})`);
|
|
42
|
+
}
|
|
43
|
+
return globalThis.__vibeman_git_service__;
|
|
44
|
+
}
|
|
45
|
+
export function resetGitService() {
|
|
46
|
+
globalThis.__vibeman_git_service__ = undefined;
|
|
47
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
// Find the repository project root by walking up from CWD
|
|
4
|
+
// Preference order:
|
|
5
|
+
// - env VIBEMAN_PROJECT_ROOT
|
|
6
|
+
// - nearest directory containing .git or .vibeman
|
|
7
|
+
// - fallback to process.cwd()
|
|
8
|
+
export function getProjectRoot() {
|
|
9
|
+
const envRoot = process.env.VIBEMAN_PROJECT_ROOT;
|
|
10
|
+
if (envRoot && envRoot.trim().length > 0) {
|
|
11
|
+
return path.resolve(envRoot);
|
|
12
|
+
}
|
|
13
|
+
// First preference: directory that contains a .git directory/file
|
|
14
|
+
let dir = process.cwd();
|
|
15
|
+
const { root } = path.parse(dir);
|
|
16
|
+
while (true) {
|
|
17
|
+
if (fs.existsSync(path.join(dir, '.git'))) {
|
|
18
|
+
return dir;
|
|
19
|
+
}
|
|
20
|
+
if (dir === root)
|
|
21
|
+
break;
|
|
22
|
+
dir = path.dirname(dir);
|
|
23
|
+
}
|
|
24
|
+
// Fallback: nearest directory with .vibeman (if repo is checked out without .git, e.g. tarball)
|
|
25
|
+
dir = process.cwd();
|
|
26
|
+
while (true) {
|
|
27
|
+
if (fs.existsSync(path.join(dir, '.vibeman'))) {
|
|
28
|
+
return dir;
|
|
29
|
+
}
|
|
30
|
+
if (dir === root)
|
|
31
|
+
break;
|
|
32
|
+
dir = path.dirname(dir);
|
|
33
|
+
}
|
|
34
|
+
return process.cwd();
|
|
35
|
+
}
|
|
36
|
+
export function getVibeDir() {
|
|
37
|
+
return path.join(getProjectRoot(), '.vibeman');
|
|
38
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { TaskService } from '../../tasks/task-service.js';
|
|
2
|
+
declare global {
|
|
3
|
+
var __vibeman_task_service__: unknown;
|
|
4
|
+
var __vibeman_task_service_init__: unknown;
|
|
5
|
+
}
|
|
6
|
+
export declare function getTaskService(): TaskService;
|
|
7
|
+
export declare function getTaskServiceAsync(): Promise<TaskService>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { getSettingsService } from '../../settings-service.js';
|
|
2
|
+
import { TaskService } from '../../tasks/task-service.js';
|
|
3
|
+
import { isProduction } from '../../utils/env.js';
|
|
4
|
+
import { getVibeDir } from './project-root.js';
|
|
5
|
+
export function getTaskService() {
|
|
6
|
+
if (!globalThis.__vibeman_task_service__) {
|
|
7
|
+
const settingsVibeDir = (() => {
|
|
8
|
+
try {
|
|
9
|
+
const svc = getSettingsService();
|
|
10
|
+
const s = svc.getSettings();
|
|
11
|
+
return s?.development?.vibeDir;
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
})();
|
|
17
|
+
// Ensure we use the repo-level .vibeman even when launched from a subpackage
|
|
18
|
+
const vibeDir = settingsVibeDir ?? getVibeDir();
|
|
19
|
+
globalThis.__vibeman_task_service__ = new TaskService(vibeDir);
|
|
20
|
+
console.log(`🗂️ Task Service initialized (vibeDir=${vibeDir})`);
|
|
21
|
+
globalThis.__vibeman_task_service__
|
|
22
|
+
.ensureInitialized()
|
|
23
|
+
.catch((e) => console.error('TaskService init error:', e));
|
|
24
|
+
}
|
|
25
|
+
return globalThis.__vibeman_task_service__;
|
|
26
|
+
}
|
|
27
|
+
export async function getTaskServiceAsync() {
|
|
28
|
+
if (globalThis.__vibeman_task_service__) {
|
|
29
|
+
return globalThis.__vibeman_task_service__;
|
|
30
|
+
}
|
|
31
|
+
if (!globalThis.__vibeman_task_service_init__) {
|
|
32
|
+
const settingsVibeDir = (() => {
|
|
33
|
+
try {
|
|
34
|
+
const svc = getSettingsService();
|
|
35
|
+
const s = svc.getSettings();
|
|
36
|
+
return s?.development?.vibeDir;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
})();
|
|
42
|
+
const vibeDir = settingsVibeDir ?? getVibeDir();
|
|
43
|
+
globalThis.__vibeman_task_service__ = new TaskService(vibeDir);
|
|
44
|
+
globalThis.__vibeman_task_service_init__ = globalThis.__vibeman_task_service__
|
|
45
|
+
.initialize()
|
|
46
|
+
.then(() => globalThis.__vibeman_task_service__);
|
|
47
|
+
}
|
|
48
|
+
return globalThis.__vibeman_task_service_init__;
|
|
49
|
+
}
|
|
50
|
+
// Cleanup on process exit
|
|
51
|
+
if (isProduction()) {
|
|
52
|
+
process.on('SIGTERM', () => {
|
|
53
|
+
if (globalThis.__vibeman_task_service__) {
|
|
54
|
+
globalThis.__vibeman_task_service__.stop();
|
|
55
|
+
globalThis.__vibeman_task_service__ = undefined;
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { VibingOrchestrator } from '../../workflows/vibing-orchestrator.js';
|
|
2
|
+
declare global {
|
|
3
|
+
var __vibeman_vibing_orchestrator__: unknown;
|
|
4
|
+
var __vibeman_vibing_orchestrator_init__: unknown;
|
|
5
|
+
}
|
|
6
|
+
export declare function getVibingOrchestrator(): VibingOrchestrator;
|
|
7
|
+
export declare function getVibingOrchestratorAsync(): Promise<VibingOrchestrator>;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { VibingOrchestrator } from '../../workflows/vibing-orchestrator.js';
|
|
2
|
+
import { getTaskService } from './task-service-singleton.js';
|
|
3
|
+
import { getAgentService } from './agent-service-singleton.js';
|
|
4
|
+
import { getGitService } from './git-service-singleton.js';
|
|
5
|
+
import { isProduction } from '../../utils/env.js';
|
|
6
|
+
// Default config fallback for VibingOrchestrator
|
|
7
|
+
const getDefaultVibingConfig = () => ({
|
|
8
|
+
autoQualityChecks: true,
|
|
9
|
+
requireHumanApproval: true,
|
|
10
|
+
aiCodeReview: true,
|
|
11
|
+
retryPolicy: { maxImplementationAttempts: 3 },
|
|
12
|
+
autoCommit: false,
|
|
13
|
+
});
|
|
14
|
+
export function getVibingOrchestrator() {
|
|
15
|
+
if (!globalThis.__vibeman_vibing_orchestrator__) {
|
|
16
|
+
const taskService = getTaskService();
|
|
17
|
+
const agentService = getAgentService();
|
|
18
|
+
const gitService = getGitService();
|
|
19
|
+
globalThis.__vibeman_vibing_orchestrator__ = new VibingOrchestrator(taskService, agentService, agentService.getWorktreeService(), getDefaultVibingConfig(), gitService);
|
|
20
|
+
}
|
|
21
|
+
// Kick off one-time initialization in background (non-blocking)
|
|
22
|
+
if (!globalThis.__vibeman_vibing_orchestrator_init__) {
|
|
23
|
+
globalThis.__vibeman_vibing_orchestrator_init__ = globalThis.__vibeman_vibing_orchestrator__
|
|
24
|
+
.initialize()
|
|
25
|
+
.catch((e) => console.error('VibingOrchestrator init error:', e))
|
|
26
|
+
.finally(() => {
|
|
27
|
+
globalThis.__vibeman_vibing_orchestrator_init__ = undefined;
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
return globalThis.__vibeman_vibing_orchestrator__;
|
|
31
|
+
}
|
|
32
|
+
export async function getVibingOrchestratorAsync() {
|
|
33
|
+
if (globalThis.__vibeman_vibing_orchestrator__) {
|
|
34
|
+
return globalThis.__vibeman_vibing_orchestrator__;
|
|
35
|
+
}
|
|
36
|
+
if (!globalThis.__vibeman_vibing_orchestrator_init__) {
|
|
37
|
+
const taskService = getTaskService();
|
|
38
|
+
const agentService = getAgentService();
|
|
39
|
+
const gitService = getGitService();
|
|
40
|
+
globalThis.__vibeman_vibing_orchestrator__ = new VibingOrchestrator(taskService, agentService, agentService.getWorktreeService(), getDefaultVibingConfig(), gitService);
|
|
41
|
+
globalThis.__vibeman_vibing_orchestrator_init__ = globalThis.__vibeman_vibing_orchestrator__
|
|
42
|
+
.initialize()
|
|
43
|
+
.catch((e) => console.error('VibingOrchestrator init error:', e));
|
|
44
|
+
}
|
|
45
|
+
await globalThis.__vibeman_vibing_orchestrator_init__;
|
|
46
|
+
return globalThis.__vibeman_vibing_orchestrator__;
|
|
47
|
+
}
|
|
48
|
+
// Cleanup on process exit
|
|
49
|
+
if (isProduction()) {
|
|
50
|
+
process.on('SIGTERM', () => {
|
|
51
|
+
if (globalThis.__vibeman_vibing_orchestrator__) {
|
|
52
|
+
// VibingOrchestrator doesn't have a stop method, but we can clean up the reference
|
|
53
|
+
globalThis.__vibeman_vibing_orchestrator__ = undefined;
|
|
54
|
+
globalThis.__vibeman_vibing_orchestrator_init__ = undefined;
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { clampSelectionPos } from './tiptap-utils.js';
|
|
3
|
+
describe('clampSelectionPos', () => {
|
|
4
|
+
it('keeps positions within valid range', () => {
|
|
5
|
+
const res = clampSelectionPos(5, 8, 20);
|
|
6
|
+
expect(res).toEqual({ from: 5, to: 8 });
|
|
7
|
+
});
|
|
8
|
+
it('clamps underflow to 1', () => {
|
|
9
|
+
const res = clampSelectionPos(-10, 0, 20);
|
|
10
|
+
expect(res).toEqual({ from: 1, to: 1 });
|
|
11
|
+
});
|
|
12
|
+
it('clamps overflow to doc.nodeSize - 2', () => {
|
|
13
|
+
const res = clampSelectionPos(100, 200, 20);
|
|
14
|
+
// maxPos = 18 for nodeSize 20
|
|
15
|
+
expect(res).toEqual({ from: 18, to: 18 });
|
|
16
|
+
});
|
|
17
|
+
it('orders from/to when anchor > head', () => {
|
|
18
|
+
const res = clampSelectionPos(10, 5, 20);
|
|
19
|
+
expect(res).toEqual({ from: 5, to: 10 });
|
|
20
|
+
});
|
|
21
|
+
it('handles tiny documents safely', () => {
|
|
22
|
+
const res0 = clampSelectionPos(5, 6, 0);
|
|
23
|
+
expect(res0).toEqual({ from: 1, to: 1 });
|
|
24
|
+
const res1 = clampSelectionPos(2, 3, 1);
|
|
25
|
+
expect(res1).toEqual({ from: 1, to: 1 });
|
|
26
|
+
});
|
|
27
|
+
});
|