@slock-ai/daemon 0.42.0 → 0.44.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chat-bridge.js +1 -1
- package/dist/{chunk-RNEIFBXW.js → chunk-NM2MFLQ7.js} +959 -114
- package/dist/cli/index.js +269 -53
- package/dist/core.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -1049,7 +1049,7 @@ function formatClaimResults(channel, data) {
|
|
|
1049
1049
|
const msgShort = r.messageId ? r.messageId.slice(0, 8) : "";
|
|
1050
1050
|
return `${label} (msg:${msgShort}): claimed`;
|
|
1051
1051
|
}
|
|
1052
|
-
return `${label}: FAILED \u2014 ${r.reason || "already claimed"}
|
|
1052
|
+
return `${label}: FAILED \u2014 ${r.reason || "already claimed"}. Do not reply.`;
|
|
1053
1053
|
});
|
|
1054
1054
|
const succeeded = data.results.filter((r) => r.success).length;
|
|
1055
1055
|
const failed = data.results.length - succeeded;
|
|
@@ -1397,7 +1397,8 @@ var RUNTIMES = [
|
|
|
1397
1397
|
{ id: "kimi", displayName: "Kimi CLI", binary: "kimi", supported: true },
|
|
1398
1398
|
{ id: "copilot", displayName: "Copilot CLI", binary: "copilot", supported: true },
|
|
1399
1399
|
{ id: "cursor", displayName: "Cursor CLI", binary: "cursor-agent", supported: true },
|
|
1400
|
-
{ id: "gemini", displayName: "Gemini CLI", binary: "gemini", supported: true }
|
|
1400
|
+
{ id: "gemini", displayName: "Gemini CLI", binary: "gemini", supported: true },
|
|
1401
|
+
{ id: "opencode", displayName: "OpenCode", binary: "opencode", supported: true }
|
|
1401
1402
|
];
|
|
1402
1403
|
function getRuntimeDisplayName(id) {
|
|
1403
1404
|
return RUNTIMES.find((r) => r.id === id)?.displayName ?? id;
|
|
@@ -1552,6 +1553,8 @@ var FILENAME_MIME_MAP2 = {
|
|
|
1552
1553
|
".gif": "image/gif",
|
|
1553
1554
|
".webp": "image/webp"
|
|
1554
1555
|
};
|
|
1556
|
+
var MAX_PROFILE_DESCRIPTION_LENGTH = 3e3;
|
|
1557
|
+
var MAX_PROFILE_DISPLAY_NAME_LENGTH = 80;
|
|
1555
1558
|
function inferImageMimeType(filename, buffer) {
|
|
1556
1559
|
const lowerFilename = filename.toLowerCase();
|
|
1557
1560
|
if (buffer.length >= 8 && buffer.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))) {
|
|
@@ -1596,7 +1599,7 @@ function readAvatarFile(avatarFile) {
|
|
|
1596
1599
|
return { filename, buffer, mimeType };
|
|
1597
1600
|
}
|
|
1598
1601
|
function registerProfileUpdateCommand(parent) {
|
|
1599
|
-
parent.command("update").description("Update your own profile").
|
|
1602
|
+
parent.command("update").description("Update your own profile").option("--avatar-file <path>", "Path to a local image file to use as your avatar").option("--display-name <name>", "Set your display name (non-empty)").option("--description <text>", "Set your profile description (non-empty)").option("--json", "Emit machine-readable JSON").action(async (opts) => {
|
|
1600
1603
|
let ctx;
|
|
1601
1604
|
try {
|
|
1602
1605
|
ctx = loadAgentContext();
|
|
@@ -1604,47 +1607,92 @@ function registerProfileUpdateCommand(parent) {
|
|
|
1604
1607
|
if (err instanceof AgentBootstrapError) fail(err.code, err.message);
|
|
1605
1608
|
throw err;
|
|
1606
1609
|
}
|
|
1607
|
-
|
|
1608
|
-
|
|
1610
|
+
const hasAvatar = opts.avatarFile !== void 0;
|
|
1611
|
+
const hasDisplayName = opts.displayName !== void 0;
|
|
1612
|
+
const hasDescription = opts.description !== void 0;
|
|
1613
|
+
if (!hasAvatar && !hasDisplayName && !hasDescription) {
|
|
1614
|
+
fail("INVALID_ARG", "Provide at least one of --avatar-file, --display-name, or --description");
|
|
1615
|
+
}
|
|
1616
|
+
let trimmedDisplayName;
|
|
1617
|
+
if (hasDisplayName) {
|
|
1618
|
+
trimmedDisplayName = opts.displayName.trim();
|
|
1619
|
+
if (trimmedDisplayName.length === 0) {
|
|
1620
|
+
fail("INVALID_ARG", "--display-name must not be empty");
|
|
1621
|
+
}
|
|
1622
|
+
if (trimmedDisplayName.length > MAX_PROFILE_DISPLAY_NAME_LENGTH) {
|
|
1623
|
+
fail("INVALID_ARG", `--display-name must be at most ${MAX_PROFILE_DISPLAY_NAME_LENGTH} characters`);
|
|
1624
|
+
}
|
|
1625
|
+
}
|
|
1626
|
+
if (hasDescription) {
|
|
1627
|
+
if (opts.description.length === 0) {
|
|
1628
|
+
fail("INVALID_ARG", "--description must not be empty");
|
|
1629
|
+
}
|
|
1630
|
+
if (opts.description.length > MAX_PROFILE_DESCRIPTION_LENGTH) {
|
|
1631
|
+
fail("INVALID_ARG", `--description must be at most ${MAX_PROFILE_DESCRIPTION_LENGTH} characters`);
|
|
1632
|
+
}
|
|
1609
1633
|
}
|
|
1610
|
-
const avatar = readAvatarFile(opts.avatarFile);
|
|
1611
|
-
const form = new FormData();
|
|
1612
|
-
const avatarBytes = Uint8Array.from(avatar.buffer);
|
|
1613
|
-
form.append("avatar", new Blob([avatarBytes], { type: avatar.mimeType }), avatar.filename);
|
|
1614
1634
|
const client = new ApiClient(ctx);
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1635
|
+
let latestProfile = null;
|
|
1636
|
+
if (hasDisplayName || hasDescription) {
|
|
1637
|
+
const body = {};
|
|
1638
|
+
if (hasDisplayName) {
|
|
1639
|
+
body.displayName = trimmedDisplayName;
|
|
1640
|
+
}
|
|
1641
|
+
if (hasDescription) {
|
|
1642
|
+
body.description = opts.description;
|
|
1643
|
+
}
|
|
1644
|
+
const res = await client.request(
|
|
1645
|
+
"POST",
|
|
1646
|
+
`/internal/agent/${encodeURIComponent(ctx.agentId)}/profile`,
|
|
1647
|
+
body
|
|
1648
|
+
);
|
|
1649
|
+
if (!res.ok || !res.data) {
|
|
1650
|
+
const code = res.errorCode ?? (res.status >= 500 ? "SERVER_5XX" : "PROFILE_UPDATE_FAILED");
|
|
1651
|
+
fail(code, res.error ?? `HTTP ${res.status}`);
|
|
1652
|
+
}
|
|
1653
|
+
latestProfile = res.data;
|
|
1654
|
+
}
|
|
1655
|
+
if (hasAvatar) {
|
|
1656
|
+
const avatar = readAvatarFile(opts.avatarFile);
|
|
1657
|
+
const form = new FormData();
|
|
1658
|
+
const avatarBytes = Uint8Array.from(avatar.buffer);
|
|
1659
|
+
form.append("avatar", new Blob([avatarBytes], { type: avatar.mimeType }), avatar.filename);
|
|
1660
|
+
const res = await client.requestMultipart(
|
|
1661
|
+
"POST",
|
|
1662
|
+
`/internal/agent/${encodeURIComponent(ctx.agentId)}/profile/avatar`,
|
|
1663
|
+
form
|
|
1664
|
+
);
|
|
1665
|
+
if (!res.ok || !res.data) {
|
|
1666
|
+
const code = res.errorCode ?? (res.status >= 500 ? "SERVER_5XX" : "PROFILE_UPDATE_FAILED");
|
|
1667
|
+
fail(code, res.error ?? `HTTP ${res.status}`);
|
|
1668
|
+
}
|
|
1669
|
+
latestProfile = res.data;
|
|
1670
|
+
}
|
|
1671
|
+
if (!latestProfile) {
|
|
1672
|
+
fail("PROFILE_UPDATE_FAILED", "No profile returned from server");
|
|
1623
1673
|
}
|
|
1624
1674
|
if (opts.json) {
|
|
1625
|
-
emit({ ok: true, data:
|
|
1675
|
+
emit({ ok: true, data: latestProfile });
|
|
1626
1676
|
return;
|
|
1627
1677
|
}
|
|
1628
|
-
process.stdout.write(`${formatProfile(
|
|
1678
|
+
process.stdout.write(`${formatProfile(latestProfile)}
|
|
1629
1679
|
`);
|
|
1630
1680
|
});
|
|
1631
1681
|
}
|
|
1632
1682
|
|
|
1633
1683
|
// src/commands/reminder/_format.ts
|
|
1634
|
-
|
|
1635
|
-
const d = new Date(iso);
|
|
1636
|
-
if (isNaN(d.getTime())) return iso;
|
|
1637
|
-
const pad = (n) => String(n).padStart(2, "0");
|
|
1638
|
-
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
|
|
1639
|
-
}
|
|
1684
|
+
var MODIFY_HINT = "(to modify: snooze/update/cancel; slock reminder --help)";
|
|
1640
1685
|
function formatReminder(r) {
|
|
1641
|
-
const fireLocal = toLocalTime2(r.fireAt);
|
|
1642
1686
|
const ref = r.msgRef ? ` ref=${r.msgRef}` : "";
|
|
1643
|
-
const
|
|
1644
|
-
return `#${r.reminderId.slice(0, 8)} [${r.status}]
|
|
1687
|
+
const timeField = r.status === "fired" ? `fired_at=${r.firedAt ?? r.fireAt}` : `next=${r.fireAt}`;
|
|
1688
|
+
return `#${r.reminderId.slice(0, 8)} [${r.status}] ${formatReminderType(r)} ${timeField} "${r.title}"${ref}`;
|
|
1645
1689
|
}
|
|
1646
1690
|
function formatReminderScheduled(r, warning) {
|
|
1647
|
-
const lines = [
|
|
1691
|
+
const lines = [
|
|
1692
|
+
`Reminder scheduled: #${r.reminderId.slice(0, 8)} ${formatReminderType(r)} "${r.title}"`,
|
|
1693
|
+
`Next: ${r.fireAt}`,
|
|
1694
|
+
MODIFY_HINT
|
|
1695
|
+
];
|
|
1648
1696
|
if (warning) lines.push(`Warning: ${warning}`);
|
|
1649
1697
|
return lines.join("\n");
|
|
1650
1698
|
}
|
|
@@ -1653,7 +1701,34 @@ function formatReminderList(reminders) {
|
|
|
1653
1701
|
return reminders.map(formatReminder).join("\n");
|
|
1654
1702
|
}
|
|
1655
1703
|
function formatReminderCanceled(r) {
|
|
1656
|
-
return `Reminder canceled:
|
|
1704
|
+
return `Reminder canceled: #${r.reminderId.slice(0, 8)} [${r.status}] "${r.title}"`;
|
|
1705
|
+
}
|
|
1706
|
+
function formatReminderSnoozed(r) {
|
|
1707
|
+
return [
|
|
1708
|
+
`Reminder snoozed: #${r.reminderId.slice(0, 8)} ${formatReminderType(r)} "${r.title}"`,
|
|
1709
|
+
`Next: ${r.fireAt}`,
|
|
1710
|
+
MODIFY_HINT
|
|
1711
|
+
].join("\n");
|
|
1712
|
+
}
|
|
1713
|
+
function formatReminderUpdated(r, warning) {
|
|
1714
|
+
const lines = [
|
|
1715
|
+
`Reminder updated: #${r.reminderId.slice(0, 8)} ${formatReminderType(r)} "${r.title}"`,
|
|
1716
|
+
`Next: ${r.fireAt}`,
|
|
1717
|
+
MODIFY_HINT
|
|
1718
|
+
];
|
|
1719
|
+
if (warning) lines.push(`Warning: ${warning}`);
|
|
1720
|
+
return lines.join("\n");
|
|
1721
|
+
}
|
|
1722
|
+
function formatReminderLog(events) {
|
|
1723
|
+
if (events.length === 0) return "No reminder events.";
|
|
1724
|
+
return events.map((event) => {
|
|
1725
|
+
const next = event.nextFireAt ? ` next=${event.nextFireAt}` : " next=none";
|
|
1726
|
+
return `${event.occurredAt} ${event.eventType.toUpperCase()} by ${event.actorType}${event.actorId ? `:${event.actorId}` : ""}${next}`;
|
|
1727
|
+
}).join("\n");
|
|
1728
|
+
}
|
|
1729
|
+
function formatReminderType(r) {
|
|
1730
|
+
if (!r.recurrence) return "(one-time)";
|
|
1731
|
+
return `(recurring \xB7 ${r.recurrence.description})`;
|
|
1657
1732
|
}
|
|
1658
1733
|
|
|
1659
1734
|
// src/commands/reminder/schedule.ts
|
|
@@ -1749,9 +1824,9 @@ function registerReminderScheduleCommand(parent) {
|
|
|
1749
1824
|
// src/commands/reminder/list.ts
|
|
1750
1825
|
var VALID_STATUSES2 = /* @__PURE__ */ new Set(["scheduled", "fired", "canceled"]);
|
|
1751
1826
|
function registerReminderListCommand(parent) {
|
|
1752
|
-
parent.command("list").description("List your own reminders (defaults to scheduled)").option(
|
|
1827
|
+
parent.command("list").description("List your own reminders (defaults to scheduled and fired)").option("--all", "Include canceled reminders").option(
|
|
1753
1828
|
"--status <s>",
|
|
1754
|
-
"Comma-separated statuses (scheduled,fired,canceled). Default: scheduled"
|
|
1829
|
+
"Comma-separated statuses (scheduled,fired,canceled). Default: scheduled,fired"
|
|
1755
1830
|
).action(async (opts) => {
|
|
1756
1831
|
let ctx;
|
|
1757
1832
|
try {
|
|
@@ -1760,14 +1835,18 @@ function registerReminderListCommand(parent) {
|
|
|
1760
1835
|
if (err instanceof AgentBootstrapError) fail(err.code, err.message);
|
|
1761
1836
|
throw err;
|
|
1762
1837
|
}
|
|
1763
|
-
const statusRaw = opts.status && opts.status.trim().length > 0 ? opts.status.trim() : "scheduled";
|
|
1838
|
+
const statusRaw = opts.status && opts.status.trim().length > 0 ? opts.status.trim() : "scheduled,fired";
|
|
1764
1839
|
for (const s of statusRaw.split(",").map((x) => x.trim()).filter(Boolean)) {
|
|
1765
1840
|
if (!VALID_STATUSES2.has(s)) {
|
|
1766
1841
|
fail("INVALID_ARG", `--status entries must be one of ${Array.from(VALID_STATUSES2).join("|")}; got ${s}`);
|
|
1767
1842
|
}
|
|
1768
1843
|
}
|
|
1769
1844
|
const params = new URLSearchParams();
|
|
1770
|
-
|
|
1845
|
+
if (opts.all && !opts.status) {
|
|
1846
|
+
params.set("all", "true");
|
|
1847
|
+
} else {
|
|
1848
|
+
params.set("status", statusRaw);
|
|
1849
|
+
}
|
|
1771
1850
|
const client = new ApiClient(ctx);
|
|
1772
1851
|
const res = await client.request(
|
|
1773
1852
|
"GET",
|
|
@@ -1781,6 +1860,37 @@ function registerReminderListCommand(parent) {
|
|
|
1781
1860
|
});
|
|
1782
1861
|
}
|
|
1783
1862
|
|
|
1863
|
+
// src/commands/reminder/_resolve.ts
|
|
1864
|
+
async function resolveReminderId(client, agentId, id, opts) {
|
|
1865
|
+
const trimmed = id.trim();
|
|
1866
|
+
if (!trimmed) fail("INVALID_ARG", "--id is required");
|
|
1867
|
+
if (trimmed.length >= 32) return trimmed;
|
|
1868
|
+
const params = new URLSearchParams();
|
|
1869
|
+
if (opts.all) {
|
|
1870
|
+
params.set("all", "true");
|
|
1871
|
+
} else if (opts.statuses && opts.statuses.length > 0) {
|
|
1872
|
+
params.set("status", opts.statuses.join(","));
|
|
1873
|
+
}
|
|
1874
|
+
const query = params.toString();
|
|
1875
|
+
const res = await client.request(
|
|
1876
|
+
"GET",
|
|
1877
|
+
`/internal/agent/${encodeURIComponent(agentId)}/reminders${query ? `?${query}` : ""}`
|
|
1878
|
+
);
|
|
1879
|
+
if (!res.ok) {
|
|
1880
|
+
const code = res.status >= 500 ? "SERVER_5XX" : opts.failureCode;
|
|
1881
|
+
fail(code, res.error ?? `HTTP ${res.status}`);
|
|
1882
|
+
}
|
|
1883
|
+
const matches = (res.data?.reminders ?? []).filter((r) => r.reminderId.startsWith(trimmed));
|
|
1884
|
+
if (matches.length === 0) {
|
|
1885
|
+
const scope = opts.all ? "reminder" : `${opts.statuses?.join("/") ?? "active"} reminder`;
|
|
1886
|
+
fail("NOT_FOUND", `No ${scope} matches id prefix '${trimmed}'.`);
|
|
1887
|
+
}
|
|
1888
|
+
if (matches.length > 1) {
|
|
1889
|
+
fail("AMBIGUOUS", `Ambiguous id prefix '${trimmed}' matches ${matches.length} reminders; pass a longer id.`);
|
|
1890
|
+
}
|
|
1891
|
+
return matches[0].reminderId;
|
|
1892
|
+
}
|
|
1893
|
+
|
|
1784
1894
|
// src/commands/reminder/cancel.ts
|
|
1785
1895
|
function registerReminderCancelCommand(parent) {
|
|
1786
1896
|
parent.command("cancel").description("Cancel a scheduled reminder by id (full uuid or 8-char prefix)").requiredOption("--id <id>", "Reminder id (full uuid or short prefix)").action(async (opts) => {
|
|
@@ -1795,25 +1905,10 @@ function registerReminderCancelCommand(parent) {
|
|
|
1795
1905
|
fail("INVALID_ARG", "--id is required");
|
|
1796
1906
|
}
|
|
1797
1907
|
const client = new ApiClient(ctx);
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
`/internal/agent/${encodeURIComponent(ctx.agentId)}/reminders?status=scheduled`
|
|
1803
|
-
);
|
|
1804
|
-
if (!listRes.ok) {
|
|
1805
|
-
const code = listRes.status >= 500 ? "SERVER_5XX" : "CANCEL_FAILED";
|
|
1806
|
-
fail(code, listRes.error ?? `HTTP ${listRes.status}`);
|
|
1807
|
-
}
|
|
1808
|
-
const matches = (listRes.data?.reminders ?? []).filter((r) => r.reminderId.startsWith(opts.id));
|
|
1809
|
-
if (matches.length === 0) {
|
|
1810
|
-
fail("NOT_FOUND", `No scheduled reminder matches id prefix '${opts.id}'.`);
|
|
1811
|
-
}
|
|
1812
|
-
if (matches.length > 1) {
|
|
1813
|
-
fail("AMBIGUOUS", `Ambiguous id prefix '${opts.id}' matches ${matches.length} reminders; pass a longer id.`);
|
|
1814
|
-
}
|
|
1815
|
-
fullId = matches[0].reminderId;
|
|
1816
|
-
}
|
|
1908
|
+
const fullId = await resolveReminderId(client, ctx.agentId, opts.id, {
|
|
1909
|
+
statuses: ["scheduled", "fired"],
|
|
1910
|
+
failureCode: "CANCEL_FAILED"
|
|
1911
|
+
});
|
|
1817
1912
|
const res = await client.request(
|
|
1818
1913
|
"DELETE",
|
|
1819
1914
|
`/internal/agent/${encodeURIComponent(ctx.agentId)}/reminders/${encodeURIComponent(fullId)}`
|
|
@@ -1826,6 +1921,124 @@ function registerReminderCancelCommand(parent) {
|
|
|
1826
1921
|
});
|
|
1827
1922
|
}
|
|
1828
1923
|
|
|
1924
|
+
// src/commands/reminder/_duration.ts
|
|
1925
|
+
function parseDurationSeconds(input) {
|
|
1926
|
+
const raw = input.trim();
|
|
1927
|
+
const match = /^(\d+)(s|m|h|d)?$/.exec(raw);
|
|
1928
|
+
if (!match) return null;
|
|
1929
|
+
const value = Number(match[1]);
|
|
1930
|
+
const unit = match[2] ?? "s";
|
|
1931
|
+
const multiplier = unit === "s" ? 1 : unit === "m" ? 60 : unit === "h" ? 3600 : 86400;
|
|
1932
|
+
const seconds = value * multiplier;
|
|
1933
|
+
if (!Number.isSafeInteger(seconds) || seconds <= 0) return null;
|
|
1934
|
+
return seconds;
|
|
1935
|
+
}
|
|
1936
|
+
|
|
1937
|
+
// src/commands/reminder/snooze.ts
|
|
1938
|
+
function registerReminderSnoozeCommand(parent) {
|
|
1939
|
+
parent.command("snooze").description("Snooze a scheduled or fired reminder").requiredOption("--id <id>", "Reminder id (full uuid or short prefix)").requiredOption("--by <duration>", "Snooze duration, e.g. 30m, 2h, 1d").action(async (opts) => {
|
|
1940
|
+
let ctx;
|
|
1941
|
+
try {
|
|
1942
|
+
ctx = loadAgentContext();
|
|
1943
|
+
} catch (err) {
|
|
1944
|
+
if (err instanceof AgentBootstrapError) fail(err.code, err.message);
|
|
1945
|
+
throw err;
|
|
1946
|
+
}
|
|
1947
|
+
const delaySeconds = parseDurationSeconds(opts.by);
|
|
1948
|
+
if (delaySeconds == null) {
|
|
1949
|
+
fail("INVALID_ARG", "--by must be a positive duration like 30m, 2h, or 1d");
|
|
1950
|
+
}
|
|
1951
|
+
const client = new ApiClient(ctx);
|
|
1952
|
+
const fullId = await resolveReminderId(client, ctx.agentId, opts.id, {
|
|
1953
|
+
statuses: ["scheduled", "fired"],
|
|
1954
|
+
failureCode: "SNOOZE_FAILED"
|
|
1955
|
+
});
|
|
1956
|
+
const res = await client.request(
|
|
1957
|
+
"POST",
|
|
1958
|
+
`/internal/agent/${encodeURIComponent(ctx.agentId)}/reminders/${encodeURIComponent(fullId)}/snooze`,
|
|
1959
|
+
{ delaySeconds }
|
|
1960
|
+
);
|
|
1961
|
+
if (!res.ok || !res.data?.reminder) {
|
|
1962
|
+
const code = res.status >= 500 ? "SERVER_5XX" : "SNOOZE_FAILED";
|
|
1963
|
+
fail(code, res.error ?? `HTTP ${res.status}`);
|
|
1964
|
+
}
|
|
1965
|
+
process.stdout.write(formatReminderSnoozed(res.data.reminder) + "\n");
|
|
1966
|
+
});
|
|
1967
|
+
}
|
|
1968
|
+
|
|
1969
|
+
// src/commands/reminder/update.ts
|
|
1970
|
+
function registerReminderUpdateCommand(parent) {
|
|
1971
|
+
parent.command("update").description("Update one field on a scheduled reminder").requiredOption("--id <id>", "Reminder id (full uuid or short prefix)").option("--fire-at <iso>", "New absolute next fire time").option("--in <duration>", "New relative next fire time, e.g. 30m, 2h").option("--cadence <rule>", "New recurrence rule: every:15m | daily@09:00 | weekly:mon,fri@09:00").option("--title <text>", "New reminder title").action(async (opts) => {
|
|
1972
|
+
let ctx;
|
|
1973
|
+
try {
|
|
1974
|
+
ctx = loadAgentContext();
|
|
1975
|
+
} catch (err) {
|
|
1976
|
+
if (err instanceof AgentBootstrapError) fail(err.code, err.message);
|
|
1977
|
+
throw err;
|
|
1978
|
+
}
|
|
1979
|
+
const mutationCount = [opts.fireAt, opts.in, opts.cadence, opts.title].filter((x) => x !== void 0 && x !== null).length;
|
|
1980
|
+
if (mutationCount !== 1) {
|
|
1981
|
+
fail("INVALID_ARG", "Pass exactly one of --fire-at, --in, --cadence, or --title");
|
|
1982
|
+
}
|
|
1983
|
+
const body = {};
|
|
1984
|
+
if (opts.fireAt !== void 0) body.fireAt = opts.fireAt;
|
|
1985
|
+
if (opts.in !== void 0) {
|
|
1986
|
+
const delaySeconds = parseDurationSeconds(opts.in);
|
|
1987
|
+
if (delaySeconds == null) {
|
|
1988
|
+
fail("INVALID_ARG", "--in must be a positive duration like 30m, 2h, or 1d");
|
|
1989
|
+
}
|
|
1990
|
+
body.delaySeconds = delaySeconds;
|
|
1991
|
+
}
|
|
1992
|
+
if (opts.cadence !== void 0) {
|
|
1993
|
+
body.repeat = opts.cadence;
|
|
1994
|
+
body.tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
1995
|
+
}
|
|
1996
|
+
if (opts.title !== void 0) body.title = opts.title;
|
|
1997
|
+
const client = new ApiClient(ctx);
|
|
1998
|
+
const fullId = await resolveReminderId(client, ctx.agentId, opts.id, {
|
|
1999
|
+
all: true,
|
|
2000
|
+
failureCode: "UPDATE_FAILED"
|
|
2001
|
+
});
|
|
2002
|
+
const res = await client.request(
|
|
2003
|
+
"PATCH",
|
|
2004
|
+
`/internal/agent/${encodeURIComponent(ctx.agentId)}/reminders/${encodeURIComponent(fullId)}`,
|
|
2005
|
+
body
|
|
2006
|
+
);
|
|
2007
|
+
if (!res.ok || !res.data?.reminder) {
|
|
2008
|
+
const code = res.status >= 500 ? "SERVER_5XX" : "UPDATE_FAILED";
|
|
2009
|
+
fail(code, res.error ?? `HTTP ${res.status}`);
|
|
2010
|
+
}
|
|
2011
|
+
process.stdout.write(formatReminderUpdated(res.data.reminder, res.data.warning ?? null) + "\n");
|
|
2012
|
+
});
|
|
2013
|
+
}
|
|
2014
|
+
|
|
2015
|
+
// src/commands/reminder/log.ts
|
|
2016
|
+
function registerReminderLogCommand(parent) {
|
|
2017
|
+
parent.command("log").description("Show lifecycle events for one reminder").requiredOption("--id <id>", "Reminder id (full uuid or short prefix)").action(async (opts) => {
|
|
2018
|
+
let ctx;
|
|
2019
|
+
try {
|
|
2020
|
+
ctx = loadAgentContext();
|
|
2021
|
+
} catch (err) {
|
|
2022
|
+
if (err instanceof AgentBootstrapError) fail(err.code, err.message);
|
|
2023
|
+
throw err;
|
|
2024
|
+
}
|
|
2025
|
+
const client = new ApiClient(ctx);
|
|
2026
|
+
const fullId = await resolveReminderId(client, ctx.agentId, opts.id, {
|
|
2027
|
+
all: true,
|
|
2028
|
+
failureCode: "LOG_FAILED"
|
|
2029
|
+
});
|
|
2030
|
+
const res = await client.request(
|
|
2031
|
+
"GET",
|
|
2032
|
+
`/internal/agent/${encodeURIComponent(ctx.agentId)}/reminders/${encodeURIComponent(fullId)}/log`
|
|
2033
|
+
);
|
|
2034
|
+
if (!res.ok || !res.data?.events) {
|
|
2035
|
+
const code = res.status >= 500 ? "SERVER_5XX" : "LOG_FAILED";
|
|
2036
|
+
fail(code, res.error ?? `HTTP ${res.status}`);
|
|
2037
|
+
}
|
|
2038
|
+
process.stdout.write(formatReminderLog(res.data.events) + "\n");
|
|
2039
|
+
});
|
|
2040
|
+
}
|
|
2041
|
+
|
|
1829
2042
|
// src/index.ts
|
|
1830
2043
|
var program = new Command();
|
|
1831
2044
|
program.name("slock").description(
|
|
@@ -1861,6 +2074,9 @@ var reminderCmd = program.command("reminder").description("Reminder operations")
|
|
|
1861
2074
|
registerReminderScheduleCommand(reminderCmd);
|
|
1862
2075
|
registerReminderListCommand(reminderCmd);
|
|
1863
2076
|
registerReminderCancelCommand(reminderCmd);
|
|
2077
|
+
registerReminderSnoozeCommand(reminderCmd);
|
|
2078
|
+
registerReminderUpdateCommand(reminderCmd);
|
|
2079
|
+
registerReminderLogCommand(reminderCmd);
|
|
1864
2080
|
program.parseAsync().catch((err) => {
|
|
1865
2081
|
if (err instanceof CliExit) {
|
|
1866
2082
|
process.exitCode = err.exitCode;
|
package/dist/core.js
CHANGED
package/dist/index.js
CHANGED