cyrus-ai 0.1.3 ā 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -0
- package/app.mjs +72 -50
- package/package.json +6 -5
package/README.md
ADDED
package/app.mjs
CHANGED
|
@@ -10,8 +10,28 @@ import { URL } from 'url'
|
|
|
10
10
|
import open from 'open'
|
|
11
11
|
import readline from 'readline'
|
|
12
12
|
|
|
13
|
-
//
|
|
14
|
-
|
|
13
|
+
// Parse command line arguments
|
|
14
|
+
const args = process.argv.slice(2)
|
|
15
|
+
const envFileArg = args.find(arg => arg.startsWith('--env-file='))
|
|
16
|
+
|
|
17
|
+
// Handle --version argument
|
|
18
|
+
if (args.includes('--version')) {
|
|
19
|
+
try {
|
|
20
|
+
const pkg = JSON.parse(readFileSync('./package.json', 'utf-8'))
|
|
21
|
+
console.log(pkg.version)
|
|
22
|
+
} catch {
|
|
23
|
+
console.log('0.1.3') // fallback version
|
|
24
|
+
}
|
|
25
|
+
process.exit(0)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Load environment variables only if --env-file is specified
|
|
29
|
+
if (envFileArg) {
|
|
30
|
+
const envFile = envFileArg.split('=')[1]
|
|
31
|
+
dotenv.config({ path: envFile })
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
15
35
|
|
|
16
36
|
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
17
37
|
|
|
@@ -27,32 +47,32 @@ class EdgeApp {
|
|
|
27
47
|
|
|
28
48
|
/**
|
|
29
49
|
* Load edge configuration (credentials and repositories)
|
|
50
|
+
* Note: Strips promptTemplatePath from all repositories to ensure built-in template is used
|
|
30
51
|
*/
|
|
31
52
|
loadEdgeConfig() {
|
|
32
53
|
const edgeConfigPath = './.edge-config.json'
|
|
54
|
+
let config = { repositories: [] }
|
|
55
|
+
|
|
33
56
|
if (existsSync(edgeConfigPath)) {
|
|
34
57
|
try {
|
|
35
|
-
|
|
58
|
+
config = JSON.parse(readFileSync(edgeConfigPath, 'utf-8'))
|
|
36
59
|
} catch (e) {
|
|
37
60
|
console.error('Failed to load edge config:', e.message)
|
|
38
61
|
}
|
|
39
62
|
}
|
|
40
63
|
|
|
41
|
-
//
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
} catch (error) {
|
|
52
|
-
// No config file found
|
|
64
|
+
// Strip promptTemplatePath from all repositories to ensure built-in template is used
|
|
65
|
+
if (config.repositories) {
|
|
66
|
+
config.repositories = config.repositories.map(repo => {
|
|
67
|
+
const { promptTemplatePath, ...repoWithoutTemplate } = repo
|
|
68
|
+
if (promptTemplatePath) {
|
|
69
|
+
console.log(`Ignoring custom prompt template for repository: ${repo.name} (using built-in template)`)
|
|
70
|
+
}
|
|
71
|
+
return repoWithoutTemplate
|
|
72
|
+
})
|
|
53
73
|
}
|
|
54
74
|
|
|
55
|
-
return
|
|
75
|
+
return config
|
|
56
76
|
}
|
|
57
77
|
|
|
58
78
|
/**
|
|
@@ -85,9 +105,16 @@ class EdgeApp {
|
|
|
85
105
|
const baseBranch = await question('Base branch (default: main): ') || 'main'
|
|
86
106
|
const workspaceBaseDir = await question(`Workspace directory (default: ${repositoryPath}/workspaces): `) || `${repositoryPath}/workspaces`
|
|
87
107
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
108
|
+
// Note: Prompt template is now hardcoded - no longer configurable
|
|
109
|
+
|
|
110
|
+
// Ask for MCP configuration
|
|
111
|
+
console.log('\nš§ MCP (Model Context Protocol) Configuration')
|
|
112
|
+
console.log('MCP allows Claude to access external tools and data sources.')
|
|
113
|
+
console.log('Examples: filesystem access, database connections, API integrations')
|
|
114
|
+
console.log('See: https://docs.anthropic.com/en/docs/claude-code/mcp')
|
|
115
|
+
console.log('')
|
|
116
|
+
const mcpConfigInput = await question('MCP config file path (optional, e.g., ./mcp-config.json): ')
|
|
117
|
+
const mcpConfigPath = mcpConfigInput.trim() || undefined
|
|
91
118
|
|
|
92
119
|
// Ask for allowed tools configuration
|
|
93
120
|
console.log('\nš§ Tool Configuration')
|
|
@@ -116,8 +143,8 @@ class EdgeApp {
|
|
|
116
143
|
linearToken: linearCredentials.linearToken,
|
|
117
144
|
workspaceBaseDir: resolve(workspaceBaseDir),
|
|
118
145
|
isActive: true,
|
|
119
|
-
...(
|
|
120
|
-
...(
|
|
146
|
+
...(allowedTools && { allowedTools }),
|
|
147
|
+
...(mcpConfigPath && { mcpConfigPath: resolve(mcpConfigPath) })
|
|
121
148
|
}
|
|
122
149
|
|
|
123
150
|
return repository
|
|
@@ -256,30 +283,10 @@ class EdgeApp {
|
|
|
256
283
|
*/
|
|
257
284
|
async start() {
|
|
258
285
|
try {
|
|
259
|
-
//
|
|
260
|
-
const proxyUrl = process.env.PROXY_URL
|
|
261
|
-
if (!proxyUrl) {
|
|
262
|
-
console.error('ā PROXY_URL environment variable is required')
|
|
263
|
-
console.log('\nPlease add the following to your .env.cyrus file:')
|
|
264
|
-
console.log('PROXY_URL=https://cyrus-proxy.ceedar.workers.dev')
|
|
265
|
-
console.log('\nThis connects to the secure public Cyrus proxy for Linear OAuth and webhooks.')
|
|
266
|
-
process.exit(1)
|
|
267
|
-
}
|
|
286
|
+
// Set proxy URL with default
|
|
287
|
+
const proxyUrl = process.env.PROXY_URL || 'https://cyrus-proxy.ceedar.workers.dev'
|
|
268
288
|
|
|
269
|
-
//
|
|
270
|
-
const claudePath = process.env.CLAUDE_PATH || 'claude'
|
|
271
|
-
try {
|
|
272
|
-
const { execSync } = await import('child_process')
|
|
273
|
-
execSync(`which ${claudePath}`, { stdio: 'ignore' })
|
|
274
|
-
} catch (error) {
|
|
275
|
-
console.error(`ā Claude CLI not found at: ${claudePath}`)
|
|
276
|
-
console.log('\nPlease ensure Claude Code is installed:')
|
|
277
|
-
console.log('⢠Claude Pro/Max users: Install from https://claude.ai/code')
|
|
278
|
-
console.log('⢠API users: Set ANTHROPIC_API_KEY in .env.cyrus and install claude-ai CLI')
|
|
279
|
-
console.log('\nIf Claude is installed in a custom location, set CLAUDE_PATH in .env.cyrus:')
|
|
280
|
-
console.log('CLAUDE_PATH=/path/to/claude')
|
|
281
|
-
process.exit(1)
|
|
282
|
-
}
|
|
289
|
+
// No need to validate Claude CLI - using Claude TypeScript SDK now
|
|
283
290
|
|
|
284
291
|
// Start OAuth server immediately for easy access
|
|
285
292
|
const oauthPort = 3457
|
|
@@ -437,8 +444,7 @@ class EdgeApp {
|
|
|
437
444
|
const config = {
|
|
438
445
|
proxyUrl,
|
|
439
446
|
repositories,
|
|
440
|
-
|
|
441
|
-
allowedTools: process.env.ALLOWED_TOOLS?.split(',').map(t => t.trim()) || [],
|
|
447
|
+
defaultAllowedTools: process.env.ALLOWED_TOOLS?.split(',').map(t => t.trim()) || [],
|
|
442
448
|
features: {
|
|
443
449
|
enableContinuation: true
|
|
444
450
|
},
|
|
@@ -537,8 +543,12 @@ class EdgeApp {
|
|
|
537
543
|
throw new Error('Not a git repository')
|
|
538
544
|
}
|
|
539
545
|
|
|
546
|
+
// Sanitize branch name by removing backticks to prevent command injection
|
|
547
|
+
const sanitizeBranchName = (name) => name ? name.replace(/`/g, '') : name
|
|
548
|
+
|
|
540
549
|
// Use Linear's preferred branch name, or generate one if not available
|
|
541
|
-
const
|
|
550
|
+
const rawBranchName = issue.branchName || `${issue.identifier}-${issue.title?.toLowerCase().replace(/\s+/g, '-').substring(0, 30)}`
|
|
551
|
+
const branchName = sanitizeBranchName(rawBranchName)
|
|
542
552
|
const workspacePath = join(repository.workspaceBaseDir, issue.identifier)
|
|
543
553
|
|
|
544
554
|
// Ensure workspace directory exists
|
|
@@ -577,10 +587,22 @@ class EdgeApp {
|
|
|
577
587
|
// Branch doesn't exist, we'll create it
|
|
578
588
|
}
|
|
579
589
|
|
|
580
|
-
//
|
|
581
|
-
console.log(
|
|
590
|
+
// Fetch latest changes from remote
|
|
591
|
+
console.log('Fetching latest changes from remote...')
|
|
592
|
+
try {
|
|
593
|
+
execSync('git fetch origin', {
|
|
594
|
+
cwd: repository.repositoryPath,
|
|
595
|
+
stdio: 'pipe'
|
|
596
|
+
})
|
|
597
|
+
} catch (e) {
|
|
598
|
+
console.warn('Warning: git fetch failed, proceeding with local branch:', e.message)
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// Create the worktree from remote branch
|
|
602
|
+
const remoteBranch = `origin/${repository.baseBranch}`
|
|
603
|
+
console.log(`Creating git worktree at ${workspacePath} from ${remoteBranch}`)
|
|
582
604
|
const worktreeCmd = createBranch
|
|
583
|
-
? `git worktree add "${workspacePath}" -b "${branchName}" "${
|
|
605
|
+
? `git worktree add "${workspacePath}" -b "${branchName}" "${remoteBranch}"`
|
|
584
606
|
: `git worktree add "${workspacePath}" "${branchName}"`
|
|
585
607
|
|
|
586
608
|
execSync(worktreeCmd, {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cyrus-ai",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "AI-powered Linear issue automation using Claude",
|
|
5
5
|
"main": "app.mjs",
|
|
6
6
|
"bin": {
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"files": [
|
|
11
11
|
"app.mjs",
|
|
12
12
|
"services/**/*.mjs",
|
|
13
|
-
"utils/**/*.mjs"
|
|
13
|
+
"utils/**/*.mjs",
|
|
14
|
+
"README.md"
|
|
14
15
|
],
|
|
15
16
|
"publishConfig": {
|
|
16
17
|
"access": "public"
|
|
@@ -39,10 +40,9 @@
|
|
|
39
40
|
"open": "^10.0.0",
|
|
40
41
|
"zod": "^3.24.4",
|
|
41
42
|
"cyrus-core": "0.0.1",
|
|
42
|
-
"cyrus-claude-runner": "0.0.1",
|
|
43
|
-
"cyrus-ndjson-client": "0.0.1",
|
|
44
43
|
"cyrus-edge-worker": "0.0.1",
|
|
45
|
-
"cyrus-claude-
|
|
44
|
+
"cyrus-claude-runner": "0.0.1",
|
|
45
|
+
"cyrus-ndjson-client": "0.0.1"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@vitest/ui": "^3.1.4",
|
|
@@ -53,6 +53,7 @@
|
|
|
53
53
|
"start": "node app.mjs",
|
|
54
54
|
"dev": "nodemon app.mjs",
|
|
55
55
|
"test": "vitest run",
|
|
56
|
+
"test:run": "vitest run --passWithNoTests",
|
|
56
57
|
"test:watch": "vitest"
|
|
57
58
|
}
|
|
58
59
|
}
|