adhdev 0.1.50 → 0.1.51

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/dist/index.js CHANGED
@@ -4510,16 +4510,16 @@ var init_daemon_commands = __esm({
4510
4510
  async handleReadChat(args) {
4511
4511
  const provider2 = this.getProvider();
4512
4512
  const _log = (msg) => console.log(`[read_chat] ${msg}`);
4513
- if (provider2?.category === "cli") {
4513
+ if (provider2?.category === "cli" || provider2?.category === "acp") {
4514
4514
  const adapter = this.getCliAdapter(provider2.type);
4515
4515
  if (adapter) {
4516
- _log(`CLI adapter: ${adapter.cliType}`);
4516
+ _log(`${provider2.category} adapter: ${adapter.cliType}`);
4517
4517
  const status = adapter.getStatus?.();
4518
4518
  if (status) {
4519
4519
  return { success: true, messages: status.messages || [], status: status.status, activeModal: status.activeModal };
4520
4520
  }
4521
4521
  }
4522
- return { success: false, error: "CLI adapter not found" };
4522
+ return { success: false, error: `${provider2.category} adapter not found` };
4523
4523
  }
4524
4524
  if (provider2?.category === "extension") {
4525
4525
  try {
@@ -4575,15 +4575,15 @@ var init_daemon_commands = __esm({
4575
4575
  if (!text) return { success: false, error: "text required" };
4576
4576
  const _log = (msg) => console.log(`[send_chat] ${msg}`);
4577
4577
  const provider2 = this.getProvider();
4578
- if (provider2?.category === "cli") {
4578
+ if (provider2?.category === "cli" || provider2?.category === "acp") {
4579
4579
  const adapter = this.getCliAdapter(provider2.type);
4580
4580
  if (adapter) {
4581
- _log(`CLI adapter: ${adapter.cliType}`);
4581
+ _log(`${provider2.category} adapter: ${adapter.cliType}`);
4582
4582
  try {
4583
4583
  await adapter.sendMessage(text);
4584
- return { success: true, sent: true, method: "cli-adapter", targetAgent: adapter.cliType };
4584
+ return { success: true, sent: true, method: `${provider2.category}-adapter`, targetAgent: adapter.cliType };
4585
4585
  } catch (e) {
4586
- return { success: false, error: `CLI send failed: ${e.message}` };
4586
+ return { success: false, error: `${provider2.category} send failed: ${e.message}` };
4587
4587
  }
4588
4588
  }
4589
4589
  }
@@ -6917,18 +6917,545 @@ var init_cli_provider_instance = __esm({
6917
6917
  }
6918
6918
  });
6919
6919
 
6920
+ // src/providers/acp-provider-instance.ts
6921
+ var path9, crypto, import_child_process6, import_readline, AcpProviderInstance;
6922
+ var init_acp_provider_instance = __esm({
6923
+ "src/providers/acp-provider-instance.ts"() {
6924
+ "use strict";
6925
+ path9 = __toESM(require("path"));
6926
+ crypto = __toESM(require("crypto"));
6927
+ import_child_process6 = require("child_process");
6928
+ import_readline = require("readline");
6929
+ init_status_monitor();
6930
+ AcpProviderInstance = class {
6931
+ constructor(provider2, workingDir, cliArgs = []) {
6932
+ this.cliArgs = cliArgs;
6933
+ this.type = provider2.type;
6934
+ this.provider = provider2;
6935
+ this.workingDir = workingDir;
6936
+ this.instanceId = `acp_${provider2.type}_${crypto.createHash("md5").update(require("os").hostname() + provider2.type + workingDir).digest("hex").slice(0, 8)}`;
6937
+ this.monitor = new StatusMonitor();
6938
+ }
6939
+ type;
6940
+ category = "acp";
6941
+ provider;
6942
+ context = null;
6943
+ settings = {};
6944
+ events = [];
6945
+ monitor;
6946
+ // Process
6947
+ process = null;
6948
+ readline = null;
6949
+ requestId = 1;
6950
+ pendingRequests = /* @__PURE__ */ new Map();
6951
+ // State
6952
+ sessionId = null;
6953
+ messages = [];
6954
+ currentStatus = "starting";
6955
+ lastStatus = "starting";
6956
+ generatingStartedAt = 0;
6957
+ agentCapabilities = {};
6958
+ currentModel;
6959
+ currentMode;
6960
+ activeToolCalls = [];
6961
+ stopReason = null;
6962
+ partialContent = "";
6963
+ // Config
6964
+ workingDir;
6965
+ instanceId;
6966
+ // ─── Lifecycle ─────────────────────────────────
6967
+ async init(context) {
6968
+ this.context = context;
6969
+ this.settings = context.settings || {};
6970
+ this.monitor.updateConfig({
6971
+ approvalAlert: this.settings.approvalAlert !== false,
6972
+ longGeneratingAlert: this.settings.longGeneratingAlert !== false,
6973
+ longGeneratingThresholdSec: this.settings.longGeneratingThresholdSec || 180
6974
+ });
6975
+ await this.spawnAgent();
6976
+ }
6977
+ async onTick() {
6978
+ if (this.process && this.process.exitCode !== null) {
6979
+ this.currentStatus = "stopped";
6980
+ this.detectStatusTransition();
6981
+ }
6982
+ }
6983
+ getState() {
6984
+ const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
6985
+ const recentMessages = this.messages.slice(-50).map((m) => ({
6986
+ role: m.role,
6987
+ content: m.content.length > 2e3 ? m.content.slice(0, 2e3) + "\n... (truncated)" : m.content,
6988
+ timestamp: m.timestamp
6989
+ }));
6990
+ if (this.currentStatus === "generating" && this.partialContent) {
6991
+ const cleaned = this.partialContent.trim();
6992
+ if (cleaned) {
6993
+ recentMessages.push({
6994
+ role: "assistant",
6995
+ content: (cleaned.length > 2e3 ? cleaned.slice(0, 2e3) + "..." : cleaned) + "...",
6996
+ timestamp: Date.now()
6997
+ });
6998
+ }
6999
+ }
7000
+ return {
7001
+ type: this.type,
7002
+ name: this.provider.name,
7003
+ category: "acp",
7004
+ status: this.currentStatus,
7005
+ mode: "chat",
7006
+ activeChat: {
7007
+ id: this.sessionId || `${this.type}_${this.workingDir}`,
7008
+ title: `${this.provider.name} \xB7 ${dirName}`,
7009
+ status: this.currentStatus,
7010
+ messages: recentMessages,
7011
+ activeModal: this.currentStatus === "waiting_approval" ? {
7012
+ message: this.activeToolCalls.find((t) => t.status === "running")?.name || "Permission requested",
7013
+ buttons: ["Approve", "Reject"]
7014
+ } : null,
7015
+ inputContent: ""
7016
+ },
7017
+ workingDir: this.workingDir,
7018
+ currentModel: this.currentModel,
7019
+ currentPlan: this.currentMode,
7020
+ instanceId: this.instanceId,
7021
+ lastUpdated: Date.now(),
7022
+ settings: this.settings,
7023
+ pendingEvents: this.flushEvents()
7024
+ };
7025
+ }
7026
+ onEvent(event, data) {
7027
+ if (event === "send_message" && data?.text) {
7028
+ this.sendPrompt(data.text).catch(
7029
+ (e) => console.warn(`[ACP:${this.type}] sendPrompt error:`, e?.message)
7030
+ );
7031
+ } else if (event === "resolve_action") {
7032
+ const action = data?.action || "approve";
7033
+ this.resolvePermission(action === "approve" || action === "accept").catch((e) => console.warn(`[ACP:${this.type}] resolvePermission error:`, e?.message));
7034
+ } else if (event === "cancel") {
7035
+ this.cancelSession().catch(
7036
+ (e) => console.warn(`[ACP:${this.type}] cancel error:`, e?.message)
7037
+ );
7038
+ }
7039
+ }
7040
+ dispose() {
7041
+ if (this.process) {
7042
+ try {
7043
+ this.process.kill("SIGTERM");
7044
+ } catch {
7045
+ }
7046
+ this.process = null;
7047
+ }
7048
+ if (this.readline) {
7049
+ this.readline.close();
7050
+ this.readline = null;
7051
+ }
7052
+ for (const [, req] of this.pendingRequests) {
7053
+ clearTimeout(req.timer);
7054
+ req.reject(new Error("Instance disposed"));
7055
+ }
7056
+ this.pendingRequests.clear();
7057
+ this.monitor.reset();
7058
+ }
7059
+ // ─── ACP Process Management ──────────────────────
7060
+ async spawnAgent() {
7061
+ const spawnConfig = this.provider.spawn;
7062
+ if (!spawnConfig) {
7063
+ throw new Error(`[ACP:${this.type}] No spawn config defined`);
7064
+ }
7065
+ const command = spawnConfig.command;
7066
+ const args = [...spawnConfig.args || [], ...this.cliArgs];
7067
+ const env = { ...process.env, ...spawnConfig.env || {} };
7068
+ console.log(`[ACP:${this.type}] Spawning: ${command} ${args.join(" ")} in ${this.workingDir}`);
7069
+ this.process = (0, import_child_process6.spawn)(command, args, {
7070
+ cwd: this.workingDir,
7071
+ env,
7072
+ stdio: ["pipe", "pipe", "pipe"],
7073
+ shell: spawnConfig.shell || false
7074
+ });
7075
+ this.readline = (0, import_readline.createInterface)({ input: this.process.stdout });
7076
+ this.readline.on("line", (line) => {
7077
+ const trimmed = line.trim();
7078
+ if (!trimmed) return;
7079
+ try {
7080
+ const msg = JSON.parse(trimmed);
7081
+ this.handleMessage(msg);
7082
+ } catch (e) {
7083
+ }
7084
+ });
7085
+ this.process.stderr?.on("data", (data) => {
7086
+ const text = data.toString().trim();
7087
+ if (text) {
7088
+ console.log(`[ACP:${this.type}:stderr] ${text.slice(0, 200)}`);
7089
+ }
7090
+ });
7091
+ this.process.on("exit", (code, signal) => {
7092
+ console.log(`[ACP:${this.type}] Process exited: code=${code} signal=${signal}`);
7093
+ this.currentStatus = "stopped";
7094
+ this.detectStatusTransition();
7095
+ });
7096
+ this.process.on("error", (err) => {
7097
+ console.error(`[ACP:${this.type}] Process error:`, err.message);
7098
+ this.currentStatus = "error";
7099
+ this.detectStatusTransition();
7100
+ });
7101
+ await this.initialize();
7102
+ }
7103
+ // ─── ACP Protocol ────────────────────────────────
7104
+ async initialize() {
7105
+ try {
7106
+ const result = await this.sendRequest("initialize", {
7107
+ protocolVersion: "0.1.0",
7108
+ clientInfo: {
7109
+ name: "adhdev",
7110
+ version: "0.1.0"
7111
+ },
7112
+ clientCapabilities: {
7113
+ roots: true
7114
+ },
7115
+ workspaceFolders: [{
7116
+ name: path9.basename(this.workingDir),
7117
+ uri: `file://${this.workingDir}`
7118
+ }]
7119
+ });
7120
+ this.agentCapabilities = result?.capabilities || {};
7121
+ console.log(`[ACP:${this.type}] Initialized. Agent capabilities:`, JSON.stringify(this.agentCapabilities));
7122
+ this.sendNotification("initialized");
7123
+ await this.createSession();
7124
+ } catch (e) {
7125
+ console.error(`[ACP:${this.type}] Initialize failed:`, e?.message);
7126
+ this.currentStatus = "error";
7127
+ }
7128
+ }
7129
+ async createSession() {
7130
+ try {
7131
+ const result = await this.sendRequest("session/new", {
7132
+ cwd: this.workingDir,
7133
+ mcpServers: []
7134
+ });
7135
+ this.sessionId = result?.sessionId || null;
7136
+ this.currentStatus = "idle";
7137
+ this.messages = [];
7138
+ if (result?.models?.currentModelId) {
7139
+ this.currentModel = result.models.currentModelId;
7140
+ }
7141
+ console.log(`[ACP:${this.type}] Session created: ${this.sessionId}${this.currentModel ? ` (model: ${this.currentModel})` : ""}`);
7142
+ } catch (e) {
7143
+ console.warn(`[ACP:${this.type}] session/new failed:`, e?.message);
7144
+ this.currentStatus = "idle";
7145
+ }
7146
+ }
7147
+ async sendPrompt(text) {
7148
+ this.messages.push({
7149
+ role: "user",
7150
+ content: text,
7151
+ timestamp: Date.now()
7152
+ });
7153
+ this.currentStatus = "generating";
7154
+ this.partialContent = "";
7155
+ this.detectStatusTransition();
7156
+ try {
7157
+ const result = await this.sendRequest("session/prompt", {
7158
+ sessionId: this.sessionId,
7159
+ prompt: [{ type: "text", text }]
7160
+ }, 3e5);
7161
+ if (result?.stopReason) {
7162
+ this.stopReason = result.stopReason;
7163
+ }
7164
+ if (this.partialContent.trim()) {
7165
+ this.messages.push({
7166
+ role: "assistant",
7167
+ content: this.partialContent.trim(),
7168
+ timestamp: Date.now()
7169
+ });
7170
+ this.partialContent = "";
7171
+ }
7172
+ this.currentStatus = "idle";
7173
+ this.detectStatusTransition();
7174
+ } catch (e) {
7175
+ console.warn(`[ACP:${this.type}] prompt error:`, e?.message);
7176
+ if (this.partialContent.trim()) {
7177
+ this.messages.push({
7178
+ role: "assistant",
7179
+ content: this.partialContent.trim(),
7180
+ timestamp: Date.now()
7181
+ });
7182
+ this.partialContent = "";
7183
+ }
7184
+ this.currentStatus = "idle";
7185
+ this.detectStatusTransition();
7186
+ }
7187
+ }
7188
+ async cancelSession() {
7189
+ this.sendNotification("session/cancel", {
7190
+ sessionId: this.sessionId
7191
+ });
7192
+ this.currentStatus = "idle";
7193
+ this.detectStatusTransition();
7194
+ }
7195
+ permissionResolvers = [];
7196
+ async resolvePermission(approved) {
7197
+ const resolver = this.permissionResolvers.shift();
7198
+ if (resolver) {
7199
+ resolver(approved);
7200
+ }
7201
+ if (this.currentStatus === "waiting_approval") {
7202
+ this.currentStatus = "generating";
7203
+ this.detectStatusTransition();
7204
+ }
7205
+ }
7206
+ // ─── JSON-RPC Transport ──────────────────────────
7207
+ sendRequest(method, params, timeoutMs = 3e4) {
7208
+ return new Promise((resolve6, reject) => {
7209
+ if (!this.process?.stdin?.writable) {
7210
+ reject(new Error("Process stdin not writable"));
7211
+ return;
7212
+ }
7213
+ const id = this.requestId++;
7214
+ const msg = {
7215
+ jsonrpc: "2.0",
7216
+ id,
7217
+ method,
7218
+ params
7219
+ };
7220
+ const timer = setTimeout(() => {
7221
+ this.pendingRequests.delete(id);
7222
+ reject(new Error(`Request ${method} timed out after ${timeoutMs}ms`));
7223
+ }, timeoutMs);
7224
+ this.pendingRequests.set(id, { resolve: resolve6, reject, timer });
7225
+ const line = JSON.stringify(msg) + "\n";
7226
+ this.process.stdin.write(line);
7227
+ });
7228
+ }
7229
+ sendNotification(method, params) {
7230
+ if (!this.process?.stdin?.writable) return;
7231
+ const msg = {
7232
+ jsonrpc: "2.0",
7233
+ method,
7234
+ ...params && { params }
7235
+ };
7236
+ const line = JSON.stringify(msg) + "\n";
7237
+ this.process.stdin.write(line);
7238
+ }
7239
+ handleMessage(msg) {
7240
+ if ("id" in msg && msg.id !== void 0 && !("method" in msg && msg.method)) {
7241
+ const pending = this.pendingRequests.get(msg.id);
7242
+ if (pending) {
7243
+ clearTimeout(pending.timer);
7244
+ this.pendingRequests.delete(msg.id);
7245
+ const resp = msg;
7246
+ if (resp.error) {
7247
+ pending.reject(new Error(`${resp.error.message} (${resp.error.code})`));
7248
+ } else {
7249
+ pending.resolve(resp.result);
7250
+ }
7251
+ }
7252
+ return;
7253
+ }
7254
+ if ("method" in msg) {
7255
+ this.handleNotification(msg);
7256
+ if ("id" in msg && msg.id !== void 0) {
7257
+ this.handleAgentRequest(msg);
7258
+ }
7259
+ }
7260
+ }
7261
+ handleNotification(msg) {
7262
+ switch (msg.method) {
7263
+ case "session/update": {
7264
+ const params = msg.params;
7265
+ this.handleSessionUpdate(params);
7266
+ break;
7267
+ }
7268
+ default:
7269
+ break;
7270
+ }
7271
+ }
7272
+ handleAgentRequest(msg) {
7273
+ switch (msg.method) {
7274
+ case "fs/readTextFile":
7275
+ case "fs/writeTextFile": {
7276
+ this.sendResponse(msg.id, null, {
7277
+ code: -32601,
7278
+ message: "File system access not supported by ADHDev client"
7279
+ });
7280
+ break;
7281
+ }
7282
+ case "requestPermission": {
7283
+ this.currentStatus = "waiting_approval";
7284
+ this.detectStatusTransition();
7285
+ const promise = new Promise((resolve6) => {
7286
+ this.permissionResolvers.push(resolve6);
7287
+ setTimeout(() => {
7288
+ const idx = this.permissionResolvers.indexOf(resolve6);
7289
+ if (idx >= 0) {
7290
+ this.permissionResolvers.splice(idx, 1);
7291
+ resolve6(false);
7292
+ }
7293
+ }, 3e5);
7294
+ });
7295
+ promise.then((approved) => {
7296
+ this.sendResponse(msg.id, {
7297
+ outcome: approved ? "approved" : "denied"
7298
+ });
7299
+ });
7300
+ break;
7301
+ }
7302
+ case "terminal/create":
7303
+ case "terminal/output":
7304
+ case "terminal/release":
7305
+ case "terminal/kill":
7306
+ case "terminal/waitForExit": {
7307
+ this.sendResponse(msg.id, null, {
7308
+ code: -32601,
7309
+ message: "Terminal not supported by ADHDev client"
7310
+ });
7311
+ break;
7312
+ }
7313
+ default: {
7314
+ this.sendResponse(msg.id, null, {
7315
+ code: -32601,
7316
+ message: `Method ${msg.method} not supported`
7317
+ });
7318
+ }
7319
+ }
7320
+ }
7321
+ sendResponse(id, result, error) {
7322
+ if (!this.process?.stdin?.writable) return;
7323
+ const msg = {
7324
+ jsonrpc: "2.0",
7325
+ id,
7326
+ ...error ? { error } : { result }
7327
+ };
7328
+ const line = JSON.stringify(msg) + "\n";
7329
+ this.process.stdin.write(line);
7330
+ }
7331
+ // ─── ACP session/update 처리 ─────────────────────
7332
+ handleSessionUpdate(params) {
7333
+ if (!params) return;
7334
+ if (params.messageDelta) {
7335
+ const delta = params.messageDelta;
7336
+ if (delta.content) {
7337
+ for (const part of Array.isArray(delta.content) ? delta.content : [delta.content]) {
7338
+ if (part.type === "text" && part.text) {
7339
+ this.partialContent += part.text;
7340
+ }
7341
+ }
7342
+ }
7343
+ this.currentStatus = "generating";
7344
+ }
7345
+ if (params.message) {
7346
+ const m = params.message;
7347
+ let content = "";
7348
+ if (typeof m.content === "string") {
7349
+ content = m.content;
7350
+ } else if (Array.isArray(m.content)) {
7351
+ content = m.content.filter((p) => p.type === "text").map((p) => p.text || "").join("\n");
7352
+ }
7353
+ if (content.trim()) {
7354
+ this.messages.push({
7355
+ role: m.role || "assistant",
7356
+ content: content.trim(),
7357
+ timestamp: Date.now()
7358
+ });
7359
+ this.partialContent = "";
7360
+ }
7361
+ }
7362
+ if (params.toolCallUpdate) {
7363
+ const tc = params.toolCallUpdate;
7364
+ const existing = this.activeToolCalls.find((t) => t.id === tc.id);
7365
+ if (existing) {
7366
+ if (tc.status) existing.status = tc.status;
7367
+ if (tc.output) existing.output = tc.output;
7368
+ } else {
7369
+ this.activeToolCalls.push({
7370
+ id: tc.id || `tc_${Date.now()}`,
7371
+ name: tc.name || "unknown",
7372
+ status: tc.status || "running",
7373
+ input: typeof tc.input === "string" ? tc.input : JSON.stringify(tc.input)
7374
+ });
7375
+ }
7376
+ }
7377
+ if (params.stopReason) {
7378
+ this.stopReason = params.stopReason;
7379
+ if (params.stopReason !== "cancelled") {
7380
+ this.currentStatus = "idle";
7381
+ }
7382
+ this.activeToolCalls = [];
7383
+ this.detectStatusTransition();
7384
+ }
7385
+ if (params.model) {
7386
+ this.currentModel = params.model;
7387
+ }
7388
+ }
7389
+ // ─── 상태 전이 감지 ────────────────────────────
7390
+ detectStatusTransition() {
7391
+ const now = Date.now();
7392
+ const newStatus = this.currentStatus;
7393
+ const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
7394
+ const chatTitle = `${this.provider.name} \xB7 ${dirName}`;
7395
+ if (newStatus !== this.lastStatus) {
7396
+ if (this.lastStatus === "idle" && newStatus === "generating") {
7397
+ this.generatingStartedAt = now;
7398
+ this.pushEvent({ event: "agent:generating_started", chatTitle, timestamp: now });
7399
+ } else if (newStatus === "waiting_approval") {
7400
+ if (!this.generatingStartedAt) this.generatingStartedAt = now;
7401
+ this.pushEvent({
7402
+ event: "agent:waiting_approval",
7403
+ chatTitle,
7404
+ timestamp: now,
7405
+ modalMessage: this.activeToolCalls.find((t) => t.status === "running")?.name
7406
+ });
7407
+ } else if (newStatus === "idle" && (this.lastStatus === "generating" || this.lastStatus === "waiting_approval")) {
7408
+ const duration = this.generatingStartedAt ? Math.round((now - this.generatingStartedAt) / 1e3) : 0;
7409
+ this.pushEvent({ event: "agent:generating_completed", chatTitle, duration, timestamp: now });
7410
+ this.generatingStartedAt = 0;
7411
+ } else if (newStatus === "stopped") {
7412
+ this.pushEvent({ event: "agent:stopped", chatTitle, timestamp: now });
7413
+ }
7414
+ this.lastStatus = newStatus;
7415
+ }
7416
+ const agentKey = `${this.type}:acp`;
7417
+ const monitorEvents = this.monitor.check(agentKey, newStatus, now);
7418
+ for (const me of monitorEvents) {
7419
+ this.pushEvent({ event: me.type, agentKey: me.agentKey, message: me.message, elapsedSec: me.elapsedSec, timestamp: me.timestamp });
7420
+ }
7421
+ }
7422
+ pushEvent(event) {
7423
+ this.events.push(event);
7424
+ if (this.events.length > 50) this.events = this.events.slice(-50);
7425
+ }
7426
+ flushEvents() {
7427
+ const events = [...this.events];
7428
+ this.events = [];
7429
+ return events;
7430
+ }
7431
+ // ─── 외부 접근 ─────────────────────────────────
7432
+ get cliType() {
7433
+ return this.type;
7434
+ }
7435
+ get cliName() {
7436
+ return this.provider.name;
7437
+ }
7438
+ /** ACP Agent capabilities (initialize 후 사용 가능) */
7439
+ getCapabilities() {
7440
+ return this.agentCapabilities;
7441
+ }
7442
+ };
7443
+ }
7444
+ });
7445
+
6920
7446
  // src/daemon-cli.ts
6921
- var os10, path9, import_chalk, DaemonCliManager;
7447
+ var os10, path10, import_chalk, DaemonCliManager;
6922
7448
  var init_daemon_cli = __esm({
6923
7449
  "src/daemon-cli.ts"() {
6924
7450
  "use strict";
6925
7451
  os10 = __toESM(require("os"));
6926
- path9 = __toESM(require("path"));
7452
+ path10 = __toESM(require("path"));
6927
7453
  import_chalk = __toESM(require("chalk"));
6928
7454
  init_provider_cli_adapter();
6929
7455
  init_cli_detector();
6930
7456
  init_config();
6931
7457
  init_cli_provider_instance();
7458
+ init_acp_provider_instance();
6932
7459
  DaemonCliManager = class {
6933
7460
  adapters = /* @__PURE__ */ new Map();
6934
7461
  deps;
@@ -6963,20 +7490,54 @@ var init_daemon_cli = __esm({
6963
7490
  // ─── 세션 시작/중지 ──────────────────────────────
6964
7491
  async startSession(cliType, workingDir, cliArgs) {
6965
7492
  const trimmed = (workingDir || os10.homedir()).trim();
6966
- const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os10.homedir()) : path9.resolve(trimmed);
6967
- const cliInfo = await detectCLI(cliType);
6968
- if (!cliInfo) throw new Error(`${cliType} not found`);
6969
- const key = this.getCliKey(cliType, resolvedDir);
6970
- if (this.adapters.has(key)) {
6971
- console.log(import_chalk.default.yellow(` \u26A1 CLI ${cliType} already running in ${resolvedDir}`));
6972
- return;
6973
- }
7493
+ const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os10.homedir()) : path10.resolve(trimmed);
6974
7494
  const typeMap = {
6975
7495
  "claude-code": "claude-cli",
6976
7496
  "codex": "codex-cli"
6977
7497
  };
6978
7498
  const normalizedType = typeMap[cliType] || cliType;
6979
7499
  const provider2 = this.providerLoader.get(normalizedType);
7500
+ const key = this.getCliKey(normalizedType, resolvedDir);
7501
+ if (this.adapters.has(key)) {
7502
+ console.log(import_chalk.default.yellow(` \u26A1 ${cliType} already running in ${resolvedDir}`));
7503
+ return;
7504
+ }
7505
+ if (provider2 && provider2.category === "acp") {
7506
+ const instanceManager2 = this.deps.getInstanceManager();
7507
+ if (!instanceManager2) throw new Error("InstanceManager not available");
7508
+ console.log(import_chalk.default.cyan(` \u{1F50C} Starting ACP agent: ${provider2.name} (${provider2.type}) in ${resolvedDir}`));
7509
+ const acpInstance = new AcpProviderInstance(provider2, resolvedDir, cliArgs);
7510
+ await instanceManager2.addInstance(key, acpInstance, {
7511
+ settings: this.providerLoader.getSettings(normalizedType)
7512
+ });
7513
+ this.adapters.set(key, {
7514
+ cliType: normalizedType,
7515
+ workingDir: resolvedDir,
7516
+ spawn: async () => {
7517
+ },
7518
+ shutdown: () => {
7519
+ instanceManager2.removeInstance(key);
7520
+ },
7521
+ sendMessage: async (text) => {
7522
+ acpInstance.onEvent("send_message", { text });
7523
+ },
7524
+ getStatus: () => ({ status: "idle", messages: [], activeModal: null }),
7525
+ setOnStatusChange: () => {
7526
+ },
7527
+ setOnPtyData: () => {
7528
+ }
7529
+ });
7530
+ console.log(import_chalk.default.green(` \u2713 ACP agent started: ${provider2.name} in ${resolvedDir}`));
7531
+ try {
7532
+ addCliHistory({ cliType: normalizedType, dir: resolvedDir, cliArgs });
7533
+ } catch (e) {
7534
+ console.warn("[ACP] History save failed:", e?.message);
7535
+ }
7536
+ this.deps.onStatusChange();
7537
+ return;
7538
+ }
7539
+ const cliInfo = await detectCLI(cliType);
7540
+ if (!cliInfo) throw new Error(`${cliType} not found`);
6980
7541
  console.log(import_chalk.default.yellow(` \u26A1 Starting CLI ${cliType} in ${resolvedDir}...`));
6981
7542
  if (provider2) {
6982
7543
  console.log(import_chalk.default.cyan(` \u{1F4E6} Using provider: ${provider2.name} (${provider2.type})`));
@@ -7408,12 +7969,12 @@ var init_extension_provider_instance = __esm({
7408
7969
  });
7409
7970
 
7410
7971
  // src/providers/ide-provider-instance.ts
7411
- var os11, crypto, IdeProviderInstance;
7972
+ var os11, crypto2, IdeProviderInstance;
7412
7973
  var init_ide_provider_instance = __esm({
7413
7974
  "src/providers/ide-provider-instance.ts"() {
7414
7975
  "use strict";
7415
7976
  os11 = __toESM(require("os"));
7416
- crypto = __toESM(require("crypto"));
7977
+ crypto2 = __toESM(require("crypto"));
7417
7978
  init_extension_provider_instance();
7418
7979
  init_status_monitor();
7419
7980
  IdeProviderInstance = class {
@@ -7441,7 +8002,7 @@ var init_ide_provider_instance = __esm({
7441
8002
  constructor(provider2, instanceKey) {
7442
8003
  this.type = provider2.type;
7443
8004
  this.provider = provider2;
7444
- this.instanceId = instanceKey ? `${instanceKey}_${crypto.createHash("md5").update(os11.hostname() + instanceKey).digest("hex").slice(0, 8)}` : `${provider2.type}_${crypto.createHash("md5").update(os11.hostname() + provider2.type).digest("hex").slice(0, 8)}`;
8005
+ this.instanceId = instanceKey ? `${instanceKey}_${crypto2.createHash("md5").update(os11.hostname() + instanceKey).digest("hex").slice(0, 8)}` : `${provider2.type}_${crypto2.createHash("md5").update(os11.hostname() + provider2.type).digest("hex").slice(0, 8)}`;
7445
8006
  this.monitor = new StatusMonitor();
7446
8007
  }
7447
8008
  // ─── Lifecycle ─────────────────────────────────
@@ -7680,9 +8241,9 @@ __export(adhdev_daemon_exports, {
7680
8241
  stopDaemon: () => stopDaemon
7681
8242
  });
7682
8243
  function getDaemonPidFile() {
7683
- const dir = path10.join(os12.homedir(), ".adhdev");
8244
+ const dir = path11.join(os12.homedir(), ".adhdev");
7684
8245
  if (!fs6.existsSync(dir)) fs6.mkdirSync(dir, { recursive: true });
7685
- return path10.join(dir, "daemon.pid");
8246
+ return path11.join(dir, "daemon.pid");
7686
8247
  }
7687
8248
  function writeDaemonPid(pid) {
7688
8249
  fs6.writeFileSync(getDaemonPidFile(), String(pid), "utf-8");
@@ -7718,7 +8279,7 @@ function stopDaemon() {
7718
8279
  return false;
7719
8280
  }
7720
8281
  }
7721
- var os12, fs6, path10, crypto2, import_chalk2, DANGEROUS_PATTERNS, AdhdevDaemon;
8282
+ var os12, fs6, path11, crypto3, import_chalk2, DANGEROUS_PATTERNS, AdhdevDaemon;
7722
8283
  var init_adhdev_daemon = __esm({
7723
8284
  "src/adhdev-daemon.ts"() {
7724
8285
  "use strict";
@@ -7741,8 +8302,8 @@ var init_adhdev_daemon = __esm({
7741
8302
  init_daemon_logger();
7742
8303
  os12 = __toESM(require("os"));
7743
8304
  fs6 = __toESM(require("fs"));
7744
- path10 = __toESM(require("path"));
7745
- crypto2 = __toESM(require("crypto"));
8305
+ path11 = __toESM(require("path"));
8306
+ crypto3 = __toESM(require("crypto"));
7746
8307
  import_chalk2 = __toESM(require("chalk"));
7747
8308
  DANGEROUS_PATTERNS = [
7748
8309
  /\brm\s+(-[a-z]*f|-[a-z]*r|--force|--recursive)/i,
@@ -7877,7 +8438,7 @@ var init_adhdev_daemon = __esm({
7877
8438
  this.commandHandler.setAgentStreamManager(this.agentStreamManager);
7878
8439
  this.startAgentStreamPolling();
7879
8440
  const machineId = os12.hostname().replace(/[^a-zA-Z0-9]/g, "_");
7880
- const machineHash = crypto2.createHash("md5").update(os12.hostname() + os12.homedir()).digest("hex").slice(0, 8);
8441
+ const machineHash = crypto3.createHash("md5").update(os12.hostname() + os12.homedir()).digest("hex").slice(0, 8);
7881
8442
  const instanceId = `daemon_${machineId}_${machineHash}`;
7882
8443
  this.bridge = new CliBridgeConnection({
7883
8444
  serverUrl: options.serverUrl || config.serverUrl,
@@ -9065,16 +9626,16 @@ async function injectTokenToIDE(ide, connectionToken) {
9065
9626
  try {
9066
9627
  const os13 = await import("os");
9067
9628
  const fs7 = await import("fs");
9068
- const path11 = await import("path");
9629
+ const path12 = await import("path");
9069
9630
  const platform7 = os13.platform();
9070
9631
  const home = os13.homedir();
9071
9632
  const getSettingsPath = (appName2) => {
9072
9633
  if (platform7 === "darwin") {
9073
- return path11.join(home, "Library", "Application Support", appName2, "User", "settings.json");
9634
+ return path12.join(home, "Library", "Application Support", appName2, "User", "settings.json");
9074
9635
  } else if (platform7 === "win32") {
9075
- return path11.join(process.env.APPDATA || path11.join(home, "AppData", "Roaming"), appName2, "User", "settings.json");
9636
+ return path12.join(process.env.APPDATA || path12.join(home, "AppData", "Roaming"), appName2, "User", "settings.json");
9076
9637
  } else {
9077
- return path11.join(home, ".config", appName2, "User", "settings.json");
9638
+ return path12.join(home, ".config", appName2, "User", "settings.json");
9078
9639
  }
9079
9640
  };
9080
9641
  const loader = new ProviderLoader({ logFn: () => {
@@ -9092,7 +9653,7 @@ async function injectTokenToIDE(ide, connectionToken) {
9092
9653
  settings = {};
9093
9654
  }
9094
9655
  } else {
9095
- fs7.mkdirSync(path11.dirname(settingsPath), { recursive: true });
9656
+ fs7.mkdirSync(path12.dirname(settingsPath), { recursive: true });
9096
9657
  }
9097
9658
  settings["adhdev.connectionToken"] = connectionToken;
9098
9659
  settings["adhdev.autoConnect"] = true;
@@ -9128,8 +9689,8 @@ async function startDaemonFlow() {
9128
9689
  const daemon = new AdhdevDaemon2();
9129
9690
  const { execSync: execSync6 } = await import("child_process");
9130
9691
  const os13 = await import("os");
9131
- const path11 = await import("path");
9132
- const logPath = path11.join(os13.homedir(), ".adhdev", "daemon.log");
9692
+ const path12 = await import("path");
9693
+ const logPath = path12.join(os13.homedir(), ".adhdev", "daemon.log");
9133
9694
  try {
9134
9695
  execSync6(`nohup adhdev daemon > "${logPath}" 2>&1 &`, {
9135
9696
  timeout: 3e3,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adhdev",
3
- "version": "0.1.50",
3
+ "version": "0.1.51",
4
4
  "description": "ADHDev CLI — Detect, install and configure your IDE + AI agent extensions",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -12,11 +12,11 @@
12
12
  * @type {import('../../../../src/providers/contracts').ProviderModule}
13
13
  */
14
14
  module.exports = {
15
- type: 'codex-cli',
16
- name: 'Codex CLI',
15
+ type: 'codex-acp',
16
+ name: 'Codex (ACP)',
17
17
  category: 'acp',
18
18
 
19
- displayName: 'Codex',
19
+ displayName: 'Codex (ACP)',
20
20
  icon: '🤖',
21
21
 
22
22
  // ACP spawn config — uses codex-acp adapter