@arcteninc/core 0.0.175 → 0.0.177
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 +73 -78
- package/dist/index.cjs +3 -16
- package/dist/index.d.ts +1 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +856 -8408
- package/dist/lib/useAgent.d.ts +1 -2
- package/dist/lib/useAgent.d.ts.map +1 -1
- package/dist/types/use-agent.d.ts +3 -44
- package/dist/types/use-agent.d.ts.map +1 -1
- package/dist/utils/extract-tool-metadata.d.ts.map +1 -1
- package/package.json +7 -46
- package/scripts/arcten-cli.cjs +14 -108
- package/scripts/cli-extract-types-auto.ts +22 -4
- package/scripts/update-core.cjs +124 -0
- package/dist/components/ArctenAgent.d.ts +0 -52
- package/dist/components/ArctenAgent.d.ts.map +0 -1
- package/dist/components/ai-elements/prompt-input.d.ts +0 -187
- package/dist/components/ai-elements/prompt-input.d.ts.map +0 -1
- package/dist/components/ai-elements/reasoning.d.ts +0 -17
- package/dist/components/ai-elements/reasoning.d.ts.map +0 -1
- package/dist/components/ai-elements/response.d.ts +0 -8
- package/dist/components/ai-elements/response.d.ts.map +0 -1
- package/dist/components/ai-elements/shimmer.d.ts +0 -10
- package/dist/components/ai-elements/shimmer.d.ts.map +0 -1
- package/dist/components/citation-button.d.ts +0 -14
- package/dist/components/citation-button.d.ts.map +0 -1
- package/dist/components/citation-text-renderer.d.ts +0 -31
- package/dist/components/citation-text-renderer.d.ts.map +0 -1
- package/dist/components/secure-modals/EmailModal.d.ts +0 -10
- package/dist/components/secure-modals/EmailModal.d.ts.map +0 -1
- package/dist/components/secure-modals/FormModal.d.ts +0 -20
- package/dist/components/secure-modals/FormModal.d.ts.map +0 -1
- package/dist/components/secure-modals/PasswordModal.d.ts +0 -10
- package/dist/components/secure-modals/PasswordModal.d.ts.map +0 -1
- package/dist/components/secure-modals/PhoneModal.d.ts +0 -10
- package/dist/components/secure-modals/PhoneModal.d.ts.map +0 -1
- package/dist/components/secure-modals/PinModal.d.ts +0 -11
- package/dist/components/secure-modals/PinModal.d.ts.map +0 -1
- package/dist/components/secure-modals/SecureModalProvider.d.ts +0 -13
- package/dist/components/secure-modals/SecureModalProvider.d.ts.map +0 -1
- package/dist/components/secure-modals/TextModal.d.ts +0 -11
- package/dist/components/secure-modals/TextModal.d.ts.map +0 -1
- package/dist/components/secure-modals/index.d.ts +0 -10
- package/dist/components/secure-modals/index.d.ts.map +0 -1
- package/dist/components/secure-modals/types.d.ts +0 -34
- package/dist/components/secure-modals/types.d.ts.map +0 -1
- package/dist/components/tool-call-approval.d.ts +0 -9
- package/dist/components/tool-call-approval.d.ts.map +0 -1
- package/dist/components/tool-call-result.d.ts +0 -8
- package/dist/components/tool-call-result.d.ts.map +0 -1
- package/dist/components/ui/autotextarea.d.ts +0 -19
- package/dist/components/ui/autotextarea.d.ts.map +0 -1
- package/dist/components/ui/badge.d.ts +0 -10
- package/dist/components/ui/badge.d.ts.map +0 -1
- package/dist/components/ui/button.d.ts +0 -14
- package/dist/components/ui/button.d.ts.map +0 -1
- package/dist/components/ui/collapsible.d.ts +0 -6
- package/dist/components/ui/collapsible.d.ts.map +0 -1
- package/dist/components/ui/command.d.ts +0 -19
- package/dist/components/ui/command.d.ts.map +0 -1
- package/dist/components/ui/dialog.d.ts +0 -16
- package/dist/components/ui/dialog.d.ts.map +0 -1
- package/dist/components/ui/dropdown-menu.d.ts +0 -26
- package/dist/components/ui/dropdown-menu.d.ts.map +0 -1
- package/dist/components/ui/hover-card.d.ts +0 -7
- package/dist/components/ui/hover-card.d.ts.map +0 -1
- package/dist/components/ui/input-group.d.ts +0 -17
- package/dist/components/ui/input-group.d.ts.map +0 -1
- package/dist/components/ui/input.d.ts +0 -4
- package/dist/components/ui/input.d.ts.map +0 -1
- package/dist/components/ui/kbd.d.ts +0 -4
- package/dist/components/ui/kbd.d.ts.map +0 -1
- package/dist/components/ui/select.d.ts +0 -16
- package/dist/components/ui/select.d.ts.map +0 -1
- package/dist/components/ui/textarea.d.ts +0 -4
- package/dist/components/ui/textarea.d.ts.map +0 -1
- package/dist/components/ui/tooltip.d.ts +0 -8
- package/dist/components/ui/tooltip.d.ts.map +0 -1
- package/dist/core.css +0 -1
- package/dist/utils/form-generator.d.ts +0 -29
- package/dist/utils/form-generator.d.ts.map +0 -1
- package/dist/utils/secure-param-detector.d.ts +0 -26
- package/dist/utils/secure-param-detector.d.ts.map +0 -1
- package/scripts/cli-agent-inject.ts +0 -205
- package/scripts/cli-agent-wrapper.cjs +0 -51
- package/scripts/cli-agent.ts +0 -483
- package/scripts/cli-create-project.ts +0 -608
- package/scripts/cli-create-wrapper.cjs +0 -60
- package/scripts/cli-init-wizard-wrapper.cjs +0 -58
- package/scripts/cli-init-wizard.ts +0 -646
- package/scripts/cli-prompt-wrapper.cjs +0 -51
- package/scripts/cli-prompt.ts +0 -306
- package/scripts/cli-sync-wrapper.cjs +0 -69
- package/scripts/cli-sync.ts +0 -915
- package/scripts/cli-tools-wrapper.cjs +0 -51
- package/scripts/cli-tools.ts +0 -320
- package/scripts/cli-uninstall-wrapper.cjs +0 -66
- package/scripts/cli-uninstall.ts +0 -173
- package/scripts/config-parser.ts +0 -432
- package/scripts/dashboard-sync.ts +0 -454
- package/scripts/tree-sitter-discover.ts +0 -526
- package/scripts/wasm/tree-sitter-tsx.wasm +0 -0
- package/scripts/wasm/tree-sitter-typescript.wasm +0 -0
package/scripts/cli-sync.ts
DELETED
|
@@ -1,915 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Arcten Sync - Sync tools from codebase to dashboard
|
|
4
|
-
*
|
|
5
|
-
* Usage:
|
|
6
|
-
* arcten sync Sync tools only
|
|
7
|
-
* arcten sync --prompt Also sync .arcten/prompt.md
|
|
8
|
-
* arcten sync --agents Also sync .arcten/agents/*.yaml
|
|
9
|
-
* arcten sync --all Sync everything (tools + prompt + agents)
|
|
10
|
-
* arcten sync --classify Force AI re-classification of all tools
|
|
11
|
-
* arcten sync --yes Auto-confirm (for CI/scripts)
|
|
12
|
-
*
|
|
13
|
-
* Runs:
|
|
14
|
-
* 1. arcten-extract-types (generates .arcten/tool-metadata.ts)
|
|
15
|
-
* 2. Generates .arcten/arcten.tools.ts with imports and arrays
|
|
16
|
-
* 3. Updates .arcten/sync-state.json for diff tracking
|
|
17
|
-
* 4. Syncs to dashboard (functions are READONLY)
|
|
18
|
-
* 5. Optionally syncs prompt and/or agents
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
import * as fs from 'fs';
|
|
22
|
-
import * as path from 'path';
|
|
23
|
-
import * as readline from 'readline';
|
|
24
|
-
import { execSync } from 'child_process';
|
|
25
|
-
|
|
26
|
-
interface ToolMetadata {
|
|
27
|
-
generated: string;
|
|
28
|
-
discoveredFrom: string[];
|
|
29
|
-
functions: Record<string, {
|
|
30
|
-
name: string;
|
|
31
|
-
description?: string;
|
|
32
|
-
parameters: unknown;
|
|
33
|
-
returnType: string;
|
|
34
|
-
isAsync: boolean;
|
|
35
|
-
}>;
|
|
36
|
-
toolOrder: string[];
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
interface SyncState {
|
|
40
|
-
lastSync: string;
|
|
41
|
-
toolsFile: string;
|
|
42
|
-
functions: Record<string, {
|
|
43
|
-
classification: 'safe' | 'sensitive';
|
|
44
|
-
}>;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
interface ClassificationResult {
|
|
48
|
-
source: string;
|
|
49
|
-
classifications: Record<string, 'safe' | 'sensitive'>;
|
|
50
|
-
safe: string[];
|
|
51
|
-
sensitive: string[];
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
interface AgentConfig {
|
|
55
|
-
name: string;
|
|
56
|
-
description?: string;
|
|
57
|
-
isDefault?: boolean;
|
|
58
|
-
toolMode?: 'inherit' | 'custom' | 'additive';
|
|
59
|
-
systemPrompt?: string;
|
|
60
|
-
enabledTools?: string[];
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
interface SyncOptions {
|
|
64
|
-
syncTools: boolean;
|
|
65
|
-
syncPrompt: boolean;
|
|
66
|
-
syncAgents: boolean;
|
|
67
|
-
forceClassify: boolean;
|
|
68
|
-
autoYes: boolean;
|
|
69
|
-
quiet: boolean;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// State
|
|
73
|
-
let rl: readline.Interface;
|
|
74
|
-
let apiKey: string;
|
|
75
|
-
let projectId: string;
|
|
76
|
-
let serverUrl: string;
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Read tool-metadata.ts to get current functions
|
|
80
|
-
*/
|
|
81
|
-
function readToolMetadata(projectRoot: string): ToolMetadata | null {
|
|
82
|
-
const metadataPath = path.join(projectRoot, '.arcten', 'tool-metadata.ts');
|
|
83
|
-
|
|
84
|
-
if (!fs.existsSync(metadataPath)) {
|
|
85
|
-
return null;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const content = fs.readFileSync(metadataPath, 'utf-8');
|
|
89
|
-
|
|
90
|
-
// Extract the object from "export const toolMetadata = { ... } as const;"
|
|
91
|
-
const match = content.match(/export const toolMetadata = ({[\s\S]*}) as const;/);
|
|
92
|
-
if (!match) {
|
|
93
|
-
return null;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
try {
|
|
97
|
-
// Use eval to parse the object (it's generated code, safe to eval)
|
|
98
|
-
const metadata = eval(`(${match[1]})`);
|
|
99
|
-
return metadata as ToolMetadata;
|
|
100
|
-
} catch {
|
|
101
|
-
return null;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Read sync-state.json to get previous state
|
|
107
|
-
*/
|
|
108
|
-
function readSyncState(projectRoot: string): SyncState | null {
|
|
109
|
-
const statePath = path.join(projectRoot, '.arcten', 'sync-state.json');
|
|
110
|
-
|
|
111
|
-
if (!fs.existsSync(statePath)) {
|
|
112
|
-
return null;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
try {
|
|
116
|
-
const content = fs.readFileSync(statePath, 'utf-8');
|
|
117
|
-
const parsed = JSON.parse(content) as SyncState;
|
|
118
|
-
// Validate the structure
|
|
119
|
-
if (!parsed.functions || typeof parsed.functions !== 'object') {
|
|
120
|
-
return null;
|
|
121
|
-
}
|
|
122
|
-
return parsed;
|
|
123
|
-
} catch {
|
|
124
|
-
return null;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Write sync-state.json
|
|
130
|
-
*/
|
|
131
|
-
function writeSyncState(projectRoot: string, state: SyncState): void {
|
|
132
|
-
const arctenDir = path.join(projectRoot, '.arcten');
|
|
133
|
-
if (!fs.existsSync(arctenDir)) {
|
|
134
|
-
fs.mkdirSync(arctenDir, { recursive: true });
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
const statePath = path.join(arctenDir, 'sync-state.json');
|
|
138
|
-
fs.writeFileSync(statePath, JSON.stringify(state, null, 2));
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Generate arcten.tools.ts with imports and arrays
|
|
143
|
-
*/
|
|
144
|
-
function generateToolsFile(
|
|
145
|
-
projectRoot: string,
|
|
146
|
-
toolsFilePath: string,
|
|
147
|
-
safeTools: string[],
|
|
148
|
-
sensitiveTools: string[]
|
|
149
|
-
): void {
|
|
150
|
-
const arctenDir = path.join(projectRoot, '.arcten');
|
|
151
|
-
if (!fs.existsSync(arctenDir)) {
|
|
152
|
-
fs.mkdirSync(arctenDir, { recursive: true });
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Calculate relative import path from .arcten to tools file
|
|
156
|
-
const toolsFileRelative = path.relative(arctenDir, path.join(projectRoot, toolsFilePath));
|
|
157
|
-
const importPath = toolsFileRelative.replace(/\.ts$/, '').replace(/\\/g, '/');
|
|
158
|
-
|
|
159
|
-
const allTools = [...safeTools, ...sensitiveTools];
|
|
160
|
-
|
|
161
|
-
const content = `// .arcten/arcten.tools.ts - AUTO-GENERATED by arcten sync
|
|
162
|
-
// DO NOT EDIT - run \`arcten sync\` to regenerate
|
|
163
|
-
|
|
164
|
-
import { preserveToolName } from '@arcteninc/core';
|
|
165
|
-
import {
|
|
166
|
-
${allTools.map(t => ` ${t} as _${t},`).join('\n')}
|
|
167
|
-
} from '${importPath}';
|
|
168
|
-
|
|
169
|
-
// Wrap tools with preserveToolName to prevent minification from breaking tool name matching
|
|
170
|
-
${allTools.map(t => `const ${t} = preserveToolName(_${t}, '${t}');`).join('\n')}
|
|
171
|
-
|
|
172
|
-
// Safe tools - auto-execute without user approval
|
|
173
|
-
export const safeTools = [
|
|
174
|
-
${safeTools.map(t => ` ${t},`).join('\n')}
|
|
175
|
-
] as const;
|
|
176
|
-
|
|
177
|
-
// Sensitive tools - require user approval before execution
|
|
178
|
-
export const sensitiveTools = [
|
|
179
|
-
${sensitiveTools.map(t => ` ${t},`).join('\n')}
|
|
180
|
-
] as const;
|
|
181
|
-
|
|
182
|
-
// All tools combined
|
|
183
|
-
export const allTools = [...safeTools, ...sensitiveTools];
|
|
184
|
-
|
|
185
|
-
// Tool names for the safeToolNames prop
|
|
186
|
-
export const safeToolNames = [
|
|
187
|
-
${safeTools.map(t => ` '${t}',`).join('\n')}
|
|
188
|
-
];
|
|
189
|
-
|
|
190
|
-
// Type exports
|
|
191
|
-
export type SafeToolName = typeof safeTools[number]['name'];
|
|
192
|
-
export type SensitiveToolName = typeof sensitiveTools[number]['name'];
|
|
193
|
-
export type AllToolName = SafeToolName | SensitiveToolName;
|
|
194
|
-
`;
|
|
195
|
-
|
|
196
|
-
const outputPath = path.join(arctenDir, 'arcten.tools.ts');
|
|
197
|
-
fs.writeFileSync(outputPath, content);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Classify tools using AI or pattern fallback
|
|
202
|
-
*/
|
|
203
|
-
async function classifyTools(
|
|
204
|
-
tools: Array<{ name: string; description?: string }>,
|
|
205
|
-
existingClassifications: Record<string, { classification: 'safe' | 'sensitive' }>
|
|
206
|
-
): Promise<ClassificationResult> {
|
|
207
|
-
// Filter to only new tools (not already classified)
|
|
208
|
-
const newTools = tools.filter(t => !existingClassifications[t.name]);
|
|
209
|
-
|
|
210
|
-
if (newTools.length === 0) {
|
|
211
|
-
// All tools already classified
|
|
212
|
-
const classifications: Record<string, 'safe' | 'sensitive'> = {};
|
|
213
|
-
for (const tool of tools) {
|
|
214
|
-
classifications[tool.name] = existingClassifications[tool.name]?.classification || 'sensitive';
|
|
215
|
-
}
|
|
216
|
-
return {
|
|
217
|
-
source: 'existing',
|
|
218
|
-
classifications,
|
|
219
|
-
safe: tools.filter(t => classifications[t.name] === 'safe').map(t => t.name),
|
|
220
|
-
sensitive: tools.filter(t => classifications[t.name] === 'sensitive').map(t => t.name),
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
// Try AI classification for new tools
|
|
225
|
-
try {
|
|
226
|
-
const response = await fetch(`${serverUrl}/ai-init/classify`, {
|
|
227
|
-
method: 'POST',
|
|
228
|
-
headers: {
|
|
229
|
-
'Content-Type': 'application/json',
|
|
230
|
-
'x-arcten-api-key': apiKey,
|
|
231
|
-
},
|
|
232
|
-
body: JSON.stringify({
|
|
233
|
-
tools: newTools.map(t => ({ name: t.name, jsDoc: t.description })),
|
|
234
|
-
}),
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
if (response.ok) {
|
|
238
|
-
const aiResult = await response.json() as ClassificationResult;
|
|
239
|
-
|
|
240
|
-
// Merge with existing classifications
|
|
241
|
-
const mergedClassifications: Record<string, 'safe' | 'sensitive'> = {};
|
|
242
|
-
for (const tool of tools) {
|
|
243
|
-
if (existingClassifications[tool.name]) {
|
|
244
|
-
mergedClassifications[tool.name] = existingClassifications[tool.name].classification;
|
|
245
|
-
} else {
|
|
246
|
-
mergedClassifications[tool.name] = aiResult.classifications[tool.name] || 'sensitive';
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
return {
|
|
251
|
-
source: 'ai',
|
|
252
|
-
classifications: mergedClassifications,
|
|
253
|
-
safe: tools.filter(t => mergedClassifications[t.name] === 'safe').map(t => t.name),
|
|
254
|
-
sensitive: tools.filter(t => mergedClassifications[t.name] === 'sensitive').map(t => t.name),
|
|
255
|
-
};
|
|
256
|
-
}
|
|
257
|
-
} catch {
|
|
258
|
-
// Fall through to pattern fallback
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
// Pattern-based fallback
|
|
262
|
-
const safePatterns = /^(get|list|search|find|fetch|load|calculate|count)/i;
|
|
263
|
-
const sensitivePatterns = /^(create|update|delete|set|add|remove|regenerate)/i;
|
|
264
|
-
const sensitiveReads = /^(get|fetch).*(api.?key|credential|secret|password|token)/i;
|
|
265
|
-
|
|
266
|
-
const classifications: Record<string, 'safe' | 'sensitive'> = {};
|
|
267
|
-
|
|
268
|
-
for (const tool of tools) {
|
|
269
|
-
if (existingClassifications[tool.name]) {
|
|
270
|
-
classifications[tool.name] = existingClassifications[tool.name].classification;
|
|
271
|
-
} else if (sensitiveReads.test(tool.name)) {
|
|
272
|
-
classifications[tool.name] = 'sensitive';
|
|
273
|
-
} else if (sensitivePatterns.test(tool.name)) {
|
|
274
|
-
classifications[tool.name] = 'sensitive';
|
|
275
|
-
} else if (safePatterns.test(tool.name)) {
|
|
276
|
-
classifications[tool.name] = 'safe';
|
|
277
|
-
} else {
|
|
278
|
-
classifications[tool.name] = 'sensitive'; // Default to sensitive
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
return {
|
|
283
|
-
source: 'pattern-fallback',
|
|
284
|
-
classifications,
|
|
285
|
-
safe: tools.filter(t => classifications[t.name] === 'safe').map(t => t.name),
|
|
286
|
-
sensitive: tools.filter(t => classifications[t.name] === 'sensitive').map(t => t.name),
|
|
287
|
-
};
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
/**
|
|
291
|
-
* Sync to dashboard
|
|
292
|
-
*/
|
|
293
|
-
async function syncToDashboard(
|
|
294
|
-
tools: Array<{ name: string; description?: string; requiresApproval: boolean }>
|
|
295
|
-
): Promise<{ success: boolean; error?: string }> {
|
|
296
|
-
try {
|
|
297
|
-
// Get JWT token
|
|
298
|
-
const tokenResponse = await fetch(`${serverUrl}/token`, {
|
|
299
|
-
method: 'POST',
|
|
300
|
-
headers: { 'Content-Type': 'application/json' },
|
|
301
|
-
body: JSON.stringify({ apiKey }),
|
|
302
|
-
});
|
|
303
|
-
|
|
304
|
-
if (!tokenResponse.ok) {
|
|
305
|
-
return { success: false, error: 'Failed to authenticate' };
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
const { clientToken: token } = await tokenResponse.json();
|
|
309
|
-
|
|
310
|
-
// Format tools for sync
|
|
311
|
-
const toolsData = tools.map(tool => ({
|
|
312
|
-
name: tool.name,
|
|
313
|
-
description: tool.description || `Function: ${tool.name}`,
|
|
314
|
-
signature: JSON.stringify({}),
|
|
315
|
-
isEnabled: true,
|
|
316
|
-
isOverridable: true,
|
|
317
|
-
requiresApproval: tool.requiresApproval,
|
|
318
|
-
sensitiveParams: [],
|
|
319
|
-
readonly: true, // Functions are readonly in dashboard
|
|
320
|
-
syncedAt: Date.now(),
|
|
321
|
-
}));
|
|
322
|
-
|
|
323
|
-
// Sync to dashboard
|
|
324
|
-
const syncResponse = await fetch(`${serverUrl}/tools/sync`, {
|
|
325
|
-
method: 'POST',
|
|
326
|
-
headers: {
|
|
327
|
-
'Content-Type': 'application/json',
|
|
328
|
-
'Authorization': `Bearer ${token}`,
|
|
329
|
-
},
|
|
330
|
-
body: JSON.stringify({
|
|
331
|
-
projectId,
|
|
332
|
-
tools: toolsData,
|
|
333
|
-
}),
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
if (!syncResponse.ok) {
|
|
337
|
-
const error = await syncResponse.text();
|
|
338
|
-
return { success: false, error: `Sync failed: ${error}` };
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
return { success: true };
|
|
342
|
-
} catch (error: any) {
|
|
343
|
-
return { success: false, error: error.message };
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
/**
|
|
348
|
-
* Sync system prompt to dashboard
|
|
349
|
-
*/
|
|
350
|
-
async function syncPromptToDashboard(
|
|
351
|
-
projectRoot: string
|
|
352
|
-
): Promise<{ success: boolean; error?: string }> {
|
|
353
|
-
const promptPath = path.join(projectRoot, '.arcten', 'prompt.md');
|
|
354
|
-
|
|
355
|
-
if (!fs.existsSync(promptPath)) {
|
|
356
|
-
return { success: false, error: 'No .arcten/prompt.md found. Create one with `arcten prompt`.' };
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
const systemPrompt = fs.readFileSync(promptPath, 'utf-8');
|
|
360
|
-
|
|
361
|
-
try {
|
|
362
|
-
// Get JWT token
|
|
363
|
-
const tokenResponse = await fetch(`${serverUrl}/token`, {
|
|
364
|
-
method: 'POST',
|
|
365
|
-
headers: { 'Content-Type': 'application/json' },
|
|
366
|
-
body: JSON.stringify({ apiKey }),
|
|
367
|
-
});
|
|
368
|
-
|
|
369
|
-
if (!tokenResponse.ok) {
|
|
370
|
-
return { success: false, error: 'Failed to authenticate' };
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
const { clientToken: token } = await tokenResponse.json();
|
|
374
|
-
|
|
375
|
-
// Sync prompt
|
|
376
|
-
const syncResponse = await fetch(`${serverUrl}/prompt/sync`, {
|
|
377
|
-
method: 'POST',
|
|
378
|
-
headers: {
|
|
379
|
-
'Content-Type': 'application/json',
|
|
380
|
-
Authorization: `Bearer ${token}`,
|
|
381
|
-
},
|
|
382
|
-
body: JSON.stringify({
|
|
383
|
-
projectId,
|
|
384
|
-
systemPrompt,
|
|
385
|
-
}),
|
|
386
|
-
});
|
|
387
|
-
|
|
388
|
-
if (!syncResponse.ok) {
|
|
389
|
-
const error = await syncResponse.text();
|
|
390
|
-
return { success: false, error: `Prompt sync failed: ${error}` };
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
return { success: true };
|
|
394
|
-
} catch (error: any) {
|
|
395
|
-
return { success: false, error: error.message };
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
/**
|
|
400
|
-
* Parse simple YAML agent config
|
|
401
|
-
*/
|
|
402
|
-
function parseAgentYaml(content: string): AgentConfig {
|
|
403
|
-
const config: AgentConfig = { name: '' };
|
|
404
|
-
const lines = content.split('\n');
|
|
405
|
-
|
|
406
|
-
let inSystemPrompt = false;
|
|
407
|
-
let inEnabledTools = false;
|
|
408
|
-
let systemPromptLines: string[] = [];
|
|
409
|
-
let enabledTools: string[] = [];
|
|
410
|
-
|
|
411
|
-
for (const line of lines) {
|
|
412
|
-
if (inSystemPrompt) {
|
|
413
|
-
if (line.match(/^[a-zA-Z]/) || line.match(/^#/)) {
|
|
414
|
-
inSystemPrompt = false;
|
|
415
|
-
config.systemPrompt = systemPromptLines.join('\n').trim();
|
|
416
|
-
} else {
|
|
417
|
-
systemPromptLines.push(line.replace(/^ /, ''));
|
|
418
|
-
continue;
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
if (inEnabledTools) {
|
|
423
|
-
if (line.match(/^\s*-\s+/)) {
|
|
424
|
-
const tool = line.replace(/^\s*-\s+/, '').trim();
|
|
425
|
-
if (tool && !tool.startsWith('#')) {
|
|
426
|
-
enabledTools.push(tool);
|
|
427
|
-
}
|
|
428
|
-
continue;
|
|
429
|
-
} else if (!line.match(/^\s*#/) && line.trim()) {
|
|
430
|
-
inEnabledTools = false;
|
|
431
|
-
config.enabledTools = enabledTools;
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
if (line.trim().startsWith('#')) continue;
|
|
436
|
-
|
|
437
|
-
const match = line.match(/^(\w+):\s*(.*)$/);
|
|
438
|
-
if (match) {
|
|
439
|
-
const [, key, value] = match;
|
|
440
|
-
|
|
441
|
-
if (key === 'systemPrompt' && value.includes('|')) {
|
|
442
|
-
inSystemPrompt = true;
|
|
443
|
-
systemPromptLines = [];
|
|
444
|
-
continue;
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
if (key === 'enabledTools' && !value.trim()) {
|
|
448
|
-
inEnabledTools = true;
|
|
449
|
-
enabledTools = [];
|
|
450
|
-
continue;
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
switch (key) {
|
|
454
|
-
case 'name':
|
|
455
|
-
config.name = value.trim();
|
|
456
|
-
break;
|
|
457
|
-
case 'description':
|
|
458
|
-
config.description = value.trim();
|
|
459
|
-
break;
|
|
460
|
-
case 'isDefault':
|
|
461
|
-
config.isDefault = value.trim().toLowerCase() === 'true';
|
|
462
|
-
break;
|
|
463
|
-
case 'toolMode':
|
|
464
|
-
config.toolMode = value.trim() as 'inherit' | 'custom' | 'additive';
|
|
465
|
-
break;
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
if (inSystemPrompt) {
|
|
471
|
-
config.systemPrompt = systemPromptLines.join('\n').trim();
|
|
472
|
-
}
|
|
473
|
-
if (inEnabledTools && enabledTools.length > 0) {
|
|
474
|
-
config.enabledTools = enabledTools;
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
return config;
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
/**
|
|
481
|
-
* Sync agents to dashboard
|
|
482
|
-
*/
|
|
483
|
-
async function syncAgentsToDashboard(
|
|
484
|
-
projectRoot: string
|
|
485
|
-
): Promise<{ success: boolean; agents: string[]; error?: string }> {
|
|
486
|
-
const agentsDir = path.join(projectRoot, '.arcten', 'agents');
|
|
487
|
-
|
|
488
|
-
if (!fs.existsSync(agentsDir)) {
|
|
489
|
-
return { success: true, agents: [] };
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
const agentFiles = fs.readdirSync(agentsDir)
|
|
493
|
-
.filter(f => f.endsWith('.yaml') || f.endsWith('.yml'));
|
|
494
|
-
|
|
495
|
-
if (agentFiles.length === 0) {
|
|
496
|
-
return { success: true, agents: [] };
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
const agents: AgentConfig[] = [];
|
|
500
|
-
for (const file of agentFiles) {
|
|
501
|
-
const content = fs.readFileSync(path.join(agentsDir, file), 'utf-8');
|
|
502
|
-
const config = parseAgentYaml(content);
|
|
503
|
-
if (config.name) {
|
|
504
|
-
agents.push(config);
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
try {
|
|
509
|
-
// Get JWT token
|
|
510
|
-
const tokenResponse = await fetch(`${serverUrl}/token`, {
|
|
511
|
-
method: 'POST',
|
|
512
|
-
headers: { 'Content-Type': 'application/json' },
|
|
513
|
-
body: JSON.stringify({ apiKey }),
|
|
514
|
-
});
|
|
515
|
-
|
|
516
|
-
if (!tokenResponse.ok) {
|
|
517
|
-
return { success: false, agents: [], error: 'Failed to authenticate' };
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
const { clientToken: token } = await tokenResponse.json();
|
|
521
|
-
|
|
522
|
-
// Sync agents
|
|
523
|
-
const syncResponse = await fetch(`${serverUrl}/agents/sync`, {
|
|
524
|
-
method: 'POST',
|
|
525
|
-
headers: {
|
|
526
|
-
'Content-Type': 'application/json',
|
|
527
|
-
Authorization: `Bearer ${token}`,
|
|
528
|
-
},
|
|
529
|
-
body: JSON.stringify({
|
|
530
|
-
projectId,
|
|
531
|
-
agents: agents.map(a => ({
|
|
532
|
-
name: a.name,
|
|
533
|
-
description: a.description || '',
|
|
534
|
-
isDefault: a.isDefault || false,
|
|
535
|
-
toolMode: a.toolMode || 'inherit',
|
|
536
|
-
systemPrompt: a.systemPrompt || '',
|
|
537
|
-
enabledTools: a.enabledTools || [],
|
|
538
|
-
})),
|
|
539
|
-
}),
|
|
540
|
-
});
|
|
541
|
-
|
|
542
|
-
if (!syncResponse.ok) {
|
|
543
|
-
const error = await syncResponse.text();
|
|
544
|
-
return { success: false, agents: agents.map(a => a.name), error: `Agent sync failed: ${error}` };
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
return { success: true, agents: agents.map(a => a.name) };
|
|
548
|
-
} catch (error: any) {
|
|
549
|
-
return { success: false, agents: agents.map(a => a.name), error: error.message };
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
/**
|
|
554
|
-
* Check for API key
|
|
555
|
-
*/
|
|
556
|
-
function checkApiKey(): { apiKey: string; projectId: string } | null {
|
|
557
|
-
// First check environment variable (for CI/Vercel builds)
|
|
558
|
-
const envKey = process.env.ARCTEN_API_KEY;
|
|
559
|
-
if (envKey) {
|
|
560
|
-
const projectIdMatch = envKey.match(/sk_(proj_[a-zA-Z0-9]+)_/);
|
|
561
|
-
if (projectIdMatch) {
|
|
562
|
-
return { apiKey: envKey, projectId: projectIdMatch[1] };
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
// Fall back to .env files for local development
|
|
567
|
-
const envFiles = ['.env.local', '.env'];
|
|
568
|
-
|
|
569
|
-
for (const envFile of envFiles) {
|
|
570
|
-
const envPath = path.join(process.cwd(), envFile);
|
|
571
|
-
if (fs.existsSync(envPath)) {
|
|
572
|
-
const envContent = fs.readFileSync(envPath, 'utf-8');
|
|
573
|
-
const match = envContent.match(/ARCTEN_API_KEY=([^\s\n]+)/);
|
|
574
|
-
if (match) {
|
|
575
|
-
const key = match[1];
|
|
576
|
-
const projectIdMatch = key.match(/sk_(proj_[a-zA-Z0-9]+)_/);
|
|
577
|
-
if (projectIdMatch) {
|
|
578
|
-
return { apiKey: key, projectId: projectIdMatch[1] };
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
return null;
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
/**
|
|
588
|
-
* Ask user a yes/no question
|
|
589
|
-
*/
|
|
590
|
-
function askYesNo(question: string): Promise<boolean> {
|
|
591
|
-
return new Promise((resolve) => {
|
|
592
|
-
rl.question(`${question} (y/n) `, (answer) => {
|
|
593
|
-
resolve(answer.trim().toLowerCase().startsWith('y'));
|
|
594
|
-
});
|
|
595
|
-
});
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
/**
|
|
599
|
-
* Parse command line options
|
|
600
|
-
*/
|
|
601
|
-
function parseOptions(args: string[]): SyncOptions {
|
|
602
|
-
const autoYes = args.includes('--yes') || args.includes('-y');
|
|
603
|
-
const syncAll = args.includes('--all');
|
|
604
|
-
const syncPrompt = syncAll || args.includes('--prompt');
|
|
605
|
-
const syncAgents = syncAll || args.includes('--agents');
|
|
606
|
-
const forceClassify = args.includes('--classify');
|
|
607
|
-
|
|
608
|
-
return {
|
|
609
|
-
syncTools: true, // Always sync tools
|
|
610
|
-
syncPrompt,
|
|
611
|
-
syncAgents,
|
|
612
|
-
forceClassify,
|
|
613
|
-
autoYes,
|
|
614
|
-
quiet: autoYes,
|
|
615
|
-
};
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
/**
|
|
619
|
-
* Main sync function
|
|
620
|
-
*/
|
|
621
|
-
async function main() {
|
|
622
|
-
const projectRoot = process.cwd();
|
|
623
|
-
const args = process.argv.slice(2);
|
|
624
|
-
const options = parseOptions(args);
|
|
625
|
-
|
|
626
|
-
if (!options.quiet) {
|
|
627
|
-
console.log('');
|
|
628
|
-
console.log('Arcten Sync');
|
|
629
|
-
if (options.syncPrompt || options.syncAgents) {
|
|
630
|
-
const extras = [];
|
|
631
|
-
if (options.syncPrompt) extras.push('prompt');
|
|
632
|
-
if (options.syncAgents) extras.push('agents');
|
|
633
|
-
console.log(` (including: ${extras.join(', ')})`);
|
|
634
|
-
}
|
|
635
|
-
console.log('');
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
// Check for API key
|
|
639
|
-
const auth = checkApiKey();
|
|
640
|
-
if (!auth) {
|
|
641
|
-
if (!options.quiet) {
|
|
642
|
-
console.log('No API key found. Run `arcten init` first.');
|
|
643
|
-
}
|
|
644
|
-
process.exit(1);
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
apiKey = auth.apiKey;
|
|
648
|
-
projectId = auth.projectId;
|
|
649
|
-
serverUrl = process.env.ARCTEN_SERVER_URL || 'https://api.arcten.com';
|
|
650
|
-
|
|
651
|
-
// Create readline interface (only if interactive)
|
|
652
|
-
if (!options.autoYes) {
|
|
653
|
-
rl = readline.createInterface({
|
|
654
|
-
input: process.stdin,
|
|
655
|
-
output: process.stdout,
|
|
656
|
-
});
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
try {
|
|
660
|
-
// Step 1: Run arcten-extract-types to update tool-metadata.ts
|
|
661
|
-
if (!options.quiet) console.log('Extracting tool types...');
|
|
662
|
-
// Get script directory (ESM compatible)
|
|
663
|
-
const scriptDir = path.dirname(new URL(import.meta.url).pathname).replace(/^\/([A-Z]:)/, '$1');
|
|
664
|
-
|
|
665
|
-
try {
|
|
666
|
-
// Read config to get tool file path
|
|
667
|
-
const configPath = path.join(projectRoot, '.arcten', 'config.ts');
|
|
668
|
-
let toolsArg = '';
|
|
669
|
-
if (fs.existsSync(configPath)) {
|
|
670
|
-
const configContent = fs.readFileSync(configPath, 'utf-8');
|
|
671
|
-
const toolFileMatch = configContent.match(/toolFile:\s*["']([^"']+)["']/);
|
|
672
|
-
if (toolFileMatch) {
|
|
673
|
-
toolsArg = ` --tools "${toolFileMatch[1]}"`;
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
// Try running the wrapper script directly first
|
|
678
|
-
const extractScript = path.join(scriptDir, 'cli-extract-types-auto-wrapper.js');
|
|
679
|
-
if (fs.existsSync(extractScript)) {
|
|
680
|
-
execSync(`node "${extractScript}"${toolsArg}`, {
|
|
681
|
-
cwd: projectRoot,
|
|
682
|
-
stdio: options.quiet ? 'pipe' : ['inherit', 'pipe', 'pipe'],
|
|
683
|
-
});
|
|
684
|
-
if (!options.quiet) console.log(' Done');
|
|
685
|
-
} else {
|
|
686
|
-
// Fall back to npx
|
|
687
|
-
execSync(`npx arcten-extract-types${toolsArg}`, {
|
|
688
|
-
cwd: projectRoot,
|
|
689
|
-
stdio: options.quiet ? 'pipe' : ['inherit', 'pipe', 'pipe'],
|
|
690
|
-
});
|
|
691
|
-
if (!options.quiet) console.log(' Done');
|
|
692
|
-
}
|
|
693
|
-
} catch (error: any) {
|
|
694
|
-
if (!options.quiet) console.log(' Warning: Could not run extract-types, continuing with existing metadata...');
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
// Step 2: Read tool-metadata.ts
|
|
698
|
-
if (!options.quiet) console.log('Reading tool metadata...');
|
|
699
|
-
const metadata = readToolMetadata(projectRoot);
|
|
700
|
-
|
|
701
|
-
if (!metadata) {
|
|
702
|
-
if (!options.quiet) {
|
|
703
|
-
console.log('');
|
|
704
|
-
console.log('No tool-metadata.ts found.');
|
|
705
|
-
console.log('Make sure you have a tools file (e.g., app/tools.ts) with exported functions.');
|
|
706
|
-
console.log('');
|
|
707
|
-
}
|
|
708
|
-
if (rl) rl.close();
|
|
709
|
-
process.exit(1);
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
const currentFunctions = Object.keys(metadata.functions);
|
|
713
|
-
const toolsFile = metadata.discoveredFrom[0] || 'app/tools.ts';
|
|
714
|
-
|
|
715
|
-
if (!options.quiet) console.log(`Found ${currentFunctions.length} functions from ${toolsFile}`);
|
|
716
|
-
|
|
717
|
-
// Step 2: Read previous sync state
|
|
718
|
-
const previousState = readSyncState(projectRoot);
|
|
719
|
-
const previousFunctions = previousState
|
|
720
|
-
? Object.keys(previousState.functions)
|
|
721
|
-
: [];
|
|
722
|
-
|
|
723
|
-
// Step 3: Compute diff
|
|
724
|
-
const newFunctions = currentFunctions.filter(f => !previousFunctions.includes(f));
|
|
725
|
-
const removedFunctions = previousFunctions.filter(f => !currentFunctions.includes(f));
|
|
726
|
-
|
|
727
|
-
// Always regenerate arcten.tools.ts to pick up any classification changes in sync-state.json
|
|
728
|
-
// Only skip dashboard sync if truly no changes
|
|
729
|
-
const hasChanges = newFunctions.length > 0 || removedFunctions.length > 0;
|
|
730
|
-
|
|
731
|
-
if (!hasChanges && previousState && !options.forceClassify) {
|
|
732
|
-
if (!options.autoYes) {
|
|
733
|
-
console.log('');
|
|
734
|
-
console.log('No function changes detected since last sync.');
|
|
735
|
-
console.log('(Will still regenerate arcten.tools.ts to apply any classification changes)');
|
|
736
|
-
}
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
// Show changes if any
|
|
740
|
-
if (newFunctions.length > 0) {
|
|
741
|
-
console.log('');
|
|
742
|
-
console.log(`New functions since last sync:`);
|
|
743
|
-
for (const fn of newFunctions) {
|
|
744
|
-
console.log(` + ${fn}`);
|
|
745
|
-
}
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
if (removedFunctions.length > 0) {
|
|
749
|
-
console.log('');
|
|
750
|
-
console.log(`Removed functions:`);
|
|
751
|
-
for (const fn of removedFunctions) {
|
|
752
|
-
console.log(` - ${fn}`);
|
|
753
|
-
}
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
// Step 4: Classify tools (AI for new, preserve existing unless --classify)
|
|
757
|
-
if (!options.quiet) {
|
|
758
|
-
console.log('');
|
|
759
|
-
console.log('Classifying tools...');
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
// If forceClassify, clear existing classifications to force re-classification
|
|
763
|
-
const existingClassifications = options.forceClassify ? {} : (previousState?.functions || {});
|
|
764
|
-
const toolsToClassify = currentFunctions.map(name => ({
|
|
765
|
-
name,
|
|
766
|
-
description: metadata.functions[name]?.description,
|
|
767
|
-
}));
|
|
768
|
-
|
|
769
|
-
const classification = await classifyTools(toolsToClassify, existingClassifications);
|
|
770
|
-
|
|
771
|
-
if (!options.quiet) {
|
|
772
|
-
console.log('');
|
|
773
|
-
console.log(`Classification (${classification.source}${options.forceClassify ? ', forced' : ''}):`);
|
|
774
|
-
console.log(` Safe (auto-execute): ${classification.safe.length} tools`);
|
|
775
|
-
if (classification.safe.length > 0 && classification.safe.length <= 10) {
|
|
776
|
-
console.log(` ${classification.safe.join(', ')}`);
|
|
777
|
-
}
|
|
778
|
-
console.log(` Sensitive (needs approval): ${classification.sensitive.length} tools`);
|
|
779
|
-
if (classification.sensitive.length > 0 && classification.sensitive.length <= 10) {
|
|
780
|
-
console.log(` ${classification.sensitive.join(', ')}`);
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
// Step 5: Confirm with user (skip if auto-yes or no new classifications needed)
|
|
785
|
-
const needsNewClassification = newFunctions.length > 0 || options.forceClassify;
|
|
786
|
-
if (!options.autoYes && needsNewClassification) {
|
|
787
|
-
console.log('');
|
|
788
|
-
const proceed = await askYesNo('Does this look right?');
|
|
789
|
-
|
|
790
|
-
if (!proceed) {
|
|
791
|
-
console.log('');
|
|
792
|
-
console.log('You can adjust classifications in .arcten/sync-state.json and re-run sync.');
|
|
793
|
-
if (rl) rl.close();
|
|
794
|
-
process.exit(0);
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
// Step 6: Generate arcten.tools.ts
|
|
799
|
-
if (!options.quiet) {
|
|
800
|
-
console.log('');
|
|
801
|
-
console.log('Generating .arcten/arcten.tools.ts...');
|
|
802
|
-
}
|
|
803
|
-
generateToolsFile(projectRoot, toolsFile.replace(/\\/g, '/'), classification.safe, classification.sensitive);
|
|
804
|
-
if (!options.quiet) console.log(' Created .arcten/arcten.tools.ts');
|
|
805
|
-
|
|
806
|
-
// Step 7: Update sync-state.json
|
|
807
|
-
const newState: SyncState = {
|
|
808
|
-
lastSync: new Date().toISOString(),
|
|
809
|
-
toolsFile,
|
|
810
|
-
functions: {},
|
|
811
|
-
};
|
|
812
|
-
for (const name of currentFunctions) {
|
|
813
|
-
newState.functions[name] = {
|
|
814
|
-
classification: classification.classifications[name],
|
|
815
|
-
};
|
|
816
|
-
}
|
|
817
|
-
writeSyncState(projectRoot, newState);
|
|
818
|
-
if (!options.quiet) console.log(' Updated .arcten/sync-state.json');
|
|
819
|
-
|
|
820
|
-
// Step 8: Sync tools to dashboard (skip logging in quiet mode unless there's an error)
|
|
821
|
-
if (!options.quiet) {
|
|
822
|
-
console.log('');
|
|
823
|
-
console.log('Syncing tools to dashboard...');
|
|
824
|
-
}
|
|
825
|
-
|
|
826
|
-
const toolsForDashboard = currentFunctions.map(name => ({
|
|
827
|
-
name,
|
|
828
|
-
description: metadata.functions[name]?.description,
|
|
829
|
-
requiresApproval: classification.classifications[name] === 'sensitive',
|
|
830
|
-
}));
|
|
831
|
-
|
|
832
|
-
const syncResult = await syncToDashboard(toolsForDashboard);
|
|
833
|
-
|
|
834
|
-
if (syncResult.success) {
|
|
835
|
-
if (!options.quiet) console.log(` Synced ${toolsForDashboard.length} tools to dashboard`);
|
|
836
|
-
} else {
|
|
837
|
-
// Always show dashboard errors
|
|
838
|
-
console.log(` Warning: Dashboard sync failed: ${syncResult.error}`);
|
|
839
|
-
if (!options.quiet) console.log(' Local files were still updated.');
|
|
840
|
-
}
|
|
841
|
-
|
|
842
|
-
// Step 9: Sync prompt if requested
|
|
843
|
-
if (options.syncPrompt) {
|
|
844
|
-
if (!options.quiet) {
|
|
845
|
-
console.log('');
|
|
846
|
-
console.log('Syncing system prompt...');
|
|
847
|
-
}
|
|
848
|
-
|
|
849
|
-
const promptResult = await syncPromptToDashboard(projectRoot);
|
|
850
|
-
if (promptResult.success) {
|
|
851
|
-
if (!options.quiet) console.log(' Synced .arcten/prompt.md to dashboard');
|
|
852
|
-
} else {
|
|
853
|
-
console.log(` Warning: ${promptResult.error}`);
|
|
854
|
-
}
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
// Step 10: Sync agents if requested
|
|
858
|
-
if (options.syncAgents) {
|
|
859
|
-
if (!options.quiet) {
|
|
860
|
-
console.log('');
|
|
861
|
-
console.log('Syncing agents...');
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
const agentsResult = await syncAgentsToDashboard(projectRoot);
|
|
865
|
-
if (agentsResult.success) {
|
|
866
|
-
if (agentsResult.agents.length > 0) {
|
|
867
|
-
if (!options.quiet) console.log(` Synced ${agentsResult.agents.length} agents: ${agentsResult.agents.join(', ')}`);
|
|
868
|
-
} else {
|
|
869
|
-
if (!options.quiet) console.log(' No agents found in .arcten/agents/');
|
|
870
|
-
}
|
|
871
|
-
} else {
|
|
872
|
-
console.log(` Warning: ${agentsResult.error}`);
|
|
873
|
-
}
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
if (!options.quiet) {
|
|
877
|
-
console.log('');
|
|
878
|
-
console.log('Sync complete!');
|
|
879
|
-
console.log('');
|
|
880
|
-
console.log('Usage in your components:');
|
|
881
|
-
console.log('');
|
|
882
|
-
console.log(' import { allTools, safeToolNames } from "./.arcten/arcten.tools";');
|
|
883
|
-
console.log('');
|
|
884
|
-
console.log(' <ArctenAgent');
|
|
885
|
-
console.log(' tools={allTools}');
|
|
886
|
-
console.log(' safeToolNames={safeToolNames}');
|
|
887
|
-
console.log(' />');
|
|
888
|
-
console.log('');
|
|
889
|
-
if (!options.syncPrompt && !options.syncAgents) {
|
|
890
|
-
console.log('To sync prompt and agents, use:');
|
|
891
|
-
console.log(' arcten sync --all');
|
|
892
|
-
console.log('');
|
|
893
|
-
}
|
|
894
|
-
} else {
|
|
895
|
-
// Brief message when there were changes in quiet mode
|
|
896
|
-
if (newFunctions.length > 0 || removedFunctions.length > 0) {
|
|
897
|
-
console.log(`Synced ${newFunctions.length} new, ${removedFunctions.length} removed tools`);
|
|
898
|
-
}
|
|
899
|
-
}
|
|
900
|
-
|
|
901
|
-
} catch (error: any) {
|
|
902
|
-
console.error('Error:', error.message);
|
|
903
|
-
process.exit(1);
|
|
904
|
-
} finally {
|
|
905
|
-
if (rl) rl.close();
|
|
906
|
-
}
|
|
907
|
-
}
|
|
908
|
-
|
|
909
|
-
// Run
|
|
910
|
-
main().catch((error) => {
|
|
911
|
-
console.error('Fatal error:', error);
|
|
912
|
-
process.exit(1);
|
|
913
|
-
});
|
|
914
|
-
|
|
915
|
-
export { main };
|