@adhdev/daemon-core 0.6.21 → 0.6.22
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.d.ts +10 -1
- package/dist/index.js +69 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/boot/daemon-lifecycle.ts +5 -2
- package/src/config/config.ts +9 -0
- package/src/daemon/dev-server.ts +55 -3
- package/src/providers/provider-loader.ts +11 -1
- package/src/status/reporter.ts +3 -8
package/dist/index.d.ts
CHANGED
|
@@ -168,6 +168,7 @@ interface ADHDevConfig {
|
|
|
168
168
|
recentWorkspaceActivity?: WorkspaceActivityEntry[];
|
|
169
169
|
machineNickname: string | null;
|
|
170
170
|
machineId?: string;
|
|
171
|
+
machineSecret?: string | null;
|
|
171
172
|
cliHistory: CliHistoryEntry[];
|
|
172
173
|
providerSettings: Record<string, Record<string, any>>;
|
|
173
174
|
ideSettings: Record<string, {
|
|
@@ -175,6 +176,7 @@ interface ADHDevConfig {
|
|
|
175
176
|
enabled: boolean;
|
|
176
177
|
}>;
|
|
177
178
|
}>;
|
|
179
|
+
disableUpstream?: boolean;
|
|
178
180
|
}
|
|
179
181
|
interface CliHistoryEntry {
|
|
180
182
|
cliType: string;
|
|
@@ -957,6 +959,7 @@ declare class ProviderLoader {
|
|
|
957
959
|
private builtinDirs;
|
|
958
960
|
private userDir;
|
|
959
961
|
private upstreamDir;
|
|
962
|
+
private disableUpstream;
|
|
960
963
|
private watchers;
|
|
961
964
|
private logFn;
|
|
962
965
|
private versionArchive;
|
|
@@ -969,6 +972,8 @@ declare class ProviderLoader {
|
|
|
969
972
|
builtinDir?: string | string[];
|
|
970
973
|
userDir?: string;
|
|
971
974
|
logFn?: (msg: string) => void;
|
|
975
|
+
/** Disable upstream auto-download (for dev/testing/OSS) */
|
|
976
|
+
disableUpstream?: boolean;
|
|
972
977
|
});
|
|
973
978
|
private log;
|
|
974
979
|
/**
|
|
@@ -2202,7 +2207,6 @@ interface StatusReporterDeps {
|
|
|
2202
2207
|
connectedPeerCount: number;
|
|
2203
2208
|
screenshotActive: boolean;
|
|
2204
2209
|
sendStatus(data: any): void;
|
|
2205
|
-
sendStatusEvent?(event: Record<string, unknown>): boolean;
|
|
2206
2210
|
} | null;
|
|
2207
2211
|
providerLoader: {
|
|
2208
2212
|
resolve(type: string): any;
|
|
@@ -2222,6 +2226,11 @@ interface StatusReporterDeps {
|
|
|
2222
2226
|
collectAllStates(): ProviderState[];
|
|
2223
2227
|
collectStatesByCategory(cat: string): ProviderState[];
|
|
2224
2228
|
};
|
|
2229
|
+
getScreenshotUsage?: () => {
|
|
2230
|
+
dailyUsedMinutes: number;
|
|
2231
|
+
dailyBudgetMinutes: number;
|
|
2232
|
+
budgetExhausted: boolean;
|
|
2233
|
+
} | null;
|
|
2225
2234
|
}
|
|
2226
2235
|
declare class DaemonStatusReporter {
|
|
2227
2236
|
private deps;
|
package/dist/index.js
CHANGED
|
@@ -361,9 +361,11 @@ var init_config = __esm({
|
|
|
361
361
|
recentWorkspaceActivity: [],
|
|
362
362
|
machineNickname: null,
|
|
363
363
|
machineId: void 0,
|
|
364
|
+
machineSecret: null,
|
|
364
365
|
cliHistory: [],
|
|
365
366
|
providerSettings: {},
|
|
366
|
-
ideSettings: {}
|
|
367
|
+
ideSettings: {},
|
|
368
|
+
disableUpstream: false
|
|
367
369
|
};
|
|
368
370
|
}
|
|
369
371
|
});
|
|
@@ -5716,6 +5718,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
5716
5718
|
builtinDirs;
|
|
5717
5719
|
userDir;
|
|
5718
5720
|
upstreamDir;
|
|
5721
|
+
disableUpstream;
|
|
5719
5722
|
watchers = [];
|
|
5720
5723
|
logFn;
|
|
5721
5724
|
versionArchive = null;
|
|
@@ -5734,6 +5737,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
5734
5737
|
}
|
|
5735
5738
|
this.userDir = options?.userDir || path6.join(os7.homedir(), ".adhdev", "providers");
|
|
5736
5739
|
this.upstreamDir = path6.join(this.userDir, ".upstream");
|
|
5740
|
+
this.disableUpstream = options?.disableUpstream ?? false;
|
|
5737
5741
|
this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
|
|
5738
5742
|
}
|
|
5739
5743
|
log(msg) {
|
|
@@ -5750,11 +5754,13 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
5750
5754
|
loadAll() {
|
|
5751
5755
|
this.providers.clear();
|
|
5752
5756
|
let upstreamCount = 0;
|
|
5753
|
-
if (fs5.existsSync(this.upstreamDir)) {
|
|
5757
|
+
if (!this.disableUpstream && fs5.existsSync(this.upstreamDir)) {
|
|
5754
5758
|
upstreamCount = this.loadDir(this.upstreamDir);
|
|
5755
5759
|
if (upstreamCount > 0) {
|
|
5756
5760
|
this.log(`Loaded ${upstreamCount} upstream providers (auto-updated)`);
|
|
5757
5761
|
}
|
|
5762
|
+
} else if (this.disableUpstream) {
|
|
5763
|
+
this.log("Upstream loading disabled (disableUpstream=true)");
|
|
5758
5764
|
}
|
|
5759
5765
|
if (fs5.existsSync(this.userDir)) {
|
|
5760
5766
|
const userCount = this.loadDir(this.userDir, [".upstream"]);
|
|
@@ -6157,6 +6163,10 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
6157
6163
|
* @returns Whether an update occurred
|
|
6158
6164
|
*/
|
|
6159
6165
|
async fetchLatest() {
|
|
6166
|
+
if (this.disableUpstream) {
|
|
6167
|
+
this.log("Upstream fetch skipped (disableUpstream=true)");
|
|
6168
|
+
return { updated: false };
|
|
6169
|
+
}
|
|
6160
6170
|
const https = require("https");
|
|
6161
6171
|
const { execSync: execSync7 } = require("child_process");
|
|
6162
6172
|
const metaPath = path6.join(this.upstreamDir, _ProviderLoader.META_FILE);
|
|
@@ -7458,12 +7468,6 @@ var DaemonStatusReporter = class {
|
|
|
7458
7468
|
emitStatusEvent(event) {
|
|
7459
7469
|
LOG.info("StatusEvent", `${event.event} (${event.providerType || event.ideType || ""})`);
|
|
7460
7470
|
this.deps.serverConn?.sendMessage("status_event", event);
|
|
7461
|
-
if (this.deps.p2p?.isConnected) {
|
|
7462
|
-
try {
|
|
7463
|
-
this.deps.p2p.sendStatusEvent?.(event);
|
|
7464
|
-
} catch {
|
|
7465
|
-
}
|
|
7466
|
-
}
|
|
7467
7471
|
}
|
|
7468
7472
|
removeAgentTracking(_key) {
|
|
7469
7473
|
}
|
|
@@ -7541,6 +7545,7 @@ var DaemonStatusReporter = class {
|
|
|
7541
7545
|
peers: p2p?.connectedPeerCount || 0,
|
|
7542
7546
|
screenshotActive: p2p?.screenshotActive || false
|
|
7543
7547
|
},
|
|
7548
|
+
screenshotUsage: this.deps.getScreenshotUsage?.() || null,
|
|
7544
7549
|
connectedExtensions: [],
|
|
7545
7550
|
detectedIdes: this.deps.detectedIdes || [],
|
|
7546
7551
|
availableProviders: this.deps.providerLoader.getAll().map((p) => ({
|
|
@@ -12525,6 +12530,22 @@ var DevServer = class _DevServer {
|
|
|
12525
12530
|
lines.push("| focusEditor | `{ focused: true/false }` |");
|
|
12526
12531
|
lines.push("| openPanel | `{ opened: true/false }` |");
|
|
12527
12532
|
lines.push("");
|
|
12533
|
+
lines.push("## \u{1F534} CRITICAL: readChat `status` Lifecycle");
|
|
12534
|
+
lines.push("The `status` field in readChat controls how the dashboard and daemon auto-approve-loop behave.");
|
|
12535
|
+
lines.push("Getting this wrong will break the entire automation pipeline. The status MUST reflect the ACTUAL current state:");
|
|
12536
|
+
lines.push("");
|
|
12537
|
+
lines.push("| Status | When to use | How to detect |");
|
|
12538
|
+
lines.push("|---|---|---|");
|
|
12539
|
+
lines.push("| `idle` | AI is NOT generating, no approval needed | Default state. No stop button, no spinners, no approval pills/buttons |");
|
|
12540
|
+
lines.push("| `generating` | AI is actively streaming/thinking | ANY of: (1) Stop/Cancel button visible, (2) CSS animation (animate-spin/pulse/bounce), (3) floating state text like Thinking/Generating/Sailing, (4) streaming indicator class |");
|
|
12541
|
+
lines.push("| `waiting_approval` | AI stopped and needs user action | Actionable buttons like Run/Skip/Accept/Reject are visible AND clickable |");
|
|
12542
|
+
lines.push("");
|
|
12543
|
+
lines.push("### \u26A0\uFE0F Status Detection Gotchas (MUST READ!)");
|
|
12544
|
+
lines.push('1. **FALSE POSITIVES from old messages**: Chat history may contain text like "Command Awaiting Approval" from PAST turns. If you search the entire chat panel for this text, you will get false matches from parent divs whose innerText includes ALL child text. ONLY match small leaf elements (under 80 chars) or use explicit button/pill selectors.');
|
|
12545
|
+
lines.push('2. **Awaiting Approval pill without actions**: Some IDEs show a floating pill/banner saying "Awaiting Approval" that is just a scroll-to indicator (not an actual approval dialog). If this pill exists but NO actionable buttons (Run/Skip/Accept/Reject) exist anywhere in the panel, the status should be `idle`, NOT `waiting_approval`.');
|
|
12546
|
+
lines.push("3. **generating detection must be multi-signal**: Do NOT rely on just one indicator. Check ALL of: stop buttons, CSS animations, floating state labels, streaming classes. IDEs differ widely.");
|
|
12547
|
+
lines.push("4. **activeModal must include actions**: When `status` is `waiting_approval`, the `activeModal` object MUST include a non-empty `actions` array listing the button labels. If you cannot find any action buttons, the status is NOT `waiting_approval`.");
|
|
12548
|
+
lines.push("");
|
|
12528
12549
|
lines.push("## Action");
|
|
12529
12550
|
lines.push("1. Edit the script files to implement working code");
|
|
12530
12551
|
lines.push("2. After editing, TEST each function using the DevConsole API (see below)");
|
|
@@ -12549,7 +12570,7 @@ var DevServer = class _DevServer {
|
|
|
12549
12570
|
lines.push("Once you save the file, test it by running:");
|
|
12550
12571
|
lines.push("```bash");
|
|
12551
12572
|
lines.push(`curl -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/providers/reload`);
|
|
12552
|
-
lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/
|
|
12573
|
+
lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/scripts/run -H "Content-Type: application/json" -d '{"script": "readChat", "type": "${type}", "ideType": "${type}"}'`);
|
|
12553
12574
|
lines.push("```");
|
|
12554
12575
|
lines.push("");
|
|
12555
12576
|
lines.push("### Task Workflow");
|
|
@@ -12561,12 +12582,44 @@ var DevServer = class _DevServer {
|
|
|
12561
12582
|
lines.push("### \u{1F525} Advanced UI Parsing (CRUCIAL for `readChat`)");
|
|
12562
12583
|
lines.push("Your `readChat` must flawlessly parse complex UI elements (tables, code blocks, tool calls, and AI thoughts). The quality must match the `antigravity` reference.");
|
|
12563
12584
|
lines.push("To achieve this, you MUST generate a live test scenario:");
|
|
12564
|
-
lines.push(
|
|
12565
|
-
lines.push(
|
|
12585
|
+
lines.push(`1. Early in your process, send a rich prompt to the IDE using the API:`);
|
|
12586
|
+
lines.push(` \`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/scripts/run -H "Content-Type: application/json" -d '{"script": "sendMessage", "type": "${type}", "ideType": "${type}", "args": {"message": "Write a python script, draw a markdown table, use a tool, and show your reasoning/thought process"}}'\``);
|
|
12566
12587
|
lines.push("2. Wait a few seconds for the IDE AI to generate these elements in the UI.");
|
|
12567
12588
|
lines.push("3. Use CDP evaluate to deeply inspect the DOM structure of the newly generated tables, code blocks, thought blocks, and tool calls.");
|
|
12568
12589
|
lines.push("4. Ensure `readChat` extracts `content` with precise markdown formatting (especially for tables/code) and assigns correct `kind` tags (`thought`, `tool`, `terminal`).");
|
|
12569
12590
|
lines.push("");
|
|
12591
|
+
lines.push("## \u{1F9EA} MANDATORY: Status Integration Test");
|
|
12592
|
+
lines.push("Before finishing, you MUST run this end-to-end test to verify readChat status transitions work:");
|
|
12593
|
+
lines.push("");
|
|
12594
|
+
lines.push("### Step 1: Baseline \u2014 confirm idle");
|
|
12595
|
+
lines.push("```bash");
|
|
12596
|
+
lines.push(`curl -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/providers/reload`);
|
|
12597
|
+
lines.push(`RESULT=$(curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/scripts/run -H "Content-Type: application/json" -d '{"script": "readChat", "type": "${type}", "ideType": "${type}"}')`);
|
|
12598
|
+
lines.push(`echo "$RESULT" | python3 -c "import sys,json; d=json.load(sys.stdin); r=d.get('result',d); r=json.loads(r) if isinstance(r,str) else r; assert r.get('status')=='idle', f'Expected idle, got {r.get(chr(34)+chr(115)+chr(116)+chr(97)+chr(116)+chr(117)+chr(115)+chr(34))}'; print('Step 1 PASS: status=idle')"`);
|
|
12599
|
+
lines.push("```");
|
|
12600
|
+
lines.push("");
|
|
12601
|
+
lines.push("### Step 2: Send a message that triggers generation");
|
|
12602
|
+
lines.push("```bash");
|
|
12603
|
+
lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/scripts/run -H "Content-Type: application/json" -d '{"script": "sendMessage", "type": "${type}", "ideType": "${type}", "args": {"message": "Say hello in one word"}}'`);
|
|
12604
|
+
lines.push("sleep 2");
|
|
12605
|
+
lines.push("```");
|
|
12606
|
+
lines.push("");
|
|
12607
|
+
lines.push("### Step 3: Check generating OR completed");
|
|
12608
|
+
lines.push("The AI may still be generating OR may have finished already. Either generating or idle is acceptable:");
|
|
12609
|
+
lines.push("```bash");
|
|
12610
|
+
lines.push(`RESULT=$(curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/scripts/run -H "Content-Type: application/json" -d '{"script": "readChat", "type": "${type}", "ideType": "${type}"}')`);
|
|
12611
|
+
lines.push(`echo "$RESULT" | python3 -c "import sys,json; d=json.load(sys.stdin); r=d.get('result',d); r=json.loads(r) if isinstance(r,str) else r; s=r.get('status'); assert s in ('generating','idle','waiting_approval'), f'Unexpected: {s}'; print(f'Step 3 PASS: status={s}')"`);
|
|
12612
|
+
lines.push("```");
|
|
12613
|
+
lines.push("");
|
|
12614
|
+
lines.push("### Step 4: Wait for completion and verify new message");
|
|
12615
|
+
lines.push("```bash");
|
|
12616
|
+
lines.push("sleep 10");
|
|
12617
|
+
lines.push(`RESULT=$(curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/scripts/run -H "Content-Type: application/json" -d '{"script": "readChat", "type": "${type}", "ideType": "${type}"}')`);
|
|
12618
|
+
lines.push(`echo "$RESULT" | python3 -c "import sys,json; d=json.load(sys.stdin); r=d.get('result',d); r=json.loads(r) if isinstance(r,str) else r; s=r.get('status'); msgs=r.get('messages',[]); assert s=='idle', f'Expected idle, got {s}'; assert len(msgs)>0, 'No messages'; print(f'Step 4 PASS: status={s}, messages={len(msgs)}')"`);
|
|
12619
|
+
lines.push("```");
|
|
12620
|
+
lines.push("");
|
|
12621
|
+
lines.push("If ANY step fails, fix your implementation and re-run the test. Do NOT finish until all 4 steps pass.");
|
|
12622
|
+
lines.push("");
|
|
12570
12623
|
if (userComment) {
|
|
12571
12624
|
lines.push("## \u26A0\uFE0F User Instructions (HIGH PRIORITY)");
|
|
12572
12625
|
lines.push("The user has provided the following additional instructions. Follow them strictly:");
|
|
@@ -13095,10 +13148,13 @@ init_logger();
|
|
|
13095
13148
|
init_config();
|
|
13096
13149
|
async function initDaemonComponents(config) {
|
|
13097
13150
|
installGlobalInterceptor();
|
|
13151
|
+
const appConfig = loadConfig();
|
|
13152
|
+
const disableUpstream = appConfig.disableUpstream ?? false;
|
|
13098
13153
|
const providerLoader = new ProviderLoader({
|
|
13099
|
-
logFn: config.providerLogFn
|
|
13154
|
+
logFn: config.providerLogFn,
|
|
13155
|
+
disableUpstream
|
|
13100
13156
|
});
|
|
13101
|
-
if (!providerLoader.hasUpstream()) {
|
|
13157
|
+
if (!disableUpstream && !providerLoader.hasUpstream()) {
|
|
13102
13158
|
LOG.info("Provider", "No upstream providers found \u2014 downloading from GitHub...");
|
|
13103
13159
|
try {
|
|
13104
13160
|
await providerLoader.fetchLatest();
|