@xortex/xcode 3.0.8 → 3.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.
Files changed (71) hide show
  1. package/INSTALLATION.md +285 -0
  2. package/QUICKSTART.md +151 -0
  3. package/SYSTEM_PROMPT.md +583 -0
  4. package/SYSTEM_PROMPT_EXTRACTED.md +1 -0
  5. package/Untitled +1 -0
  6. package/bin/xcode +33 -85
  7. package/bootstrap/state.ts +1758 -0
  8. package/bun.lock +645 -0
  9. package/context/QueuedMessageContext.tsx +63 -0
  10. package/context/fpsMetrics.tsx +30 -0
  11. package/context/mailbox.tsx +38 -0
  12. package/context/modalContext.tsx +58 -0
  13. package/context/notifications.tsx +240 -0
  14. package/context/overlayContext.tsx +151 -0
  15. package/context/promptOverlayContext.tsx +125 -0
  16. package/context/stats.tsx +220 -0
  17. package/context/voice.tsx +88 -0
  18. package/coordinator/coordinatorMode.ts +369 -0
  19. package/costHook.ts +22 -0
  20. package/dialogLaunchers.tsx +133 -0
  21. package/entrypoints/cli.tsx +1 -1
  22. package/extract_prompt.ts +304 -0
  23. package/ink.ts +85 -0
  24. package/install.sh +221 -0
  25. package/interactiveHelpers.tsx +366 -0
  26. package/macro.ts +1 -1
  27. package/memdir/findRelevantMemories.ts +141 -0
  28. package/memdir/memdir.ts +511 -0
  29. package/memdir/memoryAge.ts +53 -0
  30. package/memdir/memoryScan.ts +94 -0
  31. package/memdir/memoryTypes.ts +271 -0
  32. package/memdir/paths.ts +291 -0
  33. package/memdir/teamMemPaths.ts +292 -0
  34. package/memdir/teamMemPrompts.ts +100 -0
  35. package/moreright/useMoreRight.tsx +26 -0
  36. package/native-ts/color-diff/index.ts +999 -0
  37. package/native-ts/file-index/index.ts +370 -0
  38. package/native-ts/yoga-layout/enums.ts +134 -0
  39. package/native-ts/yoga-layout/index.ts +2578 -0
  40. package/outputStyles/loadOutputStylesDir.ts +98 -0
  41. package/package.json +3 -42
  42. package/plugins/builtinPlugins.ts +159 -0
  43. package/plugins/bundled/index.ts +23 -0
  44. package/projectOnboardingState.ts +83 -0
  45. package/public/claude-files.png +0 -0
  46. package/public/leak-tweet.png +0 -0
  47. package/query/config.ts +46 -0
  48. package/query/deps.ts +40 -0
  49. package/query/stopHooks.ts +470 -0
  50. package/query/tokenBudget.ts +93 -0
  51. package/replLauncher.tsx +27 -0
  52. package/schemas/hooks.ts +222 -0
  53. package/screens/Doctor.tsx +575 -0
  54. package/screens/REPL.tsx +7107 -0
  55. package/screens/ResumeConversation.tsx +399 -0
  56. package/scripts/postinstall.js +90 -0
  57. package/server/createDirectConnectSession.ts +88 -0
  58. package/server/directConnectManager.ts +213 -0
  59. package/server/types.ts +57 -0
  60. package/setup.ts +477 -0
  61. package/stub_types.sh +13 -0
  62. package/tasks.ts +39 -0
  63. package/tools.ts +396 -0
  64. package/upstreamproxy/relay.ts +455 -0
  65. package/upstreamproxy/upstreamproxy.ts +285 -0
  66. package/vim/motions.ts +82 -0
  67. package/vim/operators.ts +556 -0
  68. package/vim/textObjects.ts +186 -0
  69. package/vim/transitions.ts +490 -0
  70. package/vim/types.ts +199 -0
  71. package/voice/voiceModeEnabled.ts +54 -0
@@ -0,0 +1,304 @@
1
+ /**
2
+ * extract_prompt.ts
3
+ * Extracts and prints the real Claude Code system prompt by directly
4
+ * reading and evaluating all prompt-generating functions from source.
5
+ * Run with: bun extract_prompt.ts
6
+ */
7
+
8
+ // ── Mock bun:bundle feature() macro (always returns false for clean external build) ──
9
+ // We patch this before any module loads it
10
+ const Module = require('module')
11
+ const originalLoad = Module._load
12
+ Module._load = function (request: string, ...args: unknown[]) {
13
+ if (request === 'bun:bundle') {
14
+ return { feature: (_: string) => false }
15
+ }
16
+ return originalLoad.call(this, request, ...args)
17
+ }
18
+
19
+ // ── Read raw source file and extract string content from template literals ──
20
+ import { readFileSync } from 'fs'
21
+ import { join } from 'path'
22
+
23
+ const ROOT = import.meta.dir
24
+
25
+ function readSource(rel: string): string {
26
+ return readFileSync(join(ROOT, rel), 'utf-8')
27
+ }
28
+
29
+ // Extract all backtick template literal bodies from a function by name
30
+ function extractTemplateLiterals(src: string): string[] {
31
+ const results: string[] = []
32
+ let i = 0
33
+ while (i < src.length) {
34
+ if (src[i] === '`') {
35
+ let j = i + 1
36
+ let body = ''
37
+ while (j < src.length) {
38
+ if (src[j] === '\\') { body += src[j] + src[j+1]; j += 2; continue }
39
+ if (src[j] === '`') break
40
+ body += src[j]
41
+ j++
42
+ }
43
+ results.push(body)
44
+ i = j + 1
45
+ } else {
46
+ i++
47
+ }
48
+ }
49
+ return results
50
+ }
51
+
52
+ // ── Extract sections from prompts.ts ────────────────────────────────────────
53
+
54
+ const promptsSrc = readSource('constants/prompts.ts')
55
+ const systemSrc = readSource('constants/system.ts')
56
+ const coordSrc = readSource('coordinator/coordinatorMode.ts')
57
+ const cyberSrc = readSource('constants/cyberRiskInstruction.ts')
58
+
59
+ // Pull CYBER_RISK_INSTRUCTION
60
+ const cyberMatch = cyberSrc.match(/CYBER_RISK_INSTRUCTION\s*=\s*`([^`]+)`/)
61
+ const CYBER_RISK = cyberMatch?.[1] ?? '[cyber risk instruction not found]'
62
+
63
+ // Pull coordinator system prompt (between the return template literal)
64
+ const coordMatch = coordSrc.match(/return\s*`(You are Claude Code, an AI assistant[\s\S]+?)`\s*\}/)
65
+ const COORDINATOR_PROMPT = coordMatch?.[1] ?? '[coordinator prompt not found]'
66
+
67
+ // Helper: extract named function body
68
+ function getFunctionBody(src: string, fnName: string): string {
69
+ const idx = src.indexOf(`function ${fnName}(`)
70
+ if (idx === -1) return `[${fnName} not found]`
71
+ let depth = 0
72
+ let start = -1
73
+ for (let i = idx; i < src.length; i++) {
74
+ if (src[i] === '{') { if (start === -1) start = i; depth++ }
75
+ else if (src[i] === '}') { depth--; if (depth === 0) return src.slice(start, i+1) }
76
+ }
77
+ return `[${fnName} body unterminated]`
78
+ }
79
+
80
+ // Extract all return template strings from a function
81
+ function getReturnStrings(fnBody: string): string[] {
82
+ // Find return `...` blocks
83
+ const results: string[] = []
84
+ const matches = fnBody.matchAll(/return\s*`([\s\S]*?)`/g)
85
+ for (const m of matches) results.push(m[1])
86
+ return results
87
+ }
88
+
89
+ // ── Manually inline relevant prompt section text ─────────────────────────────
90
+
91
+ // 1. getSimpleIntroSection
92
+ const introFn = getFunctionBody(promptsSrc, 'getSimpleIntroSection')
93
+ const introStr = getReturnStrings(introFn)
94
+
95
+ // 2. getSimpleSystemSection
96
+ const sysFn = getFunctionBody(promptsSrc, 'getSimpleSystemSection')
97
+
98
+ // 3. getSimpleDoingTasksSection
99
+ const doingFn = getFunctionBody(promptsSrc, 'getSimpleDoingTasksSection')
100
+
101
+ // 4. getActionsSection
102
+ const actionsFn = getFunctionBody(promptsSrc, 'getActionsSection')
103
+ const actionsStr = getReturnStrings(actionsFn)
104
+
105
+ // 5. getOutputEfficiencySection
106
+ const effFn = getFunctionBody(promptsSrc, 'getOutputEfficiencySection')
107
+ const effStrings = getReturnStrings(effFn)
108
+
109
+ // 6. computeSimpleEnvInfo - template
110
+ const envFn = getFunctionBody(promptsSrc, 'computeSimpleEnvInfo')
111
+ const envTemplate = getReturnStrings(envFn)
112
+
113
+ // 7. getScratchpadInstructions
114
+ const scratchFn = getFunctionBody(promptsSrc, 'getScratchpadInstructions')
115
+ const scratchStr = getReturnStrings(scratchFn)
116
+
117
+ // 8. DEFAULT_AGENT_PROMPT
118
+ const agentMatch = promptsSrc.match(/DEFAULT_AGENT_PROMPT\s*=\s*`([^`]+)`/)
119
+ const DEFAULT_AGENT_PROMPT = agentMatch?.[1] ?? '[not found]'
120
+
121
+ // 9. SUMMARIZE_TOOL_RESULTS_SECTION
122
+ const sumMatch = promptsSrc.match(/SUMMARIZE_TOOL_RESULTS_SECTION\s*=\s*`([^`]+)`/)
123
+ const SUMMARIZE = sumMatch?.[1] ?? '[not found]'
124
+
125
+ // 10. getSystemRemindersSection
126
+ const remMatch = promptsSrc.match(/function getSystemRemindersSection[\s\S]*?return\s*`([\s\S]*?)`/)
127
+ const SYSTEM_REMINDERS = remMatch?.[1] ?? '[not found]'
128
+
129
+ // 11. getHooksSection
130
+ const hooksMatch = promptsSrc.match(/function getHooksSection[\s\S]*?return\s*`([\s\S]*?)`/)
131
+ const HOOKS = hooksMatch?.[1] ?? '[not found]'
132
+
133
+ // 12. getFunctionResultClearingSection template
134
+ const frcMatch = promptsSrc.match(/return\s*`# Function Result Clearing[\s\S]*?`/)
135
+ const FRC = frcMatch?.[0]?.replace(/^return\s*`/, '').replace(/`$/, '') ?? '[not found]'
136
+
137
+ // 13. Token budget section
138
+ const tokenMatch = promptsSrc.match(/'token_budget',\s*\(\)\s*=>\s*'([\s\S]*?)',/)
139
+ const TOKEN_BUDGET = tokenMatch?.[1] ?? '[not found]'
140
+
141
+ // 14. Proactive section
142
+ const proactiveFn = getFunctionBody(promptsSrc, 'getProactiveSection')
143
+ const proactiveStr = getReturnStrings(proactiveFn)
144
+
145
+ // 15. getSimpleToneAndStyleSection items
146
+ const toneFn = getFunctionBody(promptsSrc, 'getSimpleToneAndStyleSection')
147
+
148
+ // 16. getMcpInstructions template
149
+ const mcpMatch = promptsSrc.match(/return\s*`# MCP Server Instructions[\s\S]*?`/)
150
+ const MCP_TEMPLATE = mcpMatch?.[0]?.replace(/^return\s*`/, '').replace(/`$/, '') ?? '[not found]'
151
+
152
+ // ── Build and print the full prompt ──────────────────────────────────────────
153
+
154
+ const HR = '\n' + '='.repeat(80) + '\n'
155
+ const output: string[] = []
156
+
157
+ output.push(`# CLAUDE CODE — REAL SYSTEM PROMPT (Extracted from Source)`)
158
+ output.push(`Generated by extract_prompt.ts — reads directly from constants/prompts.ts\n`)
159
+
160
+ output.push(HR)
161
+ output.push(`## SECTION 0 — IDENTITY PREFIX`)
162
+ output.push(`\`\`\``)
163
+ output.push(`You are Claude Code, Anthropic's official CLI for Claude.`)
164
+ output.push(`\`\`\``)
165
+
166
+ output.push(HR)
167
+ output.push(`## SECTION 1 — SIMPLE MODE (env CLAUDE_CODE_SIMPLE=1)`)
168
+ output.push(`\`\`\``)
169
+ output.push(`You are Claude Code, Anthropic's official CLI for Claude.\n\nCWD: <cwd>\nDate: <session start date>`)
170
+ output.push(`\`\`\``)
171
+
172
+ output.push(HR)
173
+ output.push(`## SECTION 2 — INTRO (getSimpleIntroSection)`)
174
+ output.push(`\`\`\``)
175
+ output.push(`\nYou are an interactive agent that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user.\n\n${CYBER_RISK}\nIMPORTANT: You must NEVER generate or guess URLs for the user unless you are confident that the URLs are for helping the user with programming. You may use URLs provided by the user in their messages or local files.`)
176
+ output.push(`\`\`\``)
177
+
178
+ output.push(HR)
179
+ output.push(`## SECTION 3 — SYSTEM (getSimpleSystemSection)`)
180
+ // Extract bullet items from the array literal in getSimpleSystemSection
181
+ const systemItemsMatch = promptsSrc.match(/function getSimpleSystemSection[\s\S]*?const items = \[([\s\S]*?)\]/m)
182
+ if (systemItemsMatch) {
183
+ // Pull backtick strings out of the items array
184
+ const itemsBlock = systemItemsMatch[1]
185
+ const ticks = extractTemplateLiterals(itemsBlock)
186
+
187
+ // Replace HOOKS placeholder
188
+ const finalItems = ticks.map(t => t.replace(/\${getHooksSection\(\)}/, HOOKS))
189
+
190
+ output.push(`\`\`\``)
191
+ output.push(`# System`)
192
+ finalItems.forEach(item => output.push(` - ${item}`))
193
+ output.push(`\`\`\``)
194
+ }
195
+
196
+ output.push(HR)
197
+ output.push(`## SECTION 4 — ACTIONS (getActionsSection)`)
198
+ output.push(`\`\`\``)
199
+ if (actionsStr[0]) output.push(actionsStr[0].replace(/\\n/g, '\n'))
200
+ output.push(`\`\`\``)
201
+
202
+ output.push(HR)
203
+ output.push(`## SECTION 5 — DOING TASKS (getSimpleDoingTasksSection) — key items`)
204
+ // Extract the outer items array
205
+ const doingItemsRegex = /`The user will primarily[\s\S]*?`/g
206
+ const doingMatches = [...doingFn.matchAll(/`([^`]{20,})`/g)].map(m => m[1]).filter(s => !s.includes('${'))
207
+ output.push(`\`\`\``)
208
+ output.push(`# Doing tasks`)
209
+ doingMatches.slice(0, 15).forEach(i => output.push(` - ${i}`))
210
+ output.push(`\`\`\``)
211
+
212
+ output.push(HR)
213
+ output.push(`## SECTION 6 — TONE AND STYLE (getSimpleToneAndStyleSection)`)
214
+ const toneItems = [...toneFn.matchAll(/`([^`]{20,})`/g)].map(m => m[1]).filter(s => !s.includes('${'))
215
+ output.push(`\`\`\``)
216
+ output.push(`# Tone and style`)
217
+ toneItems.forEach(i => output.push(` - ${i}`))
218
+ output.push(`\`\`\``)
219
+
220
+ output.push(HR)
221
+ output.push(`## SECTION 7 — OUTPUT EFFICIENCY (getOutputEfficiencySection)`)
222
+ output.push(`\`\`\``)
223
+ if (effStrings[1]) output.push(effStrings[1])
224
+ else if (effStrings[0]) output.push(effStrings[0])
225
+ output.push(`\`\`\``)
226
+
227
+ output.push(HR)
228
+ output.push(`## SECTION 8 — ENVIRONMENT (computeSimpleEnvInfo) — template`)
229
+ output.push(`\`\`\``)
230
+ output.push(`# Environment
231
+ You have been invoked in the following environment:
232
+ - Primary working directory: <cwd>
233
+ - Is a git repository: Yes/No
234
+ - Platform: darwin/linux/win32
235
+ - Shell: zsh/bash
236
+ - OS Version: Darwin 25.x.x
237
+ - You are powered by the model named <model>. The exact model ID is <model-id>.
238
+ - Assistant knowledge cutoff is <date>.
239
+ - The most recent Claude model family is Claude 4.5/4.6. Model IDs — Opus 4.6: 'claude-opus-4-6', Sonnet 4.6: 'claude-sonnet-4-6', Haiku 4.5: 'claude-haiku-4-5-20251001'. When building AI applications, default to the latest and most capable Claude models.
240
+ - Claude Code is available as a CLI in the terminal, desktop app (Mac/Windows), web app (claude.ai/code), and IDE extensions (VS Code, JetBrains).
241
+ - Fast mode for Claude Code uses the same Claude Opus 4.6 model with faster output. It does NOT switch to a different model. It can be toggled with /fast.`)
242
+ output.push(`\`\`\``)
243
+
244
+ output.push(HR)
245
+ output.push(`## SECTION 9 — SYSTEM REMINDERS (getSystemRemindersSection)`)
246
+ output.push(`\`\`\``)
247
+ output.push(SYSTEM_REMINDERS)
248
+ output.push(`\`\`\``)
249
+
250
+ output.push(HR)
251
+ output.push(`## SECTION 10 — SUMMARIZE TOOL RESULTS`)
252
+ output.push(`\`\`\``)
253
+ output.push(SUMMARIZE)
254
+ output.push(`\`\`\``)
255
+
256
+ output.push(HR)
257
+ output.push(`## SECTION 11 — SCRATCHPAD DIRECTORY (getScratchpadInstructions)`)
258
+ output.push(`\`\`\``)
259
+ if (scratchStr[0]) output.push(scratchStr[0])
260
+ output.push(`\`\`\``)
261
+
262
+ output.push(HR)
263
+ output.push(`## SECTION 12 — MCP SERVER INSTRUCTIONS TEMPLATE`)
264
+ output.push(`\`\`\``)
265
+ output.push(MCP_TEMPLATE)
266
+ output.push(`\`\`\``)
267
+
268
+ output.push(HR)
269
+ output.push(`## SECTION 13 — FUNCTION RESULT CLEARING`)
270
+ output.push(`\`\`\``)
271
+ output.push(FRC)
272
+ output.push(`\`\`\``)
273
+
274
+ output.push(HR)
275
+ output.push(`## SECTION 14 — TOKEN BUDGET`)
276
+ output.push(`\`\`\``)
277
+ output.push(TOKEN_BUDGET)
278
+ output.push(`\`\`\``)
279
+
280
+ output.push(HR)
281
+ output.push(`## SECTION 15 — DEFAULT AGENT PROMPT`)
282
+ output.push(`\`\`\``)
283
+ output.push(DEFAULT_AGENT_PROMPT)
284
+ output.push(`\`\`\``)
285
+
286
+ output.push(HR)
287
+ output.push(`## SECTION 16 — COORDINATOR MODE SYSTEM PROMPT`)
288
+ output.push(`\`\`\``)
289
+ output.push(COORDINATOR_PROMPT)
290
+ output.push(`\`\`\``)
291
+
292
+ output.push(HR)
293
+ output.push(`## SECTION 17 — AUTONOMOUS / PROACTIVE MODE SECTION`)
294
+ output.push(`\`\`\``)
295
+ if (proactiveStr[0]) output.push(proactiveStr[0])
296
+ output.push(`\`\`\``)
297
+
298
+ const finalOutput = output.join('\n')
299
+ console.log(finalOutput)
300
+
301
+ // Also write to file
302
+ import { writeFileSync } from 'fs'
303
+ writeFileSync(join(ROOT, 'SYSTEM_PROMPT_EXTRACTED.md'), finalOutput, 'utf-8')
304
+ console.error('\n\nWritten to SYSTEM_PROMPT_EXTRACTED.md')
package/ink.ts ADDED
@@ -0,0 +1,85 @@
1
+ import { createElement, type ReactNode } from 'react'
2
+ import { ThemeProvider } from './components/design-system/ThemeProvider.js'
3
+ import inkRender, {
4
+ type Instance,
5
+ createRoot as inkCreateRoot,
6
+ type RenderOptions,
7
+ type Root,
8
+ } from './ink/root.js'
9
+
10
+ export type { RenderOptions, Instance, Root }
11
+
12
+ // Wrap all CC render calls with ThemeProvider so ThemedBox/ThemedText work
13
+ // without every call site having to mount it. Ink itself is theme-agnostic.
14
+ function withTheme(node: ReactNode): ReactNode {
15
+ return createElement(ThemeProvider, null, node)
16
+ }
17
+
18
+ export async function render(
19
+ node: ReactNode,
20
+ options?: NodeJS.WriteStream | RenderOptions,
21
+ ): Promise<Instance> {
22
+ return inkRender(withTheme(node), options)
23
+ }
24
+
25
+ export async function createRoot(options?: RenderOptions): Promise<Root> {
26
+ const root = await inkCreateRoot(options)
27
+ return {
28
+ ...root,
29
+ render: node => root.render(withTheme(node)),
30
+ }
31
+ }
32
+
33
+ export { color } from './components/design-system/color.js'
34
+ export type { Props as BoxProps } from './components/design-system/ThemedBox.js'
35
+ export { default as Box } from './components/design-system/ThemedBox.js'
36
+ export type { Props as TextProps } from './components/design-system/ThemedText.js'
37
+ export { default as Text } from './components/design-system/ThemedText.js'
38
+ export {
39
+ ThemeProvider,
40
+ usePreviewTheme,
41
+ useTheme,
42
+ useThemeSetting,
43
+ } from './components/design-system/ThemeProvider.js'
44
+ export { Ansi } from './ink/Ansi.js'
45
+ export type { Props as AppProps } from './ink/components/AppContext.js'
46
+ export type { Props as BaseBoxProps } from './ink/components/Box.js'
47
+ export { default as BaseBox } from './ink/components/Box.js'
48
+ export type {
49
+ ButtonState,
50
+ Props as ButtonProps,
51
+ } from './ink/components/Button.js'
52
+ export { default as Button } from './ink/components/Button.js'
53
+ export type { Props as LinkProps } from './ink/components/Link.js'
54
+ export { default as Link } from './ink/components/Link.js'
55
+ export type { Props as NewlineProps } from './ink/components/Newline.js'
56
+ export { default as Newline } from './ink/components/Newline.js'
57
+ export { NoSelect } from './ink/components/NoSelect.js'
58
+ export { RawAnsi } from './ink/components/RawAnsi.js'
59
+ export { default as Spacer } from './ink/components/Spacer.js'
60
+ export type { Props as StdinProps } from './ink/components/StdinContext.js'
61
+ export type { Props as BaseTextProps } from './ink/components/Text.js'
62
+ export { default as BaseText } from './ink/components/Text.js'
63
+ export type { DOMElement } from './ink/dom.js'
64
+ export { ClickEvent } from './ink/events/click-event.js'
65
+ export { EventEmitter } from './ink/events/emitter.js'
66
+ export { Event } from './ink/events/event.js'
67
+ export type { Key } from './ink/events/input-event.js'
68
+ export { InputEvent } from './ink/events/input-event.js'
69
+ export type { TerminalFocusEventType } from './ink/events/terminal-focus-event.js'
70
+ export { TerminalFocusEvent } from './ink/events/terminal-focus-event.js'
71
+ export { FocusManager } from './ink/focus.js'
72
+ export type { FlickerReason } from './ink/frame.js'
73
+ export { useAnimationFrame } from './ink/hooks/use-animation-frame.js'
74
+ export { default as useApp } from './ink/hooks/use-app.js'
75
+ export { default as useInput } from './ink/hooks/use-input.js'
76
+ export { useAnimationTimer, useInterval } from './ink/hooks/use-interval.js'
77
+ export { useSelection } from './ink/hooks/use-selection.js'
78
+ export { default as useStdin } from './ink/hooks/use-stdin.js'
79
+ export { useTabStatus } from './ink/hooks/use-tab-status.js'
80
+ export { useTerminalFocus } from './ink/hooks/use-terminal-focus.js'
81
+ export { useTerminalTitle } from './ink/hooks/use-terminal-title.js'
82
+ export { useTerminalViewport } from './ink/hooks/use-terminal-viewport.js'
83
+ export { default as measureElement } from './ink/measure-element.js'
84
+ export { supportsTabStatus } from './ink/termio/osc.js'
85
+ export { default as wrapText } from './ink/wrap-text.js'
package/install.sh ADDED
@@ -0,0 +1,221 @@
1
+ #!/bin/bash
2
+ #
3
+ # XCode Installation Script
4
+ #
5
+ # Install with:
6
+ # curl -fsSL https://raw.githubusercontent.com/XortexAI/XCode/main/install.sh | bash
7
+ #
8
+ # Or with wget:
9
+ # wget -qO- https://raw.githubusercontent.com/XortexAI/XCode/main/install.sh | bash
10
+ #
11
+
12
+ set -e
13
+
14
+ # Colors for output
15
+ RED='\033[0;31m'
16
+ GREEN='\033[0;32m'
17
+ YELLOW='\033[1;33m'
18
+ BLUE='\033[0;34m'
19
+ NC='\033[0m' # No Color
20
+
21
+ # Configuration
22
+ REPO_URL="https://github.com/XortexAI/XCode"
23
+ INSTALL_DIR="$HOME/.xcode"
24
+ BIN_DIR="$HOME/.local/bin"
25
+
26
+ # Detect OS and architecture
27
+ OS=$(uname -s)
28
+ ARCH=$(uname -m)
29
+
30
+ echo -e "${BLUE}🚀 Installing XCode...${NC}"
31
+ echo ""
32
+
33
+ # Check if required dependencies are installed
34
+ check_dependencies() {
35
+ local missing_deps=()
36
+
37
+ # Check for git
38
+ if ! command -v git &> /dev/null; then
39
+ missing_deps+=("git")
40
+ fi
41
+
42
+ # Check for either Bun or Node.js
43
+ if ! command -v bun &> /dev/null && ! command -v node &> /dev/null; then
44
+ missing_deps+=("bun or node")
45
+ fi
46
+
47
+ if [ ${#missing_deps[@]} -ne 0 ]; then
48
+ echo -e "${RED}❌ Missing required dependencies:${NC}"
49
+ for dep in "${missing_deps[@]}"; do
50
+ echo " - $dep"
51
+ done
52
+ echo ""
53
+ echo "Please install the missing dependencies and try again."
54
+ echo ""
55
+ echo "To install Bun (recommended):"
56
+ echo " curl -fsSL https://bun.sh/install | bash"
57
+ echo ""
58
+ echo "To install Node.js:"
59
+ echo " Visit https://nodejs.org/ or use your package manager"
60
+ exit 1
61
+ fi
62
+ }
63
+
64
+ # Create necessary directories
65
+ setup_directories() {
66
+ echo -e "${BLUE}📁 Creating directories...${NC}"
67
+ mkdir -p "$INSTALL_DIR"
68
+ mkdir -p "$BIN_DIR"
69
+ }
70
+
71
+ # Clone or update the repository
72
+ install_xcode() {
73
+ if [ -d "$INSTALL_DIR/.git" ]; then
74
+ echo -e "${BLUE}🔄 Updating existing installation...${NC}"
75
+ cd "$INSTALL_DIR"
76
+ git pull origin main
77
+ else
78
+ echo -e "${BLUE}📦 Cloning XCode repository...${NC}"
79
+ rm -rf "$INSTALL_DIR"
80
+ git clone --depth=1 "$REPO_URL" "$INSTALL_DIR"
81
+ cd "$INSTALL_DIR"
82
+ fi
83
+ }
84
+
85
+ # Install dependencies
86
+ install_dependencies() {
87
+ echo -e "${BLUE}📥 Installing dependencies...${NC}"
88
+
89
+ if command -v bun &> /dev/null; then
90
+ echo "Using Bun..."
91
+ bun install
92
+ elif command -v npm &> /dev/null; then
93
+ echo "Using npm..."
94
+ npm install
95
+ fi
96
+ }
97
+
98
+ # Create the launcher script
99
+ create_launcher() {
100
+ echo -e "${BLUE}🎯 Creating launcher...${NC}"
101
+
102
+ cat > "$BIN_DIR/xcode" << 'EOF'
103
+ #!/bin/bash
104
+ # XCode Launcher
105
+
106
+ INSTALL_DIR="$HOME/.xcode"
107
+
108
+ # Check if installation exists
109
+ if [ ! -d "$INSTALL_DIR" ]; then
110
+ echo "❌ XCode not found. Please install first:"
111
+ echo " curl -fsSL https://raw.githubusercontent.com/XortexAI/XCode/main/install.sh | bash"
112
+ exit 1
113
+ fi
114
+
115
+ cd "$INSTALL_DIR"
116
+
117
+ # Use Bun if available, otherwise fall back to npm/npx
118
+ if command -v bun &> /dev/null; then
119
+ exec bun run ./entrypoints/cli.tsx "$@"
120
+ elif command -v npx &> /dev/null; then
121
+ exec npx tsx ./entrypoints/cli.tsx "$@"
122
+ else
123
+ echo "❌ Neither Bun nor npx is available. Please install Bun:"
124
+ echo " curl -fsSL https://bun.sh/install | bash"
125
+ exit 1
126
+ fi
127
+ EOF
128
+
129
+ chmod +x "$BIN_DIR/xcode"
130
+ }
131
+
132
+ # Add to PATH if needed
133
+ update_path() {
134
+ local shell_rc=""
135
+ local current_shell=$(basename "$SHELL")
136
+
137
+ case "$current_shell" in
138
+ bash)
139
+ shell_rc="$HOME/.bashrc"
140
+ ;;
141
+ zsh)
142
+ shell_rc="$HOME/.zshrc"
143
+ ;;
144
+ fish)
145
+ shell_rc="$HOME/.config/fish/config.fish"
146
+ ;;
147
+ *)
148
+ shell_rc="$HOME/.profile"
149
+ ;;
150
+ esac
151
+
152
+ # Check if BIN_DIR is already in PATH
153
+ if [[ ":$PATH:" != *":$BIN_DIR:"* ]]; then
154
+ echo -e "${BLUE}🔧 Adding $BIN_DIR to PATH in $shell_rc${NC}"
155
+ echo "export PATH=\"$BIN_DIR:\$PATH\"" >> "$shell_rc"
156
+ echo ""
157
+ echo -e "${YELLOW}⚠️ Please run: source $shell_rc${NC}"
158
+ echo " Or restart your terminal to use the 'xcode' command"
159
+ fi
160
+ }
161
+
162
+ # Setup XMem configuration
163
+ setup_xmem() {
164
+ echo ""
165
+ echo -e "${BLUE}🧠 XMem Memory Configuration${NC}"
166
+ echo "XCode uses XMem for long-term memory storage."
167
+ echo ""
168
+
169
+ # Check if XMem is already configured
170
+ if [ -z "$XMEM_API_URL" ]; then
171
+ echo -e "${YELLOW}⚠️ XMEM_API_URL not set${NC}"
172
+ echo " Using default: http://localhost:8000"
173
+ echo " Set it with: export XMEM_API_URL=http://your-xmem-server:8000"
174
+ fi
175
+
176
+ echo ""
177
+ }
178
+
179
+ # Print success message
180
+ print_success() {
181
+ echo ""
182
+ echo -e "${GREEN}✅ XCode installed successfully!${NC}"
183
+ echo ""
184
+ echo -e "${BLUE}🎉 Usage:${NC}"
185
+ echo " xcode # Start interactive session"
186
+ echo " xcode --model gemini-2.5-pro # Use Gemini 2.5 Pro"
187
+ echo " xcode --model kimi-k2.5 # Use Kimi K2.5"
188
+ echo " xcode --model deepseek-v3.2 # Use DeepSeek V3.2"
189
+ echo ""
190
+ echo -e "${BLUE}🔑 API Keys (set these environment variables):${NC}"
191
+ echo " OPENROUTER_API_KEY # For Gemini, Kimi, DeepSeek via OpenRouter"
192
+ echo " ANTHROPIC_API_KEY # For Claude models"
193
+ echo " GEMINI_API_KEY # For Google Gemini directly"
194
+ echo " XMEM_API_URL # XMem server URL (default: http://localhost:8000)"
195
+ echo ""
196
+ echo -e "${BLUE}📚 Documentation:${NC}"
197
+ echo " https://github.com/XortexAI/XCode#readme"
198
+ echo ""
199
+ echo -e "${GREEN}Happy coding! 🚀${NC}"
200
+ }
201
+
202
+ # Main installation flow
203
+ main() {
204
+ echo -e "${BLUE}╔════════════════════════════════════╗${NC}"
205
+ echo -e "${BLUE}║ XCode Installer v3.0.0 ║${NC}"
206
+ echo -e "${BLUE}║ AI Coding with XMem Memory ║${NC}"
207
+ echo -e "${BLUE}╚════════════════════════════════════╝${NC}"
208
+ echo ""
209
+
210
+ check_dependencies
211
+ setup_directories
212
+ install_xcode
213
+ install_dependencies
214
+ create_launcher
215
+ update_path
216
+ setup_xmem
217
+ print_success
218
+ }
219
+
220
+ # Run main function
221
+ main "$@"