craig-cli 0.19.2 → 0.19.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/dist/cli.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,10 +22,12 @@
|
|
|
22
22
|
|
|
23
23
|
</div>
|
|
24
24
|
|
|
25
|
-
<a href="https://craig-cli.com">
|
|
26
|
-
<img src="https://craig-cli.com/craig-
|
|
25
|
+
<a href="https://craig-cli.com/#demo">
|
|
26
|
+
<img src="https://craig-cli.com/craig-hero-poster.jpg" alt="Watch Craig's task-to-merge demo: agent work, pull request checks, and merge">
|
|
27
27
|
</a>
|
|
28
28
|
|
|
29
|
+
[▶ Watch the full task-to-merge demo (65 seconds)](https://craig-cli.com/#demo)
|
|
30
|
+
|
|
29
31
|
Craig gives every task its own Git branch, isolated worktree, and live PTY, then keeps the agents, changes, pull requests, and checks together in one keyboard-driven workspace.
|
|
30
32
|
|
|
31
33
|
Bring the agent CLIs you already use—Claude Code, Codex, or Cursor. Craig is not another coding agent; it is the heads-up display and controls around them.
|
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
var sk=Object.defineProperty;var Bs=(e,t)=>{for(var n in t)sk(e,n,{get:t[n],enumerable:!0})};import{realpath as A0}from"node:fs/promises";import Te from"node:path";function $e(e){let t=Te.join(e,".craig");return{workspaceRoot:e,repoRoot:e,craigDir:t,indexFile:Te.join(t,"index.json"),reposDir:Te.join(t,"repos"),workspacesDir:Te.join(t,"workspaces"),runtimeDir:Te.join(t,"runtime"),uiStateFile:Te.join(t,"runtime","ui-state.json"),tasksDir:Te.join(t,"tasks"),jobsDir:Te.join(t,"jobs"),commandsDir:Te.join(t,"commands"),eventsDir:Te.join(t,"events"),orchestrationDir:Te.join(t,"orchestration"),logsDir:Te.join(t,"logs"),logFile:Te.join(t,"logs","craig.jsonl"),artifactsDir:Te.join(t,"artifacts"),worktreesDir:Te.join(t,"worktrees"),configFile:Te.join(t,"config.json")}}import Tu from"node:path";import{readFile as bv}from"node:fs/promises";import{readFile as pk}from"node:fs/promises";import{randomUUID as ik}from"node:crypto";import{chmod as ok,open as ak,readFile as lk,rename as ck,rm as uk}from"node:fs/promises";import wa from"node:path";async function U(e,t,n={}){let r=wa.dirname(e),s=wa.join(r,`.${wa.basename(e)}.${process.pid}.${Date.now()}.${ik()}.tmp`),i=await ak(s,"w",n.mode);try{let o=`${JSON.stringify(t,null,2)}
|
|
3
3
|
`;await i.writeFile(o,"utf8"),await i.sync(),await i.close(),await ck(s,e),n.mode!==void 0&&await ok(e,n.mode)}catch(o){throw await i.close().catch(()=>{}),await uk(s,{force:!0}).catch(()=>{}),o}}async function Ws(e){try{let t=await lk(e,"utf8");return JSON.parse(t)}catch(t){if(dk(t))return null;throw t}}function dk(e){return typeof e=="object"&&e!==null&&"code"in e&&typeof e.code=="string"&&e.code==="ENOENT"}async function Un(e){try{let t=await pk(e.uiStateFile,"utf8"),n=JSON.parse(t);return fk(n,e.uiStateFile)}catch(t){if(mk(t))return null;throw t}}async function gt(e,t){await U(e.uiStateFile,{...t,updatedAt:new Date().toISOString()})}function Ks(){return{version:1,selectedRepoId:null,selectedWorkspaceId:null,selectedTaskId:null,selectedPtyTabId:null,inputMode:"control",focusedRegion:"tasks",activeTab:"agent",inspectorSection:"task",inspectionMode:"files",openInspectionKind:null,selectedFileTreePath:null,selectedFilePath:null,selectedDiffPath:null,collapsedFileTreePaths:[],selectedActionId:"commit",updatedAt:new Date().toISOString()}}function fk(e,t){if(typeof e!="object"||e===null||e.version!==1||!(e.selectedRepoId===null||typeof e.selectedRepoId=="string")||!(e.selectedWorkspaceId===null||typeof e.selectedWorkspaceId=="string")||!(e.selectedTaskId===null||typeof e.selectedTaskId=="string")||!(e.selectedPtyTabId===void 0||e.selectedPtyTabId===null||typeof e.selectedPtyTabId=="string")||!wn(e,"inputMode")||!wn(e,"focusedRegion")||!wn(e,"activeTab")||!wn(e,"inspectorSection")||!wn(e,"inspectionMode")||!Vs(e,"openInspectionKind")||!Vs(e,"selectedFileTreePath")||!Vs(e,"selectedFilePath")||!Vs(e,"selectedDiffPath")||!Od(e,"collapsedFileTreePaths")||!wn(e,"ignoredUpdateVersion")||!Od(e,"seenPreviewIds")||!wn(e,"selectedActionId")||!hk(e,"readAgentActivityAt")||typeof e.updatedAt!="string")throw new Error(`Craig UI state at ${t} is invalid. Remove or repair the file before rerunning Craig.`);return e}function wn(e,t){return typeof e=="object"&&e!==null&&(!(t in e)||typeof e[t]=="string")}function Vs(e,t){return typeof e=="object"&&e!==null&&(!(t in e)||e[t]===null||typeof e[t]=="string")}function Od(e,t){return typeof e=="object"&&e!==null&&(!(t in e)||Array.isArray(e[t])&&e[t].every(n=>typeof n=="string"))}function mk(e){return typeof e=="object"&&e!==null&&"code"in e&&typeof e.code=="string"&&e.code==="ENOENT"}function hk(e,t){if(!(t in e))return!0;let n=e[t];return typeof n=="object"&&n!==null&&!Array.isArray(n)&&Object.values(n).every(r=>typeof r=="number"&&Number.isFinite(r)&&r>=0)}var ka={};Bs(ka,{RUNNER_IDS:()=>fe,STABLE_RUNNER_IDS:()=>yt,assertEnabled:()=>Dd,buildCommand:()=>Fd,getConfiguredProfile:()=>Gs,getDefault:()=>Nd,getDisplayName:()=>xd,getEnabled:()=>Hs,getProfile:()=>Bn,isRunnerType:()=>Ys,parse:()=>_d,setRunnerEnabled:()=>Ld,setRunnerPath:()=>Md});var yt=["codex","cursor","claude"],fe=[...yt,"pi"];var $d={codex:{id:"codex",displayName:"Codex",executable:"codex",defaultAgentTitle:"Codex"},cursor:{id:"cursor",displayName:"Cursor",executable:"cursor-agent",defaultAgentTitle:"Cursor"},claude:{id:"claude",displayName:"Claude",executable:"claude",defaultAgentTitle:"Claude"},pi:{id:"pi",displayName:"Pi",executable:"pi",defaultAgentTitle:"Pi"}};var Bn=e=>$d[e];var Gs=(e,t={})=>{let n=Bn(e),r=t.runners?.[e]?.path?.trim();return{...n,executable:r&&r.length>0?r:n.executable}};var Hs=(e={})=>fe.filter(t=>t!=="pi"||e.previews?.piRunner===!0).filter(t=>e.runners?.[t]?.enabled!==!1);var Nd=(e={})=>{let t=Hs(e);if(t.length===0)throw new Error("No runners are enabled. Enable at least one runner in .craig/config.json.");return t.includes("codex")?"codex":t[0]};var Dd=(e,t={})=>{if(e==="pi"&&t.previews?.piRunner!==!0)throw new Error('Runner "pi" is experimental. Enable the piRunner feature preview in .craig/config.json.');if(t.runners?.[e]?.enabled===!1)throw new Error(`Runner "${e}" is disabled in .craig/config.json.`)};var Ys=e=>fe.includes(e);var _d=e=>{if(!e||e.length===0)return"codex";if(!Ys(e))throw new Error(`Unsupported runner "${e}". Expected one of: ${fe.join(", ")}.`);return e};var xd=e=>Bn(e).displayName;var Fd=(e,t,n={})=>{let r=[Gs(e,n).executable];return t&&t.length>0&&r.push(t),r};var Ld=(e,t,n)=>({...e,runners:{...e.runners??{},[t]:{...e.runners?.[t]??{},enabled:n}}});var Md=(e,t,n)=>{let r=e.runners?.[t]??{},{path:s,...i}=r;return{...e,runners:{...e.runners??{},[t]:n!=null?{...r,path:n}:i}}};var Ta={};Bs(Ta,{PREVIEW_FEATURE_IDS:()=>wt,isEnabled:()=>jd,setEnabled:()=>qd});var wt=["agentOrchestration","piRunner","fileOpen","panelPolish"];function jd(e,t){return e.previews?.[t]===!0}function qd(e,t,n){return{...e,previews:{...e.previews,[t]:n}}}import{mkdir as gk,readFile as yk,writeFile as wk}from"node:fs/promises";import kk from"node:path";var Tk=e=>typeof e=="object"&&e!==null&&"code"in e&&typeof e.code=="string"&&e.code==="ENOENT",Ud=async e=>{try{return await yk(e,"utf8")}catch(t){if(Tk(t))return null;throw t}},Bd=async(e,t)=>{await gk(kk.dirname(e),{recursive:!0}),await wk(e,t,"utf8")};var zs=(e,t)=>{if(typeof e!="object"||e===null)throw new Error(`Craig config at ${t} is invalid. Expected a JSON object.`);let n=e;if(n.runners!==void 0){if(typeof n.runners!="object"||n.runners===null||Array.isArray(n.runners))throw new Error(`Craig config at ${t} is invalid. "runners" must be an object.`);for(let[r,s]of Object.entries(n.runners)){if(!fe.includes(r))throw new Error(`Craig config at ${t} is invalid. "runners.${r}" is not supported. Expected one of: ${fe.join(", ")}.`);if(typeof s!="object"||s===null||Array.isArray(s))throw new Error(`Craig config at ${t} is invalid. "runners.${r}" must be an object.`);let i=s;if(i.enabled!==void 0&&typeof i.enabled!="boolean")throw new Error(`Craig config at ${t} is invalid. "runners.${r}.enabled" must be a boolean.`);if(i.path!==void 0&&(typeof i.path!="string"||i.path.trim().length===0))throw new Error(`Craig config at ${t} is invalid. "runners.${r}.path" must be a non-empty string.`)}}if(n.checks!==void 0&&(typeof n.checks!="object"||n.checks===null||!Array.isArray(n.checks.commands)||!n.checks.commands.every(r=>typeof r=="string")))throw new Error(`Craig config at ${t} is invalid. "checks.commands" must be an array of strings.`);if(n.open!==void 0&&(typeof n.open!="object"||n.open===null||!Array.isArray(n.open.command)||!n.open.command.every(r=>typeof r=="string")))throw new Error(`Craig config at ${t} is invalid. "open.command" must be an array of strings.`);if(n.github!==void 0){if(typeof n.github!="object"||n.github===null)throw new Error(`Craig config at ${t} is invalid. "github" must be an object.`);if(n.github.mergeMethod!==void 0&&n.github.mergeMethod!=="merge"&&n.github.mergeMethod!=="rebase"&&n.github.mergeMethod!=="squash")throw new Error(`Craig config at ${t} is invalid. "github.mergeMethod" must be "merge", "rebase", or "squash".`);if(n.github.watchIntervalSeconds!==void 0&&(!Number.isInteger(n.github.watchIntervalSeconds)||n.github.watchIntervalSeconds<=0))throw new Error(`Craig config at ${t} is invalid. "github.watchIntervalSeconds" must be a positive integer.`)}if(n.previews!==void 0){if(typeof n.previews!="object"||n.previews===null||Array.isArray(n.previews))throw new Error(`Craig config at ${t} is invalid. "previews" must be an object.`);for(let[r,s]of Object.entries(n.previews))if(typeof s!="boolean")throw new Error(`Craig config at ${t} is invalid. "previews.${r}" must be a boolean.`)}return n};var ba=async(e,t={readConfigFile:Ud})=>{let n=await t.readConfigFile(e.configFile);if(!n)return{};if(n.trimStart()[0]!=="{")throw new Error(`Craig config at ${e.configFile} is malformed. Remove or repair the file before rerunning Craig.`);let r;try{r=JSON.parse(n)}catch{throw new Error(`Craig config at ${e.configFile} is malformed. Remove or repair the file before rerunning Craig.`)}return zs(r,e.configFile)};var Ra=async(e,t,n={writeConfigFile:Bd})=>{zs(t,e.configFile),await n.writeConfigFile(e.configFile,`${JSON.stringify(t,null,2)}
|
|
4
|
-
`)};var Sa={};Bs(Sa,{checkForUpdate:()=>Vd,getCurrent:()=>Js,isNewer:()=>Pa});var Js=()=>{try{return"0.19.
|
|
4
|
+
`)};var Sa={};Bs(Sa,{checkForUpdate:()=>Vd,getCurrent:()=>Js,isNewer:()=>Pa});var Js=()=>{try{return"0.19.3"}catch{return"unknown"}};var bk="https://registry.npmjs.org/craig-cli/latest",Rk=3600*1e3,Pk={value:null},Wd=/^\d+\.\d+\.\d+$/,Pa=(e,t)=>{if(!Wd.test(e)||!Wd.test(t))return!1;let n=c=>c.split(".").map(Number),[r=0,s=0,i=0]=n(e),[o=0,a=0,l=0]=n(t);return r!==o?r>o:s!==a?s>a:i>l},Vd=async(e={fetch:globalThis.fetch,getCurrent:Js,cache:Pk})=>{let t=e.getCurrent(),n=Date.now();if(e.cache.value&&n-e.cache.value.cachedAt<Rk)return e.cache.value.result;let r=null;try{let i=await e.fetch(bk,{signal:AbortSignal.timeout(5e3)});i.ok&&(r=(await i.json()).version??null)}catch{}let s={current:t,latest:r,updateAvailable:r!==null&&r!==t&&Pa(r,t)};return e.cache.value={result:s,cachedAt:n},s};var k={load:ba,save:Ra,previews:Ta,runners:ka,version:Sa};var Kd={CLI_USAGE:2,INPUT_REQUIRED:2,WORKSPACE_CONTEXT_NOT_FOUND:3,WORKSPACE_CONTEXT_INVALID:4,WORKSPACE_NOT_FOUND:3,WORKSPACE_RECORD_INVALID:2,TASK_CONTEXT_NOT_FOUND:3,TASK_CONTEXT_AMBIGUOUS:4,TASK_CONTEXT_CONFLICT:4,TASK_NOT_FOUND:3,TASK_RECORD_INVALID:2,REPO_NOT_FOUND:3,REPO_RECORD_INVALID:2,PR_REPOSITORY_MISMATCH:4,PR_BRANCH_MISMATCH:4,EXTERNAL_DEPENDENCY_FAILED:5,OPERATION_TIMEOUT:6,OPERATION_CANCELLED:6,EVENT_CURSOR_INVALID:2,EVENT_CURSOR_EXPIRED:4,EVENT_JOURNAL_CORRUPT:2,COMMAND_NOT_FOUND:3,COMMAND_RECORD_INVALID:2,COMMAND_STATE_CONFLICT:4,CAPABILITY_NOT_FOUND:3,CAPABILITY_RECORD_INVALID:2,CAPABILITY_DENIED:4,DELEGATION_LIMIT_EXCEEDED:4,FURY_DEFINITION_INVALID:2,FURY_INPUT_INVALID:2,FURY_PLAN_NOT_FOUND:3,FURY_APPROVAL_REQUIRED:4,FURY_RUN_NOT_FOUND:3,FURY_REVIEW_NOT_FOUND:3,FURY_RECORD_INVALID:2,FURY_STATE_CONFLICT:4,FURY_OUTPUT_INVALID:4,PARTIAL_RESULT:7,INTERNAL_ERROR:1},g=class extends Error{code;exitCode;retryable;details;constructor(t,n,r){super(n,r.cause===void 0?void 0:{cause:r.cause}),this.name="CraigError",this.code=t,this.exitCode=Kd[t],this.retryable=r.retryable??!1,this.details=r.details??{}}};function Ia(e){return e instanceof g?e:new g("INTERNAL_ERROR",e instanceof Error?e.message:"Unknown Craig error",{cause:e})}import{appendFile as Sk,mkdir as Ik,readFile as vk}from"node:fs/promises";import Ck from"node:path";var Gd=80,Xs=async(e,t)=>{await Ik(Ck.dirname(e.logFile),{recursive:!0});let n={timestamp:new Date().toISOString(),...t};await Sk(e.logFile,`${JSON.stringify(n)}
|
|
5
5
|
`,"utf8")},Hd=async(e,t)=>{try{await Xs(e,t)}catch{}},Qs=async(e,t=Gd)=>{try{let s=(await vk(e.logFile,"utf8")).trimEnd().split(`
|
|
6
6
|
`).filter(i=>i.length>0).map(Ak);return{path:e.logFile,lines:s.slice(Math.max(0,s.length-t)),empty:s.length===0}}catch(n){if(Ok(n))return{path:e.logFile,lines:[],empty:!0};throw n}},va=async(e,t)=>Xs(e,{level:"error",component:"application",event:Ek(t.context),message:t.message,...t.details?{details:t.details}:{}}),Yd=async(e,t)=>{try{await va(e,t)}catch{}},zd=Qs,Jd=async(e,t=Gd)=>Qs(e,t);function Ak(e){try{let t=JSON.parse(e);if(!t.timestamp||!t.level||!t.component||!t.event||!t.message)return e;let n=[t.taskId,t.tabId].filter(Boolean).join("/");return`[${t.timestamp}] ${t.level.toUpperCase().padEnd(5)} ${t.component}.${t.event}${n?` ${n}`:""} \u2014 ${t.message}`}catch{return e}}function Ek(e){return e.trim().toLowerCase().replace(/[^a-z0-9]+/g,".").replace(/^\.+|\.+$/g,"")||"error"}function Ok(e){return typeof e=="object"&&e!==null&&"code"in e&&typeof e.code=="string"&&e.code==="ENOENT"}var ue={appendErrorLog:va,appendErrorLogBestEffort:Yd,appendLog:Xs,appendLogBestEffort:Hd,readLog:Qs,readErrorLog:zd,readRecentErrorLines:Jd};function ep(e){let{commandTokens:t,options:n,help:r}=Nk(e);if(r)return Qd({kind:"help"},n);if(t.length===0)return{mode:"interactive",options:n};let[s,i,...o]=t,a;switch(`${s??""}:${i??""}`){case"context:show":_r(o,"context show"),a={kind:"showContext"};break;case"repo:add":a={kind:"addRepo",path:Ca(o,"Repo path")};break;case"repo:list":_r(o,"repo list"),a={kind:"listRepos"};break;case"repo:remove":a={kind:"removeRepo",repoId:ne(o,"Repo id")};break;case"workspace:add":a={kind:"addWorkspace",path:Ca(o,"Workspace path")};break;case"workspace:list":a=Dk(o);break;case"workspace:archive":a={kind:"archiveWorkspace",workspaceId:ne(o,"Workspace id")};break;case"workspace:restore":a={kind:"restoreWorkspace",workspaceId:ne(o,"Workspace id")};break;case"workspace:remove":a={kind:"removeWorkspace",workspaceId:ne(o,"Workspace id")};break;case"file:open":a={kind:"openFile",path:ne(o,"File path")};break;case"task:new":a=xk(o);break;case"task:create-child":a=Fk(o);break;case"task:children":a={kind:"listTaskChildren",...o.length===0?{}:{taskId:ne(o,"Task id")}};break;case"task:cancel-tree":a={kind:"cancelTaskTree",...o.length===0?{}:{taskId:ne(o,"Task id")}};break;case"task:list":a=_k(o);break;case"task:current":_r(o,"task current"),a={kind:"currentTask"};break;case"task:rename":a={kind:"renameTask",title:Ca(o,"Task title")};break;case"task:show":a=o.length===0?{kind:"showCurrentTask"}:{kind:"showTask",taskId:ne(o,"Task id")};break;case"task:pr":a=Lk(o);break;case"task:repo":if(o[0]!=="add")throw I(`Unsupported task repo command: ${o.join(" ")}`);ei(o,3,"task repo add"),a={kind:"addTaskRepoTarget",taskId:Zs(o,1,"Task id"),repoId:Zs(o,2,"Repo id")};break;case"task:wait":a=Vk(o);break;case"agent:list":_r(o,"agent list"),a={kind:"listAgents"};break;case"agent:status":a=qk(o);break;case"agent:send":a=Uk(o);break;case"command:show":a={kind:"showPromptCommand",commandId:ne(o,"Command id")};break;case"command:list":_r(o,"command list"),a={kind:"listPromptCommands"};break;case"command:cancel":a={kind:"cancelPromptCommand",commandId:ne(o,"Command id")};break;case"command:wait":a=Bk(o);break;case"events:list":a=Xd(o,!1);break;case"events:watch":a=Xd(o,!0);break;case"fury:validate":a={kind:"validateFury",file:ne(o,"Fury file")};break;case"fury:plan":a=Kk(o);break;case"fury:approve":a={kind:"approveFury",planId:ne(o,"Fury plan id")};break;case"fury:run":a={kind:"runFury",planId:ne(o,"Fury plan id")};break;case"fury:status":a={kind:"showFury",runId:ne(o,"Fury run id")};break;case"fury:watch":a=Gk(o);break;case"fury:cancel":a={kind:"cancelFury",runId:ne(o,"Fury run id")};break;case"fury:resume":a={kind:"resumeFury",runId:ne(o,"Fury run id")};break;case"fury:step":a=Hk(o);break;case"fury:reviews":a=Yk(o);break;case"fury:review":a=zk(o);break;case"task:logs":a={kind:"streamTaskLogs",taskId:ne(o,"Task id")};break;case"task:diff":a={kind:"showTaskDiff",taskId:ne(o,"Task id")};break;case"task:open":a={kind:"openTask",taskId:ne(o,"Task id")};break;case"task:check":a={kind:"runChecks",taskId:ne(o,"Task id")};break;case"task:commit":a={kind:"commitTask",taskId:ne(o,"Task id")};break;case"link:add":a={kind:"addTaskLink",taskId:Zs(o,0,"Task id"),repoId:Zs(o,1,"Repo id")},ei(o,2,"link add");break;case"link:list":a={kind:"listTaskLinks",taskId:ne(o,"Task id")};break;default:if(t.length===1&&(s==="help"||s==="--help"||s==="-h")){a={kind:"help"};break}throw I(`Unsupported command: ${t.join(" ")}`)}return Qd(a,n)}function tp(e){let t=e[0]==="--"?e.slice(1):e,n=!0;for(let r of t){if(r==="--"){n=!1;continue}if(n&&r==="--json")return!0}return!1}function $k(e){return e.kind==="actFuryReview"?`fury.review.${e.action==="request_changes"?"request-changes":e.action}`:{addWorkspace:"workspace.add",addRepo:"repo.add",listRepos:"repo.list",removeRepo:"repo.remove",listWorkspaces:"workspace.list",archiveWorkspace:"workspace.archive",restoreWorkspace:"workspace.restore",removeWorkspace:"workspace.remove",createTask:"task.new",createChildTask:"task.create-child",listTaskChildren:"task.children",cancelTaskTree:"task.cancel-tree",validateFury:"fury.validate",planFury:"fury.plan",approveFury:"fury.approve",runFury:"fury.run",showFury:"fury.status",watchFury:"fury.watch",cancelFury:"fury.cancel",resumeFury:"fury.resume",completeFuryStep:"fury.step.complete",failFuryStep:"fury.step.fail",listFuryReviews:"fury.reviews.list",showFuryReview:"fury.review.show",actFuryReview:"fury.review.action",listTasks:"task.list",currentTask:"task.current",renameTask:"task.rename",showTask:"task.show",showCurrentTask:"task.show",showTaskPr:"task.pr.show",discoverTaskPr:"task.pr.discover",linkTaskPr:"task.pr.link",refreshTaskPr:"task.pr.refresh",unlinkTaskPr:"task.pr.unlink",listAgents:"agent.list",showAgentStatus:"agent.status",sendAgentPrompt:"agent.send",showPromptCommand:"command.show",listPromptCommands:"command.list",cancelPromptCommand:"command.cancel",waitPromptCommand:"command.wait",waitTask:"task.wait",listEvents:"events.list",watchEvents:"events.watch",addTaskLink:"link.add",addTaskRepoTarget:"task.repo.add",listTaskLinks:"link.list",openFile:"file.open",refreshInteractiveState:"interactive.refresh",showSelectedTask:"task.show",streamTaskLogs:"task.logs",streamSelectedTaskLogs:"task.logs",showTaskDiff:"task.diff",showSelectedTaskDiff:"task.diff",openTask:"task.open",openSelectedTask:"task.open",runChecks:"task.check",runSelectedTaskChecks:"task.check",commitTask:"task.commit",commitSelectedTask:"task.commit",showContext:"context.show",help:"help",exit:"exit"}[e.kind]}function Aa(){return["Craig commands:"," craig [--workspace-root <path>] [--task <id>] [--json] [--no-input] <command>"," craig context show Show resolved workspace, task, and agent-tab context"," craig repo add <path> Register a repo in the current Craig workspace"," craig workspace add <path> Register a repo or parent-directory workspace"," craig repo list List registered repos"," craig repo remove <id> Remove a registered repo"," craig workspace list [--archived] List workspaces"," craig workspace archive <id> Archive a workspace"," craig workspace restore <id> Restore an archived workspace"," craig workspace remove <id> Remove an archived workspace"," craig file open <path> Open a readable file in the active Craig TUI (preview)"," craig task new --repo <repo-id> [--runner codex|cursor|claude|pi] <prompt>"," craig task new --workspace <workspace-id> [--runner codex|cursor|claude|pi] <prompt>"," craig task create-child [--parent <task-id>] [--repo <repo-id> | --workspace <workspace-id>] [--runner codex|cursor|claude|pi] [--idempotency-key <key>] <prompt>"," craig task children [<task-id>] List direct child tasks"," craig task cancel-tree [<task-id>] Cancel a task and all descendants"," craig task list [--repo <repo-id>] List known Craig tasks"," craig task current Show the task resolved from flags, environment, or cwd"," craig task rename <name> Rename the resolved task without changing its ID or worktree"," craig task show [<id>] Show task details; omit id to use resolved context"," craig task repo add <task-id> <repo-id> Provision a repo target in an existing project task"," craig task pr show [<id>] [--repo <repo-id>]"," craig task pr discover [<id>] [--repo <repo-id>]"," craig task pr link [<id>] --pr <url|number> [--repo <repo-id>]"," craig task pr refresh [<id>] [--repo <repo-id>]"," craig task pr unlink [<id>] --pr <url|number> [--repo <repo-id>]"," craig agent list [--task <task-id>] List agent-tab and task roll-up states"," craig agent status [--task <task-id>] [--tab <tab-id>] Show agent state details"," craig agent send --task <task-id> [--tab <tab-id>] (--prompt <text> | --prompt-file <path> | --stdin)"," [--delivery when-ready|immediate] [--timeout <duration>] [--idempotency-key <key>]"," craig command show <command-id> Show a durable prompt command"," craig command list [--task <task-id>] List durable prompt commands"," craig command cancel <command-id> Cancel a queued prompt command"," craig command wait <command-id> [--state <states>] [--timeout <duration>]"," craig task wait [<id>] --state <states> [--tab <tab-id>] [--timeout <duration>]"," craig events list [--task <task-id>] [--type <glob>] [--after <cursor>] --json"," craig events watch [--task <task-id>] [--type <glob>] [--after <cursor>] [--format jsonl]"," craig fury validate <file> Validate a versioned fury YAML definition"," craig fury plan <file> [--root-task <id>] [--input key=value] Create an immutable approval plan"," craig fury approve <plan-id> Approve an exact validated plan (human only)"," craig fury run <plan-id> Start the single run authorized by an approved plan"," craig fury status|watch|cancel|resume <run-id> Inspect or control a durable run"," craig fury step complete|fail --run <run-id> --step <step-id> Explicitly finish agent work"," craig fury reviews list [--run <run-id>] [--state <state>] List human checkpoints"," craig fury review show|approve|reject|request-changes|resubmit <review-id>"," craig task logs <id> Stream Craig-managed logs for a task"," craig task diff <id> Show the current worktree diff for a task"," craig task open <id> Open the task worktree or print its path"," craig task check <id> Run configured checks for a task"," craig task commit <id> Commit all task worktree changes"," craig link add <task-id> <repo-id> Add contextual repo linkage only (does not provision a target)"," craig link list <task-id> List linked repos for a task"].join(`
|
|
7
7
|
`)}function Nk(e){let t=[...e];t[0]==="--"&&t.shift();let n=[],r={json:!1,noInput:!1},s=new Set,i=!1,o=!0;for(let a=0;a<t.length;a+=1){let l=t[a];if(l==="--"){o=!1,n.push(l);continue}if(!o||!Zd(l)){n.push(l);continue}if(s.has(l))throw I(`Global option ${l} may only be provided once.`);if(s.add(l),l==="--json"){r.json=!0;continue}if(l==="--no-input"){r.noInput=!0;continue}if(l==="--help"||l==="-h"){i=!0;continue}let c=t[a+1];if(c===void 0||c==="--"||Zd(c))throw I(`Global option ${l} requires a value.`);a+=1,l==="--workspace-root"?r.workspaceRoot=M(c,"Workspace root"):r.taskId=M(c,"Task id")}return{commandTokens:n,options:r,help:i}}function Dk(e){if(e.length===0)return{kind:"listWorkspaces",archived:!1};if(e.length===1&&e[0]==="--archived")return{kind:"listWorkspaces",archived:!0};throw I(`Unsupported command: workspace list ${e.join(" ")}`)}function _k(e){if(e.length===0)return{kind:"listTasks"};if(e.length===2&&e[0]==="--repo")return{kind:"listTasks",repoId:M(e[1],"Repo id")};throw I(`Unsupported command: task list ${e.join(" ")}`)}function xk(e){let t,n,r,s=[],i=!0;for(let a=0;a<e.length;a+=1){let l=e[a];if(l==="--"){i=!1;continue}if(!i||!["--repo","--workspace","--runner"].includes(l)){if(i&&l.startsWith("--"))throw I(`Unsupported task new option: ${l}`);s.push(l);continue}let c=e[a+1];if(c===void 0||c==="--")throw I(`Task option ${l} requires a value.`);if(a+=1,l==="--repo"){if(t!==void 0)throw I("Task option --repo may only be provided once.");t=M(c,"Repo id")}else if(l==="--workspace"){if(n!==void 0)throw I("Task option --workspace may only be provided once.");n=M(c,"Workspace id")}else{if(r!==void 0)throw I("Task option --runner may only be provided once.");try{r=k.runners.parse(c)}catch(d){throw I(d instanceof Error?d.message:"Unsupported runner.")}}}if(!t&&!n)throw I("Task creation requires '--repo <repo-id>' or '--workspace <workspace-id>'.");if(t&&n)throw I("Task creation accepts either '--repo' or '--workspace', not both.");let o=M(s.join(" "),"Task prompt");return{kind:"createTask",...t?{repoId:t}:{},...n?{workspaceId:n}:{},...r?{runner:r}:{},prompt:o}}function Fk(e){let t,n,r,s,i,o=[],a=!0;for(let l=0;l<e.length;l+=1){let c=e[l];if(c==="--"){a=!1;continue}if(!a||!["--parent","--repo","--workspace","--runner","--idempotency-key"].includes(c)){if(a&&c.startsWith("--"))throw I(`Unsupported task create-child option: ${c}`);o.push(c);continue}let d=e[l+1];if(d===void 0||d==="--")throw I(`Task option ${c} requires a value.`);if(l+=1,c==="--parent"){if(t)throw I("Task option --parent may only be provided once.");t=M(d,"Parent task id")}else if(c==="--repo"){if(n)throw I("Task option --repo may only be provided once.");n=M(d,"Repo id")}else if(c==="--workspace"){if(r)throw I("Task option --workspace may only be provided once.");r=M(d,"Workspace id")}else if(c==="--runner"){if(s)throw I("Task option --runner may only be provided once.");try{s=k.runners.parse(d)}catch(u){throw I(u instanceof Error?u.message:"Unsupported runner.")}}else{if(i)throw I("Task option --idempotency-key may only be provided once.");i=M(d,"Idempotency key")}}if(n&&r)throw I("Child task creation accepts only one of --repo or --workspace.");return{kind:"createChildTask",...t?{parentTaskId:t}:{},...n?{repoId:n}:{},...r?{workspaceId:r}:{},prompt:M(o.join(" "),"Child task prompt"),...s?{runner:s}:{},...i?{idempotencyKey:i}:{}}}function Lk(e){let[t,...n]=e;if(!["show","discover","link","refresh","unlink"].includes(t??""))throw I(`Unsupported command: task pr ${e.join(" ")}`);let r,s,i;for(let a=0;a<n.length;a+=1){let l=n[a];if(l!=="--repo"&&l!=="--pr"){if(l.startsWith("--"))throw I(`Unsupported task pr ${t} option: ${l}`);if(r!==void 0)throw I(`task pr ${t} accepts at most one task id.`);r=M(l,"Task id");continue}let c=n[a+1];if(c===void 0||c==="--")throw I(`Task PR option ${l} requires a value.`);if(a+=1,l==="--repo"){if(s!==void 0)throw I("Task PR option --repo may only be provided once.");s=M(c,"Repo id")}else{if(i!==void 0)throw I("Task PR option --pr may only be provided once.");i=M(c,"Pull request selector")}}if((t==="link"||t==="unlink")&&i===void 0)throw I(`task pr ${t} requires --pr <url|number>.`);if(t!=="link"&&t!=="unlink"&&i!==void 0)throw I(`task pr ${t} does not accept --pr.`);let o={...r?{taskId:r}:{},...s?{repoId:s}:{}};switch(t){case"show":return{kind:"showTaskPr",...o};case"discover":return{kind:"discoverTaskPr",...o};case"link":return{kind:"linkTaskPr",...o,pullRequest:i};case"refresh":return{kind:"refreshTaskPr",...o};case"unlink":return{kind:"unlinkTaskPr",...o,pullRequest:i};default:throw I(`Unsupported command: task pr ${e.join(" ")}`)}}var Ea=300*1e3,Mk=new Set(["idle","working","ready","error"]),jk=new Set(["queued","delivering","delivered","failed","cancelled"]);function qk(e){if(e.length===0)return{kind:"showAgentStatus"};if(e.length===2&&e[0]==="--tab")return{kind:"showAgentStatus",tabId:M(e[1],"Agent tab id")};throw I(`Unsupported command: agent status ${e.join(" ")}`)}function Uk(e){let t,n,r="when-ready",s=Ea,i,o=new Set;for(let a=0;a<e.length;a+=1){let l=e[a];if(!["--prompt","--prompt-file","--stdin","--tab","--delivery","--timeout","--idempotency-key"].includes(l))throw I(`Unsupported agent send option: ${l}`);if(o.has(l))throw I(`Agent send option ${l} may only be provided once.`);if(o.add(l),l==="--stdin"){if(t)throw I("Agent send accepts exactly one prompt source.");t={source:"stdin"};continue}let c=e[a+1];if(c===void 0||c.startsWith("--"))throw I(`Agent send option ${l} requires a value.`);if(a+=1,l==="--prompt"||l==="--prompt-file"){if(t)throw I("Agent send accepts exactly one prompt source.");t=l==="--prompt"?{source:"inline",text:M(c,"Prompt")}:{source:"file",path:M(c,"Prompt file")}}else if(l==="--tab")n=M(c,"Agent tab id");else if(l==="--delivery"){if(c!=="when-ready"&&c!=="immediate")throw I('Agent send delivery must be "when-ready" or "immediate".');r=c}else l==="--timeout"?s=$a(c):i=M(c,"Idempotency key")}if(!t)throw I("Agent send requires --prompt, --prompt-file, or --stdin.");return{kind:"sendAgentPrompt",prompt:t,delivery:r,timeoutMs:s,...n?{tabId:n}:{},...i?{idempotencyKey:i}:{}}}function Bk(e){let t=M(e[0]??"","Command id"),n,r=Ea,s=new Set;for(let i=1;i<e.length;i+=1){let o=e[i];if(o!=="--state"&&o!=="--timeout")throw I(`Unsupported command wait option: ${o}`);if(s.has(o))throw I(`Command wait option ${o} may only be provided once.`);s.add(o);let a=e[i+1];if(a===void 0||a.startsWith("--"))throw I(`Command wait option ${o} requires a value.`);i+=1,o==="--state"?n=Wk(a):r=$a(a)}return{kind:"waitPromptCommand",commandId:t,...n?{states:n}:{},timeoutMs:r}}function Wk(e){let t=e.split(",").map(n=>n.trim()).filter(Boolean);if(t.length===0||t.some(n=>!jk.has(n)))throw I(`Invalid command state list "${e}". Use queued, delivering, delivered, failed, or cancelled.`);return[...new Set(t)]}function Xd(e,t){let n,r,s="human",i=new Set;for(let a=0;a<e.length;a+=1){let l=e[a];if(!["--type","--after","--format"].includes(l))throw I(`Unsupported events ${t?"watch":"list"} option: ${l}`);if(!t&&l==="--format")throw I("--format is supported only by events watch.");if(i.has(l))throw I(`Events option ${l} may only be provided once.`);i.add(l);let c=e[a+1];if(c===void 0||c.startsWith("--"))throw I(`Events option ${l} requires a value.`);if(a+=1,l==="--type")n=M(c,"Event type glob");else if(l==="--after")r=M(c,"Event cursor");else if(c==="jsonl")s="jsonl";else throw I('Events watch format must be "jsonl".')}let o={...n?{typeGlob:n}:{},...r?{after:r}:{}};return t?{kind:"watchEvents",...o,format:s}:{kind:"listEvents",...o}}function Vk(e){let t,n,r,s=Ea,i=new Set;for(let o=0;o<e.length;o+=1){let a=e[o];if(!["--state","--tab","--timeout"].includes(a)){if(a.startsWith("--"))throw I(`Unsupported task wait option: ${a}`);if(t!==void 0)throw I("task wait accepts at most one task id.");t=M(a,"Task id");continue}if(i.has(a))throw I(`Task wait option ${a} may only be provided once.`);i.add(a);let l=e[o+1];if(l===void 0||l.startsWith("--"))throw I(`Task wait option ${a} requires a value.`);o+=1,a==="--state"?n=Jk(l):a==="--tab"?r=M(l,"Agent tab id"):s=$a(l)}if(!n)throw I("task wait requires --state <idle|working|ready|error>[,...].");return{kind:"waitTask",...t?{taskId:t}:{},states:n,...r?{tabId:r}:{},timeoutMs:s}}function Kk(e){let t,n,r={};for(let s=0;s<e.length;s+=1){let i=e[s];if(i!=="--input"&&i!=="--root-task"){if(i.startsWith("--"))throw I(`Unsupported fury plan option: ${i}`);if(t!==void 0)throw I("fury plan accepts exactly one definition file.");t=M(i,"Fury file");continue}let o=e[s+1];if(o===void 0||o.startsWith("--"))throw I(`Fury plan option ${i} requires a value.`);if(s+=1,i==="--root-task"){if(n)throw I("Fury plan option --root-task may only be provided once.");n=M(o,"Root task id");continue}let a=o.indexOf("=");if(a<1)throw I(`Invalid fury input "${o}". Use key=value.`);let l=M(o.slice(0,a),"Fury input name");if(Object.hasOwn(r,l))throw I(`Fury input "${l}" may only be provided once.`);r[l]=o.slice(a+1)}if(!t)throw I("fury plan requires a definition file.");return{kind:"planFury",file:t,inputs:r,...n?{rootTaskId:n}:{}}}function Gk(e){let t=M(e[0]??"","Fury run id"),n,r="human";for(let s=1;s<e.length;s+=2){let i=e[s],o=e[s+1];if(!o||!["--after","--format"].includes(i??""))throw I("fury watch supports --after and --format jsonl.");if(i==="--after")n=M(o,"Event cursor");else if(o==="jsonl")r=o;else throw I("fury watch format must be jsonl.")}return{kind:"watchFury",runId:t,...n?{after:n}:{},format:r}}function Hk(e){let t=e[0];if(t!=="complete"&&t!=="fail")throw I("fury step requires complete or fail.");let n=Oa(e.slice(1),["--run","--step","--output","--output-file","--stdin","--reason"]),r=M(n.get("--run")??"","Fury run id"),s=M(n.get("--step")??"","Fury step id");if(t==="fail"){if(["--output","--output-file","--stdin"].some(a=>n.has(a)))throw I("fury step fail accepts only --reason.");return{kind:"failFuryStep",runId:r,stepId:s,reason:M(n.get("--reason")??"","Failure reason")}}if(n.has("--reason"))throw I("fury step complete does not accept --reason.");let i=["--output","--output-file","--stdin"].filter(a=>n.has(a));if(i.length>1)throw I("fury step complete accepts only one output source.");let o=i[0];return{kind:"completeFuryStep",runId:r,stepId:s,...o==="--output"?{output:{source:"inline",text:n.get(o)}}:o==="--output-file"?{output:{source:"file",path:n.get(o)}}:o==="--stdin"?{output:{source:"stdin"}}:{}}}function Yk(e){if(e[0]!=="list")throw I("fury reviews requires list.");let t=Oa(e.slice(1),["--run","--state"]),n=t.get("--run"),r=t.get("--state");if(r&&!["waiting_for_review","changes_requested","approved","rejected","timed_out","cancelled"].includes(r))throw I(`Unsupported fury review state: ${r}`);return{kind:"listFuryReviews",...n?{runId:n}:{},...r?{state:r}:{}}}function zk(e){let t=e[0],n=M(e[1]??"","Fury review id");if(t==="show")return ei(e,2,"fury review show"),{kind:"showFuryReview",reviewId:n};if(!t||!["approve","reject","request-changes","resubmit"].includes(t))throw I("Unsupported fury review action.");let r=Oa(e.slice(2),["--note","--reason","--summary"]),s=t==="request-changes"?"request_changes":t,i=r.get("--note")??r.get("--reason")??r.get("--summary"),o=t==="approve"?"--note":t==="resubmit"?"--summary":"--reason";if([...r.keys()].some(a=>a!==o))throw I(`fury review ${t} accepts only ${o}.`);return{kind:"actFuryReview",reviewId:n,action:s,...i?{message:i}:{}}}function Oa(e,t){let n=new Map;for(let r=0;r<e.length;r+=1){let s=e[r];if(!t.includes(s)||n.has(s))throw I(`Unsupported or duplicate option: ${s}`);if(s==="--stdin"){n.set(s,"true");continue}let i=e[++r];if(i===void 0||i.startsWith("--"))throw I(`Option ${s} requires a value.`);n.set(s,M(i,s))}return n}function Jk(e){let t=e.split(",").map(n=>n.trim()).filter(Boolean);if(t.length===0||t.some(n=>!Mk.has(n)))throw I(`Invalid agent state list "${e}". Use idle, working, ready, or error.`);return[...new Set(t)]}function $a(e){let t=/^(\d+)(ms|s|m|h)$/.exec(e.trim());if(!t)throw I(`Invalid duration "${e}". Use values such as 500ms, 30s, 5m, or 1h.`);let n=Number(t[1]),r={ms:1,s:1e3,m:6e4,h:36e5}[t[2]],s=n*r;if(!Number.isSafeInteger(s))throw I(`Duration "${e}" is too large.`);return s}function Qd(e,t){return{mode:"command",command:e,commandName:$k(e),options:t}}function Zd(e){return["--json","--no-input","--workspace-root","--task","--help","-h"].includes(e)}function _r(e,t){ei(e,0,t)}function ei(e,t,n){if(e.length!==t)throw I(`Command ${n} received an unexpected number of arguments.`)}function ne(e,t){if(e.length!==1)throw I(`${t} is required and must be provided once.`);return M(e[0],t)}function Ca(e,t){return M(e.join(" "),t)}function Zs(e,t,n){return M(e[t]??"",n)}function M(e,t){let n=e.trim();if(n.length===0)throw I(`${t} cannot be empty.`);return n}function I(e){return new g("CLI_USAGE",`${e}
|