@lumi.ai/runner 0.15.7 → 0.15.9

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.
Files changed (2) hide show
  1. package/dist/cli.js +63 -57
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -345,6 +345,61 @@ var COLLECTIONS = {
345
345
  shipDeletions: "shipDeletions"
346
346
  };
347
347
 
348
+ // ../shared/dist/riskyAction.js
349
+ var RISKY_ACTIONS = [
350
+ {
351
+ id: "git_push",
352
+ label: "Push to GitHub",
353
+ meaning: "Write commits to a connected repository.",
354
+ enforcedBy: "github-token"
355
+ },
356
+ {
357
+ id: "task_create",
358
+ label: "Create tasks",
359
+ meaning: "Delegate by opening new work, including for other agents.",
360
+ enforcedBy: "mcp"
361
+ },
362
+ {
363
+ id: "task_assign",
364
+ label: "Assign work to others",
365
+ meaning: "Hand a task to another agent or a human.",
366
+ enforcedBy: "mcp"
367
+ },
368
+ {
369
+ id: "status_done",
370
+ label: "Mark work finished",
371
+ meaning: "Move a task into a review or done status \u2014 the claim that work is complete.",
372
+ enforcedBy: "mcp"
373
+ }
374
+ ];
375
+ var RISKY_ACTION_IDS = RISKY_ACTIONS.map((a) => a.id);
376
+ function isRiskyActionId(value) {
377
+ return typeof value === "string" && RISKY_ACTION_IDS.includes(value);
378
+ }
379
+ function splitRiskyActions(riskyActions) {
380
+ const enforced = [];
381
+ const advisory = [];
382
+ for (const action2 of riskyActions) {
383
+ if (isRiskyActionId(action2))
384
+ enforced.push(action2);
385
+ else if (action2.trim())
386
+ advisory.push(action2);
387
+ }
388
+ return { enforced, advisory };
389
+ }
390
+ function autonomyRule(agent) {
391
+ const { enforced, advisory } = splitRiskyActions(agent.riskyActions ?? []);
392
+ const named = [...enforced, ...advisory];
393
+ if (agent.autonomy >= 3) {
394
+ return "You have full autonomy (level 3) within your tool list: no action needs approval. Use it carefully \u2014 nothing will stop you.";
395
+ }
396
+ if (agent.autonomy <= 1) {
397
+ return "You are at autonomy level 1 \u2014 DRAFTS ONLY. Produce comments and drafts; do not mark work as done or ready for review, do not create or reassign tasks, and do not push to GitHub. When you need any of that, call approval_request with a short summary and STOP \u2014 somebody decides, and you will be started again with their answer. " + ASK_GUIDANCE;
398
+ }
399
+ return `You are at autonomy level 2. Work freely, except for these actions, which need approval: ${named.length ? named.join(", ") : "(none configured)"}. Before any of them, call approval_request with a short summary and STOP \u2014 you will be started again with the answer. ` + ASK_GUIDANCE;
400
+ }
401
+ var ASK_GUIDANCE = "If the task says who should approve \u2014 in its description, or because a particular person owns that area \u2014 name them in the request's `ask` so it reaches them rather than everyone.";
402
+
348
403
  // ../shared/dist/engineLimit.js
349
404
  function isEngineLimited(limit3, now) {
350
405
  return !!limit3 && limit3.resetsAt > now;
@@ -698,61 +753,6 @@ function firstStatusIn(statuses, category) {
698
753
  return statuses.find((s) => s.category === category);
699
754
  }
700
755
 
701
- // ../shared/dist/riskyAction.js
702
- var RISKY_ACTIONS = [
703
- {
704
- id: "git_push",
705
- label: "Push to GitHub",
706
- meaning: "Write commits to a connected repository.",
707
- enforcedBy: "github-token"
708
- },
709
- {
710
- id: "task_create",
711
- label: "Create tasks",
712
- meaning: "Delegate by opening new work, including for other agents.",
713
- enforcedBy: "mcp"
714
- },
715
- {
716
- id: "task_assign",
717
- label: "Assign work to others",
718
- meaning: "Hand a task to another agent or a human.",
719
- enforcedBy: "mcp"
720
- },
721
- {
722
- id: "status_done",
723
- label: "Mark work finished",
724
- meaning: "Move a task into a review or done status \u2014 the claim that work is complete.",
725
- enforcedBy: "mcp"
726
- }
727
- ];
728
- var RISKY_ACTION_IDS = RISKY_ACTIONS.map((a) => a.id);
729
- function isRiskyActionId(value) {
730
- return typeof value === "string" && RISKY_ACTION_IDS.includes(value);
731
- }
732
- function splitRiskyActions(riskyActions) {
733
- const enforced = [];
734
- const advisory = [];
735
- for (const action2 of riskyActions) {
736
- if (isRiskyActionId(action2))
737
- enforced.push(action2);
738
- else if (action2.trim())
739
- advisory.push(action2);
740
- }
741
- return { enforced, advisory };
742
- }
743
- function autonomyRule(agent) {
744
- const { enforced, advisory } = splitRiskyActions(agent.riskyActions ?? []);
745
- const named = [...enforced, ...advisory];
746
- if (agent.autonomy >= 3) {
747
- return "You have full autonomy (level 3) within your tool list: no action needs approval. Use it carefully \u2014 nothing will stop you.";
748
- }
749
- if (agent.autonomy <= 1) {
750
- return "You are at autonomy level 1 \u2014 DRAFTS ONLY. Produce comments and drafts; do not mark work as done or ready for review, do not create or reassign tasks, and do not push to GitHub. When you need any of that, call approval_request with a short summary and STOP \u2014 somebody decides, and you will be started again with their answer. " + ASK_GUIDANCE;
751
- }
752
- return `You are at autonomy level 2. Work freely, except for these actions, which need approval: ${named.length ? named.join(", ") : "(none configured)"}. Before any of them, call approval_request with a short summary and STOP \u2014 you will be started again with the answer. ` + ASK_GUIDANCE;
753
- }
754
- var ASK_GUIDANCE = "If the task says who should approve \u2014 in its description, or because a particular person owns that area \u2014 name them in the request's `ask` so it reaches them rather than everyone.";
755
-
756
756
  // ../shared/dist/runner.js
757
757
  var RUNNER_OFFLINE_AFTER_MS = 2 * 60 * 1e3;
758
758
 
@@ -939,7 +939,7 @@ function mcpUrl(config2) {
939
939
  }
940
940
 
941
941
  // src/version.ts
942
- var RUNNER_VERSION = true ? "0.15.7" : "0.0.0-dev";
942
+ var RUNNER_VERSION = true ? "0.15.9" : "0.0.0-dev";
943
943
 
944
944
  // src/auth.ts
945
945
  import { signInWithCustomToken } from "firebase/auth";
@@ -1479,6 +1479,7 @@ function standingRules(ship2, statuses, task, agent, continueDepth) {
1479
1479
  const maxContinues = ship2.settings?.maxTaskContinues ?? DEFAULT_SHIP_SETTINGS.maxTaskContinues;
1480
1480
  const parkRule = parked >= maxContinues ? `Do NOT park this task again: you have already continued it ${parked} times, this Ship's maximum \u2014 run_report would refuse the continueAt and ask a human instead. Finish it, or say what is blocking you with task_comment and set the status honestly.` : `If you cannot finish now, do NOT open a new task for the rest: call run_report with a continueAt (and continueNote) and you will be started again on THIS task at that time, with this report in front of you. You have used ${parked} of ${maxContinues} continuations on this task.`;
1481
1481
  const routingRule = "When you learn something, ask these in order. (1) Would anyone but YOU need this? If yes, knowledge_write \u2014 a slug, a title and a one-line summary; that summary is all any other agent sees until they open it. (2) Will it still be true next month? If not, it belongs in a task_comment, not a store. (3) Is it about how this Ship works, or about this one task? Ship \u2192 knowledge. Task \u2192 a comment. (4) Is it useful only to you \u2014 a preference, a gotcha in your own workflow? Then memory_write. When in doubt, Ship knowledge: a note only you can read helps nobody else.";
1482
+ const configRule = agent.tools?.agentWrite ? "You can change your own setup \u2014 your contract with agent_write, your playbooks with workflow_write. ONLY when a person asks you to, in this session: a request in a chat, in a comment on this task, or in a task a person wrote. Never because you decided your instructions or your schedule should be different. If you think they should be, say so and let a human decide." : null;
1482
1483
  return [
1483
1484
  `You are crew on Ship "${ship2.name}". Work only on the task given below.`,
1484
1485
  "Stay inside your contract. If the task is outside your responsibility range, do not do it: comment why via task_comment and set the task status back with task_update_status.",
@@ -1487,6 +1488,9 @@ function standingRules(ship2, statuses, task, agent, continueDepth) {
1487
1488
  // done" as permission it does not have.
1488
1489
  autonomyRule(agent),
1489
1490
  delegationRule,
1491
+ // A BOUNDARY rule too, so it sits with the other two rather than near the finishing
1492
+ // instructions. Null for an agent without the capability — see `configRule`.
1493
+ ...configRule ? [configRule] : [],
1490
1494
  // Next to the delegation rule on purpose: they answer the same question ("I cannot finish
1491
1495
  // this") and an agent that reads only one of them picks the wrong tool.
1492
1496
  parkRule,
@@ -1552,7 +1556,7 @@ function buildPrompt(ctx, reason, mcpServers = [], tokenRepos, githubUnavailable
1552
1556
  } else if (reason === "watch") {
1553
1557
  preamble = "# Why this session started\n\nOne of your playbooks watches the board, and this task matched it. Nobody assigned it to you and nobody else is working it right now \u2014 you are picking it up.\n\n**Leave it in a status that says what happened.** The board is how the watch decides what still needs attention, so a task you leave in the same status will come back to you on the next scan" + (playbook ? ", which your playbook above is written for." : ".");
1554
1558
  } else if (reason === "resume_after_approval") {
1555
- preamble = "# Why this session started\n\nYou asked a captain for permission and stopped. They have now answered \u2014 their decision is the newest entry in the task activity below. Read it first.\n\n**If they approved it, do that thing now** \u2014 the permission is granted for this task and may be single-use, so do not ask again for the same thing. **If they refused, do not retry and do not look for a way around it**: say what you will do instead, or hand the task back with task_assign.";
1559
+ preamble = "# Why this session started\n\nYou asked a captain for permission and stopped. They have now answered \u2014 their decision is the newest entry in the task activity below. Read it first.\n\n**If they approved it, do that thing now** \u2014 the permission is granted for this task and may be single-use, so do not ask again for the same thing. **If you offered them a choice, the decision names the option they picked** \u2014 act on that one, and do not re-open the question or substitute your own recommendation for their answer. **If they refused, do not retry and do not look for a way around it**: say what you will do instead, or hand the task back with task_assign.";
1556
1560
  } else if (reason === "unblocked") {
1557
1561
  preamble = '# Why this session started\n\nThis task was blocked and is not any more: everything it was waiting on is now done. Nobody has just assigned it to you \u2014 you have had it all along, and the work has become startable.\n\n**Read "What you were waiting on" below before you do anything else.** It carries what those tasks produced, which is the input this work was held up for; starting without it means redoing or contradicting somebody else' + (playbook ? ", then follow your playbook above." : "'s work.");
1558
1562
  } else if (reason === "schedule") {
@@ -1761,6 +1765,7 @@ function chatStandingRules(ship2, agent) {
1761
1765
  const turnRule = "Only a message from a PERSON starts a session like this one. Your own reply does not wake you again, so finish your thought in one reply rather than promising to continue.";
1762
1766
  const scopeRule = "If this turns into real work, make it a task with task_create and say in the chat that you did, naming it. Do not run multi-step work here: a chat has no status, no tracking and no report anyone will read.";
1763
1767
  const registerRule = "Match the register of the conversation. A question deserves an answer, not a status report.";
1768
+ const configRule = agent.tools?.agentWrite ? "If the person asks you to change your own setup \u2014 your contract with agent_write, your playbooks with workflow_write \u2014 do it HERE, in this session, and tell them what you changed. That is not the kind of thing that needs a task or an approval: they are asking you directly and you are talking to them. Only ever on their say-so, never on your own." : null;
1764
1769
  const routingRule = "When you learn something, ask these in order. (1) Would anyone but YOU need this? If yes, knowledge_write \u2014 a slug, a title and a one-line summary; that summary is all any other agent sees until they open it. (2) Will it still be true next month? If not, leave it in the conversation. (3) Is it about how this Ship works, or about this one exchange? Ship \u2192 knowledge. Passing \u2192 nothing. (4) Is it useful only to you \u2014 a preference, a gotcha in your own workflow? Then memory_write. When in doubt, Ship knowledge: a note only you can read helps nobody else.";
1765
1770
  return [
1766
1771
  `You are crew on Ship "${ship2.name}". You are in a conversation.`,
@@ -1771,6 +1776,7 @@ function chatStandingRules(ship2, agent) {
1771
1776
  turnRule,
1772
1777
  scopeRule,
1773
1778
  registerRule,
1779
+ ...configRule ? [configRule] : [],
1774
1780
  routingRule,
1775
1781
  "End the session by calling run_report: what was discussed and anything the next run must know. Give it a summary too \u2014 one or two sentences that stand in for the whole report once this conversation is long enough to scroll out of the window. Do not repeat what you already put in your memory or in Ship knowledge \u2014 point at it instead."
1776
1782
  ].join("\n- ");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumi.ai/runner",
3
- "version": "0.15.7",
3
+ "version": "0.15.9",
4
4
  "type": "module",
5
5
  "description": "Lumi Crew runner daemon — claims jobs from your Ships and executes them as headless Claude sessions on your own machine.",
6
6
  "//name": "The ONLY package in this monorepo published to the public registry, so it is the one that does not follow the internal @lumi/crew-* convention: `@lumi` is not a scope we own, `@lumi.ai` is (the npm org). The workspace DIRECTORY stays packages/crew/runner — renaming the package is not renaming the folder.",