openfox 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.
Files changed (102) hide show
  1. package/README.md +68 -0
  2. package/dist/branch.api-WDHKZJS6.js +48 -0
  3. package/dist/branch.api-WDHKZJS6.js.map +1 -0
  4. package/dist/chunk-26NRL3HX.js +116 -0
  5. package/dist/chunk-26NRL3HX.js.map +1 -0
  6. package/dist/chunk-43SWNGYW.js +273 -0
  7. package/dist/chunk-43SWNGYW.js.map +1 -0
  8. package/dist/chunk-4Z2OZ6NX.js +132 -0
  9. package/dist/chunk-4Z2OZ6NX.js.map +1 -0
  10. package/dist/chunk-6MOGZMGX.js +218 -0
  11. package/dist/chunk-6MOGZMGX.js.map +1 -0
  12. package/dist/chunk-AF7XS4OI.js +55 -0
  13. package/dist/chunk-AF7XS4OI.js.map +1 -0
  14. package/dist/chunk-EI46G5WO.js +138 -0
  15. package/dist/chunk-EI46G5WO.js.map +1 -0
  16. package/dist/chunk-FF6Z2MC3.js +844 -0
  17. package/dist/chunk-FF6Z2MC3.js.map +1 -0
  18. package/dist/chunk-IKAWIOXM.js +5817 -0
  19. package/dist/chunk-IKAWIOXM.js.map +1 -0
  20. package/dist/chunk-IVHCPQO2.js +29 -0
  21. package/dist/chunk-IVHCPQO2.js.map +1 -0
  22. package/dist/chunk-MTX5Y3V3.js +46 -0
  23. package/dist/chunk-MTX5Y3V3.js.map +1 -0
  24. package/dist/chunk-N2XYX4ZA.js +83 -0
  25. package/dist/chunk-N2XYX4ZA.js.map +1 -0
  26. package/dist/chunk-QY7BMXWT.js +124 -0
  27. package/dist/chunk-QY7BMXWT.js.map +1 -0
  28. package/dist/chunk-U62ZECSQ.js +54 -0
  29. package/dist/chunk-U62ZECSQ.js.map +1 -0
  30. package/dist/chunk-YQ36AK5A.js +5570 -0
  31. package/dist/chunk-YQ36AK5A.js.map +1 -0
  32. package/dist/cli/dev.d.ts +1 -0
  33. package/dist/cli/dev.js +14 -0
  34. package/dist/cli/dev.js.map +1 -0
  35. package/dist/cli/index.d.ts +1 -0
  36. package/dist/cli/index.js +14 -0
  37. package/dist/cli/index.js.map +1 -0
  38. package/dist/command-defaults/defaults/commit-push.command.md +13 -0
  39. package/dist/command-defaults/defaults/init.command.md +18 -0
  40. package/dist/command-defaults/defaults/test-ui.command.md +16 -0
  41. package/dist/config-6GJ4SVFH.js +33 -0
  42. package/dist/config-6GJ4SVFH.js.map +1 -0
  43. package/dist/init-UVZDOHMX.js +185 -0
  44. package/dist/init-UVZDOHMX.js.map +1 -0
  45. package/dist/paths-4BPXWB2W.js +17 -0
  46. package/dist/paths-4BPXWB2W.js.map +1 -0
  47. package/dist/project-creator-CWPKRIKI.js +69 -0
  48. package/dist/project-creator-CWPKRIKI.js.map +1 -0
  49. package/dist/protocol-BJsm88OW.d.ts +760 -0
  50. package/dist/provider-LCE6WZA6.js +343 -0
  51. package/dist/provider-LCE6WZA6.js.map +1 -0
  52. package/dist/serve-27DZK34K.js +177 -0
  53. package/dist/serve-27DZK34K.js.map +1 -0
  54. package/dist/server/index.d.ts +479 -0
  55. package/dist/server/index.js +20 -0
  56. package/dist/server/index.js.map +1 -0
  57. package/dist/settings-D5O3TMLD.js +17 -0
  58. package/dist/settings-D5O3TMLD.js.map +1 -0
  59. package/dist/shared/index.d.ts +19 -0
  60. package/dist/shared/index.js +17 -0
  61. package/dist/shared/index.js.map +1 -0
  62. package/dist/skill-defaults/defaults/playwright-cli.skill.md +38 -0
  63. package/dist/tools-R4YQAYUF.js +46 -0
  64. package/dist/tools-R4YQAYUF.js.map +1 -0
  65. package/dist/web/assets/html2canvas.esm-QH1iLAAe.js +22 -0
  66. package/dist/web/assets/index-BMNDCsbJ.js +120 -0
  67. package/dist/web/assets/index-BSlSWZrM.css +1 -0
  68. package/dist/web/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
  69. package/dist/web/assets/jetbrains-mono-cyrillic-400-normal-ugxPyKxw.woff +0 -0
  70. package/dist/web/assets/jetbrains-mono-cyrillic-500-normal-DJqRU3vO.woff +0 -0
  71. package/dist/web/assets/jetbrains-mono-cyrillic-500-normal-DmUKJPL_.woff2 +0 -0
  72. package/dist/web/assets/jetbrains-mono-cyrillic-600-normal-8K4wrrwR.woff +0 -0
  73. package/dist/web/assets/jetbrains-mono-cyrillic-600-normal-EVf6-Yzo.woff2 +0 -0
  74. package/dist/web/assets/jetbrains-mono-greek-400-normal-B9oWc5Lo.woff +0 -0
  75. package/dist/web/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
  76. package/dist/web/assets/jetbrains-mono-greek-500-normal-D7SFKleX.woff +0 -0
  77. package/dist/web/assets/jetbrains-mono-greek-500-normal-JpySY46c.woff2 +0 -0
  78. package/dist/web/assets/jetbrains-mono-greek-600-normal-H7WoG9Et.woff2 +0 -0
  79. package/dist/web/assets/jetbrains-mono-greek-600-normal-mc2nkWzM.woff +0 -0
  80. package/dist/web/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
  81. package/dist/web/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
  82. package/dist/web/assets/jetbrains-mono-latin-500-normal-BWZEU5yA.woff2 +0 -0
  83. package/dist/web/assets/jetbrains-mono-latin-500-normal-CJOVTJB7.woff +0 -0
  84. package/dist/web/assets/jetbrains-mono-latin-600-normal-BfsvjouI.woff +0 -0
  85. package/dist/web/assets/jetbrains-mono-latin-600-normal-C8RAYTDA.woff2 +0 -0
  86. package/dist/web/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
  87. package/dist/web/assets/jetbrains-mono-latin-ext-400-normal-fXTG6kC5.woff +0 -0
  88. package/dist/web/assets/jetbrains-mono-latin-ext-500-normal-Cut-4mMH.woff2 +0 -0
  89. package/dist/web/assets/jetbrains-mono-latin-ext-500-normal-ckzbgY84.woff +0 -0
  90. package/dist/web/assets/jetbrains-mono-latin-ext-600-normal-BfB_LPfz.woff2 +0 -0
  91. package/dist/web/assets/jetbrains-mono-latin-ext-600-normal-DObL3zCW.woff +0 -0
  92. package/dist/web/assets/jetbrains-mono-vietnamese-400-normal-CqNFfHCs.woff +0 -0
  93. package/dist/web/assets/jetbrains-mono-vietnamese-500-normal-DNRqzVM1.woff +0 -0
  94. package/dist/web/assets/jetbrains-mono-vietnamese-600-normal-OWROknRo.woff +0 -0
  95. package/dist/web/assets/openfox.png +0 -0
  96. package/dist/web/fox.svg +25 -0
  97. package/dist/web/index.html +14 -0
  98. package/dist/web/sounds/achievement.mp3 +0 -0
  99. package/dist/web/sounds/intervention.mp3 +0 -0
  100. package/dist/web/sounds/notification.mp3 +0 -0
  101. package/dist/web/sounds/waiting-for-user.mp3 +0 -0
  102. package/package.json +101 -0
@@ -0,0 +1,132 @@
1
+ import {
2
+ logger
3
+ } from "./chunk-U62ZECSQ.js";
4
+
5
+ // src/server/db/index.ts
6
+ import Database from "better-sqlite3";
7
+ var db = null;
8
+ function initDatabase(config) {
9
+ if (db) {
10
+ return db;
11
+ }
12
+ logger.info("Initializing database", { path: config.database.path });
13
+ db = new Database(config.database.path);
14
+ db.pragma("journal_mode = WAL");
15
+ db.pragma("foreign_keys = ON");
16
+ runMigrations(db);
17
+ const result = db.prepare(`UPDATE sessions SET is_running = 0 WHERE is_running = 1`).run();
18
+ if (result.changes > 0) {
19
+ logger.info("Reset stale running states", { count: result.changes });
20
+ }
21
+ return db;
22
+ }
23
+ function getDatabase() {
24
+ if (!db) {
25
+ throw new Error("Database not initialized. Call initDatabase first.");
26
+ }
27
+ return db;
28
+ }
29
+ function runMigrations(db2) {
30
+ logger.info("Running database migrations");
31
+ db2.exec(`
32
+ CREATE TABLE IF NOT EXISTS projects (
33
+ id TEXT PRIMARY KEY,
34
+ name TEXT NOT NULL,
35
+ workdir TEXT NOT NULL UNIQUE,
36
+ created_at TEXT NOT NULL,
37
+ updated_at TEXT NOT NULL
38
+ )
39
+ `);
40
+ db2.exec(`
41
+ CREATE TABLE IF NOT EXISTS sessions (
42
+ id TEXT PRIMARY KEY,
43
+ project_id TEXT NOT NULL,
44
+ workdir TEXT NOT NULL,
45
+ phase TEXT NOT NULL DEFAULT 'idle',
46
+ created_at TEXT NOT NULL,
47
+ updated_at TEXT NOT NULL,
48
+ title TEXT,
49
+ total_tokens_used INTEGER DEFAULT 0,
50
+ total_tool_calls INTEGER DEFAULT 0,
51
+ iteration_count INTEGER DEFAULT 0,
52
+ FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
53
+ )
54
+ `);
55
+ db2.exec(`
56
+ CREATE INDEX IF NOT EXISTS idx_sessions_project ON sessions(project_id)
57
+ `);
58
+ const columns = db2.prepare(`PRAGMA table_info(sessions)`).all();
59
+ const columnNames = columns.map((c) => c.name);
60
+ if (!columnNames.includes("mode")) {
61
+ logger.info("Migrating sessions table: adding mode column");
62
+ db2.exec(`ALTER TABLE sessions ADD COLUMN mode TEXT NOT NULL DEFAULT 'planner'`);
63
+ db2.exec(`
64
+ UPDATE sessions SET mode = CASE
65
+ WHEN phase = 'idle' THEN 'planner'
66
+ WHEN phase = 'planning' THEN 'planner'
67
+ WHEN phase = 'executing' THEN 'builder'
68
+ WHEN phase = 'validating' THEN 'verifier'
69
+ WHEN phase = 'completed' THEN 'planner'
70
+ ELSE 'planner'
71
+ END
72
+ `);
73
+ }
74
+ if (!columnNames.includes("is_running")) {
75
+ logger.info("Migrating sessions table: adding is_running column");
76
+ db2.exec(`ALTER TABLE sessions ADD COLUMN is_running INTEGER NOT NULL DEFAULT 0`);
77
+ }
78
+ if (!columnNames.includes("summary")) {
79
+ logger.info("Migrating sessions table: adding summary column");
80
+ db2.exec(`ALTER TABLE sessions ADD COLUMN summary TEXT`);
81
+ }
82
+ if (!columnNames.includes("workflow_phase")) {
83
+ logger.info("Migrating sessions table: adding workflow_phase column");
84
+ db2.exec(`ALTER TABLE sessions ADD COLUMN workflow_phase TEXT NOT NULL DEFAULT 'plan'`);
85
+ }
86
+ db2.exec(`
87
+ CREATE TABLE IF NOT EXISTS settings (
88
+ key TEXT PRIMARY KEY,
89
+ value TEXT NOT NULL,
90
+ updated_at TEXT NOT NULL
91
+ )
92
+ `);
93
+ const projectColumns = db2.prepare(`PRAGMA table_info(projects)`).all();
94
+ const projectColumnNames = projectColumns.map((c) => c.name);
95
+ if (!projectColumnNames.includes("custom_instructions")) {
96
+ logger.info("Migrating projects table: adding custom_instructions column");
97
+ db2.exec(`ALTER TABLE projects ADD COLUMN custom_instructions TEXT`);
98
+ }
99
+ db2.exec(`
100
+ CREATE TABLE IF NOT EXISTS events (
101
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
102
+ session_id TEXT NOT NULL,
103
+ seq INTEGER NOT NULL,
104
+ timestamp INTEGER NOT NULL,
105
+ event_type TEXT NOT NULL,
106
+ payload TEXT NOT NULL,
107
+ UNIQUE(session_id, seq),
108
+ FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
109
+ )
110
+ `);
111
+ db2.exec(`
112
+ CREATE INDEX IF NOT EXISTS idx_events_session_seq ON events(session_id, seq)
113
+ `);
114
+ db2.exec(`
115
+ CREATE INDEX IF NOT EXISTS idx_events_session_type ON events(session_id, event_type)
116
+ `);
117
+ if (!columnNames.includes("provider_id")) {
118
+ logger.info("Migrating sessions table: adding provider_id column");
119
+ db2.exec(`ALTER TABLE sessions ADD COLUMN provider_id TEXT`);
120
+ }
121
+ if (!columnNames.includes("provider_model")) {
122
+ logger.info("Migrating sessions table: adding provider_model column");
123
+ db2.exec(`ALTER TABLE sessions ADD COLUMN provider_model TEXT`);
124
+ }
125
+ logger.info("Database migrations completed");
126
+ }
127
+
128
+ export {
129
+ initDatabase,
130
+ getDatabase
131
+ };
132
+ //# sourceMappingURL=chunk-4Z2OZ6NX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/server/db/index.ts"],"sourcesContent":["import Database from 'better-sqlite3'\nimport type { Config } from '../config.js'\nimport { logger } from '../utils/logger.js'\n\nlet db: Database.Database | null = null\n\nexport function initDatabase(config: Config): Database.Database {\n if (db) {\n return db\n }\n \n logger.info('Initializing database', { path: config.database.path })\n \n db = new Database(config.database.path)\n db.pragma('journal_mode = WAL')\n db.pragma('foreign_keys = ON')\n \n runMigrations(db)\n \n // Reset any stale running states from previous server runs\n // Sessions cannot actually be running when server starts\n const result = db.prepare(`UPDATE sessions SET is_running = 0 WHERE is_running = 1`).run()\n if (result.changes > 0) {\n logger.info('Reset stale running states', { count: result.changes })\n }\n \n return db\n}\n\nexport function getDatabase(): Database.Database {\n if (!db) {\n throw new Error('Database not initialized. Call initDatabase first.')\n }\n return db\n}\n\nexport function closeDatabase(): void {\n if (db) {\n db.close()\n db = null\n }\n}\n\nfunction runMigrations(db: Database.Database): void {\n logger.info('Running database migrations')\n \n // Create projects table\n db.exec(`\n CREATE TABLE IF NOT EXISTS projects (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n workdir TEXT NOT NULL UNIQUE,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n )\n `)\n \n // Create sessions table with project_id\n // Note: mode, phase, isRunning, summary are persisted here for quick access\n // Full session state (messages, criteria, todos) is derived from events table\n db.exec(`\n CREATE TABLE IF NOT EXISTS sessions (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL,\n workdir TEXT NOT NULL,\n phase TEXT NOT NULL DEFAULT 'idle',\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n title TEXT,\n total_tokens_used INTEGER DEFAULT 0,\n total_tool_calls INTEGER DEFAULT 0,\n iteration_count INTEGER DEFAULT 0,\n FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE\n )\n `)\n \n // Create indexes\n db.exec(`\n CREATE INDEX IF NOT EXISTS idx_sessions_project ON sessions(project_id)\n `)\n \n // Migration: Add mode, is_running, summary columns if they don't exist\n const columns = db.prepare(`PRAGMA table_info(sessions)`).all() as { name: string }[]\n const columnNames = columns.map(c => c.name)\n \n if (!columnNames.includes('mode')) {\n logger.info('Migrating sessions table: adding mode column')\n db.exec(`ALTER TABLE sessions ADD COLUMN mode TEXT NOT NULL DEFAULT 'planner'`)\n // Migrate existing phase values to mode\n db.exec(`\n UPDATE sessions SET mode = CASE\n WHEN phase = 'idle' THEN 'planner'\n WHEN phase = 'planning' THEN 'planner'\n WHEN phase = 'executing' THEN 'builder'\n WHEN phase = 'validating' THEN 'verifier'\n WHEN phase = 'completed' THEN 'planner'\n ELSE 'planner'\n END\n `)\n }\n \n if (!columnNames.includes('is_running')) {\n logger.info('Migrating sessions table: adding is_running column')\n db.exec(`ALTER TABLE sessions ADD COLUMN is_running INTEGER NOT NULL DEFAULT 0`)\n }\n \n if (!columnNames.includes('summary')) {\n logger.info('Migrating sessions table: adding summary column')\n db.exec(`ALTER TABLE sessions ADD COLUMN summary TEXT`)\n }\n \n // Note: The old 'phase' column was for the state machine (idle/planning/executing/etc.)\n // This new 'workflow_phase' column is for UI display (plan/build/verification/done)\n if (!columnNames.includes('workflow_phase')) {\n logger.info('Migrating sessions table: adding workflow_phase column')\n db.exec(`ALTER TABLE sessions ADD COLUMN workflow_phase TEXT NOT NULL DEFAULT 'plan'`)\n }\n \n // Create settings table for global configuration (e.g., global instructions)\n db.exec(`\n CREATE TABLE IF NOT EXISTS settings (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL,\n updated_at TEXT NOT NULL\n )\n `)\n \n // Migration: Add custom_instructions column to projects table\n const projectColumns = db.prepare(`PRAGMA table_info(projects)`).all() as { name: string }[]\n const projectColumnNames = projectColumns.map(c => c.name)\n \n if (!projectColumnNames.includes('custom_instructions')) {\n logger.info('Migrating projects table: adding custom_instructions column')\n db.exec(`ALTER TABLE projects ADD COLUMN custom_instructions TEXT`)\n }\n \n // Create events table for EventStore (single source of truth)\n // Note: EventStore creates this table with its own schema in initSchema()\n // We just ensure the index exists for the event_type column\n db.exec(`\n CREATE TABLE IF NOT EXISTS events (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n session_id TEXT NOT NULL,\n seq INTEGER NOT NULL,\n timestamp INTEGER NOT NULL,\n event_type TEXT NOT NULL,\n payload TEXT NOT NULL,\n UNIQUE(session_id, seq),\n FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE\n )\n `)\n \n db.exec(`\n CREATE INDEX IF NOT EXISTS idx_events_session_seq ON events(session_id, seq)\n `)\n \n db.exec(`\n CREATE INDEX IF NOT EXISTS idx_events_session_type ON events(session_id, event_type)\n `)\n \n // Migration: Add per-session provider/model columns\n if (!columnNames.includes('provider_id')) {\n logger.info('Migrating sessions table: adding provider_id column')\n db.exec(`ALTER TABLE sessions ADD COLUMN provider_id TEXT`)\n }\n\n if (!columnNames.includes('provider_model')) {\n logger.info('Migrating sessions table: adding provider_model column')\n db.exec(`ALTER TABLE sessions ADD COLUMN provider_model TEXT`)\n }\n\n logger.info('Database migrations completed')\n}\n"],"mappings":";;;;;AAAA,OAAO,cAAc;AAIrB,IAAI,KAA+B;AAE5B,SAAS,aAAa,QAAmC;AAC9D,MAAI,IAAI;AACN,WAAO;AAAA,EACT;AAEA,SAAO,KAAK,yBAAyB,EAAE,MAAM,OAAO,SAAS,KAAK,CAAC;AAEnE,OAAK,IAAI,SAAS,OAAO,SAAS,IAAI;AACtC,KAAG,OAAO,oBAAoB;AAC9B,KAAG,OAAO,mBAAmB;AAE7B,gBAAc,EAAE;AAIhB,QAAM,SAAS,GAAG,QAAQ,yDAAyD,EAAE,IAAI;AACzF,MAAI,OAAO,UAAU,GAAG;AACtB,WAAO,KAAK,8BAA8B,EAAE,OAAO,OAAO,QAAQ,CAAC;AAAA,EACrE;AAEA,SAAO;AACT;AAEO,SAAS,cAAiC;AAC/C,MAAI,CAAC,IAAI;AACP,UAAM,IAAI,MAAM,oDAAoD;AAAA,EACtE;AACA,SAAO;AACT;AASA,SAAS,cAAcA,KAA6B;AAClD,SAAO,KAAK,6BAA6B;AAGzC,EAAAA,IAAG,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAQP;AAKD,EAAAA,IAAG,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAcP;AAGD,EAAAA,IAAG,KAAK;AAAA;AAAA,GAEP;AAGD,QAAM,UAAUA,IAAG,QAAQ,6BAA6B,EAAE,IAAI;AAC9D,QAAM,cAAc,QAAQ,IAAI,OAAK,EAAE,IAAI;AAE3C,MAAI,CAAC,YAAY,SAAS,MAAM,GAAG;AACjC,WAAO,KAAK,8CAA8C;AAC1D,IAAAA,IAAG,KAAK,sEAAsE;AAE9E,IAAAA,IAAG,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KASP;AAAA,EACH;AAEA,MAAI,CAAC,YAAY,SAAS,YAAY,GAAG;AACvC,WAAO,KAAK,oDAAoD;AAChE,IAAAA,IAAG,KAAK,uEAAuE;AAAA,EACjF;AAEA,MAAI,CAAC,YAAY,SAAS,SAAS,GAAG;AACpC,WAAO,KAAK,iDAAiD;AAC7D,IAAAA,IAAG,KAAK,8CAA8C;AAAA,EACxD;AAIA,MAAI,CAAC,YAAY,SAAS,gBAAgB,GAAG;AAC3C,WAAO,KAAK,wDAAwD;AACpE,IAAAA,IAAG,KAAK,6EAA6E;AAAA,EACvF;AAGA,EAAAA,IAAG,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAMP;AAGD,QAAM,iBAAiBA,IAAG,QAAQ,6BAA6B,EAAE,IAAI;AACrE,QAAM,qBAAqB,eAAe,IAAI,OAAK,EAAE,IAAI;AAEzD,MAAI,CAAC,mBAAmB,SAAS,qBAAqB,GAAG;AACvD,WAAO,KAAK,6DAA6D;AACzE,IAAAA,IAAG,KAAK,0DAA0D;AAAA,EACpE;AAKA,EAAAA,IAAG,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAWP;AAED,EAAAA,IAAG,KAAK;AAAA;AAAA,GAEP;AAED,EAAAA,IAAG,KAAK;AAAA;AAAA,GAEP;AAGD,MAAI,CAAC,YAAY,SAAS,aAAa,GAAG;AACxC,WAAO,KAAK,qDAAqD;AACjE,IAAAA,IAAG,KAAK,kDAAkD;AAAA,EAC5D;AAEA,MAAI,CAAC,YAAY,SAAS,gBAAgB,GAAG;AAC3C,WAAO,KAAK,wDAAwD;AACpE,IAAAA,IAAG,KAAK,qDAAqD;AAAA,EAC/D;AAEA,SAAO,KAAK,+BAA+B;AAC7C;","names":["db"]}
@@ -0,0 +1,218 @@
1
+ import {
2
+ clearModelCache,
3
+ createLLMClient,
4
+ detectBackend,
5
+ detectModel
6
+ } from "./chunk-FF6Z2MC3.js";
7
+ import {
8
+ logger
9
+ } from "./chunk-U62ZECSQ.js";
10
+
11
+ // src/server/provider-manager.ts
12
+ async function fetchAvailableModelsFromBackend(baseUrl, apiKey) {
13
+ const url = baseUrl.includes("/v1") ? `${baseUrl}/models` : `${baseUrl}/v1/models`;
14
+ try {
15
+ const headers = {
16
+ "Content-Type": "application/json"
17
+ };
18
+ if (apiKey) {
19
+ headers["Authorization"] = `Bearer ${apiKey}`;
20
+ }
21
+ const response = await fetch(url, {
22
+ method: "GET",
23
+ headers,
24
+ signal: AbortSignal.timeout(1e4)
25
+ });
26
+ if (!response.ok) {
27
+ logger.debug("Failed to fetch models", { url, status: response.status });
28
+ return [];
29
+ }
30
+ const data = await response.json();
31
+ if (data.data && Array.isArray(data.data)) {
32
+ return data.data.map((m) => m.id).filter(Boolean);
33
+ }
34
+ return [];
35
+ } catch (error) {
36
+ logger.debug("Error fetching models from backend", { url, error: error instanceof Error ? error.message : String(error) });
37
+ return [];
38
+ }
39
+ }
40
+ function parseDefaultModelSelection(selection) {
41
+ if (!selection) return { providerId: void 0, model: void 0 };
42
+ const parts = selection.split("/");
43
+ return {
44
+ providerId: parts[0],
45
+ model: parts[1] ?? "auto"
46
+ };
47
+ }
48
+ function createProviderManager(config) {
49
+ let providers = [...config.providers ?? []];
50
+ const { providerId: initialProviderId, model: initialModel } = parseDefaultModelSelection(config.defaultModelSelection);
51
+ let defaultModelSelection = config.defaultModelSelection;
52
+ let llmClient = createLLMClient(config);
53
+ const providerStatus = /* @__PURE__ */ new Map();
54
+ for (const p of providers) {
55
+ providerStatus.set(p.id, "unknown");
56
+ }
57
+ function createConfigForProvider(provider, model) {
58
+ return {
59
+ ...config,
60
+ llm: {
61
+ ...config.llm,
62
+ baseUrl: provider.url.includes("/v1") ? provider.url : `${provider.url}/v1`,
63
+ model,
64
+ backend: provider.backend
65
+ }
66
+ };
67
+ }
68
+ return {
69
+ getProviders() {
70
+ return [...providers];
71
+ },
72
+ getActiveProvider() {
73
+ const { providerId } = parseDefaultModelSelection(defaultModelSelection);
74
+ if (!providerId) return void 0;
75
+ return providers.find((p) => p.id === providerId);
76
+ },
77
+ getActiveProviderId() {
78
+ const { providerId } = parseDefaultModelSelection(defaultModelSelection);
79
+ return providerId;
80
+ },
81
+ getCurrentModel() {
82
+ const { model } = parseDefaultModelSelection(defaultModelSelection);
83
+ return model;
84
+ },
85
+ getLLMClient() {
86
+ return llmClient;
87
+ },
88
+ async activateProvider(providerId, options) {
89
+ const provider = providers.find((p) => p.id === providerId);
90
+ if (!provider) {
91
+ return { success: false, error: "Provider not found" };
92
+ }
93
+ const currentModel = parseDefaultModelSelection(defaultModelSelection).model ?? "auto";
94
+ const targetModel = options?.model ?? currentModel;
95
+ const isModelSwitch = providerId === parseDefaultModelSelection(defaultModelSelection).providerId && options?.model && options.model !== currentModel;
96
+ if (providerId === parseDefaultModelSelection(defaultModelSelection).providerId && !isModelSwitch) {
97
+ return { success: true };
98
+ }
99
+ logger.info("Switching provider", {
100
+ from: parseDefaultModelSelection(defaultModelSelection).providerId,
101
+ to: providerId,
102
+ providerName: provider.name,
103
+ url: provider.url,
104
+ model: targetModel
105
+ });
106
+ const providerConfig = createConfigForProvider(provider, targetModel);
107
+ const newClient = createLLMClient(providerConfig);
108
+ try {
109
+ const url = provider.url.includes("/v1") ? provider.url.replace("/v1", "") : provider.url;
110
+ clearModelCache(url);
111
+ if (provider.backend === "auto") {
112
+ const detected = await detectBackend(url);
113
+ newClient.setBackend(detected);
114
+ } else {
115
+ newClient.setBackend(provider.backend);
116
+ }
117
+ if (targetModel === "auto") {
118
+ const detected = await detectModel(url);
119
+ if (detected) {
120
+ newClient.setModel(detected);
121
+ }
122
+ } else {
123
+ newClient.setModel(targetModel);
124
+ }
125
+ providerStatus.set(providerId, "connected");
126
+ } catch (err) {
127
+ logger.warn("Could not connect to provider", {
128
+ providerId,
129
+ error: err instanceof Error ? err.message : String(err)
130
+ });
131
+ providerStatus.set(providerId, "disconnected");
132
+ }
133
+ providers = providers.map((p) => ({
134
+ ...p,
135
+ isActive: p.id === providerId
136
+ }));
137
+ defaultModelSelection = `${providerId}/${targetModel}`;
138
+ llmClient = newClient;
139
+ logger.info("Provider activated", {
140
+ providerId,
141
+ providerName: provider.name,
142
+ model: llmClient.getModel(),
143
+ backend: llmClient.getBackend()
144
+ });
145
+ return { success: true };
146
+ },
147
+ addProvider(providerData) {
148
+ const id = crypto.randomUUID();
149
+ const provider = {
150
+ ...providerData,
151
+ id,
152
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
153
+ };
154
+ if (providerData.isActive || providers.length === 0) {
155
+ providers = providers.map((p) => ({ ...p, isActive: false }));
156
+ provider.isActive = true;
157
+ defaultModelSelection = `${id}/auto`;
158
+ }
159
+ providers.push(provider);
160
+ providerStatus.set(id, "unknown");
161
+ return provider;
162
+ },
163
+ removeProvider(providerId) {
164
+ const index = providers.findIndex((p) => p.id === providerId);
165
+ if (index === -1) return false;
166
+ const wasActive = providers[index]?.isActive;
167
+ providers.splice(index, 1);
168
+ providerStatus.delete(providerId);
169
+ if (wasActive && providers.length > 0) {
170
+ providers[0].isActive = true;
171
+ defaultModelSelection = `${providers[0].id}/auto`;
172
+ } else if (providers.length === 0) {
173
+ defaultModelSelection = void 0;
174
+ }
175
+ return true;
176
+ },
177
+ setProviders(newProviders, newDefaultModelSelection) {
178
+ providers = [...newProviders];
179
+ defaultModelSelection = newDefaultModelSelection;
180
+ providerStatus.clear();
181
+ for (const p of providers) {
182
+ providerStatus.set(p.id, "unknown");
183
+ }
184
+ },
185
+ getProviderStatus(providerId) {
186
+ return providerStatus.get(providerId) ?? "unknown";
187
+ },
188
+ async getProviderModels(providerId) {
189
+ const provider = providers.find((p) => p.id === providerId);
190
+ if (!provider) {
191
+ return [];
192
+ }
193
+ const url = provider.url.includes("/v1") ? provider.url.replace("/v1", "") : provider.url;
194
+ return fetchAvailableModelsFromBackend(url, provider.apiKey);
195
+ },
196
+ async setDefaultModelSelection(providerId, model) {
197
+ const provider = providers.find((p) => p.id === providerId);
198
+ if (!provider) {
199
+ return { success: false, error: "Provider not found" };
200
+ }
201
+ logger.info("Setting default model selection", { providerId, model, providerName: provider.name });
202
+ defaultModelSelection = `${providerId}/${model}`;
203
+ providers = providers.map((p) => ({ ...p, isActive: p.id === providerId }));
204
+ const currentProviderId = parseDefaultModelSelection(defaultModelSelection).providerId;
205
+ if (currentProviderId === providerId) {
206
+ llmClient.setModel(model);
207
+ logger.info("Model updated", { providerId, model });
208
+ }
209
+ return { success: true };
210
+ }
211
+ };
212
+ }
213
+
214
+ export {
215
+ fetchAvailableModelsFromBackend,
216
+ createProviderManager
217
+ };
218
+ //# sourceMappingURL=chunk-6MOGZMGX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/server/provider-manager.ts"],"sourcesContent":["import type { Provider, Config, LlmBackend } from '../shared/types.js'\nimport { createLLMClient, detectBackend, detectModel, clearModelCache, type LLMClientWithModel } from './llm/index.js'\nimport { logger } from './utils/logger.js'\n\n/** Fetch available models from a provider's backend */\nexport async function fetchAvailableModelsFromBackend(baseUrl: string, apiKey?: string): Promise<string[]> {\n const url = baseUrl.includes('/v1') ? `${baseUrl}/models` : `${baseUrl}/v1/models`\n\n try {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n }\n if (apiKey) {\n headers['Authorization'] = `Bearer ${apiKey}`\n }\n\n const response = await fetch(url, {\n method: 'GET',\n headers,\n signal: AbortSignal.timeout(10000),\n })\n\n if (!response.ok) {\n logger.debug('Failed to fetch models', { url, status: response.status })\n return []\n }\n\n const data = await response.json() as { data?: Array<{ id: string }> }\n if (data.data && Array.isArray(data.data)) {\n return data.data.map(m => m.id).filter(Boolean)\n }\n\n return []\n } catch (error) {\n logger.debug('Error fetching models from backend', { url, error: error instanceof Error ? error.message : String(error) })\n return []\n }\n}\n\nexport interface ProviderManager {\n getProviders(): Provider[]\n getActiveProvider(): Provider | undefined\n getActiveProviderId(): string | undefined\n getCurrentModel(): string | undefined\n getLLMClient(): LLMClientWithModel\n activateProvider(providerId: string, options?: { model?: string }): Promise<{ success: boolean; error?: string }>\n addProvider(provider: Omit<Provider, 'id' | 'createdAt'>): Provider\n removeProvider(providerId: string): boolean\n setProviders(providers: Provider[], defaultModelSelection?: string): void\n getProviderStatus(providerId: string): 'connected' | 'disconnected' | 'unknown'\n getProviderModels(providerId: string): Promise<string[]>\n setDefaultModelSelection(providerId: string, model: string): Promise<{ success: boolean; error?: string }>\n}\n\nfunction parseDefaultModelSelection(selection?: string): { providerId: string | undefined; model: string | undefined } {\n if (!selection) return { providerId: undefined, model: undefined }\n const parts = selection.split('/')\n return {\n providerId: parts[0],\n model: parts[1] ?? 'auto',\n }\n}\n\nexport function createProviderManager(config: Config): ProviderManager {\n let providers: Provider[] = [...(config.providers ?? [])]\n const { providerId: initialProviderId, model: initialModel } = parseDefaultModelSelection(config.defaultModelSelection)\n let defaultModelSelection: string | undefined = config.defaultModelSelection\n let llmClient = createLLMClient(config)\n const providerStatus = new Map<string, 'connected' | 'disconnected' | 'unknown'>()\n \n for (const p of providers) {\n providerStatus.set(p.id, 'unknown')\n }\n \n function createConfigForProvider(provider: Provider, model: string): Config {\n return {\n ...config,\n llm: {\n ...config.llm,\n baseUrl: provider.url.includes('/v1') ? provider.url : `${provider.url}/v1`,\n model,\n backend: provider.backend as LlmBackend | 'auto',\n },\n }\n }\n \n return {\n getProviders() {\n return [...providers]\n },\n \n getActiveProvider() {\n const { providerId } = parseDefaultModelSelection(defaultModelSelection)\n if (!providerId) return undefined\n return providers.find(p => p.id === providerId)\n },\n \n getActiveProviderId() {\n const { providerId } = parseDefaultModelSelection(defaultModelSelection)\n return providerId\n },\n \n getCurrentModel() {\n const { model } = parseDefaultModelSelection(defaultModelSelection)\n return model\n },\n \n getLLMClient() {\n return llmClient\n },\n \n async activateProvider(providerId: string, options?: { model?: string }) {\n const provider = providers.find(p => p.id === providerId)\n if (!provider) {\n return { success: false, error: 'Provider not found' }\n }\n\n const currentModel = parseDefaultModelSelection(defaultModelSelection).model ?? 'auto'\n const targetModel = options?.model ?? currentModel\n const isModelSwitch = providerId === parseDefaultModelSelection(defaultModelSelection).providerId && options?.model && options.model !== currentModel\n \n if (providerId === parseDefaultModelSelection(defaultModelSelection).providerId && !isModelSwitch) {\n return { success: true }\n }\n\n logger.info('Switching provider', {\n from: parseDefaultModelSelection(defaultModelSelection).providerId,\n to: providerId,\n providerName: provider.name,\n url: provider.url,\n model: targetModel,\n })\n\n const providerConfig = createConfigForProvider(provider, targetModel)\n const newClient = createLLMClient(providerConfig)\n\n try {\n const url = provider.url.includes('/v1') ? provider.url.replace('/v1', '') : provider.url\n clearModelCache(url)\n\n if (provider.backend === 'auto') {\n const detected = await detectBackend(url)\n newClient.setBackend(detected)\n } else {\n newClient.setBackend(provider.backend as LlmBackend)\n }\n\n if (targetModel === 'auto') {\n const detected = await detectModel(url)\n if (detected) {\n newClient.setModel(detected)\n }\n } else {\n newClient.setModel(targetModel)\n }\n\n providerStatus.set(providerId, 'connected')\n } catch (err) {\n logger.warn('Could not connect to provider', {\n providerId,\n error: err instanceof Error ? err.message : String(err),\n })\n providerStatus.set(providerId, 'disconnected')\n }\n\n providers = providers.map(p => ({\n ...p,\n isActive: p.id === providerId,\n }))\n defaultModelSelection = `${providerId}/${targetModel}`\n llmClient = newClient\n\n logger.info('Provider activated', {\n providerId,\n providerName: provider.name,\n model: llmClient.getModel(),\n backend: llmClient.getBackend(),\n })\n\n return { success: true }\n },\n \n addProvider(providerData) {\n const id = crypto.randomUUID()\n const provider: Provider = {\n ...providerData,\n id,\n createdAt: new Date().toISOString(),\n }\n \n if (providerData.isActive || providers.length === 0) {\n providers = providers.map(p => ({ ...p, isActive: false }))\n provider.isActive = true\n defaultModelSelection = `${id}/auto`\n }\n \n providers.push(provider)\n providerStatus.set(id, 'unknown')\n \n return provider\n },\n \n removeProvider(providerId) {\n const index = providers.findIndex(p => p.id === providerId)\n if (index === -1) return false\n \n const wasActive = providers[index]?.isActive\n providers.splice(index, 1)\n providerStatus.delete(providerId)\n \n if (wasActive && providers.length > 0) {\n providers[0]!.isActive = true\n defaultModelSelection = `${providers[0]!.id}/auto`\n } else if (providers.length === 0) {\n defaultModelSelection = undefined\n }\n \n return true\n },\n \n setProviders(newProviders, newDefaultModelSelection) {\n providers = [...newProviders]\n defaultModelSelection = newDefaultModelSelection\n \n providerStatus.clear()\n for (const p of providers) {\n providerStatus.set(p.id, 'unknown')\n }\n },\n \n getProviderStatus(providerId) {\n return providerStatus.get(providerId) ?? 'unknown'\n },\n\n async getProviderModels(providerId: string): Promise<string[]> {\n const provider = providers.find(p => p.id === providerId)\n if (!provider) {\n return []\n }\n\n const url = provider.url.includes('/v1') ? provider.url.replace('/v1', '') : provider.url\n return fetchAvailableModelsFromBackend(url, provider.apiKey)\n },\n\n async setDefaultModelSelection(providerId: string, model: string) {\n const provider = providers.find(p => p.id === providerId)\n if (!provider) {\n return { success: false, error: 'Provider not found' }\n }\n\n logger.info('Setting default model selection', { providerId, model, providerName: provider.name })\n\n defaultModelSelection = `${providerId}/${model}`\n providers = providers.map(p => ({ ...p, isActive: p.id === providerId }))\n\n const currentProviderId = parseDefaultModelSelection(defaultModelSelection).providerId\n if (currentProviderId === providerId) {\n llmClient.setModel(model)\n logger.info('Model updated', { providerId, model })\n }\n\n return { success: true }\n },\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,55 @@
1
+ // src/cli/paths.ts
2
+ import { homedir, platform } from "os";
3
+ import { join } from "path";
4
+ import { mkdir, access } from "fs/promises";
5
+ function getGlobalConfigDir(mode) {
6
+ const suffix = mode === "development" ? "-dev" : "";
7
+ const home = homedir();
8
+ switch (platform()) {
9
+ case "darwin":
10
+ return join(home, "Library", "Application Support", `openfox${suffix}`);
11
+ case "win32":
12
+ return join(process.env["APPDATA"] ?? join(home, "AppData", "Roaming"), `openfox${suffix}`);
13
+ default:
14
+ return join(process.env["XDG_CONFIG_HOME"] ?? join(home, ".config"), `openfox${suffix}`);
15
+ }
16
+ }
17
+ function getGlobalConfigPath(mode) {
18
+ return join(getGlobalConfigDir(mode), "config.json");
19
+ }
20
+ function getGlobalDataDir(mode) {
21
+ const suffix = mode === "development" ? "-dev" : "";
22
+ const home = homedir();
23
+ switch (platform()) {
24
+ case "darwin":
25
+ return join(home, "Library", "Application Support", `openfox${suffix}`);
26
+ case "win32":
27
+ return join(process.env["LOCALAPPDATA"] ?? join(home, "AppData", "Local"), `openfox${suffix}`);
28
+ default:
29
+ return join(process.env["XDG_DATA_HOME"] ?? join(home, ".local", "share"), `openfox${suffix}`);
30
+ }
31
+ }
32
+ function getDatabasePath(mode) {
33
+ return join(getGlobalDataDir(mode), "sessions.db");
34
+ }
35
+ function getSkillsDir(mode) {
36
+ return join(getGlobalConfigDir(mode), "skills");
37
+ }
38
+ async function ensureDataDirExists(mode) {
39
+ const dataDir = getGlobalDataDir(mode);
40
+ try {
41
+ await access(dataDir);
42
+ } catch {
43
+ await mkdir(dataDir, { recursive: true });
44
+ }
45
+ }
46
+
47
+ export {
48
+ getGlobalConfigDir,
49
+ getGlobalConfigPath,
50
+ getGlobalDataDir,
51
+ getDatabasePath,
52
+ getSkillsDir,
53
+ ensureDataDirExists
54
+ };
55
+ //# sourceMappingURL=chunk-AF7XS4OI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/paths.ts"],"sourcesContent":["import { homedir, platform } from 'node:os'\nimport { join } from 'node:path'\nimport { mkdir, access } from 'node:fs/promises'\nimport type { Mode } from './main.js'\n\nexport function getGlobalConfigDir(mode: Mode): string {\n const suffix = mode === 'development' ? '-dev' : ''\n const home = homedir()\n \n switch (platform()) {\n case 'darwin':\n return join(home, 'Library', 'Application Support', `openfox${suffix}`)\n case 'win32':\n return join(process.env['APPDATA'] ?? join(home, 'AppData', 'Roaming'), `openfox${suffix}`)\n default:\n return join(process.env['XDG_CONFIG_HOME'] ?? join(home, '.config'), `openfox${suffix}`)\n }\n}\n\nexport function getGlobalConfigPath(mode: Mode): string {\n return join(getGlobalConfigDir(mode), 'config.json')\n}\n\nexport function getGlobalDataDir(mode: Mode): string {\n const suffix = mode === 'development' ? '-dev' : ''\n const home = homedir()\n \n switch (platform()) {\n case 'darwin':\n return join(home, 'Library', 'Application Support', `openfox${suffix}`)\n case 'win32':\n return join(process.env['LOCALAPPDATA'] ?? join(home, 'AppData', 'Local'), `openfox${suffix}`)\n default:\n return join(process.env['XDG_DATA_HOME'] ?? join(home, '.local', 'share'), `openfox${suffix}`)\n }\n}\n\nexport function getDatabasePath(mode: Mode): string {\n return join(getGlobalDataDir(mode), 'sessions.db')\n}\n\nexport function getSkillsDir(mode: Mode): string {\n return join(getGlobalConfigDir(mode), 'skills')\n}\n\nexport async function ensureDataDirExists(mode: Mode): Promise<void> {\n const dataDir = getGlobalDataDir(mode)\n try {\n await access(dataDir)\n } catch {\n await mkdir(dataDir, { recursive: true })\n }\n}\n"],"mappings":";AAAA,SAAS,SAAS,gBAAgB;AAClC,SAAS,YAAY;AACrB,SAAS,OAAO,cAAc;AAGvB,SAAS,mBAAmB,MAAoB;AACrD,QAAM,SAAS,SAAS,gBAAgB,SAAS;AACjD,QAAM,OAAO,QAAQ;AAErB,UAAQ,SAAS,GAAG;AAAA,IAClB,KAAK;AACH,aAAO,KAAK,MAAM,WAAW,uBAAuB,UAAU,MAAM,EAAE;AAAA,IACxE,KAAK;AACH,aAAO,KAAK,QAAQ,IAAI,SAAS,KAAK,KAAK,MAAM,WAAW,SAAS,GAAG,UAAU,MAAM,EAAE;AAAA,IAC5F;AACE,aAAO,KAAK,QAAQ,IAAI,iBAAiB,KAAK,KAAK,MAAM,SAAS,GAAG,UAAU,MAAM,EAAE;AAAA,EAC3F;AACF;AAEO,SAAS,oBAAoB,MAAoB;AACtD,SAAO,KAAK,mBAAmB,IAAI,GAAG,aAAa;AACrD;AAEO,SAAS,iBAAiB,MAAoB;AACnD,QAAM,SAAS,SAAS,gBAAgB,SAAS;AACjD,QAAM,OAAO,QAAQ;AAErB,UAAQ,SAAS,GAAG;AAAA,IAClB,KAAK;AACH,aAAO,KAAK,MAAM,WAAW,uBAAuB,UAAU,MAAM,EAAE;AAAA,IACxE,KAAK;AACH,aAAO,KAAK,QAAQ,IAAI,cAAc,KAAK,KAAK,MAAM,WAAW,OAAO,GAAG,UAAU,MAAM,EAAE;AAAA,IAC/F;AACE,aAAO,KAAK,QAAQ,IAAI,eAAe,KAAK,KAAK,MAAM,UAAU,OAAO,GAAG,UAAU,MAAM,EAAE;AAAA,EACjG;AACF;AAEO,SAAS,gBAAgB,MAAoB;AAClD,SAAO,KAAK,iBAAiB,IAAI,GAAG,aAAa;AACnD;AAEO,SAAS,aAAa,MAAoB;AAC/C,SAAO,KAAK,mBAAmB,IAAI,GAAG,QAAQ;AAChD;AAEA,eAAsB,oBAAoB,MAA2B;AACnE,QAAM,UAAU,iBAAiB,IAAI;AACrC,MAAI;AACF,UAAM,OAAO,OAAO;AAAA,EACtB,QAAQ;AACN,UAAM,MAAM,SAAS,EAAE,WAAW,KAAK,CAAC;AAAA,EAC1C;AACF;","names":[]}
@@ -0,0 +1,138 @@
1
+ // src/cli/main.ts
2
+ import { parseArgs } from "util";
3
+ function printHelp() {
4
+ console.log(`
5
+ OpenFox - Local LLM coding assistant
6
+
7
+ Usage:
8
+ openfox [command] [options]
9
+
10
+ Commands:
11
+ (none) Start server for current project
12
+ init Interactive configuration setup
13
+ config Show current configuration
14
+ provider add Add a new LLM provider
15
+ provider list List configured providers
16
+ provider use Switch active provider
17
+ provider remove Remove a provider
18
+
19
+ Options:
20
+ -p, --port <number> Specify port (default: 10369 for prod, 10469 for dev)
21
+ --no-browser Don't open browser on start
22
+ -h, --help Show this help message
23
+ -v, --version Show version number
24
+ `);
25
+ }
26
+ async function runConfig(mode) {
27
+ const { loadGlobalConfig, getActiveProvider, getDefaultModel } = await import("./config-6GJ4SVFH.js");
28
+ const { getGlobalConfigPath } = await import("./paths-4BPXWB2W.js");
29
+ const config = await loadGlobalConfig(mode);
30
+ const configPath = getGlobalConfigPath(mode);
31
+ const activeProvider = getActiveProvider(config);
32
+ const defaultModel = getDefaultModel(config);
33
+ console.log(`Configuration (${mode}):`);
34
+ console.log(` Location: ${configPath}`);
35
+ console.log(` Providers: ${config.providers.length}`);
36
+ if (activeProvider) {
37
+ console.log(` Active: ${activeProvider.name}`);
38
+ console.log(` URL: ${activeProvider.url}`);
39
+ console.log(` Model: ${defaultModel ?? "auto"}`);
40
+ console.log(` Backend: ${activeProvider.backend}`);
41
+ } else {
42
+ console.log(` Active: (none configured)`);
43
+ }
44
+ const hostDisplay = config.server.host === "0.0.0.0" ? `${config.server.host} (accessible from local network)` : `${config.server.host} (localhost only)`;
45
+ console.log(` Server: ${hostDisplay}`);
46
+ console.log(` Port: ${config.server.port}`);
47
+ }
48
+ async function runCli(options) {
49
+ const { mode } = options;
50
+ const { values, positionals } = parseArgs({
51
+ options: {
52
+ port: { type: "string", short: "p" },
53
+ "no-browser": { type: "boolean" },
54
+ help: { type: "boolean", short: "h" },
55
+ version: { type: "boolean", short: "v" }
56
+ },
57
+ allowPositionals: true,
58
+ strict: true
59
+ });
60
+ if (values.help) {
61
+ printHelp();
62
+ process.exit(0);
63
+ }
64
+ if (values.version) {
65
+ console.log("0.1.0");
66
+ process.exit(0);
67
+ }
68
+ const [command] = positionals;
69
+ switch (command) {
70
+ case "init": {
71
+ const { runInitWithSelect } = await import("./init-UVZDOHMX.js");
72
+ const { loadGlobalConfig, getActiveProvider } = await import("./config-6GJ4SVFH.js");
73
+ const config = await loadGlobalConfig(mode);
74
+ const activeProvider = getActiveProvider(config);
75
+ if (activeProvider) {
76
+ console.log(`Current provider: ${activeProvider.name} (${activeProvider.url})
77
+ `);
78
+ }
79
+ await runInitWithSelect(mode, config);
80
+ break;
81
+ }
82
+ case "config": {
83
+ await runConfig(mode);
84
+ break;
85
+ }
86
+ case "provider": {
87
+ const { runProviderCommand } = await import("./provider-LCE6WZA6.js");
88
+ const [, subcommand] = positionals;
89
+ await runProviderCommand(mode, subcommand);
90
+ break;
91
+ }
92
+ default: {
93
+ const { configFileExists } = await import("./config-6GJ4SVFH.js");
94
+ const configExists = await configFileExists(mode);
95
+ if (!configExists) {
96
+ console.log("Welcome to OpenFox!\n");
97
+ const { trySmartDefaults, saveGlobalConfig, addProvider } = await import("./config-6GJ4SVFH.js");
98
+ const detected = await trySmartDefaults(mode);
99
+ if (detected) {
100
+ console.log(`\u2713 Found ${detected.backend} (${detected.model}) at ${detected.url}`);
101
+ const baseConfig = {
102
+ providers: [],
103
+ server: { port: 10369, host: "127.0.0.1", openBrowser: true },
104
+ logging: { level: "info" },
105
+ database: { path: "" },
106
+ workspace: { workdir: process.cwd() }
107
+ };
108
+ const configWithProvider = addProvider(baseConfig, {
109
+ name: "Default",
110
+ url: detected.url,
111
+ backend: detected.backend,
112
+ maxContext: 2e5,
113
+ isActive: true
114
+ });
115
+ const { setDefaultModelSelection } = await import("./config-6GJ4SVFH.js");
116
+ const finalConfig = setDefaultModelSelection(configWithProvider, configWithProvider.providers[0].id, detected.model);
117
+ await saveGlobalConfig(mode, finalConfig);
118
+ console.log("Configuration saved!\n");
119
+ } else {
120
+ console.log("\u2717 No LLM server detected\n");
121
+ const { runInitWithSelect } = await import("./init-UVZDOHMX.js");
122
+ await runInitWithSelect(mode);
123
+ }
124
+ }
125
+ const { runServe } = await import("./serve-27DZK34K.js");
126
+ await runServe({
127
+ mode,
128
+ port: values.port ? parseInt(values.port) : void 0,
129
+ openBrowser: !values["no-browser"]
130
+ });
131
+ }
132
+ }
133
+ }
134
+
135
+ export {
136
+ runCli
137
+ };
138
+ //# sourceMappingURL=chunk-EI46G5WO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/main.ts"],"sourcesContent":["import { parseArgs } from 'node:util'\n\nexport type Mode = 'production' | 'development'\n\nexport function printHelp(): void {\n console.log(`\nOpenFox - Local LLM coding assistant\n\nUsage:\n openfox [command] [options]\n\nCommands:\n (none) Start server for current project\n init Interactive configuration setup\n config Show current configuration\n provider add Add a new LLM provider\n provider list List configured providers\n provider use Switch active provider\n provider remove Remove a provider\n\nOptions:\n -p, --port <number> Specify port (default: 10369 for prod, 10469 for dev)\n --no-browser Don't open browser on start\n -h, --help Show this help message\n -v, --version Show version number\n`)\n}\n\nexport async function runConfig(mode: Mode): Promise<void> {\n const { loadGlobalConfig, getActiveProvider, getDefaultModel } = await import('./config.js')\n const { getGlobalConfigPath } = await import('./paths.js')\n \n const config = await loadGlobalConfig(mode)\n const configPath = getGlobalConfigPath(mode)\n const activeProvider = getActiveProvider(config)\n const defaultModel = getDefaultModel(config)\n \n console.log(`Configuration (${mode}):`)\n console.log(` Location: ${configPath}`)\n console.log(` Providers: ${config.providers.length}`)\n if (activeProvider) {\n console.log(` Active: ${activeProvider.name}`)\n console.log(` URL: ${activeProvider.url}`)\n console.log(` Model: ${defaultModel ?? 'auto'}`)\n console.log(` Backend: ${activeProvider.backend}`)\n } else {\n console.log(` Active: (none configured)`)\n }\n \n // Display server host with human-readable description\n const hostDisplay = config.server.host === '0.0.0.0' \n ? `${config.server.host} (accessible from local network)`\n : `${config.server.host} (localhost only)`\n console.log(` Server: ${hostDisplay}`)\n console.log(` Port: ${config.server.port}`)\n}\n\nexport async function runCli(options: { mode: Mode }): Promise<void> {\n const { mode } = options\n \n const { values, positionals } = parseArgs({\n options: {\n port: { type: 'string', short: 'p' },\n 'no-browser': { type: 'boolean' },\n help: { type: 'boolean', short: 'h' },\n version: { type: 'boolean', short: 'v' },\n },\n allowPositionals: true,\n strict: true,\n })\n\n if (values.help) {\n printHelp()\n process.exit(0)\n }\n\n if (values.version) {\n console.log('0.1.0')\n process.exit(0)\n }\n\n const [command] = positionals\n\n switch (command) {\n case 'init': {\n const { runInitWithSelect } = await import('./init.js')\n const { loadGlobalConfig, getActiveProvider } = await import('./config.js')\n const config = await loadGlobalConfig(mode)\n const activeProvider = getActiveProvider(config)\n if (activeProvider) {\n console.log(`Current provider: ${activeProvider.name} (${activeProvider.url})\\n`)\n }\n // Pass existing config to init for potential preservation\n await runInitWithSelect(mode, config)\n break\n }\n case 'config': {\n await runConfig(mode)\n break\n }\n case 'provider': {\n const { runProviderCommand } = await import('./provider.js')\n const [, subcommand] = positionals\n await runProviderCommand(mode, subcommand)\n break\n }\n default: {\n // Check if config exists - only run wizard on first install\n const { configFileExists } = await import('./config.js')\n const configExists = await configFileExists(mode)\n \n if (!configExists) {\n // First run - show welcome message\n console.log('Welcome to OpenFox!\\n')\n \n // Try smart defaults in parallel (silent - no logs)\n const { trySmartDefaults, saveGlobalConfig, addProvider } = await import('./config.js')\n const detected = await trySmartDefaults(mode)\n \n if (detected) {\n console.log(`✓ Found ${detected.backend} (${detected.model}) at ${detected.url}`)\n const baseConfig = {\n providers: [],\n server: { port: 10369, host: '127.0.0.1', openBrowser: true },\n logging: { level: 'info' as const },\n database: { path: '' },\n workspace: { workdir: process.cwd() },\n }\n const configWithProvider = addProvider(baseConfig, {\n name: 'Default',\n url: detected.url,\n backend: detected.backend as 'auto' | 'vllm' | 'sglang' | 'ollama' | 'llamacpp',\n maxContext: 200000,\n isActive: true,\n })\n // Set the default model selection after adding provider\n const { setDefaultModelSelection } = await import('./config.js')\n const finalConfig = setDefaultModelSelection(configWithProvider, configWithProvider.providers[0]!.id, detected.model)\n await saveGlobalConfig(mode, finalConfig)\n console.log('Configuration saved!\\n')\n } else {\n console.log('✗ No LLM server detected\\n')\n const { runInitWithSelect } = await import('./init.js')\n await runInitWithSelect(mode)\n }\n }\n \n const { runServe } = await import('./serve.js')\n await runServe({\n mode,\n port: values.port ? parseInt(values.port) : undefined,\n openBrowser: !values['no-browser'],\n } as any)\n }\n }\n}\n"],"mappings":"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","names":[]}