@mod-computer/cli 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.
- package/README.md +125 -0
- package/commands/execute.md +156 -0
- package/commands/overview.md +233 -0
- package/commands/review.md +151 -0
- package/commands/spec.md +169 -0
- package/dist/app.js +227 -0
- package/dist/cli.bundle.js +25824 -0
- package/dist/cli.bundle.js.map +7 -0
- package/dist/cli.js +121 -0
- package/dist/commands/agents-run.js +71 -0
- package/dist/commands/auth.js +151 -0
- package/dist/commands/branch.js +1411 -0
- package/dist/commands/claude-sync.js +772 -0
- package/dist/commands/index.js +43 -0
- package/dist/commands/init.js +378 -0
- package/dist/commands/recover.js +207 -0
- package/dist/commands/spec.js +386 -0
- package/dist/commands/status.js +329 -0
- package/dist/commands/sync.js +95 -0
- package/dist/commands/workspace.js +423 -0
- package/dist/components/conflict-resolution-ui.js +120 -0
- package/dist/components/messages.js +5 -0
- package/dist/components/thread.js +8 -0
- package/dist/config/features.js +72 -0
- package/dist/config/release-profiles/development.json +11 -0
- package/dist/config/release-profiles/mvp.json +12 -0
- package/dist/config/release-profiles/v0.1.json +11 -0
- package/dist/config/release-profiles/v0.2.json +11 -0
- package/dist/containers/branches-container.js +140 -0
- package/dist/containers/directory-container.js +92 -0
- package/dist/containers/thread-container.js +214 -0
- package/dist/containers/threads-container.js +27 -0
- package/dist/containers/workspaces-container.js +27 -0
- package/dist/daemon-worker.js +257 -0
- package/dist/lib/auth-server.js +153 -0
- package/dist/lib/browser.js +35 -0
- package/dist/lib/storage.js +203 -0
- package/dist/services/automatic-file-tracker.js +303 -0
- package/dist/services/cli-orchestrator.js +227 -0
- package/dist/services/feature-flags.js +187 -0
- package/dist/services/file-import-service.js +283 -0
- package/dist/services/file-transformation-service.js +218 -0
- package/dist/services/logger.js +44 -0
- package/dist/services/mod-config.js +61 -0
- package/dist/services/modignore-service.js +326 -0
- package/dist/services/sync-daemon.js +244 -0
- package/dist/services/thread-notification-service.js +50 -0
- package/dist/services/thread-service.js +147 -0
- package/dist/stores/use-directory-store.js +96 -0
- package/dist/stores/use-threads-store.js +46 -0
- package/dist/stores/use-workspaces-store.js +32 -0
- package/dist/types/config.js +16 -0
- package/dist/types/index.js +2 -0
- package/dist/types/workspace-connection.js +2 -0
- package/dist/types.js +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export class ThreadNotificationService {
|
|
2
|
+
constructor(repo) {
|
|
3
|
+
this.repo = repo;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Add a file update notification to the thread
|
|
7
|
+
* For now, this just logs the notification - can be enhanced later
|
|
8
|
+
*/
|
|
9
|
+
async addFileUpdateNotification(threadId, fileName, action) {
|
|
10
|
+
try {
|
|
11
|
+
const message = this.getNotificationMessage(fileName, action);
|
|
12
|
+
// For now, just log the notification
|
|
13
|
+
// TODO: Later integrate with actual thread message system
|
|
14
|
+
console.log(`📢 ${message}`);
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
console.error(`Failed to add file update notification:`, error);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Generate notification message based on action
|
|
22
|
+
*/
|
|
23
|
+
getNotificationMessage(fileName, action) {
|
|
24
|
+
const emoji = this.getActionEmoji(action);
|
|
25
|
+
const verb = this.getActionVerb(action);
|
|
26
|
+
return `${emoji} ${fileName} ${verb}`;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Get emoji for action type
|
|
30
|
+
*/
|
|
31
|
+
getActionEmoji(action) {
|
|
32
|
+
switch (action) {
|
|
33
|
+
case 'updated': return '📝';
|
|
34
|
+
case 'created': return '✨';
|
|
35
|
+
case 'deleted': return '🗑️';
|
|
36
|
+
default: return '📄';
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Get verb for action type
|
|
41
|
+
*/
|
|
42
|
+
getActionVerb(action) {
|
|
43
|
+
switch (action) {
|
|
44
|
+
case 'updated': return 'updated';
|
|
45
|
+
case 'created': return 'created';
|
|
46
|
+
case 'deleted': return 'deleted';
|
|
47
|
+
default: return 'changed';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { ThreadService as CoreThreadService } from '@mod/mod-core/services/thread-service';
|
|
2
|
+
import { BranchService } from '@mod/mod-core/services/branch-service';
|
|
3
|
+
import { chatWithAgentCli } from './cli-orchestrator.js';
|
|
4
|
+
import { log } from './logger.js';
|
|
5
|
+
export class CLIThreadService {
|
|
6
|
+
// private ai: typeof runAgentWithStream; // Placeholder for orchestrator/agent logic
|
|
7
|
+
constructor(repo) {
|
|
8
|
+
this.core = new CoreThreadService(repo);
|
|
9
|
+
this.repo = repo;
|
|
10
|
+
// this.ai = runAgentWithStream; // Assign orchestrator/agent logic as needed
|
|
11
|
+
}
|
|
12
|
+
async getThreads(workspaceId) {
|
|
13
|
+
const wsHandle = await this.repo.find(workspaceId);
|
|
14
|
+
const workspace = (await wsHandle.doc());
|
|
15
|
+
if (!workspace || !workspace.branchesDocId)
|
|
16
|
+
return [];
|
|
17
|
+
const branchService = new BranchService(this.repo);
|
|
18
|
+
const threads = [];
|
|
19
|
+
try {
|
|
20
|
+
const branches = await branchService.getBranchesForWorkspace(workspace.branchesDocId);
|
|
21
|
+
for (const branch of branches) {
|
|
22
|
+
const threadId = branch?.threadId;
|
|
23
|
+
if (!threadId)
|
|
24
|
+
continue;
|
|
25
|
+
try {
|
|
26
|
+
const thread = await this.core.getThread(threadId);
|
|
27
|
+
if (thread)
|
|
28
|
+
threads.push(thread);
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
log('[CLIThreadService] Failed to load thread', {
|
|
32
|
+
branchId: branch?.id,
|
|
33
|
+
threadId,
|
|
34
|
+
err,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
log('[CLIThreadService] Failed to load branches for workspace', {
|
|
41
|
+
workspaceId,
|
|
42
|
+
err,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
return threads;
|
|
46
|
+
}
|
|
47
|
+
async getThread(threadId) {
|
|
48
|
+
return this.core.getThread(threadId);
|
|
49
|
+
}
|
|
50
|
+
async createThread(name, branchId, workspaceId) {
|
|
51
|
+
const threadId = await this.core.createThread(name, branchId);
|
|
52
|
+
try {
|
|
53
|
+
const branchService = new BranchService(this.repo);
|
|
54
|
+
const wsHandle = await this.repo.find(workspaceId);
|
|
55
|
+
const workspace = (await wsHandle.doc());
|
|
56
|
+
if (workspace?.branchesDocId) {
|
|
57
|
+
await branchService.setThreadId(branchId, threadId, workspace.branchesDocId);
|
|
58
|
+
}
|
|
59
|
+
wsHandle.change((doc) => {
|
|
60
|
+
doc.activeThreadId = threadId;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
log('[CLIThreadService] Failed to persist threadId on branch', {
|
|
65
|
+
branchId,
|
|
66
|
+
workspaceId,
|
|
67
|
+
err,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return threadId;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Stream agent chat for a thread in the CLI.
|
|
74
|
+
* Yields agent response chunks for UI updates.
|
|
75
|
+
*/
|
|
76
|
+
async *streamAgentChat({ threadId, userMessage, user = { id: 'user-1', name: 'You', avatarUrl: '' }, workspace, agent, files = [], images = [], maxMessages = 20, ...opts }) {
|
|
77
|
+
// 1) Persist user message immediately
|
|
78
|
+
await this.core.addThreadItemToThread(threadId, userMessage, user.id, user.name, user.avatarUrl, { workspaceId: workspace.id });
|
|
79
|
+
// 2) Start CLI-native orchestrator stream
|
|
80
|
+
const apiKey = (process.env.OPENAI_API_KEY || process.env.OPENAI_API_TOKEN || process.env.OPENAI || process.env.ANTHROPIC_API_KEY || '').trim();
|
|
81
|
+
try {
|
|
82
|
+
try {
|
|
83
|
+
log('[CLIThreadService] Starting stream with agent:', {
|
|
84
|
+
name: agent?.name,
|
|
85
|
+
id: agent?.id,
|
|
86
|
+
defaultModel: agent?.defaultModel,
|
|
87
|
+
tools: agent?.tools ? Object.keys(agent.tools) : [],
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
catch { }
|
|
91
|
+
for await (const part of chatWithAgentCli({
|
|
92
|
+
repo: this.repo,
|
|
93
|
+
threadId,
|
|
94
|
+
userMessage,
|
|
95
|
+
user,
|
|
96
|
+
workspace,
|
|
97
|
+
agent: agent || { name: 'Assistant', instructions: 'Be helpful.' },
|
|
98
|
+
files,
|
|
99
|
+
images,
|
|
100
|
+
apiKey,
|
|
101
|
+
tools: (agent && agent.tools) || {},
|
|
102
|
+
})) {
|
|
103
|
+
const p = part;
|
|
104
|
+
if (p.type === 'content' && p.content) {
|
|
105
|
+
yield { type: 'content', content: p.content };
|
|
106
|
+
}
|
|
107
|
+
else if (p.type === 'tool-call') {
|
|
108
|
+
yield p;
|
|
109
|
+
}
|
|
110
|
+
else if (p.type === 'tool-result') {
|
|
111
|
+
yield { type: 'tool-result', output: p.output };
|
|
112
|
+
}
|
|
113
|
+
else if (p.type === 'error') {
|
|
114
|
+
yield { type: 'error', error: String(p.error) };
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
const msg = `orchestrator import/stream failed: ${err?.message || String(err)}`;
|
|
120
|
+
yield { type: 'error', error: msg };
|
|
121
|
+
try {
|
|
122
|
+
await this.core.addAssistantMessageToThread(threadId, msg, agent?.name || 'Assistant');
|
|
123
|
+
}
|
|
124
|
+
catch { }
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
async sendUserMessage(threadId, message, agentConfig) {
|
|
128
|
+
// 1. Add user message to thread (core)
|
|
129
|
+
// const threadRepo = new ThreadRepository(this.repo);
|
|
130
|
+
// await threadRepo.addThreadItem(
|
|
131
|
+
// threadId,
|
|
132
|
+
// message,
|
|
133
|
+
// [], // contextDocumentIds
|
|
134
|
+
// true, // addToThread
|
|
135
|
+
// 'user-1', // userId
|
|
136
|
+
// 'You', // userName
|
|
137
|
+
// undefined, // userAvatarUrl
|
|
138
|
+
// {type: 'message'},
|
|
139
|
+
// );
|
|
140
|
+
// 2. TODO: Start agent stream (mod-ai)
|
|
141
|
+
// 3. TODO: As agent responses stream in, append to thread
|
|
142
|
+
// 4. TODO: Notify UI of updates (if needed)
|
|
143
|
+
}
|
|
144
|
+
subscribeToThread(threadId, callback) {
|
|
145
|
+
// TODO: Implement Automerge doc subscription for reactivity
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { createStore } from 'zustand';
|
|
2
|
+
import { useStore } from 'zustand';
|
|
3
|
+
import { BranchableRepo } from '@mod/mod-core/services/branchable-repo';
|
|
4
|
+
import { readModConfig } from '../services/mod-config.js';
|
|
5
|
+
export const directoryStore = createStore((set, get) => ({
|
|
6
|
+
items: {},
|
|
7
|
+
rootIds: [],
|
|
8
|
+
currentPath: [],
|
|
9
|
+
expandedFolders: {},
|
|
10
|
+
loading: false,
|
|
11
|
+
error: null,
|
|
12
|
+
setItems: (items, rootIds) => set(() => ({
|
|
13
|
+
items: Object.fromEntries(items.map((i) => [i.id, i])),
|
|
14
|
+
rootIds,
|
|
15
|
+
})),
|
|
16
|
+
setCurrentPath: (path) => set(() => ({ currentPath: path })),
|
|
17
|
+
setExpanded: (folderId, expanded) => set((state) => ({
|
|
18
|
+
expandedFolders: { ...state.expandedFolders, [folderId]: expanded }
|
|
19
|
+
})),
|
|
20
|
+
setLoading: (loading) => set(() => ({ loading })),
|
|
21
|
+
setError: (error) => set(() => ({ error })),
|
|
22
|
+
reset: () => set(() => ({
|
|
23
|
+
items: {},
|
|
24
|
+
rootIds: [],
|
|
25
|
+
currentPath: [],
|
|
26
|
+
expandedFolders: {},
|
|
27
|
+
loading: false,
|
|
28
|
+
error: null,
|
|
29
|
+
})),
|
|
30
|
+
async loadRootDirectory({ repo, selectedWorkspace, selectedThread }) {
|
|
31
|
+
set({ loading: true, error: null });
|
|
32
|
+
try {
|
|
33
|
+
if (!repo) {
|
|
34
|
+
set({ error: 'No repo available', loading: false });
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const effectiveWorkspaceId = (selectedWorkspace && selectedWorkspace.id) || readModConfig()?.workspaceId;
|
|
38
|
+
if (!effectiveWorkspaceId) {
|
|
39
|
+
set({ error: 'No workspace selected or configured (.mod/config.json)', loading: false });
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const branchContext = new BranchableRepo(repo);
|
|
43
|
+
// Resolve branchId for consistent branch-aware view (prefer config > workspace.activeBranchId > selectedThread)
|
|
44
|
+
let resolvedBranchId = undefined;
|
|
45
|
+
try {
|
|
46
|
+
resolvedBranchId = readModConfig()?.activeBranchId;
|
|
47
|
+
if (!resolvedBranchId) {
|
|
48
|
+
const wsHandle = await repo.find(effectiveWorkspaceId);
|
|
49
|
+
const wsDoc = await wsHandle.doc();
|
|
50
|
+
resolvedBranchId = wsDoc?.activeBranchId;
|
|
51
|
+
}
|
|
52
|
+
if (!resolvedBranchId && selectedThread?.branchId) {
|
|
53
|
+
resolvedBranchId = selectedThread.branchId;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch { }
|
|
57
|
+
const wsWrap = await branchContext.openHandle(effectiveWorkspaceId, { branchId: (resolvedBranchId || undefined), workspaceId: effectiveWorkspaceId });
|
|
58
|
+
const wsDoc = wsWrap.doc();
|
|
59
|
+
const fileRefs = wsDoc.fileRefs || [];
|
|
60
|
+
const folders = wsDoc.folders || [];
|
|
61
|
+
// Build root-level items and dedupe by name to avoid duplicates
|
|
62
|
+
const itemMapByName = {};
|
|
63
|
+
for (const f of folders) {
|
|
64
|
+
if (!f.parentId) {
|
|
65
|
+
const item = { id: f.id, name: f.name, type: 'folder', parentId: f.parentId || null };
|
|
66
|
+
if (!itemMapByName[item.name])
|
|
67
|
+
itemMapByName[item.name] = item;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
for (const f of fileRefs) {
|
|
71
|
+
if (!f.folderId) {
|
|
72
|
+
const item = { id: f.id, name: f.name, type: 'file', parentId: f.folderId || null };
|
|
73
|
+
if (!itemMapByName[item.name])
|
|
74
|
+
itemMapByName[item.name] = item;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const items = Object.values(itemMapByName).sort((a, b) => a.name.localeCompare(b.name));
|
|
78
|
+
const rootIds = items.map(i => i.id);
|
|
79
|
+
get().setItems(items, rootIds);
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
set({ error: err.message || 'Failed to load directory' });
|
|
83
|
+
}
|
|
84
|
+
finally {
|
|
85
|
+
set({ loading: false });
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
}));
|
|
89
|
+
// React hook for using the vanilla store in components
|
|
90
|
+
export const useDirectoryStore = (selector) => useStore(directoryStore, selector);
|
|
91
|
+
// Custom hook for loading directory (merged from use-directory)
|
|
92
|
+
export function useDirectoryLoader() {
|
|
93
|
+
const loadRootDirectory = useDirectoryStore((s) => s.loadRootDirectory);
|
|
94
|
+
const reset = useDirectoryStore((s) => s.reset);
|
|
95
|
+
return { loadRootDirectory, reset };
|
|
96
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { create } from 'zustand';
|
|
2
|
+
import { BranchService } from '@mod/mod-core/services/branch-service';
|
|
3
|
+
export const useThreadsStore = create((set) => ({
|
|
4
|
+
threads: [],
|
|
5
|
+
loading: false,
|
|
6
|
+
error: null,
|
|
7
|
+
fetchThreads: async (repo, selected) => {
|
|
8
|
+
if (!selected || !repo)
|
|
9
|
+
return;
|
|
10
|
+
set({ loading: true, error: null });
|
|
11
|
+
try {
|
|
12
|
+
const wsHandle = await repo.find(selected.id);
|
|
13
|
+
const wsDoc = wsHandle.doc();
|
|
14
|
+
const threadList = [];
|
|
15
|
+
if (wsDoc?.branchesDocId) {
|
|
16
|
+
const branchService = new BranchService(repo);
|
|
17
|
+
const branches = await branchService.getBranchesForWorkspace(wsDoc.branchesDocId);
|
|
18
|
+
for (const branch of branches || []) {
|
|
19
|
+
const branchId = String(branch?.id || '');
|
|
20
|
+
if (!branchId)
|
|
21
|
+
continue;
|
|
22
|
+
const threadId = branch?.threadId ? String(branch.threadId) : branchId;
|
|
23
|
+
let threadDoc = null;
|
|
24
|
+
try {
|
|
25
|
+
const tHandle = await repo.find(threadId);
|
|
26
|
+
threadDoc = tHandle.doc();
|
|
27
|
+
}
|
|
28
|
+
catch { }
|
|
29
|
+
threadList.push({
|
|
30
|
+
id: String(threadDoc?.id || threadId),
|
|
31
|
+
name: threadDoc?.name || branch?.name || 'Untitled',
|
|
32
|
+
branchId,
|
|
33
|
+
hasThread: Boolean(branch?.threadId),
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
set({ threads: threadList });
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
set({ error: err.message || String(err) });
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
set({ loading: false });
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
}));
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { create } from 'zustand';
|
|
2
|
+
export const useWorkspacesStore = create((set) => ({
|
|
3
|
+
workspaces: [],
|
|
4
|
+
loading: false,
|
|
5
|
+
error: null,
|
|
6
|
+
fetchWorkspaces: async (repo) => {
|
|
7
|
+
set({ loading: true, error: null });
|
|
8
|
+
try {
|
|
9
|
+
// const rootDocId = '3RrsuQCaieHkXPUNSsq3UhEAxnHW';
|
|
10
|
+
// const rootDocId = 'rY75AHsEfNx1vKnrtpdfmo5dyjr';
|
|
11
|
+
// const rootDocId = '2a9anXJNoBxstgrhRJfkBGS3uxs';
|
|
12
|
+
// const rootDocId = '3pW2EWyQPrshmj4Y1KqEo7sMTqxV';
|
|
13
|
+
const rootDocId = 'KRkJrMQeNQo9bTwSsoKZBxcpz1y';
|
|
14
|
+
const wsHandle = await repo.find(rootDocId);
|
|
15
|
+
const doc = wsHandle.doc();
|
|
16
|
+
const workspacesRaw = doc.workspaces || [];
|
|
17
|
+
const workspacesList = (Array.isArray(workspacesRaw)
|
|
18
|
+
? workspacesRaw
|
|
19
|
+
: []).map((w) => ({
|
|
20
|
+
id: w.id || '',
|
|
21
|
+
name: w.name || w.title || 'Untitled',
|
|
22
|
+
}));
|
|
23
|
+
set({ workspaces: workspacesList });
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
set({ error: err.message || String(err) });
|
|
27
|
+
}
|
|
28
|
+
finally {
|
|
29
|
+
set({ loading: false });
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
}));
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// glassware[type=implementation, id=cli-config-types, requirements=req-cli-storage-config-1,req-cli-storage-config-2]
|
|
2
|
+
/**
|
|
3
|
+
* Default settings values.
|
|
4
|
+
*/
|
|
5
|
+
export const DEFAULT_SETTINGS = {
|
|
6
|
+
syncDebounceMs: 100,
|
|
7
|
+
logLevel: 'info',
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Default config for new installations.
|
|
11
|
+
*/
|
|
12
|
+
export const DEFAULT_CONFIG = {
|
|
13
|
+
version: 1,
|
|
14
|
+
auth: null,
|
|
15
|
+
settings: DEFAULT_SETTINGS,
|
|
16
|
+
};
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mod-computer/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"bin": {
|
|
6
|
+
"mod": "dist/cli.bundle.js"
|
|
7
|
+
},
|
|
8
|
+
"type": "module",
|
|
9
|
+
"engines": {
|
|
10
|
+
"node": ">=16"
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc && node fix-imports.js && cp -r source/config/release-profiles dist/config/",
|
|
14
|
+
"build:bundle": "node build-bundle.js",
|
|
15
|
+
"prepublishOnly": "pnpm build:bundle",
|
|
16
|
+
"dev": "tsc --watch",
|
|
17
|
+
"test": "vitest run",
|
|
18
|
+
"package": "node build-for-docs.js"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"commands"
|
|
23
|
+
],
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@automerge/automerge": "^3.1.2",
|
|
26
|
+
"@automerge/automerge-repo": "^2.3.1",
|
|
27
|
+
"@automerge/automerge-repo-network-websocket": "^2.3.1",
|
|
28
|
+
"@automerge/automerge-repo-storage-nodefs": "^2.3.1",
|
|
29
|
+
"@ai-sdk/anthropic": "2.0.0-beta.3",
|
|
30
|
+
"@ai-sdk/openai": "2.0.0-beta.5",
|
|
31
|
+
"ai": "5.0.0-beta.11",
|
|
32
|
+
"chokidar": "^4.0.3",
|
|
33
|
+
"dotenv": "^17.1.0",
|
|
34
|
+
"ink": "^6.0.1",
|
|
35
|
+
"ink-select-input": "^6.2.0",
|
|
36
|
+
"ink-text-input": "^6.0.0",
|
|
37
|
+
"meow": "^11.0.0",
|
|
38
|
+
"react": "19.1.0",
|
|
39
|
+
"react-dom": "19.1.0",
|
|
40
|
+
"zustand": "^5.0.6"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@mod/mod-core": "workspace:*",
|
|
44
|
+
"esbuild": "^0.24.0",
|
|
45
|
+
"@babel/cli": "^7.21.0",
|
|
46
|
+
"@babel/preset-react": "^7.18.6",
|
|
47
|
+
"@types/ink": "^2.0.3",
|
|
48
|
+
"@types/ink-select-input": "^3.0.5",
|
|
49
|
+
"@types/ink-text-input": "^2.0.5",
|
|
50
|
+
"@types/meow": "^5.0.0",
|
|
51
|
+
"@types/node": "^24.0.10",
|
|
52
|
+
"@types/react": "^19.1.8",
|
|
53
|
+
"@vdemedes/prettier-config": "^2.0.1",
|
|
54
|
+
"chalk": "^5.2.0",
|
|
55
|
+
"eslint-config-xo-react": "^0.27.0",
|
|
56
|
+
"eslint-plugin-react": "^7.32.2",
|
|
57
|
+
"eslint-plugin-react-hooks": "^4.6.0",
|
|
58
|
+
"import-jsx": "^5.0.0",
|
|
59
|
+
"ink-testing-library": "^3.0.0",
|
|
60
|
+
"prettier": "^2.8.7",
|
|
61
|
+
"react-test-renderer": "^19.1.0",
|
|
62
|
+
"ts-node": "^10.9.2",
|
|
63
|
+
"typescript": "^5.8.3",
|
|
64
|
+
"vitest": "^1.6.1"
|
|
65
|
+
},
|
|
66
|
+
"prettier": "@vdemedes/prettier-config"
|
|
67
|
+
}
|