@commentary-dev/cli 0.1.0 → 0.1.1
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/README.md +17 -5
- package/dist/index.js +254 -31
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -97,13 +97,14 @@ Wait for the next new review comment:
|
|
|
97
97
|
```bash
|
|
98
98
|
commentary wait-comment --json
|
|
99
99
|
commentary wait-comment --file docs/spec.md --timeout 15m
|
|
100
|
+
commentary wait-comment --no-include-replies
|
|
100
101
|
```
|
|
101
102
|
|
|
102
103
|
Reply and resolve:
|
|
103
104
|
|
|
104
105
|
```bash
|
|
105
|
-
commentary reply <thread-id> "Updated this in revision 3."
|
|
106
|
-
commentary resolve <thread-id> --message "Addressed in revision 3."
|
|
106
|
+
commentary reply <thread-id> "Updated this in revision 3." --alias "Docs agent"
|
|
107
|
+
commentary resolve <thread-id> --message "Addressed in revision 3." --alias "Docs agent"
|
|
107
108
|
```
|
|
108
109
|
|
|
109
110
|
Pull latest reviewed content safely:
|
|
@@ -132,8 +133,8 @@ commentary revision
|
|
|
132
133
|
commentary watch
|
|
133
134
|
commentary comments
|
|
134
135
|
commentary wait-comment
|
|
135
|
-
commentary reply <
|
|
136
|
-
commentary resolve <
|
|
136
|
+
commentary reply <thread-id> <message>
|
|
137
|
+
commentary resolve <thread-id>
|
|
137
138
|
commentary pull
|
|
138
139
|
commentary open
|
|
139
140
|
commentary status
|
|
@@ -161,6 +162,7 @@ COMMENTARY_TOKEN
|
|
|
161
162
|
COMMENTARY_SESSION
|
|
162
163
|
COMMENTARY_NO_COLOR
|
|
163
164
|
COMMENTARY_CONFIG_DIR
|
|
165
|
+
COMMENTARY_AGENT_ALIAS
|
|
164
166
|
```
|
|
165
167
|
|
|
166
168
|
## Base URLs
|
|
@@ -259,7 +261,17 @@ JSON output is intended to be stable across patch releases. Additive fields may
|
|
|
259
261
|
|
|
260
262
|
`commentary wait-comment` uses Commentary draft-review live updates and requires a server that exposes `GET /api/v1/draft-reviews/{sessionId}/events`. Tokens need the `commentary.comments.read` scope.
|
|
261
263
|
|
|
262
|
-
By default the command starts from `cursor=latest`, waits for a future `comment.created` event, prints the first match, and exits. Use `--include-replies` to
|
|
264
|
+
By default the command starts from `cursor=latest`, waits for a future `comment.created` or `reply.created` event, prints the first match, and exits. Replies are included by default so a human follow-up to an agent reply wakes the waiting agent. Use `--no-include-replies` to wait only for top-level comments, `--cursor <id>` to resume after a known live-event cursor, `--from beginning` to read historical events, and `--timeout 0` to wait indefinitely. If the event stream disconnects before a matching comment arrives, the CLI reconnects with the latest cursor it has seen.
|
|
265
|
+
|
|
266
|
+
## Heading Anchors
|
|
267
|
+
|
|
268
|
+
Commentary-rendered Markdown heading anchors normalize heading text to lowercase words separated by single hyphens. Punctuation and repeated separators collapse, so `Security & Compliance` becomes `#security-compliance`. This can differ from GitHub-style anchors for headings with punctuation.
|
|
269
|
+
|
|
270
|
+
## Agent Alias
|
|
271
|
+
|
|
272
|
+
Use `--alias <name>` on `reply` or `resolve --message` to attribute agent-authored replies. For automation, set `COMMENTARY_AGENT_ALIAS`; an explicit `--alias` flag takes precedence.
|
|
273
|
+
|
|
274
|
+
`commentary reply` reopens a resolved thread when the reply API response still reports the thread as resolved. This keeps a thread active after a new follow-up response.
|
|
263
275
|
|
|
264
276
|
## Local Metadata
|
|
265
277
|
|
package/dist/index.js
CHANGED
|
@@ -220,7 +220,10 @@ var CommentaryApiClient = class {
|
|
|
220
220
|
`/api/v1/draft-reviews/${encodeURIComponent(input.sessionId)}/comments/${encodeURIComponent(input.threadId)}/replies`,
|
|
221
221
|
{
|
|
222
222
|
method: "POST",
|
|
223
|
-
body: {
|
|
223
|
+
body: {
|
|
224
|
+
bodyMarkdown: input.bodyMarkdown,
|
|
225
|
+
...input.agentAlias ? { agentAlias: input.agentAlias } : {}
|
|
226
|
+
}
|
|
224
227
|
}
|
|
225
228
|
);
|
|
226
229
|
}
|
|
@@ -717,7 +720,7 @@ function commentBody(thread) {
|
|
|
717
720
|
}
|
|
718
721
|
function commentAuthor(thread) {
|
|
719
722
|
const first = thread.comments[0];
|
|
720
|
-
return first?.authorLogin ?? first?.author ?? "Unknown";
|
|
723
|
+
return first?.agentAlias ?? first?.authorLogin ?? first?.author ?? "Unknown";
|
|
721
724
|
}
|
|
722
725
|
function formatCommentsText(threads) {
|
|
723
726
|
if (threads.length === 0) {
|
|
@@ -762,7 +765,7 @@ function formatCommentsMarkdown(input) {
|
|
|
762
765
|
lines.push("Replies:");
|
|
763
766
|
replies.forEach((reply) => {
|
|
764
767
|
lines.push(
|
|
765
|
-
`- ${reply.authorLogin ?? reply.author ?? "Unknown"}: ${reply.bodyMarkdown ?? reply.body ?? ""}`
|
|
768
|
+
`- ${reply.agentAlias ?? reply.authorLogin ?? reply.author ?? "Unknown"}: ${reply.bodyMarkdown ?? reply.body ?? ""}`
|
|
766
769
|
);
|
|
767
770
|
});
|
|
768
771
|
lines.push("");
|
|
@@ -968,8 +971,12 @@ function payloadString(event, key) {
|
|
|
968
971
|
const value = event.payload[key];
|
|
969
972
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
970
973
|
}
|
|
974
|
+
function resolveAgentAlias(alias) {
|
|
975
|
+
const value = alias?.trim() || process.env.COMMENTARY_AGENT_ALIAS?.trim();
|
|
976
|
+
return value || void 0;
|
|
977
|
+
}
|
|
971
978
|
function isWaitCommentMatch(input) {
|
|
972
|
-
const allowed = input.event.type === "comment.created" || input.includeReplies
|
|
979
|
+
const allowed = input.event.type === "comment.created" || input.includeReplies !== false && input.event.type === "reply.created";
|
|
973
980
|
if (!allowed) {
|
|
974
981
|
return false;
|
|
975
982
|
}
|
|
@@ -1365,11 +1372,24 @@ async function replyCommand(runtime, threadId, message, options) {
|
|
|
1365
1372
|
...options,
|
|
1366
1373
|
baseUrl: loaded?.metadata.baseUrl ?? options.baseUrl
|
|
1367
1374
|
});
|
|
1368
|
-
const result = await client.replyToComment({
|
|
1375
|
+
const result = await client.replyToComment({
|
|
1376
|
+
sessionId,
|
|
1377
|
+
threadId,
|
|
1378
|
+
bodyMarkdown: message,
|
|
1379
|
+
agentAlias: resolveAgentAlias(options.alias)
|
|
1380
|
+
});
|
|
1381
|
+
const thread = result.thread.status === "resolved" ? (await client.updateCommentStatus({
|
|
1382
|
+
sessionId,
|
|
1383
|
+
threadId,
|
|
1384
|
+
status: "open"
|
|
1385
|
+
})).thread : result.thread;
|
|
1369
1386
|
if (options.json) {
|
|
1370
|
-
writeJson(runtime.stdout, { ok: true, thread
|
|
1387
|
+
writeJson(runtime.stdout, { ok: true, thread });
|
|
1371
1388
|
} else {
|
|
1372
|
-
writeText(
|
|
1389
|
+
writeText(
|
|
1390
|
+
runtime.stdout,
|
|
1391
|
+
thread.status === "open" && result.thread.status === "resolved" ? `Replied to ${threadId} and reopened the thread.` : `Replied to ${threadId}.`
|
|
1392
|
+
);
|
|
1373
1393
|
}
|
|
1374
1394
|
}
|
|
1375
1395
|
async function resolveCommand(runtime, threadId, options) {
|
|
@@ -1383,7 +1403,12 @@ async function resolveCommand(runtime, threadId, options) {
|
|
|
1383
1403
|
baseUrl: loaded?.metadata.baseUrl ?? options.baseUrl
|
|
1384
1404
|
});
|
|
1385
1405
|
if (options.message?.trim()) {
|
|
1386
|
-
await client.replyToComment({
|
|
1406
|
+
await client.replyToComment({
|
|
1407
|
+
sessionId,
|
|
1408
|
+
threadId,
|
|
1409
|
+
bodyMarkdown: options.message.trim(),
|
|
1410
|
+
agentAlias: resolveAgentAlias(options.alias)
|
|
1411
|
+
});
|
|
1387
1412
|
}
|
|
1388
1413
|
const result = await client.updateCommentStatus({ sessionId, threadId, status: "resolved" });
|
|
1389
1414
|
if (options.json) {
|
|
@@ -1472,13 +1497,25 @@ async function statusCommand(runtime, options) {
|
|
|
1472
1497
|
const current = await readTrackedFiles(root, loaded.metadata.trackedFiles);
|
|
1473
1498
|
const changed = changedFiles(current, loaded.metadata.trackedFiles).map((file) => file.path);
|
|
1474
1499
|
let openComments = null;
|
|
1500
|
+
let resolvedComments = null;
|
|
1475
1501
|
try {
|
|
1476
1502
|
const client = await makeClient(runtime, { ...options, baseUrl: loaded.metadata.baseUrl });
|
|
1477
|
-
|
|
1503
|
+
const [openResult, resolvedResult] = await Promise.all([
|
|
1504
|
+
client.listComments({ sessionId: loaded.metadata.reviewSessionId, status: "open" }),
|
|
1505
|
+
client.listComments({ sessionId: loaded.metadata.reviewSessionId, status: "resolved" })
|
|
1506
|
+
]);
|
|
1507
|
+
openComments = openResult.threads.length;
|
|
1508
|
+
resolvedComments = resolvedResult.threads.length;
|
|
1478
1509
|
} catch {
|
|
1479
1510
|
openComments = null;
|
|
1511
|
+
resolvedComments = null;
|
|
1480
1512
|
}
|
|
1481
|
-
const payload = {
|
|
1513
|
+
const payload = {
|
|
1514
|
+
...publicSessionJson(loaded.metadata),
|
|
1515
|
+
changedFiles: changed,
|
|
1516
|
+
openComments,
|
|
1517
|
+
resolvedComments
|
|
1518
|
+
};
|
|
1482
1519
|
if (options.json) {
|
|
1483
1520
|
writeJson(runtime.stdout, payload);
|
|
1484
1521
|
} else {
|
|
@@ -1491,7 +1528,8 @@ async function statusCommand(runtime, options) {
|
|
|
1491
1528
|
`Tracked files: ${loaded.metadata.trackedFiles.length}`,
|
|
1492
1529
|
`Last revision: ${loaded.metadata.lastKnownRevision ?? "unknown"}`,
|
|
1493
1530
|
`Changed files: ${changed.length ? changed.join(", ") : "none"}`,
|
|
1494
|
-
`Open comments: ${openComments ?? "unknown"}
|
|
1531
|
+
`Open comments: ${openComments ?? "unknown"}`,
|
|
1532
|
+
`Resolved comments: ${resolvedComments ?? "unknown"}`
|
|
1495
1533
|
].join("\n")
|
|
1496
1534
|
);
|
|
1497
1535
|
}
|
|
@@ -1561,66 +1599,251 @@ function commandOptionsWithNoOpen(command) {
|
|
|
1561
1599
|
noOpen: options.open === false
|
|
1562
1600
|
};
|
|
1563
1601
|
}
|
|
1602
|
+
function helpText(details, examples) {
|
|
1603
|
+
return [
|
|
1604
|
+
"",
|
|
1605
|
+
"Details:",
|
|
1606
|
+
` ${details}`,
|
|
1607
|
+
"",
|
|
1608
|
+
"Examples:",
|
|
1609
|
+
...examples.map((example) => ` ${example}`)
|
|
1610
|
+
].join("\n");
|
|
1611
|
+
}
|
|
1564
1612
|
function buildProgram(runtime) {
|
|
1565
1613
|
const program = new Command();
|
|
1566
|
-
program.
|
|
1567
|
-
|
|
1568
|
-
|
|
1614
|
+
program.configureOutput({
|
|
1615
|
+
writeOut: (chunk) => runtime.stdout.write(chunk),
|
|
1616
|
+
writeErr: (chunk) => runtime.stderr.write(chunk),
|
|
1617
|
+
outputError: (chunk, write) => write(chunk)
|
|
1618
|
+
});
|
|
1619
|
+
program.name("commentary").description(
|
|
1620
|
+
"Create and manage Commentary draft review sessions from local Markdown, MDX, HTML, and text files."
|
|
1621
|
+
).version("0.1.0").showHelpAfterError().exitOverride();
|
|
1622
|
+
program.option(
|
|
1623
|
+
"--base-url <url>",
|
|
1624
|
+
"Commentary base URL. Defaults to COMMENTARY_BASE_URL or https://commentary.dev."
|
|
1625
|
+
).option(
|
|
1626
|
+
"--token <token>",
|
|
1627
|
+
"Commentary API token. Defaults to COMMENTARY_TOKEN or the stored login token."
|
|
1628
|
+
).option("--json", "Print machine-readable JSON output for agent automation.").option("--verbose", "Print verbose diagnostics, including live-event reconnect notices.").option("--quiet", "Suppress non-essential human-readable output.").option("--no-color", "Disable color output").option(
|
|
1629
|
+
"--session-file <path>",
|
|
1630
|
+
"Path to project session metadata. Defaults to .commentary/session.json."
|
|
1631
|
+
);
|
|
1632
|
+
program.command("login").description("Authenticate with Commentary.").option(
|
|
1633
|
+
"--token <token>",
|
|
1634
|
+
"Store an existing API token instead of starting browser/device login."
|
|
1635
|
+
).option("--no-open", "Print the device login URL instead of opening a browser.").addHelpText(
|
|
1636
|
+
"after",
|
|
1637
|
+
helpText("Stores the token outside project metadata. Session files never contain secrets.", [
|
|
1638
|
+
"commentary login",
|
|
1639
|
+
"commentary login --token <commentary-api-token>",
|
|
1640
|
+
"commentary --base-url https://commentary.example.com login"
|
|
1641
|
+
])
|
|
1642
|
+
).action(async function() {
|
|
1569
1643
|
await loginCommand(runtime, commandOptionsWithNoOpen(this));
|
|
1570
1644
|
});
|
|
1571
|
-
program.command("logout").description("Remove the stored Commentary token for the selected base URL.").
|
|
1572
|
-
|
|
1573
|
-
|
|
1645
|
+
program.command("logout").description("Remove the stored Commentary token for the selected base URL.").addHelpText(
|
|
1646
|
+
"after",
|
|
1647
|
+
helpText(
|
|
1648
|
+
"Removes only local CLI authentication state for the selected Commentary base URL.",
|
|
1649
|
+
["commentary logout", "commentary --base-url https://commentary.example.com logout"]
|
|
1650
|
+
)
|
|
1651
|
+
).action(wrap(runtime, (options) => logoutCommand(runtime, options)));
|
|
1652
|
+
program.command("whoami").description("Validate the configured Commentary token.").addHelpText(
|
|
1653
|
+
"after",
|
|
1654
|
+
helpText("Checks whether the active token can reach the draft-review API.", [
|
|
1655
|
+
"commentary whoami",
|
|
1656
|
+
"COMMENTARY_TOKEN=<token> commentary whoami --json"
|
|
1657
|
+
])
|
|
1658
|
+
).action(wrap(runtime, (options) => whoamiCommand(runtime, options)));
|
|
1659
|
+
program.command("review").description("Create a draft review from files or folders.").argument("<paths...>").option("--title <title>", "Review title shown in Commentary.").option("--description <description>", "Optional review description shown in Commentary.").addOption(
|
|
1574
1660
|
new Option("--content-type <type>", "Content type").choices(["auto", "markdown", "html", "plain_text"]).default("auto")
|
|
1575
|
-
).option("--watch", "
|
|
1661
|
+
).option("--watch", "Keep running and upload a new revision whenever tracked files change.").option("--no-open", "Do not open the browser after creating the review.").option(
|
|
1662
|
+
"--root <path>",
|
|
1663
|
+
"Root used for relative review paths. Defaults to the current directory."
|
|
1664
|
+
).option(
|
|
1665
|
+
"--include <glob>",
|
|
1666
|
+
"Include glob for directory review. May be repeated.",
|
|
1667
|
+
collectOption
|
|
1668
|
+
).option(
|
|
1669
|
+
"--exclude <glob>",
|
|
1670
|
+
"Exclude glob for directory review. May be repeated.",
|
|
1671
|
+
collectOption
|
|
1672
|
+
).addHelpText(
|
|
1673
|
+
"after",
|
|
1674
|
+
helpText(
|
|
1675
|
+
"Creates a hosted draft review and writes .commentary/session.json for later commands.",
|
|
1676
|
+
[
|
|
1677
|
+
'commentary review ./docs/spec.md --title "Product spec"',
|
|
1678
|
+
'commentary review ./docs --include "**/*.md" --exclude "drafts/**"',
|
|
1679
|
+
"commentary review ./docs/spec.md --watch --no-open",
|
|
1680
|
+
"commentary review ./docs/spec.md --json"
|
|
1681
|
+
]
|
|
1682
|
+
)
|
|
1683
|
+
).action(async function(paths) {
|
|
1576
1684
|
await reviewCommand(runtime, paths, commandOptionsWithNoOpen(this));
|
|
1577
1685
|
});
|
|
1578
|
-
const sync = program.command("sync").description("Upload current tracked files as a new revision.").option("--message <summary>", "Revision summary").option("--all", "Upload even when hashes have not changed").option("--dry-run", "Print pending
|
|
1686
|
+
const sync = program.command("sync").description("Upload current tracked files as a new revision.").option("--message <summary>", "Revision summary shown in Commentary.").option("--all", "Upload even when tracked file hashes have not changed.").option("--dry-run", "Print pending changed paths without uploading a revision.").addHelpText(
|
|
1687
|
+
"after",
|
|
1688
|
+
helpText("Reads the linked session, compares tracked files, and uploads changed content.", [
|
|
1689
|
+
'commentary sync --message "Address review comments"',
|
|
1690
|
+
"commentary sync --dry-run --json",
|
|
1691
|
+
'commentary sync --all --message "Refresh rendered output"'
|
|
1692
|
+
])
|
|
1693
|
+
).action(async function() {
|
|
1579
1694
|
await syncCommand(runtime, { ...globalOptions(this), ...this.opts() });
|
|
1580
1695
|
});
|
|
1581
|
-
program.command("revision").description("Alias for sync.").option("--message <summary>", "Revision summary").option("--all", "Upload even when hashes have not changed").option("--dry-run", "Print pending
|
|
1696
|
+
program.command("revision").description("Alias for sync.").option("--message <summary>", "Revision summary shown in Commentary.").option("--all", "Upload even when tracked file hashes have not changed.").option("--dry-run", "Print pending changed paths without uploading a revision.").addHelpText(
|
|
1697
|
+
"after",
|
|
1698
|
+
helpText("Alias for commentary sync.", [
|
|
1699
|
+
'commentary revision --message "Address review comments"',
|
|
1700
|
+
"commentary revision --dry-run"
|
|
1701
|
+
])
|
|
1702
|
+
).action(async function() {
|
|
1582
1703
|
await syncCommand(runtime, { ...globalOptions(this), ...this.opts() });
|
|
1583
1704
|
});
|
|
1584
|
-
program.command("watch").description("Watch tracked files and sync revisions.").option("--debounce <ms>", "
|
|
1705
|
+
program.command("watch").description("Watch tracked files and sync revisions.").option("--debounce <ms>", "Milliseconds to wait after a file event before syncing.", "1500").option("--message <summary>", "Revision summary used for watch-triggered uploads.").addHelpText(
|
|
1706
|
+
"after",
|
|
1707
|
+
helpText(
|
|
1708
|
+
"Runs until interrupted. It watches files already listed in .commentary/session.json.",
|
|
1709
|
+
["commentary watch", 'commentary watch --debounce 3000 --message "Watch sync"']
|
|
1710
|
+
)
|
|
1711
|
+
).action(async function() {
|
|
1585
1712
|
await watchCommand(runtime, { ...globalOptions(this), ...this.opts() });
|
|
1586
1713
|
});
|
|
1587
1714
|
program.command("comments").description("List draft review comments.").addOption(
|
|
1588
1715
|
new Option("--format <format>", "Output format").choices(["text", "markdown", "json"]).default("text")
|
|
1589
|
-
).option("--open", "Show open
|
|
1716
|
+
).option("--open", "Show open threads. This is the default unless --resolved or --all is used.").option("--resolved", "Show resolved threads.").option("--all", "Show open and resolved threads.").option("--file <path>", "Filter by review file path, e.g. docs/spec.md.").option("--session <id>", "Use an explicit draft review session id instead of local metadata.").addHelpText(
|
|
1717
|
+
"after",
|
|
1718
|
+
helpText(
|
|
1719
|
+
"Prints thread ids, file anchors, comment bodies, and replies for the selected session.",
|
|
1720
|
+
[
|
|
1721
|
+
"commentary comments --format markdown --open",
|
|
1722
|
+
"commentary comments --all --json",
|
|
1723
|
+
"commentary comments --file docs/spec.md --format text",
|
|
1724
|
+
"commentary comments --session draft_123 --json"
|
|
1725
|
+
]
|
|
1726
|
+
)
|
|
1727
|
+
).action(async function() {
|
|
1590
1728
|
await commentsCommand(runtime, { ...globalOptions(this), ...this.opts() });
|
|
1591
1729
|
});
|
|
1592
|
-
program.command("wait-comment").description("Wait for the next draft review comment event.").option("--session <id>", "
|
|
1730
|
+
program.command("wait-comment").description("Wait for the next draft review comment event.").option("--session <id>", "Use an explicit draft review session id instead of local metadata.").option("--file <path>", "Filter by review file path, e.g. docs/spec.md.").option("--include-replies", "Return reply.created events. This is enabled by default.").option(
|
|
1731
|
+
"--no-include-replies",
|
|
1732
|
+
"Ignore reply.created events and wait only for new top-level comments."
|
|
1733
|
+
).option(
|
|
1734
|
+
"--cursor <id>",
|
|
1735
|
+
"Resume after a specific live-event cursor returned by a previous wait."
|
|
1736
|
+
).addOption(
|
|
1593
1737
|
new Option("--from <position>", "Where to start when no cursor is provided").choices(["beginning", "latest"]).default("latest")
|
|
1594
|
-
).option("--timeout <duration>", "Maximum wait time, e.g. 30m, 10s, or 0", "30m").addOption(
|
|
1738
|
+
).option("--timeout <duration>", "Maximum wait time, e.g. 30m, 10s, or 0 for no timeout.", "30m").addOption(
|
|
1595
1739
|
new Option("--format <format>", "Output format").choices(["text", "markdown", "json"]).default("markdown")
|
|
1740
|
+
).addHelpText(
|
|
1741
|
+
"after",
|
|
1742
|
+
helpText(
|
|
1743
|
+
"Streams draft-review live events, auto-reconnects on stream drops, and exits after the first matching comment or reply.",
|
|
1744
|
+
[
|
|
1745
|
+
"commentary wait-comment --json",
|
|
1746
|
+
"commentary wait-comment --file docs/spec.md --timeout 15m",
|
|
1747
|
+
"commentary wait-comment --cursor event_123 --json",
|
|
1748
|
+
"commentary wait-comment --from beginning --no-include-replies",
|
|
1749
|
+
"commentary wait-comment --timeout 0 --format markdown"
|
|
1750
|
+
]
|
|
1751
|
+
)
|
|
1596
1752
|
).action(async function() {
|
|
1597
1753
|
await waitCommentCommand(runtime, { ...globalOptions(this), ...this.opts() });
|
|
1598
1754
|
});
|
|
1599
|
-
program.command("reply").description("Reply to a comment thread.").argument("<
|
|
1755
|
+
program.command("reply").description("Reply to a comment thread.").argument("<thread-id>").argument("<message>").option("--session <id>", "Use an explicit draft review session id instead of local metadata.").option(
|
|
1756
|
+
"--alias <name>",
|
|
1757
|
+
"Agent alias for reply attribution. Overrides COMMENTARY_AGENT_ALIAS."
|
|
1758
|
+
).addHelpText(
|
|
1759
|
+
"after",
|
|
1760
|
+
helpText(
|
|
1761
|
+
"Adds a reply to the thread id printed by comments or wait-comment. Replies reopen resolved threads.",
|
|
1762
|
+
[
|
|
1763
|
+
'commentary reply thread_123 "Updated this in revision 3."',
|
|
1764
|
+
'commentary reply thread_123 "Fixed." --alias "Docs agent"',
|
|
1765
|
+
'COMMENTARY_AGENT_ALIAS="Docs agent" commentary reply thread_123 "Fixed." --json'
|
|
1766
|
+
]
|
|
1767
|
+
)
|
|
1768
|
+
).action(async function(threadId, message) {
|
|
1600
1769
|
await replyCommand(runtime, threadId, message, { ...globalOptions(this), ...this.opts() });
|
|
1601
1770
|
});
|
|
1602
|
-
program.command("resolve").description("Resolve a comment thread.").argument("<
|
|
1771
|
+
program.command("resolve").description("Resolve a comment thread.").argument("<thread-id>").option("--session <id>", "Use an explicit draft review session id instead of local metadata.").option("--message <message>", "Add a closing reply before resolving the thread.").option(
|
|
1772
|
+
"--alias <name>",
|
|
1773
|
+
"Agent alias for the closing reply. Overrides COMMENTARY_AGENT_ALIAS."
|
|
1774
|
+
).addHelpText(
|
|
1775
|
+
"after",
|
|
1776
|
+
helpText(
|
|
1777
|
+
"Marks a thread resolved. Use --message when the final response should be visible in the thread.",
|
|
1778
|
+
[
|
|
1779
|
+
"commentary resolve thread_123",
|
|
1780
|
+
'commentary resolve thread_123 --message "Addressed in revision 3."',
|
|
1781
|
+
'commentary resolve thread_123 --message "Fixed." --alias "Docs agent" --json'
|
|
1782
|
+
]
|
|
1783
|
+
)
|
|
1784
|
+
).action(async function(threadId) {
|
|
1603
1785
|
await resolveCommand(runtime, threadId, { ...globalOptions(this), ...this.opts() });
|
|
1604
1786
|
});
|
|
1605
|
-
program.command("pull").description("Download latest reviewed files safely.").option("--dry-run", "Show
|
|
1787
|
+
program.command("pull").description("Download latest reviewed files safely.").option("--dry-run", "Show which files would change without writing to disk.").option("--yes", "Allow overwriting changed local files.").option("--backup", "Create .bak files before overwriting existing files.").option(
|
|
1788
|
+
"--output <dir>",
|
|
1789
|
+
"Write files to a separate directory instead of overwriting tracked files."
|
|
1790
|
+
).addHelpText(
|
|
1791
|
+
"after",
|
|
1792
|
+
helpText("Downloads the latest Commentary file content for the linked draft review.", [
|
|
1793
|
+
"commentary pull --dry-run",
|
|
1794
|
+
"commentary pull --output reviewed",
|
|
1795
|
+
"commentary pull --backup --yes"
|
|
1796
|
+
])
|
|
1797
|
+
).action(async function() {
|
|
1606
1798
|
await pullCommand(runtime, { ...globalOptions(this), ...this.opts() });
|
|
1607
1799
|
});
|
|
1608
|
-
program.command("open").description("Open the linked review in a browser, or print the URL in headless output.").option("--session <id>", "
|
|
1800
|
+
program.command("open").description("Open the linked review in a browser, or print the URL in headless output.").option("--session <id>", "Open an explicit draft review session id instead of local metadata.").addHelpText(
|
|
1801
|
+
"after",
|
|
1802
|
+
helpText("In CI or non-TTY output this prints the URL instead of launching a browser.", [
|
|
1803
|
+
"commentary open",
|
|
1804
|
+
"commentary open --session draft_123"
|
|
1805
|
+
])
|
|
1806
|
+
).action(async function() {
|
|
1609
1807
|
await openCommand(runtime, { ...globalOptions(this), ...this.opts() });
|
|
1610
1808
|
});
|
|
1611
|
-
program.command("status").description("Show current linked review status.").
|
|
1612
|
-
|
|
1613
|
-
|
|
1809
|
+
program.command("status").description("Show current linked review status.").addHelpText(
|
|
1810
|
+
"after",
|
|
1811
|
+
helpText(
|
|
1812
|
+
"Summarizes local metadata, changed tracked files, and open/resolved thread counts.",
|
|
1813
|
+
["commentary status", "commentary status --json"]
|
|
1814
|
+
)
|
|
1815
|
+
).action(wrap(runtime, (options) => statusCommand(runtime, options)));
|
|
1816
|
+
program.command("sessions").description("List draft review sessions for the authenticated account.").addHelpText(
|
|
1817
|
+
"after",
|
|
1818
|
+
helpText("Lists draft reviews visible to the configured token.", [
|
|
1819
|
+
"commentary sessions",
|
|
1820
|
+
"commentary sessions --json"
|
|
1821
|
+
])
|
|
1822
|
+
).action(wrap(runtime, (options) => sessionsCommand(runtime, options)));
|
|
1823
|
+
program.command("revisions").description("List revisions for the linked or specified draft review.").option("--session <id>", "Use an explicit draft review session id instead of local metadata.").addHelpText(
|
|
1824
|
+
"after",
|
|
1825
|
+
helpText("Shows uploaded revisions for the selected draft review.", [
|
|
1826
|
+
"commentary revisions",
|
|
1827
|
+
"commentary revisions --session draft_123 --json"
|
|
1828
|
+
])
|
|
1829
|
+
).action(async function() {
|
|
1614
1830
|
await revisionsCommand(runtime, { ...globalOptions(this), ...this.opts() });
|
|
1615
1831
|
});
|
|
1616
1832
|
sync.alias("upload");
|
|
1617
1833
|
program.addHelpText(
|
|
1618
1834
|
"after",
|
|
1619
1835
|
`
|
|
1836
|
+
Agent loop:
|
|
1837
|
+
1. commentary review ./docs/spec.md --title "Spec"
|
|
1838
|
+
2. commentary wait-comment --json
|
|
1839
|
+
3. edit files, then commentary sync --message "Address comments"
|
|
1840
|
+
4. commentary reply <thread-id> "Fixed." --alias "Docs agent"
|
|
1841
|
+
|
|
1620
1842
|
Examples:
|
|
1621
1843
|
npx ${PACKAGE_NAME} review ./docs/spec.md
|
|
1622
1844
|
commentary comments --format markdown --open
|
|
1623
1845
|
commentary wait-comment --json
|
|
1846
|
+
commentary resolve <thread-id> --message "Addressed."
|
|
1624
1847
|
`
|
|
1625
1848
|
);
|
|
1626
1849
|
return program;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/commands.ts","../src/errors.ts","../src/sse.ts","../src/api-client.ts","../src/constants.ts","../src/config.ts","../src/content.ts","../src/files.ts","../src/hash.ts","../src/output.ts","../src/session.ts","../src/index.ts"],"sourcesContent":["import { Command, Option } from \"commander\";\nimport {\n commentsCommand,\n loginCommand,\n logoutCommand,\n openCommand,\n pullCommand,\n replyCommand,\n resolveCommand,\n reviewCommand,\n revisionsCommand,\n sessionsCommand,\n statusCommand,\n syncCommand,\n watchCommand,\n waitCommentCommand,\n whoamiCommand,\n type CommandRuntime,\n type GlobalOptions,\n} from \"./commands.js\";\nimport { PACKAGE_NAME } from \"./constants.js\";\nimport { CliError, ExitCode, toErrorMessage } from \"./errors.js\";\n\ntype RunOptions = Partial<CommandRuntime>;\n\nfunction collectOption(value: string, previous: string[] = []) {\n previous.push(value);\n return previous;\n}\n\nfunction runtimeFromOptions(options?: RunOptions): CommandRuntime {\n return {\n cwd: options?.cwd ?? process.cwd(),\n stdout: options?.stdout ?? process.stdout,\n stderr: options?.stderr ?? process.stderr,\n fetchImpl: options?.fetchImpl,\n isTty: options?.isTty ?? process.stdout.isTTY,\n };\n}\n\nfunction globalOptions(command: Command): GlobalOptions {\n return command.optsWithGlobals<GlobalOptions>();\n}\n\nfunction wrap(runtime: CommandRuntime, action: (options: GlobalOptions) => Promise<void>) {\n return async function wrapped(this: Command) {\n await action(globalOptions(this));\n };\n}\n\nfunction commandOptionsWithNoOpen(command: Command) {\n const options = command.opts();\n return {\n ...globalOptions(command),\n ...options,\n noOpen: (options as { open?: boolean }).open === false,\n };\n}\n\nexport function buildProgram(runtime: CommandRuntime) {\n const program = new Command();\n program\n .name(\"commentary\")\n .description(\"Create and manage Commentary draft review sessions from local files.\")\n .version(\"0.1.0\")\n .showHelpAfterError()\n .exitOverride();\n\n program\n .option(\"--base-url <url>\", \"Commentary base URL\")\n .option(\"--token <token>\", \"Commentary API token\")\n .option(\"--json\", \"Print JSON output\")\n .option(\"--verbose\", \"Print verbose diagnostics\")\n .option(\"--quiet\", \"Suppress non-essential output\")\n .option(\"--no-color\", \"Disable color output\")\n .option(\"--session-file <path>\", \"Path to project session metadata\");\n\n program\n .command(\"login\")\n .description(\"Authenticate with Commentary.\")\n .option(\"--token <token>\", \"Store an existing API token\")\n .option(\"--no-open\", \"Do not open the browser during device login\")\n .action(async function (this: Command) {\n await loginCommand(runtime, commandOptionsWithNoOpen(this));\n });\n\n program\n .command(\"logout\")\n .description(\"Remove the stored Commentary token for the selected base URL.\")\n .action(wrap(runtime, (options) => logoutCommand(runtime, options)));\n\n program\n .command(\"whoami\")\n .description(\"Validate the configured Commentary token.\")\n .action(wrap(runtime, (options) => whoamiCommand(runtime, options)));\n\n program\n .command(\"review\")\n .description(\"Create a draft review from files or folders.\")\n .argument(\"<paths...>\")\n .option(\"--title <title>\", \"Review title\")\n .option(\"--description <description>\", \"Review description\")\n .addOption(\n new Option(\"--content-type <type>\", \"Content type\")\n .choices([\"auto\", \"markdown\", \"html\", \"plain_text\"])\n .default(\"auto\"),\n )\n .option(\"--watch\", \"Watch files and sync after creating the review\")\n .option(\"--no-open\", \"Do not open the browser\")\n .option(\"--root <path>\", \"Root for relative review paths\")\n .option(\"--include <glob>\", \"Include glob for directory review\", collectOption)\n .option(\"--exclude <glob>\", \"Exclude glob for directory review\", collectOption)\n .action(async function (this: Command, paths: string[]) {\n await reviewCommand(runtime, paths, commandOptionsWithNoOpen(this));\n });\n\n const sync = program\n .command(\"sync\")\n .description(\"Upload current tracked files as a new revision.\")\n .option(\"--message <summary>\", \"Revision summary\")\n .option(\"--all\", \"Upload even when hashes have not changed\")\n .option(\"--dry-run\", \"Print pending changes without uploading\")\n .action(async function (this: Command) {\n await syncCommand(runtime, { ...globalOptions(this), ...this.opts() });\n });\n program\n .command(\"revision\")\n .description(\"Alias for sync.\")\n .option(\"--message <summary>\", \"Revision summary\")\n .option(\"--all\", \"Upload even when hashes have not changed\")\n .option(\"--dry-run\", \"Print pending changes without uploading\")\n .action(async function (this: Command) {\n await syncCommand(runtime, { ...globalOptions(this), ...this.opts() });\n });\n\n program\n .command(\"watch\")\n .description(\"Watch tracked files and sync revisions.\")\n .option(\"--debounce <ms>\", \"Debounce in milliseconds\", \"1500\")\n .option(\"--message <summary>\", \"Revision summary\")\n .action(async function (this: Command) {\n await watchCommand(runtime, { ...globalOptions(this), ...this.opts() });\n });\n\n program\n .command(\"comments\")\n .description(\"List draft review comments.\")\n .addOption(\n new Option(\"--format <format>\", \"Output format\")\n .choices([\"text\", \"markdown\", \"json\"])\n .default(\"text\"),\n )\n .option(\"--open\", \"Show open comments\")\n .option(\"--resolved\", \"Show resolved comments\")\n .option(\"--all\", \"Show all comments\")\n .option(\"--file <path>\", \"Filter by file path\")\n .option(\"--session <id>\", \"Explicit session id\")\n .action(async function (this: Command) {\n await commentsCommand(runtime, { ...globalOptions(this), ...this.opts() });\n });\n\n program\n .command(\"wait-comment\")\n .description(\"Wait for the next draft review comment event.\")\n .option(\"--session <id>\", \"Explicit session id\")\n .option(\"--file <path>\", \"Filter by file path\")\n .option(\"--include-replies\", \"Also return reply.created events\")\n .option(\"--cursor <id>\", \"Resume after a specific live event cursor\")\n .addOption(\n new Option(\"--from <position>\", \"Where to start when no cursor is provided\")\n .choices([\"beginning\", \"latest\"])\n .default(\"latest\"),\n )\n .option(\"--timeout <duration>\", \"Maximum wait time, e.g. 30m, 10s, or 0\", \"30m\")\n .addOption(\n new Option(\"--format <format>\", \"Output format\")\n .choices([\"text\", \"markdown\", \"json\"])\n .default(\"markdown\"),\n )\n .action(async function (this: Command) {\n await waitCommentCommand(runtime, { ...globalOptions(this), ...this.opts() });\n });\n\n program\n .command(\"reply\")\n .description(\"Reply to a comment thread.\")\n .argument(\"<comment-id>\")\n .argument(\"<message>\")\n .option(\"--session <id>\", \"Explicit session id\")\n .action(async function (this: Command, threadId: string, message: string) {\n await replyCommand(runtime, threadId, message, { ...globalOptions(this), ...this.opts() });\n });\n\n program\n .command(\"resolve\")\n .description(\"Resolve a comment thread.\")\n .argument(\"<comment-id>\")\n .option(\"--session <id>\", \"Explicit session id\")\n .option(\"--message <message>\", \"Reply before resolving\")\n .action(async function (this: Command, threadId: string) {\n await resolveCommand(runtime, threadId, { ...globalOptions(this), ...this.opts() });\n });\n\n program\n .command(\"pull\")\n .description(\"Download latest reviewed files safely.\")\n .option(\"--dry-run\", \"Show what would change\")\n .option(\"--yes\", \"Overwrite changed files\")\n .option(\"--backup\", \"Create .bak files before overwrite\")\n .option(\"--output <dir>\", \"Write files to a separate directory\")\n .action(async function (this: Command) {\n await pullCommand(runtime, { ...globalOptions(this), ...this.opts() });\n });\n\n program\n .command(\"open\")\n .description(\"Open the linked review in a browser, or print the URL in headless output.\")\n .option(\"--session <id>\", \"Explicit session id\")\n .action(async function (this: Command) {\n await openCommand(runtime, { ...globalOptions(this), ...this.opts() });\n });\n\n program\n .command(\"status\")\n .description(\"Show current linked review status.\")\n .action(wrap(runtime, (options) => statusCommand(runtime, options)));\n\n program\n .command(\"sessions\")\n .description(\"List draft review sessions for the authenticated account.\")\n .action(wrap(runtime, (options) => sessionsCommand(runtime, options)));\n\n program\n .command(\"revisions\")\n .description(\"List revisions for the linked or specified draft review.\")\n .option(\"--session <id>\", \"Explicit session id\")\n .action(async function (this: Command) {\n await revisionsCommand(runtime, { ...globalOptions(this), ...this.opts() });\n });\n\n sync.alias(\"upload\");\n program.addHelpText(\n \"after\",\n `\\nExamples:\\n npx ${PACKAGE_NAME} review ./docs/spec.md\\n commentary comments --format markdown --open\\n commentary wait-comment --json\\n`,\n );\n return program;\n}\n\nexport async function runCli(argv = process.argv.slice(2), options?: RunOptions) {\n const runtime = runtimeFromOptions(options);\n const program = buildProgram(runtime);\n try {\n await program.parseAsync(argv, { from: \"user\" });\n return ExitCode.Ok;\n } catch (error) {\n const commanderError = error as { code?: string; exitCode?: number; message?: string };\n if (\n commanderError.code === \"commander.helpDisplayed\" ||\n commanderError.code === \"commander.version\"\n ) {\n return ExitCode.Ok;\n }\n if (commanderError.code?.startsWith(\"commander.\")) {\n runtime.stderr.write(`${commanderError.message ?? \"Invalid command.\"}\\n`);\n return commanderError.exitCode ?? ExitCode.Usage;\n }\n if (error instanceof CliError) {\n runtime.stderr.write(`${error.message}\\n`);\n return error.exitCode;\n }\n runtime.stderr.write(`${toErrorMessage(error)}\\n`);\n return ExitCode.General;\n }\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport chokidar from \"chokidar\";\nimport open from \"open\";\nimport { CommentaryApiClient } from \"./api-client.js\";\nimport { CLIENT_ID, CLIENT_NAME, REQUIRED_SCOPES, SESSION_FILE } from \"./constants.js\";\nimport { normalizeBaseUrl, removeStoredToken, resolveToken, setStoredToken } from \"./config.js\";\nimport { normalizeReviewPath } from \"./content.js\";\nimport { CliError, ExitCode } from \"./errors.js\";\nimport { collectFiles, readTrackedFiles, toTrackedFiles } from \"./files.js\";\nimport { contentHash } from \"./hash.js\";\nimport {\n formatCommentsMarkdown,\n formatCommentsText,\n formatReviewCreated,\n formatRevision,\n formatWaitCommentMarkdown,\n formatWaitCommentText,\n publicSessionJson,\n writeJson,\n writeText,\n type Writer,\n} from \"./output.js\";\nimport {\n findSessionFile,\n loadSessionMetadata,\n saveSessionMetadata,\n sessionRoot,\n} from \"./session.js\";\nimport type { CollectedFile } from \"./files.js\";\nimport type {\n DraftReviewLiveEvent,\n DraftReviewRevision,\n RequestedContentType,\n SessionMetadata,\n TrackedFile,\n} from \"./types.js\";\n\nexport type CommandRuntime = {\n cwd: string;\n stdout: Writer;\n stderr: Writer;\n fetchImpl?: typeof fetch | undefined;\n isTty?: boolean | undefined;\n};\n\nexport type GlobalOptions = {\n baseUrl?: string | undefined;\n token?: string | undefined;\n json?: boolean | undefined;\n verbose?: boolean | undefined;\n quiet?: boolean | undefined;\n noColor?: boolean | undefined;\n sessionFile?: string | undefined;\n};\n\nfunction nowIso() {\n return new Date().toISOString();\n}\n\nasync function makeClient(runtime: CommandRuntime, options: GlobalOptions) {\n const baseUrl = normalizeBaseUrl(options.baseUrl);\n const token = await resolveToken({ baseUrl, token: options.token });\n return new CommentaryApiClient({ baseUrl, token, fetchImpl: runtime.fetchImpl });\n}\n\nfunction apiFilesFromRevision(revision: DraftReviewRevision | null) {\n return revision?.files.map((file) => ({\n fileId: file.fileId,\n path: file.path,\n contentHash: file.contentHash,\n sizeBytes: file.sizeBytes,\n contentType: file.contentType,\n }));\n}\n\nfunction changedFiles(current: CollectedFile[], tracked: TrackedFile[]) {\n const trackedByPath = new Map(tracked.map((file) => [file.path, file]));\n return current.filter((file) => {\n const previous = trackedByPath.get(file.path);\n return (\n !previous ||\n previous.contentHash !== file.contentHash ||\n previous.contentType !== file.contentType\n );\n });\n}\n\nasync function loadSession(runtime: CommandRuntime, options: GlobalOptions) {\n return loadSessionMetadata(runtime.cwd, options.sessionFile);\n}\n\nfunction shouldOpen(runtime: CommandRuntime, noOpen?: boolean) {\n return !noOpen && runtime.isTty !== false && !process.env.CI;\n}\n\nfunction placeholderSessionMetadata(input: {\n sessionId: string;\n baseUrl: string;\n}): SessionMetadata {\n return {\n version: 1,\n reviewSessionId: input.sessionId,\n reviewUrl: `${input.baseUrl}/review/draft/${encodeURIComponent(input.sessionId)}`,\n baseUrl: input.baseUrl,\n rootPath: \".\",\n trackedFiles: [],\n source: [],\n createdAt: \"\",\n lastSyncedAt: \"\",\n lastKnownRevision: null,\n };\n}\n\nasync function openOrPrint(runtime: CommandRuntime, url: string, noOpen?: boolean) {\n if (!shouldOpen(runtime, noOpen)) {\n writeText(runtime.stdout, url);\n return;\n }\n try {\n await open(url);\n } catch {\n writeText(runtime.stdout, url);\n }\n}\n\nfunction parseDurationMs(value: string | undefined, defaultMs: number) {\n const raw = value?.trim();\n if (!raw) {\n return defaultMs;\n }\n if (raw === \"0\") {\n return 0;\n }\n const match = raw.match(/^(\\d+)(ms|s|m|h)?$/i);\n if (!match) {\n throw new CliError(\n \"Duration must be a number with optional ms, s, m, or h suffix.\",\n ExitCode.Usage,\n );\n }\n const amount = Number(match[1]);\n const unit = match[2]?.toLowerCase() ?? \"ms\";\n const multiplier = unit === \"h\" ? 3_600_000 : unit === \"m\" ? 60_000 : unit === \"s\" ? 1_000 : 1;\n return amount * multiplier;\n}\n\nfunction delay(ms: number, signal: AbortSignal) {\n return new Promise<void>((resolve) => {\n if (signal.aborted) {\n resolve();\n return;\n }\n const timeout = setTimeout(resolve, ms);\n signal.addEventListener(\n \"abort\",\n () => {\n clearTimeout(timeout);\n resolve();\n },\n { once: true },\n );\n });\n}\n\nfunction payloadString(event: DraftReviewLiveEvent, key: string) {\n const value = event.payload[key];\n return typeof value === \"string\" && value.trim() ? value.trim() : null;\n}\n\nfunction isWaitCommentMatch(input: {\n event: DraftReviewLiveEvent;\n includeReplies?: boolean | undefined;\n filePath?: string | undefined;\n}) {\n const allowed =\n input.event.type === \"comment.created\" ||\n (input.includeReplies === true && input.event.type === \"reply.created\");\n if (!allowed) {\n return false;\n }\n if (!input.filePath) {\n return true;\n }\n return (\n (input.event.thread?.filePath ?? payloadString(input.event, \"filePath\")) === input.filePath\n );\n}\n\nexport async function loginCommand(\n runtime: CommandRuntime,\n options: GlobalOptions & { token?: string | undefined; noOpen?: boolean | undefined },\n) {\n const baseUrl = normalizeBaseUrl(options.baseUrl);\n if (options.token?.trim()) {\n await setStoredToken(baseUrl, { accessToken: options.token.trim() });\n if (options.json) {\n writeJson(runtime.stdout, { ok: true, baseUrl });\n } else {\n writeText(runtime.stdout, `Stored Commentary token for ${baseUrl}.`);\n }\n return;\n }\n\n const client = new CommentaryApiClient({ baseUrl, fetchImpl: runtime.fetchImpl });\n const resource = `${baseUrl}/api`;\n const device = await client.requestDeviceCode({\n clientId: CLIENT_ID,\n clientName: CLIENT_NAME,\n scope: REQUIRED_SCOPES.join(\" \"),\n resource,\n });\n if (options.json) {\n writeJson(runtime.stdout, {\n verificationUri: device.verification_uri,\n verificationUriComplete: device.verification_uri_complete,\n userCode: device.user_code,\n expiresIn: device.expires_in,\n });\n } else {\n writeText(\n runtime.stdout,\n [\n \"Connect Commentary\",\n \"\",\n `Open: ${device.verification_uri_complete}`,\n `Code: ${device.user_code}`,\n \"\",\n \"Waiting for approval...\",\n ].join(\"\\n\"),\n );\n }\n if (shouldOpen(runtime, options.noOpen)) {\n await open(device.verification_uri_complete).catch(() => undefined);\n }\n\n const startedAt = Date.now();\n const intervalMs = Math.max(1, device.interval) * 1000;\n while (Date.now() - startedAt < device.expires_in * 1000) {\n await new Promise((resolve) => setTimeout(resolve, intervalMs));\n try {\n const token = await client.exchangeDeviceCode({ deviceCode: device.device_code, resource });\n await setStoredToken(baseUrl, {\n accessToken: token.access_token,\n refreshToken: token.refresh_token,\n expiresAt: new Date(Date.now() + token.expires_in * 1000).toISOString(),\n });\n if (!options.json) {\n writeText(runtime.stdout, `Logged in to ${baseUrl}.`);\n }\n return;\n } catch (error) {\n if (error instanceof CliError && error.message === \"authorization_pending\") {\n continue;\n }\n throw error;\n }\n }\n throw new CliError(\"Device authorization expired.\", ExitCode.Auth);\n}\n\nexport async function logoutCommand(runtime: CommandRuntime, options: GlobalOptions) {\n const baseUrl = normalizeBaseUrl(options.baseUrl);\n await removeStoredToken(baseUrl);\n if (options.json) {\n writeJson(runtime.stdout, { ok: true, baseUrl });\n } else {\n writeText(runtime.stdout, `Removed Commentary token for ${baseUrl}.`);\n }\n}\n\nexport async function whoamiCommand(runtime: CommandRuntime, options: GlobalOptions) {\n const client = await makeClient(runtime, options);\n const result = await client.listDraftReviews();\n const payload = {\n ok: true,\n baseUrl: client.baseUrl,\n token: \"valid\",\n accessibleDraftReviews: result.draftReviews.length,\n };\n if (options.json) {\n writeJson(runtime.stdout, payload);\n } else {\n writeText(\n runtime.stdout,\n `Authenticated for ${client.baseUrl}. Accessible draft reviews: ${result.draftReviews.length}`,\n );\n }\n}\n\nexport async function reviewCommand(\n runtime: CommandRuntime,\n paths: string[],\n options: GlobalOptions & {\n title?: string;\n description?: string;\n contentType?: RequestedContentType;\n watch?: boolean;\n noOpen?: boolean;\n include?: string[];\n exclude?: string[];\n root?: string;\n },\n) {\n const root = path.resolve(runtime.cwd, options.root ?? \".\");\n const files = await collectFiles(paths, {\n root,\n include: options.include,\n exclude: options.exclude,\n requestedContentType: options.contentType ?? \"auto\",\n });\n const title =\n options.title?.trim() ||\n (files.length === 1\n ? path.basename(files[0]!.path, path.extname(files[0]!.path))\n : path.basename(root)) ||\n \"Commentary review\";\n const client = await makeClient(runtime, options);\n const result = await client.createDraftReview({\n title,\n description: options.description ?? null,\n files,\n });\n const sessionFilePath = await findSessionFile(root, options.sessionFile ?? SESSION_FILE);\n const now = nowIso();\n const metadata: SessionMetadata = {\n version: 1,\n reviewSessionId: result.sessionId,\n reviewUrl: result.reviewUrl,\n baseUrl: client.baseUrl,\n rootPath: path.relative(path.dirname(sessionFilePath), root) || \".\",\n trackedFiles: toTrackedFiles(files, apiFilesFromRevision(result.draftReview.latestRevision)),\n source: [\"review\", ...paths],\n createdAt: now,\n lastSyncedAt: now,\n lastKnownRevision: result.draftReview.latestRevision?.revisionNumber ?? null,\n };\n await saveSessionMetadata(sessionFilePath, metadata);\n\n if (options.json) {\n writeJson(runtime.stdout, {\n ok: true,\n draftReview: result.draftReview,\n sessionFilePath,\n session: publicSessionJson(metadata),\n });\n } else {\n writeText(\n runtime.stdout,\n formatReviewCreated({\n draftReview: result.draftReview,\n sessionFilePath,\n fileCount: files.length,\n }),\n );\n }\n if (!options.noOpen) {\n await openOrPrint(runtime, result.reviewUrl, options.noOpen);\n }\n if (options.watch) {\n await watchCommand(runtime, { ...options, sessionFile: sessionFilePath });\n }\n}\n\nexport async function syncCommand(\n runtime: CommandRuntime,\n options: GlobalOptions & {\n message?: string;\n all?: boolean;\n dryRun?: boolean;\n },\n) {\n const loaded = await loadSession(runtime, options);\n const root = sessionRoot(loaded.filePath, loaded.metadata);\n const current = await readTrackedFiles(root, loaded.metadata.trackedFiles);\n const changed = changedFiles(current, loaded.metadata.trackedFiles);\n if (options.dryRun) {\n const payload = {\n ok: true,\n changedFiles: changed.map((file) => file.path),\n fileCount: current.length,\n };\n if (options.json) {\n writeJson(runtime.stdout, payload);\n } else {\n writeText(\n runtime.stdout,\n payload.changedFiles.length ? payload.changedFiles.join(\"\\n\") : \"No local changes.\",\n );\n }\n return;\n }\n if (!options.all && changed.length === 0) {\n const revision = {\n id: \"\",\n revisionNumber: loaded.metadata.lastKnownRevision ?? 0,\n files: [],\n };\n if (options.json) {\n writeJson(runtime.stdout, {\n ok: true,\n noOp: true,\n session: publicSessionJson(loaded.metadata),\n });\n } else {\n writeText(\n runtime.stdout,\n formatRevision({ metadata: loaded.metadata, revision, uploaded: 0, noOp: true }),\n );\n }\n return;\n }\n\n const client = await makeClient(runtime, { ...options, baseUrl: loaded.metadata.baseUrl });\n const result = await client.createRevision({\n sessionId: loaded.metadata.reviewSessionId,\n summary: options.message ?? null,\n files: current,\n });\n const nextMetadata: SessionMetadata = {\n ...loaded.metadata,\n trackedFiles: toTrackedFiles(current, apiFilesFromRevision(result.revision)),\n lastSyncedAt: nowIso(),\n lastKnownRevision: result.revision.revisionNumber,\n };\n await saveSessionMetadata(loaded.filePath, nextMetadata);\n\n if (options.json) {\n writeJson(runtime.stdout, {\n ok: true,\n revision: result.revision,\n noOp: Boolean(result.noOp),\n session: publicSessionJson(nextMetadata),\n });\n } else {\n writeText(\n runtime.stdout,\n formatRevision({\n metadata: nextMetadata,\n revision: result.revision,\n uploaded: current.length,\n noOp: result.noOp,\n }),\n );\n }\n}\n\nexport async function watchCommand(\n runtime: CommandRuntime,\n options: GlobalOptions & {\n debounce?: number;\n message?: string;\n },\n) {\n const loaded = await loadSession(runtime, options);\n const root = sessionRoot(loaded.filePath, loaded.metadata);\n const debounceMs = Number(options.debounce ?? 1500);\n let timer: NodeJS.Timeout | null = null;\n let syncing = false;\n const watcher = chokidar.watch(\n loaded.metadata.trackedFiles.map((file) => path.resolve(root, file.path)),\n {\n ignoreInitial: true,\n ignored:\n /(^|[/\\\\])(\\.git|node_modules|dist|build|\\.next|\\.commentary)([/\\\\]|$)|(~$|\\.tmp$|\\.swp$)/,\n },\n );\n\n const runSync = () => {\n if (timer) {\n clearTimeout(timer);\n }\n timer = setTimeout(() => {\n if (syncing) {\n return;\n }\n syncing = true;\n syncCommand(runtime, { ...options, message: options.message ?? \"Watch sync\" })\n .catch((error: unknown) =>\n runtime.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`),\n )\n .finally(() => {\n syncing = false;\n });\n }, debounceMs);\n };\n\n watcher.on(\"add\", runSync).on(\"change\", runSync).on(\"unlink\", runSync);\n writeText(\n runtime.stdout,\n `Watching ${loaded.metadata.trackedFiles.length} file(s). Press Ctrl+C to stop.`,\n );\n await new Promise<void>((resolve) => {\n const close = () => {\n void watcher.close().finally(resolve);\n };\n process.once(\"SIGINT\", close);\n process.once(\"SIGTERM\", close);\n });\n}\n\nexport async function commentsCommand(\n runtime: CommandRuntime,\n options: GlobalOptions & {\n format?: \"text\" | \"markdown\" | \"json\";\n open?: boolean;\n resolved?: boolean;\n all?: boolean;\n file?: string;\n session?: string;\n },\n) {\n const loaded = options.session ? null : await loadSession(runtime, options);\n const metadata = loaded?.metadata;\n const sessionId = options.session ?? metadata?.reviewSessionId;\n if (!sessionId) {\n throw new CliError(\"A session id is required.\", ExitCode.Usage);\n }\n const baseUrl = metadata?.baseUrl ?? normalizeBaseUrl(options.baseUrl);\n const client = await makeClient(runtime, { ...options, baseUrl });\n const status = options.all ? undefined : options.resolved ? \"resolved\" : \"open\";\n const result = await client.listComments({\n sessionId,\n status,\n filePath: options.file ? normalizeReviewPath(options.file) : undefined,\n });\n const format = options.json ? \"json\" : (options.format ?? \"text\");\n if (format === \"json\") {\n writeJson(runtime.stdout, { ok: true, threads: result.threads });\n } else if (format === \"markdown\") {\n writeText(\n runtime.stdout,\n formatCommentsMarkdown({\n session: metadata ?? {\n version: 1,\n reviewSessionId: sessionId,\n reviewUrl: `${baseUrl}/review/draft/${encodeURIComponent(sessionId)}`,\n baseUrl,\n rootPath: \".\",\n trackedFiles: [],\n source: [],\n createdAt: \"\",\n lastSyncedAt: \"\",\n lastKnownRevision: null,\n },\n threads: result.threads,\n }),\n );\n } else {\n writeText(runtime.stdout, formatCommentsText(result.threads));\n }\n}\n\nexport async function waitCommentCommand(\n runtime: CommandRuntime,\n options: GlobalOptions & {\n session?: string;\n file?: string;\n includeReplies?: boolean;\n cursor?: string;\n from?: \"beginning\" | \"latest\";\n timeout?: string;\n format?: \"text\" | \"markdown\" | \"json\";\n },\n) {\n const loaded = options.session ? null : await loadSession(runtime, options);\n const sessionId = options.session ?? loaded?.metadata.reviewSessionId;\n if (!sessionId) {\n throw new CliError(\"A session id is required.\", ExitCode.Usage);\n }\n\n const baseUrl = loaded?.metadata.baseUrl ?? normalizeBaseUrl(options.baseUrl);\n const session = loaded?.metadata ?? placeholderSessionMetadata({ sessionId, baseUrl });\n const client = await makeClient(runtime, { ...options, baseUrl });\n const filePath = options.file ? normalizeReviewPath(options.file) : undefined;\n const timeoutMs = parseDurationMs(options.timeout, 30 * 60 * 1000);\n const abortController = new AbortController();\n let timedOut = false;\n let cursor = options.cursor ?? (options.from === \"beginning\" ? undefined : \"latest\");\n let reconnectDelayMs = 1000;\n const timeout =\n timeoutMs > 0\n ? setTimeout(() => {\n timedOut = true;\n abortController.abort();\n }, timeoutMs)\n : null;\n\n try {\n while (!abortController.signal.aborted) {\n try {\n for await (const event of client.streamDraftReviewEvents({\n sessionId,\n cursor,\n signal: abortController.signal,\n })) {\n cursor = event.id;\n reconnectDelayMs = 1000;\n if (event.type === \"draft.deleted\") {\n throw new CliError(\"Draft review was deleted before a comment arrived.\", ExitCode.Api);\n }\n if (!isWaitCommentMatch({ event, includeReplies: options.includeReplies, filePath })) {\n continue;\n }\n\n const format = options.json ? \"json\" : (options.format ?? \"markdown\");\n if (format === \"json\") {\n writeJson(runtime.stdout, { ok: true, event });\n } else if (format === \"text\") {\n writeText(runtime.stdout, formatWaitCommentText(event));\n } else {\n writeText(runtime.stdout, formatWaitCommentMarkdown({ session, event }));\n }\n abortController.abort();\n return;\n }\n } catch (error) {\n if (abortController.signal.aborted) {\n break;\n }\n if (error instanceof CliError && error.exitCode !== ExitCode.Network) {\n throw error;\n }\n if (options.verbose) {\n runtime.stderr.write(\n `Event stream disconnected; reconnecting in ${reconnectDelayMs}ms.\\n`,\n );\n }\n }\n\n await delay(reconnectDelayMs, abortController.signal);\n reconnectDelayMs = Math.min(reconnectDelayMs * 2, 10_000);\n }\n } finally {\n if (timeout) {\n clearTimeout(timeout);\n }\n }\n\n throw new CliError(\n timedOut\n ? \"Timed out waiting for a draft review comment.\"\n : \"Stopped waiting for a draft review comment.\",\n timedOut ? ExitCode.Timeout : ExitCode.General,\n );\n}\n\nexport async function replyCommand(\n runtime: CommandRuntime,\n threadId: string,\n message: string,\n options: GlobalOptions & { session?: string },\n) {\n const loaded = options.session ? null : await loadSession(runtime, options);\n const sessionId = options.session ?? loaded?.metadata.reviewSessionId;\n if (!sessionId) {\n throw new CliError(\"A session id is required.\", ExitCode.Usage);\n }\n const client = await makeClient(runtime, {\n ...options,\n baseUrl: loaded?.metadata.baseUrl ?? options.baseUrl,\n });\n const result = await client.replyToComment({ sessionId, threadId, bodyMarkdown: message });\n if (options.json) {\n writeJson(runtime.stdout, { ok: true, thread: result.thread });\n } else {\n writeText(runtime.stdout, `Replied to ${threadId}.`);\n }\n}\n\nexport async function resolveCommand(\n runtime: CommandRuntime,\n threadId: string,\n options: GlobalOptions & {\n session?: string;\n message?: string;\n },\n) {\n const loaded = options.session ? null : await loadSession(runtime, options);\n const sessionId = options.session ?? loaded?.metadata.reviewSessionId;\n if (!sessionId) {\n throw new CliError(\"A session id is required.\", ExitCode.Usage);\n }\n const client = await makeClient(runtime, {\n ...options,\n baseUrl: loaded?.metadata.baseUrl ?? options.baseUrl,\n });\n if (options.message?.trim()) {\n await client.replyToComment({ sessionId, threadId, bodyMarkdown: options.message.trim() });\n }\n const result = await client.updateCommentStatus({ sessionId, threadId, status: \"resolved\" });\n if (options.json) {\n writeJson(runtime.stdout, { ok: true, thread: result.thread });\n } else {\n writeText(runtime.stdout, `Resolved ${threadId}.`);\n }\n}\n\nexport async function pullCommand(\n runtime: CommandRuntime,\n options: GlobalOptions & {\n dryRun?: boolean;\n yes?: boolean;\n backup?: boolean;\n output?: string;\n },\n) {\n const loaded = await loadSession(runtime, options);\n const root = sessionRoot(loaded.filePath, loaded.metadata);\n const client = await makeClient(runtime, { ...options, baseUrl: loaded.metadata.baseUrl });\n const session = await client.getDraftReview(loaded.metadata.reviewSessionId);\n const writes: Array<{ path: string; target: string; content: string; changed: boolean }> = [];\n for (const file of session.draftReview.files) {\n const content = await client.getFileContent({\n sessionId: loaded.metadata.reviewSessionId,\n fileId: file.id,\n });\n const targetRoot = options.output ? path.resolve(runtime.cwd, options.output) : root;\n const target = path.resolve(targetRoot, file.path);\n let current: string | null = null;\n try {\n current = await fs.readFile(target, \"utf8\");\n } catch {\n current = null;\n }\n writes.push({ path: file.path, target, content, changed: current !== content });\n }\n\n if (options.dryRun) {\n const changed = writes.filter((write) => write.changed).map((write) => write.path);\n if (options.json) {\n writeJson(runtime.stdout, { ok: true, changedFiles: changed });\n } else {\n writeText(runtime.stdout, changed.length ? changed.join(\"\\n\") : \"No remote changes.\");\n }\n return;\n }\n\n const changedWrites = writes.filter((write) => write.changed);\n if (changedWrites.length > 0 && !options.yes && !options.output) {\n throw new CliError(\n \"Pull would overwrite local files. Rerun with --yes, --backup, or --output <dir>.\",\n ExitCode.Safety,\n );\n }\n\n for (const write of writes) {\n if (!write.changed) {\n continue;\n }\n await fs.mkdir(path.dirname(write.target), { recursive: true });\n if (options.backup) {\n try {\n await fs.copyFile(write.target, `${write.target}.bak`);\n } catch {\n // No existing file to back up.\n }\n }\n await fs.writeFile(write.target, write.content, \"utf8\");\n }\n\n const nextTracked = loaded.metadata.trackedFiles.map((tracked) => {\n const write = writes.find((candidate) => candidate.path === tracked.path);\n return write\n ? {\n ...tracked,\n contentHash: contentHash(write.content),\n sizeBytes: Buffer.byteLength(write.content),\n }\n : tracked;\n });\n await saveSessionMetadata(loaded.filePath, { ...loaded.metadata, trackedFiles: nextTracked });\n\n if (options.json) {\n writeJson(runtime.stdout, { ok: true, filesWritten: changedWrites.length });\n } else {\n writeText(runtime.stdout, `Pulled ${changedWrites.length} file(s).`);\n }\n}\n\nexport async function openCommand(\n runtime: CommandRuntime,\n options: GlobalOptions & { session?: string },\n) {\n if (options.session) {\n const baseUrl = normalizeBaseUrl(options.baseUrl);\n await openOrPrint(runtime, `${baseUrl}/review/draft/${encodeURIComponent(options.session)}`);\n return;\n }\n const loaded = await loadSession(runtime, options);\n await openOrPrint(runtime, loaded.metadata.reviewUrl);\n}\n\nexport async function statusCommand(runtime: CommandRuntime, options: GlobalOptions) {\n const loaded = await loadSession(runtime, options);\n const root = sessionRoot(loaded.filePath, loaded.metadata);\n const current = await readTrackedFiles(root, loaded.metadata.trackedFiles);\n const changed = changedFiles(current, loaded.metadata.trackedFiles).map((file) => file.path);\n let openComments: number | null = null;\n try {\n const client = await makeClient(runtime, { ...options, baseUrl: loaded.metadata.baseUrl });\n openComments = (\n await client.listComments({ sessionId: loaded.metadata.reviewSessionId, status: \"open\" })\n ).threads.length;\n } catch {\n openComments = null;\n }\n const payload = { ...publicSessionJson(loaded.metadata), changedFiles: changed, openComments };\n if (options.json) {\n writeJson(runtime.stdout, payload);\n } else {\n writeText(\n runtime.stdout,\n [\n `Session: ${loaded.metadata.reviewSessionId}`,\n `URL: ${loaded.metadata.reviewUrl}`,\n `Base URL: ${loaded.metadata.baseUrl}`,\n `Tracked files: ${loaded.metadata.trackedFiles.length}`,\n `Last revision: ${loaded.metadata.lastKnownRevision ?? \"unknown\"}`,\n `Changed files: ${changed.length ? changed.join(\", \") : \"none\"}`,\n `Open comments: ${openComments ?? \"unknown\"}`,\n ].join(\"\\n\"),\n );\n }\n}\n\nexport async function sessionsCommand(runtime: CommandRuntime, options: GlobalOptions) {\n const client = await makeClient(runtime, options);\n const result = await client.listDraftReviews();\n if (options.json) {\n writeJson(runtime.stdout, result);\n } else {\n writeText(\n runtime.stdout,\n result.draftReviews\n .map((draft) => `${draft.id}\\t${draft.title}\\t${draft.reviewUrl}`)\n .join(\"\\n\") || \"No draft reviews found.\",\n );\n }\n}\n\nexport async function revisionsCommand(\n runtime: CommandRuntime,\n options: GlobalOptions & { session?: string },\n) {\n const loaded = options.session ? null : await loadSession(runtime, options);\n const sessionId = options.session ?? loaded?.metadata.reviewSessionId;\n if (!sessionId) {\n throw new CliError(\"A session id is required.\", ExitCode.Usage);\n }\n const client = await makeClient(runtime, {\n ...options,\n baseUrl: loaded?.metadata.baseUrl ?? options.baseUrl,\n });\n const result = await client.listRevisions(sessionId);\n if (options.json) {\n writeJson(runtime.stdout, result);\n } else {\n writeText(\n runtime.stdout,\n result.revisions\n .map(\n (revision) =>\n `#${revision.revisionNumber}\\t${revision.summary ?? \"\"}\\t${revision.createdAt ?? \"\"}`,\n )\n .join(\"\\n\") || \"No revisions found.\",\n );\n }\n}\n","export class CliError extends Error {\n readonly exitCode: number;\n\n constructor(message: string, exitCode = 1) {\n super(message);\n this.name = \"CliError\";\n this.exitCode = exitCode;\n }\n}\n\nexport const ExitCode = {\n Ok: 0,\n General: 1,\n Usage: 2,\n Auth: 3,\n Network: 4,\n Api: 5,\n Safety: 6,\n Timeout: 124,\n} as const;\n\nexport function toErrorMessage(error: unknown) {\n return error instanceof Error ? error.message : String(error);\n}\n","export type SseMessage = {\n id?: string | undefined;\n event?: string | undefined;\n data?: string | undefined;\n retry?: number | undefined;\n};\n\nexport class SseParser {\n private buffer = \"\";\n private id: string | undefined;\n private event: string | undefined;\n private dataLines: string[] = [];\n private retry: number | undefined;\n\n feed(chunk: string) {\n this.buffer += chunk;\n const messages: SseMessage[] = [];\n\n while (true) {\n const boundary = this.findBoundary();\n if (!boundary) {\n break;\n }\n const raw = this.buffer.slice(0, boundary.index);\n this.buffer = this.buffer.slice(boundary.index + boundary.length);\n const message = this.consumeBlock(raw);\n if (message) {\n messages.push(message);\n }\n }\n\n return messages;\n }\n\n flush() {\n if (!this.buffer.trim()) {\n this.buffer = \"\";\n return [];\n }\n const message = this.consumeBlock(this.buffer);\n this.buffer = \"\";\n return message ? [message] : [];\n }\n\n private findBoundary() {\n const candidates = [\n { index: this.buffer.indexOf(\"\\r\\n\\r\\n\"), length: 4 },\n { index: this.buffer.indexOf(\"\\n\\n\"), length: 2 },\n { index: this.buffer.indexOf(\"\\r\\r\"), length: 2 },\n ].filter((candidate) => candidate.index >= 0);\n return candidates.sort((a, b) => a.index - b.index)[0] ?? null;\n }\n\n private consumeBlock(raw: string): SseMessage | null {\n for (const line of raw.split(/\\r\\n|\\r|\\n/)) {\n this.consumeLine(line);\n }\n\n if (this.dataLines.length === 0) {\n this.event = undefined;\n this.dataLines = [];\n this.retry = undefined;\n return null;\n }\n\n const message: SseMessage = {\n id: this.id,\n event: this.event,\n data: this.dataLines.join(\"\\n\"),\n retry: this.retry,\n };\n this.event = undefined;\n this.dataLines = [];\n this.retry = undefined;\n return message;\n }\n\n private consumeLine(line: string) {\n if (!line || line.startsWith(\":\")) {\n return;\n }\n\n const separator = line.indexOf(\":\");\n const field = separator >= 0 ? line.slice(0, separator) : line;\n const value = separator >= 0 ? line.slice(separator + 1).replace(/^ /, \"\") : \"\";\n\n if (field === \"id\") {\n this.id = value;\n } else if (field === \"event\") {\n this.event = value;\n } else if (field === \"data\") {\n this.dataLines.push(value);\n } else if (field === \"retry\") {\n const retry = Number(value);\n if (Number.isInteger(retry) && retry >= 0) {\n this.retry = retry;\n }\n }\n }\n}\n","import { CliError, ExitCode } from \"./errors.js\";\nimport { SseParser } from \"./sse.js\";\nimport type {\n DraftFileInput,\n DraftReviewLiveEvent,\n DraftReviewRevision,\n DraftReviewSession,\n DraftThread,\n} from \"./types.js\";\n\nexport type FetchLike = typeof fetch;\n\ntype ApiClientOptions = {\n baseUrl: string;\n token?: string | null | undefined;\n fetchImpl?: FetchLike | undefined;\n};\n\ntype OAuthMetadata = {\n issuer: string;\n token_endpoint: string;\n device_authorization_endpoint: string;\n authorization_endpoint?: string;\n registration_endpoint?: string;\n};\n\nexport class CommentaryApiClient {\n readonly baseUrl: string;\n private readonly token: string | null;\n private readonly fetchImpl: FetchLike;\n\n constructor(options: ApiClientOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, \"\");\n this.token = options.token ?? null;\n this.fetchImpl = options.fetchImpl ?? fetch;\n }\n\n async getOAuthMetadata() {\n return this.rawJson<OAuthMetadata>(\"/.well-known/oauth-authorization-server\", { auth: false });\n }\n\n async requestDeviceCode(input: {\n clientId: string;\n clientName: string;\n scope: string;\n resource: string;\n }) {\n const metadata = await this.getOAuthMetadata();\n return this.rawJson<{\n device_code: string;\n user_code: string;\n verification_uri: string;\n verification_uri_complete: string;\n expires_in: number;\n interval: number;\n }>(metadata.device_authorization_endpoint, {\n auth: false,\n method: \"POST\",\n body: {\n client_id: input.clientId,\n client_name: input.clientName,\n scope: input.scope,\n resource: input.resource,\n },\n });\n }\n\n async exchangeDeviceCode(input: { deviceCode: string; resource: string }) {\n const metadata = await this.getOAuthMetadata();\n return this.rawJson<{\n access_token: string;\n refresh_token: string;\n token_type: \"Bearer\";\n expires_in: number;\n }>(metadata.token_endpoint, {\n auth: false,\n method: \"POST\",\n body: {\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n device_code: input.deviceCode,\n resource: input.resource,\n },\n });\n }\n\n async listDraftReviews() {\n return this.request<{ ok: true; draftReviews: DraftReviewSession[] }>(\"/api/v1/draft-reviews\");\n }\n\n async createDraftReview(input: {\n title: string;\n description?: string | null;\n files: DraftFileInput[];\n }) {\n return this.request<{\n ok: true;\n draftReview: DraftReviewSession;\n sessionId: string;\n reviewUrl: string;\n }>(\"/api/v1/draft-reviews\", {\n method: \"POST\",\n body: {\n title: input.title,\n description: input.description,\n sourceType: \"cli\",\n files: input.files.map((file) => ({\n path: file.path,\n content: file.content,\n contentType: file.contentType,\n })),\n },\n });\n }\n\n async getDraftReview(sessionId: string) {\n return this.request<{ ok: true; draftReview: DraftReviewSession }>(\n `/api/v1/draft-reviews/${encodeURIComponent(sessionId)}`,\n );\n }\n\n async createRevision(input: {\n sessionId: string;\n summary?: string | null;\n files: DraftFileInput[];\n }) {\n return this.request<{ ok: true; revision: DraftReviewRevision; noOp?: boolean }>(\n `/api/v1/draft-reviews/${encodeURIComponent(input.sessionId)}/revisions`,\n {\n method: \"POST\",\n body: {\n summary: input.summary,\n files: input.files.map((file) => ({\n fileId: file.fileId,\n path: file.path,\n content: file.content,\n contentType: file.contentType,\n })),\n },\n },\n );\n }\n\n async listRevisions(sessionId: string) {\n return this.request<{ ok: true; revisions: DraftReviewRevision[] }>(\n `/api/v1/draft-reviews/${encodeURIComponent(sessionId)}/revisions`,\n );\n }\n\n async listComments(input: {\n sessionId: string;\n status?: \"open\" | \"resolved\" | undefined;\n filePath?: string | undefined;\n fileId?: string | undefined;\n }) {\n const params = new URLSearchParams();\n if (input.status) {\n params.set(\"status\", input.status);\n }\n if (input.filePath) {\n params.set(\"filePath\", input.filePath);\n }\n if (input.fileId) {\n params.set(\"fileId\", input.fileId);\n }\n const suffix = params.size ? `?${params}` : \"\";\n return this.request<{ ok: true; threads: DraftThread[] }>(\n `/api/v1/draft-reviews/${encodeURIComponent(input.sessionId)}/comments${suffix}`,\n );\n }\n\n async replyToComment(input: { sessionId: string; threadId: string; bodyMarkdown: string }) {\n return this.request<{ ok: true; thread: DraftThread }>(\n `/api/v1/draft-reviews/${encodeURIComponent(input.sessionId)}/comments/${encodeURIComponent(input.threadId)}/replies`,\n {\n method: \"POST\",\n body: { bodyMarkdown: input.bodyMarkdown },\n },\n );\n }\n\n async updateCommentStatus(input: {\n sessionId: string;\n threadId: string;\n status: \"open\" | \"resolved\";\n }) {\n return this.request<{ ok: true; thread: DraftThread }>(\n `/api/v1/draft-reviews/${encodeURIComponent(input.sessionId)}/comments/${encodeURIComponent(input.threadId)}/status`,\n {\n method: \"POST\",\n body: { status: input.status },\n },\n );\n }\n\n async getFileContent(input: { sessionId: string; fileId: string }) {\n return this.rawText(\n `/api/v1/draft-reviews/${encodeURIComponent(input.sessionId)}/files/${encodeURIComponent(input.fileId)}/content`,\n { auth: true },\n );\n }\n\n async *streamDraftReviewEvents(input: {\n sessionId: string;\n cursor?: string | undefined;\n once?: boolean | undefined;\n signal?: AbortSignal | undefined;\n }): AsyncGenerator<DraftReviewLiveEvent> {\n const params = new URLSearchParams();\n if (input.cursor) {\n params.set(\"cursor\", input.cursor);\n }\n if (input.once) {\n params.set(\"once\", \"1\");\n }\n const suffix = params.size ? `?${params}` : \"\";\n const response = await this.doFetch(\n `/api/v1/draft-reviews/${encodeURIComponent(input.sessionId)}/events${suffix}`,\n { auth: true, accept: \"text/event-stream\", signal: input.signal },\n );\n if (!response.ok) {\n await this.throwApiError(response);\n }\n if (!response.body) {\n throw new CliError(\"Commentary event stream did not include a response body.\", ExitCode.Api);\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n const parser = new SseParser();\n let completed = false;\n try {\n while (true) {\n const { done, value } = await reader.read();\n completed = done;\n const messages = done\n ? parser.flush()\n : parser.feed(decoder.decode(value, { stream: true }));\n for (const message of messages) {\n if (message.event && message.event !== \"draft-review\") {\n continue;\n }\n if (!message.data) {\n continue;\n }\n yield JSON.parse(message.data) as DraftReviewLiveEvent;\n }\n if (done) {\n break;\n }\n }\n } catch (error) {\n if (input.signal?.aborted) {\n return;\n }\n throw new CliError(\n error instanceof Error ? error.message : \"Commentary event stream failed.\",\n ExitCode.Network,\n );\n } finally {\n if (!completed) {\n await reader.cancel().catch(() => undefined);\n }\n reader.releaseLock();\n }\n }\n\n private async request<T>(pathOrUrl: string, init?: { method?: string; body?: unknown }) {\n return this.rawJson<T>(pathOrUrl, { ...init, auth: true });\n }\n\n private async rawText(\n pathOrUrl: string,\n init: { auth: boolean; method?: string; body?: unknown },\n ) {\n const response = await this.doFetch(pathOrUrl, init);\n if (!response.ok) {\n await this.throwApiError(response);\n }\n return response.text();\n }\n\n private async rawJson<T>(\n pathOrUrl: string,\n init: { auth: boolean; method?: string; body?: unknown },\n ) {\n const response = await this.doFetch(pathOrUrl, init);\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n const payload = contentType.includes(\"application/json\")\n ? ((await response.json()) as unknown)\n : null;\n if (!response.ok) {\n this.throwPayloadError(response.status, payload);\n }\n return payload as T;\n }\n\n private async doFetch(\n pathOrUrl: string,\n init: {\n auth: boolean;\n method?: string;\n body?: unknown;\n accept?: string;\n signal?: AbortSignal | undefined;\n },\n ) {\n const url =\n pathOrUrl.startsWith(\"http://\") || pathOrUrl.startsWith(\"https://\")\n ? pathOrUrl\n : `${this.baseUrl}${pathOrUrl}`;\n const headers: Record<string, string> = {\n accept: init.accept ?? \"application/json\",\n };\n let body: string | undefined;\n if (init.body !== undefined) {\n headers[\"content-type\"] = \"application/json\";\n body = JSON.stringify(init.body);\n }\n if (init.auth) {\n if (!this.token) {\n throw new CliError(\n \"Authentication is required. Run commentary login or set COMMENTARY_TOKEN.\",\n ExitCode.Auth,\n );\n }\n headers.authorization = `Bearer ${this.token}`;\n }\n try {\n const requestInit: RequestInit = {\n method: init.method ?? \"GET\",\n headers,\n };\n if (init.signal) {\n requestInit.signal = init.signal;\n }\n if (body !== undefined) {\n requestInit.body = body;\n }\n return await this.fetchImpl(url, requestInit);\n } catch (error) {\n throw new CliError(\n error instanceof Error ? error.message : \"Network request failed.\",\n ExitCode.Network,\n );\n }\n }\n\n private async throwApiError(response: Response): Promise<never> {\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (contentType.includes(\"application/json\")) {\n this.throwPayloadError(response.status, await response.json());\n }\n throw new CliError(\n `Commentary API returned ${response.status}.`,\n response.status === 401 ? ExitCode.Auth : ExitCode.Api,\n );\n }\n\n private throwPayloadError(status: number, payload: unknown): never {\n const body =\n payload && typeof payload === \"object\"\n ? (payload as { error?: unknown; error_description?: unknown })\n : {};\n const message =\n typeof body.error === \"string\"\n ? body.error\n : typeof body.error_description === \"string\"\n ? body.error_description\n : `Commentary API returned ${status}.`;\n throw new CliError(message, status === 401 || status === 403 ? ExitCode.Auth : ExitCode.Api);\n }\n}\n","export const DEFAULT_BASE_URL = \"https://commentary.dev\";\nexport const SESSION_FILE = \".commentary/session.json\";\nexport const PACKAGE_NAME = \"@commentary-dev/cli\";\nexport const CLIENT_ID = \"commentary-cli\";\nexport const CLIENT_NAME = \"Commentary CLI\";\n\nexport const REQUIRED_SCOPES = [\n \"commentary.review.read\",\n \"commentary.comments.read\",\n \"commentary.comments.write\",\n \"commentary.comments.status\",\n] as const;\n\nexport const SUPPORTED_EXTENSIONS = [\".md\", \".markdown\", \".mdx\", \".html\", \".htm\", \".txt\"] as const;\nexport const DEFAULT_IGNORES = [\n \"**/.git/**\",\n \"**/node_modules/**\",\n \"**/dist/**\",\n \"**/build/**\",\n \"**/.next/**\",\n \"**/.nuxt/**\",\n \"**/coverage/**\",\n \"**/.commentary/**\",\n \"**/.DS_Store\",\n] as const;\n\nexport const DRAFT_REVIEW_MAX_FILES = 20;\nexport const DRAFT_REVIEW_MAX_FILE_BYTES = 512 * 1024;\nexport const DRAFT_REVIEW_MAX_TOTAL_BYTES = 2 * 1024 * 1024;\n","import fs from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { DEFAULT_BASE_URL } from \"./constants.js\";\n\ntype StoredToken = {\n accessToken: string;\n refreshToken?: string;\n expiresAt?: string;\n};\n\ntype StoredConfig = {\n tokens?: Record<string, StoredToken>;\n};\n\nfunction configDir() {\n if (process.env.COMMENTARY_CONFIG_DIR) {\n return process.env.COMMENTARY_CONFIG_DIR;\n }\n if (process.platform === \"win32\" && process.env.APPDATA) {\n return path.join(process.env.APPDATA, \"commentary\");\n }\n if (process.env.XDG_CONFIG_HOME) {\n return path.join(process.env.XDG_CONFIG_HOME, \"commentary\");\n }\n return path.join(os.homedir(), \".config\", \"commentary\");\n}\n\nexport function configPath() {\n return path.join(configDir(), \"config.json\");\n}\n\nasync function readConfig(): Promise<StoredConfig> {\n try {\n return JSON.parse(await fs.readFile(configPath(), \"utf8\")) as StoredConfig;\n } catch {\n return {};\n }\n}\n\nasync function writeConfig(config: StoredConfig) {\n await fs.mkdir(configDir(), { recursive: true, mode: 0o700 });\n await fs.writeFile(configPath(), `${JSON.stringify(config, null, 2)}\\n`, {\n encoding: \"utf8\",\n mode: 0o600,\n });\n}\n\nexport function normalizeBaseUrl(baseUrl: string | undefined | null) {\n const value = baseUrl?.trim() || process.env.COMMENTARY_BASE_URL || DEFAULT_BASE_URL;\n const url = new URL(value);\n url.hash = \"\";\n url.search = \"\";\n return url.toString().replace(/\\/$/, \"\");\n}\n\nexport async function getStoredToken(baseUrl: string) {\n const config = await readConfig();\n return config.tokens?.[normalizeBaseUrl(baseUrl)] ?? null;\n}\n\nexport async function setStoredToken(baseUrl: string, token: StoredToken) {\n const config = await readConfig();\n config.tokens ??= {};\n config.tokens[normalizeBaseUrl(baseUrl)] = token;\n await writeConfig(config);\n}\n\nexport async function removeStoredToken(baseUrl: string) {\n const config = await readConfig();\n if (config.tokens) {\n delete config.tokens[normalizeBaseUrl(baseUrl)];\n }\n await writeConfig(config);\n}\n\nexport async function resolveToken(input: { baseUrl: string; token?: string | null | undefined }) {\n if (input.token?.trim()) {\n return input.token.trim();\n }\n if (process.env.COMMENTARY_TOKEN?.trim()) {\n return process.env.COMMENTARY_TOKEN.trim();\n }\n const stored = await getStoredToken(input.baseUrl);\n return stored?.accessToken ?? null;\n}\n","import path from \"node:path\";\nimport { CliError, ExitCode } from \"./errors.js\";\nimport type { DraftContentType, RequestedContentType } from \"./types.js\";\n\nconst MARKDOWN_EXTENSIONS = new Set([\".md\", \".markdown\", \".mdx\"]);\nconst HTML_EXTENSIONS = new Set([\".html\", \".htm\"]);\nconst PLAIN_EXTENSIONS = new Set([\".txt\"]);\nconst SUPPORTED_EXTENSIONS = new Set([\n ...MARKDOWN_EXTENSIONS,\n ...HTML_EXTENSIONS,\n ...PLAIN_EXTENSIONS,\n]);\n\nexport function normalizeSlashes(value: string) {\n return value.replaceAll(\"\\\\\", \"/\");\n}\n\nexport function normalizeReviewPath(filePath: string) {\n const normalized = normalizeSlashes(filePath).trim().replace(/^\\/+/, \"\");\n if (!normalized) {\n throw new CliError(\"Draft review file path is required.\", ExitCode.Usage);\n }\n if (\n /^[a-z]:\\//iu.test(normalized) ||\n filePath.trim().startsWith(\"/\") ||\n filePath.trim().startsWith(\"\\\\\")\n ) {\n throw new CliError(\"Draft review file paths must be relative.\", ExitCode.Usage);\n }\n if (normalized.split(\"/\").some((segment) => !segment || segment === \".\" || segment === \"..\")) {\n throw new CliError(\n \"Draft review file paths must not contain empty, current, or parent directory segments.\",\n ExitCode.Usage,\n );\n }\n return normalized;\n}\n\nexport function getPathExtension(filePath: string) {\n return path.posix.extname(normalizeSlashes(filePath)).toLowerCase();\n}\n\nexport function isSupportedPath(filePath: string) {\n return SUPPORTED_EXTENSIONS.has(getPathExtension(filePath));\n}\n\nexport function isLikelyHtml(content: string) {\n const trimmed = content.trimStart().toLowerCase();\n return (\n trimmed.startsWith(\"<!doctype html\") ||\n trimmed.startsWith(\"<html\") ||\n /<(head|body|main|article|section|div|p|h[1-6]|table|ul|ol)\\b[^>]*>[\\s\\S]*<\\/\\1>/iu.test(\n content,\n )\n );\n}\n\nexport function contentTypeFromPath(filePath: string): DraftContentType | null {\n const extension = getPathExtension(filePath);\n if (MARKDOWN_EXTENSIONS.has(extension)) {\n return \"markdown\";\n }\n if (HTML_EXTENSIONS.has(extension)) {\n return \"html\";\n }\n if (PLAIN_EXTENSIONS.has(extension)) {\n return \"plain_text\";\n }\n return null;\n}\n\nexport function detectContentType(input: {\n filePath: string;\n content: string;\n requested?: RequestedContentType | undefined;\n}): DraftContentType {\n const requested = input.requested ?? \"auto\";\n if (requested !== \"auto\") {\n if (![\"markdown\", \"html\", \"plain_text\"].includes(requested)) {\n throw new CliError(\"Choose a supported draft content type.\", ExitCode.Usage);\n }\n return requested;\n }\n\n const fromPath = contentTypeFromPath(input.filePath);\n if (fromPath) {\n return fromPath;\n }\n return isLikelyHtml(input.content) ? \"html\" : \"markdown\";\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport fg from \"fast-glob\";\nimport {\n DEFAULT_IGNORES,\n DRAFT_REVIEW_MAX_FILE_BYTES,\n DRAFT_REVIEW_MAX_FILES,\n DRAFT_REVIEW_MAX_TOTAL_BYTES,\n SUPPORTED_EXTENSIONS,\n} from \"./constants.js\";\nimport {\n detectContentType,\n isSupportedPath,\n normalizeReviewPath,\n normalizeSlashes,\n} from \"./content.js\";\nimport { CliError, ExitCode } from \"./errors.js\";\nimport { contentHash } from \"./hash.js\";\nimport type { DraftFileInput, RequestedContentType, TrackedFile } from \"./types.js\";\n\nexport type CollectOptions = {\n root: string;\n include?: string[] | undefined;\n exclude?: string[] | undefined;\n requestedContentType?: RequestedContentType | undefined;\n};\n\nexport type CollectedFile = DraftFileInput & {\n absolutePath: string;\n contentHash: string;\n sizeBytes: number;\n};\n\nfunction toPosixRelative(root: string, absolutePath: string) {\n const relative = path.relative(root, absolutePath);\n if (!relative || relative.startsWith(\"..\") || path.isAbsolute(relative)) {\n throw new CliError(`Path is outside the review root: ${absolutePath}`, ExitCode.Usage);\n }\n return normalizeReviewPath(relative);\n}\n\nasync function readUtf8File(absolutePath: string) {\n const bytes = await fs.readFile(absolutePath);\n const content = bytes.toString(\"utf8\");\n if (content.includes(\"\\u0000\")) {\n throw new CliError(\n `File must be UTF-8 text, not binary content: ${absolutePath}`,\n ExitCode.Usage,\n );\n }\n return content;\n}\n\nasync function collectPathEntries(inputPaths: string[], options: CollectOptions) {\n const root = path.resolve(options.root);\n const entries = new Set<string>();\n const includeExtensions = SUPPORTED_EXTENSIONS.map((extension) => extension.replace(\".\", \"\"));\n\n for (const inputPath of inputPaths) {\n const absolute = path.resolve(root, inputPath);\n let stat;\n try {\n stat = await fs.stat(absolute);\n } catch {\n throw new CliError(`Path does not exist: ${inputPath}`, ExitCode.Usage);\n }\n\n if (stat.isDirectory()) {\n const relativeDir = normalizeSlashes(path.relative(root, absolute)) || \".\";\n const patterns = options.include?.length\n ? options.include.map((pattern) => normalizeSlashes(path.posix.join(relativeDir, pattern)))\n : [`${relativeDir === \".\" ? \"\" : `${relativeDir}/`}**/*.{${includeExtensions.join(\",\")}}`];\n const matches = await fg(patterns, {\n cwd: root,\n onlyFiles: true,\n dot: false,\n ignore: [...DEFAULT_IGNORES, ...(options.exclude ?? [])],\n });\n matches.forEach((match) => entries.add(path.resolve(root, match)));\n continue;\n }\n\n if (stat.isFile()) {\n if (!isSupportedPath(absolute)) {\n throw new CliError(`Unsupported file type: ${inputPath}`, ExitCode.Usage);\n }\n entries.add(absolute);\n }\n }\n\n return [...entries].sort((left, right) => left.localeCompare(right));\n}\n\nexport async function collectFiles(\n inputPaths: string[],\n options: CollectOptions,\n): Promise<CollectedFile[]> {\n if (inputPaths.length === 0) {\n throw new CliError(\"At least one path is required.\", ExitCode.Usage);\n }\n\n const root = path.resolve(options.root);\n const absolutePaths = await collectPathEntries(inputPaths, options);\n if (absolutePaths.length === 0) {\n throw new CliError(\"No supported files were found.\", ExitCode.Usage);\n }\n if (absolutePaths.length > DRAFT_REVIEW_MAX_FILES) {\n throw new CliError(\n `Draft reviews support up to ${DRAFT_REVIEW_MAX_FILES} files per revision.`,\n ExitCode.Usage,\n );\n }\n\n let totalBytes = 0;\n const collected: CollectedFile[] = [];\n for (const absolutePath of absolutePaths) {\n const content = await readUtf8File(absolutePath);\n const sizeBytes = Buffer.byteLength(content);\n if (sizeBytes > DRAFT_REVIEW_MAX_FILE_BYTES) {\n throw new CliError(\n `Draft review file exceeds ${DRAFT_REVIEW_MAX_FILE_BYTES} bytes: ${absolutePath}`,\n ExitCode.Usage,\n );\n }\n totalBytes += sizeBytes;\n if (totalBytes > DRAFT_REVIEW_MAX_TOTAL_BYTES) {\n throw new CliError(\n `Draft review revisions support up to ${DRAFT_REVIEW_MAX_TOTAL_BYTES} total bytes.`,\n ExitCode.Usage,\n );\n }\n const reviewPath = toPosixRelative(root, absolutePath);\n const contentType = detectContentType({\n filePath: reviewPath,\n content,\n requested: options.requestedContentType,\n });\n collected.push({\n absolutePath,\n path: reviewPath,\n content,\n contentType,\n contentHash: contentHash(content),\n sizeBytes,\n });\n }\n\n return collected;\n}\n\nexport async function readTrackedFiles(\n root: string,\n trackedFiles: TrackedFile[],\n): Promise<CollectedFile[]> {\n const collected: CollectedFile[] = [];\n for (const tracked of trackedFiles) {\n const absolutePath = path.resolve(root, tracked.path);\n const content = await readUtf8File(absolutePath);\n const sizeBytes = Buffer.byteLength(content);\n collected.push({\n absolutePath,\n path: tracked.path,\n fileId: tracked.fileId,\n content,\n contentType: tracked.contentType,\n contentHash: contentHash(content),\n sizeBytes,\n });\n }\n return collected;\n}\n\nexport function toTrackedFiles(\n files: CollectedFile[],\n apiFiles?: Array<{\n fileId: string;\n path: string;\n contentHash: string;\n sizeBytes: number;\n contentType: string;\n }>,\n): TrackedFile[] {\n const apiByPath = new Map(apiFiles?.map((file) => [file.path, file]) ?? []);\n return files.map((file) => {\n const apiFile = apiByPath.get(file.path);\n return {\n path: file.path,\n fileId: apiFile?.fileId ?? file.fileId,\n contentType: file.contentType,\n contentHash: apiFile?.contentHash ?? file.contentHash,\n sizeBytes: apiFile?.sizeBytes ?? file.sizeBytes,\n };\n });\n}\n","import { createHash } from \"node:crypto\";\n\nexport function contentHash(content: string) {\n return createHash(\"sha256\").update(content).digest(\"hex\");\n}\n","import type {\n DraftReviewLiveEvent,\n DraftReviewRevision,\n DraftReviewSession,\n DraftThread,\n JsonObject,\n SessionMetadata,\n} from \"./types.js\";\n\nexport type Writer = {\n write(chunk: string): void;\n};\n\nexport function writeJson(stdout: Writer, value: unknown) {\n stdout.write(`${JSON.stringify(value, null, 2)}\\n`);\n}\n\nexport function writeText(stdout: Writer, value: string) {\n stdout.write(`${value.trimEnd()}\\n`);\n}\n\nexport function formatReviewCreated(input: {\n draftReview: DraftReviewSession;\n sessionFilePath: string;\n fileCount: number;\n}) {\n return [\n \"Created Commentary review\",\n \"\",\n `Title: ${input.draftReview.title}`,\n `Files: ${input.fileCount}`,\n `Session: ${input.draftReview.id}`,\n `URL: ${input.draftReview.reviewUrl}`,\n \"\",\n `Saved local session metadata to ${input.sessionFilePath}`,\n ].join(\"\\n\");\n}\n\nexport function formatRevision(input: {\n metadata: SessionMetadata;\n revision: DraftReviewRevision;\n uploaded: number;\n noOp?: boolean | undefined;\n}) {\n return [\n input.noOp ? \"No changes to sync\" : \"Synced Commentary review\",\n \"\",\n `Session: ${input.metadata.reviewSessionId}`,\n `Revision: ${input.revision.revisionNumber}`,\n `Files uploaded: ${input.uploaded}`,\n `URL: ${input.metadata.reviewUrl}`,\n ].join(\"\\n\");\n}\n\nfunction commentBody(thread: DraftThread) {\n const first = thread.comments[0];\n return first?.bodyMarkdown ?? first?.body ?? \"\";\n}\n\nfunction commentAuthor(thread: DraftThread) {\n const first = thread.comments[0];\n return first?.authorLogin ?? first?.author ?? \"Unknown\";\n}\n\nexport function formatCommentsText(threads: DraftThread[]) {\n if (threads.length === 0) {\n return \"No comments found.\";\n }\n return threads\n .map((thread) =>\n [\n `[${thread.id}] ${thread.filePath}`,\n `Status: ${thread.status}`,\n thread.selectedText ? `Anchor: \"${thread.selectedText}\"` : null,\n `${commentAuthor(thread)}: ${commentBody(thread)}`,\n ]\n .filter(Boolean)\n .join(\"\\n\"),\n )\n .join(\"\\n\\n\");\n}\n\nexport function formatCommentsMarkdown(input: {\n session: SessionMetadata;\n threads: DraftThread[];\n}) {\n const lines = [\n \"# Commentary Review Comments\",\n \"\",\n `Session: ${input.session.reviewSessionId}`,\n `URL: ${input.session.reviewUrl}`,\n \"\",\n ];\n if (input.threads.length === 0) {\n lines.push(\"No comments found.\");\n return lines.join(\"\\n\");\n }\n for (const thread of input.threads) {\n lines.push(`## Comment ${thread.id}`, \"\");\n lines.push(`File: ${thread.filePath}`);\n lines.push(`Status: ${thread.status}`);\n if (thread.selectedText) {\n lines.push(`Anchor: \"${thread.selectedText}\"`);\n }\n if (thread.sourceLineStart) {\n lines.push(\n `Lines: ${thread.sourceLineStart}${thread.sourceLineEnd && thread.sourceLineEnd !== thread.sourceLineStart ? `-${thread.sourceLineEnd}` : \"\"}`,\n );\n }\n lines.push(\"\", \"User comment:\", `> ${commentBody(thread).replace(/\\n/g, \"\\n> \")}`, \"\");\n const replies = thread.comments.slice(1);\n if (replies.length > 0) {\n lines.push(\"Replies:\");\n replies.forEach((reply) => {\n lines.push(\n `- ${reply.authorLogin ?? reply.author ?? \"Unknown\"}: ${reply.bodyMarkdown ?? reply.body ?? \"\"}`,\n );\n });\n lines.push(\"\");\n }\n }\n return lines.join(\"\\n\").trimEnd();\n}\n\nexport function formatWaitCommentText(event: DraftReviewLiveEvent) {\n if (!event.thread) {\n return `Received ${event.type} (${event.id}).`;\n }\n const thread = event.thread;\n const body = commentBody(thread);\n return [\n `[${thread.id}] ${thread.filePath}`,\n `Event: ${event.type}`,\n `Status: ${thread.status}`,\n thread.selectedText ? `Anchor: \"${thread.selectedText}\"` : null,\n `${commentAuthor(thread)}: ${body}`,\n ]\n .filter(Boolean)\n .join(\"\\n\");\n}\n\nexport function formatWaitCommentMarkdown(input: {\n session: SessionMetadata;\n event: DraftReviewLiveEvent;\n}) {\n const lines = [\n \"# Commentary Comment\",\n \"\",\n `Session: ${input.session.reviewSessionId}`,\n `URL: ${input.session.reviewUrl}`,\n `Event: ${input.event.type}`,\n `Cursor: ${input.event.id}`,\n \"\",\n ];\n if (!input.event.thread) {\n lines.push(\"No thread payload was available for this event.\");\n return lines.join(\"\\n\");\n }\n lines.push(formatCommentsMarkdown({ session: input.session, threads: [input.event.thread] }));\n return lines.join(\"\\n\").trimEnd();\n}\n\nexport function publicSessionJson(metadata: SessionMetadata): JsonObject {\n return {\n reviewSessionId: metadata.reviewSessionId,\n reviewUrl: metadata.reviewUrl,\n baseUrl: metadata.baseUrl,\n rootPath: metadata.rootPath,\n trackedFiles: metadata.trackedFiles,\n createdAt: metadata.createdAt,\n lastSyncedAt: metadata.lastSyncedAt,\n lastKnownRevision: metadata.lastKnownRevision,\n };\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { SESSION_FILE } from \"./constants.js\";\nimport { CliError, ExitCode } from \"./errors.js\";\nimport type { SessionMetadata } from \"./types.js\";\n\nasync function pathExists(filePath: string) {\n try {\n await fs.access(filePath);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function findSessionFile(startDir: string, explicitPath?: string) {\n if (explicitPath) {\n return path.resolve(startDir, explicitPath);\n }\n\n let current = path.resolve(startDir);\n while (true) {\n const candidate = path.join(current, SESSION_FILE);\n if (await pathExists(candidate)) {\n return candidate;\n }\n const parent = path.dirname(current);\n if (parent === current) {\n return path.resolve(startDir, SESSION_FILE);\n }\n current = parent;\n }\n}\n\nexport async function loadSessionMetadata(startDir: string, explicitPath?: string) {\n const filePath = await findSessionFile(startDir, explicitPath);\n let raw;\n try {\n raw = await fs.readFile(filePath, \"utf8\");\n } catch {\n throw new CliError(\n `No Commentary session metadata found at ${filePath}. Run commentary review first.`,\n ExitCode.Usage,\n );\n }\n\n const metadata = JSON.parse(raw) as SessionMetadata;\n return {\n filePath,\n metadata,\n };\n}\n\nexport async function saveSessionMetadata(filePath: string, metadata: SessionMetadata) {\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n await fs.writeFile(filePath, `${JSON.stringify(metadata, null, 2)}\\n`, {\n encoding: \"utf8\",\n mode: 0o644,\n });\n}\n\nexport function sessionRoot(sessionFilePath: string, metadata: SessionMetadata) {\n return path.resolve(path.dirname(sessionFilePath), metadata.rootPath);\n}\n","#!/usr/bin/env node\nimport { runCli } from \"./cli.js\";\n\nconst exitCode = await runCli();\nif (exitCode !== 0) {\n process.exitCode = exitCode;\n}\n"],"mappings":"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","names":["fs","path","exitCode","path","SUPPORTED_EXTENSIONS","path","fs","path","path","fs","fs","path","fs","path","path","fs"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/commands.ts","../src/errors.ts","../src/sse.ts","../src/api-client.ts","../src/constants.ts","../src/config.ts","../src/content.ts","../src/files.ts","../src/hash.ts","../src/output.ts","../src/session.ts","../src/index.ts"],"sourcesContent":["import { Command, Option } from \"commander\";\nimport {\n commentsCommand,\n loginCommand,\n logoutCommand,\n openCommand,\n pullCommand,\n replyCommand,\n resolveCommand,\n reviewCommand,\n revisionsCommand,\n sessionsCommand,\n statusCommand,\n syncCommand,\n watchCommand,\n waitCommentCommand,\n whoamiCommand,\n type CommandRuntime,\n type GlobalOptions,\n} from \"./commands.js\";\nimport { PACKAGE_NAME } from \"./constants.js\";\nimport { CliError, ExitCode, toErrorMessage } from \"./errors.js\";\n\ntype RunOptions = Partial<CommandRuntime>;\n\nfunction collectOption(value: string, previous: string[] = []) {\n previous.push(value);\n return previous;\n}\n\nfunction runtimeFromOptions(options?: RunOptions): CommandRuntime {\n return {\n cwd: options?.cwd ?? process.cwd(),\n stdout: options?.stdout ?? process.stdout,\n stderr: options?.stderr ?? process.stderr,\n fetchImpl: options?.fetchImpl,\n isTty: options?.isTty ?? process.stdout.isTTY,\n };\n}\n\nfunction globalOptions(command: Command): GlobalOptions {\n return command.optsWithGlobals<GlobalOptions>();\n}\n\nfunction wrap(runtime: CommandRuntime, action: (options: GlobalOptions) => Promise<void>) {\n return async function wrapped(this: Command) {\n await action(globalOptions(this));\n };\n}\n\nfunction commandOptionsWithNoOpen(command: Command) {\n const options = command.opts();\n return {\n ...globalOptions(command),\n ...options,\n noOpen: (options as { open?: boolean }).open === false,\n };\n}\n\nfunction helpText(details: string, examples: string[]) {\n return [\n \"\",\n \"Details:\",\n ` ${details}`,\n \"\",\n \"Examples:\",\n ...examples.map((example) => ` ${example}`),\n ].join(\"\\n\");\n}\n\nexport function buildProgram(runtime: CommandRuntime) {\n const program = new Command();\n program.configureOutput({\n writeOut: (chunk) => runtime.stdout.write(chunk),\n writeErr: (chunk) => runtime.stderr.write(chunk),\n outputError: (chunk, write) => write(chunk),\n });\n program\n .name(\"commentary\")\n .description(\n \"Create and manage Commentary draft review sessions from local Markdown, MDX, HTML, and text files.\",\n )\n .version(\"0.1.0\")\n .showHelpAfterError()\n .exitOverride();\n\n program\n .option(\n \"--base-url <url>\",\n \"Commentary base URL. Defaults to COMMENTARY_BASE_URL or https://commentary.dev.\",\n )\n .option(\n \"--token <token>\",\n \"Commentary API token. Defaults to COMMENTARY_TOKEN or the stored login token.\",\n )\n .option(\"--json\", \"Print machine-readable JSON output for agent automation.\")\n .option(\"--verbose\", \"Print verbose diagnostics, including live-event reconnect notices.\")\n .option(\"--quiet\", \"Suppress non-essential human-readable output.\")\n .option(\"--no-color\", \"Disable color output\")\n .option(\n \"--session-file <path>\",\n \"Path to project session metadata. Defaults to .commentary/session.json.\",\n );\n\n program\n .command(\"login\")\n .description(\"Authenticate with Commentary.\")\n .option(\n \"--token <token>\",\n \"Store an existing API token instead of starting browser/device login.\",\n )\n .option(\"--no-open\", \"Print the device login URL instead of opening a browser.\")\n .addHelpText(\n \"after\",\n helpText(\"Stores the token outside project metadata. Session files never contain secrets.\", [\n \"commentary login\",\n \"commentary login --token <commentary-api-token>\",\n \"commentary --base-url https://commentary.example.com login\",\n ]),\n )\n .action(async function (this: Command) {\n await loginCommand(runtime, commandOptionsWithNoOpen(this));\n });\n\n program\n .command(\"logout\")\n .description(\"Remove the stored Commentary token for the selected base URL.\")\n .addHelpText(\n \"after\",\n helpText(\n \"Removes only local CLI authentication state for the selected Commentary base URL.\",\n [\"commentary logout\", \"commentary --base-url https://commentary.example.com logout\"],\n ),\n )\n .action(wrap(runtime, (options) => logoutCommand(runtime, options)));\n\n program\n .command(\"whoami\")\n .description(\"Validate the configured Commentary token.\")\n .addHelpText(\n \"after\",\n helpText(\"Checks whether the active token can reach the draft-review API.\", [\n \"commentary whoami\",\n \"COMMENTARY_TOKEN=<token> commentary whoami --json\",\n ]),\n )\n .action(wrap(runtime, (options) => whoamiCommand(runtime, options)));\n\n program\n .command(\"review\")\n .description(\"Create a draft review from files or folders.\")\n .argument(\"<paths...>\")\n .option(\"--title <title>\", \"Review title shown in Commentary.\")\n .option(\"--description <description>\", \"Optional review description shown in Commentary.\")\n .addOption(\n new Option(\"--content-type <type>\", \"Content type\")\n .choices([\"auto\", \"markdown\", \"html\", \"plain_text\"])\n .default(\"auto\"),\n )\n .option(\"--watch\", \"Keep running and upload a new revision whenever tracked files change.\")\n .option(\"--no-open\", \"Do not open the browser after creating the review.\")\n .option(\n \"--root <path>\",\n \"Root used for relative review paths. Defaults to the current directory.\",\n )\n .option(\n \"--include <glob>\",\n \"Include glob for directory review. May be repeated.\",\n collectOption,\n )\n .option(\n \"--exclude <glob>\",\n \"Exclude glob for directory review. May be repeated.\",\n collectOption,\n )\n .addHelpText(\n \"after\",\n helpText(\n \"Creates a hosted draft review and writes .commentary/session.json for later commands.\",\n [\n 'commentary review ./docs/spec.md --title \"Product spec\"',\n 'commentary review ./docs --include \"**/*.md\" --exclude \"drafts/**\"',\n \"commentary review ./docs/spec.md --watch --no-open\",\n \"commentary review ./docs/spec.md --json\",\n ],\n ),\n )\n .action(async function (this: Command, paths: string[]) {\n await reviewCommand(runtime, paths, commandOptionsWithNoOpen(this));\n });\n\n const sync = program\n .command(\"sync\")\n .description(\"Upload current tracked files as a new revision.\")\n .option(\"--message <summary>\", \"Revision summary shown in Commentary.\")\n .option(\"--all\", \"Upload even when tracked file hashes have not changed.\")\n .option(\"--dry-run\", \"Print pending changed paths without uploading a revision.\")\n .addHelpText(\n \"after\",\n helpText(\"Reads the linked session, compares tracked files, and uploads changed content.\", [\n 'commentary sync --message \"Address review comments\"',\n \"commentary sync --dry-run --json\",\n 'commentary sync --all --message \"Refresh rendered output\"',\n ]),\n )\n .action(async function (this: Command) {\n await syncCommand(runtime, { ...globalOptions(this), ...this.opts() });\n });\n program\n .command(\"revision\")\n .description(\"Alias for sync.\")\n .option(\"--message <summary>\", \"Revision summary shown in Commentary.\")\n .option(\"--all\", \"Upload even when tracked file hashes have not changed.\")\n .option(\"--dry-run\", \"Print pending changed paths without uploading a revision.\")\n .addHelpText(\n \"after\",\n helpText(\"Alias for commentary sync.\", [\n 'commentary revision --message \"Address review comments\"',\n \"commentary revision --dry-run\",\n ]),\n )\n .action(async function (this: Command) {\n await syncCommand(runtime, { ...globalOptions(this), ...this.opts() });\n });\n\n program\n .command(\"watch\")\n .description(\"Watch tracked files and sync revisions.\")\n .option(\"--debounce <ms>\", \"Milliseconds to wait after a file event before syncing.\", \"1500\")\n .option(\"--message <summary>\", \"Revision summary used for watch-triggered uploads.\")\n .addHelpText(\n \"after\",\n helpText(\n \"Runs until interrupted. It watches files already listed in .commentary/session.json.\",\n [\"commentary watch\", 'commentary watch --debounce 3000 --message \"Watch sync\"'],\n ),\n )\n .action(async function (this: Command) {\n await watchCommand(runtime, { ...globalOptions(this), ...this.opts() });\n });\n\n program\n .command(\"comments\")\n .description(\"List draft review comments.\")\n .addOption(\n new Option(\"--format <format>\", \"Output format\")\n .choices([\"text\", \"markdown\", \"json\"])\n .default(\"text\"),\n )\n .option(\"--open\", \"Show open threads. This is the default unless --resolved or --all is used.\")\n .option(\"--resolved\", \"Show resolved threads.\")\n .option(\"--all\", \"Show open and resolved threads.\")\n .option(\"--file <path>\", \"Filter by review file path, e.g. docs/spec.md.\")\n .option(\"--session <id>\", \"Use an explicit draft review session id instead of local metadata.\")\n .addHelpText(\n \"after\",\n helpText(\n \"Prints thread ids, file anchors, comment bodies, and replies for the selected session.\",\n [\n \"commentary comments --format markdown --open\",\n \"commentary comments --all --json\",\n \"commentary comments --file docs/spec.md --format text\",\n \"commentary comments --session draft_123 --json\",\n ],\n ),\n )\n .action(async function (this: Command) {\n await commentsCommand(runtime, { ...globalOptions(this), ...this.opts() });\n });\n\n program\n .command(\"wait-comment\")\n .description(\"Wait for the next draft review comment event.\")\n .option(\"--session <id>\", \"Use an explicit draft review session id instead of local metadata.\")\n .option(\"--file <path>\", \"Filter by review file path, e.g. docs/spec.md.\")\n .option(\"--include-replies\", \"Return reply.created events. This is enabled by default.\")\n .option(\n \"--no-include-replies\",\n \"Ignore reply.created events and wait only for new top-level comments.\",\n )\n .option(\n \"--cursor <id>\",\n \"Resume after a specific live-event cursor returned by a previous wait.\",\n )\n .addOption(\n new Option(\"--from <position>\", \"Where to start when no cursor is provided\")\n .choices([\"beginning\", \"latest\"])\n .default(\"latest\"),\n )\n .option(\"--timeout <duration>\", \"Maximum wait time, e.g. 30m, 10s, or 0 for no timeout.\", \"30m\")\n .addOption(\n new Option(\"--format <format>\", \"Output format\")\n .choices([\"text\", \"markdown\", \"json\"])\n .default(\"markdown\"),\n )\n .addHelpText(\n \"after\",\n helpText(\n \"Streams draft-review live events, auto-reconnects on stream drops, and exits after the first matching comment or reply.\",\n [\n \"commentary wait-comment --json\",\n \"commentary wait-comment --file docs/spec.md --timeout 15m\",\n \"commentary wait-comment --cursor event_123 --json\",\n \"commentary wait-comment --from beginning --no-include-replies\",\n \"commentary wait-comment --timeout 0 --format markdown\",\n ],\n ),\n )\n .action(async function (this: Command) {\n await waitCommentCommand(runtime, { ...globalOptions(this), ...this.opts() });\n });\n\n program\n .command(\"reply\")\n .description(\"Reply to a comment thread.\")\n .argument(\"<thread-id>\")\n .argument(\"<message>\")\n .option(\"--session <id>\", \"Use an explicit draft review session id instead of local metadata.\")\n .option(\n \"--alias <name>\",\n \"Agent alias for reply attribution. Overrides COMMENTARY_AGENT_ALIAS.\",\n )\n .addHelpText(\n \"after\",\n helpText(\n \"Adds a reply to the thread id printed by comments or wait-comment. Replies reopen resolved threads.\",\n [\n 'commentary reply thread_123 \"Updated this in revision 3.\"',\n 'commentary reply thread_123 \"Fixed.\" --alias \"Docs agent\"',\n 'COMMENTARY_AGENT_ALIAS=\"Docs agent\" commentary reply thread_123 \"Fixed.\" --json',\n ],\n ),\n )\n .action(async function (this: Command, threadId: string, message: string) {\n await replyCommand(runtime, threadId, message, { ...globalOptions(this), ...this.opts() });\n });\n\n program\n .command(\"resolve\")\n .description(\"Resolve a comment thread.\")\n .argument(\"<thread-id>\")\n .option(\"--session <id>\", \"Use an explicit draft review session id instead of local metadata.\")\n .option(\"--message <message>\", \"Add a closing reply before resolving the thread.\")\n .option(\n \"--alias <name>\",\n \"Agent alias for the closing reply. Overrides COMMENTARY_AGENT_ALIAS.\",\n )\n .addHelpText(\n \"after\",\n helpText(\n \"Marks a thread resolved. Use --message when the final response should be visible in the thread.\",\n [\n \"commentary resolve thread_123\",\n 'commentary resolve thread_123 --message \"Addressed in revision 3.\"',\n 'commentary resolve thread_123 --message \"Fixed.\" --alias \"Docs agent\" --json',\n ],\n ),\n )\n .action(async function (this: Command, threadId: string) {\n await resolveCommand(runtime, threadId, { ...globalOptions(this), ...this.opts() });\n });\n\n program\n .command(\"pull\")\n .description(\"Download latest reviewed files safely.\")\n .option(\"--dry-run\", \"Show which files would change without writing to disk.\")\n .option(\"--yes\", \"Allow overwriting changed local files.\")\n .option(\"--backup\", \"Create .bak files before overwriting existing files.\")\n .option(\n \"--output <dir>\",\n \"Write files to a separate directory instead of overwriting tracked files.\",\n )\n .addHelpText(\n \"after\",\n helpText(\"Downloads the latest Commentary file content for the linked draft review.\", [\n \"commentary pull --dry-run\",\n \"commentary pull --output reviewed\",\n \"commentary pull --backup --yes\",\n ]),\n )\n .action(async function (this: Command) {\n await pullCommand(runtime, { ...globalOptions(this), ...this.opts() });\n });\n\n program\n .command(\"open\")\n .description(\"Open the linked review in a browser, or print the URL in headless output.\")\n .option(\"--session <id>\", \"Open an explicit draft review session id instead of local metadata.\")\n .addHelpText(\n \"after\",\n helpText(\"In CI or non-TTY output this prints the URL instead of launching a browser.\", [\n \"commentary open\",\n \"commentary open --session draft_123\",\n ]),\n )\n .action(async function (this: Command) {\n await openCommand(runtime, { ...globalOptions(this), ...this.opts() });\n });\n\n program\n .command(\"status\")\n .description(\"Show current linked review status.\")\n .addHelpText(\n \"after\",\n helpText(\n \"Summarizes local metadata, changed tracked files, and open/resolved thread counts.\",\n [\"commentary status\", \"commentary status --json\"],\n ),\n )\n .action(wrap(runtime, (options) => statusCommand(runtime, options)));\n\n program\n .command(\"sessions\")\n .description(\"List draft review sessions for the authenticated account.\")\n .addHelpText(\n \"after\",\n helpText(\"Lists draft reviews visible to the configured token.\", [\n \"commentary sessions\",\n \"commentary sessions --json\",\n ]),\n )\n .action(wrap(runtime, (options) => sessionsCommand(runtime, options)));\n\n program\n .command(\"revisions\")\n .description(\"List revisions for the linked or specified draft review.\")\n .option(\"--session <id>\", \"Use an explicit draft review session id instead of local metadata.\")\n .addHelpText(\n \"after\",\n helpText(\"Shows uploaded revisions for the selected draft review.\", [\n \"commentary revisions\",\n \"commentary revisions --session draft_123 --json\",\n ]),\n )\n .action(async function (this: Command) {\n await revisionsCommand(runtime, { ...globalOptions(this), ...this.opts() });\n });\n\n sync.alias(\"upload\");\n program.addHelpText(\n \"after\",\n `\\nAgent loop:\\n 1. commentary review ./docs/spec.md --title \"Spec\"\\n 2. commentary wait-comment --json\\n 3. edit files, then commentary sync --message \"Address comments\"\\n 4. commentary reply <thread-id> \"Fixed.\" --alias \"Docs agent\"\\n\\nExamples:\\n npx ${PACKAGE_NAME} review ./docs/spec.md\\n commentary comments --format markdown --open\\n commentary wait-comment --json\\n commentary resolve <thread-id> --message \"Addressed.\"\\n`,\n );\n return program;\n}\n\nexport async function runCli(argv = process.argv.slice(2), options?: RunOptions) {\n const runtime = runtimeFromOptions(options);\n const program = buildProgram(runtime);\n try {\n await program.parseAsync(argv, { from: \"user\" });\n return ExitCode.Ok;\n } catch (error) {\n const commanderError = error as { code?: string; exitCode?: number; message?: string };\n if (\n commanderError.code === \"commander.helpDisplayed\" ||\n commanderError.code === \"commander.version\"\n ) {\n return ExitCode.Ok;\n }\n if (commanderError.code?.startsWith(\"commander.\")) {\n runtime.stderr.write(`${commanderError.message ?? \"Invalid command.\"}\\n`);\n return commanderError.exitCode ?? ExitCode.Usage;\n }\n if (error instanceof CliError) {\n runtime.stderr.write(`${error.message}\\n`);\n return error.exitCode;\n }\n runtime.stderr.write(`${toErrorMessage(error)}\\n`);\n return ExitCode.General;\n }\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport chokidar from \"chokidar\";\nimport open from \"open\";\nimport { CommentaryApiClient } from \"./api-client.js\";\nimport { CLIENT_ID, CLIENT_NAME, REQUIRED_SCOPES, SESSION_FILE } from \"./constants.js\";\nimport { normalizeBaseUrl, removeStoredToken, resolveToken, setStoredToken } from \"./config.js\";\nimport { normalizeReviewPath } from \"./content.js\";\nimport { CliError, ExitCode } from \"./errors.js\";\nimport { collectFiles, readTrackedFiles, toTrackedFiles } from \"./files.js\";\nimport { contentHash } from \"./hash.js\";\nimport {\n formatCommentsMarkdown,\n formatCommentsText,\n formatReviewCreated,\n formatRevision,\n formatWaitCommentMarkdown,\n formatWaitCommentText,\n publicSessionJson,\n writeJson,\n writeText,\n type Writer,\n} from \"./output.js\";\nimport {\n findSessionFile,\n loadSessionMetadata,\n saveSessionMetadata,\n sessionRoot,\n} from \"./session.js\";\nimport type { CollectedFile } from \"./files.js\";\nimport type {\n DraftReviewLiveEvent,\n DraftReviewRevision,\n RequestedContentType,\n SessionMetadata,\n TrackedFile,\n} from \"./types.js\";\n\nexport type CommandRuntime = {\n cwd: string;\n stdout: Writer;\n stderr: Writer;\n fetchImpl?: typeof fetch | undefined;\n isTty?: boolean | undefined;\n};\n\nexport type GlobalOptions = {\n baseUrl?: string | undefined;\n token?: string | undefined;\n json?: boolean | undefined;\n verbose?: boolean | undefined;\n quiet?: boolean | undefined;\n noColor?: boolean | undefined;\n sessionFile?: string | undefined;\n};\n\nfunction nowIso() {\n return new Date().toISOString();\n}\n\nasync function makeClient(runtime: CommandRuntime, options: GlobalOptions) {\n const baseUrl = normalizeBaseUrl(options.baseUrl);\n const token = await resolveToken({ baseUrl, token: options.token });\n return new CommentaryApiClient({ baseUrl, token, fetchImpl: runtime.fetchImpl });\n}\n\nfunction apiFilesFromRevision(revision: DraftReviewRevision | null) {\n return revision?.files.map((file) => ({\n fileId: file.fileId,\n path: file.path,\n contentHash: file.contentHash,\n sizeBytes: file.sizeBytes,\n contentType: file.contentType,\n }));\n}\n\nfunction changedFiles(current: CollectedFile[], tracked: TrackedFile[]) {\n const trackedByPath = new Map(tracked.map((file) => [file.path, file]));\n return current.filter((file) => {\n const previous = trackedByPath.get(file.path);\n return (\n !previous ||\n previous.contentHash !== file.contentHash ||\n previous.contentType !== file.contentType\n );\n });\n}\n\nasync function loadSession(runtime: CommandRuntime, options: GlobalOptions) {\n return loadSessionMetadata(runtime.cwd, options.sessionFile);\n}\n\nfunction shouldOpen(runtime: CommandRuntime, noOpen?: boolean) {\n return !noOpen && runtime.isTty !== false && !process.env.CI;\n}\n\nfunction placeholderSessionMetadata(input: {\n sessionId: string;\n baseUrl: string;\n}): SessionMetadata {\n return {\n version: 1,\n reviewSessionId: input.sessionId,\n reviewUrl: `${input.baseUrl}/review/draft/${encodeURIComponent(input.sessionId)}`,\n baseUrl: input.baseUrl,\n rootPath: \".\",\n trackedFiles: [],\n source: [],\n createdAt: \"\",\n lastSyncedAt: \"\",\n lastKnownRevision: null,\n };\n}\n\nasync function openOrPrint(runtime: CommandRuntime, url: string, noOpen?: boolean) {\n if (!shouldOpen(runtime, noOpen)) {\n writeText(runtime.stdout, url);\n return;\n }\n try {\n await open(url);\n } catch {\n writeText(runtime.stdout, url);\n }\n}\n\nfunction parseDurationMs(value: string | undefined, defaultMs: number) {\n const raw = value?.trim();\n if (!raw) {\n return defaultMs;\n }\n if (raw === \"0\") {\n return 0;\n }\n const match = raw.match(/^(\\d+)(ms|s|m|h)?$/i);\n if (!match) {\n throw new CliError(\n \"Duration must be a number with optional ms, s, m, or h suffix.\",\n ExitCode.Usage,\n );\n }\n const amount = Number(match[1]);\n const unit = match[2]?.toLowerCase() ?? \"ms\";\n const multiplier = unit === \"h\" ? 3_600_000 : unit === \"m\" ? 60_000 : unit === \"s\" ? 1_000 : 1;\n return amount * multiplier;\n}\n\nfunction delay(ms: number, signal: AbortSignal) {\n return new Promise<void>((resolve) => {\n if (signal.aborted) {\n resolve();\n return;\n }\n const timeout = setTimeout(resolve, ms);\n signal.addEventListener(\n \"abort\",\n () => {\n clearTimeout(timeout);\n resolve();\n },\n { once: true },\n );\n });\n}\n\nfunction payloadString(event: DraftReviewLiveEvent, key: string) {\n const value = event.payload[key];\n return typeof value === \"string\" && value.trim() ? value.trim() : null;\n}\n\nfunction resolveAgentAlias(alias?: string | undefined) {\n const value = alias?.trim() || process.env.COMMENTARY_AGENT_ALIAS?.trim();\n return value || undefined;\n}\n\nfunction isWaitCommentMatch(input: {\n event: DraftReviewLiveEvent;\n includeReplies?: boolean | undefined;\n filePath?: string | undefined;\n}) {\n const allowed =\n input.event.type === \"comment.created\" ||\n (input.includeReplies !== false && input.event.type === \"reply.created\");\n if (!allowed) {\n return false;\n }\n if (!input.filePath) {\n return true;\n }\n return (\n (input.event.thread?.filePath ?? payloadString(input.event, \"filePath\")) === input.filePath\n );\n}\n\nexport async function loginCommand(\n runtime: CommandRuntime,\n options: GlobalOptions & { token?: string | undefined; noOpen?: boolean | undefined },\n) {\n const baseUrl = normalizeBaseUrl(options.baseUrl);\n if (options.token?.trim()) {\n await setStoredToken(baseUrl, { accessToken: options.token.trim() });\n if (options.json) {\n writeJson(runtime.stdout, { ok: true, baseUrl });\n } else {\n writeText(runtime.stdout, `Stored Commentary token for ${baseUrl}.`);\n }\n return;\n }\n\n const client = new CommentaryApiClient({ baseUrl, fetchImpl: runtime.fetchImpl });\n const resource = `${baseUrl}/api`;\n const device = await client.requestDeviceCode({\n clientId: CLIENT_ID,\n clientName: CLIENT_NAME,\n scope: REQUIRED_SCOPES.join(\" \"),\n resource,\n });\n if (options.json) {\n writeJson(runtime.stdout, {\n verificationUri: device.verification_uri,\n verificationUriComplete: device.verification_uri_complete,\n userCode: device.user_code,\n expiresIn: device.expires_in,\n });\n } else {\n writeText(\n runtime.stdout,\n [\n \"Connect Commentary\",\n \"\",\n `Open: ${device.verification_uri_complete}`,\n `Code: ${device.user_code}`,\n \"\",\n \"Waiting for approval...\",\n ].join(\"\\n\"),\n );\n }\n if (shouldOpen(runtime, options.noOpen)) {\n await open(device.verification_uri_complete).catch(() => undefined);\n }\n\n const startedAt = Date.now();\n const intervalMs = Math.max(1, device.interval) * 1000;\n while (Date.now() - startedAt < device.expires_in * 1000) {\n await new Promise((resolve) => setTimeout(resolve, intervalMs));\n try {\n const token = await client.exchangeDeviceCode({ deviceCode: device.device_code, resource });\n await setStoredToken(baseUrl, {\n accessToken: token.access_token,\n refreshToken: token.refresh_token,\n expiresAt: new Date(Date.now() + token.expires_in * 1000).toISOString(),\n });\n if (!options.json) {\n writeText(runtime.stdout, `Logged in to ${baseUrl}.`);\n }\n return;\n } catch (error) {\n if (error instanceof CliError && error.message === \"authorization_pending\") {\n continue;\n }\n throw error;\n }\n }\n throw new CliError(\"Device authorization expired.\", ExitCode.Auth);\n}\n\nexport async function logoutCommand(runtime: CommandRuntime, options: GlobalOptions) {\n const baseUrl = normalizeBaseUrl(options.baseUrl);\n await removeStoredToken(baseUrl);\n if (options.json) {\n writeJson(runtime.stdout, { ok: true, baseUrl });\n } else {\n writeText(runtime.stdout, `Removed Commentary token for ${baseUrl}.`);\n }\n}\n\nexport async function whoamiCommand(runtime: CommandRuntime, options: GlobalOptions) {\n const client = await makeClient(runtime, options);\n const result = await client.listDraftReviews();\n const payload = {\n ok: true,\n baseUrl: client.baseUrl,\n token: \"valid\",\n accessibleDraftReviews: result.draftReviews.length,\n };\n if (options.json) {\n writeJson(runtime.stdout, payload);\n } else {\n writeText(\n runtime.stdout,\n `Authenticated for ${client.baseUrl}. Accessible draft reviews: ${result.draftReviews.length}`,\n );\n }\n}\n\nexport async function reviewCommand(\n runtime: CommandRuntime,\n paths: string[],\n options: GlobalOptions & {\n title?: string;\n description?: string;\n contentType?: RequestedContentType;\n watch?: boolean;\n noOpen?: boolean;\n include?: string[];\n exclude?: string[];\n root?: string;\n },\n) {\n const root = path.resolve(runtime.cwd, options.root ?? \".\");\n const files = await collectFiles(paths, {\n root,\n include: options.include,\n exclude: options.exclude,\n requestedContentType: options.contentType ?? \"auto\",\n });\n const title =\n options.title?.trim() ||\n (files.length === 1\n ? path.basename(files[0]!.path, path.extname(files[0]!.path))\n : path.basename(root)) ||\n \"Commentary review\";\n const client = await makeClient(runtime, options);\n const result = await client.createDraftReview({\n title,\n description: options.description ?? null,\n files,\n });\n const sessionFilePath = await findSessionFile(root, options.sessionFile ?? SESSION_FILE);\n const now = nowIso();\n const metadata: SessionMetadata = {\n version: 1,\n reviewSessionId: result.sessionId,\n reviewUrl: result.reviewUrl,\n baseUrl: client.baseUrl,\n rootPath: path.relative(path.dirname(sessionFilePath), root) || \".\",\n trackedFiles: toTrackedFiles(files, apiFilesFromRevision(result.draftReview.latestRevision)),\n source: [\"review\", ...paths],\n createdAt: now,\n lastSyncedAt: now,\n lastKnownRevision: result.draftReview.latestRevision?.revisionNumber ?? null,\n };\n await saveSessionMetadata(sessionFilePath, metadata);\n\n if (options.json) {\n writeJson(runtime.stdout, {\n ok: true,\n draftReview: result.draftReview,\n sessionFilePath,\n session: publicSessionJson(metadata),\n });\n } else {\n writeText(\n runtime.stdout,\n formatReviewCreated({\n draftReview: result.draftReview,\n sessionFilePath,\n fileCount: files.length,\n }),\n );\n }\n if (!options.noOpen) {\n await openOrPrint(runtime, result.reviewUrl, options.noOpen);\n }\n if (options.watch) {\n await watchCommand(runtime, { ...options, sessionFile: sessionFilePath });\n }\n}\n\nexport async function syncCommand(\n runtime: CommandRuntime,\n options: GlobalOptions & {\n message?: string;\n all?: boolean;\n dryRun?: boolean;\n },\n) {\n const loaded = await loadSession(runtime, options);\n const root = sessionRoot(loaded.filePath, loaded.metadata);\n const current = await readTrackedFiles(root, loaded.metadata.trackedFiles);\n const changed = changedFiles(current, loaded.metadata.trackedFiles);\n if (options.dryRun) {\n const payload = {\n ok: true,\n changedFiles: changed.map((file) => file.path),\n fileCount: current.length,\n };\n if (options.json) {\n writeJson(runtime.stdout, payload);\n } else {\n writeText(\n runtime.stdout,\n payload.changedFiles.length ? payload.changedFiles.join(\"\\n\") : \"No local changes.\",\n );\n }\n return;\n }\n if (!options.all && changed.length === 0) {\n const revision = {\n id: \"\",\n revisionNumber: loaded.metadata.lastKnownRevision ?? 0,\n files: [],\n };\n if (options.json) {\n writeJson(runtime.stdout, {\n ok: true,\n noOp: true,\n session: publicSessionJson(loaded.metadata),\n });\n } else {\n writeText(\n runtime.stdout,\n formatRevision({ metadata: loaded.metadata, revision, uploaded: 0, noOp: true }),\n );\n }\n return;\n }\n\n const client = await makeClient(runtime, { ...options, baseUrl: loaded.metadata.baseUrl });\n const result = await client.createRevision({\n sessionId: loaded.metadata.reviewSessionId,\n summary: options.message ?? null,\n files: current,\n });\n const nextMetadata: SessionMetadata = {\n ...loaded.metadata,\n trackedFiles: toTrackedFiles(current, apiFilesFromRevision(result.revision)),\n lastSyncedAt: nowIso(),\n lastKnownRevision: result.revision.revisionNumber,\n };\n await saveSessionMetadata(loaded.filePath, nextMetadata);\n\n if (options.json) {\n writeJson(runtime.stdout, {\n ok: true,\n revision: result.revision,\n noOp: Boolean(result.noOp),\n session: publicSessionJson(nextMetadata),\n });\n } else {\n writeText(\n runtime.stdout,\n formatRevision({\n metadata: nextMetadata,\n revision: result.revision,\n uploaded: current.length,\n noOp: result.noOp,\n }),\n );\n }\n}\n\nexport async function watchCommand(\n runtime: CommandRuntime,\n options: GlobalOptions & {\n debounce?: number;\n message?: string;\n },\n) {\n const loaded = await loadSession(runtime, options);\n const root = sessionRoot(loaded.filePath, loaded.metadata);\n const debounceMs = Number(options.debounce ?? 1500);\n let timer: NodeJS.Timeout | null = null;\n let syncing = false;\n const watcher = chokidar.watch(\n loaded.metadata.trackedFiles.map((file) => path.resolve(root, file.path)),\n {\n ignoreInitial: true,\n ignored:\n /(^|[/\\\\])(\\.git|node_modules|dist|build|\\.next|\\.commentary)([/\\\\]|$)|(~$|\\.tmp$|\\.swp$)/,\n },\n );\n\n const runSync = () => {\n if (timer) {\n clearTimeout(timer);\n }\n timer = setTimeout(() => {\n if (syncing) {\n return;\n }\n syncing = true;\n syncCommand(runtime, { ...options, message: options.message ?? \"Watch sync\" })\n .catch((error: unknown) =>\n runtime.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`),\n )\n .finally(() => {\n syncing = false;\n });\n }, debounceMs);\n };\n\n watcher.on(\"add\", runSync).on(\"change\", runSync).on(\"unlink\", runSync);\n writeText(\n runtime.stdout,\n `Watching ${loaded.metadata.trackedFiles.length} file(s). Press Ctrl+C to stop.`,\n );\n await new Promise<void>((resolve) => {\n const close = () => {\n void watcher.close().finally(resolve);\n };\n process.once(\"SIGINT\", close);\n process.once(\"SIGTERM\", close);\n });\n}\n\nexport async function commentsCommand(\n runtime: CommandRuntime,\n options: GlobalOptions & {\n format?: \"text\" | \"markdown\" | \"json\";\n open?: boolean;\n resolved?: boolean;\n all?: boolean;\n file?: string;\n session?: string;\n },\n) {\n const loaded = options.session ? null : await loadSession(runtime, options);\n const metadata = loaded?.metadata;\n const sessionId = options.session ?? metadata?.reviewSessionId;\n if (!sessionId) {\n throw new CliError(\"A session id is required.\", ExitCode.Usage);\n }\n const baseUrl = metadata?.baseUrl ?? normalizeBaseUrl(options.baseUrl);\n const client = await makeClient(runtime, { ...options, baseUrl });\n const status = options.all ? undefined : options.resolved ? \"resolved\" : \"open\";\n const result = await client.listComments({\n sessionId,\n status,\n filePath: options.file ? normalizeReviewPath(options.file) : undefined,\n });\n const format = options.json ? \"json\" : (options.format ?? \"text\");\n if (format === \"json\") {\n writeJson(runtime.stdout, { ok: true, threads: result.threads });\n } else if (format === \"markdown\") {\n writeText(\n runtime.stdout,\n formatCommentsMarkdown({\n session: metadata ?? {\n version: 1,\n reviewSessionId: sessionId,\n reviewUrl: `${baseUrl}/review/draft/${encodeURIComponent(sessionId)}`,\n baseUrl,\n rootPath: \".\",\n trackedFiles: [],\n source: [],\n createdAt: \"\",\n lastSyncedAt: \"\",\n lastKnownRevision: null,\n },\n threads: result.threads,\n }),\n );\n } else {\n writeText(runtime.stdout, formatCommentsText(result.threads));\n }\n}\n\nexport async function waitCommentCommand(\n runtime: CommandRuntime,\n options: GlobalOptions & {\n session?: string;\n file?: string;\n includeReplies?: boolean;\n cursor?: string;\n from?: \"beginning\" | \"latest\";\n timeout?: string;\n format?: \"text\" | \"markdown\" | \"json\";\n },\n) {\n const loaded = options.session ? null : await loadSession(runtime, options);\n const sessionId = options.session ?? loaded?.metadata.reviewSessionId;\n if (!sessionId) {\n throw new CliError(\"A session id is required.\", ExitCode.Usage);\n }\n\n const baseUrl = loaded?.metadata.baseUrl ?? normalizeBaseUrl(options.baseUrl);\n const session = loaded?.metadata ?? placeholderSessionMetadata({ sessionId, baseUrl });\n const client = await makeClient(runtime, { ...options, baseUrl });\n const filePath = options.file ? normalizeReviewPath(options.file) : undefined;\n const timeoutMs = parseDurationMs(options.timeout, 30 * 60 * 1000);\n const abortController = new AbortController();\n let timedOut = false;\n let cursor = options.cursor ?? (options.from === \"beginning\" ? undefined : \"latest\");\n let reconnectDelayMs = 1000;\n const timeout =\n timeoutMs > 0\n ? setTimeout(() => {\n timedOut = true;\n abortController.abort();\n }, timeoutMs)\n : null;\n\n try {\n while (!abortController.signal.aborted) {\n try {\n for await (const event of client.streamDraftReviewEvents({\n sessionId,\n cursor,\n signal: abortController.signal,\n })) {\n cursor = event.id;\n reconnectDelayMs = 1000;\n if (event.type === \"draft.deleted\") {\n throw new CliError(\"Draft review was deleted before a comment arrived.\", ExitCode.Api);\n }\n if (!isWaitCommentMatch({ event, includeReplies: options.includeReplies, filePath })) {\n continue;\n }\n\n const format = options.json ? \"json\" : (options.format ?? \"markdown\");\n if (format === \"json\") {\n writeJson(runtime.stdout, { ok: true, event });\n } else if (format === \"text\") {\n writeText(runtime.stdout, formatWaitCommentText(event));\n } else {\n writeText(runtime.stdout, formatWaitCommentMarkdown({ session, event }));\n }\n abortController.abort();\n return;\n }\n } catch (error) {\n if (abortController.signal.aborted) {\n break;\n }\n if (error instanceof CliError && error.exitCode !== ExitCode.Network) {\n throw error;\n }\n if (options.verbose) {\n runtime.stderr.write(\n `Event stream disconnected; reconnecting in ${reconnectDelayMs}ms.\\n`,\n );\n }\n }\n\n await delay(reconnectDelayMs, abortController.signal);\n reconnectDelayMs = Math.min(reconnectDelayMs * 2, 10_000);\n }\n } finally {\n if (timeout) {\n clearTimeout(timeout);\n }\n }\n\n throw new CliError(\n timedOut\n ? \"Timed out waiting for a draft review comment.\"\n : \"Stopped waiting for a draft review comment.\",\n timedOut ? ExitCode.Timeout : ExitCode.General,\n );\n}\n\nexport async function replyCommand(\n runtime: CommandRuntime,\n threadId: string,\n message: string,\n options: GlobalOptions & { session?: string; alias?: string },\n) {\n const loaded = options.session ? null : await loadSession(runtime, options);\n const sessionId = options.session ?? loaded?.metadata.reviewSessionId;\n if (!sessionId) {\n throw new CliError(\"A session id is required.\", ExitCode.Usage);\n }\n const client = await makeClient(runtime, {\n ...options,\n baseUrl: loaded?.metadata.baseUrl ?? options.baseUrl,\n });\n const result = await client.replyToComment({\n sessionId,\n threadId,\n bodyMarkdown: message,\n agentAlias: resolveAgentAlias(options.alias),\n });\n const thread =\n result.thread.status === \"resolved\"\n ? (\n await client.updateCommentStatus({\n sessionId,\n threadId,\n status: \"open\",\n })\n ).thread\n : result.thread;\n if (options.json) {\n writeJson(runtime.stdout, { ok: true, thread });\n } else {\n writeText(\n runtime.stdout,\n thread.status === \"open\" && result.thread.status === \"resolved\"\n ? `Replied to ${threadId} and reopened the thread.`\n : `Replied to ${threadId}.`,\n );\n }\n}\n\nexport async function resolveCommand(\n runtime: CommandRuntime,\n threadId: string,\n options: GlobalOptions & {\n session?: string;\n message?: string;\n alias?: string;\n },\n) {\n const loaded = options.session ? null : await loadSession(runtime, options);\n const sessionId = options.session ?? loaded?.metadata.reviewSessionId;\n if (!sessionId) {\n throw new CliError(\"A session id is required.\", ExitCode.Usage);\n }\n const client = await makeClient(runtime, {\n ...options,\n baseUrl: loaded?.metadata.baseUrl ?? options.baseUrl,\n });\n if (options.message?.trim()) {\n await client.replyToComment({\n sessionId,\n threadId,\n bodyMarkdown: options.message.trim(),\n agentAlias: resolveAgentAlias(options.alias),\n });\n }\n const result = await client.updateCommentStatus({ sessionId, threadId, status: \"resolved\" });\n if (options.json) {\n writeJson(runtime.stdout, { ok: true, thread: result.thread });\n } else {\n writeText(runtime.stdout, `Resolved ${threadId}.`);\n }\n}\n\nexport async function pullCommand(\n runtime: CommandRuntime,\n options: GlobalOptions & {\n dryRun?: boolean;\n yes?: boolean;\n backup?: boolean;\n output?: string;\n },\n) {\n const loaded = await loadSession(runtime, options);\n const root = sessionRoot(loaded.filePath, loaded.metadata);\n const client = await makeClient(runtime, { ...options, baseUrl: loaded.metadata.baseUrl });\n const session = await client.getDraftReview(loaded.metadata.reviewSessionId);\n const writes: Array<{ path: string; target: string; content: string; changed: boolean }> = [];\n for (const file of session.draftReview.files) {\n const content = await client.getFileContent({\n sessionId: loaded.metadata.reviewSessionId,\n fileId: file.id,\n });\n const targetRoot = options.output ? path.resolve(runtime.cwd, options.output) : root;\n const target = path.resolve(targetRoot, file.path);\n let current: string | null = null;\n try {\n current = await fs.readFile(target, \"utf8\");\n } catch {\n current = null;\n }\n writes.push({ path: file.path, target, content, changed: current !== content });\n }\n\n if (options.dryRun) {\n const changed = writes.filter((write) => write.changed).map((write) => write.path);\n if (options.json) {\n writeJson(runtime.stdout, { ok: true, changedFiles: changed });\n } else {\n writeText(runtime.stdout, changed.length ? changed.join(\"\\n\") : \"No remote changes.\");\n }\n return;\n }\n\n const changedWrites = writes.filter((write) => write.changed);\n if (changedWrites.length > 0 && !options.yes && !options.output) {\n throw new CliError(\n \"Pull would overwrite local files. Rerun with --yes, --backup, or --output <dir>.\",\n ExitCode.Safety,\n );\n }\n\n for (const write of writes) {\n if (!write.changed) {\n continue;\n }\n await fs.mkdir(path.dirname(write.target), { recursive: true });\n if (options.backup) {\n try {\n await fs.copyFile(write.target, `${write.target}.bak`);\n } catch {\n // No existing file to back up.\n }\n }\n await fs.writeFile(write.target, write.content, \"utf8\");\n }\n\n const nextTracked = loaded.metadata.trackedFiles.map((tracked) => {\n const write = writes.find((candidate) => candidate.path === tracked.path);\n return write\n ? {\n ...tracked,\n contentHash: contentHash(write.content),\n sizeBytes: Buffer.byteLength(write.content),\n }\n : tracked;\n });\n await saveSessionMetadata(loaded.filePath, { ...loaded.metadata, trackedFiles: nextTracked });\n\n if (options.json) {\n writeJson(runtime.stdout, { ok: true, filesWritten: changedWrites.length });\n } else {\n writeText(runtime.stdout, `Pulled ${changedWrites.length} file(s).`);\n }\n}\n\nexport async function openCommand(\n runtime: CommandRuntime,\n options: GlobalOptions & { session?: string },\n) {\n if (options.session) {\n const baseUrl = normalizeBaseUrl(options.baseUrl);\n await openOrPrint(runtime, `${baseUrl}/review/draft/${encodeURIComponent(options.session)}`);\n return;\n }\n const loaded = await loadSession(runtime, options);\n await openOrPrint(runtime, loaded.metadata.reviewUrl);\n}\n\nexport async function statusCommand(runtime: CommandRuntime, options: GlobalOptions) {\n const loaded = await loadSession(runtime, options);\n const root = sessionRoot(loaded.filePath, loaded.metadata);\n const current = await readTrackedFiles(root, loaded.metadata.trackedFiles);\n const changed = changedFiles(current, loaded.metadata.trackedFiles).map((file) => file.path);\n let openComments: number | null = null;\n let resolvedComments: number | null = null;\n try {\n const client = await makeClient(runtime, { ...options, baseUrl: loaded.metadata.baseUrl });\n const [openResult, resolvedResult] = await Promise.all([\n client.listComments({ sessionId: loaded.metadata.reviewSessionId, status: \"open\" }),\n client.listComments({ sessionId: loaded.metadata.reviewSessionId, status: \"resolved\" }),\n ]);\n openComments = openResult.threads.length;\n resolvedComments = resolvedResult.threads.length;\n } catch {\n openComments = null;\n resolvedComments = null;\n }\n const payload = {\n ...publicSessionJson(loaded.metadata),\n changedFiles: changed,\n openComments,\n resolvedComments,\n };\n if (options.json) {\n writeJson(runtime.stdout, payload);\n } else {\n writeText(\n runtime.stdout,\n [\n `Session: ${loaded.metadata.reviewSessionId}`,\n `URL: ${loaded.metadata.reviewUrl}`,\n `Base URL: ${loaded.metadata.baseUrl}`,\n `Tracked files: ${loaded.metadata.trackedFiles.length}`,\n `Last revision: ${loaded.metadata.lastKnownRevision ?? \"unknown\"}`,\n `Changed files: ${changed.length ? changed.join(\", \") : \"none\"}`,\n `Open comments: ${openComments ?? \"unknown\"}`,\n `Resolved comments: ${resolvedComments ?? \"unknown\"}`,\n ].join(\"\\n\"),\n );\n }\n}\n\nexport async function sessionsCommand(runtime: CommandRuntime, options: GlobalOptions) {\n const client = await makeClient(runtime, options);\n const result = await client.listDraftReviews();\n if (options.json) {\n writeJson(runtime.stdout, result);\n } else {\n writeText(\n runtime.stdout,\n result.draftReviews\n .map((draft) => `${draft.id}\\t${draft.title}\\t${draft.reviewUrl}`)\n .join(\"\\n\") || \"No draft reviews found.\",\n );\n }\n}\n\nexport async function revisionsCommand(\n runtime: CommandRuntime,\n options: GlobalOptions & { session?: string },\n) {\n const loaded = options.session ? null : await loadSession(runtime, options);\n const sessionId = options.session ?? loaded?.metadata.reviewSessionId;\n if (!sessionId) {\n throw new CliError(\"A session id is required.\", ExitCode.Usage);\n }\n const client = await makeClient(runtime, {\n ...options,\n baseUrl: loaded?.metadata.baseUrl ?? options.baseUrl,\n });\n const result = await client.listRevisions(sessionId);\n if (options.json) {\n writeJson(runtime.stdout, result);\n } else {\n writeText(\n runtime.stdout,\n result.revisions\n .map(\n (revision) =>\n `#${revision.revisionNumber}\\t${revision.summary ?? \"\"}\\t${revision.createdAt ?? \"\"}`,\n )\n .join(\"\\n\") || \"No revisions found.\",\n );\n }\n}\n","export class CliError extends Error {\n readonly exitCode: number;\n\n constructor(message: string, exitCode = 1) {\n super(message);\n this.name = \"CliError\";\n this.exitCode = exitCode;\n }\n}\n\nexport const ExitCode = {\n Ok: 0,\n General: 1,\n Usage: 2,\n Auth: 3,\n Network: 4,\n Api: 5,\n Safety: 6,\n Timeout: 124,\n} as const;\n\nexport function toErrorMessage(error: unknown) {\n return error instanceof Error ? error.message : String(error);\n}\n","export type SseMessage = {\n id?: string | undefined;\n event?: string | undefined;\n data?: string | undefined;\n retry?: number | undefined;\n};\n\nexport class SseParser {\n private buffer = \"\";\n private id: string | undefined;\n private event: string | undefined;\n private dataLines: string[] = [];\n private retry: number | undefined;\n\n feed(chunk: string) {\n this.buffer += chunk;\n const messages: SseMessage[] = [];\n\n while (true) {\n const boundary = this.findBoundary();\n if (!boundary) {\n break;\n }\n const raw = this.buffer.slice(0, boundary.index);\n this.buffer = this.buffer.slice(boundary.index + boundary.length);\n const message = this.consumeBlock(raw);\n if (message) {\n messages.push(message);\n }\n }\n\n return messages;\n }\n\n flush() {\n if (!this.buffer.trim()) {\n this.buffer = \"\";\n return [];\n }\n const message = this.consumeBlock(this.buffer);\n this.buffer = \"\";\n return message ? [message] : [];\n }\n\n private findBoundary() {\n const candidates = [\n { index: this.buffer.indexOf(\"\\r\\n\\r\\n\"), length: 4 },\n { index: this.buffer.indexOf(\"\\n\\n\"), length: 2 },\n { index: this.buffer.indexOf(\"\\r\\r\"), length: 2 },\n ].filter((candidate) => candidate.index >= 0);\n return candidates.sort((a, b) => a.index - b.index)[0] ?? null;\n }\n\n private consumeBlock(raw: string): SseMessage | null {\n for (const line of raw.split(/\\r\\n|\\r|\\n/)) {\n this.consumeLine(line);\n }\n\n if (this.dataLines.length === 0) {\n this.event = undefined;\n this.dataLines = [];\n this.retry = undefined;\n return null;\n }\n\n const message: SseMessage = {\n id: this.id,\n event: this.event,\n data: this.dataLines.join(\"\\n\"),\n retry: this.retry,\n };\n this.event = undefined;\n this.dataLines = [];\n this.retry = undefined;\n return message;\n }\n\n private consumeLine(line: string) {\n if (!line || line.startsWith(\":\")) {\n return;\n }\n\n const separator = line.indexOf(\":\");\n const field = separator >= 0 ? line.slice(0, separator) : line;\n const value = separator >= 0 ? line.slice(separator + 1).replace(/^ /, \"\") : \"\";\n\n if (field === \"id\") {\n this.id = value;\n } else if (field === \"event\") {\n this.event = value;\n } else if (field === \"data\") {\n this.dataLines.push(value);\n } else if (field === \"retry\") {\n const retry = Number(value);\n if (Number.isInteger(retry) && retry >= 0) {\n this.retry = retry;\n }\n }\n }\n}\n","import { CliError, ExitCode } from \"./errors.js\";\nimport { SseParser } from \"./sse.js\";\nimport type {\n DraftFileInput,\n DraftReviewLiveEvent,\n DraftReviewRevision,\n DraftReviewSession,\n DraftThread,\n} from \"./types.js\";\n\nexport type FetchLike = typeof fetch;\n\ntype ApiClientOptions = {\n baseUrl: string;\n token?: string | null | undefined;\n fetchImpl?: FetchLike | undefined;\n};\n\ntype OAuthMetadata = {\n issuer: string;\n token_endpoint: string;\n device_authorization_endpoint: string;\n authorization_endpoint?: string;\n registration_endpoint?: string;\n};\n\nexport class CommentaryApiClient {\n readonly baseUrl: string;\n private readonly token: string | null;\n private readonly fetchImpl: FetchLike;\n\n constructor(options: ApiClientOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, \"\");\n this.token = options.token ?? null;\n this.fetchImpl = options.fetchImpl ?? fetch;\n }\n\n async getOAuthMetadata() {\n return this.rawJson<OAuthMetadata>(\"/.well-known/oauth-authorization-server\", { auth: false });\n }\n\n async requestDeviceCode(input: {\n clientId: string;\n clientName: string;\n scope: string;\n resource: string;\n }) {\n const metadata = await this.getOAuthMetadata();\n return this.rawJson<{\n device_code: string;\n user_code: string;\n verification_uri: string;\n verification_uri_complete: string;\n expires_in: number;\n interval: number;\n }>(metadata.device_authorization_endpoint, {\n auth: false,\n method: \"POST\",\n body: {\n client_id: input.clientId,\n client_name: input.clientName,\n scope: input.scope,\n resource: input.resource,\n },\n });\n }\n\n async exchangeDeviceCode(input: { deviceCode: string; resource: string }) {\n const metadata = await this.getOAuthMetadata();\n return this.rawJson<{\n access_token: string;\n refresh_token: string;\n token_type: \"Bearer\";\n expires_in: number;\n }>(metadata.token_endpoint, {\n auth: false,\n method: \"POST\",\n body: {\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n device_code: input.deviceCode,\n resource: input.resource,\n },\n });\n }\n\n async listDraftReviews() {\n return this.request<{ ok: true; draftReviews: DraftReviewSession[] }>(\"/api/v1/draft-reviews\");\n }\n\n async createDraftReview(input: {\n title: string;\n description?: string | null;\n files: DraftFileInput[];\n }) {\n return this.request<{\n ok: true;\n draftReview: DraftReviewSession;\n sessionId: string;\n reviewUrl: string;\n }>(\"/api/v1/draft-reviews\", {\n method: \"POST\",\n body: {\n title: input.title,\n description: input.description,\n sourceType: \"cli\",\n files: input.files.map((file) => ({\n path: file.path,\n content: file.content,\n contentType: file.contentType,\n })),\n },\n });\n }\n\n async getDraftReview(sessionId: string) {\n return this.request<{ ok: true; draftReview: DraftReviewSession }>(\n `/api/v1/draft-reviews/${encodeURIComponent(sessionId)}`,\n );\n }\n\n async createRevision(input: {\n sessionId: string;\n summary?: string | null;\n files: DraftFileInput[];\n }) {\n return this.request<{ ok: true; revision: DraftReviewRevision; noOp?: boolean }>(\n `/api/v1/draft-reviews/${encodeURIComponent(input.sessionId)}/revisions`,\n {\n method: \"POST\",\n body: {\n summary: input.summary,\n files: input.files.map((file) => ({\n fileId: file.fileId,\n path: file.path,\n content: file.content,\n contentType: file.contentType,\n })),\n },\n },\n );\n }\n\n async listRevisions(sessionId: string) {\n return this.request<{ ok: true; revisions: DraftReviewRevision[] }>(\n `/api/v1/draft-reviews/${encodeURIComponent(sessionId)}/revisions`,\n );\n }\n\n async listComments(input: {\n sessionId: string;\n status?: \"open\" | \"resolved\" | undefined;\n filePath?: string | undefined;\n fileId?: string | undefined;\n }) {\n const params = new URLSearchParams();\n if (input.status) {\n params.set(\"status\", input.status);\n }\n if (input.filePath) {\n params.set(\"filePath\", input.filePath);\n }\n if (input.fileId) {\n params.set(\"fileId\", input.fileId);\n }\n const suffix = params.size ? `?${params}` : \"\";\n return this.request<{ ok: true; threads: DraftThread[] }>(\n `/api/v1/draft-reviews/${encodeURIComponent(input.sessionId)}/comments${suffix}`,\n );\n }\n\n async replyToComment(input: {\n sessionId: string;\n threadId: string;\n bodyMarkdown: string;\n agentAlias?: string | undefined;\n }) {\n return this.request<{ ok: true; thread: DraftThread }>(\n `/api/v1/draft-reviews/${encodeURIComponent(input.sessionId)}/comments/${encodeURIComponent(input.threadId)}/replies`,\n {\n method: \"POST\",\n body: {\n bodyMarkdown: input.bodyMarkdown,\n ...(input.agentAlias ? { agentAlias: input.agentAlias } : {}),\n },\n },\n );\n }\n\n async updateCommentStatus(input: {\n sessionId: string;\n threadId: string;\n status: \"open\" | \"resolved\";\n }) {\n return this.request<{ ok: true; thread: DraftThread }>(\n `/api/v1/draft-reviews/${encodeURIComponent(input.sessionId)}/comments/${encodeURIComponent(input.threadId)}/status`,\n {\n method: \"POST\",\n body: { status: input.status },\n },\n );\n }\n\n async getFileContent(input: { sessionId: string; fileId: string }) {\n return this.rawText(\n `/api/v1/draft-reviews/${encodeURIComponent(input.sessionId)}/files/${encodeURIComponent(input.fileId)}/content`,\n { auth: true },\n );\n }\n\n async *streamDraftReviewEvents(input: {\n sessionId: string;\n cursor?: string | undefined;\n once?: boolean | undefined;\n signal?: AbortSignal | undefined;\n }): AsyncGenerator<DraftReviewLiveEvent> {\n const params = new URLSearchParams();\n if (input.cursor) {\n params.set(\"cursor\", input.cursor);\n }\n if (input.once) {\n params.set(\"once\", \"1\");\n }\n const suffix = params.size ? `?${params}` : \"\";\n const response = await this.doFetch(\n `/api/v1/draft-reviews/${encodeURIComponent(input.sessionId)}/events${suffix}`,\n { auth: true, accept: \"text/event-stream\", signal: input.signal },\n );\n if (!response.ok) {\n await this.throwApiError(response);\n }\n if (!response.body) {\n throw new CliError(\"Commentary event stream did not include a response body.\", ExitCode.Api);\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n const parser = new SseParser();\n let completed = false;\n try {\n while (true) {\n const { done, value } = await reader.read();\n completed = done;\n const messages = done\n ? parser.flush()\n : parser.feed(decoder.decode(value, { stream: true }));\n for (const message of messages) {\n if (message.event && message.event !== \"draft-review\") {\n continue;\n }\n if (!message.data) {\n continue;\n }\n yield JSON.parse(message.data) as DraftReviewLiveEvent;\n }\n if (done) {\n break;\n }\n }\n } catch (error) {\n if (input.signal?.aborted) {\n return;\n }\n throw new CliError(\n error instanceof Error ? error.message : \"Commentary event stream failed.\",\n ExitCode.Network,\n );\n } finally {\n if (!completed) {\n await reader.cancel().catch(() => undefined);\n }\n reader.releaseLock();\n }\n }\n\n private async request<T>(pathOrUrl: string, init?: { method?: string; body?: unknown }) {\n return this.rawJson<T>(pathOrUrl, { ...init, auth: true });\n }\n\n private async rawText(\n pathOrUrl: string,\n init: { auth: boolean; method?: string; body?: unknown },\n ) {\n const response = await this.doFetch(pathOrUrl, init);\n if (!response.ok) {\n await this.throwApiError(response);\n }\n return response.text();\n }\n\n private async rawJson<T>(\n pathOrUrl: string,\n init: { auth: boolean; method?: string; body?: unknown },\n ) {\n const response = await this.doFetch(pathOrUrl, init);\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n const payload = contentType.includes(\"application/json\")\n ? ((await response.json()) as unknown)\n : null;\n if (!response.ok) {\n this.throwPayloadError(response.status, payload);\n }\n return payload as T;\n }\n\n private async doFetch(\n pathOrUrl: string,\n init: {\n auth: boolean;\n method?: string;\n body?: unknown;\n accept?: string;\n signal?: AbortSignal | undefined;\n },\n ) {\n const url =\n pathOrUrl.startsWith(\"http://\") || pathOrUrl.startsWith(\"https://\")\n ? pathOrUrl\n : `${this.baseUrl}${pathOrUrl}`;\n const headers: Record<string, string> = {\n accept: init.accept ?? \"application/json\",\n };\n let body: string | undefined;\n if (init.body !== undefined) {\n headers[\"content-type\"] = \"application/json\";\n body = JSON.stringify(init.body);\n }\n if (init.auth) {\n if (!this.token) {\n throw new CliError(\n \"Authentication is required. Run commentary login or set COMMENTARY_TOKEN.\",\n ExitCode.Auth,\n );\n }\n headers.authorization = `Bearer ${this.token}`;\n }\n try {\n const requestInit: RequestInit = {\n method: init.method ?? \"GET\",\n headers,\n };\n if (init.signal) {\n requestInit.signal = init.signal;\n }\n if (body !== undefined) {\n requestInit.body = body;\n }\n return await this.fetchImpl(url, requestInit);\n } catch (error) {\n throw new CliError(\n error instanceof Error ? error.message : \"Network request failed.\",\n ExitCode.Network,\n );\n }\n }\n\n private async throwApiError(response: Response): Promise<never> {\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (contentType.includes(\"application/json\")) {\n this.throwPayloadError(response.status, await response.json());\n }\n throw new CliError(\n `Commentary API returned ${response.status}.`,\n response.status === 401 ? ExitCode.Auth : ExitCode.Api,\n );\n }\n\n private throwPayloadError(status: number, payload: unknown): never {\n const body =\n payload && typeof payload === \"object\"\n ? (payload as { error?: unknown; error_description?: unknown })\n : {};\n const message =\n typeof body.error === \"string\"\n ? body.error\n : typeof body.error_description === \"string\"\n ? body.error_description\n : `Commentary API returned ${status}.`;\n throw new CliError(message, status === 401 || status === 403 ? ExitCode.Auth : ExitCode.Api);\n }\n}\n","export const DEFAULT_BASE_URL = \"https://commentary.dev\";\nexport const SESSION_FILE = \".commentary/session.json\";\nexport const PACKAGE_NAME = \"@commentary-dev/cli\";\nexport const CLIENT_ID = \"commentary-cli\";\nexport const CLIENT_NAME = \"Commentary CLI\";\n\nexport const REQUIRED_SCOPES = [\n \"commentary.review.read\",\n \"commentary.comments.read\",\n \"commentary.comments.write\",\n \"commentary.comments.status\",\n] as const;\n\nexport const SUPPORTED_EXTENSIONS = [\".md\", \".markdown\", \".mdx\", \".html\", \".htm\", \".txt\"] as const;\nexport const DEFAULT_IGNORES = [\n \"**/.git/**\",\n \"**/node_modules/**\",\n \"**/dist/**\",\n \"**/build/**\",\n \"**/.next/**\",\n \"**/.nuxt/**\",\n \"**/coverage/**\",\n \"**/.commentary/**\",\n \"**/.DS_Store\",\n] as const;\n\nexport const DRAFT_REVIEW_MAX_FILES = 20;\nexport const DRAFT_REVIEW_MAX_FILE_BYTES = 512 * 1024;\nexport const DRAFT_REVIEW_MAX_TOTAL_BYTES = 2 * 1024 * 1024;\n","import fs from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { DEFAULT_BASE_URL } from \"./constants.js\";\n\ntype StoredToken = {\n accessToken: string;\n refreshToken?: string;\n expiresAt?: string;\n};\n\ntype StoredConfig = {\n tokens?: Record<string, StoredToken>;\n};\n\nfunction configDir() {\n if (process.env.COMMENTARY_CONFIG_DIR) {\n return process.env.COMMENTARY_CONFIG_DIR;\n }\n if (process.platform === \"win32\" && process.env.APPDATA) {\n return path.join(process.env.APPDATA, \"commentary\");\n }\n if (process.env.XDG_CONFIG_HOME) {\n return path.join(process.env.XDG_CONFIG_HOME, \"commentary\");\n }\n return path.join(os.homedir(), \".config\", \"commentary\");\n}\n\nexport function configPath() {\n return path.join(configDir(), \"config.json\");\n}\n\nasync function readConfig(): Promise<StoredConfig> {\n try {\n return JSON.parse(await fs.readFile(configPath(), \"utf8\")) as StoredConfig;\n } catch {\n return {};\n }\n}\n\nasync function writeConfig(config: StoredConfig) {\n await fs.mkdir(configDir(), { recursive: true, mode: 0o700 });\n await fs.writeFile(configPath(), `${JSON.stringify(config, null, 2)}\\n`, {\n encoding: \"utf8\",\n mode: 0o600,\n });\n}\n\nexport function normalizeBaseUrl(baseUrl: string | undefined | null) {\n const value = baseUrl?.trim() || process.env.COMMENTARY_BASE_URL || DEFAULT_BASE_URL;\n const url = new URL(value);\n url.hash = \"\";\n url.search = \"\";\n return url.toString().replace(/\\/$/, \"\");\n}\n\nexport async function getStoredToken(baseUrl: string) {\n const config = await readConfig();\n return config.tokens?.[normalizeBaseUrl(baseUrl)] ?? null;\n}\n\nexport async function setStoredToken(baseUrl: string, token: StoredToken) {\n const config = await readConfig();\n config.tokens ??= {};\n config.tokens[normalizeBaseUrl(baseUrl)] = token;\n await writeConfig(config);\n}\n\nexport async function removeStoredToken(baseUrl: string) {\n const config = await readConfig();\n if (config.tokens) {\n delete config.tokens[normalizeBaseUrl(baseUrl)];\n }\n await writeConfig(config);\n}\n\nexport async function resolveToken(input: { baseUrl: string; token?: string | null | undefined }) {\n if (input.token?.trim()) {\n return input.token.trim();\n }\n if (process.env.COMMENTARY_TOKEN?.trim()) {\n return process.env.COMMENTARY_TOKEN.trim();\n }\n const stored = await getStoredToken(input.baseUrl);\n return stored?.accessToken ?? null;\n}\n","import path from \"node:path\";\nimport { CliError, ExitCode } from \"./errors.js\";\nimport type { DraftContentType, RequestedContentType } from \"./types.js\";\n\nconst MARKDOWN_EXTENSIONS = new Set([\".md\", \".markdown\", \".mdx\"]);\nconst HTML_EXTENSIONS = new Set([\".html\", \".htm\"]);\nconst PLAIN_EXTENSIONS = new Set([\".txt\"]);\nconst SUPPORTED_EXTENSIONS = new Set([\n ...MARKDOWN_EXTENSIONS,\n ...HTML_EXTENSIONS,\n ...PLAIN_EXTENSIONS,\n]);\n\nexport function normalizeSlashes(value: string) {\n return value.replaceAll(\"\\\\\", \"/\");\n}\n\nexport function normalizeReviewPath(filePath: string) {\n const normalized = normalizeSlashes(filePath).trim().replace(/^\\/+/, \"\");\n if (!normalized) {\n throw new CliError(\"Draft review file path is required.\", ExitCode.Usage);\n }\n if (\n /^[a-z]:\\//iu.test(normalized) ||\n filePath.trim().startsWith(\"/\") ||\n filePath.trim().startsWith(\"\\\\\")\n ) {\n throw new CliError(\"Draft review file paths must be relative.\", ExitCode.Usage);\n }\n if (normalized.split(\"/\").some((segment) => !segment || segment === \".\" || segment === \"..\")) {\n throw new CliError(\n \"Draft review file paths must not contain empty, current, or parent directory segments.\",\n ExitCode.Usage,\n );\n }\n return normalized;\n}\n\nexport function getPathExtension(filePath: string) {\n return path.posix.extname(normalizeSlashes(filePath)).toLowerCase();\n}\n\nexport function isSupportedPath(filePath: string) {\n return SUPPORTED_EXTENSIONS.has(getPathExtension(filePath));\n}\n\nexport function isLikelyHtml(content: string) {\n const trimmed = content.trimStart().toLowerCase();\n return (\n trimmed.startsWith(\"<!doctype html\") ||\n trimmed.startsWith(\"<html\") ||\n /<(head|body|main|article|section|div|p|h[1-6]|table|ul|ol)\\b[^>]*>[\\s\\S]*<\\/\\1>/iu.test(\n content,\n )\n );\n}\n\nexport function contentTypeFromPath(filePath: string): DraftContentType | null {\n const extension = getPathExtension(filePath);\n if (MARKDOWN_EXTENSIONS.has(extension)) {\n return \"markdown\";\n }\n if (HTML_EXTENSIONS.has(extension)) {\n return \"html\";\n }\n if (PLAIN_EXTENSIONS.has(extension)) {\n return \"plain_text\";\n }\n return null;\n}\n\nexport function detectContentType(input: {\n filePath: string;\n content: string;\n requested?: RequestedContentType | undefined;\n}): DraftContentType {\n const requested = input.requested ?? \"auto\";\n if (requested !== \"auto\") {\n if (![\"markdown\", \"html\", \"plain_text\"].includes(requested)) {\n throw new CliError(\"Choose a supported draft content type.\", ExitCode.Usage);\n }\n return requested;\n }\n\n const fromPath = contentTypeFromPath(input.filePath);\n if (fromPath) {\n return fromPath;\n }\n return isLikelyHtml(input.content) ? \"html\" : \"markdown\";\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport fg from \"fast-glob\";\nimport {\n DEFAULT_IGNORES,\n DRAFT_REVIEW_MAX_FILE_BYTES,\n DRAFT_REVIEW_MAX_FILES,\n DRAFT_REVIEW_MAX_TOTAL_BYTES,\n SUPPORTED_EXTENSIONS,\n} from \"./constants.js\";\nimport {\n detectContentType,\n isSupportedPath,\n normalizeReviewPath,\n normalizeSlashes,\n} from \"./content.js\";\nimport { CliError, ExitCode } from \"./errors.js\";\nimport { contentHash } from \"./hash.js\";\nimport type { DraftFileInput, RequestedContentType, TrackedFile } from \"./types.js\";\n\nexport type CollectOptions = {\n root: string;\n include?: string[] | undefined;\n exclude?: string[] | undefined;\n requestedContentType?: RequestedContentType | undefined;\n};\n\nexport type CollectedFile = DraftFileInput & {\n absolutePath: string;\n contentHash: string;\n sizeBytes: number;\n};\n\nfunction toPosixRelative(root: string, absolutePath: string) {\n const relative = path.relative(root, absolutePath);\n if (!relative || relative.startsWith(\"..\") || path.isAbsolute(relative)) {\n throw new CliError(`Path is outside the review root: ${absolutePath}`, ExitCode.Usage);\n }\n return normalizeReviewPath(relative);\n}\n\nasync function readUtf8File(absolutePath: string) {\n const bytes = await fs.readFile(absolutePath);\n const content = bytes.toString(\"utf8\");\n if (content.includes(\"\\u0000\")) {\n throw new CliError(\n `File must be UTF-8 text, not binary content: ${absolutePath}`,\n ExitCode.Usage,\n );\n }\n return content;\n}\n\nasync function collectPathEntries(inputPaths: string[], options: CollectOptions) {\n const root = path.resolve(options.root);\n const entries = new Set<string>();\n const includeExtensions = SUPPORTED_EXTENSIONS.map((extension) => extension.replace(\".\", \"\"));\n\n for (const inputPath of inputPaths) {\n const absolute = path.resolve(root, inputPath);\n let stat;\n try {\n stat = await fs.stat(absolute);\n } catch {\n throw new CliError(`Path does not exist: ${inputPath}`, ExitCode.Usage);\n }\n\n if (stat.isDirectory()) {\n const relativeDir = normalizeSlashes(path.relative(root, absolute)) || \".\";\n const patterns = options.include?.length\n ? options.include.map((pattern) => normalizeSlashes(path.posix.join(relativeDir, pattern)))\n : [`${relativeDir === \".\" ? \"\" : `${relativeDir}/`}**/*.{${includeExtensions.join(\",\")}}`];\n const matches = await fg(patterns, {\n cwd: root,\n onlyFiles: true,\n dot: false,\n ignore: [...DEFAULT_IGNORES, ...(options.exclude ?? [])],\n });\n matches.forEach((match) => entries.add(path.resolve(root, match)));\n continue;\n }\n\n if (stat.isFile()) {\n if (!isSupportedPath(absolute)) {\n throw new CliError(`Unsupported file type: ${inputPath}`, ExitCode.Usage);\n }\n entries.add(absolute);\n }\n }\n\n return [...entries].sort((left, right) => left.localeCompare(right));\n}\n\nexport async function collectFiles(\n inputPaths: string[],\n options: CollectOptions,\n): Promise<CollectedFile[]> {\n if (inputPaths.length === 0) {\n throw new CliError(\"At least one path is required.\", ExitCode.Usage);\n }\n\n const root = path.resolve(options.root);\n const absolutePaths = await collectPathEntries(inputPaths, options);\n if (absolutePaths.length === 0) {\n throw new CliError(\"No supported files were found.\", ExitCode.Usage);\n }\n if (absolutePaths.length > DRAFT_REVIEW_MAX_FILES) {\n throw new CliError(\n `Draft reviews support up to ${DRAFT_REVIEW_MAX_FILES} files per revision.`,\n ExitCode.Usage,\n );\n }\n\n let totalBytes = 0;\n const collected: CollectedFile[] = [];\n for (const absolutePath of absolutePaths) {\n const content = await readUtf8File(absolutePath);\n const sizeBytes = Buffer.byteLength(content);\n if (sizeBytes > DRAFT_REVIEW_MAX_FILE_BYTES) {\n throw new CliError(\n `Draft review file exceeds ${DRAFT_REVIEW_MAX_FILE_BYTES} bytes: ${absolutePath}`,\n ExitCode.Usage,\n );\n }\n totalBytes += sizeBytes;\n if (totalBytes > DRAFT_REVIEW_MAX_TOTAL_BYTES) {\n throw new CliError(\n `Draft review revisions support up to ${DRAFT_REVIEW_MAX_TOTAL_BYTES} total bytes.`,\n ExitCode.Usage,\n );\n }\n const reviewPath = toPosixRelative(root, absolutePath);\n const contentType = detectContentType({\n filePath: reviewPath,\n content,\n requested: options.requestedContentType,\n });\n collected.push({\n absolutePath,\n path: reviewPath,\n content,\n contentType,\n contentHash: contentHash(content),\n sizeBytes,\n });\n }\n\n return collected;\n}\n\nexport async function readTrackedFiles(\n root: string,\n trackedFiles: TrackedFile[],\n): Promise<CollectedFile[]> {\n const collected: CollectedFile[] = [];\n for (const tracked of trackedFiles) {\n const absolutePath = path.resolve(root, tracked.path);\n const content = await readUtf8File(absolutePath);\n const sizeBytes = Buffer.byteLength(content);\n collected.push({\n absolutePath,\n path: tracked.path,\n fileId: tracked.fileId,\n content,\n contentType: tracked.contentType,\n contentHash: contentHash(content),\n sizeBytes,\n });\n }\n return collected;\n}\n\nexport function toTrackedFiles(\n files: CollectedFile[],\n apiFiles?: Array<{\n fileId: string;\n path: string;\n contentHash: string;\n sizeBytes: number;\n contentType: string;\n }>,\n): TrackedFile[] {\n const apiByPath = new Map(apiFiles?.map((file) => [file.path, file]) ?? []);\n return files.map((file) => {\n const apiFile = apiByPath.get(file.path);\n return {\n path: file.path,\n fileId: apiFile?.fileId ?? file.fileId,\n contentType: file.contentType,\n contentHash: apiFile?.contentHash ?? file.contentHash,\n sizeBytes: apiFile?.sizeBytes ?? file.sizeBytes,\n };\n });\n}\n","import { createHash } from \"node:crypto\";\n\nexport function contentHash(content: string) {\n return createHash(\"sha256\").update(content).digest(\"hex\");\n}\n","import type {\n DraftReviewLiveEvent,\n DraftReviewRevision,\n DraftReviewSession,\n DraftThread,\n JsonObject,\n SessionMetadata,\n} from \"./types.js\";\n\nexport type Writer = {\n write(chunk: string): void;\n};\n\nexport function writeJson(stdout: Writer, value: unknown) {\n stdout.write(`${JSON.stringify(value, null, 2)}\\n`);\n}\n\nexport function writeText(stdout: Writer, value: string) {\n stdout.write(`${value.trimEnd()}\\n`);\n}\n\nexport function formatReviewCreated(input: {\n draftReview: DraftReviewSession;\n sessionFilePath: string;\n fileCount: number;\n}) {\n return [\n \"Created Commentary review\",\n \"\",\n `Title: ${input.draftReview.title}`,\n `Files: ${input.fileCount}`,\n `Session: ${input.draftReview.id}`,\n `URL: ${input.draftReview.reviewUrl}`,\n \"\",\n `Saved local session metadata to ${input.sessionFilePath}`,\n ].join(\"\\n\");\n}\n\nexport function formatRevision(input: {\n metadata: SessionMetadata;\n revision: DraftReviewRevision;\n uploaded: number;\n noOp?: boolean | undefined;\n}) {\n return [\n input.noOp ? \"No changes to sync\" : \"Synced Commentary review\",\n \"\",\n `Session: ${input.metadata.reviewSessionId}`,\n `Revision: ${input.revision.revisionNumber}`,\n `Files uploaded: ${input.uploaded}`,\n `URL: ${input.metadata.reviewUrl}`,\n ].join(\"\\n\");\n}\n\nfunction commentBody(thread: DraftThread) {\n const first = thread.comments[0];\n return first?.bodyMarkdown ?? first?.body ?? \"\";\n}\n\nfunction commentAuthor(thread: DraftThread) {\n const first = thread.comments[0];\n return first?.agentAlias ?? first?.authorLogin ?? first?.author ?? \"Unknown\";\n}\n\nexport function formatCommentsText(threads: DraftThread[]) {\n if (threads.length === 0) {\n return \"No comments found.\";\n }\n return threads\n .map((thread) =>\n [\n `[${thread.id}] ${thread.filePath}`,\n `Status: ${thread.status}`,\n thread.selectedText ? `Anchor: \"${thread.selectedText}\"` : null,\n `${commentAuthor(thread)}: ${commentBody(thread)}`,\n ]\n .filter(Boolean)\n .join(\"\\n\"),\n )\n .join(\"\\n\\n\");\n}\n\nexport function formatCommentsMarkdown(input: {\n session: SessionMetadata;\n threads: DraftThread[];\n}) {\n const lines = [\n \"# Commentary Review Comments\",\n \"\",\n `Session: ${input.session.reviewSessionId}`,\n `URL: ${input.session.reviewUrl}`,\n \"\",\n ];\n if (input.threads.length === 0) {\n lines.push(\"No comments found.\");\n return lines.join(\"\\n\");\n }\n for (const thread of input.threads) {\n lines.push(`## Comment ${thread.id}`, \"\");\n lines.push(`File: ${thread.filePath}`);\n lines.push(`Status: ${thread.status}`);\n if (thread.selectedText) {\n lines.push(`Anchor: \"${thread.selectedText}\"`);\n }\n if (thread.sourceLineStart) {\n lines.push(\n `Lines: ${thread.sourceLineStart}${thread.sourceLineEnd && thread.sourceLineEnd !== thread.sourceLineStart ? `-${thread.sourceLineEnd}` : \"\"}`,\n );\n }\n lines.push(\"\", \"User comment:\", `> ${commentBody(thread).replace(/\\n/g, \"\\n> \")}`, \"\");\n const replies = thread.comments.slice(1);\n if (replies.length > 0) {\n lines.push(\"Replies:\");\n replies.forEach((reply) => {\n lines.push(\n `- ${reply.agentAlias ?? reply.authorLogin ?? reply.author ?? \"Unknown\"}: ${reply.bodyMarkdown ?? reply.body ?? \"\"}`,\n );\n });\n lines.push(\"\");\n }\n }\n return lines.join(\"\\n\").trimEnd();\n}\n\nexport function formatWaitCommentText(event: DraftReviewLiveEvent) {\n if (!event.thread) {\n return `Received ${event.type} (${event.id}).`;\n }\n const thread = event.thread;\n const body = commentBody(thread);\n return [\n `[${thread.id}] ${thread.filePath}`,\n `Event: ${event.type}`,\n `Status: ${thread.status}`,\n thread.selectedText ? `Anchor: \"${thread.selectedText}\"` : null,\n `${commentAuthor(thread)}: ${body}`,\n ]\n .filter(Boolean)\n .join(\"\\n\");\n}\n\nexport function formatWaitCommentMarkdown(input: {\n session: SessionMetadata;\n event: DraftReviewLiveEvent;\n}) {\n const lines = [\n \"# Commentary Comment\",\n \"\",\n `Session: ${input.session.reviewSessionId}`,\n `URL: ${input.session.reviewUrl}`,\n `Event: ${input.event.type}`,\n `Cursor: ${input.event.id}`,\n \"\",\n ];\n if (!input.event.thread) {\n lines.push(\"No thread payload was available for this event.\");\n return lines.join(\"\\n\");\n }\n lines.push(formatCommentsMarkdown({ session: input.session, threads: [input.event.thread] }));\n return lines.join(\"\\n\").trimEnd();\n}\n\nexport function publicSessionJson(metadata: SessionMetadata): JsonObject {\n return {\n reviewSessionId: metadata.reviewSessionId,\n reviewUrl: metadata.reviewUrl,\n baseUrl: metadata.baseUrl,\n rootPath: metadata.rootPath,\n trackedFiles: metadata.trackedFiles,\n createdAt: metadata.createdAt,\n lastSyncedAt: metadata.lastSyncedAt,\n lastKnownRevision: metadata.lastKnownRevision,\n };\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { SESSION_FILE } from \"./constants.js\";\nimport { CliError, ExitCode } from \"./errors.js\";\nimport type { SessionMetadata } from \"./types.js\";\n\nasync function pathExists(filePath: string) {\n try {\n await fs.access(filePath);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function findSessionFile(startDir: string, explicitPath?: string) {\n if (explicitPath) {\n return path.resolve(startDir, explicitPath);\n }\n\n let current = path.resolve(startDir);\n while (true) {\n const candidate = path.join(current, SESSION_FILE);\n if (await pathExists(candidate)) {\n return candidate;\n }\n const parent = path.dirname(current);\n if (parent === current) {\n return path.resolve(startDir, SESSION_FILE);\n }\n current = parent;\n }\n}\n\nexport async function loadSessionMetadata(startDir: string, explicitPath?: string) {\n const filePath = await findSessionFile(startDir, explicitPath);\n let raw;\n try {\n raw = await fs.readFile(filePath, \"utf8\");\n } catch {\n throw new CliError(\n `No Commentary session metadata found at ${filePath}. Run commentary review first.`,\n ExitCode.Usage,\n );\n }\n\n const metadata = JSON.parse(raw) as SessionMetadata;\n return {\n filePath,\n metadata,\n };\n}\n\nexport async function saveSessionMetadata(filePath: string, metadata: SessionMetadata) {\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n await fs.writeFile(filePath, `${JSON.stringify(metadata, null, 2)}\\n`, {\n encoding: \"utf8\",\n mode: 0o644,\n });\n}\n\nexport function sessionRoot(sessionFilePath: string, metadata: SessionMetadata) {\n return path.resolve(path.dirname(sessionFilePath), metadata.rootPath);\n}\n","#!/usr/bin/env node\nimport { runCli } from \"./cli.js\";\n\nconst exitCode = await runCli();\nif (exitCode !== 0) {\n process.exitCode = exitCode;\n}\n"],"mappings":"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","names":["fs","path","exitCode","path","SUPPORTED_EXTENSIONS","path","fs","path","path","fs","fs","path","fs","path","path","fs"]}
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@commentary-dev/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Command-line companion for Commentary draft review sessions.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
|
-
"commentary": "
|
|
8
|
+
"commentary": "dist/index.js"
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"dist",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
},
|
|
49
49
|
"repository": {
|
|
50
50
|
"type": "git",
|
|
51
|
-
"url": "https://github.com/commentary-dev/commentary-cli.git"
|
|
51
|
+
"url": "git+https://github.com/commentary-dev/commentary-cli.git"
|
|
52
52
|
},
|
|
53
53
|
"publishConfig": {
|
|
54
54
|
"access": "public",
|