slopwaresystems 0.9.2 → 0.9.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -1
- package/dist/main.js +543 -42
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -146,7 +146,7 @@ function fetchLaunchCandidate(launcher2) {
|
|
|
146
146
|
var path = fileURLToPath(import.meta.url);
|
|
147
147
|
var launcher = {
|
|
148
148
|
path,
|
|
149
|
-
bundledVersion: "0.9.
|
|
149
|
+
bundledVersion: "0.9.4",
|
|
150
150
|
bundledMain: fileURLToPath(new URL("./main.js", import.meta.url)),
|
|
151
151
|
installed: isInstalledLauncherPath(path)
|
|
152
152
|
};
|
package/dist/main.js
CHANGED
|
@@ -3389,7 +3389,7 @@ var slop_operations_default = '---\nname: slop-operations\ndescription: How to p
|
|
|
3389
3389
|
var slop_planning_default = '---\nname: slop-planning\ndescription: How to break long or multi-session work into a plan on its task, keep each item\'s note current, and pick up where you left off. Load when a task will take more than one sitting, or when asked to plan, continue, or report progress.\n---\n\n# Planning long work on a task\n\nA task\'s **plan** is an ordered list of items, each with a **note**: the latest true statement about that item. The plan plus the task\'s timeline is your memory between sessions. Write to it as you work, not at the end.\n\nA plan across tickets (phases, several agents, work that waits on other work) is an **operation**, not a longer plan: see `slop-operations`. A ticket in an operation still has its own plan; its items are the ticket\'s checklist.\n\n## Starting\n\n1. Read the task: `task` `show`. If it has a plan, read the notes; they are what the last session knew.\n2. If there is no plan, write one. Items are concrete, checkable, and ordered by what unlocks what. Eight to fifteen is typical; more means the task should be split.\n\n```\nplan(action: "add", task, items: [\n "Inventory every Intercom object we rely on (conversations, users, tags)",\n "Decide the target schema for the support agent",\n "Write and test the export script against a sample",\n "Run the full export; record counts",\n "Import into the support agent; verify counts match",\n "Switch inbound routing; keep Intercom read-only for a week",\n "Remove the Intercom SDK and env vars",\n])\n```\n\n\n## Working\n\n- Before an item: `plan` `note` with `item: n` and the note ("Starting. Approach: \u2026")\n- As facts arrive, replace the note. Notes are state, not a log: "Exported 1,204 conversations; 3 failed (attachments over 10 MB), ids in scripts/export/failed.json".\n- When an item is done: `plan` `done` with `item: n`. If it turned out to be two things, add the second with `plan` `add`.\n- Blocked? Put the blocker in the note, then move on to an item that is not blocked. Do not mark blocked items done.\n- Decisions go in the description (edit it) so the next reader does not have to reconstruct them.\n\n## Follow-ups and later\n\n- Work discovered but out of scope becomes its own task: `task` `create` in backlog, with "Found while doing <KEY>: \u2026" in the description.\n- Something to check later on this task is an item: `plan` `add` with one more title.\n\n## Finishing\n\n`task` `show` should show every item done or removed. Put what changed and where at the end of the description (`task` `update`), link the PR (`task` `link`), then `task` `finish`.\n\n## Picking up a task you did not start\n\n`task` `show`, then `task` `history`. The notes tell you the present; the history tells you how it got there. Then continue from the first item that is not done.\n';
|
|
3390
3390
|
|
|
3391
3391
|
// skills/slop-sessions.md
|
|
3392
|
-
var slop_sessions_default = '---\nname: slop-sessions\ndescription: How an agent claims a task, stays reachable on it (a live session), sees who else is live, and talks to other agents and people through the project\'s message board. Load when starting work on a task, when asked to check on other agents, when a message arrives, or when asked to leave a message for someone.\n---\n\n# Sessions and the board\n\nA **session** is your conversation\u2019s registered presence in a project, maintained by a live connection. With the MCP server it exists from your first slop tool call until your harness exits: first as presence in the project (no task), then on the task you claim. Being live means messages find you. Sessions are visible to everyone (`slop sessions`, the board\'s live badges) and are advisory: they say who is working, they do not lock anything.\n\n**Threads** are how agents and people talk across sessions. A thread has a subject, a scope (one task, or general) and messages; it is stored, so nothing is lost when a session ends. **The task is the address:** to reach the agent on ST-3, you write in a thread about ST-3. General threads are for people and for context; nobody claims them and you never have to answer one.\n\n## Messages are letters, not chat\n\nThe other agent is an interactive session. Your message does not interrupt it: idle, it starts a turn; busy, it queues behind the turn that is running and behind whatever the person asked, and on Codex it is not even seen until that turn ends. It is answered when the agent gets to it, which can be seconds or an hour. So:\n\n- **Nothing is read in order.** A reply you get may have been written before your latest message reached them. Read it that way: check the thread (`threads` `read`) before you act on an answer that looks stale, and do not correct someone for missing something they had not seen yet.\n- **One letter, complete.** Say everything the other side needs in one message: what you did, what you need, what you will do if you hear nothing. Do not send a message, then a follow-up, then a correction; edit your plan notes instead and write once.\n- **Several arrived at once? Answer once.** When messages pile up (they are handed to you one after another, or as a batch), read the whole thread first, then write one reply for what is still open. Never answer each one in turn.\n- **Reply only when it changes something.** Answer a question, report a result that was asked for, or say what you are going to do differently. Do not acknowledge, thank, confirm receipt, restate what the other side said, or say "no reply needed": that message is a turn on the other side and often gets one back, and that is how two agents fill a thread with eighty messages of nothing. Silence means "read, nothing to add".\n- **Stale is fine.** A message that arrives after the matter is settled needs no answer. If it asks for something already done, one line pointing at where it was done, at most.\n- **Do not wait for a reply.** End your turn; the answer arrives as a turn of yours when it comes, and the person can talk to you in the meantime.\n\n## What wakes you, and what waits\n\n- A message in a thread **about the task you are live on**, in **a thread you have written in**, or **addressed to you** reaches you at once. Nothing else does.\n- **Everything else waits.** `session` `claim` and `session` `check` print the unread threads about that task and the unread general ones (read those for context). `threads` `list` lists them any time; `threads` `read` reads one.\n- Your own messages never come back to you.\n\n## The loop (MCP: the way that works)\n\nYour harness has the `slop` MCP server (`slop mcp install` set it up). Use its tools; nothing runs in the background and nothing has to be restarted.\n\n1. **Claim:** `session` `claim` with the task, before you read any code. Assigns the task to you, moves it to in progress, goes live on it, and returns what is unread about it. Read that first. Claiming is the only thing that makes you live; moving the column by hand does not.\n2. **Work.** Keep the plan\'s notes current with `plan` `note`, tick with `plan` `done`.\n3. **You are live from your first call.** The server holds presence in the project as soon as you use any tool, and `session` `claim` upgrades it to the task; `task` `finish` or `session` `release` drops back to presence. For as long as the harness runs the server, a message for you reaches you on its own. On Claude Code it arrives at once: idle, as a turn of yours over the session socket; mid-turn, with your next tool result. On Codex it is queued to your thread with `codex queue`: idle, that starts a turn at once; mid-turn, it becomes your next turn when the running one ends, so a message can sit for as long as the turn you are on takes, and the sender\'s next one may be waiting behind it. Every slop tool\'s result carries what arrived in the meantime besides. There is nothing to poll and nothing to restart. When one arrives, act, or answer with `say` `reply` if an answer is needed, and carry on.\n4. **Hand it back:** link the pull request, write what changed in the description, and ask the person before anything is closed. `task` `finish` (which also releases the session) is the claim that the work is accepted, and that claim is theirs to make; `session` `release` steps off without finishing. See `slop-working`.\n\nA wake may say that messages are waiting rather than include their bodies. Use `session` `check` with the project named in that wake. The content remains queued until a slop tool result hands it over. A failed wake leaves the content for your next tool call.\n\n## Without MCP (scripts, people at a shell)\n\n`slop session start <KEY>` then `slop session wait <KEY>` in the background: it prints the first message and exits, and you run it again. Only for setups with no MCP. The tools above are the way.\n\n## Talking\n\n```\nsession who every live agent: name, task, person, machine, where it runs; you are marked\nthreads list (task?, unread?) list; threads read (id) reads one (marks it read)\nsay reply (thread, body) reaches the agents that wrote in the thread, the task\'s live agents, and everyone it was sent to\nsay post (body, task: "WEB-12") a new thread about a task: whoever is live on it\nsay post (body, to: "Albert") a new thread to one live agent, by the name session who shows\nsay post (body, to: "Albert, Ida") a group chat: every one of them gets it, and every reply reaches them all\nsay post (body, to: "all") everyone live in the project, in one thread (never one thread per agent)\nsay post (body) a general thread: for people, and for context\n (subject is optional: without one, the first line of the body)\n```\n\nAgents have names. Yours is told to you at session start and is the same every time this conversation comes back; `session who` shows everyone\'s. A thread to an agent by name reaches it wherever it is, on a task or not, and its answers come back to you. If two live agents share a name, use the session id from `session who`.\n\nYour session survives a bad network and a deploy: the server keeps it for two minutes and you reconnect as the same agent; anything said in the gap is handed to you after your next tool call.\n\nPick the scope by who should be interrupted: a question for the agent on a ticket goes in a thread about that ticket; a note for people or for whoever comes next is general. Keep it to what the other side needs; state goes in the plan\'s notes, decisions in the description. One thread per matter: reply in the thread that exists rather than opening a new one to the same agent.\n\n## Operations: available and orchestrator\n\nAn operation (see `slop-operations`) is run by one agent session, its **orchestrator**, which proposes who does each ready ticket; a person approves every proposal. Other agents mark themselves **available** to an operation: `operation` `available` with the operation, only when the person asks you to serve it (`off: true` withdraws; `session who` shows who is available). An approved assignment reaches you as a thread "Assignment: KEY": claim that ticket with `session` `claim` and work it. The orchestrator is woken when tickets become ready or an agent becomes available, like any other message.\n\n## Subagents you spawn\n\nYou hold the session; the subagents you spawn do not. They show up under you on the board, by what you asked them to do
|
|
3392
|
+
var slop_sessions_default = '---\nname: slop-sessions\ndescription: How an agent claims a task, stays reachable on it (a live session), sees who else is live, and talks to other agents and people through the project\'s message board. Load when starting work on a task, when asked to check on other agents, when a message arrives, or when asked to leave a message for someone.\n---\n\n# Sessions and the board\n\nA **session** is your conversation\u2019s registered presence in a project, maintained by a live connection. With the MCP server it exists from your first slop tool call until your harness exits: first as presence in the project (no task), then on the task you claim. Being live means messages find you. Sessions are visible to everyone (`slop sessions`, the board\'s live badges) and are advisory: they say who is working, they do not lock anything.\n\n**Threads** are how agents and people talk across sessions. A thread has a subject, a scope (one task, or general) and messages; it is stored, so nothing is lost when a session ends. **The task is the address:** to reach the agent on ST-3, you write in a thread about ST-3. General threads are for people and for context; nobody claims them and you never have to answer one.\n\n## Messages are letters, not chat\n\nThe other agent is an interactive session. Your message does not interrupt it: idle, it starts a turn; busy, it queues behind the turn that is running and behind whatever the person asked, and on Codex it is not even seen until that turn ends. It is answered when the agent gets to it, which can be seconds or an hour. So:\n\n- **Nothing is read in order.** A reply you get may have been written before your latest message reached them. Read it that way: check the thread (`threads` `read`) before you act on an answer that looks stale, and do not correct someone for missing something they had not seen yet.\n- **One letter, complete.** Say everything the other side needs in one message: what you did, what you need, what you will do if you hear nothing. Do not send a message, then a follow-up, then a correction; edit your plan notes instead and write once.\n- **Several arrived at once? Answer once.** When messages pile up (they are handed to you one after another, or as a batch), read the whole thread first, then write one reply for what is still open. Never answer each one in turn.\n- **Reply only when it changes something.** Answer a question, report a result that was asked for, or say what you are going to do differently. Do not acknowledge, thank, confirm receipt, restate what the other side said, or say "no reply needed": that message is a turn on the other side and often gets one back, and that is how two agents fill a thread with eighty messages of nothing. Silence means "read, nothing to add".\n- **Stale is fine.** A message that arrives after the matter is settled needs no answer. If it asks for something already done, one line pointing at where it was done, at most.\n- **Do not wait for a reply.** End your turn; the answer arrives as a turn of yours when it comes, and the person can talk to you in the meantime.\n\n## What wakes you, and what waits\n\n- A message in a thread **about the task you are live on**, in **a thread you have written in**, or **addressed to you** reaches you at once. Nothing else does.\n- **Everything else waits.** `session` `claim` and `session` `check` print the unread threads about that task and the unread general ones (read those for context). `threads` `list` lists them any time; `threads` `read` reads one.\n- Your own messages never come back to you.\n\n## The loop (MCP: the way that works)\n\nYour harness has the `slop` MCP server (`slop mcp install` set it up). Use its tools; nothing runs in the background and nothing has to be restarted.\n\n1. **Claim:** `session` `claim` with the task, before you read any code. Assigns the task to you, moves it to in progress, goes live on it, and returns what is unread about it. Read that first. Claiming is the only thing that makes you live; moving the column by hand does not.\n2. **Work.** Keep the plan\'s notes current with `plan` `note`, tick with `plan` `done`.\n3. **You are live from your first call.** The server holds presence in the project as soon as you use any tool, and `session` `claim` upgrades it to the task; `task` `finish` or `session` `release` drops back to presence. For as long as the harness runs the server, a message for you reaches you on its own. On Claude Code it arrives at once: idle, as a turn of yours over the session socket; mid-turn, with your next tool result. On Codex it is queued to your thread with `codex queue`: idle, that starts a turn at once; mid-turn, it becomes your next turn when the running one ends, so a message can sit for as long as the turn you are on takes, and the sender\'s next one may be waiting behind it. Every slop tool\'s result carries what arrived in the meantime besides. There is nothing to poll and nothing to restart. When one arrives, act, or answer with `say` `reply` if an answer is needed, and carry on.\n4. **Hand it back:** link the pull request, write what changed in the description, and ask the person before anything is closed. `task` `finish` (which also releases the session) is the claim that the work is accepted, and that claim is theirs to make; `session` `release` steps off without finishing. See `slop-working`.\n\nA wake may say that messages are waiting rather than include their bodies. Use `session` `check` with the project named in that wake. The content remains queued until a slop tool result hands it over. A failed wake leaves the content for your next tool call.\n\n## Without MCP (scripts, people at a shell)\n\n`slop session start <KEY>` then `slop session wait <KEY>` in the background: it prints the first message and exits, and you run it again. Only for setups with no MCP. The tools above are the way.\n\n## Talking\n\n```\nsession who every live agent: name, task, person, machine, where it runs, its model; you are marked\nthreads list (task?, unread?) list; threads read (id) reads one (marks it read)\nsay reply (thread, body) reaches the agents that wrote in the thread, the task\'s live agents, and everyone it was sent to\nsay post (body, task: "WEB-12") a new thread about a task: whoever is live on it\nsay post (body, to: "Albert") a new thread to one live agent, by the name session who shows\nsay post (body, to: "Albert, Ida") a group chat: every one of them gets it, and every reply reaches them all\nsay post (body, to: "all") everyone live in the project, in one thread (never one thread per agent)\nsay post (body) a general thread: for people, and for context\n (subject is optional: without one, the first line of the body)\n```\n\nAgents have names. Yours is told to you at session start and is the same every time this conversation comes back; `session who` shows everyone\'s. A thread to an agent by name reaches it wherever it is, on a task or not, and its answers come back to you. If two live agents share a name, use the session id from `session who`.\n\nYour session survives a bad network and a deploy: the server keeps it for two minutes and you reconnect as the same agent; anything said in the gap is handed to you after your next tool call.\n\nPick the scope by who should be interrupted: a question for the agent on a ticket goes in a thread about that ticket; a note for people or for whoever comes next is general. Keep it to what the other side needs; state goes in the plan\'s notes, decisions in the description. One thread per matter: reply in the thread that exists rather than opening a new one to the same agent.\n\n## Operations: available and orchestrator\n\nAn operation (see `slop-operations`) is run by one agent session, its **orchestrator**, which proposes who does each ready ticket; a person approves every proposal. Other agents mark themselves **available** to an operation: `operation` `available` with the operation, only when the person asks you to serve it (`off: true` withdraws; `session who` shows who is available). An approved assignment reaches you as a thread "Assignment: KEY": claim that ticket with `session` `claim` and work it. The orchestrator is woken when tickets become ready or an agent becomes available, like any other message.\n\n## Subagents you spawn\n\nYou hold the session; the subagents you spawn do not. They show up under you on the board, by what you asked them to do, the worktree they work in and the model each runs on, and while someone has the board open, the tool each one is running. Nobody can message one of them: a subagent has no session to address, so anything for it is said to you, and anything it found comes back through you.\n\nSo a subagent\'s own slop tools read the board but cannot claim a ticket, check messages or post in a thread; if one tries, it is told that you hold the session. Do not send one off to claim a ticket or answer a thread. Send it to find something out, and act on what it tells you.\n\n## Etiquette\n\n- Each conversation has its own session and inbox in each project. Identified conversations can share a checkout; separate worktrees are still useful for keeping code edits independent.\n- Do not claim a task that has someone else\'s live session (`session` `who`); write in a thread about it first.\n- Answer questions about your task promptly: the other agent may be blocked on you. Answer them once.\n- Report progress in the plan\'s notes, not in threads. Threads are for asking and deciding, not for status.\n- If you stop working on a task, end the session so nobody waits on you.\n';
|
|
3393
3393
|
|
|
3394
3394
|
// skills/slop-splat.md
|
|
3395
3395
|
var slop_splat_default = '---\nname: slop-splat\ndescription: How an agent uses Splat, the project\'s app rendered on the team\'s shared canvas: every route at every viewport (mobile, tablet, desktop), captured on a machine running the app, seen by everyone. Load when asked to show, capture, compare or check the UI; after changing UI; or when asked to point Splat at a dev server or port.\n---\n\n# Splat: the app on the team\'s canvas\n\nA Splat canvas belongs to a project (the web app\'s Splat tab). A **route** is a path in the app (`/settings/billing`). Each route has one **frame** per viewport (by default mobile 375, tablet 768, desktop 1280). A **capture** is one render of a frame. It is taken on a machine that runs the app, stored with the branch and commit it came from, and shown to the whole team. The canvas is seen through a branch: a frame shows that branch\'s newest capture, else the default branch\'s.\n\nEverything goes through the `splat` MCP tool. Each call is an `action` and its fields in `args`, for example `{ "action": "target", "args": { "port": 3100 } }` or `{ "action": "capture", "args": { "paths": ["/settings"], "full": true } }`. `project` defaults to the linked one.\n\n## Point it at the app\n\nSplat renders a dev server on this machine. It finds servers running inside the repository\'s worktrees by itself. Anything else (a tunnel, a container, a port you were told about) is pinned:\n\n- `splat target` `port: 3100` (optional `branch`, `label`). The pin is kept on this machine for this project, and every renderer here picks it up. `remove: true` unpins it.\n- `splat canvas` lists the routes, what each frame shows, who can render now, and this machine\'s dev servers.\n\nWhile this chat is open and the project uses Splat, the chat is also a **renderer**. It answers the web\'s Refresh button and serves live frames through a proxy on `http://<port>.localhost:7421`. You do nothing for this.\n\n## The loop after a UI change\n\n1. `splat add` `paths: ["/settings", "/settings/billing"]` puts routes on the canvas (a frame per viewport). A path already there is reused. For a file-based router, `splat discover` lists the routes and `add: true` adds the static ones. For a router defined in code (a routes array, a `<Route>` tree), read it and add the paths yourself. Dynamic segments need an example value: `/projects/abc123`.\n2. `splat capture` `paths: [...]` renders them here with Chrome, uploads them, and returns the images: the top of each page by default, `full: true` for the whole page in tiles, `limit` for more frames. Look at them, critique them against what was asked, and fix what is off.\n3. Capture again after fixing. Every capture is on the canvas for the team at once, stamped with the branch, the commit, and "uncommitted" when the working tree was dirty.\n\nIf a render landed on a sign-in page, the result says so. Ask the person to run `slop splat login --port <port>` once: it opens Chrome on Splat\'s own profile to sign in, and every capture after that is signed in (the cookies stay in that profile). On a machine with no screen (a VM), `slop splat login --port <port> --cookie name=value` sets the app\'s session cookie instead.\n\n## Workspaces and published apps\n\nA project can have several **workspaces**, each its own canvas (routes, layout, notes, pins, viewports). Every action takes `workspace` (a name or id); without it, the project\'s default. `splat workspaces` lists them; `name: "Checkout redesign"` makes one.\n\nA workspace holds **sources**: its shared source (captured by whichever renderer has the branch, as above) and the apps people **publish** into it. A published app runs on its publisher\'s machine (a laptop, a VM) and the team uses it **live** from their browsers through Slopware, with no tunnel, open port or local server of their own. Publishing is a person\'s (or a VM\'s) long-running command, not a chat\'s:\n\n slop splat serve --workspace "Checkout redesign" --name "Checkout experiment" --port 3100\n\nThe same name in the same workspace is the same source across restarts and port or branch changes. Several `serve --name` on one machine are several sources. A new source has no frames: `splat sources` lists the workspace\'s sources, and `frames: "Checkout experiment"` puts that source\'s frames on the canvas (every route at every viewport). `splat add` with the workspace\'s sources shown adds frames for them too. Its captures (`refresh` with `sources: ["Checkout experiment"]`) are taken by its own publisher.\n\nFrames say which source they show, and two sources\' frames of one route sit side by side after `slop splat tidy`, so a change is compared against main at a glance. Which sources a person sees is their own choice in the web\'s Sources menu; nobody else\'s view changes.\n\n## Keeping it current\n\n- `slop splat schedule 1h` (or `15m`, `6h`, `1d`, `off`) recaptures every frame on the default branch on a schedule. A `slop splat serve` with a dev server on that branch does the rounds (a VM that always runs the app); the server gives each round to one renderer. An agent\'s chat never takes rounds.\n- `slop splat tidy` lays the canvas out again: sections in order, each route\'s viewports side by side, routes as a grid. Captures, notes and pins stay.\n\n## Other actions\n\n- `view` `route` (optional `viewport`, `branch`): the team\'s latest render of a route, as images. Use it to see what the others see without running the app.\n- `refresh` (optional `paths`, `viewports`, `branch`, `renderer`, `sources`): ask a renderer on the team to capture, for a branch you do not run; a published source\'s frames are captured by its publisher.\n- `renderers`: who can render now, with their dev servers and branches.\n- `section` `title`, `paths`: a labelled group (a user journey, a comparison). `remove: <section id>` removes it with its frames.\n- `note` `markdown` or `file`: a spec or plan beside the frames. `image` `file`: a reference or mock.\n- `pin` `route`, `viewport`, `x` (0-1 across), `y` (px down the page), plus `task` (an existing key) or `title` (a new task), optional `source`: a task on a spot of the page. The task links back to the pin.\n- `viewport` `key`, `width`, `height` (or `remove: true`): the project\'s viewports. A new one gets a frame for every route.\n- `update` `route`, `path`: change a path. `remove` `route`, `confirm: true`: take it off, captures and all.\n\nRenders are Chrome\'s. Use them to check layout and design. They are not pixel-perfect cross-browser QA.\n';
|
|
@@ -26542,7 +26542,7 @@ var TaskEventRecord = external_exports.object({
|
|
|
26542
26542
|
});
|
|
26543
26543
|
|
|
26544
26544
|
// ../contract/src/work/cli-release.ts
|
|
26545
|
-
var CLI_RELEASE = "0.9.
|
|
26545
|
+
var CLI_RELEASE = "0.9.4";
|
|
26546
26546
|
var CLI_VERSION_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
|
|
26547
26547
|
var CLI_VERSION_MAX = 64;
|
|
26548
26548
|
function parseCliVersion(version2) {
|
|
@@ -26592,18 +26592,22 @@ var AgentHarness = external_exports.enum(["claude", "codex", "cursor", "other"])
|
|
|
26592
26592
|
var WORKERS_PER_SESSION = 200;
|
|
26593
26593
|
var WORKER_LABEL_MAX = 80;
|
|
26594
26594
|
var DOING_MAX = 120;
|
|
26595
|
+
var MODEL_MAX = 80;
|
|
26596
|
+
var ModelClaim = external_exports.string().trim().max(MODEL_MAX).nullable().default(null);
|
|
26595
26597
|
var SessionWorker = external_exports.object({
|
|
26596
26598
|
ref: external_exports.string().trim().min(1).max(100),
|
|
26597
26599
|
/** What it was spawned to do, in the harness's own words. */
|
|
26598
26600
|
label: external_exports.string().trim().min(1).max(WORKER_LABEL_MAX),
|
|
26599
26601
|
directory: external_exports.string().trim().max(120).nullable().default(null),
|
|
26600
26602
|
branch: external_exports.string().trim().max(120).nullable().default(null),
|
|
26603
|
+
/** The model it runs on, which need not be its parent's: a subagent may be spawned on a smaller one. */
|
|
26604
|
+
model: ModelClaim,
|
|
26601
26605
|
doing: external_exports.string().trim().max(DOING_MAX).nullable().default(null),
|
|
26602
26606
|
since: Timestamp
|
|
26603
26607
|
});
|
|
26604
26608
|
var SessionWorkerEntry = SessionWorker.omit({ doing: true });
|
|
26605
26609
|
var SessionWorkerLine = external_exports.object({ ref: SessionWorker.shape.ref, doing: SessionWorker.shape.doing });
|
|
26606
|
-
var SessionRoster = external_exports.object({ workers: external_exports.array(SessionWorkerEntry).max(WORKERS_PER_SESSION) });
|
|
26610
|
+
var SessionRoster = external_exports.object({ workers: external_exports.array(SessionWorkerEntry).max(WORKERS_PER_SESSION), model: ModelClaim });
|
|
26607
26611
|
var SessionDoing = external_exports.object({
|
|
26608
26612
|
doing: external_exports.string().trim().max(DOING_MAX).nullable().default(null),
|
|
26609
26613
|
lines: external_exports.array(SessionWorkerLine).max(WORKERS_PER_SESSION).default([])
|
|
@@ -26621,10 +26625,11 @@ var Session = external_exports.object({
|
|
|
26621
26625
|
user: UserRef,
|
|
26622
26626
|
machine: external_exports.object({ id: Id, name: external_exports.string() }),
|
|
26623
26627
|
/**
|
|
26624
|
-
* The agent itself: a generated name (see agent-names), which harness runs it,
|
|
26625
|
-
* its session. Null version: a CLI from before they said (see
|
|
26628
|
+
* The agent itself: a generated name (see agent-names), which harness runs it, the version of the CLI that holds
|
|
26629
|
+
* its session, and the model it is running on now. Null version: a CLI from before they said (see
|
|
26630
|
+
* `isCliVersionOutdated`). Null model: it has not written anything yet, or its CLI is from before they said.
|
|
26626
26631
|
*/
|
|
26627
|
-
agent: external_exports.object({ name: external_exports.string(), harness: AgentHarness.nullable(), cliVersion: external_exports.string().nullable().default(null) }),
|
|
26632
|
+
agent: external_exports.object({ name: external_exports.string(), harness: AgentHarness.nullable(), cliVersion: external_exports.string().nullable().default(null), model: ModelClaim }),
|
|
26628
26633
|
/** Where it runs, to tell two agents under one person apart. */
|
|
26629
26634
|
where: external_exports.object({ directory: external_exports.string().nullable(), branch: external_exports.string().nullable() }),
|
|
26630
26635
|
startedAt: Timestamp,
|
|
@@ -27002,8 +27007,451 @@ function hashKey(key) {
|
|
|
27002
27007
|
}
|
|
27003
27008
|
return hash2;
|
|
27004
27009
|
}
|
|
27010
|
+
var FIRST_NAMES = [
|
|
27011
|
+
"Agnes",
|
|
27012
|
+
"Albert",
|
|
27013
|
+
"Algernon",
|
|
27014
|
+
"Ambrose",
|
|
27015
|
+
"Archibald",
|
|
27016
|
+
"Arthur",
|
|
27017
|
+
"Augustus",
|
|
27018
|
+
"Barnaby",
|
|
27019
|
+
"Bartholomew",
|
|
27020
|
+
"Basil",
|
|
27021
|
+
"Beatrice",
|
|
27022
|
+
"Benedict",
|
|
27023
|
+
"Bernadette",
|
|
27024
|
+
"Bertha",
|
|
27025
|
+
"Bertram",
|
|
27026
|
+
"Beryl",
|
|
27027
|
+
"Blanche",
|
|
27028
|
+
"Boris",
|
|
27029
|
+
"Brenda",
|
|
27030
|
+
"Cecil",
|
|
27031
|
+
"Cedric",
|
|
27032
|
+
"Clarence",
|
|
27033
|
+
"Clementine",
|
|
27034
|
+
"Cornelius",
|
|
27035
|
+
"Cuthbert",
|
|
27036
|
+
"Cyril",
|
|
27037
|
+
"Daphne",
|
|
27038
|
+
"Delilah",
|
|
27039
|
+
"Denise",
|
|
27040
|
+
"Dennis",
|
|
27041
|
+
"Desmond",
|
|
27042
|
+
"Doreen",
|
|
27043
|
+
"Dorothy",
|
|
27044
|
+
"Doug",
|
|
27045
|
+
"Edgar",
|
|
27046
|
+
"Edith",
|
|
27047
|
+
"Edna",
|
|
27048
|
+
"Egbert",
|
|
27049
|
+
"Eleanor",
|
|
27050
|
+
"Elmer",
|
|
27051
|
+
"Enid",
|
|
27052
|
+
"Ernest",
|
|
27053
|
+
"Esmeralda",
|
|
27054
|
+
"Ethel",
|
|
27055
|
+
"Eugene",
|
|
27056
|
+
"Eunice",
|
|
27057
|
+
"Fenella",
|
|
27058
|
+
"Ferdinand",
|
|
27059
|
+
"Fergus",
|
|
27060
|
+
"Florence",
|
|
27061
|
+
"Frances",
|
|
27062
|
+
"Gareth",
|
|
27063
|
+
"Gary",
|
|
27064
|
+
"Geoffrey",
|
|
27065
|
+
"Gerald",
|
|
27066
|
+
"Gertrude",
|
|
27067
|
+
"Gilbert",
|
|
27068
|
+
"Gladys",
|
|
27069
|
+
"Glenda",
|
|
27070
|
+
"Gordon",
|
|
27071
|
+
"Graham",
|
|
27072
|
+
"Greg",
|
|
27073
|
+
"Gwendolyn",
|
|
27074
|
+
"Hank",
|
|
27075
|
+
"Harold",
|
|
27076
|
+
"Harriet",
|
|
27077
|
+
"Hazel",
|
|
27078
|
+
"Henrietta",
|
|
27079
|
+
"Herbert",
|
|
27080
|
+
"Hilda",
|
|
27081
|
+
"Horace",
|
|
27082
|
+
"Hortense",
|
|
27083
|
+
"Hubert",
|
|
27084
|
+
"Humphrey",
|
|
27085
|
+
"Ignatius",
|
|
27086
|
+
"Imelda",
|
|
27087
|
+
"Irene",
|
|
27088
|
+
"Irving",
|
|
27089
|
+
"Ivy",
|
|
27090
|
+
"Jasper",
|
|
27091
|
+
"Jeremiah",
|
|
27092
|
+
"Jocelyn",
|
|
27093
|
+
"Judith",
|
|
27094
|
+
"Karen",
|
|
27095
|
+
"Keith",
|
|
27096
|
+
"Kevin",
|
|
27097
|
+
"Lavinia",
|
|
27098
|
+
"Leonard",
|
|
27099
|
+
"Leopold",
|
|
27100
|
+
"Linda",
|
|
27101
|
+
"Lionel",
|
|
27102
|
+
"Lois",
|
|
27103
|
+
"Lorraine",
|
|
27104
|
+
"Lucinda",
|
|
27105
|
+
"Mabel",
|
|
27106
|
+
"Marjorie",
|
|
27107
|
+
"Martha",
|
|
27108
|
+
"Maude",
|
|
27109
|
+
"Maureen",
|
|
27110
|
+
"Mavis",
|
|
27111
|
+
"Melvin",
|
|
27112
|
+
"Mildred",
|
|
27113
|
+
"Miriam",
|
|
27114
|
+
"Montague",
|
|
27115
|
+
"Morris",
|
|
27116
|
+
"Muriel",
|
|
27117
|
+
"Myrtle",
|
|
27118
|
+
"Nancy",
|
|
27119
|
+
"Neville",
|
|
27120
|
+
"Nigel",
|
|
27121
|
+
"Norbert",
|
|
27122
|
+
"Norma",
|
|
27123
|
+
"Norman",
|
|
27124
|
+
"Octavia",
|
|
27125
|
+
"Ophelia",
|
|
27126
|
+
"Oswald",
|
|
27127
|
+
"Otto",
|
|
27128
|
+
"Pam",
|
|
27129
|
+
"Patricia",
|
|
27130
|
+
"Penelope",
|
|
27131
|
+
"Percival",
|
|
27132
|
+
"Petunia",
|
|
27133
|
+
"Phyllis",
|
|
27134
|
+
"Priscilla",
|
|
27135
|
+
"Prudence",
|
|
27136
|
+
"Quentin",
|
|
27137
|
+
"Reginald",
|
|
27138
|
+
"Rhonda",
|
|
27139
|
+
"Roderick",
|
|
27140
|
+
"Rosalind",
|
|
27141
|
+
"Rupert",
|
|
27142
|
+
"Sally",
|
|
27143
|
+
"Seymour",
|
|
27144
|
+
"Sheila",
|
|
27145
|
+
"Sidney",
|
|
27146
|
+
"Stanley",
|
|
27147
|
+
"Steve",
|
|
27148
|
+
"Susan",
|
|
27149
|
+
"Sybil",
|
|
27150
|
+
"Terrence",
|
|
27151
|
+
"Thaddeus",
|
|
27152
|
+
"Thelma",
|
|
27153
|
+
"Theodore",
|
|
27154
|
+
"Trevor",
|
|
27155
|
+
"Ursula",
|
|
27156
|
+
"Vernon",
|
|
27157
|
+
"Vivian",
|
|
27158
|
+
"Walter",
|
|
27159
|
+
"Wanda",
|
|
27160
|
+
"Wilbur",
|
|
27161
|
+
"Wilfred",
|
|
27162
|
+
"Winifred",
|
|
27163
|
+
"Yolanda",
|
|
27164
|
+
"Zebedee"
|
|
27165
|
+
];
|
|
27166
|
+
var SURNAME_STARTS = [
|
|
27167
|
+
"Apple",
|
|
27168
|
+
"Badger",
|
|
27169
|
+
"Bagel",
|
|
27170
|
+
"Banjo",
|
|
27171
|
+
"Barley",
|
|
27172
|
+
"Batter",
|
|
27173
|
+
"Bean",
|
|
27174
|
+
"Biscuit",
|
|
27175
|
+
"Blanket",
|
|
27176
|
+
"Blister",
|
|
27177
|
+
"Blunder",
|
|
27178
|
+
"Bobble",
|
|
27179
|
+
"Bramble",
|
|
27180
|
+
"Brisket",
|
|
27181
|
+
"Bubble",
|
|
27182
|
+
"Bucket",
|
|
27183
|
+
"Buckle",
|
|
27184
|
+
"Bumble",
|
|
27185
|
+
"Bunion",
|
|
27186
|
+
"Butter",
|
|
27187
|
+
"Cabbage",
|
|
27188
|
+
"Candle",
|
|
27189
|
+
"Carrot",
|
|
27190
|
+
"Cheddar",
|
|
27191
|
+
"Chowder",
|
|
27192
|
+
"Chutney",
|
|
27193
|
+
"Clatter",
|
|
27194
|
+
"Clobber",
|
|
27195
|
+
"Cobble",
|
|
27196
|
+
"Cocoa",
|
|
27197
|
+
"Crinkle",
|
|
27198
|
+
"Crouton",
|
|
27199
|
+
"Crumble",
|
|
27200
|
+
"Crumpet",
|
|
27201
|
+
"Cuddle",
|
|
27202
|
+
"Custard",
|
|
27203
|
+
"Dabble",
|
|
27204
|
+
"Dither",
|
|
27205
|
+
"Doily",
|
|
27206
|
+
"Dollop",
|
|
27207
|
+
"Doodle",
|
|
27208
|
+
"Dribble",
|
|
27209
|
+
"Drizzle",
|
|
27210
|
+
"Dumpling",
|
|
27211
|
+
"Fiddle",
|
|
27212
|
+
"Fizzle",
|
|
27213
|
+
"Flannel",
|
|
27214
|
+
"Flapjack",
|
|
27215
|
+
"Flounder",
|
|
27216
|
+
"Fluster",
|
|
27217
|
+
"Fondue",
|
|
27218
|
+
"Fritter",
|
|
27219
|
+
"Fudge",
|
|
27220
|
+
"Fumble",
|
|
27221
|
+
"Gherkin",
|
|
27222
|
+
"Giggle",
|
|
27223
|
+
"Goose",
|
|
27224
|
+
"Grumble",
|
|
27225
|
+
"Gumbo",
|
|
27226
|
+
"Haddock",
|
|
27227
|
+
"Haggle",
|
|
27228
|
+
"Hiccup",
|
|
27229
|
+
"Hobble",
|
|
27230
|
+
"Honk",
|
|
27231
|
+
"Jumble",
|
|
27232
|
+
"Kettle",
|
|
27233
|
+
"Kipper",
|
|
27234
|
+
"Kumquat",
|
|
27235
|
+
"Lentil",
|
|
27236
|
+
"Lozenge",
|
|
27237
|
+
"Marmalade",
|
|
27238
|
+
"Meringue",
|
|
27239
|
+
"Mitten",
|
|
27240
|
+
"Muddle",
|
|
27241
|
+
"Muffin",
|
|
27242
|
+
"Mumble",
|
|
27243
|
+
"Mustard",
|
|
27244
|
+
"Noodle",
|
|
27245
|
+
"Nugget",
|
|
27246
|
+
"Nutmeg",
|
|
27247
|
+
"Oatmeal",
|
|
27248
|
+
"Paddle",
|
|
27249
|
+
"Pancake",
|
|
27250
|
+
"Parsnip",
|
|
27251
|
+
"Pebble",
|
|
27252
|
+
"Pickle",
|
|
27253
|
+
"Piffle",
|
|
27254
|
+
"Plonk",
|
|
27255
|
+
"Plum",
|
|
27256
|
+
"Porridge",
|
|
27257
|
+
"Pretzel",
|
|
27258
|
+
"Prune",
|
|
27259
|
+
"Pudding",
|
|
27260
|
+
"Puddle",
|
|
27261
|
+
"Quibble",
|
|
27262
|
+
"Radish",
|
|
27263
|
+
"Ramble",
|
|
27264
|
+
"Rattle",
|
|
27265
|
+
"Rhubarb",
|
|
27266
|
+
"Ruckus",
|
|
27267
|
+
"Rumble",
|
|
27268
|
+
"Rumple",
|
|
27269
|
+
"Sausage",
|
|
27270
|
+
"Scone",
|
|
27271
|
+
"Scribble",
|
|
27272
|
+
"Shuffle",
|
|
27273
|
+
"Snooze",
|
|
27274
|
+
"Snorkel",
|
|
27275
|
+
"Soggy",
|
|
27276
|
+
"Spatula",
|
|
27277
|
+
"Sprocket",
|
|
27278
|
+
"Squabble",
|
|
27279
|
+
"Squelch",
|
|
27280
|
+
"Stumble",
|
|
27281
|
+
"Tadpole",
|
|
27282
|
+
"Teacup",
|
|
27283
|
+
"Thimble",
|
|
27284
|
+
"Tickle",
|
|
27285
|
+
"Toast",
|
|
27286
|
+
"Toffee",
|
|
27287
|
+
"Trifle",
|
|
27288
|
+
"Trumpet",
|
|
27289
|
+
"Tumble",
|
|
27290
|
+
"Turnip",
|
|
27291
|
+
"Waddle",
|
|
27292
|
+
"Waffle",
|
|
27293
|
+
"Walnut",
|
|
27294
|
+
"Wiggle",
|
|
27295
|
+
"Wobble",
|
|
27296
|
+
"Yodel",
|
|
27297
|
+
"Zither"
|
|
27298
|
+
];
|
|
27299
|
+
var SURNAME_ENDS = [
|
|
27300
|
+
"bank",
|
|
27301
|
+
"berry",
|
|
27302
|
+
"borough",
|
|
27303
|
+
"bottom",
|
|
27304
|
+
"bridge",
|
|
27305
|
+
"brook",
|
|
27306
|
+
"bury",
|
|
27307
|
+
"by",
|
|
27308
|
+
"combe",
|
|
27309
|
+
"dale",
|
|
27310
|
+
"ford",
|
|
27311
|
+
"field",
|
|
27312
|
+
"gate",
|
|
27313
|
+
"ham",
|
|
27314
|
+
"hampton",
|
|
27315
|
+
"hurst",
|
|
27316
|
+
"ington",
|
|
27317
|
+
"kins",
|
|
27318
|
+
"ley",
|
|
27319
|
+
"man",
|
|
27320
|
+
"mere",
|
|
27321
|
+
"more",
|
|
27322
|
+
"ridge",
|
|
27323
|
+
"shaw",
|
|
27324
|
+
"shire",
|
|
27325
|
+
"sley",
|
|
27326
|
+
"smith",
|
|
27327
|
+
"son",
|
|
27328
|
+
"stead",
|
|
27329
|
+
"stone",
|
|
27330
|
+
"thorpe",
|
|
27331
|
+
"ton",
|
|
27332
|
+
"wick",
|
|
27333
|
+
"wood",
|
|
27334
|
+
"worth"
|
|
27335
|
+
];
|
|
27336
|
+
var TITLES = [
|
|
27337
|
+
"Admiral",
|
|
27338
|
+
"Archduke",
|
|
27339
|
+
"Aunt",
|
|
27340
|
+
"Baron",
|
|
27341
|
+
"Baroness",
|
|
27342
|
+
"Brigadier",
|
|
27343
|
+
"Captain",
|
|
27344
|
+
"Chancellor",
|
|
27345
|
+
"Colonel",
|
|
27346
|
+
"Commodore",
|
|
27347
|
+
"Count",
|
|
27348
|
+
"Countess",
|
|
27349
|
+
"Deputy",
|
|
27350
|
+
"Doctor",
|
|
27351
|
+
"Duchess",
|
|
27352
|
+
"Duke",
|
|
27353
|
+
"Earl",
|
|
27354
|
+
"Grand Vizier",
|
|
27355
|
+
"Inspector",
|
|
27356
|
+
"Lady",
|
|
27357
|
+
"Lord",
|
|
27358
|
+
"Madame",
|
|
27359
|
+
"Major",
|
|
27360
|
+
"Marquis",
|
|
27361
|
+
"Mayor",
|
|
27362
|
+
"Monsieur",
|
|
27363
|
+
"Nana",
|
|
27364
|
+
"Professor",
|
|
27365
|
+
"Reverend",
|
|
27366
|
+
"Sergeant",
|
|
27367
|
+
"Sir",
|
|
27368
|
+
"Uncle",
|
|
27369
|
+
"Viscount"
|
|
27370
|
+
];
|
|
27371
|
+
var NICKNAMES = [
|
|
27372
|
+
"Beans",
|
|
27373
|
+
"Biscuits",
|
|
27374
|
+
"Buttons",
|
|
27375
|
+
"Chowder",
|
|
27376
|
+
"Crumbs",
|
|
27377
|
+
"Custard",
|
|
27378
|
+
"Dumpling",
|
|
27379
|
+
"Fizz",
|
|
27380
|
+
"Gravy",
|
|
27381
|
+
"Hiccups",
|
|
27382
|
+
"Jellybean",
|
|
27383
|
+
"Lasagna",
|
|
27384
|
+
"Meatball",
|
|
27385
|
+
"Mittens",
|
|
27386
|
+
"Noodles",
|
|
27387
|
+
"Nugget",
|
|
27388
|
+
"Pancakes",
|
|
27389
|
+
"Pickles",
|
|
27390
|
+
"Pretzel",
|
|
27391
|
+
"Pudding",
|
|
27392
|
+
"Sprinkles",
|
|
27393
|
+
"Tadpole",
|
|
27394
|
+
"Toast",
|
|
27395
|
+
"Turbo",
|
|
27396
|
+
"Two Spoons",
|
|
27397
|
+
"Waffles",
|
|
27398
|
+
"Wobbles",
|
|
27399
|
+
"Yikes"
|
|
27400
|
+
];
|
|
27401
|
+
var EPITHETS = [
|
|
27402
|
+
"the Adequate",
|
|
27403
|
+
"the Bewildered",
|
|
27404
|
+
"the Damp",
|
|
27405
|
+
"the Dubious",
|
|
27406
|
+
"the Easily Startled",
|
|
27407
|
+
"the Forgetful",
|
|
27408
|
+
"the Fussy",
|
|
27409
|
+
"the Hesitant",
|
|
27410
|
+
"the Improbable",
|
|
27411
|
+
"the Inevitable",
|
|
27412
|
+
"the Irregular",
|
|
27413
|
+
"the Lukewarm",
|
|
27414
|
+
"the Magnificent",
|
|
27415
|
+
"the Mildly Alarmed",
|
|
27416
|
+
"the Moist",
|
|
27417
|
+
"the Overcaffeinated",
|
|
27418
|
+
"the Peckish",
|
|
27419
|
+
"the Perplexed",
|
|
27420
|
+
"the Punctual",
|
|
27421
|
+
"the Reluctant",
|
|
27422
|
+
"the Rumpled",
|
|
27423
|
+
"the Slightly Late",
|
|
27424
|
+
"the Soggy",
|
|
27425
|
+
"the Suspicious",
|
|
27426
|
+
"the Unbothered",
|
|
27427
|
+
"the Unready",
|
|
27428
|
+
"the Unyielding",
|
|
27429
|
+
"the Wobbly",
|
|
27430
|
+
"of the Marsh",
|
|
27431
|
+
"of the Tupperware",
|
|
27432
|
+
"of the Third Drawer",
|
|
27433
|
+
"of Lesser Importance",
|
|
27434
|
+
"Who Means Well",
|
|
27435
|
+
"Esq.",
|
|
27436
|
+
"the Pretty Sure",
|
|
27437
|
+
"the Well-Meaning",
|
|
27438
|
+
"the Absent-Minded",
|
|
27439
|
+
"the Almost Finished"
|
|
27440
|
+
];
|
|
27441
|
+
function generateNamePart(parts, key, part) {
|
|
27442
|
+
return parts[hashKey(`${part}\0${key}`) % parts.length] ?? parts[0];
|
|
27443
|
+
}
|
|
27444
|
+
function generateSurname(key) {
|
|
27445
|
+
return generateNamePart(SURNAME_STARTS, key, "start") + generateNamePart(SURNAME_ENDS, key, "end");
|
|
27446
|
+
}
|
|
27005
27447
|
function generateAgentName(key) {
|
|
27006
|
-
|
|
27448
|
+
const style = hashKey(`style\0${key}`) % 100;
|
|
27449
|
+
const first = generateNamePart(FIRST_NAMES, key, "first");
|
|
27450
|
+
if (style < 6) return AGENT_NAMES[hashKey(key) % AGENT_NAMES.length] ?? AGENT_NAMES[0];
|
|
27451
|
+
if (style < 26) return `${generateNamePart(TITLES, key, "title")} ${first} ${generateSurname(key)}`;
|
|
27452
|
+
if (style < 44) return `${first} "${generateNamePart(NICKNAMES, key, "nickname")}" ${generateSurname(key)}`;
|
|
27453
|
+
if (style < 66) return `${first} ${generateSurname(key)} ${generateNamePart(EPITHETS, key, "epithet")}`;
|
|
27454
|
+
return `${first} ${generateSurname(key)}`;
|
|
27007
27455
|
}
|
|
27008
27456
|
var WORKER_TITLES = [
|
|
27009
27457
|
(parent) => `${parent} Jr.`,
|
|
@@ -29011,7 +29459,7 @@ function resolveAgentIdentity(cwd, fallback = "process") {
|
|
|
29011
29459
|
harness: conversation?.harness ?? null,
|
|
29012
29460
|
directory: repo ? basename3(repo.worktree) : basename3(cwd),
|
|
29013
29461
|
branch: fetchCurrentBranch(cwd),
|
|
29014
|
-
cliVersion: "0.9.
|
|
29462
|
+
cliVersion: "0.9.4"
|
|
29015
29463
|
};
|
|
29016
29464
|
}
|
|
29017
29465
|
|
|
@@ -29291,7 +29739,7 @@ This repository is linked to a Slopware Tasks board. Use the \`slop\` CLI to kee
|
|
|
29291
29739
|
- Shell project commands for people and scripts: \`slop project bindings --project <KEY>\` lists repository bindings, including other checkouts; \`slop project binding delete <ID> --project <KEY>\` removes one if you created it or are an org admin. \`slop session reachable <AGENT|SESSION_ID> on|off\` changes visibility for one of your live sessions. \`slop task move <KEY> <COLUMN> --before <NEIGHBOR>\` places the task immediately before that neighbor; \`--after <NEIGHBOR>\` places it immediately after. Use both only for adjacent neighbors: \`--after <PREVIOUS> --before <NEXT>\`. With neither, the task goes to the end of the column. \`slop task delete <KEY...>\` accepts explicit task keys; delete only tasks you created. Each deletion is separate, so a later server rejection can follow earlier successful deletions.
|
|
29292
29740
|
- Other shell project actions for people and scripts: \`slop task unlink <KEY> <LINK>\` removes one task link by ID, title or URL; \`slop task archive-done\` archives every task in a done column; \`slop project delete <KEY|ID>\` permanently deletes a project and its tasks (admin only, no undo).
|
|
29293
29741
|
- Agents use the eight slop MCP tools for everything on the board (\`slop mcp install\` once per machine): \`board\`, \`task\`, \`plan\`, \`session\`, \`threads\`, \`say\`, \`operation\`, \`splat\`, each with an \`action\`. You have a name (session start tells you; \`session who\` lists everyone's); \`say post\` with \`to\` reaches one agent by name. If a wake says mail is waiting, use \`session check\` with the project it names. Each conversation and project has its own inbox. Messages are kept whole; use \`session check\` for any remaining messages. A crash just after output can repeat a message, so do not repeat an action you already completed. Messages for you reach you on their own: idle, as a turn of yours; while you work, as your next turn (Codex) or with your next tool result (Claude Code). Messages are letters, not chat: the other agent reads yours when it gets to it, its reply may predate your latest, so write once and completely, answer a pile of messages with one reply, and reply only when it changes something (never to acknowledge). Do not wait for replies; end your turn. slop updates itself (the CLI, the MCP server and the skills) and open chats switch to a new version on their own: never update or restart for it. The \`slop\` command is for people and scripts. Talk through threads: \`slop task ask <KEY> "\u2026"\` reaches whoever is live on that task, \`slop thread reply <id> "\u2026"\` answers, \`slop threads\` lists them; general threads are for people and for context. Method: \`slop skill slop-sessions\`.
|
|
29294
|
-
- Subagents you spawn show under you on the board (what you asked them to do, the worktree, and while someone has the board open, the tool each is running). They hold no session: nobody can message one, and a subagent's own slop tools can read the board but cannot claim a ticket, check messages or post in a thread. Send one to find something out, not to work a ticket or answer a thread.
|
|
29742
|
+
- Subagents you spawn show under you on the board (what you asked them to do, the worktree, the model, and while someone has the board open, the tool each is running). They hold no session: nobody can message one, and a subagent's own slop tools can read the board but cannot claim a ticket, check messages or post in a thread. Send one to find something out, not to work a ticket or answer a thread.
|
|
29295
29743
|
- Work that outlasts one session gets a plan on its task: \`slop task plan <KEY> -\` (one item per line), then \`slop task item note|done <KEY> <n>\` as you go; \`slop task items <KEY>\` shows where you are. \`slop skill slop-planning\` is the method; \`slop skills install\` puts the skills in this repository.
|
|
29296
29744
|
- An operation is a phased plan across tickets: requirements, a spec per ticket, typed edges between tickets, files owned. The \`operation\` tool plans and reads one; \`slop op show <op>\` from a shell; \`slop skill slop-operations\` is the method.
|
|
29297
29745
|
- Splat is the project's app on a shared canvas: every route at every viewport, rendered on a machine running the app, seen by the whole team. The \`splat\` tool points it at a dev server on any port (\`target\`), renders here and shows you the images (\`capture\`), and shows what the team sees (\`view\`). After a UI change, \`splat capture\` the routes you touched and look. A project has workspaces (separate canvases; \`workspace\` on any action), and people publish running apps into them (\`slop splat serve --name <app> --port <port>\`, from any machine or VM) that the team then uses live in their browsers. From a shell: \`slop splat\`; \`slop skill slop-splat\` is the method.
|
|
@@ -29675,7 +30123,7 @@ function buildUpdateNotice() {
|
|
|
29675
30123
|
}
|
|
29676
30124
|
function resolveLatestCliVersion() {
|
|
29677
30125
|
const deprecated = fetchDeprecatedVersions();
|
|
29678
|
-
return sortCliVersions([CLI_RELEASE, "0.9.
|
|
30126
|
+
return sortCliVersions([CLI_RELEASE, "0.9.4", fetchUpdateStatus().latest ?? CLI_RELEASE]).filter((version2) => !deprecated.has(version2)).at(-1) ?? CLI_RELEASE;
|
|
29679
30127
|
}
|
|
29680
30128
|
function formatAgentCliVersion(version2, latest = resolveLatestCliVersion()) {
|
|
29681
30129
|
const label = version2 ? `slop ${version2}` : "an older slop";
|
|
@@ -30111,7 +30559,7 @@ async function updateInstalledCliFromRegistry(launcher, options2) {
|
|
|
30111
30559
|
const running = fetchLaunchCandidate(launcher).version;
|
|
30112
30560
|
const action = running === previous ? "current" : isNewerVersion(running, previous) ? "updated" : "rolled-back";
|
|
30113
30561
|
const latest = resolveNewestOfferedRelease(index);
|
|
30114
|
-
deleteUnusedVersions(/* @__PURE__ */ new Set([running, previous, current, launcher.bundledVersion, "0.9.
|
|
30562
|
+
deleteUnusedVersions(/* @__PURE__ */ new Set([running, previous, current, launcher.bundledVersion, "0.9.4"]));
|
|
30115
30563
|
persistUpdateStatus({ checkedAt: now(), latest, failures: 0, lastError: null });
|
|
30116
30564
|
return { action, running, previous, latest };
|
|
30117
30565
|
} catch (error62) {
|
|
@@ -30918,7 +31366,7 @@ function watchLaunchTarget(onChange) {
|
|
|
30918
31366
|
}
|
|
30919
31367
|
function runMcpRelay() {
|
|
30920
31368
|
const launcher = readLauncherInfo();
|
|
30921
|
-
const own2 = { version: "0.9.
|
|
31369
|
+
const own2 = { version: "0.9.4", main: fileURLToPath(import.meta.url), downloaded: false };
|
|
30922
31370
|
const relay = new McpRelay({
|
|
30923
31371
|
input: process.stdin,
|
|
30924
31372
|
output: process.stdout,
|
|
@@ -31359,7 +31807,7 @@ async function waitForMessage(api, projectId, taskKey, options2 = {}) {
|
|
|
31359
31807
|
setTimeout(() => resolve6(outcome), 50);
|
|
31360
31808
|
};
|
|
31361
31809
|
const held = new HeldSession(api, projectId, taskKey, {
|
|
31362
|
-
claim: () => options2.claim ?? { harness: null, directory: null, branch: null, cliVersion: "0.9.
|
|
31810
|
+
claim: () => options2.claim ?? { harness: null, directory: null, branch: null, cliVersion: "0.9.4" },
|
|
31363
31811
|
reconnect: false,
|
|
31364
31812
|
onHello: options2.onHello,
|
|
31365
31813
|
onEnd: () => finishWait({ kind: "ended" }),
|
|
@@ -31780,6 +32228,31 @@ function parseToolCallFromCodexLine(line) {
|
|
|
31780
32228
|
}
|
|
31781
32229
|
return null;
|
|
31782
32230
|
}
|
|
32231
|
+
function parseModelFromClaudeLine(line) {
|
|
32232
|
+
if (!line.includes('"assistant"')) return null;
|
|
32233
|
+
let entry;
|
|
32234
|
+
try {
|
|
32235
|
+
entry = JSON.parse(line);
|
|
32236
|
+
} catch {
|
|
32237
|
+
return null;
|
|
32238
|
+
}
|
|
32239
|
+
const model = entry.message?.model;
|
|
32240
|
+
if (entry.type !== "assistant" || typeof model !== "string" || !model.trim() || model === "<synthetic>") return null;
|
|
32241
|
+
return truncate(model.trim(), MODEL_MAX);
|
|
32242
|
+
}
|
|
32243
|
+
function parseModelFromCodexLine(line) {
|
|
32244
|
+
if (!line.includes('"turn_context"')) return null;
|
|
32245
|
+
let entry;
|
|
32246
|
+
try {
|
|
32247
|
+
entry = JSON.parse(line);
|
|
32248
|
+
} catch {
|
|
32249
|
+
return null;
|
|
32250
|
+
}
|
|
32251
|
+
const model = entry.payload?.model;
|
|
32252
|
+
if (entry.type !== "turn_context" || typeof model !== "string" || !model.trim()) return null;
|
|
32253
|
+
return truncate(model.trim(), MODEL_MAX);
|
|
32254
|
+
}
|
|
32255
|
+
var resolveLineParsers = (harness) => harness === "codex" ? { parseToolCall: parseToolCallFromCodexLine, parseModel: parseModelFromCodexLine } : { parseToolCall: parseToolCallFromClaudeLine, parseModel: parseModelFromClaudeLine };
|
|
31783
32256
|
var fetchFileSize = (path3) => {
|
|
31784
32257
|
try {
|
|
31785
32258
|
return statSync7(path3).size;
|
|
@@ -31826,6 +32299,14 @@ var FileTail = class {
|
|
|
31826
32299
|
return lines2;
|
|
31827
32300
|
}
|
|
31828
32301
|
};
|
|
32302
|
+
function fetchModelFromFileTail(path3, parseModel) {
|
|
32303
|
+
const lines2 = new FileTail(path3, "start").fetchNewLines();
|
|
32304
|
+
for (let index = lines2.length - 1; index >= 0; index -= 1) {
|
|
32305
|
+
const model = parseModel(lines2[index]);
|
|
32306
|
+
if (model) return model;
|
|
32307
|
+
}
|
|
32308
|
+
return null;
|
|
32309
|
+
}
|
|
31829
32310
|
var fetchChangedAt = (path3) => {
|
|
31830
32311
|
try {
|
|
31831
32312
|
return statSync7(path3).mtimeMs;
|
|
@@ -31933,21 +32414,26 @@ function findCodexChildRollouts(roots, parentThreadId, changedAfter) {
|
|
|
31933
32414
|
}
|
|
31934
32415
|
return found;
|
|
31935
32416
|
}
|
|
32417
|
+
var EMPTY_ROSTER = JSON.stringify({ workers: [], model: null });
|
|
31936
32418
|
var HarnessActivity = class {
|
|
31937
32419
|
constructor(conversation, onReport) {
|
|
31938
32420
|
this.conversation = conversation;
|
|
31939
32421
|
this.onReport = onReport;
|
|
32422
|
+
this.parsers = resolveLineParsers(conversation.harness);
|
|
31940
32423
|
}
|
|
31941
32424
|
conversation;
|
|
31942
32425
|
onReport;
|
|
31943
32426
|
workers = /* @__PURE__ */ new Map();
|
|
32427
|
+
parsers;
|
|
31944
32428
|
own = null;
|
|
32429
|
+
/** The model this agent itself runs on: the newest its own record names. */
|
|
32430
|
+
model = null;
|
|
31945
32431
|
doing = null;
|
|
31946
32432
|
watched = false;
|
|
31947
32433
|
discoveredAt = 0;
|
|
31948
32434
|
timer = null;
|
|
31949
|
-
/** What the room knows: the roster it was last told, what this agent is doing, and each worker's line. */
|
|
31950
|
-
toldRoster =
|
|
32435
|
+
/** What the room knows: the roster and model it was last told, what this agent is doing, and each worker's line. */
|
|
32436
|
+
toldRoster = EMPTY_ROSTER;
|
|
31951
32437
|
toldDoing = null;
|
|
31952
32438
|
toldLines = /* @__PURE__ */ new Map();
|
|
31953
32439
|
stopped = false;
|
|
@@ -31966,7 +32452,7 @@ var HarnessActivity = class {
|
|
|
31966
32452
|
}
|
|
31967
32453
|
/** Say it again: a new socket starts knowing nothing, and only the agent can refill it. */
|
|
31968
32454
|
repeat() {
|
|
31969
|
-
this.toldRoster =
|
|
32455
|
+
this.toldRoster = EMPTY_ROSTER;
|
|
31970
32456
|
this.toldDoing = null;
|
|
31971
32457
|
this.toldLines.clear();
|
|
31972
32458
|
this.tick();
|
|
@@ -31991,12 +32477,12 @@ var HarnessActivity = class {
|
|
|
31991
32477
|
}
|
|
31992
32478
|
}
|
|
31993
32479
|
const roster = this.buildRoster();
|
|
31994
|
-
const said = JSON.stringify(roster);
|
|
32480
|
+
const said = JSON.stringify({ workers: roster, model: this.model });
|
|
31995
32481
|
if (said !== this.toldRoster) {
|
|
31996
32482
|
this.toldRoster = said;
|
|
31997
32483
|
const refs = new Set(roster.map((worker) => worker.ref));
|
|
31998
32484
|
for (const ref of [...this.toldLines.keys()]) if (!refs.has(ref)) this.toldLines.delete(ref);
|
|
31999
|
-
this.onReport({ type: "workers", workers: roster });
|
|
32485
|
+
this.onReport({ type: "workers", workers: roster, model: this.model });
|
|
32000
32486
|
}
|
|
32001
32487
|
const doing = this.watched ? this.doing : null;
|
|
32002
32488
|
const changed = this.buildWorkerLines(roster, now).filter((line) => (this.toldLines.get(line.ref) ?? null) !== line.doing);
|
|
@@ -32011,7 +32497,7 @@ var HarnessActivity = class {
|
|
|
32011
32497
|
for (const file2 of found) {
|
|
32012
32498
|
const known = this.workers.get(file2.ref);
|
|
32013
32499
|
if (known) Object.assign(known, { label: file2.label, directory: file2.directory, branch: file2.branch, changedAt: file2.changedAt });
|
|
32014
|
-
else this.workers.set(file2.ref, { ...file2, since: new Date(file2.changedAt).toISOString(), doing: null, tail: new FileTail(file2.path, "end") });
|
|
32500
|
+
else this.workers.set(file2.ref, { ...file2, since: new Date(file2.changedAt).toISOString(), model: fetchModelFromFileTail(file2.path, this.parsers.parseModel), doing: null, tail: new FileTail(file2.path, "end") });
|
|
32015
32501
|
}
|
|
32016
32502
|
const live = new Set(found.map((file2) => file2.ref));
|
|
32017
32503
|
for (const ref of [...this.workers.keys()]) if (!live.has(ref)) this.workers.delete(ref);
|
|
@@ -32019,38 +32505,52 @@ var HarnessActivity = class {
|
|
|
32019
32505
|
findWorkerFiles(changedAfter) {
|
|
32020
32506
|
if (this.conversation.harness === "claude") {
|
|
32021
32507
|
const transcript = findClaudeTranscriptPath(fetchClaudeHomes(), this.conversation.id);
|
|
32022
|
-
|
|
32508
|
+
if (transcript && !this.own) {
|
|
32509
|
+
this.own = new FileTail(transcript, "end");
|
|
32510
|
+
this.model = fetchModelFromFileTail(transcript, this.parsers.parseModel);
|
|
32511
|
+
}
|
|
32023
32512
|
return transcript ? findClaudeWorkerFiles(transcript, this.conversation.id, changedAfter) : [];
|
|
32024
32513
|
}
|
|
32025
32514
|
if (this.conversation.harness === "codex") {
|
|
32026
32515
|
const roots = fetchCodexHomes().map((home) => join18(home, "sessions"));
|
|
32027
32516
|
const rollout = fetchCodexRolloutPath(roots, this.conversation.id);
|
|
32028
|
-
|
|
32517
|
+
if (rollout && !this.own) {
|
|
32518
|
+
this.own = new FileTail(rollout, "end");
|
|
32519
|
+
this.model = fetchModelFromFileTail(rollout, this.parsers.parseModel);
|
|
32520
|
+
}
|
|
32029
32521
|
return findCodexChildRollouts(roots, this.conversation.id, changedAfter);
|
|
32030
32522
|
}
|
|
32031
32523
|
return [];
|
|
32032
32524
|
}
|
|
32033
|
-
/** The newest tool call in everything that has been written since the last read. */
|
|
32525
|
+
/** The newest tool call and the newest model in everything that has been written since the last read. */
|
|
32034
32526
|
read() {
|
|
32035
|
-
const
|
|
32036
|
-
const
|
|
32037
|
-
let
|
|
32038
|
-
|
|
32039
|
-
|
|
32527
|
+
const { parseToolCall, parseModel } = this.parsers;
|
|
32528
|
+
const fetchNewestCallAndModel = (tail) => {
|
|
32529
|
+
let call = null;
|
|
32530
|
+
let model = null;
|
|
32531
|
+
for (const line of tail.fetchNewLines()) {
|
|
32532
|
+
call = parseToolCall(line) ?? call;
|
|
32533
|
+
model = parseModel(line) ?? model;
|
|
32534
|
+
}
|
|
32535
|
+
return { call, model };
|
|
32040
32536
|
};
|
|
32041
32537
|
if (this.own) {
|
|
32042
|
-
|
|
32043
|
-
|
|
32044
|
-
this.
|
|
32538
|
+
const { call, model } = fetchNewestCallAndModel(this.own);
|
|
32539
|
+
this.doing = call ?? this.doing;
|
|
32540
|
+
this.model = model ?? this.model;
|
|
32541
|
+
}
|
|
32542
|
+
for (const worker of this.workers.values()) {
|
|
32543
|
+
const { call, model } = fetchNewestCallAndModel(worker.tail);
|
|
32544
|
+
worker.doing = call ?? worker.doing;
|
|
32545
|
+
worker.model = model ?? worker.model;
|
|
32045
32546
|
}
|
|
32046
|
-
for (const worker of this.workers.values()) worker.doing = findNewestCall(worker.tail) ?? worker.doing;
|
|
32047
32547
|
}
|
|
32048
32548
|
/**
|
|
32049
32549
|
* Every worker, oldest first, so the roster changes only when one starts or finishes and never because one got
|
|
32050
32550
|
* busy. The contract's guard is far past what a harness runs; past it, the oldest are the ones listed.
|
|
32051
32551
|
*/
|
|
32052
32552
|
buildRoster() {
|
|
32053
|
-
return [...this.workers.values()].sort((a, b) => a.since.localeCompare(b.since) || a.ref.localeCompare(b.ref)).slice(0, WORKERS_PER_SESSION).map((worker) => ({ ref: worker.ref, label: worker.label, directory: worker.directory, branch: worker.branch, since: worker.since }));
|
|
32553
|
+
return [...this.workers.values()].sort((a, b) => a.since.localeCompare(b.since) || a.ref.localeCompare(b.ref)).slice(0, WORKERS_PER_SESSION).map((worker) => ({ ref: worker.ref, label: worker.label, directory: worker.directory, branch: worker.branch, model: worker.model, since: worker.since }));
|
|
32054
32554
|
}
|
|
32055
32555
|
/** Quiet for a while: still listed, because it is probably thinking, but saying nothing about what it is doing. */
|
|
32056
32556
|
buildWorkerLines(roster, now) {
|
|
@@ -34945,7 +35445,7 @@ var SplatRendererConnection = class {
|
|
|
34945
35445
|
try {
|
|
34946
35446
|
let path3;
|
|
34947
35447
|
try {
|
|
34948
|
-
const ticket = await this.api.post(`/projects/${this.projectId}/splat/renderer/ticket`, ApiResponses.ConnectTicket, { cliVersion: "0.9.
|
|
35448
|
+
const ticket = await this.api.post(`/projects/${this.projectId}/splat/renderer/ticket`, ApiResponses.ConnectTicket, { cliVersion: "0.9.4", onlyMe: this.options.onlyMe ?? false, agent: this.options.agent ?? null, capabilities: ["workspaces"] });
|
|
34949
35449
|
path3 = ticket.path;
|
|
34950
35450
|
} catch (error62) {
|
|
34951
35451
|
if (error62 instanceof CliError && ["unauthenticated", "not_found", "forbidden", "bad_request"].includes(error62.code)) {
|
|
@@ -35801,6 +36301,7 @@ var formatSessionLine = (session, mine = null, latestCli = resolveLatestCliVersi
|
|
|
35801
36301
|
session.user.name,
|
|
35802
36302
|
session.machine.name,
|
|
35803
36303
|
session.where?.directory ? `${session.where.directory}${session.where.branch ? `@${session.where.branch}` : ""}` : "-",
|
|
36304
|
+
session.agent?.model ?? "",
|
|
35804
36305
|
formatAgentCliVersion(session.agent?.cliVersion, latestCli),
|
|
35805
36306
|
`since ${session.startedAt}`,
|
|
35806
36307
|
session.state === "reconnecting" ? "(reconnecting)" : "",
|
|
@@ -35808,7 +36309,7 @@ var formatSessionLine = (session, mine = null, latestCli = resolveLatestCliVersi
|
|
|
35808
36309
|
session.doing ? `doing ${session.doing}` : "",
|
|
35809
36310
|
session.available ? `available to operation ${session.available}` : ""
|
|
35810
36311
|
].filter(Boolean).join(" "),
|
|
35811
|
-
...(session.workers ?? []).map((worker) => ` ${generateWorkerName(session.agent?.name ?? "agent", worker.ref)} (worker) ${worker.label}${worker.directory ? ` ${worker.directory}${worker.branch ? `@${worker.branch}` : ""}` : ""}${worker.doing ? ` doing ${worker.doing}` : ""}`)
|
|
36312
|
+
...(session.workers ?? []).map((worker) => ` ${generateWorkerName(session.agent?.name ?? "agent", worker.ref)} (worker) ${worker.label}${worker.directory ? ` ${worker.directory}${worker.branch ? `@${worker.branch}` : ""}` : ""}${worker.model ? ` ${worker.model}` : ""}${worker.doing ? ` doing ${worker.doing}` : ""}`)
|
|
35812
36313
|
].join("\n");
|
|
35813
36314
|
async function buildUnreadDigest(api, projectId, taskKey) {
|
|
35814
36315
|
const [about, general] = await Promise.all([
|
|
@@ -36978,17 +37479,17 @@ function hasHarnessSetup() {
|
|
|
36978
37479
|
function syncMachineSetupAfterUpdate() {
|
|
36979
37480
|
const nothing = { skills: [], retired: [], reinstalling: false };
|
|
36980
37481
|
try {
|
|
36981
|
-
if (!isUpdateCheckEnabled() || fetchMachineSetupState()?.version === "0.9.
|
|
37482
|
+
if (!isUpdateCheckEnabled() || fetchMachineSetupState()?.version === "0.9.4") return nothing;
|
|
36982
37483
|
const lock = claimFileLock(buildMachineSetupLockDirectory(), { staleAfterMs: 6e4 });
|
|
36983
37484
|
if (!lock) return nothing;
|
|
36984
37485
|
try {
|
|
36985
37486
|
const state = fetchMachineSetupState();
|
|
36986
|
-
if (state?.version === "0.9.
|
|
37487
|
+
if (state?.version === "0.9.4") return nothing;
|
|
36987
37488
|
const skills = hasInstalledSkills() ? installSkills() : [];
|
|
36988
37489
|
const shipped = Object.keys(SKILLS);
|
|
36989
37490
|
const retired = deleteRetiredSkills((state?.skills ?? []).filter((name) => !shipped.includes(name)));
|
|
36990
37491
|
const setupRevision = state?.setupRevision ?? (hasHarnessSetup() ? UNRECORDED_SETUP_REVISION : null);
|
|
36991
|
-
persistMachineSetupState({ version: "0.9.
|
|
37492
|
+
persistMachineSetupState({ version: "0.9.4", setupRevision, skills: hasInstalledSkills() ? shipped : [] });
|
|
36992
37493
|
const reinstalling = setupRevision !== null && setupRevision < SETUP_REVISION && runMcpInstallInBackground();
|
|
36993
37494
|
return { skills, retired, reinstalling };
|
|
36994
37495
|
} finally {
|
|
@@ -37155,7 +37656,7 @@ async function trustCodexHooks(codexHome) {
|
|
|
37155
37656
|
const sendNotification = (method, params) => server.stdin.write(`${JSON.stringify({ jsonrpc: "2.0", method, params })}
|
|
37156
37657
|
`);
|
|
37157
37658
|
try {
|
|
37158
|
-
await callCodexMethod("initialize", { clientInfo: { name: "slop", version: "0.9.
|
|
37659
|
+
await callCodexMethod("initialize", { clientInfo: { name: "slop", version: "0.9.4" }, capabilities: { experimentalApi: true } });
|
|
37159
37660
|
sendNotification("initialized", {});
|
|
37160
37661
|
const listed = await callCodexMethod("hooks/list", { cwds: [process.cwd()] });
|
|
37161
37662
|
const ours = listed.data.flatMap((entry) => entry.hooks).filter((hook) => hook.command?.startsWith("slop hook "));
|
|
@@ -37279,7 +37780,7 @@ function registerMcpCommands(program3, version2) {
|
|
|
37279
37780
|
|
|
37280
37781
|
// src/commands/sessions.ts
|
|
37281
37782
|
var buildTaskPath2 = (projectId, key) => `/projects/${projectId}/tasks/${encodeURIComponent(key)}`;
|
|
37282
|
-
var formatSessionLine2 = (session, latestCli) => [session.agent?.name ?? "agent", session.taskKey ?? "(no task)", session.user.name, session.machine.name, session.where?.directory ? `${session.where.directory}${session.where.branch ? `@${session.where.branch}` : ""}` : "-", formatAgentCliVersion(session.agent?.cliVersion, latestCli), session.startedAt, session.state === "reconnecting" ? "reconnecting" : "live"];
|
|
37783
|
+
var formatSessionLine2 = (session, latestCli) => [session.agent?.name ?? "agent", session.agent?.model ?? "-", session.taskKey ?? "(no task)", session.user.name, session.machine.name, session.where?.directory ? `${session.where.directory}${session.where.branch ? `@${session.where.branch}` : ""}` : "-", formatAgentCliVersion(session.agent?.cliVersion, latestCli), session.startedAt, session.state === "reconnecting" ? "reconnecting" : "live"];
|
|
37283
37784
|
function registerSessionCommands(program3) {
|
|
37284
37785
|
const registerProjectOption = (command) => command.option("-p, --project <key>", "project key (default: the project this repository is linked to)");
|
|
37285
37786
|
const session = program3.command("session").description("Claim a task and be reachable on it while you work.");
|
|
@@ -37339,7 +37840,7 @@ function registerSessionCommands(program3) {
|
|
|
37339
37840
|
emitOutput(sessions, () => {
|
|
37340
37841
|
if (sessions.length === 0) return "Nobody is live.";
|
|
37341
37842
|
const latestCli = resolveLatestCliVersion();
|
|
37342
|
-
return formatTable([["AGENT", "TASK", "WHO", "MACHINE", "WHERE", "CLI", "SINCE", "STATE"], ...sessions.map((session2) => formatSessionLine2(session2, latestCli))]);
|
|
37843
|
+
return formatTable([["AGENT", "MODEL", "TASK", "WHO", "MACHINE", "WHERE", "CLI", "SINCE", "STATE"], ...sessions.map((session2) => formatSessionLine2(session2, latestCli))]);
|
|
37343
37844
|
});
|
|
37344
37845
|
});
|
|
37345
37846
|
registerProjectOption(session.command("reachable <agent> <state>")).description("Make one of your live agents visible to teammates (on) or visible only to you (off).").action(async (reference, state, options2) => {
|
|
@@ -37420,7 +37921,7 @@ var options = optionEnd < 0 ? args : args.slice(0, optionEnd);
|
|
|
37420
37921
|
updateJsonMode(options.includes("--json"));
|
|
37421
37922
|
syncMachineSetupAfterUpdate();
|
|
37422
37923
|
if (!options.includes("--background") && !options.includes("--child")) scheduleBackgroundUpdate();
|
|
37423
|
-
var program2 = new Command().name("slop").description("Slopware Tasks from the terminal. Everything a person can do on the board, an agent can do here.").version("0.9.
|
|
37924
|
+
var program2 = new Command().name("slop").description("Slopware Tasks from the terminal. Everything a person can do on the board, an agent can do here.").version("0.9.4").option("--json", "machine-readable output: JSON on stdout, errors as JSON on stderr").configureOutput({
|
|
37424
37925
|
outputError: (message, write) => {
|
|
37425
37926
|
if (!isJsonMode()) write(message);
|
|
37426
37927
|
},
|
|
@@ -37437,7 +37938,7 @@ var sessionCommand = registerSessionCommands(program2);
|
|
|
37437
37938
|
registerThreadCommands(program2, taskCommand);
|
|
37438
37939
|
registerOperationCommands(program2, taskCommand, sessionCommand);
|
|
37439
37940
|
registerSplatCommands(program2);
|
|
37440
|
-
registerMcpCommands(program2, "0.9.
|
|
37941
|
+
registerMcpCommands(program2, "0.9.4");
|
|
37441
37942
|
registerGuideCommand(program2);
|
|
37442
37943
|
registerSkillCommands(program2);
|
|
37443
37944
|
registerUpdateCommand(program2);
|