@slock-ai/daemon 0.57.4 → 0.57.5-play.20260611173452
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/{chunk-EXLDUFWR.js → chunk-NHANGBTA.js} +359 -349
- package/dist/cli/index.js +905 -323
- package/dist/cli/package.json +1 -1
- package/dist/core.js +5 -1
- package/dist/index.js +5 -3
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/core.ts
|
|
2
|
-
import
|
|
3
|
-
import
|
|
2
|
+
import path16 from "path";
|
|
3
|
+
import os8 from "os";
|
|
4
4
|
import { createRequire as createRequire2 } from "module";
|
|
5
5
|
import { accessSync } from "fs";
|
|
6
6
|
import { fileURLToPath } from "url";
|
|
@@ -1301,6 +1301,7 @@ var RUNTIME_MODELS = {
|
|
|
1301
1301
|
{ id: "claude-opus-4-8", label: "Claude Opus 4.8" },
|
|
1302
1302
|
{ id: "claude-opus-4-7", label: "Claude Opus 4.7" },
|
|
1303
1303
|
{ id: "claude-opus-4-6", label: "Claude Opus 4.6" },
|
|
1304
|
+
{ id: "fable", label: "Claude Fable" },
|
|
1304
1305
|
{ id: "sonnet", label: "Claude Sonnet" },
|
|
1305
1306
|
{ id: "claude-sonnet-4-6", label: "Claude Sonnet 4.6" },
|
|
1306
1307
|
{ id: "haiku", label: "Claude Haiku" },
|
|
@@ -1503,11 +1504,11 @@ var DISPLAY_PLAN_CONFIG = {
|
|
|
1503
1504
|
};
|
|
1504
1505
|
|
|
1505
1506
|
// src/agentProcessManager.ts
|
|
1506
|
-
import { mkdirSync as
|
|
1507
|
+
import { mkdirSync as mkdirSync4, readdirSync as readdirSync2, statSync, writeFileSync as writeFileSync4 } from "fs";
|
|
1507
1508
|
import { mkdir, writeFile, access, readdir as readdir2, stat as stat2, readFile, rm as rm2 } from "fs/promises";
|
|
1508
1509
|
import { createHash as createHash3 } from "crypto";
|
|
1509
|
-
import
|
|
1510
|
-
import
|
|
1510
|
+
import path12 from "path";
|
|
1511
|
+
import os6 from "os";
|
|
1511
1512
|
|
|
1512
1513
|
// src/drivers/claude.ts
|
|
1513
1514
|
import { spawn } from "child_process";
|
|
@@ -1841,9 +1842,6 @@ function buildSlockCliGuideSections(options) {
|
|
|
1841
1842
|
}
|
|
1842
1843
|
|
|
1843
1844
|
// src/drivers/systemPrompt.ts
|
|
1844
|
-
function toolRef(prefix, name) {
|
|
1845
|
-
return `${prefix}${name}`;
|
|
1846
|
-
}
|
|
1847
1845
|
function runtimeContextLines(config) {
|
|
1848
1846
|
const ctx = config.runtimeContext;
|
|
1849
1847
|
if (!ctx) return [];
|
|
@@ -1865,10 +1863,8 @@ function runtimeContextLines(config) {
|
|
|
1865
1863
|
if (ctx.workspacePath) lines.push(`- Workspace: ${ctx.workspacePath}`);
|
|
1866
1864
|
return lines.length > 4 ? lines : [];
|
|
1867
1865
|
}
|
|
1868
|
-
function buildPrompt(config,
|
|
1869
|
-
const
|
|
1870
|
-
const t = (name) => toolRef(opts.toolPrefix, name);
|
|
1871
|
-
const taskClaimCmd = isCli ? "`slock task claim`" : `\`${t("claim_tasks")}\``;
|
|
1866
|
+
function buildPrompt(config, opts) {
|
|
1867
|
+
const taskClaimCmd = "`slock task claim`";
|
|
1872
1868
|
const cliGuideSections = buildSlockCliGuideSections({
|
|
1873
1869
|
// The daemon prompt audience is always managed-runner regardless of
|
|
1874
1870
|
// CLI vs MCP variant — both are daemon-spawned. The self-hosted-runner
|
|
@@ -1880,162 +1876,42 @@ function buildPrompt(config, variant, opts) {
|
|
|
1880
1876
|
},
|
|
1881
1877
|
taskClaimCmd
|
|
1882
1878
|
});
|
|
1883
|
-
const
|
|
1884
|
-
const
|
|
1885
|
-
const checkCmd = isCli ? "`slock message check`" : `\`${t("check_messages")}\``;
|
|
1886
|
-
const inboxCheckCmd = isCli ? "`slock inbox check`" : checkCmd;
|
|
1887
|
-
const taskCreateCmd = isCli ? "`slock task create`" : `\`${t("create_tasks")}\``;
|
|
1888
|
-
const taskUpdateCmd = isCli ? "`slock task update`" : `\`${t("update_task_status")}\``;
|
|
1889
|
-
const serverInfoCmd = isCli ? "`slock server info`" : `\`${t("list_server")}\``;
|
|
1890
|
-
const scheduleReminderCmd = isCli ? "`slock reminder schedule`" : `\`${t("schedule_reminder")}\``;
|
|
1891
|
-
const listRemindersCmd = isCli ? "`slock reminder list`" : `\`${t("list_reminders")}\``;
|
|
1892
|
-
const cancelReminderCmd = isCli ? "`slock reminder cancel`" : `\`${t("cancel_reminder")}\``;
|
|
1879
|
+
const checkCmd = "`slock message check`";
|
|
1880
|
+
const inboxCheckCmd = "`slock inbox check`";
|
|
1893
1881
|
const messageDeliveryText = opts.includeStdinNotificationSection ? "New messages may be delivered to you automatically while your process stays alive." : "The daemon will automatically restart you when new messages arrive.";
|
|
1894
|
-
const
|
|
1882
|
+
const noConcreteMessageStartupStep = opts.includeStdinNotificationSection ? `3. If there is no concrete incoming message to handle, but this turn includes a Slock inbox notice, treat it as a wake signal: call ${checkCmd} to read the pending message content before deciding there is no work. If there is neither a concrete message nor an inbox notice, stop and wait. ${messageDeliveryText}` : `3. If there is no concrete incoming message to handle, stop and wait. ${messageDeliveryText}`;
|
|
1883
|
+
const criticalRules = [
|
|
1895
1884
|
"- Always communicate through `slock` CLI commands. This is your only output channel: text you produce outside a `slock` command is not delivered to anyone.",
|
|
1896
1885
|
...opts.extraCriticalRules,
|
|
1897
1886
|
"- Use only the provided `slock` CLI commands for messaging.",
|
|
1898
1887
|
"- Do not combine multiple `slock` CLI commands in one shell command. Run one `slock` command per tool call, read its output, then decide the next command.",
|
|
1899
1888
|
"- Always claim a task via `slock task claim` before starting work on it. If the claim fails, move on to a different task."
|
|
1900
|
-
] : [
|
|
1901
|
-
`- Always communicate through ${sendCmd}. This is your only output channel: text you produce outside a messaging tool is not delivered to anyone.`,
|
|
1902
|
-
...opts.extraCriticalRules,
|
|
1903
|
-
"- Use only the provided MCP tools for messaging \u2014 they are already available and ready.",
|
|
1904
|
-
`- Always claim a task via ${taskClaimCmd} before starting work on it. If the claim fails, move on to a different task.`
|
|
1905
1889
|
];
|
|
1906
1890
|
const runtimeProfileControl = config.runtimeProfileControl?.kind === "daemon_release_notice" ? config.runtimeProfileControl : null;
|
|
1907
1891
|
const runtimeProfileControlStartupStep = runtimeProfileControl ? [
|
|
1908
1892
|
"0. If this system prompt contains a **Runtime Profile Control** section, read that notice first. It is informational only; no runtime control action or chat reply is required. Do not read MEMORY.md, check messages, or respond to inbox messages before reading it."
|
|
1909
1893
|
] : [];
|
|
1910
|
-
const startupSteps =
|
|
1894
|
+
const startupSteps = [
|
|
1911
1895
|
...runtimeProfileControlStartupStep,
|
|
1912
1896
|
"1. If this turn already includes a concrete incoming message, first decide whether that message needs a visible acknowledgment, blocker question, or ownership signal. If it does, send it early with `slock message send` before deep context gathering.",
|
|
1913
1897
|
"2. Read MEMORY.md (in your cwd) and then only the additional memory/files you need to handle the current turn well.",
|
|
1914
|
-
|
|
1898
|
+
noConcreteMessageStartupStep,
|
|
1915
1899
|
"4. When you receive a message, process it and reply with `slock message send`.",
|
|
1916
1900
|
"5. **Complete ALL your work before stopping.** If a task requires multi-step work (research, code changes, testing), finish everything, report results, then stop. New messages arrive automatically \u2014 you do not need to poll or wait for them."
|
|
1917
|
-
] : [
|
|
1918
|
-
...runtimeProfileControlStartupStep,
|
|
1919
|
-
`1. If this turn already includes a concrete incoming message, first decide whether that message needs a visible acknowledgment, blocker question, or ownership signal. If it does, send it early with ${sendCmd} before deep context gathering.`,
|
|
1920
|
-
"2. Read MEMORY.md (in your cwd) and then only the additional memory/files you need to handle the current turn well.",
|
|
1921
|
-
`3. If there is no concrete incoming message to handle, stop and wait. ${messageDeliveryText}`,
|
|
1922
|
-
`4. When you receive a message, process it and reply with ${sendCmd}.`,
|
|
1923
|
-
"5. **Complete ALL your work before stopping.** If a task requires multi-step work (research, code changes, testing), finish everything, report results, then stop. New messages arrive automatically \u2014 you do not need to poll or wait for them."
|
|
1924
1901
|
];
|
|
1925
|
-
const communicationSection =
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
10. **${taskClaimCmd}** \u2014 Claim tasks by number or message ID (supports batch, handles conflicts).
|
|
1939
|
-
11. **\`${t("unclaim_task")}\`** \u2014 Release your claim on a task.
|
|
1940
|
-
12. **${taskUpdateCmd}** \u2014 Change a task's status (e.g. to in_review or done).
|
|
1941
|
-
13. **\`${t("upload_file")}\`** \u2014 Upload a file up to 50MB to attach to a message. Returns an attachment ID to pass to ${sendCmd}. Videos are downloadable attachments and are not parsed by agents; large PDFs may need to be downloaded and inspected in smaller chunks.
|
|
1942
|
-
14. **\`${t("view_file")}\`** \u2014 Download an attached file by its attachment ID so you can inspect it locally.
|
|
1943
|
-
15. **${scheduleReminderCmd}** \u2014 Schedule a reminder for yourself later, at a specific time, or on a recurring cadence.
|
|
1944
|
-
16. **${listRemindersCmd}** \u2014 List your reminders.
|
|
1945
|
-
17. **${cancelReminderCmd}** \u2014 Cancel one of your reminders by ID.`;
|
|
1946
|
-
const credentialHygieneSection = isCli ? cliGuideSections.credentialHygiene : `### Credential hygiene
|
|
1947
|
-
|
|
1948
|
-
**Never paste credentials into public Slock channels, public-channel threads, or public-channel task/attachment fields.** Agent tokens (\`sk_agent_*\`), legacy machine API keys (\`sk_machine_*\`), session bearers, JWTs, \`.env\` files, or \`credential.json\` contents must not appear in public channel chat. DMs and private channels are allowed for authorized secret handoff, but verify the audience first. If you accidentally paste one into a public channel, immediately tell the credential owner so they can rotate it.
|
|
1949
|
-
|
|
1950
|
-
If a tool or error output contains credential-shaped strings, redact them to \`sk_agent_<redacted>\` / \`sk_machine_<redacted>\` shape before posting to a public channel.`;
|
|
1951
|
-
const reminderSection = isCli ? cliGuideSections.reminders : `### Reminders
|
|
1952
|
-
|
|
1953
|
-
Use reminders for follow-up that depends on future state you cannot resolve now, whether user-requested or self-driven. A reminder is an author-owned, persistent, observable, snoozable, updatable, and cancelable wake-up signal anchored to a Slock message or thread; when it fires, it wakes the author who scheduled it, not other people. If anchored to a message or thread, the receipt/fire system message is visible in that surface, but wake ownership does not transfer. To notify another human or agent later, schedule your own reminder and then @mention them when it fires. Use reminders instead of keeping the current turn alive with a long sleep or relying on MEMORY to wake you. If you expect the wait to finish within about 1 minute, you may briefly poll, but say so in the relevant thread first.
|
|
1954
|
-
When a reminder already exists, prefer \`slock reminder snooze\` to push it later, \`slock reminder update\` to change its meaning or schedule, and \`slock reminder cancel\` only when it is truly no longer needed.
|
|
1955
|
-
Use ${scheduleReminderCmd} rather than runtime-native wake or cron tools such as ScheduleWakeup or CronCreate for user-visible reminders, so reminders stay author-owned, persistent, observable, snoozable, updatable, and cancelable in Slock.
|
|
1956
|
-
Create agent reminders only after resolving the anchor message from the current conversation and passing its msgId explicitly; if no anchor can be resolved, consider posting a status update in the relevant thread so the intent is visible, then revisit when context is available.`;
|
|
1957
|
-
const sendingMessagesSection = isCli ? cliGuideSections.sendingMessages : `### Sending messages
|
|
1958
|
-
|
|
1959
|
-
- **Reply to a channel**: \`${t("send_message")}(target="#channel-name", content="...")\`
|
|
1960
|
-
- **Reply to a DM**: \`${t("send_message")}(target="dm:@peer-name", content="...")\`
|
|
1961
|
-
- **Reply in a thread**: \`${t("send_message")}(target="#channel:shortid", content="...")\` or \`${t("send_message")}(target="dm:@peer:shortid", content="...")\`
|
|
1962
|
-
- **Start a NEW DM**: \`${t("send_message")}(target="dm:@person-name", content="...")\`
|
|
1963
|
-
|
|
1964
|
-
**IMPORTANT**: To reply to any message, always reuse the exact \`target\` from the received message. This ensures your reply goes to the right place \u2014 whether it's a channel, DM, or thread.`;
|
|
1965
|
-
const threadsSection = isCli ? cliGuideSections.threads : `### Threads
|
|
1966
|
-
|
|
1967
|
-
Threads are sub-conversations attached to a specific message. They let you discuss a topic without cluttering the main channel.
|
|
1968
|
-
|
|
1969
|
-
- **Thread targets** have a colon and short ID suffix: \`#general:00000000\` (thread in #general) or \`dm:@richard:11111111\` (thread in a DM).
|
|
1970
|
-
- When you receive a message from a thread (the target has a \`:shortid\` suffix), **always reply using that same target** to keep the conversation in the thread.
|
|
1971
|
-
- **Start a new thread**: Use the \`msg=\` field from the header as the thread suffix. For example, if you see \`[target=#general msg=00000000 ...]\`, call \`${t("send_message")}(target="#general:00000000", content="...")\`. The thread will be auto-created if it doesn't exist yet. Example IDs like \`00000000\` are placeholders; real message IDs come from received messages.
|
|
1972
|
-
- When you send a message, the response includes the message ID. You can use it to start a thread on your own message.
|
|
1973
|
-
- You can read thread history via ${readCmd} with the same thread target.
|
|
1974
|
-
- Threads cannot be nested \u2014 you cannot start a thread inside a thread.`;
|
|
1975
|
-
const discoverySection = isCli ? cliGuideSections.discovery : `### Discovering people and channels
|
|
1976
|
-
|
|
1977
|
-
Call ${serverInfoCmd} to see all channels in this server, which ones you have joined, other agents, and humans.
|
|
1978
|
-
Visible public channels may appear even when \`joined=false\`. In that state you can still inspect them with ${readCmd}, but you cannot send messages there or receive ordinary channel delivery until you join with \`${t("join_channel")}\`. Private channels require a human with access to add you. To leave a regular channel you have joined, use \`${t("leave_channel")}\`.
|
|
1979
|
-
Private channels are membership-gated. If ${serverInfoCmd} shows a channel as private, treat its name, members, and content as private to that channel; do not disclose that information in other channels, DMs, summaries, or task reports unless a human explicitly asks within an authorized context. In channel member listings, human role labels such as owner/admin show server-level authority; no role label means ordinary member.`;
|
|
1980
|
-
const channelAwarenessSection = isCli ? cliGuideSections.channelAwareness : `### Channel awareness
|
|
1981
|
-
|
|
1982
|
-
Each channel has a **name** and optionally a **description** that define its purpose (visible via ${serverInfoCmd}). Respect them:
|
|
1983
|
-
- **Reply in context** \u2014 always respond in the channel/thread the message came from.
|
|
1984
|
-
- **Stay on topic** \u2014 when proactively sharing results or updates, post in the channel most relevant to the work. Don't scatter messages across unrelated channels.
|
|
1985
|
-
- If unsure where something belongs, call ${serverInfoCmd} to review channel descriptions.`;
|
|
1986
|
-
const thirdPartyIntegrationsSection = isCli ? `### Third-party integrations
|
|
1987
|
-
|
|
1988
|
-
If a built-in Slock app or registered third-party service requires login, use Slock Agent Login through the CLI instead of asking the human to copy tokens or complete human OAuth for you. If a human asks you to sign into, open, use, or fetch identity from a third-party app or built-in Slock app, first run \`slock integration list\` and match the app to a listed service before browsing the app. Use \`slock integration login --service <service>\` to provision or reuse your agent login for that service. If the service exposes an agent behavior manifest and you need to run its local CLI, run \`slock integration env --service <service>\` before invoking that CLI; if it prints exports, apply them first so service credentials stay under a per-agent profile HOME/XDG tree instead of the host user's global HOME. If it reports that no local env is required, do not invent HOME/XDG overrides. If it fails, do not run that local CLI with the host user's HOME; report that the service manifest is unsupported. Slock does not execute commands from remote manifests automatically. If the CLI reports that the \`integration\` command is unknown, the local daemon/CLI is too old for Slock Agent Login; report that the machine must be upgraded/restarted instead of calling internal HTTP endpoints yourself. When the command returns \`Agent login ready\` or \`Already logged in\`, the agent-side login is ready. If the output includes an app URL, open that URL as the service-provided app surface; it should look like the service's normal Login with Slock callback and not require you to understand Slock's internal grant/request protocol. Do not crawl third-party routes looking for a session before trying the registered-service login path. Do not open the human \`Login with Slock\` browser flow, use internal request IDs as OAuth callback codes, call internal Slock integration endpoints directly, or call third-party exchange endpoints unless a human explicitly asks you to debug that server-to-server protocol. If the service or human asks for your Slock Agent identity card, use \`slock profile show\`. Third-party pages may show \`Login with Slock\`; for agent-facing access, prefer the listed service / Slock Agent Login path.` : `### Third-party integrations
|
|
1989
|
-
|
|
1990
|
-
If a built-in Slock app or registered third-party service requires login, use Slock Agent Login through the available registered-service interface instead of asking the human to copy tokens or complete human OAuth for you. If a human asks you to sign into, open, use, or fetch identity from a third-party app or built-in Slock app, first inspect the registered-service interface and match the app to a listed service before browsing the app. Once the registered-service interface reports the agent login is ready, the agent-side login is ready. If that interface provides an app URL, use it as the service-provided app surface; it should look like the service's normal Login with Slock callback and not require you to understand Slock's internal grant/request protocol. Do not crawl third-party routes looking for a session before trying the registered-service login path. Do not open the human \`Login with Slock\` browser flow or treat internal request IDs as OAuth callback codes unless a human explicitly asks you to debug that server-to-server protocol. If the service or human asks for your Slock Agent identity card, use your Slock profile view. Third-party pages may show \`Login with Slock\`; for agent-facing access, prefer the listed service / Slock Agent Login path.`;
|
|
1991
|
-
const readingHistorySection = isCli ? cliGuideSections.readingHistory : `### Reading history
|
|
1992
|
-
|
|
1993
|
-
Use ${readCmd} with the \`channel\` parameter set to \`"#channel-name"\`, \`"dm:@peer-name"\`, or a thread target like \`"#channel:shortid"\`.
|
|
1994
|
-
|
|
1995
|
-
To jump directly to a specific hit with nearby context, pass \`around\` set to a message ID or seq number.`;
|
|
1996
|
-
const historicalReferenceSection = isCli ? cliGuideSections.historicalReferences : `### Historical references
|
|
1997
|
-
|
|
1998
|
-
When a user refers to prior Slock discussion and the relevant context is not already available, first use \`${t("search_messages")}\` and ${readCmd} to find the original thread, decision, or owner before answering. If you find it, summarize the original conclusion with the source thread/message; if you cannot find it, say that explicitly.`;
|
|
1999
|
-
const tasksSection = isCli ? cliGuideSections.tasks : `### Tasks
|
|
2000
|
-
|
|
2001
|
-
When someone sends a message that asks you to do something \u2014 fix a bug, write code, review a PR, deploy, investigate an issue \u2014 that is work. Claim it before you start.
|
|
2002
|
-
|
|
2003
|
-
**Decision rule:** if fulfilling a message requires you to take action beyond just replying (running tools, writing code, making changes), claim the message first. If you're only answering a question or having a conversation, no claim needed.
|
|
2004
|
-
|
|
2005
|
-
**What you see in messages:**
|
|
2006
|
-
- A message already marked as a task: \`@Alice: Fix the login bug [task #3 status=in_progress]\`
|
|
2007
|
-
- A regular message (no task suffix): \`@Alice: Can someone look into the login bug?\`
|
|
2008
|
-
- A system notification about task changes: \`\u{1F4CB} Alice converted a message to task #3 "Fix the login bug"\`
|
|
2009
|
-
|
|
2010
|
-
Only top-level channel / DM messages can become tasks. Messages inside threads are discussion context \u2014 reply there, but keep claims and conversions to top-level messages.
|
|
2011
|
-
|
|
2012
|
-
${readCmd} shows messages in their current state. If a message was later converted to a task, it will show the \`[task #N ...]\` suffix.
|
|
2013
|
-
|
|
2014
|
-
**Status flow:** \`todo\` \u2192 \`in_progress\` \u2192 \`in_review\` \u2192 \`done\`
|
|
2015
|
-
|
|
2016
|
-
**Assignee** is independent from status \u2014 a task can be claimed or unclaimed at any status except \`done\`.
|
|
2017
|
-
|
|
2018
|
-
**Workflow:**
|
|
2019
|
-
1. Receive a message that requires action \u2192 claim it first (by task number if already a task, or by message ID if it's a regular message)
|
|
2020
|
-
2. If the claim fails, someone else is working on it \u2014 move on to another task
|
|
2021
|
-
3. Post updates in the task's thread via ${sendCmd} with \`target="#channel:msgShortId"\`
|
|
2022
|
-
4. When done, set status to \`in_review\` so a human can validate via ${taskUpdateCmd}
|
|
2023
|
-
5. After approval (e.g. "looks good", "merge it"), set status to \`done\`
|
|
2024
|
-
|
|
2025
|
-
**What ${taskCreateCmd} really means:**
|
|
2026
|
-
- Tasks live in the same chat flow as messages. A task is just a message with task metadata, not a separate source of truth.
|
|
2027
|
-
- ${taskCreateCmd} is a convenience helper for a specific sequence: create a brand-new message, then publish that new message as a task-message.
|
|
2028
|
-
- ${taskCreateCmd} only creates the task \u2014 to own it, call ${taskClaimCmd} afterward.
|
|
2029
|
-
- Typical uses for ${taskCreateCmd} are breaking down a larger task into parallel subtasks, or batch-creating genuinely new work for others to claim.
|
|
2030
|
-
- If someone already sent the work item as a message, just claim that existing message/task instead of creating a new one.
|
|
2031
|
-
- If the work already exists as a message, reuse it via ${taskClaimCmd} with the message ID.
|
|
2032
|
-
|
|
2033
|
-
**Creating new tasks:**
|
|
2034
|
-
- The task system exists to prevent duplicate work. If you see an existing task for the work, either claim that task or leave it alone.
|
|
2035
|
-
- If a message already shows a \`[task #N ...]\` suffix, claim \`#N\` if it is yours to take; otherwise move on.
|
|
2036
|
-
- Before calling ${taskCreateCmd}, first check whether the work already exists on the task board or is already being handled.
|
|
2037
|
-
- Reuse existing tasks and threads instead of creating duplicates.
|
|
2038
|
-
- Use ${taskCreateCmd} only for genuinely new subtasks or follow-up work that does not already have a canonical task.`;
|
|
1902
|
+
const communicationSection = cliGuideSections.communication;
|
|
1903
|
+
const credentialHygieneSection = cliGuideSections.credentialHygiene;
|
|
1904
|
+
const reminderSection = cliGuideSections.reminders;
|
|
1905
|
+
const sendingMessagesSection = cliGuideSections.sendingMessages;
|
|
1906
|
+
const threadsSection = cliGuideSections.threads;
|
|
1907
|
+
const discoverySection = cliGuideSections.discovery;
|
|
1908
|
+
const channelAwarenessSection = cliGuideSections.channelAwareness;
|
|
1909
|
+
const thirdPartyIntegrationsSection = `### Third-party integrations
|
|
1910
|
+
|
|
1911
|
+
If a built-in Slock app or registered third-party service requires login, use Slock Agent Login through the CLI instead of asking the human to copy tokens or complete human OAuth for you. If a human asks you to sign into, open, use, or fetch identity from a third-party app or built-in Slock app, first run \`slock integration list\` and match the app to a listed service before browsing the app. Use \`slock integration login --service <service>\` to provision or reuse your agent login for that service. If the service exposes an agent behavior manifest and you need to run its local CLI, run \`slock integration env --service <service>\` before invoking that CLI; if it prints exports, apply them first so service credentials stay under a per-agent profile HOME/XDG tree instead of the host user's global HOME. If it reports that no local env is required, do not invent HOME/XDG overrides. If it fails, do not run that local CLI with the host user's HOME; report that the service manifest is unsupported. Slock does not execute commands from remote manifests automatically. If the CLI reports that the \`integration\` command is unknown, the local daemon/CLI is too old for Slock Agent Login; report that the machine must be upgraded/restarted instead of calling internal HTTP endpoints yourself. When the command returns \`Agent login ready\` or \`Already logged in\`, the agent-side login is ready. If the output includes an app URL, open that URL as the service-provided app surface; it should look like the service's normal Login with Slock callback and not require you to understand Slock's internal grant/request protocol. Do not crawl third-party routes looking for a session before trying the registered-service login path. Do not open the human \`Login with Slock\` browser flow, use internal request IDs as OAuth callback codes, call internal Slock integration endpoints directly, or call third-party exchange endpoints unless a human explicitly asks you to debug that server-to-server protocol. If the service or human asks for your Slock Agent identity card, use \`slock profile show\`. Third-party pages may show \`Login with Slock\`; for agent-facing access, prefer the listed service / Slock Agent Login path.`;
|
|
1912
|
+
const readingHistorySection = cliGuideSections.readingHistory;
|
|
1913
|
+
const historicalReferenceSection = cliGuideSections.historicalReferences;
|
|
1914
|
+
const tasksSection = cliGuideSections.tasks;
|
|
2039
1915
|
let prompt = `You are "${config.displayName || config.name}", an AI agent in Slock \u2014 a collaborative platform for human-AI collaboration, serving as a shared message service for humans and agents who may be running on different computers.
|
|
2040
1916
|
|
|
2041
1917
|
## Who you are
|
|
@@ -2149,10 +2025,11 @@ While you are working, the daemon may write a batched, content-free inbox update
|
|
|
2149
2025
|
|
|
2150
2026
|
How to handle these:
|
|
2151
2027
|
- Treat the notification as a non-urgent signal that new Slock messages are waiting; it does not include the message content and does not require an immediate interruption.
|
|
2152
|
-
-
|
|
2028
|
+
- If an inbox notice is the only input that woke this turn, call ${checkCmd} to read the pending message content before deciding there is no action to take.
|
|
2029
|
+
- Keep working until a natural breakpoint. If you then choose to inspect pending targets, call ${inboxCheckCmd}; use ${checkCmd} / \`slock message read\` when you choose to inspect message content.
|
|
2153
2030
|
- If a message you explicitly read is higher priority, pivot to it. If not, continue your current work.`;
|
|
2154
2031
|
} else {
|
|
2155
|
-
const notifyExample =
|
|
2032
|
+
const notifyExample = `\`[Slock inbox notice:\\nInbox update: N unread messages total; M changed targets\\n#channel pending: K messages ...]\``;
|
|
2156
2033
|
prompt += `
|
|
2157
2034
|
|
|
2158
2035
|
## Message Notifications
|
|
@@ -2163,7 +2040,8 @@ ${notifyExample}
|
|
|
2163
2040
|
|
|
2164
2041
|
How to handle these:
|
|
2165
2042
|
- The notice is target-scoped and content-free. Its header may show total unread/pending count, while detail rows list the targets changed by this update; it never includes message bodies.
|
|
2166
|
-
-
|
|
2043
|
+
- If an inbox notice is the only input that woke this turn, call ${checkCmd} to read the pending message content before deciding there is no action to take.
|
|
2044
|
+
- Do not interrupt the current step just because a notice arrived. At a natural breakpoint, call ${inboxCheckCmd} if you choose to inspect pending targets, or use ${checkCmd} / \`slock message read\` when you choose to inspect message content.
|
|
2167
2045
|
- If a message you explicitly read is higher priority, you may pivot to it. If not, continue your current work.`;
|
|
2168
2046
|
}
|
|
2169
2047
|
}
|
|
@@ -2176,7 +2054,7 @@ ${config.description}. This may evolve.`;
|
|
|
2176
2054
|
return prompt;
|
|
2177
2055
|
}
|
|
2178
2056
|
function buildCliSystemPrompt(config, opts) {
|
|
2179
|
-
return buildPrompt(config,
|
|
2057
|
+
return buildPrompt(config, opts);
|
|
2180
2058
|
}
|
|
2181
2059
|
|
|
2182
2060
|
// src/slockHome.ts
|
|
@@ -2218,6 +2096,19 @@ function listLegacySlockStatePaths(slockHome = resolveSlockHome(), homeDir = os.
|
|
|
2218
2096
|
return candidates.filter((candidate) => existsSync(candidate.path));
|
|
2219
2097
|
}
|
|
2220
2098
|
|
|
2099
|
+
// src/authEnv.ts
|
|
2100
|
+
var DAEMON_API_KEY_ENV = "SLOCK_MACHINE_API_KEY";
|
|
2101
|
+
var SLOCK_AGENT_TOKEN_ENV = "SLOCK_AGENT_TOKEN";
|
|
2102
|
+
function scrubDaemonAuthEnv(env) {
|
|
2103
|
+
delete env[DAEMON_API_KEY_ENV];
|
|
2104
|
+
return env;
|
|
2105
|
+
}
|
|
2106
|
+
function scrubDaemonChildEnv(env) {
|
|
2107
|
+
delete env[DAEMON_API_KEY_ENV];
|
|
2108
|
+
delete env[SLOCK_AGENT_TOKEN_ENV];
|
|
2109
|
+
return env;
|
|
2110
|
+
}
|
|
2111
|
+
|
|
2221
2112
|
// src/agentCredentialProxy.ts
|
|
2222
2113
|
import { randomBytes } from "crypto";
|
|
2223
2114
|
import http from "http";
|
|
@@ -3704,7 +3595,9 @@ var LOOPBACK_NO_PROXY = "127.0.0.1,localhost";
|
|
|
3704
3595
|
var CLI_TRANSPORT_TRACE_DIR_ENV = "SLOCK_CLI_TRANSPORT_TRACE_DIR";
|
|
3705
3596
|
var safePathPart = (value) => value.replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
3706
3597
|
var RAW_CREDENTIAL_ENV_DENYLIST = [
|
|
3707
|
-
"
|
|
3598
|
+
"SLOCK_AGENT_TOKEN",
|
|
3599
|
+
"SLOCK_AGENT_CREDENTIAL_KEY",
|
|
3600
|
+
"SLOCK_AGENT_CREDENTIAL_KEY_FILE"
|
|
3708
3601
|
];
|
|
3709
3602
|
var cachedOpencliBinPath;
|
|
3710
3603
|
function resolveOpencliBinPath() {
|
|
@@ -3919,7 +3812,7 @@ exec ${shellSingleQuote(process.execPath)} ${shellSingleQuote(opencliBinPath)} "
|
|
|
3919
3812
|
...agentCredentialProxy ? {} : { SLOCK_AGENT_TOKEN_FILE: tokenFile },
|
|
3920
3813
|
PATH: `${slockDir}${path2.delimiter}${process.env.PATH ?? ""}`
|
|
3921
3814
|
};
|
|
3922
|
-
|
|
3815
|
+
scrubDaemonChildEnv(spawnEnv);
|
|
3923
3816
|
for (const key of RAW_CREDENTIAL_ENV_DENYLIST) {
|
|
3924
3817
|
delete spawnEnv[key];
|
|
3925
3818
|
}
|
|
@@ -4348,7 +4241,7 @@ function resolveCommandOnWindows(command, env, execFileSyncFn, existsSyncFn) {
|
|
|
4348
4241
|
}
|
|
4349
4242
|
function resolveCommandOnPath(command, deps = {}) {
|
|
4350
4243
|
const platform = deps.platform ?? process.platform;
|
|
4351
|
-
const env = withWindowsUserEnvironment(deps.env ?? process.env, deps);
|
|
4244
|
+
const env = scrubDaemonChildEnv({ ...withWindowsUserEnvironment(deps.env ?? process.env, deps) });
|
|
4352
4245
|
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync;
|
|
4353
4246
|
const existsSyncFn = deps.existsSyncFn ?? existsSync2;
|
|
4354
4247
|
if (platform === "win32") {
|
|
@@ -4374,7 +4267,7 @@ function firstExistingPath(candidates, deps = {}) {
|
|
|
4374
4267
|
return null;
|
|
4375
4268
|
}
|
|
4376
4269
|
function readCommandVersion(command, args = [], deps = {}) {
|
|
4377
|
-
const env = withWindowsUserEnvironment(deps.env ?? process.env, deps);
|
|
4270
|
+
const env = scrubDaemonChildEnv({ ...withWindowsUserEnvironment(deps.env ?? process.env, deps) });
|
|
4378
4271
|
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync;
|
|
4379
4272
|
try {
|
|
4380
4273
|
const output = normalizeExecOutput(execFileSyncFn(command, [...args, "--version"], {
|
|
@@ -4468,6 +4361,52 @@ function buildClaudeSpawnSpec(claudeCommand, platform = process.platform) {
|
|
|
4468
4361
|
};
|
|
4469
4362
|
}
|
|
4470
4363
|
|
|
4364
|
+
// src/drivers/claudeProviderIsolation.ts
|
|
4365
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, symlinkSync } from "fs";
|
|
4366
|
+
import os2 from "os";
|
|
4367
|
+
import path5 from "path";
|
|
4368
|
+
function isClaudeCustomProviderConfig(config) {
|
|
4369
|
+
const launchRuntimeFields = runtimeConfigToLaunchFields(config);
|
|
4370
|
+
return launchRuntimeFields.runtime === "claude" && Boolean(launchRuntimeFields.envVars?.ANTHROPIC_BASE_URL) && Boolean(launchRuntimeFields.envVars?.ANTHROPIC_API_KEY);
|
|
4371
|
+
}
|
|
4372
|
+
function getClaudeProviderStatePaths(workingDirectory) {
|
|
4373
|
+
const root = path5.join(workingDirectory, ".slock", "claude-provider");
|
|
4374
|
+
const home = path5.join(root, "home");
|
|
4375
|
+
return {
|
|
4376
|
+
root,
|
|
4377
|
+
home,
|
|
4378
|
+
configDir: path5.join(home, ".claude")
|
|
4379
|
+
};
|
|
4380
|
+
}
|
|
4381
|
+
function linkIfPresent(source, target) {
|
|
4382
|
+
try {
|
|
4383
|
+
if (!existsSync3(source) || existsSync3(target)) return;
|
|
4384
|
+
mkdirSync2(path5.dirname(target), { recursive: true, mode: 448 });
|
|
4385
|
+
symlinkSync(source, target, "dir");
|
|
4386
|
+
} catch {
|
|
4387
|
+
}
|
|
4388
|
+
}
|
|
4389
|
+
function ensureClaudeProviderStatePaths(workingDirectory, hostClaudeHome = path5.join(os2.homedir(), ".claude")) {
|
|
4390
|
+
const paths = getClaudeProviderStatePaths(workingDirectory);
|
|
4391
|
+
mkdirSync2(paths.home, { recursive: true, mode: 448 });
|
|
4392
|
+
mkdirSync2(paths.configDir, { recursive: true, mode: 448 });
|
|
4393
|
+
linkIfPresent(path5.join(hostClaudeHome, "skills"), path5.join(paths.configDir, "skills"));
|
|
4394
|
+
linkIfPresent(path5.join(hostClaudeHome, "commands"), path5.join(paths.configDir, "commands"));
|
|
4395
|
+
return paths;
|
|
4396
|
+
}
|
|
4397
|
+
function buildClaudeProviderIsolationEnv(ctx) {
|
|
4398
|
+
if (!isClaudeCustomProviderConfig(ctx.config)) {
|
|
4399
|
+
return {};
|
|
4400
|
+
}
|
|
4401
|
+
const paths = ensureClaudeProviderStatePaths(ctx.workingDirectory);
|
|
4402
|
+
return {
|
|
4403
|
+
HOME: paths.home,
|
|
4404
|
+
USERPROFILE: paths.home,
|
|
4405
|
+
CLAUDE_CONFIG_DIR: paths.configDir,
|
|
4406
|
+
CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST: "1"
|
|
4407
|
+
};
|
|
4408
|
+
}
|
|
4409
|
+
|
|
4471
4410
|
// src/drivers/claude.ts
|
|
4472
4411
|
var ClaudeDriver = class {
|
|
4473
4412
|
id = "claude";
|
|
@@ -4488,8 +4427,6 @@ var ClaudeDriver = class {
|
|
|
4488
4427
|
toLaunchSpec: (modelId) => ({ args: ["--model", modelId] })
|
|
4489
4428
|
};
|
|
4490
4429
|
supportsStdinNotification = true;
|
|
4491
|
-
mcpToolPrefix = "";
|
|
4492
|
-
usesSlockCliForCommunication = true;
|
|
4493
4430
|
// Claude Code supports same-turn steering, but raw stdin injection at an
|
|
4494
4431
|
// arbitrary busy instant can collide with active signed thinking blocks. The
|
|
4495
4432
|
// daemon therefore gates busy delivery on Claude stream-json boundaries.
|
|
@@ -4503,7 +4440,10 @@ var ClaudeDriver = class {
|
|
|
4503
4440
|
return buildClaudeArgs(config, opts);
|
|
4504
4441
|
}
|
|
4505
4442
|
async spawn(ctx) {
|
|
4506
|
-
const { slockDir, tokenFile, spawnEnv } = await prepareCliTransport(
|
|
4443
|
+
const { slockDir, tokenFile, spawnEnv } = await prepareCliTransport(
|
|
4444
|
+
ctx,
|
|
4445
|
+
buildClaudeProviderIsolationEnv(ctx)
|
|
4446
|
+
);
|
|
4507
4447
|
const systemPromptPath = writeClaudeSystemPromptFile(ctx.standingPrompt, slockDir);
|
|
4508
4448
|
const args = this.buildClaudeArgs(ctx.config, {
|
|
4509
4449
|
standingPromptFilePath: systemPromptPath
|
|
@@ -4549,7 +4489,6 @@ var ClaudeDriver = class {
|
|
|
4549
4489
|
}
|
|
4550
4490
|
buildSystemPrompt(config, _agentId) {
|
|
4551
4491
|
return buildCliTransportSystemPrompt(config, {
|
|
4552
|
-
toolPrefix: "",
|
|
4553
4492
|
extraCriticalRules: [],
|
|
4554
4493
|
postStartupNotes: [
|
|
4555
4494
|
"**Claude runtime note:** While you are busy, Slock batches inbox-count notifications instead of injecting message content. Use `slock message check` at natural breakpoints to pull the pending messages before side-effect actions that depend on current context."
|
|
@@ -4562,9 +4501,9 @@ var ClaudeDriver = class {
|
|
|
4562
4501
|
|
|
4563
4502
|
// src/drivers/codex.ts
|
|
4564
4503
|
import { spawn as spawn2, execFileSync as execFileSync2, execSync } from "child_process";
|
|
4565
|
-
import { existsSync as
|
|
4566
|
-
import
|
|
4567
|
-
import
|
|
4504
|
+
import { existsSync as existsSync4, readFileSync as readFileSync2 } from "fs";
|
|
4505
|
+
import os3 from "os";
|
|
4506
|
+
import path6 from "path";
|
|
4568
4507
|
|
|
4569
4508
|
// src/runtimeTurnState.ts
|
|
4570
4509
|
var RuntimeTurnState = class {
|
|
@@ -4721,16 +4660,17 @@ function rawResponseItemProgressEvent(message) {
|
|
|
4721
4660
|
function nonEmptyString2(value) {
|
|
4722
4661
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
4723
4662
|
}
|
|
4663
|
+
function codexMcpToolName(item) {
|
|
4664
|
+
const tool = nonEmptyString2(item.tool) ?? "unknown";
|
|
4665
|
+
const server = nonEmptyString2(item.server);
|
|
4666
|
+
return server ? `mcp_${server}_${tool}` : `mcp_${tool}`;
|
|
4667
|
+
}
|
|
4724
4668
|
var CodexEventNormalizer = class {
|
|
4725
|
-
mcpToolPrefix;
|
|
4726
4669
|
currentThreadId = null;
|
|
4727
4670
|
sessionAnnounced = false;
|
|
4728
4671
|
streamedAgentMessageIds = /* @__PURE__ */ new Set();
|
|
4729
4672
|
streamedReasoningIds = /* @__PURE__ */ new Set();
|
|
4730
4673
|
turnState = new RuntimeTurnState();
|
|
4731
|
-
constructor(opts) {
|
|
4732
|
-
this.mcpToolPrefix = opts.mcpToolPrefix;
|
|
4733
|
-
}
|
|
4734
4674
|
reset(opts = {}) {
|
|
4735
4675
|
this.currentThreadId = opts.threadId ?? null;
|
|
4736
4676
|
this.turnState.reset();
|
|
@@ -4890,11 +4830,11 @@ var CodexEventNormalizer = class {
|
|
|
4890
4830
|
break;
|
|
4891
4831
|
case "mcpToolCall":
|
|
4892
4832
|
if (isStarted) {
|
|
4893
|
-
const toolName = item
|
|
4833
|
+
const toolName = codexMcpToolName(item);
|
|
4894
4834
|
events.push({ kind: "tool_call", name: toolName, input: item.arguments });
|
|
4895
4835
|
}
|
|
4896
4836
|
if (isCompleted) {
|
|
4897
|
-
const toolName = item
|
|
4837
|
+
const toolName = codexMcpToolName(item);
|
|
4898
4838
|
events.push({ kind: "tool_output", name: toolName });
|
|
4899
4839
|
this.turnState.markToolBoundary();
|
|
4900
4840
|
}
|
|
@@ -4950,9 +4890,9 @@ var CodexEventNormalizer = class {
|
|
|
4950
4890
|
|
|
4951
4891
|
// src/drivers/codex.ts
|
|
4952
4892
|
function ensureGitRepoForCodex(workingDirectory, deps = {}) {
|
|
4953
|
-
const existsSyncFn = deps.existsSyncFn ??
|
|
4893
|
+
const existsSyncFn = deps.existsSyncFn ?? existsSync4;
|
|
4954
4894
|
const execSyncFn = deps.execSyncFn ?? execSync;
|
|
4955
|
-
const gitDir =
|
|
4895
|
+
const gitDir = path6.join(workingDirectory, ".git");
|
|
4956
4896
|
if (existsSyncFn(gitDir)) return;
|
|
4957
4897
|
execSyncFn("git init", { cwd: workingDirectory, stdio: "pipe" });
|
|
4958
4898
|
execSyncFn(
|
|
@@ -4965,13 +4905,13 @@ function ensureGitRepoForCodex(workingDirectory, deps = {}) {
|
|
|
4965
4905
|
}
|
|
4966
4906
|
var CODEX_DESKTOP_BUNDLE_PATH = "/Applications/Codex.app/Contents/Resources/codex";
|
|
4967
4907
|
function isWindowsSandboxRunner(commandPath) {
|
|
4968
|
-
return
|
|
4908
|
+
return path6.basename(commandPath).toLowerCase().startsWith("codex-command-runner");
|
|
4969
4909
|
}
|
|
4970
4910
|
function resolveWindowsNpmCodexEntry(deps = {}) {
|
|
4971
|
-
const existsSyncFn = deps.existsSyncFn ??
|
|
4911
|
+
const existsSyncFn = deps.existsSyncFn ?? existsSync4;
|
|
4972
4912
|
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync2;
|
|
4973
4913
|
const env = deps.env ?? process.env;
|
|
4974
|
-
const winPath =
|
|
4914
|
+
const winPath = path6.win32;
|
|
4975
4915
|
try {
|
|
4976
4916
|
const globalRoot = String(execFileSyncFn("npm", ["root", "-g"], {
|
|
4977
4917
|
encoding: "utf8",
|
|
@@ -4990,10 +4930,10 @@ function resolveWindowsNpmCodexEntry(deps = {}) {
|
|
|
4990
4930
|
return null;
|
|
4991
4931
|
}
|
|
4992
4932
|
function resolveWindowsCodexDesktopEntry(deps = {}) {
|
|
4993
|
-
const existsSyncFn = deps.existsSyncFn ??
|
|
4933
|
+
const existsSyncFn = deps.existsSyncFn ?? existsSync4;
|
|
4994
4934
|
const env = deps.env ?? process.env;
|
|
4995
4935
|
const homeDir = deps.homeDir;
|
|
4996
|
-
const winPath =
|
|
4936
|
+
const winPath = path6.win32;
|
|
4997
4937
|
const candidates = [
|
|
4998
4938
|
env.LOCALAPPDATA ? winPath.join(env.LOCALAPPDATA, "OpenAI", "Codex", "bin", "codex.exe") : null,
|
|
4999
4939
|
env.USERPROFILE ? winPath.join(env.USERPROFILE, "AppData", "Local", "OpenAI", "Codex", "bin", "codex.exe") : null,
|
|
@@ -5081,8 +5021,6 @@ var CodexDriver = class {
|
|
|
5081
5021
|
toLaunchSpec: (modelId) => ({ params: { model: modelId } })
|
|
5082
5022
|
};
|
|
5083
5023
|
supportsStdinNotification = true;
|
|
5084
|
-
mcpToolPrefix = "mcp_chat_";
|
|
5085
|
-
usesSlockCliForCommunication = true;
|
|
5086
5024
|
busyDeliveryMode = "direct";
|
|
5087
5025
|
supportsNativeStandingPrompt = true;
|
|
5088
5026
|
probe() {
|
|
@@ -5129,7 +5067,7 @@ var CodexDriver = class {
|
|
|
5129
5067
|
initializeRequestId = null;
|
|
5130
5068
|
pendingThreadRequest = null;
|
|
5131
5069
|
initialTurnStarted = false;
|
|
5132
|
-
normalizer = new CodexEventNormalizer(
|
|
5070
|
+
normalizer = new CodexEventNormalizer();
|
|
5133
5071
|
async spawn(ctx) {
|
|
5134
5072
|
ensureGitRepoForCodex(ctx.workingDirectory);
|
|
5135
5073
|
const { spawnEnv } = await prepareCliTransport(ctx, { NO_COLOR: "1" });
|
|
@@ -5221,7 +5159,6 @@ var CodexDriver = class {
|
|
|
5221
5159
|
}
|
|
5222
5160
|
buildSystemPrompt(config, _agentId) {
|
|
5223
5161
|
return buildCliTransportSystemPrompt(config, {
|
|
5224
|
-
toolPrefix: "",
|
|
5225
5162
|
extraCriticalRules: [],
|
|
5226
5163
|
postStartupNotes: [
|
|
5227
5164
|
"**IMPORTANT**: Your process stays alive across turns. While you are working, Slock may write batched inbox-count notifications into the current turn; call `slock message check` at natural breakpoints to read the pending messages."
|
|
@@ -5265,9 +5202,9 @@ var CodexDriver = class {
|
|
|
5265
5202
|
return detectCodexModels();
|
|
5266
5203
|
}
|
|
5267
5204
|
};
|
|
5268
|
-
function detectCodexModels(home =
|
|
5269
|
-
const cachePath =
|
|
5270
|
-
const configPath =
|
|
5205
|
+
function detectCodexModels(home = os3.homedir()) {
|
|
5206
|
+
const cachePath = path6.join(home, ".codex", "models_cache.json");
|
|
5207
|
+
const configPath = path6.join(home, ".codex", "config.toml");
|
|
5271
5208
|
let models = [];
|
|
5272
5209
|
try {
|
|
5273
5210
|
const raw = readFileSync2(cachePath, "utf8");
|
|
@@ -5361,9 +5298,7 @@ var AntigravityDriver = class {
|
|
|
5361
5298
|
toLaunchSpec: (_modelId) => ({ args: [] })
|
|
5362
5299
|
};
|
|
5363
5300
|
supportsStdinNotification = false;
|
|
5364
|
-
mcpToolPrefix = "";
|
|
5365
5301
|
busyDeliveryMode = "none";
|
|
5366
|
-
usesSlockCliForCommunication = true;
|
|
5367
5302
|
sessionId = null;
|
|
5368
5303
|
sessionAnnounced = false;
|
|
5369
5304
|
probe() {
|
|
@@ -5411,7 +5346,6 @@ var AntigravityDriver = class {
|
|
|
5411
5346
|
}
|
|
5412
5347
|
buildSystemPrompt(config, _agentId) {
|
|
5413
5348
|
return buildCliTransportSystemPrompt(config, {
|
|
5414
|
-
toolPrefix: "",
|
|
5415
5349
|
extraCriticalRules: [],
|
|
5416
5350
|
postStartupNotes: [
|
|
5417
5351
|
"**Antigravity runtime note:** Slock launches you as a per-turn process. Complete the current wake using `slock` CLI commands, then stop; the daemon will restart you when new messages arrive."
|
|
@@ -5450,9 +5384,7 @@ var CopilotDriver = class {
|
|
|
5450
5384
|
toLaunchSpec: (modelId) => ({ args: ["--model", modelId] })
|
|
5451
5385
|
};
|
|
5452
5386
|
supportsStdinNotification = false;
|
|
5453
|
-
mcpToolPrefix = "";
|
|
5454
5387
|
busyDeliveryMode = "none";
|
|
5455
|
-
usesSlockCliForCommunication = true;
|
|
5456
5388
|
sessionId = null;
|
|
5457
5389
|
sessionAnnounced = false;
|
|
5458
5390
|
async spawn(ctx) {
|
|
@@ -5558,7 +5490,6 @@ var CopilotDriver = class {
|
|
|
5558
5490
|
}
|
|
5559
5491
|
buildSystemPrompt(config, _agentId) {
|
|
5560
5492
|
return buildCliTransportSystemPrompt(config, {
|
|
5561
|
-
toolPrefix: "",
|
|
5562
5493
|
extraCriticalRules: [],
|
|
5563
5494
|
postStartupNotes: [
|
|
5564
5495
|
"**Copilot runtime note:** Slock launches you as a per-turn process. Complete the current wake using `slock` CLI commands, then stop; the daemon will restart you when new messages arrive."
|
|
@@ -5595,9 +5526,7 @@ var CursorDriver = class {
|
|
|
5595
5526
|
toLaunchSpec: (modelId) => ({ args: ["--model", modelId] })
|
|
5596
5527
|
};
|
|
5597
5528
|
supportsStdinNotification = false;
|
|
5598
|
-
mcpToolPrefix = "mcp__chat__";
|
|
5599
5529
|
busyDeliveryMode = "none";
|
|
5600
|
-
usesSlockCliForCommunication = true;
|
|
5601
5530
|
async spawn(ctx) {
|
|
5602
5531
|
const args = [
|
|
5603
5532
|
"--print",
|
|
@@ -5683,7 +5612,6 @@ var CursorDriver = class {
|
|
|
5683
5612
|
}
|
|
5684
5613
|
buildSystemPrompt(config, _agentId) {
|
|
5685
5614
|
return buildCliTransportSystemPrompt(config, {
|
|
5686
|
-
toolPrefix: "mcp__chat__",
|
|
5687
5615
|
extraCriticalRules: [],
|
|
5688
5616
|
postStartupNotes: [
|
|
5689
5617
|
"**Cursor runtime note:** Slock launches you as a per-turn process. Complete the current wake using `slock` CLI commands, then stop; the daemon will restart you when new messages arrive."
|
|
@@ -5728,11 +5656,11 @@ function detectCursorModels(runCommand = runCursorModelsCommand) {
|
|
|
5728
5656
|
return parseCursorModelsOutput(String(result.stdout || ""));
|
|
5729
5657
|
}
|
|
5730
5658
|
function buildCursorModelProbeEnv(deps = {}) {
|
|
5731
|
-
return withWindowsUserEnvironment({
|
|
5659
|
+
return scrubDaemonChildEnv(withWindowsUserEnvironment({
|
|
5732
5660
|
...deps.env ?? process.env,
|
|
5733
5661
|
FORCE_COLOR: "0",
|
|
5734
5662
|
NO_COLOR: "1"
|
|
5735
|
-
}, deps);
|
|
5663
|
+
}, deps));
|
|
5736
5664
|
}
|
|
5737
5665
|
function runCursorModelsCommand() {
|
|
5738
5666
|
return spawnSync("cursor-agent", ["models"], {
|
|
@@ -5744,8 +5672,8 @@ function runCursorModelsCommand() {
|
|
|
5744
5672
|
|
|
5745
5673
|
// src/drivers/gemini.ts
|
|
5746
5674
|
import { execFileSync as execFileSync3, spawn as spawn6 } from "child_process";
|
|
5747
|
-
import { existsSync as
|
|
5748
|
-
import
|
|
5675
|
+
import { existsSync as existsSync5 } from "fs";
|
|
5676
|
+
import path7 from "path";
|
|
5749
5677
|
async function buildGeminiSpawnEnv(ctx, platform = process.platform) {
|
|
5750
5678
|
const { spawnEnv } = await prepareCliTransport(ctx, { NO_COLOR: "1" }, platform);
|
|
5751
5679
|
const launchEnvVars = runtimeConfigToLaunchFields(ctx.config).envVars;
|
|
@@ -5787,9 +5715,9 @@ function resolveGeminiSpawn(commandArgs, deps = {}) {
|
|
|
5787
5715
|
return { command: resolveCommandOnPath("gemini", deps) ?? "gemini", args: commandArgs };
|
|
5788
5716
|
}
|
|
5789
5717
|
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync3;
|
|
5790
|
-
const existsSyncFn = deps.existsSyncFn ??
|
|
5791
|
-
const env = deps.env ?? process.env;
|
|
5792
|
-
const winPath =
|
|
5718
|
+
const existsSyncFn = deps.existsSyncFn ?? existsSync5;
|
|
5719
|
+
const env = scrubDaemonChildEnv({ ...deps.env ?? process.env });
|
|
5720
|
+
const winPath = path7.win32;
|
|
5793
5721
|
let geminiEntry = null;
|
|
5794
5722
|
try {
|
|
5795
5723
|
const globalRoot = normalizeExecOutput2(execFileSyncFn("npm", ["root", "-g"], {
|
|
@@ -5843,9 +5771,7 @@ var GeminiDriver = class {
|
|
|
5843
5771
|
toLaunchSpec: (modelId) => modelId && modelId !== "default" ? { args: ["--model", modelId] } : { args: [] }
|
|
5844
5772
|
};
|
|
5845
5773
|
supportsStdinNotification = false;
|
|
5846
|
-
mcpToolPrefix = "";
|
|
5847
5774
|
busyDeliveryMode = "none";
|
|
5848
|
-
usesSlockCliForCommunication = true;
|
|
5849
5775
|
sessionId = null;
|
|
5850
5776
|
sessionAnnounced = false;
|
|
5851
5777
|
async spawn(ctx) {
|
|
@@ -5914,7 +5840,6 @@ var GeminiDriver = class {
|
|
|
5914
5840
|
}
|
|
5915
5841
|
buildSystemPrompt(config, _agentId) {
|
|
5916
5842
|
return buildCliTransportSystemPrompt(config, {
|
|
5917
|
-
toolPrefix: "",
|
|
5918
5843
|
extraCriticalRules: [],
|
|
5919
5844
|
postStartupNotes: [
|
|
5920
5845
|
"**Gemini runtime note:** Slock launches you as a per-turn process. Complete the current wake using `slock` CLI commands, then stop; the daemon will restart you when new messages arrive."
|
|
@@ -5928,12 +5853,15 @@ var GeminiDriver = class {
|
|
|
5928
5853
|
// src/drivers/kimi.ts
|
|
5929
5854
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
5930
5855
|
import { spawn as spawn7 } from "child_process";
|
|
5931
|
-
import { existsSync as
|
|
5932
|
-
import
|
|
5933
|
-
import
|
|
5856
|
+
import { chmodSync, existsSync as existsSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
5857
|
+
import os4 from "os";
|
|
5858
|
+
import path8 from "path";
|
|
5934
5859
|
var KIMI_WIRE_PROTOCOL_VERSION = "1.3";
|
|
5935
5860
|
var KIMI_SYSTEM_PROMPT_FILE = ".slock-kimi-system.md";
|
|
5936
5861
|
var KIMI_AGENT_FILE = ".slock-kimi-agent.yaml";
|
|
5862
|
+
var KIMI_GENERATED_CONFIG_FILE = ".slock-kimi-config.toml";
|
|
5863
|
+
var SLOCK_KIMI_CONFIG_CONTENT_ENV = "SLOCK_KIMI_CONFIG_CONTENT";
|
|
5864
|
+
var SLOCK_KIMI_CONFIG_FILE_ENV = "SLOCK_KIMI_CONFIG_FILE";
|
|
5937
5865
|
function parseToolArguments(raw) {
|
|
5938
5866
|
if (typeof raw !== "string") return raw;
|
|
5939
5867
|
try {
|
|
@@ -5942,6 +5870,73 @@ function parseToolArguments(raw) {
|
|
|
5942
5870
|
return raw;
|
|
5943
5871
|
}
|
|
5944
5872
|
}
|
|
5873
|
+
function readKimiConfigSource(home = os4.homedir(), env = process.env) {
|
|
5874
|
+
const inlineConfig = env[SLOCK_KIMI_CONFIG_CONTENT_ENV];
|
|
5875
|
+
if (inlineConfig && inlineConfig.trim()) {
|
|
5876
|
+
return {
|
|
5877
|
+
raw: inlineConfig,
|
|
5878
|
+
explicitPath: null,
|
|
5879
|
+
sourcePath: SLOCK_KIMI_CONFIG_CONTENT_ENV
|
|
5880
|
+
};
|
|
5881
|
+
}
|
|
5882
|
+
const explicitPath = env[SLOCK_KIMI_CONFIG_FILE_ENV];
|
|
5883
|
+
const configPath = explicitPath && explicitPath.trim() ? explicitPath : path8.join(home, ".kimi", "config.toml");
|
|
5884
|
+
try {
|
|
5885
|
+
return {
|
|
5886
|
+
raw: readFileSync3(configPath, "utf8"),
|
|
5887
|
+
explicitPath: explicitPath && explicitPath.trim() ? explicitPath : null,
|
|
5888
|
+
sourcePath: configPath
|
|
5889
|
+
};
|
|
5890
|
+
} catch {
|
|
5891
|
+
return {
|
|
5892
|
+
raw: null,
|
|
5893
|
+
explicitPath: explicitPath && explicitPath.trim() ? explicitPath : null,
|
|
5894
|
+
sourcePath: configPath
|
|
5895
|
+
};
|
|
5896
|
+
}
|
|
5897
|
+
}
|
|
5898
|
+
function buildKimiSpawnEnv(env = process.env) {
|
|
5899
|
+
const spawnEnv = { ...env, FORCE_COLOR: "0", NO_COLOR: "1" };
|
|
5900
|
+
delete spawnEnv[SLOCK_KIMI_CONFIG_CONTENT_ENV];
|
|
5901
|
+
delete spawnEnv[SLOCK_KIMI_CONFIG_FILE_ENV];
|
|
5902
|
+
return scrubDaemonChildEnv(spawnEnv);
|
|
5903
|
+
}
|
|
5904
|
+
function buildKimiEffectiveEnv(ctx, overrideEnv) {
|
|
5905
|
+
return {
|
|
5906
|
+
...process.env,
|
|
5907
|
+
...ctx.config.envVars || {},
|
|
5908
|
+
...overrideEnv || {}
|
|
5909
|
+
};
|
|
5910
|
+
}
|
|
5911
|
+
function buildKimiLaunchOptions(ctx, opts = {}) {
|
|
5912
|
+
const env = buildKimiEffectiveEnv(ctx, opts.env);
|
|
5913
|
+
const source = readKimiConfigSource(opts.home ?? os4.homedir(), env);
|
|
5914
|
+
const args = [];
|
|
5915
|
+
let configFilePath = null;
|
|
5916
|
+
let configContent = null;
|
|
5917
|
+
if (source.explicitPath) {
|
|
5918
|
+
configFilePath = source.explicitPath;
|
|
5919
|
+
} else if (source.raw !== null && source.sourcePath === SLOCK_KIMI_CONFIG_CONTENT_ENV) {
|
|
5920
|
+
configFilePath = path8.join(ctx.workingDirectory, KIMI_GENERATED_CONFIG_FILE);
|
|
5921
|
+
configContent = source.raw;
|
|
5922
|
+
if (opts.writeGeneratedConfig !== false) {
|
|
5923
|
+
writeFileSync3(configFilePath, source.raw, { encoding: "utf8", mode: 384 });
|
|
5924
|
+
chmodSync(configFilePath, 384);
|
|
5925
|
+
}
|
|
5926
|
+
}
|
|
5927
|
+
if (configFilePath) {
|
|
5928
|
+
args.push("--config-file", configFilePath);
|
|
5929
|
+
}
|
|
5930
|
+
if (ctx.config.model && ctx.config.model !== "default") {
|
|
5931
|
+
args.push("--model", ctx.config.model);
|
|
5932
|
+
}
|
|
5933
|
+
return {
|
|
5934
|
+
args,
|
|
5935
|
+
env: buildKimiSpawnEnv(env),
|
|
5936
|
+
configFilePath,
|
|
5937
|
+
configContent
|
|
5938
|
+
};
|
|
5939
|
+
}
|
|
5945
5940
|
function resolveKimiSpawn(commandArgs, deps = {}) {
|
|
5946
5941
|
return {
|
|
5947
5942
|
command: resolveCommandOnPath("kimi", deps) ?? "kimi",
|
|
@@ -5965,12 +5960,28 @@ var KimiDriver = class {
|
|
|
5965
5960
|
};
|
|
5966
5961
|
model = {
|
|
5967
5962
|
detectedModelsVerifiedAs: "launchable",
|
|
5968
|
-
toLaunchSpec: (modelId) =>
|
|
5963
|
+
toLaunchSpec: (modelId, ctx, opts) => {
|
|
5964
|
+
if (!ctx) return { args: ["--model", modelId] };
|
|
5965
|
+
const launchCtx = {
|
|
5966
|
+
...ctx,
|
|
5967
|
+
config: {
|
|
5968
|
+
...ctx.config,
|
|
5969
|
+
model: modelId
|
|
5970
|
+
}
|
|
5971
|
+
};
|
|
5972
|
+
const launch = buildKimiLaunchOptions(launchCtx, {
|
|
5973
|
+
home: opts?.home,
|
|
5974
|
+
writeGeneratedConfig: false
|
|
5975
|
+
});
|
|
5976
|
+
return {
|
|
5977
|
+
args: launch.args,
|
|
5978
|
+
env: launch.env,
|
|
5979
|
+
configFiles: launch.configFilePath ? [launch.configFilePath] : void 0
|
|
5980
|
+
};
|
|
5981
|
+
}
|
|
5969
5982
|
};
|
|
5970
5983
|
supportsStdinNotification = true;
|
|
5971
|
-
mcpToolPrefix = "";
|
|
5972
5984
|
busyDeliveryMode = "direct";
|
|
5973
|
-
usesSlockCliForCommunication = true;
|
|
5974
5985
|
sessionId = null;
|
|
5975
5986
|
sessionAnnounced = false;
|
|
5976
5987
|
promptRequestId = null;
|
|
@@ -5979,9 +5990,9 @@ var KimiDriver = class {
|
|
|
5979
5990
|
this.sessionId = ctx.config.sessionId || randomUUID2();
|
|
5980
5991
|
this.sessionAnnounced = false;
|
|
5981
5992
|
this.promptRequestId = randomUUID2();
|
|
5982
|
-
const systemPromptPath =
|
|
5983
|
-
const agentFilePath =
|
|
5984
|
-
if (!isResume || !
|
|
5993
|
+
const systemPromptPath = path8.join(ctx.workingDirectory, KIMI_SYSTEM_PROMPT_FILE);
|
|
5994
|
+
const agentFilePath = path8.join(ctx.workingDirectory, KIMI_AGENT_FILE);
|
|
5995
|
+
if (!isResume || !existsSync6(systemPromptPath)) {
|
|
5985
5996
|
writeFileSync3(systemPromptPath, ctx.prompt, "utf8");
|
|
5986
5997
|
}
|
|
5987
5998
|
writeFileSync3(agentFilePath, [
|
|
@@ -5991,21 +6002,23 @@ var KimiDriver = class {
|
|
|
5991
6002
|
` system_prompt_path: ./${KIMI_SYSTEM_PROMPT_FILE}`,
|
|
5992
6003
|
""
|
|
5993
6004
|
].join("\n"), "utf8");
|
|
6005
|
+
const launch = buildKimiLaunchOptions(ctx);
|
|
5994
6006
|
const args = [
|
|
5995
6007
|
"--wire",
|
|
5996
6008
|
"--yolo",
|
|
5997
6009
|
"--agent-file",
|
|
5998
6010
|
agentFilePath,
|
|
5999
6011
|
"--session",
|
|
6000
|
-
this.sessionId
|
|
6012
|
+
this.sessionId,
|
|
6013
|
+
...launch.args
|
|
6001
6014
|
];
|
|
6002
6015
|
const launchRuntimeFields = runtimeConfigToLaunchFields(ctx.config);
|
|
6003
6016
|
if (launchRuntimeFields.model && launchRuntimeFields.model !== "default") {
|
|
6004
6017
|
args.push("--model", launchRuntimeFields.model);
|
|
6005
6018
|
}
|
|
6006
6019
|
const spawnEnv = (await prepareCliTransport(ctx, { NO_COLOR: "1" })).spawnEnv;
|
|
6007
|
-
const
|
|
6008
|
-
const proc = spawn7(
|
|
6020
|
+
const spawnTarget = resolveKimiSpawn(args);
|
|
6021
|
+
const proc = spawn7(spawnTarget.command, spawnTarget.args, {
|
|
6009
6022
|
cwd: ctx.workingDirectory,
|
|
6010
6023
|
stdio: ["pipe", "pipe", "pipe"],
|
|
6011
6024
|
env: spawnEnv,
|
|
@@ -6013,7 +6026,7 @@ var KimiDriver = class {
|
|
|
6013
6026
|
// and has an 8191-character command-line limit. Kimi's official
|
|
6014
6027
|
// installer/uv entrypoint is an executable, so launch it directly and
|
|
6015
6028
|
// keep prompts on stdin / files instead of routing through cmd.exe.
|
|
6016
|
-
shell:
|
|
6029
|
+
shell: spawnTarget.shell
|
|
6017
6030
|
});
|
|
6018
6031
|
proc.stdin?.write(JSON.stringify({
|
|
6019
6032
|
jsonrpc: "2.0",
|
|
@@ -6116,7 +6129,6 @@ var KimiDriver = class {
|
|
|
6116
6129
|
}
|
|
6117
6130
|
buildSystemPrompt(config, _agentId) {
|
|
6118
6131
|
return buildCliTransportSystemPrompt(config, {
|
|
6119
|
-
toolPrefix: "",
|
|
6120
6132
|
extraCriticalRules: [],
|
|
6121
6133
|
postStartupNotes: [],
|
|
6122
6134
|
includeStdinNotificationSection: true,
|
|
@@ -6127,14 +6139,9 @@ var KimiDriver = class {
|
|
|
6127
6139
|
return detectKimiModels();
|
|
6128
6140
|
}
|
|
6129
6141
|
};
|
|
6130
|
-
function detectKimiModels(home =
|
|
6131
|
-
const
|
|
6132
|
-
|
|
6133
|
-
try {
|
|
6134
|
-
raw = readFileSync3(configPath, "utf8");
|
|
6135
|
-
} catch {
|
|
6136
|
-
return null;
|
|
6137
|
-
}
|
|
6142
|
+
function detectKimiModels(home = os4.homedir(), opts = {}) {
|
|
6143
|
+
const raw = readKimiConfigSource(home, opts.env).raw;
|
|
6144
|
+
if (raw === null) return null;
|
|
6138
6145
|
const models = [];
|
|
6139
6146
|
const sectionRe = /^\s*\[models(?:\.([^\]]+)|"\.[^"]+"|\."[^"]+")\s*\]\s*$/gm;
|
|
6140
6147
|
const lineRe = /^\s*\[models\.(.+?)\s*\]\s*$/gm;
|
|
@@ -6155,11 +6162,9 @@ function detectKimiModels(home = os3.homedir()) {
|
|
|
6155
6162
|
|
|
6156
6163
|
// src/drivers/opencode.ts
|
|
6157
6164
|
import { spawn as spawn8, spawnSync as spawnSync2 } from "child_process";
|
|
6158
|
-
import { existsSync as
|
|
6159
|
-
import
|
|
6160
|
-
import
|
|
6161
|
-
var CHAT_MCP_SERVER_NAME = "chat";
|
|
6162
|
-
var CHAT_MCP_TOOL_PREFIX = `${CHAT_MCP_SERVER_NAME}_`;
|
|
6165
|
+
import { existsSync as existsSync7, readFileSync as readFileSync4 } from "fs";
|
|
6166
|
+
import os5 from "os";
|
|
6167
|
+
import path9 from "path";
|
|
6163
6168
|
var SLOCK_AGENT_NAME = "slock";
|
|
6164
6169
|
var NO_MESSAGE_PROMPT = "No new messages are pending. Stop now.";
|
|
6165
6170
|
var FIRST_MESSAGE_TASK_PREFIX = "First message task (system-triggered):";
|
|
@@ -6187,8 +6192,8 @@ function parseUserOpenCodeConfig(ctx) {
|
|
|
6187
6192
|
const raw = runtimeConfigToLaunchFields(ctx.config).envVars?.OPENCODE_CONFIG_CONTENT;
|
|
6188
6193
|
return parseOpenCodeConfigContent(raw);
|
|
6189
6194
|
}
|
|
6190
|
-
function readLocalOpenCodeConfig(home =
|
|
6191
|
-
const configPath =
|
|
6195
|
+
function readLocalOpenCodeConfig(home = os5.homedir()) {
|
|
6196
|
+
const configPath = path9.join(home, ".config", "opencode", "opencode.json");
|
|
6192
6197
|
try {
|
|
6193
6198
|
return parseOpenCodeConfigContent(readFileSync4(configPath, "utf8"));
|
|
6194
6199
|
} catch {
|
|
@@ -6248,7 +6253,7 @@ function mergeOpenCodeConfigs(localConfig, envConfig) {
|
|
|
6248
6253
|
}
|
|
6249
6254
|
};
|
|
6250
6255
|
}
|
|
6251
|
-
function buildOpenCodeConfig(ctx, home =
|
|
6256
|
+
function buildOpenCodeConfig(ctx, home = os5.homedir()) {
|
|
6252
6257
|
const userConfig = mergeOpenCodeConfigs(readLocalOpenCodeConfig(home), parseUserOpenCodeConfig(ctx));
|
|
6253
6258
|
const userAgents = recordField(userConfig.agent);
|
|
6254
6259
|
const userSlockAgent = recordField(userAgents[SLOCK_AGENT_NAME]);
|
|
@@ -6266,7 +6271,7 @@ function buildOpenCodeConfig(ctx, home = os4.homedir()) {
|
|
|
6266
6271
|
mcp: recordField(userConfig.mcp)
|
|
6267
6272
|
};
|
|
6268
6273
|
}
|
|
6269
|
-
async function buildOpenCodeLaunchOptions(ctx, home =
|
|
6274
|
+
async function buildOpenCodeLaunchOptions(ctx, home = os5.homedir(), version = null) {
|
|
6270
6275
|
const slock = await prepareCliTransport(ctx, { NO_COLOR: "1" });
|
|
6271
6276
|
const config = buildOpenCodeConfig(ctx, home);
|
|
6272
6277
|
const env = {
|
|
@@ -6365,7 +6370,7 @@ function formatOpenCodeLabelToken(token) {
|
|
|
6365
6370
|
if (/^\d/.test(token)) return token;
|
|
6366
6371
|
return normalized.charAt(0).toUpperCase() + normalized.slice(1);
|
|
6367
6372
|
}
|
|
6368
|
-
function detectOpenCodeModels(home =
|
|
6373
|
+
function detectOpenCodeModels(home = os5.homedir(), runCommand = runOpenCodeModelsCommand) {
|
|
6369
6374
|
const commandResult = runCommand(home);
|
|
6370
6375
|
if (commandResult.error || commandResult.status !== 0) return null;
|
|
6371
6376
|
return parseOpenCodeModelsOutput(commandResult.stdout);
|
|
@@ -6374,7 +6379,7 @@ function runOpenCodeModelsCommand(home, deps = {}) {
|
|
|
6374
6379
|
const platform = deps.platform ?? process.platform;
|
|
6375
6380
|
const spawnSyncFn = deps.spawnSyncFn ?? spawnSync2;
|
|
6376
6381
|
const result = spawnSyncFn("opencode", ["models"], {
|
|
6377
|
-
env: { ...process.env, HOME: home, FORCE_COLOR: "0", NO_COLOR: "1" },
|
|
6382
|
+
env: scrubDaemonChildEnv({ ...process.env, HOME: home, FORCE_COLOR: "0", NO_COLOR: "1" }),
|
|
6378
6383
|
encoding: "utf8",
|
|
6379
6384
|
timeout: 5e3,
|
|
6380
6385
|
shell: platform === "win32"
|
|
@@ -6386,11 +6391,11 @@ function runOpenCodeModelsCommand(home, deps = {}) {
|
|
|
6386
6391
|
};
|
|
6387
6392
|
}
|
|
6388
6393
|
function isWindowsCommandShim(commandPath) {
|
|
6389
|
-
const ext =
|
|
6394
|
+
const ext = path9.win32.extname(commandPath).toLowerCase();
|
|
6390
6395
|
return ext === ".cmd" || ext === ".bat";
|
|
6391
6396
|
}
|
|
6392
6397
|
function opencodePackageEntryCandidates(packageRoot) {
|
|
6393
|
-
const winPath =
|
|
6398
|
+
const winPath = path9.win32;
|
|
6394
6399
|
return [
|
|
6395
6400
|
winPath.join(packageRoot, "bin", "opencode.exe"),
|
|
6396
6401
|
winPath.join(packageRoot, "bin", "opencode.js"),
|
|
@@ -6399,16 +6404,16 @@ function opencodePackageEntryCandidates(packageRoot) {
|
|
|
6399
6404
|
];
|
|
6400
6405
|
}
|
|
6401
6406
|
function openCodeSpecForEntry(entry, commandArgs) {
|
|
6402
|
-
if (
|
|
6407
|
+
if (path9.win32.extname(entry).toLowerCase() === ".exe") {
|
|
6403
6408
|
return { command: entry, args: commandArgs, shell: false };
|
|
6404
6409
|
}
|
|
6405
6410
|
return { command: process.execPath, args: [entry, ...commandArgs], shell: false };
|
|
6406
6411
|
}
|
|
6407
6412
|
function resolveWindowsOpenCodePackageEntry(commandPath, deps = {}) {
|
|
6408
|
-
const existsSyncFn = deps.existsSyncFn ??
|
|
6413
|
+
const existsSyncFn = deps.existsSyncFn ?? existsSync7;
|
|
6409
6414
|
const execFileSyncFn = deps.execFileSyncFn;
|
|
6410
6415
|
const env = deps.env ?? process.env;
|
|
6411
|
-
const winPath =
|
|
6416
|
+
const winPath = path9.win32;
|
|
6412
6417
|
const candidates = [];
|
|
6413
6418
|
if (execFileSyncFn) {
|
|
6414
6419
|
try {
|
|
@@ -6436,7 +6441,7 @@ function resolveWindowsOpenCodePackageEntry(commandPath, deps = {}) {
|
|
|
6436
6441
|
function extractWindowsShimTargets(commandPath, deps = {}) {
|
|
6437
6442
|
if (!isWindowsCommandShim(commandPath)) return [];
|
|
6438
6443
|
const readFileSyncFn = deps.readFileSyncFn ?? readFileSync4;
|
|
6439
|
-
const commandDir =
|
|
6444
|
+
const commandDir = path9.win32.dirname(commandPath);
|
|
6440
6445
|
let raw;
|
|
6441
6446
|
try {
|
|
6442
6447
|
raw = String(readFileSyncFn(commandPath, "utf8"));
|
|
@@ -6447,7 +6452,7 @@ function extractWindowsShimTargets(commandPath, deps = {}) {
|
|
|
6447
6452
|
const dp0Pattern = /%~dp0\\?([^"\r\n]*?opencode\.(?:exe|js|mjs|cjs))/gi;
|
|
6448
6453
|
for (const match of raw.matchAll(dp0Pattern)) {
|
|
6449
6454
|
const relative = match[1]?.replace(/^\\+/, "");
|
|
6450
|
-
if (relative) candidates.push(
|
|
6455
|
+
if (relative) candidates.push(path9.win32.normalize(path9.win32.join(commandDir, relative)));
|
|
6451
6456
|
}
|
|
6452
6457
|
return candidates;
|
|
6453
6458
|
}
|
|
@@ -6461,7 +6466,7 @@ function resolveOpenCodeSpawn(commandArgs, deps = {}) {
|
|
|
6461
6466
|
};
|
|
6462
6467
|
}
|
|
6463
6468
|
const command = resolveCommandOnPath("opencode", deps);
|
|
6464
|
-
if (command &&
|
|
6469
|
+
if (command && path9.win32.extname(command).toLowerCase() === ".exe") {
|
|
6465
6470
|
return { command, args: commandArgs, shell: false };
|
|
6466
6471
|
}
|
|
6467
6472
|
const packageEntry = resolveWindowsOpenCodePackageEntry(command, deps);
|
|
@@ -6486,7 +6491,6 @@ function isSystemFirstMessageTask(message) {
|
|
|
6486
6491
|
}
|
|
6487
6492
|
function buildOpenCodeSystemPrompt(config) {
|
|
6488
6493
|
return buildCliTransportSystemPrompt(config, {
|
|
6489
|
-
toolPrefix: CHAT_MCP_TOOL_PREFIX,
|
|
6490
6494
|
extraCriticalRules: [],
|
|
6491
6495
|
postStartupNotes: [
|
|
6492
6496
|
"**OpenCode runtime note:** Slock launches you as a per-turn process. Complete the current wake using `slock` CLI commands, then stop; the daemon will restart you when new messages arrive."
|
|
@@ -6531,11 +6535,9 @@ var OpenCodeDriver = class {
|
|
|
6531
6535
|
}
|
|
6532
6536
|
};
|
|
6533
6537
|
supportsStdinNotification = false;
|
|
6534
|
-
mcpToolPrefix = CHAT_MCP_TOOL_PREFIX;
|
|
6535
6538
|
busyDeliveryMode = "none";
|
|
6536
6539
|
terminateProcessOnTurnEnd = true;
|
|
6537
6540
|
deferSpawnUntilMessage = true;
|
|
6538
|
-
usesSlockCliForCommunication = true;
|
|
6539
6541
|
shouldDeferWakeMessage(message) {
|
|
6540
6542
|
return isSystemFirstMessageTask(message);
|
|
6541
6543
|
}
|
|
@@ -6569,7 +6571,7 @@ var OpenCodeDriver = class {
|
|
|
6569
6571
|
if (unsupportedMessage) {
|
|
6570
6572
|
throw new Error(unsupportedMessage);
|
|
6571
6573
|
}
|
|
6572
|
-
const launch = await buildOpenCodeLaunchOptions(ctx,
|
|
6574
|
+
const launch = await buildOpenCodeLaunchOptions(ctx, os5.homedir(), version);
|
|
6573
6575
|
const spawnSpec = resolveOpenCodeSpawn(launch.args);
|
|
6574
6576
|
const proc = spawn8(spawnSpec.command, spawnSpec.args, {
|
|
6575
6577
|
cwd: ctx.workingDirectory,
|
|
@@ -6636,8 +6638,8 @@ var OpenCodeDriver = class {
|
|
|
6636
6638
|
// src/drivers/pi.ts
|
|
6637
6639
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
6638
6640
|
import { EventEmitter } from "events";
|
|
6639
|
-
import { mkdirSync as
|
|
6640
|
-
import
|
|
6641
|
+
import { mkdirSync as mkdirSync3, readdirSync } from "fs";
|
|
6642
|
+
import path10 from "path";
|
|
6641
6643
|
import {
|
|
6642
6644
|
AuthStorage,
|
|
6643
6645
|
createBashTool,
|
|
@@ -6664,7 +6666,7 @@ function createPiSdkEventMappingState(sessionId = null) {
|
|
|
6664
6666
|
};
|
|
6665
6667
|
}
|
|
6666
6668
|
function buildPiSessionDir(workingDirectory) {
|
|
6667
|
-
return
|
|
6669
|
+
return path10.join(workingDirectory, PI_SESSION_DIR);
|
|
6668
6670
|
}
|
|
6669
6671
|
async function buildPiSpawnEnv(ctx) {
|
|
6670
6672
|
return (await prepareCliTransport(ctx, { NO_COLOR: "1" })).spawnEnv;
|
|
@@ -6686,7 +6688,7 @@ function findPiSessionFile(sessionDir, sessionId) {
|
|
|
6686
6688
|
}
|
|
6687
6689
|
const suffix = `_${sessionId}.jsonl`;
|
|
6688
6690
|
const match = entries.find((entry) => entry.endsWith(suffix));
|
|
6689
|
-
return match ?
|
|
6691
|
+
return match ? path10.join(sessionDir, match) : null;
|
|
6690
6692
|
}
|
|
6691
6693
|
function detectPiModelsFromRegistry(modelRegistry) {
|
|
6692
6694
|
const models = [];
|
|
@@ -6839,11 +6841,11 @@ var PI_IDLE_PROMPT_RETRY_MS = 25;
|
|
|
6839
6841
|
var PI_IDLE_PROMPT_MAX_WAIT_MS = 1e3;
|
|
6840
6842
|
async function createPiAgentSessionForContext(ctx, sessionId) {
|
|
6841
6843
|
const sessionDir = buildPiSessionDir(ctx.workingDirectory);
|
|
6842
|
-
|
|
6844
|
+
mkdirSync3(sessionDir, { recursive: true });
|
|
6843
6845
|
const spawnEnv = await buildPiSpawnEnv(ctx);
|
|
6844
6846
|
const agentDir = spawnEnv.PI_CODING_AGENT_DIR || getAgentDir();
|
|
6845
|
-
const authStorage = AuthStorage.create(
|
|
6846
|
-
const modelRegistry = ModelRegistry.create(authStorage,
|
|
6847
|
+
const authStorage = AuthStorage.create(path10.join(agentDir, "auth.json"));
|
|
6848
|
+
const modelRegistry = ModelRegistry.create(authStorage, path10.join(agentDir, "models.json"));
|
|
6847
6849
|
const launchRuntimeFields = runtimeConfigToLaunchFields(ctx.config);
|
|
6848
6850
|
const model = resolvePiModelFromRegistry(launchRuntimeFields.model, modelRegistry);
|
|
6849
6851
|
if (launchRuntimeFields.model && launchRuntimeFields.model !== "default" && !model) {
|
|
@@ -7086,9 +7088,7 @@ var PiDriver = class {
|
|
|
7086
7088
|
toLaunchSpec: (modelId) => ({ params: { model: modelId } })
|
|
7087
7089
|
};
|
|
7088
7090
|
supportsStdinNotification = true;
|
|
7089
|
-
mcpToolPrefix = "";
|
|
7090
7091
|
busyDeliveryMode = "direct";
|
|
7091
|
-
usesSlockCliForCommunication = true;
|
|
7092
7092
|
sessionId = null;
|
|
7093
7093
|
get currentSessionId() {
|
|
7094
7094
|
return this.sessionId;
|
|
@@ -7119,7 +7119,6 @@ var PiDriver = class {
|
|
|
7119
7119
|
}
|
|
7120
7120
|
buildSystemPrompt(config, _agentId) {
|
|
7121
7121
|
return buildCliTransportSystemPrompt(config, {
|
|
7122
|
-
toolPrefix: "",
|
|
7123
7122
|
extraCriticalRules: [],
|
|
7124
7123
|
postStartupNotes: [
|
|
7125
7124
|
"**Pi runtime note:** Slock keeps Pi running as a persistent SDK session. While you are working, Slock may send inbox-count notifications into the current turn; call `slock message check` at natural breakpoints."
|
|
@@ -7293,7 +7292,7 @@ function getDriver(runtimeId) {
|
|
|
7293
7292
|
|
|
7294
7293
|
// src/workspaces.ts
|
|
7295
7294
|
import { readdir, rm, stat } from "fs/promises";
|
|
7296
|
-
import
|
|
7295
|
+
import path11 from "path";
|
|
7297
7296
|
function isValidWorkspaceDirectoryName(directoryName) {
|
|
7298
7297
|
return !directoryName.includes("/") && !directoryName.includes("\\") && !directoryName.includes("..");
|
|
7299
7298
|
}
|
|
@@ -7301,7 +7300,7 @@ function resolveWorkspaceDirectoryPath(dataDir, directoryName) {
|
|
|
7301
7300
|
if (!isValidWorkspaceDirectoryName(directoryName)) {
|
|
7302
7301
|
return null;
|
|
7303
7302
|
}
|
|
7304
|
-
return
|
|
7303
|
+
return path11.join(dataDir, directoryName);
|
|
7305
7304
|
}
|
|
7306
7305
|
function emptyWorkspaceDirectorySummary(latestMtime = /* @__PURE__ */ new Date(0)) {
|
|
7307
7306
|
return {
|
|
@@ -7350,7 +7349,7 @@ async function summarizeWorkspaceDirectory(dirPath) {
|
|
|
7350
7349
|
return summary;
|
|
7351
7350
|
}
|
|
7352
7351
|
const childSummaries = await Promise.all(
|
|
7353
|
-
entries.map((entry) => summarizeWorkspaceEntry(
|
|
7352
|
+
entries.map((entry) => summarizeWorkspaceEntry(path11.join(dirPath, entry.name), entry))
|
|
7354
7353
|
);
|
|
7355
7354
|
for (const childSummary of childSummaries) {
|
|
7356
7355
|
summary = mergeWorkspaceDirectorySummaries(summary, childSummary);
|
|
@@ -7369,7 +7368,7 @@ async function scanWorkspaceDirectories(dataDir) {
|
|
|
7369
7368
|
if (!entry.isDirectory()) {
|
|
7370
7369
|
return null;
|
|
7371
7370
|
}
|
|
7372
|
-
const dirPath =
|
|
7371
|
+
const dirPath = path11.join(dataDir, entry.name);
|
|
7373
7372
|
try {
|
|
7374
7373
|
const summary = await summarizeWorkspaceDirectory(dirPath);
|
|
7375
7374
|
return {
|
|
@@ -7920,12 +7919,12 @@ function findSessionJsonl(root, predicate) {
|
|
|
7920
7919
|
for (const entry of entries) {
|
|
7921
7920
|
if (++visited > maxEntries) return null;
|
|
7922
7921
|
if (!entry.isFile() || !predicate(entry.name)) continue;
|
|
7923
|
-
return
|
|
7922
|
+
return path12.join(dir, entry.name);
|
|
7924
7923
|
}
|
|
7925
7924
|
for (const entry of entries) {
|
|
7926
7925
|
if (++visited > maxEntries) return null;
|
|
7927
7926
|
if (!entry.isDirectory()) continue;
|
|
7928
|
-
const found = visit(
|
|
7927
|
+
const found = visit(path12.join(dir, entry.name), depth - 1);
|
|
7929
7928
|
if (found) return found;
|
|
7930
7929
|
}
|
|
7931
7930
|
return null;
|
|
@@ -7938,9 +7937,9 @@ function safeSessionFilename(value) {
|
|
|
7938
7937
|
}
|
|
7939
7938
|
function writeRuntimeSessionHandoff(runtime, sessionId, fallbackDir) {
|
|
7940
7939
|
try {
|
|
7941
|
-
const dir =
|
|
7942
|
-
|
|
7943
|
-
const filePath =
|
|
7940
|
+
const dir = path12.join(fallbackDir, ".slock", "runtime-sessions");
|
|
7941
|
+
mkdirSync4(dir, { recursive: true });
|
|
7942
|
+
const filePath = path12.join(dir, `${runtime}-${safeSessionFilename(sessionId)}.jsonl`);
|
|
7944
7943
|
writeFileSync4(filePath, JSON.stringify({
|
|
7945
7944
|
type: "runtime_session_handoff",
|
|
7946
7945
|
runtime,
|
|
@@ -7959,8 +7958,20 @@ function writeRuntimeSessionHandoff(runtime, sessionId, fallbackDir) {
|
|
|
7959
7958
|
return null;
|
|
7960
7959
|
}
|
|
7961
7960
|
}
|
|
7962
|
-
function
|
|
7963
|
-
|
|
7961
|
+
function resolveRuntimeHomeDir(config, defaultHomeDir, workspacePath) {
|
|
7962
|
+
if (isClaudeCustomProviderConfig(config)) {
|
|
7963
|
+
return getClaudeProviderStatePaths(workspacePath).home;
|
|
7964
|
+
}
|
|
7965
|
+
return defaultHomeDir;
|
|
7966
|
+
}
|
|
7967
|
+
function ensureRuntimeHomeDir(config, defaultHomeDir, workspacePath) {
|
|
7968
|
+
if (isClaudeCustomProviderConfig(config)) {
|
|
7969
|
+
return ensureClaudeProviderStatePaths(workspacePath).home;
|
|
7970
|
+
}
|
|
7971
|
+
return defaultHomeDir;
|
|
7972
|
+
}
|
|
7973
|
+
function resolveRuntimeSessionRef(runtime, sessionId, homeDir = os6.homedir(), fallbackDir) {
|
|
7974
|
+
const directPath = path12.isAbsolute(sessionId) ? sessionId : null;
|
|
7964
7975
|
if (directPath) {
|
|
7965
7976
|
try {
|
|
7966
7977
|
if (statSync(directPath).isFile()) {
|
|
@@ -7969,7 +7980,7 @@ function resolveRuntimeSessionRef(runtime, sessionId, homeDir = os5.homedir(), f
|
|
|
7969
7980
|
} catch {
|
|
7970
7981
|
}
|
|
7971
7982
|
}
|
|
7972
|
-
const resolvedPath = runtime === "claude" ? findSessionJsonl(
|
|
7983
|
+
const resolvedPath = runtime === "claude" ? findSessionJsonl(path12.join(homeDir, ".claude", "projects"), (filename) => filename === `${sessionId}.jsonl`) : runtime === "codex" ? findSessionJsonl(path12.join(homeDir, ".codex", "sessions"), (filename) => filename.endsWith(".jsonl") && filename.includes(sessionId)) : null;
|
|
7973
7984
|
if (!resolvedPath && fallbackDir) {
|
|
7974
7985
|
const fallback = writeRuntimeSessionHandoff(runtime, sessionId, fallbackDir);
|
|
7975
7986
|
if (fallback) return fallback;
|
|
@@ -8030,13 +8041,7 @@ function formatThreadContextMessage(message) {
|
|
|
8030
8041
|
const senderType = formatVisibleActorType(message.sender_type);
|
|
8031
8042
|
return `- [msg=${msgId} time=${time}${senderType}] ${formatSenderHandle(message)}: ${message.content}`;
|
|
8032
8043
|
}
|
|
8033
|
-
function
|
|
8034
|
-
return `${driver?.mcpToolPrefix ?? ""}${name}`;
|
|
8035
|
-
}
|
|
8036
|
-
function communicationCommand(driver, name) {
|
|
8037
|
-
if (!driver?.usesSlockCliForCommunication) {
|
|
8038
|
-
return mcpToolName(driver, name);
|
|
8039
|
-
}
|
|
8044
|
+
function communicationCommand(name) {
|
|
8040
8045
|
switch (name) {
|
|
8041
8046
|
case "send_message":
|
|
8042
8047
|
return "slock message send";
|
|
@@ -8050,18 +8055,18 @@ function communicationCommand(driver, name) {
|
|
|
8050
8055
|
return `slock ${name.replace(/_/g, " ")}`;
|
|
8051
8056
|
}
|
|
8052
8057
|
}
|
|
8053
|
-
function dynamicReplyInstruction(
|
|
8054
|
-
return
|
|
8058
|
+
function dynamicReplyInstruction() {
|
|
8059
|
+
return "reply using `slock message send --target <exact target>`";
|
|
8055
8060
|
}
|
|
8056
|
-
function dynamicClaimInstruction(
|
|
8057
|
-
return
|
|
8061
|
+
function dynamicClaimInstruction() {
|
|
8062
|
+
return "claim the relevant task with `slock task claim`";
|
|
8058
8063
|
}
|
|
8059
|
-
function formatIncomingMessage(message
|
|
8064
|
+
function formatIncomingMessage(message) {
|
|
8060
8065
|
const threadJoinPrefix = message.thread_join_context ? [
|
|
8061
8066
|
`[Slock thread context: you were added to a new thread via @mention.]`,
|
|
8062
8067
|
`parent: ${message.thread_join_context.parent_target}`,
|
|
8063
8068
|
`thread: ${message.thread_join_context.thread_target}`,
|
|
8064
|
-
`suggested next step:
|
|
8069
|
+
`suggested next step: slock message read --channel "${message.thread_join_context.suggested_read_history_target}"`,
|
|
8065
8070
|
"",
|
|
8066
8071
|
"Parent message:",
|
|
8067
8072
|
formatThreadContextMessage(message.thread_join_context.parent_message),
|
|
@@ -9016,7 +9021,7 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
9016
9021
|
this.daemonApiKey = daemonApiKey;
|
|
9017
9022
|
this.serverUrl = opts.serverUrl;
|
|
9018
9023
|
this.dataDir = opts.dataDir || resolveSlockHomePath("agents");
|
|
9019
|
-
this.runtimeSessionHomeDir = opts.runtimeSessionHomeDir ||
|
|
9024
|
+
this.runtimeSessionHomeDir = opts.runtimeSessionHomeDir || os6.homedir();
|
|
9020
9025
|
this.driverResolver = opts.driverResolver || getDriver;
|
|
9021
9026
|
this.defaultAgentEnvVarsProvider = opts.defaultAgentEnvVarsProvider || null;
|
|
9022
9027
|
this.tracer = opts.tracer ?? noopTracer;
|
|
@@ -9918,7 +9923,7 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
9918
9923
|
);
|
|
9919
9924
|
wakeMessage = void 0;
|
|
9920
9925
|
}
|
|
9921
|
-
const agentDataDir =
|
|
9926
|
+
const agentDataDir = path12.join(this.dataDir, agentId);
|
|
9922
9927
|
await mkdir(agentDataDir, { recursive: true });
|
|
9923
9928
|
let runtimeConfig = withLocalRuntimeContext(config, agentId, agentDataDir);
|
|
9924
9929
|
const legacyRuntimeProfileControl = runtimeConfig.runtimeProfileControl?.kind === "migration" ? runtimeConfig.runtimeProfileControl : null;
|
|
@@ -9932,23 +9937,23 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
9932
9937
|
);
|
|
9933
9938
|
runtimeConfig = { ...runtimeConfig, runtimeProfileControl: null };
|
|
9934
9939
|
}
|
|
9935
|
-
const memoryMdPath =
|
|
9940
|
+
const memoryMdPath = path12.join(agentDataDir, "MEMORY.md");
|
|
9936
9941
|
try {
|
|
9937
9942
|
await access(memoryMdPath);
|
|
9938
9943
|
} catch {
|
|
9939
9944
|
const initialMemoryMd = buildInitialMemoryMd(runtimeConfig);
|
|
9940
9945
|
await writeFile(memoryMdPath, initialMemoryMd);
|
|
9941
9946
|
}
|
|
9942
|
-
const notesDir =
|
|
9947
|
+
const notesDir = path12.join(agentDataDir, "notes");
|
|
9943
9948
|
await mkdir(notesDir, { recursive: true });
|
|
9944
9949
|
if (getOnboardingSeedMode(config) === FIRST_CINDY_SEED_MODE) {
|
|
9945
9950
|
const seedFiles = buildOnboardingSeedFiles();
|
|
9946
9951
|
for (const { relativePath, content } of seedFiles) {
|
|
9947
|
-
const fullPath =
|
|
9952
|
+
const fullPath = path12.join(agentDataDir, relativePath);
|
|
9948
9953
|
try {
|
|
9949
9954
|
await access(fullPath);
|
|
9950
9955
|
} catch {
|
|
9951
|
-
await mkdir(
|
|
9956
|
+
await mkdir(path12.dirname(fullPath), { recursive: true });
|
|
9952
9957
|
await writeFile(fullPath, content);
|
|
9953
9958
|
}
|
|
9954
9959
|
}
|
|
@@ -9972,7 +9977,7 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
9972
9977
|
if (transientWakeMessage) {
|
|
9973
9978
|
prompt = `System notice received:
|
|
9974
9979
|
|
|
9975
|
-
${formatIncomingMessage(wakeMessage
|
|
9980
|
+
${formatIncomingMessage(wakeMessage)}
|
|
9976
9981
|
|
|
9977
9982
|
Respond as appropriate. Complete all your work before stopping.
|
|
9978
9983
|
${RESPONSE_TARGET_HINT}`;
|
|
@@ -10006,7 +10011,7 @@ Use the inbox/read commands at a natural breakpoint if you choose to inspect tho
|
|
|
10006
10011
|
}
|
|
10007
10012
|
prompt += `
|
|
10008
10013
|
|
|
10009
|
-
Use ${communicationCommand(
|
|
10014
|
+
Use ${communicationCommand("read_history")} to catch up on the channels listed above, then stop. Read each listed channel at most once unless a read fails. Do NOT call ${communicationCommand("check_messages")} in this mode. If the history reveals a direct request, assignment, @mention, review request, or task clearly addressed to you, switch into active handling instead of stopping: ${dynamicReplyInstruction()} and ${dynamicClaimInstruction()} before starting work. Otherwise, do NOT send any message in this mode. ${getMessageDeliveryText(driver)}`;
|
|
10010
10015
|
promptSource = "resume_unread_summary";
|
|
10011
10016
|
} else if (isResume) {
|
|
10012
10017
|
prompt = `No new messages while you were away. Nothing to do \u2014 just stop. ${getMessageDeliveryText(driver)}`;
|
|
@@ -11084,7 +11089,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
11084
11089
|
return true;
|
|
11085
11090
|
}
|
|
11086
11091
|
async resetWorkspace(agentId) {
|
|
11087
|
-
const agentDataDir =
|
|
11092
|
+
const agentDataDir = path12.join(this.dataDir, agentId);
|
|
11088
11093
|
try {
|
|
11089
11094
|
await rm2(agentDataDir, { recursive: true, force: true });
|
|
11090
11095
|
logger.info(`[Agent ${agentId}] Workspace reset complete (${agentDataDir})`);
|
|
@@ -11145,7 +11150,8 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
11145
11150
|
return result;
|
|
11146
11151
|
}
|
|
11147
11152
|
buildRuntimeProfileReport(agentId, config, sessionId, launchId) {
|
|
11148
|
-
const workspacePath =
|
|
11153
|
+
const workspacePath = path12.join(this.dataDir, agentId);
|
|
11154
|
+
const runtimeHomeDir = resolveRuntimeHomeDir(config, this.runtimeSessionHomeDir, workspacePath);
|
|
11149
11155
|
return {
|
|
11150
11156
|
agentId,
|
|
11151
11157
|
launchId,
|
|
@@ -11159,7 +11165,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
11159
11165
|
path: workspacePath,
|
|
11160
11166
|
reachable: true
|
|
11161
11167
|
},
|
|
11162
|
-
sessionRef: sessionId ? resolveRuntimeSessionRef(config.runtime, sessionId,
|
|
11168
|
+
sessionRef: sessionId ? resolveRuntimeSessionRef(config.runtime, sessionId, runtimeHomeDir, workspacePath) : null
|
|
11163
11169
|
}
|
|
11164
11170
|
};
|
|
11165
11171
|
}
|
|
@@ -11438,7 +11444,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
11438
11444
|
}
|
|
11439
11445
|
// Workspace file browsing
|
|
11440
11446
|
async getFileTree(agentId, dirPath) {
|
|
11441
|
-
const agentDir =
|
|
11447
|
+
const agentDir = path12.join(this.dataDir, agentId);
|
|
11442
11448
|
try {
|
|
11443
11449
|
await stat2(agentDir);
|
|
11444
11450
|
} catch {
|
|
@@ -11446,8 +11452,8 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
11446
11452
|
}
|
|
11447
11453
|
let targetDir = agentDir;
|
|
11448
11454
|
if (dirPath) {
|
|
11449
|
-
const resolved =
|
|
11450
|
-
if (!resolved.startsWith(agentDir +
|
|
11455
|
+
const resolved = path12.resolve(agentDir, dirPath);
|
|
11456
|
+
if (!resolved.startsWith(agentDir + path12.sep) && resolved !== agentDir) {
|
|
11451
11457
|
return [];
|
|
11452
11458
|
}
|
|
11453
11459
|
targetDir = resolved;
|
|
@@ -11455,14 +11461,14 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
11455
11461
|
return this.listDirectoryChildren(targetDir, agentDir);
|
|
11456
11462
|
}
|
|
11457
11463
|
async readFile(agentId, filePath) {
|
|
11458
|
-
const agentDir =
|
|
11459
|
-
const resolved =
|
|
11460
|
-
if (!resolved.startsWith(agentDir +
|
|
11464
|
+
const agentDir = path12.join(this.dataDir, agentId);
|
|
11465
|
+
const resolved = path12.resolve(agentDir, filePath);
|
|
11466
|
+
if (!resolved.startsWith(agentDir + path12.sep) && resolved !== agentDir) {
|
|
11461
11467
|
throw new Error("Access denied");
|
|
11462
11468
|
}
|
|
11463
11469
|
const info = await stat2(resolved);
|
|
11464
11470
|
if (info.isDirectory()) throw new Error("Cannot read a directory");
|
|
11465
|
-
const ext =
|
|
11471
|
+
const ext = path12.extname(resolved).toLowerCase();
|
|
11466
11472
|
if (WORKSPACE_TEXT_EXTENSIONS.has(ext) || ext === "") {
|
|
11467
11473
|
if (info.size > WORKSPACE_TEXT_FILE_MAX_BYTES) throw new Error("File too large");
|
|
11468
11474
|
const content = await readFile(resolved, "utf-8");
|
|
@@ -11495,15 +11501,17 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
11495
11501
|
};
|
|
11496
11502
|
async listSkills(agentId, runtimeHint) {
|
|
11497
11503
|
const agent = this.agents.get(agentId);
|
|
11498
|
-
const
|
|
11499
|
-
const
|
|
11500
|
-
const
|
|
11504
|
+
const idle = this.idleAgentConfigs.get(agentId);
|
|
11505
|
+
const config = agent?.config ?? idle?.config ?? null;
|
|
11506
|
+
const runtime = runtimeHint || config?.runtime || "claude";
|
|
11507
|
+
const workspaceDir = path12.join(this.dataDir, agentId);
|
|
11508
|
+
const home = config ? ensureRuntimeHomeDir(config, os6.homedir(), workspaceDir) : os6.homedir();
|
|
11501
11509
|
const paths = _AgentProcessManager.SKILL_PATHS[runtime] || _AgentProcessManager.SKILL_PATHS.claude;
|
|
11502
11510
|
const globalResults = await Promise.all(
|
|
11503
|
-
paths.global.map((p) => this.scanSkillsDir(
|
|
11511
|
+
paths.global.map((p) => this.scanSkillsDir(path12.join(home, p)))
|
|
11504
11512
|
);
|
|
11505
11513
|
const workspaceResults = await Promise.all(
|
|
11506
|
-
paths.workspace.map((p) => this.scanSkillsDir(
|
|
11514
|
+
paths.workspace.map((p) => this.scanSkillsDir(path12.join(workspaceDir, p)))
|
|
11507
11515
|
);
|
|
11508
11516
|
const dedup = (skills) => {
|
|
11509
11517
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -11532,7 +11540,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
11532
11540
|
const skills = [];
|
|
11533
11541
|
for (const entry of entries) {
|
|
11534
11542
|
if (entry.isDirectory() || entry.isSymbolicLink()) {
|
|
11535
|
-
const skillMd =
|
|
11543
|
+
const skillMd = path12.join(dir, entry.name, "SKILL.md");
|
|
11536
11544
|
try {
|
|
11537
11545
|
const content = await readFile(skillMd, "utf-8");
|
|
11538
11546
|
const skill = this.parseSkillMd(entry.name, content);
|
|
@@ -11543,7 +11551,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
11543
11551
|
} else if (entry.name.endsWith(".md")) {
|
|
11544
11552
|
const cmdName = entry.name.replace(/\.md$/, "");
|
|
11545
11553
|
try {
|
|
11546
|
-
const content = await readFile(
|
|
11554
|
+
const content = await readFile(path12.join(dir, entry.name), "utf-8");
|
|
11547
11555
|
const skill = this.parseSkillMd(cmdName, content);
|
|
11548
11556
|
skill.sourcePath = dir;
|
|
11549
11557
|
skills.push(skill);
|
|
@@ -12947,12 +12955,12 @@ ${formatAgentInboxDelta(inboxRows, { totalPendingMessages: inboxCount })}]`;
|
|
|
12947
12955
|
const traceSource = options.transient ? `stdin_${mode}_transient_delivery` : `stdin_${mode}_delivery`;
|
|
12948
12956
|
const prompt = formatRuntimeProfileControlPrompt(messages) ?? (messages.length === 1 ? `New message received:
|
|
12949
12957
|
|
|
12950
|
-
${formatIncomingMessage(messages[0]
|
|
12958
|
+
${formatIncomingMessage(messages[0])}
|
|
12951
12959
|
|
|
12952
12960
|
Respond as appropriate. Complete all your work before stopping.
|
|
12953
12961
|
${RESPONSE_TARGET_HINT}` : `New messages received:
|
|
12954
12962
|
|
|
12955
|
-
${messages.map((message) => formatIncomingMessage(message
|
|
12963
|
+
${messages.map((message) => formatIncomingMessage(message)).join("\n")}
|
|
12956
12964
|
|
|
12957
12965
|
Respond as appropriate. Complete all your work before stopping.
|
|
12958
12966
|
${RESPONSE_TARGET_HINT}`);
|
|
@@ -13023,8 +13031,8 @@ ${RESPONSE_TARGET_HINT}`);
|
|
|
13023
13031
|
const nodes = [];
|
|
13024
13032
|
for (const entry of entries) {
|
|
13025
13033
|
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
13026
|
-
const fullPath =
|
|
13027
|
-
const relativePath =
|
|
13034
|
+
const fullPath = path12.join(dir, entry.name);
|
|
13035
|
+
const relativePath = path12.relative(rootDir, fullPath);
|
|
13028
13036
|
let info;
|
|
13029
13037
|
try {
|
|
13030
13038
|
info = await stat2(fullPath);
|
|
@@ -13398,9 +13406,9 @@ var ReminderCache = class {
|
|
|
13398
13406
|
|
|
13399
13407
|
// src/machineLock.ts
|
|
13400
13408
|
import { createHash as createHash4, randomUUID as randomUUID4 } from "crypto";
|
|
13401
|
-
import { mkdirSync as
|
|
13402
|
-
import
|
|
13403
|
-
import
|
|
13409
|
+
import { mkdirSync as mkdirSync5, readFileSync as readFileSync5, rmSync as rmSync3, statSync as statSync2, writeFileSync as writeFileSync5 } from "fs";
|
|
13410
|
+
import os7 from "os";
|
|
13411
|
+
import path13 from "path";
|
|
13404
13412
|
var INCOMPLETE_LOCK_STALE_MS = 3e4;
|
|
13405
13413
|
var DaemonMachineLockConflictError = class extends Error {
|
|
13406
13414
|
code = "DAEMON_MACHINE_LOCK_HELD";
|
|
@@ -13422,7 +13430,7 @@ function resolveDefaultMachineStateRoot() {
|
|
|
13422
13430
|
return resolveSlockHomePath("machines");
|
|
13423
13431
|
}
|
|
13424
13432
|
function ownerPath(lockDir) {
|
|
13425
|
-
return
|
|
13433
|
+
return path13.join(lockDir, "owner.json");
|
|
13426
13434
|
}
|
|
13427
13435
|
function readOwner(lockDir) {
|
|
13428
13436
|
try {
|
|
@@ -13452,17 +13460,17 @@ function acquireDaemonMachineLock(options) {
|
|
|
13452
13460
|
const rootDir = options.rootDir ?? resolveDefaultMachineStateRoot();
|
|
13453
13461
|
const fingerprint = apiKeyFingerprint(options.apiKey);
|
|
13454
13462
|
const lockId = getDaemonMachineLockId(options.apiKey);
|
|
13455
|
-
const machineDir =
|
|
13456
|
-
const lockDir =
|
|
13463
|
+
const machineDir = path13.join(rootDir, lockId);
|
|
13464
|
+
const lockDir = path13.join(machineDir, "daemon.lock");
|
|
13457
13465
|
const token = randomUUID4();
|
|
13458
|
-
|
|
13466
|
+
mkdirSync5(machineDir, { recursive: true });
|
|
13459
13467
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
13460
13468
|
try {
|
|
13461
|
-
|
|
13469
|
+
mkdirSync5(lockDir);
|
|
13462
13470
|
const owner = {
|
|
13463
13471
|
pid: process.pid,
|
|
13464
13472
|
token,
|
|
13465
|
-
hostname:
|
|
13473
|
+
hostname: os7.hostname(),
|
|
13466
13474
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
13467
13475
|
serverUrl: options.serverUrl,
|
|
13468
13476
|
apiKeyFingerprint: fingerprint.slice(0, 16)
|
|
@@ -13513,8 +13521,8 @@ function acquireDaemonMachineLock(options) {
|
|
|
13513
13521
|
}
|
|
13514
13522
|
|
|
13515
13523
|
// src/localTraceSink.ts
|
|
13516
|
-
import { appendFileSync, mkdirSync as
|
|
13517
|
-
import
|
|
13524
|
+
import { appendFileSync, mkdirSync as mkdirSync6, readdirSync as readdirSync3, rmSync as rmSync4, statSync as statSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
13525
|
+
import path14 from "path";
|
|
13518
13526
|
var DEFAULT_MAX_FILE_BYTES = 5 * 1024 * 1024;
|
|
13519
13527
|
var DEFAULT_MAX_FILE_AGE_MS = 5 * 60 * 1e3;
|
|
13520
13528
|
var DEFAULT_MAX_FILES = 8;
|
|
@@ -13551,7 +13559,7 @@ var LocalRotatingTraceSink = class {
|
|
|
13551
13559
|
currentSize = 0;
|
|
13552
13560
|
sequence = 0;
|
|
13553
13561
|
constructor(options) {
|
|
13554
|
-
this.traceDir =
|
|
13562
|
+
this.traceDir = path14.join(options.machineDir, "traces");
|
|
13555
13563
|
this.maxFileBytes = Math.max(1024, Math.floor(options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES));
|
|
13556
13564
|
const baseAgeMs = Math.max(1e3, Math.floor(options.maxFileAgeMs ?? DEFAULT_MAX_FILE_AGE_MS));
|
|
13557
13565
|
const ageJitterMs = Math.max(0, Math.floor(options.maxFileAgeJitterMs ?? 0));
|
|
@@ -13577,11 +13585,11 @@ var LocalRotatingTraceSink = class {
|
|
|
13577
13585
|
return this.currentFile;
|
|
13578
13586
|
}
|
|
13579
13587
|
ensureFile(nextBytes) {
|
|
13580
|
-
|
|
13588
|
+
mkdirSync6(this.traceDir, { recursive: true, mode: 448 });
|
|
13581
13589
|
const nowMs = this.nowMsProvider();
|
|
13582
13590
|
const shouldRotateForAge = this.currentFileOpenedAtMs !== null && nowMs - this.currentFileOpenedAtMs >= this.maxFileAgeMs;
|
|
13583
13591
|
if (!this.currentFile || this.currentSize + nextBytes > this.maxFileBytes || shouldRotateForAge) {
|
|
13584
|
-
this.currentFile =
|
|
13592
|
+
this.currentFile = path14.join(
|
|
13585
13593
|
this.traceDir,
|
|
13586
13594
|
`daemon-trace-${safeTimestamp(nowMs)}-${process.pid}-${String(this.sequence++).padStart(4, "0")}.jsonl`
|
|
13587
13595
|
);
|
|
@@ -13596,7 +13604,7 @@ var LocalRotatingTraceSink = class {
|
|
|
13596
13604
|
const excess = files.length - this.maxFiles;
|
|
13597
13605
|
if (excess <= 0) return;
|
|
13598
13606
|
for (const file of files.slice(0, excess)) {
|
|
13599
|
-
rmSync4(
|
|
13607
|
+
rmSync4(path14.join(this.traceDir, file), { force: true });
|
|
13600
13608
|
}
|
|
13601
13609
|
}
|
|
13602
13610
|
};
|
|
@@ -13687,7 +13695,7 @@ function isDiagnosticErrorAttr(key) {
|
|
|
13687
13695
|
import { createHash as createHash6, randomUUID as randomUUID5 } from "crypto";
|
|
13688
13696
|
import { gzipSync } from "zlib";
|
|
13689
13697
|
import { mkdir as mkdir2, readFile as readFile2, readdir as readdir3, stat as stat3, writeFile as writeFile2 } from "fs/promises";
|
|
13690
|
-
import
|
|
13698
|
+
import path15 from "path";
|
|
13691
13699
|
|
|
13692
13700
|
// src/chatBridgeRequest.ts
|
|
13693
13701
|
var DEFAULT_CHAT_BRIDGE_TOOL_TIMEOUT_MS = Number.parseInt(
|
|
@@ -13787,8 +13795,8 @@ async function executeResponseRequest(url, init, {
|
|
|
13787
13795
|
}
|
|
13788
13796
|
|
|
13789
13797
|
// src/directUploadCapability.ts
|
|
13790
|
-
function joinUrl(base,
|
|
13791
|
-
return `${base.replace(/\/+$/, "")}${
|
|
13798
|
+
function joinUrl(base, path17) {
|
|
13799
|
+
return `${base.replace(/\/+$/, "")}${path17}`;
|
|
13792
13800
|
}
|
|
13793
13801
|
function jsonHeaders(apiKey) {
|
|
13794
13802
|
return {
|
|
@@ -14007,7 +14015,7 @@ var DaemonTraceBundleUploader = class {
|
|
|
14007
14015
|
}, nextMs);
|
|
14008
14016
|
}
|
|
14009
14017
|
async findUploadCandidates() {
|
|
14010
|
-
const traceDir =
|
|
14018
|
+
const traceDir = path15.join(this.options.machineDir, "traces");
|
|
14011
14019
|
let names;
|
|
14012
14020
|
try {
|
|
14013
14021
|
names = await readdir3(traceDir);
|
|
@@ -14019,8 +14027,8 @@ var DaemonTraceBundleUploader = class {
|
|
|
14019
14027
|
const currentFile = this.options.currentFileProvider?.();
|
|
14020
14028
|
const candidates = [];
|
|
14021
14029
|
for (const name of names.filter((entry) => entry.startsWith("daemon-trace-") && entry.endsWith(".jsonl")).sort()) {
|
|
14022
|
-
const file =
|
|
14023
|
-
if (currentFile &&
|
|
14030
|
+
const file = path15.join(traceDir, name);
|
|
14031
|
+
if (currentFile && path15.resolve(file) === path15.resolve(currentFile)) continue;
|
|
14024
14032
|
if (await this.isUploaded(file)) continue;
|
|
14025
14033
|
try {
|
|
14026
14034
|
const info = await stat3(file);
|
|
@@ -14094,8 +14102,8 @@ var DaemonTraceBundleUploader = class {
|
|
|
14094
14102
|
}
|
|
14095
14103
|
}
|
|
14096
14104
|
uploadStatePath(file) {
|
|
14097
|
-
const stateDir =
|
|
14098
|
-
return
|
|
14105
|
+
const stateDir = path15.join(this.options.machineDir, "trace-uploads");
|
|
14106
|
+
return path15.join(stateDir, `${path15.basename(file)}.uploaded.json`);
|
|
14099
14107
|
}
|
|
14100
14108
|
async isUploaded(file) {
|
|
14101
14109
|
try {
|
|
@@ -14107,9 +14115,9 @@ var DaemonTraceBundleUploader = class {
|
|
|
14107
14115
|
}
|
|
14108
14116
|
async markUploaded(file, metadata) {
|
|
14109
14117
|
const stateFile = this.uploadStatePath(file);
|
|
14110
|
-
await mkdir2(
|
|
14118
|
+
await mkdir2(path15.dirname(stateFile), { recursive: true, mode: 448 });
|
|
14111
14119
|
await writeFile2(stateFile, `${JSON.stringify({
|
|
14112
|
-
file:
|
|
14120
|
+
file: path15.basename(file),
|
|
14113
14121
|
uploadedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
14114
14122
|
...metadata
|
|
14115
14123
|
}, null, 2)}
|
|
@@ -14176,7 +14184,7 @@ var DAEMON_CORE_TRACE_ATTR_CONTRACTS = {
|
|
|
14176
14184
|
spanAttrs: ["running_agents_count", "idle_agents_count"]
|
|
14177
14185
|
}
|
|
14178
14186
|
};
|
|
14179
|
-
var DAEMON_CLI_USAGE =
|
|
14187
|
+
var DAEMON_CLI_USAGE = `Usage: slock-daemon --server-url <url> (--api-key <key> or ${DAEMON_API_KEY_ENV}=<key>)`;
|
|
14180
14188
|
var RunnerCredentialMintError2 = class extends Error {
|
|
14181
14189
|
code;
|
|
14182
14190
|
retryable;
|
|
@@ -14212,9 +14220,9 @@ function runnerCredentialErrorDetail2(error) {
|
|
|
14212
14220
|
async function waitForRunnerCredentialRetry2() {
|
|
14213
14221
|
await new Promise((resolve) => setTimeout(resolve, RUNNER_CREDENTIAL_MINT_RETRY_DELAY_MS2));
|
|
14214
14222
|
}
|
|
14215
|
-
function parseDaemonCliArgs(args) {
|
|
14223
|
+
function parseDaemonCliArgs(args, env = {}) {
|
|
14216
14224
|
let serverUrl = "";
|
|
14217
|
-
let apiKey = "";
|
|
14225
|
+
let apiKey = env[DAEMON_API_KEY_ENV] ?? "";
|
|
14218
14226
|
for (let i = 0; i < args.length; i++) {
|
|
14219
14227
|
if (args[i] === "--server-url" && args[i + 1]) serverUrl = args[++i];
|
|
14220
14228
|
if (args[i] === "--api-key" && args[i + 1]) apiKey = args[++i];
|
|
@@ -14231,13 +14239,13 @@ function readDaemonVersion(moduleUrl = import.meta.url) {
|
|
|
14231
14239
|
}
|
|
14232
14240
|
}
|
|
14233
14241
|
function resolveSlockCliPath(moduleUrl = import.meta.url) {
|
|
14234
|
-
const thisDir =
|
|
14235
|
-
const bundledDistPath =
|
|
14242
|
+
const thisDir = path16.dirname(fileURLToPath(moduleUrl));
|
|
14243
|
+
const bundledDistPath = path16.resolve(thisDir, "cli", "index.js");
|
|
14236
14244
|
try {
|
|
14237
14245
|
accessSync(bundledDistPath);
|
|
14238
14246
|
return bundledDistPath;
|
|
14239
14247
|
} catch {
|
|
14240
|
-
const workspaceDistPath =
|
|
14248
|
+
const workspaceDistPath = path16.resolve(thisDir, "..", "..", "cli", "dist", "index.js");
|
|
14241
14249
|
accessSync(workspaceDistPath);
|
|
14242
14250
|
return workspaceDistPath;
|
|
14243
14251
|
}
|
|
@@ -14426,7 +14434,7 @@ var DaemonCore = class {
|
|
|
14426
14434
|
}
|
|
14427
14435
|
resolveMachineStateRoot() {
|
|
14428
14436
|
if (this.options.machineStateDir) return this.options.machineStateDir;
|
|
14429
|
-
if (this.options.dataDir) return
|
|
14437
|
+
if (this.options.dataDir) return path16.join(path16.dirname(this.options.dataDir), "machines");
|
|
14430
14438
|
return resolveDefaultMachineStateRoot();
|
|
14431
14439
|
}
|
|
14432
14440
|
shouldEnableLocalTrace() {
|
|
@@ -14453,7 +14461,7 @@ var DaemonCore = class {
|
|
|
14453
14461
|
sink: this.localTraceSink
|
|
14454
14462
|
}));
|
|
14455
14463
|
this.agentManager.setTracer(this.tracer);
|
|
14456
|
-
this.agentManager.setCliTransportTraceDir(
|
|
14464
|
+
this.agentManager.setCliTransportTraceDir(path16.join(machineDir, "traces"));
|
|
14457
14465
|
}
|
|
14458
14466
|
installTraceBundleUploader(machineDir) {
|
|
14459
14467
|
if (!this.shouldEnableLocalTrace()) return;
|
|
@@ -14930,8 +14938,8 @@ var DaemonCore = class {
|
|
|
14930
14938
|
capabilities: ["agent:start", "agent:stop", "agent:deliver", "workspace:files"],
|
|
14931
14939
|
runtimes,
|
|
14932
14940
|
runningAgents: runningAgentIds,
|
|
14933
|
-
hostname: this.options.hostname ??
|
|
14934
|
-
os: this.options.osDescription ?? `${
|
|
14941
|
+
hostname: this.options.hostname ?? os8.hostname(),
|
|
14942
|
+
os: this.options.osDescription ?? `${os8.platform()} ${os8.arch()}`,
|
|
14935
14943
|
daemonVersion: this.daemonVersion,
|
|
14936
14944
|
...this.computerVersion ? { computerVersion: this.computerVersion } : {}
|
|
14937
14945
|
});
|
|
@@ -14995,6 +15003,8 @@ var DaemonCore = class {
|
|
|
14995
15003
|
};
|
|
14996
15004
|
|
|
14997
15005
|
export {
|
|
15006
|
+
DAEMON_API_KEY_ENV,
|
|
15007
|
+
scrubDaemonAuthEnv,
|
|
14998
15008
|
subscribeDaemonLogs,
|
|
14999
15009
|
resolveWorkspaceDirectoryPath,
|
|
15000
15010
|
scanWorkspaceDirectories,
|