agent-dbg 0.1.0 → 0.1.2
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/.claude/settings.local.json +7 -5
- package/.claude/skills/agent-dbg/SKILL.md +116 -0
- package/.claude/skills/agent-dbg/references/commands.md +173 -0
- package/.vscode/launch.json +19 -0
- package/CLAUDE.md +2 -2
- package/PROGRESS.md +91 -91
- package/README.md +45 -17
- package/{ndbg-spec.md → SPEC.md} +152 -152
- package/dist/main.js +12500 -0
- package/package.json +3 -3
- package/src/cdp/client.ts +18 -4
- package/src/cdp/logger.ts +69 -0
- package/src/cli/parser.ts +54 -43
- package/src/commands/attach.ts +2 -2
- package/src/commands/blackbox-ls.ts +1 -1
- package/src/commands/blackbox-rm.ts +3 -3
- package/src/commands/blackbox.ts +2 -2
- package/src/commands/break-ls.ts +3 -2
- package/src/commands/break-rm.ts +2 -2
- package/src/commands/break-toggle.ts +2 -2
- package/src/commands/break.ts +46 -17
- package/src/commands/breakable.ts +2 -2
- package/src/commands/catch.ts +2 -2
- package/src/commands/console.ts +1 -1
- package/src/commands/continue.ts +5 -18
- package/src/commands/eval.ts +2 -2
- package/src/commands/exceptions.ts +1 -1
- package/src/commands/hotpatch.ts +2 -2
- package/src/commands/launch.ts +7 -11
- package/src/commands/logpoint.ts +7 -6
- package/src/commands/logs.ts +116 -0
- package/src/commands/pause.ts +5 -18
- package/src/commands/print-state.ts +85 -0
- package/src/commands/props.ts +2 -2
- package/src/commands/restart-frame.ts +1 -1
- package/src/commands/restart.ts +42 -0
- package/src/commands/run-to.ts +7 -20
- package/src/commands/scripts.ts +1 -1
- package/src/commands/search.ts +4 -3
- package/src/commands/set-return.ts +2 -2
- package/src/commands/set.ts +3 -3
- package/src/commands/source.ts +3 -2
- package/src/commands/sourcemap.ts +1 -1
- package/src/commands/stack.ts +1 -1
- package/src/commands/state.ts +3 -73
- package/src/commands/status.ts +3 -2
- package/src/commands/step.ts +5 -18
- package/src/commands/vars.ts +3 -1
- package/src/daemon/entry.ts +16 -6
- package/src/daemon/paths.ts +6 -2
- package/src/daemon/server.ts +1 -1
- package/src/daemon/session-breakpoints.ts +7 -2
- package/src/daemon/session-inspection.ts +6 -10
- package/src/daemon/session-state.ts +6 -5
- package/src/daemon/session.ts +23 -3
- package/src/formatter/logs.ts +110 -0
- package/src/formatter/path.ts +27 -0
- package/src/formatter/stack.ts +5 -2
- package/src/formatter/variables.ts +48 -1
- package/src/main.ts +2 -0
- package/src/protocol/messages.ts +3 -0
- package/tests/fixtures/async-app.js +1 -1
- package/tests/fixtures/error-app.js +1 -1
- package/tests/fixtures/simple-app.js +1 -1
- package/tests/fixtures/ts-app/src/app.ts +4 -0
- package/tests/integration/state.test.ts +7 -7
- package/tests/unit/daemon.test.ts +1 -1
- package/tests/unit/formatter.test.ts +8 -4
- package/.bin/ndbg +0 -0
- package/.claude/skills/ndbg-debugger/ndbg-debugger/SKILL.md +0 -116
- package/.claude/skills/ndbg-debugger/ndbg-debugger/references/commands.md +0 -173
|
@@ -15,7 +15,7 @@ registerCommand("exceptions", async (args) => {
|
|
|
15
15
|
|
|
16
16
|
if (!DaemonClient.isRunning(session)) {
|
|
17
17
|
console.error(`No active session "${session}"`);
|
|
18
|
-
console.error(" -> Try:
|
|
18
|
+
console.error(" -> Try: agent-dbg launch --brk node app.js");
|
|
19
19
|
return 1;
|
|
20
20
|
}
|
|
21
21
|
|
package/src/commands/hotpatch.ts
CHANGED
|
@@ -6,14 +6,14 @@ registerCommand("hotpatch", async (args) => {
|
|
|
6
6
|
|
|
7
7
|
if (!DaemonClient.isRunning(session)) {
|
|
8
8
|
console.error(`No active session "${session}"`);
|
|
9
|
-
console.error(" -> Try:
|
|
9
|
+
console.error(" -> Try: agent-dbg launch --brk node app.js");
|
|
10
10
|
return 1;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
const file = args.subcommand;
|
|
14
14
|
if (!file) {
|
|
15
15
|
console.error("No file specified");
|
|
16
|
-
console.error(" -> Try:
|
|
16
|
+
console.error(" -> Try: agent-dbg hotpatch app.js");
|
|
17
17
|
return 1;
|
|
18
18
|
}
|
|
19
19
|
|
package/src/commands/launch.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { registerCommand } from "../cli/registry.ts";
|
|
2
2
|
import { DaemonClient } from "../daemon/client.ts";
|
|
3
3
|
import { spawnDaemon } from "../daemon/spawn.ts";
|
|
4
|
+
import { shortPath } from "../formatter/path.ts";
|
|
4
5
|
|
|
5
6
|
registerCommand("launch", async (args) => {
|
|
6
7
|
const session = args.global.session;
|
|
@@ -12,26 +13,21 @@ registerCommand("launch", async (args) => {
|
|
|
12
13
|
// Reconstruct the full command from subcommand + positionals.
|
|
13
14
|
// The parser treats the second non-flag word as subcommand, but for launch
|
|
14
15
|
// it should be part of the command to execute.
|
|
15
|
-
// e.g., "
|
|
16
|
+
// e.g., "agent-dbg launch node app.js" -> subcommand="node", positionals=["app.js"]
|
|
16
17
|
// We need command = ["node", "app.js"]
|
|
17
18
|
const command = args.subcommand ? [args.subcommand, ...args.positionals] : [...args.positionals];
|
|
18
19
|
|
|
19
20
|
if (command.length === 0) {
|
|
20
21
|
console.error("No command specified");
|
|
21
|
-
console.error(" -> Try:
|
|
22
|
+
console.error(" -> Try: agent-dbg launch --brk node app.js");
|
|
22
23
|
return 1;
|
|
23
24
|
}
|
|
24
25
|
|
|
25
|
-
//
|
|
26
|
-
if (DaemonClient.isRunning(session)) {
|
|
27
|
-
|
|
28
|
-
console.error(` -> Try: ndbg stop --session ${session}`);
|
|
29
|
-
return 1;
|
|
26
|
+
// Spawn daemon if not already running (e.g. started externally for debugging)
|
|
27
|
+
if (!DaemonClient.isRunning(session)) {
|
|
28
|
+
await spawnDaemon(session, { timeout });
|
|
30
29
|
}
|
|
31
30
|
|
|
32
|
-
// Spawn daemon
|
|
33
|
-
await spawnDaemon(session, { timeout });
|
|
34
|
-
|
|
35
31
|
// Send launch command to daemon
|
|
36
32
|
const client = new DaemonClient(session);
|
|
37
33
|
const response = await client.request("launch", { command, brk, port });
|
|
@@ -57,7 +53,7 @@ registerCommand("launch", async (args) => {
|
|
|
57
53
|
if (data.paused && data.pauseInfo) {
|
|
58
54
|
const col = data.pauseInfo.column !== undefined ? `:${data.pauseInfo.column + 1}` : "";
|
|
59
55
|
const loc = data.pauseInfo.url
|
|
60
|
-
? `${data.pauseInfo.url}:${data.pauseInfo.line}${col}`
|
|
56
|
+
? `${shortPath(data.pauseInfo.url)}:${data.pauseInfo.line}${col}`
|
|
61
57
|
: "unknown";
|
|
62
58
|
console.log(`Paused at ${loc}`);
|
|
63
59
|
} else {
|
package/src/commands/logpoint.ts
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import { registerCommand } from "../cli/registry.ts";
|
|
2
2
|
import { DaemonClient } from "../daemon/client.ts";
|
|
3
|
+
import { shortPath } from "../formatter/path.ts";
|
|
3
4
|
|
|
4
5
|
registerCommand("logpoint", async (args) => {
|
|
5
6
|
const session = args.global.session;
|
|
6
7
|
|
|
7
8
|
if (!DaemonClient.isRunning(session)) {
|
|
8
9
|
console.error(`No active session "${session}"`);
|
|
9
|
-
console.error(" -> Try:
|
|
10
|
+
console.error(" -> Try: agent-dbg launch --brk node app.js");
|
|
10
11
|
return 1;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
const target = args.subcommand;
|
|
14
15
|
if (!target) {
|
|
15
16
|
console.error("No target specified");
|
|
16
|
-
console.error(' -> Try:
|
|
17
|
+
console.error(' -> Try: agent-dbg logpoint src/app.ts:42 "x =", x');
|
|
17
18
|
return 1;
|
|
18
19
|
}
|
|
19
20
|
|
|
@@ -21,7 +22,7 @@ registerCommand("logpoint", async (args) => {
|
|
|
21
22
|
const lastColon = target.lastIndexOf(":");
|
|
22
23
|
if (lastColon === -1 || lastColon === 0) {
|
|
23
24
|
console.error(`Invalid logpoint target: "${target}"`);
|
|
24
|
-
console.error(' -> Try:
|
|
25
|
+
console.error(' -> Try: agent-dbg logpoint src/app.ts:42 "x =", x');
|
|
25
26
|
return 1;
|
|
26
27
|
}
|
|
27
28
|
|
|
@@ -29,7 +30,7 @@ registerCommand("logpoint", async (args) => {
|
|
|
29
30
|
const line = parseInt(target.slice(lastColon + 1), 10);
|
|
30
31
|
if (Number.isNaN(line) || line <= 0) {
|
|
31
32
|
console.error(`Invalid line number in "${target}"`);
|
|
32
|
-
console.error(' -> Try:
|
|
33
|
+
console.error(' -> Try: agent-dbg logpoint src/app.ts:42 "x =", x');
|
|
33
34
|
return 1;
|
|
34
35
|
}
|
|
35
36
|
|
|
@@ -37,7 +38,7 @@ registerCommand("logpoint", async (args) => {
|
|
|
37
38
|
const template = args.positionals[0];
|
|
38
39
|
if (!template) {
|
|
39
40
|
console.error("No log template specified");
|
|
40
|
-
console.error(' -> Try:
|
|
41
|
+
console.error(' -> Try: agent-dbg logpoint src/app.ts:42 "x =", x');
|
|
41
42
|
return 1;
|
|
42
43
|
}
|
|
43
44
|
|
|
@@ -70,7 +71,7 @@ registerCommand("logpoint", async (args) => {
|
|
|
70
71
|
if (args.global.json) {
|
|
71
72
|
console.log(JSON.stringify(data, null, 2));
|
|
72
73
|
} else {
|
|
73
|
-
const loc = `${data.location.url}:${data.location.line}`;
|
|
74
|
+
const loc = `${shortPath(data.location.url)}:${data.location.line}`;
|
|
74
75
|
console.log(`${data.ref} set at ${loc} (log: ${template})`);
|
|
75
76
|
}
|
|
76
77
|
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import type { FSWatcher } from "node:fs";
|
|
2
|
+
import {
|
|
3
|
+
closeSync,
|
|
4
|
+
existsSync,
|
|
5
|
+
openSync,
|
|
6
|
+
readFileSync,
|
|
7
|
+
readSync,
|
|
8
|
+
watch,
|
|
9
|
+
writeFileSync,
|
|
10
|
+
} from "node:fs";
|
|
11
|
+
import type { CdpLogEntry } from "../cdp/logger.ts";
|
|
12
|
+
import { registerCommand } from "../cli/registry.ts";
|
|
13
|
+
import { getLogPath } from "../daemon/paths.ts";
|
|
14
|
+
import { formatLogEntry } from "../formatter/logs.ts";
|
|
15
|
+
|
|
16
|
+
function parseEntries(text: string): CdpLogEntry[] {
|
|
17
|
+
const entries: CdpLogEntry[] = [];
|
|
18
|
+
for (const line of text.split("\n")) {
|
|
19
|
+
if (!line.trim()) continue;
|
|
20
|
+
try {
|
|
21
|
+
entries.push(JSON.parse(line) as CdpLogEntry);
|
|
22
|
+
} catch {
|
|
23
|
+
// skip malformed lines
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return entries;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function filterByDomain(entries: CdpLogEntry[], domain: string): CdpLogEntry[] {
|
|
30
|
+
return entries.filter((e) => e.method.startsWith(`${domain}.`));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function printEntries(entries: CdpLogEntry[], json: boolean): void {
|
|
34
|
+
for (const entry of entries) {
|
|
35
|
+
if (json) {
|
|
36
|
+
console.log(JSON.stringify(entry));
|
|
37
|
+
} else {
|
|
38
|
+
console.log(formatLogEntry(entry));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
registerCommand("logs", async (args) => {
|
|
44
|
+
const session = args.global.session;
|
|
45
|
+
const logPath = getLogPath(session);
|
|
46
|
+
|
|
47
|
+
// --clear: truncate log file
|
|
48
|
+
if (args.flags.clear === true) {
|
|
49
|
+
if (existsSync(logPath)) {
|
|
50
|
+
writeFileSync(logPath, "");
|
|
51
|
+
console.log("Log cleared");
|
|
52
|
+
} else {
|
|
53
|
+
console.log("No log file to clear");
|
|
54
|
+
}
|
|
55
|
+
return 0;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (!existsSync(logPath)) {
|
|
59
|
+
console.error(`No log file for session "${session}"`);
|
|
60
|
+
console.error(" -> Try: agent-dbg launch --brk node app.js");
|
|
61
|
+
return 1;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const isJson = args.global.json;
|
|
65
|
+
const domain = typeof args.flags.domain === "string" ? args.flags.domain : undefined;
|
|
66
|
+
const limit = typeof args.flags.limit === "string" ? parseInt(args.flags.limit, 10) : 50;
|
|
67
|
+
const follow = args.flags.follow === true;
|
|
68
|
+
|
|
69
|
+
// Read existing entries
|
|
70
|
+
const content = readFileSync(logPath, "utf-8");
|
|
71
|
+
let entries = parseEntries(content);
|
|
72
|
+
if (domain) entries = filterByDomain(entries, domain);
|
|
73
|
+
|
|
74
|
+
// Apply limit (show last N) — in follow mode, show all existing
|
|
75
|
+
const sliced = follow ? entries : entries.slice(-limit);
|
|
76
|
+
printEntries(sliced, isJson);
|
|
77
|
+
|
|
78
|
+
if (!follow) return 0;
|
|
79
|
+
|
|
80
|
+
// Follow mode: watch for new lines appended to the file
|
|
81
|
+
let offset = Buffer.byteLength(content, "utf-8");
|
|
82
|
+
let watcher: FSWatcher | undefined;
|
|
83
|
+
|
|
84
|
+
const readNew = () => {
|
|
85
|
+
try {
|
|
86
|
+
const size = Bun.file(logPath).size;
|
|
87
|
+
if (size <= offset) return;
|
|
88
|
+
|
|
89
|
+
const fd = openSync(logPath, "r");
|
|
90
|
+
const buf = Buffer.alloc(size - offset);
|
|
91
|
+
readSync(fd, buf, 0, buf.length, offset);
|
|
92
|
+
closeSync(fd);
|
|
93
|
+
offset = size;
|
|
94
|
+
|
|
95
|
+
let newEntries = parseEntries(buf.toString("utf-8"));
|
|
96
|
+
if (domain) newEntries = filterByDomain(newEntries, domain);
|
|
97
|
+
printEntries(newEntries, isJson);
|
|
98
|
+
} catch {
|
|
99
|
+
// File may have been truncated or removed
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
watcher = watch(logPath, () => {
|
|
104
|
+
readNew();
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// Keep alive until Ctrl+C
|
|
108
|
+
await new Promise<void>((resolve) => {
|
|
109
|
+
process.on("SIGINT", () => {
|
|
110
|
+
watcher?.close();
|
|
111
|
+
resolve();
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
return 0;
|
|
116
|
+
});
|
package/src/commands/pause.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { registerCommand } from "../cli/registry.ts";
|
|
2
2
|
import { DaemonClient } from "../daemon/client.ts";
|
|
3
|
-
import type {
|
|
3
|
+
import type { StateSnapshot } from "../daemon/session.ts";
|
|
4
|
+
import { printState } from "./print-state.ts";
|
|
4
5
|
|
|
5
6
|
registerCommand("pause", async (args) => {
|
|
6
7
|
const session = args.global.session;
|
|
7
8
|
|
|
8
9
|
if (!DaemonClient.isRunning(session)) {
|
|
9
10
|
console.error(`No active session "${session}"`);
|
|
10
|
-
console.error(" -> Try:
|
|
11
|
+
console.error(" -> Try: agent-dbg launch --brk node app.js");
|
|
11
12
|
return 1;
|
|
12
13
|
}
|
|
13
14
|
|
|
@@ -20,27 +21,13 @@ registerCommand("pause", async (args) => {
|
|
|
20
21
|
return 1;
|
|
21
22
|
}
|
|
22
23
|
|
|
23
|
-
const data = response.data as
|
|
24
|
+
const data = response.data as StateSnapshot;
|
|
24
25
|
|
|
25
26
|
if (args.global.json) {
|
|
26
27
|
console.log(JSON.stringify(data, null, 2));
|
|
27
28
|
} else {
|
|
28
|
-
|
|
29
|
+
printState(data);
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
return 0;
|
|
32
33
|
});
|
|
33
|
-
|
|
34
|
-
function printStatus(data: SessionStatus): void {
|
|
35
|
-
if (data.state === "paused" && data.pauseInfo) {
|
|
36
|
-
const col = data.pauseInfo.column !== undefined ? `:${data.pauseInfo.column + 1}` : "";
|
|
37
|
-
const loc = data.pauseInfo.url
|
|
38
|
-
? `${data.pauseInfo.url}:${(data.pauseInfo.line ?? 0) + 1}${col}`
|
|
39
|
-
: "unknown";
|
|
40
|
-
console.log(`Paused at ${loc} (${data.pauseInfo.reason})`);
|
|
41
|
-
} else if (data.state === "running") {
|
|
42
|
-
console.log("Running");
|
|
43
|
-
} else {
|
|
44
|
-
console.log(`${data.state}`);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { StateSnapshot } from "../daemon/session.ts";
|
|
2
|
+
import { shortPath } from "../formatter/path.ts";
|
|
3
|
+
import type { SourceLine } from "../formatter/source.ts";
|
|
4
|
+
import { formatSource } from "../formatter/source.ts";
|
|
5
|
+
import type { StackFrame } from "../formatter/stack.ts";
|
|
6
|
+
import { formatStack } from "../formatter/stack.ts";
|
|
7
|
+
import type { Variable } from "../formatter/variables.ts";
|
|
8
|
+
import { formatVariables } from "../formatter/variables.ts";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Shared formatting for StateSnapshot output.
|
|
12
|
+
* Used by state, step, continue, pause, run-to commands.
|
|
13
|
+
*/
|
|
14
|
+
export function printState(data: StateSnapshot): void {
|
|
15
|
+
// Non-paused states
|
|
16
|
+
if (data.status !== "paused") {
|
|
17
|
+
const icon = data.status === "running" ? "\u25B6" : "\u25CB";
|
|
18
|
+
console.log(`${icon} ${data.status === "running" ? "Running" : "Idle"}`);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Paused state — header
|
|
23
|
+
const loc = data.location
|
|
24
|
+
? `${shortPath(data.location.url)}:${data.location.line}${data.location.column !== undefined ? `:${data.location.column}` : ""}`
|
|
25
|
+
: "unknown";
|
|
26
|
+
const reason = data.reason ?? "unknown";
|
|
27
|
+
console.log(`\u23F8 Paused at ${loc} (${reason})`);
|
|
28
|
+
|
|
29
|
+
// Source section
|
|
30
|
+
if (data.source?.lines) {
|
|
31
|
+
console.log("");
|
|
32
|
+
console.log("Source:");
|
|
33
|
+
const sourceLines: SourceLine[] = data.source.lines.map((l) => ({
|
|
34
|
+
lineNumber: l.line,
|
|
35
|
+
content: l.text,
|
|
36
|
+
isCurrent: l.current,
|
|
37
|
+
currentColumn: l.current ? data.location?.column : undefined,
|
|
38
|
+
}));
|
|
39
|
+
console.log(formatSource(sourceLines));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Variables section
|
|
43
|
+
if (data.vars) {
|
|
44
|
+
console.log("");
|
|
45
|
+
const vars: Variable[] = data.vars.map((v) => ({
|
|
46
|
+
ref: v.ref,
|
|
47
|
+
name: v.name,
|
|
48
|
+
value: v.value,
|
|
49
|
+
scope: v.scope,
|
|
50
|
+
}));
|
|
51
|
+
const formatted = formatVariables(vars);
|
|
52
|
+
if (formatted) {
|
|
53
|
+
// Single scope: simple header; multi-scope: grouped headers from formatter
|
|
54
|
+
const scopes = new Set(vars.map((v) => v.scope ?? "local"));
|
|
55
|
+
if (scopes.size <= 1) {
|
|
56
|
+
console.log("Locals:");
|
|
57
|
+
}
|
|
58
|
+
console.log(formatted);
|
|
59
|
+
} else {
|
|
60
|
+
console.log("Locals:");
|
|
61
|
+
console.log(" (none)");
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Stack section
|
|
66
|
+
if (data.stack) {
|
|
67
|
+
console.log("");
|
|
68
|
+
console.log("Stack:");
|
|
69
|
+
const frames: StackFrame[] = data.stack.map((f) => ({
|
|
70
|
+
ref: f.ref,
|
|
71
|
+
functionName: f.functionName,
|
|
72
|
+
file: f.file,
|
|
73
|
+
line: f.line,
|
|
74
|
+
column: f.column,
|
|
75
|
+
isAsync: f.isAsync,
|
|
76
|
+
}));
|
|
77
|
+
console.log(formatStack(frames));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Breakpoints section
|
|
81
|
+
if (data.breakpointCount !== undefined) {
|
|
82
|
+
console.log("");
|
|
83
|
+
console.log(`Breakpoints: ${data.breakpointCount} active`);
|
|
84
|
+
}
|
|
85
|
+
}
|
package/src/commands/props.ts
CHANGED
|
@@ -6,14 +6,14 @@ registerCommand("props", async (args) => {
|
|
|
6
6
|
|
|
7
7
|
if (!DaemonClient.isRunning(session)) {
|
|
8
8
|
console.error(`No active session "${session}"`);
|
|
9
|
-
console.error(" -> Try:
|
|
9
|
+
console.error(" -> Try: agent-dbg launch --brk node app.js");
|
|
10
10
|
return 1;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
const ref = args.subcommand;
|
|
14
14
|
if (!ref) {
|
|
15
15
|
console.error("No ref specified");
|
|
16
|
-
console.error(" -> Try:
|
|
16
|
+
console.error(" -> Try: agent-dbg props @v1");
|
|
17
17
|
return 1;
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -7,7 +7,7 @@ registerCommand("restart-frame", async (args) => {
|
|
|
7
7
|
|
|
8
8
|
if (!DaemonClient.isRunning(session)) {
|
|
9
9
|
console.error(`No active session "${session}"`);
|
|
10
|
-
console.error(" -> Try:
|
|
10
|
+
console.error(" -> Try: agent-dbg launch --brk node app.js");
|
|
11
11
|
return 1;
|
|
12
12
|
}
|
|
13
13
|
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { registerCommand } from "../cli/registry.ts";
|
|
2
|
+
import { DaemonClient } from "../daemon/client.ts";
|
|
3
|
+
import type { LaunchResult } from "../daemon/session.ts";
|
|
4
|
+
import { shortPath } from "../formatter/path.ts";
|
|
5
|
+
|
|
6
|
+
registerCommand("restart", async (args) => {
|
|
7
|
+
const session = args.global.session;
|
|
8
|
+
|
|
9
|
+
if (!DaemonClient.isRunning(session)) {
|
|
10
|
+
console.error(`No active session "${session}"`);
|
|
11
|
+
console.error(" -> Try: agent-dbg launch --brk node app.js");
|
|
12
|
+
return 1;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const client = new DaemonClient(session);
|
|
16
|
+
const response = await client.request("restart");
|
|
17
|
+
|
|
18
|
+
if (!response.ok) {
|
|
19
|
+
console.error(`${response.error}`);
|
|
20
|
+
if (response.suggestion) console.error(` ${response.suggestion}`);
|
|
21
|
+
return 1;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const data = response.data as LaunchResult;
|
|
25
|
+
|
|
26
|
+
if (args.global.json) {
|
|
27
|
+
console.log(JSON.stringify(data, null, 2));
|
|
28
|
+
} else {
|
|
29
|
+
console.log(`Session "${session}" restarted (pid ${data.pid})`);
|
|
30
|
+
if (data.paused && data.pauseInfo) {
|
|
31
|
+
const col = data.pauseInfo.column !== undefined ? `:${data.pauseInfo.column + 1}` : "";
|
|
32
|
+
const loc = data.pauseInfo.url
|
|
33
|
+
? `${shortPath(data.pauseInfo.url)}:${data.pauseInfo.line}${col}`
|
|
34
|
+
: "unknown";
|
|
35
|
+
console.log(`Paused at ${loc}`);
|
|
36
|
+
} else {
|
|
37
|
+
console.log("Running");
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return 0;
|
|
42
|
+
});
|
package/src/commands/run-to.ts
CHANGED
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
import { registerCommand } from "../cli/registry.ts";
|
|
2
2
|
import { DaemonClient } from "../daemon/client.ts";
|
|
3
|
-
import type {
|
|
3
|
+
import type { StateSnapshot } from "../daemon/session.ts";
|
|
4
|
+
import { printState } from "./print-state.ts";
|
|
4
5
|
|
|
5
6
|
registerCommand("run-to", async (args) => {
|
|
6
7
|
const session = args.global.session;
|
|
7
8
|
|
|
8
9
|
if (!DaemonClient.isRunning(session)) {
|
|
9
10
|
console.error(`No active session "${session}"`);
|
|
10
|
-
console.error(" -> Try:
|
|
11
|
+
console.error(" -> Try: agent-dbg launch --brk node app.js");
|
|
11
12
|
return 1;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
// Parse file:line from subcommand
|
|
15
|
-
// e.g., "
|
|
16
|
+
// e.g., "agent-dbg run-to src/file.ts:42" -> subcommand = "src/file.ts:42"
|
|
16
17
|
const target = args.subcommand ?? args.positionals[0];
|
|
17
18
|
if (!target) {
|
|
18
19
|
console.error("No target specified");
|
|
19
|
-
console.error(" -> Try:
|
|
20
|
+
console.error(" -> Try: agent-dbg run-to src/file.ts:42");
|
|
20
21
|
return 1;
|
|
21
22
|
}
|
|
22
23
|
|
|
@@ -44,27 +45,13 @@ registerCommand("run-to", async (args) => {
|
|
|
44
45
|
return 1;
|
|
45
46
|
}
|
|
46
47
|
|
|
47
|
-
const data = response.data as
|
|
48
|
+
const data = response.data as StateSnapshot;
|
|
48
49
|
|
|
49
50
|
if (args.global.json) {
|
|
50
51
|
console.log(JSON.stringify(data, null, 2));
|
|
51
52
|
} else {
|
|
52
|
-
|
|
53
|
+
printState(data);
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
return 0;
|
|
56
57
|
});
|
|
57
|
-
|
|
58
|
-
function printStatus(data: SessionStatus): void {
|
|
59
|
-
if (data.state === "paused" && data.pauseInfo) {
|
|
60
|
-
const col = data.pauseInfo.column !== undefined ? `:${data.pauseInfo.column + 1}` : "";
|
|
61
|
-
const loc = data.pauseInfo.url
|
|
62
|
-
? `${data.pauseInfo.url}:${(data.pauseInfo.line ?? 0) + 1}${col}`
|
|
63
|
-
: "unknown";
|
|
64
|
-
console.log(`Paused at ${loc} (${data.pauseInfo.reason})`);
|
|
65
|
-
} else if (data.state === "running") {
|
|
66
|
-
console.log("Running");
|
|
67
|
-
} else {
|
|
68
|
-
console.log(`${data.state}`);
|
|
69
|
-
}
|
|
70
|
-
}
|
package/src/commands/scripts.ts
CHANGED
|
@@ -6,7 +6,7 @@ registerCommand("scripts", async (args) => {
|
|
|
6
6
|
|
|
7
7
|
if (!DaemonClient.isRunning(session)) {
|
|
8
8
|
console.error(`No active session "${session}"`);
|
|
9
|
-
console.error(" -> Try:
|
|
9
|
+
console.error(" -> Try: agent-dbg launch --brk node app.js");
|
|
10
10
|
return 1;
|
|
11
11
|
}
|
|
12
12
|
|
package/src/commands/search.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { registerCommand } from "../cli/registry.ts";
|
|
2
2
|
import { DaemonClient } from "../daemon/client.ts";
|
|
3
|
+
import { shortPath } from "../formatter/path.ts";
|
|
3
4
|
|
|
4
5
|
registerCommand("search", async (args) => {
|
|
5
6
|
const session = args.global.session;
|
|
6
7
|
|
|
7
8
|
if (!DaemonClient.isRunning(session)) {
|
|
8
9
|
console.error(`No active session "${session}"`);
|
|
9
|
-
console.error(" -> Try:
|
|
10
|
+
console.error(" -> Try: agent-dbg launch --brk node app.js");
|
|
10
11
|
return 1;
|
|
11
12
|
}
|
|
12
13
|
|
|
@@ -22,7 +23,7 @@ registerCommand("search", async (args) => {
|
|
|
22
23
|
|
|
23
24
|
if (!query) {
|
|
24
25
|
console.error("No search query specified");
|
|
25
|
-
console.error(" -> Try:
|
|
26
|
+
console.error(" -> Try: agent-dbg search <query> [--regex] [--case-sensitive]");
|
|
26
27
|
return 1;
|
|
27
28
|
}
|
|
28
29
|
|
|
@@ -66,7 +67,7 @@ registerCommand("search", async (args) => {
|
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
for (const match of data) {
|
|
69
|
-
console.log(`${match.url}:${match.line}: ${match.content}`);
|
|
70
|
+
console.log(`${shortPath(match.url)}:${match.line}: ${match.content}`);
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
return 0;
|
|
@@ -6,7 +6,7 @@ registerCommand("set-return", async (args) => {
|
|
|
6
6
|
|
|
7
7
|
if (!DaemonClient.isRunning(session)) {
|
|
8
8
|
console.error(`No active session "${session}"`);
|
|
9
|
-
console.error(" -> Try:
|
|
9
|
+
console.error(" -> Try: agent-dbg launch --brk node app.js");
|
|
10
10
|
return 1;
|
|
11
11
|
}
|
|
12
12
|
|
|
@@ -20,7 +20,7 @@ registerCommand("set-return", async (args) => {
|
|
|
20
20
|
|
|
21
21
|
if (!value) {
|
|
22
22
|
console.error("No value specified");
|
|
23
|
-
console.error(" -> Try:
|
|
23
|
+
console.error(" -> Try: agent-dbg set-return 42");
|
|
24
24
|
return 1;
|
|
25
25
|
}
|
|
26
26
|
|
package/src/commands/set.ts
CHANGED
|
@@ -6,21 +6,21 @@ registerCommand("set", async (args) => {
|
|
|
6
6
|
|
|
7
7
|
if (!DaemonClient.isRunning(session)) {
|
|
8
8
|
console.error(`No active session "${session}"`);
|
|
9
|
-
console.error(" -> Try:
|
|
9
|
+
console.error(" -> Try: agent-dbg launch --brk node app.js");
|
|
10
10
|
return 1;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
const varName = args.subcommand;
|
|
14
14
|
if (!varName) {
|
|
15
15
|
console.error("No variable name specified");
|
|
16
|
-
console.error(" -> Try:
|
|
16
|
+
console.error(" -> Try: agent-dbg set counter 42");
|
|
17
17
|
return 1;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
const valueParts = args.positionals;
|
|
21
21
|
if (valueParts.length === 0) {
|
|
22
22
|
console.error("No value specified");
|
|
23
|
-
console.error(" -> Try:
|
|
23
|
+
console.error(" -> Try: agent-dbg set counter 42");
|
|
24
24
|
return 1;
|
|
25
25
|
}
|
|
26
26
|
const value = valueParts.join(" ");
|
package/src/commands/source.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { registerCommand } from "../cli/registry.ts";
|
|
2
2
|
import { DaemonClient } from "../daemon/client.ts";
|
|
3
|
+
import { shortPath } from "../formatter/path.ts";
|
|
3
4
|
import type { SourceLine } from "../formatter/source.ts";
|
|
4
5
|
import { formatSource } from "../formatter/source.ts";
|
|
5
6
|
|
|
@@ -8,7 +9,7 @@ registerCommand("source", async (args) => {
|
|
|
8
9
|
|
|
9
10
|
if (!DaemonClient.isRunning(session)) {
|
|
10
11
|
console.error(`No active session "${session}"`);
|
|
11
|
-
console.error(" -> Try:
|
|
12
|
+
console.error(" -> Try: agent-dbg launch --brk node app.js");
|
|
12
13
|
return 1;
|
|
13
14
|
}
|
|
14
15
|
|
|
@@ -47,7 +48,7 @@ registerCommand("source", async (args) => {
|
|
|
47
48
|
return 0;
|
|
48
49
|
}
|
|
49
50
|
|
|
50
|
-
console.log(`Source: ${data.url}`);
|
|
51
|
+
console.log(`Source: ${shortPath(data.url)}`);
|
|
51
52
|
const sourceLines: SourceLine[] = data.lines.map((l) => ({
|
|
52
53
|
lineNumber: l.line,
|
|
53
54
|
content: l.text,
|
|
@@ -6,7 +6,7 @@ registerCommand("sourcemap", async (args) => {
|
|
|
6
6
|
|
|
7
7
|
if (!DaemonClient.isRunning(session)) {
|
|
8
8
|
console.error(`No active session "${session}"`);
|
|
9
|
-
console.error(" -> Try:
|
|
9
|
+
console.error(" -> Try: agent-dbg launch --brk node app.js");
|
|
10
10
|
return 1;
|
|
11
11
|
}
|
|
12
12
|
|
package/src/commands/stack.ts
CHANGED
|
@@ -8,7 +8,7 @@ registerCommand("stack", async (args) => {
|
|
|
8
8
|
|
|
9
9
|
if (!DaemonClient.isRunning(session)) {
|
|
10
10
|
console.error(`No active session "${session}"`);
|
|
11
|
-
console.error(" -> Try:
|
|
11
|
+
console.error(" -> Try: agent-dbg launch --brk node app.js");
|
|
12
12
|
return 1;
|
|
13
13
|
}
|
|
14
14
|
|