@automagik/genie 4.260505.1 → 4.260505.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/genie.js CHANGED
@@ -2141,7 +2141,7 @@ Agent "${ctx.workerId}" SDK session ended.`),ctx.workerId}async function launchI
2141
2141
  Agent "${ctx.workerId}" session ended.`),process.exit(result2.status??0)}async function findDeadResumable(team,role,isAliveFn=isPaneAliveOrDead){let prefiltered=(await list()).filter((w)=>w.role===role&&w.team===team&&w.provider==="claude"&&w.transport==="tmux"),candidate=null;for(let w of prefiltered)if((await getCurrentExecutor(w.id))?.claudeSessionId){candidate=w;break}if(!candidate)return null;if(await isAliveFn(candidate.paneId)){if(candidate.kind==="permanent")throw new OwnerSpawnCollisionError(role,team,candidate.id,candidate.paneId,candidate.state);return null}return candidate}async function rejectDuplicateRole(team,role){let existing=await list();for(let w of existing){if(w.team!==team)continue;let matchesRole=w.role===role,matchesName=w.id===role;if(!matchesRole&&!matchesName)continue;if(await classifyCollisionLiveness(w)==="alive"){let collisionLabel=matchesName&&!matchesRole?`name "${w.id}"`:`role "${role}"`;console.error(`Error: Worker with ${collisionLabel} already exists in team "${team}" (state: ${w.state}, pane: ${w.paneId})
2142
2142
  Use a different --role name for a second worker, e.g.: --role ${role}-2`),process.exit(1)}await unregister(w.id)}}async function classifyCollisionLiveness(w){if(!await resolveWorkerLivenessByTransport(w))return"dead";if(w.session&&/^%\d+$/.test(w.paneId)){if(await getPaneSession(w.paneId)!==w.session)return"recycled"}return"alive"}async function getPaneSession(paneId){try{return(await executeTmux2(`display-message -t '${paneId}' -p '#{session_name}'`)).trim()||null}catch{return null}}async function resolveNativeTeam(team,_repoPath,options){let leaderName=await resolveLeaderName(team),sanitizedTeam=sanitizeTeamName(team),leaderAgent=await getAgentByName(leaderName,sanitizedTeam).catch(()=>null),parentSessionId;if(leaderAgent&&!options.isIdentitySpawn)parentSessionId=(await shouldResume(leaderAgent.id).catch(()=>null))?.sessionId;if(!parentSessionId)parentSessionId=await discoverClaudeParentSessionId()??`genie-${team}`;await ensureNativeTeam(team,`Genie team: ${team}`,parentSessionId);let spawnColor=options.color??await assignColor(team),nativeTeam;if(options.provider==="claude")nativeTeam={enabled:!0,parentSessionId,color:spawnColor,agentType:options.role??"general-purpose",planModeRequired:options.planMode,permissionMode:options.permissionMode,agentName:options.role};return{parentSessionId,spawnColor,nativeTeam}}function autoSyncDisabled(options){return options.noAutoSync===!0||options.autoSync===!1||process.env.GENIE_DISABLE_AUTO_SYNC==="1"}function isWithinAgentsRoot(agentsRoot,agentDir){let rel=relative(agentsRoot,agentDir);return rel!==""&&!rel.startsWith("..")&&!isAbsolute2(rel)}async function tryAutoRegisterAgent(name,options){if(autoSyncDisabled(options))return null;let workspace=_spawnAutoSyncDeps.findWorkspace();if(!workspace)return null;let agentsRoot=join50(workspace.root,"agents"),agentDir=resolvePath(agentsRoot,name);if(!isWithinAgentsRoot(agentsRoot,agentDir))return null;let agentsMdPath=join50(agentDir,"AGENTS.md");if(!_spawnAutoSyncDeps.existsSync(agentsMdPath))return null;let frontmatter;try{frontmatter=_spawnAutoSyncDeps.parseFrontmatter(_spawnAutoSyncDeps.readFileSync(agentsMdPath,"utf-8"))}catch{return null}if(frontmatter.name!==name)return null;if(typeof frontmatter.description!=="string"||frontmatter.description.trim().length===0)return null;try{if(await _spawnAutoSyncDeps.syncSingleAgentByName(workspace.root,name)==="not-found")return null}catch{return null}let resolved=await _spawnAutoSyncDeps.resolveAgent(name);if(!resolved)return null;return _spawnAutoSyncDeps.stderr(`Auto-registered agent '${name}' from ${agentDir}`),resolved}async function resolveAgentForSpawn(name,options){let resolved=await _spawnAutoSyncDeps.resolveAgent(name)??await tryAutoRegisterAgent(name,options);if(!resolved)console.error(`Error: Agent "${name}" not found in directory or built-ins.`),console.error(` Register with: genie dir add ${name} --dir <path>`),console.error(" Or use a built-in: engineer, reviewer, qa, fix, ..."),process.exit(1);let entry2=resolved.entry,identityPath=null;if(resolved.builtin)identityPath=resolveBuiltinAgentPath(name);else if(entry2.dir)identityPath=_spawnAutoSyncDeps.loadIdentity(entry2);if(!identityPath)identityPath=resolveBuiltinAgentPath(name);let repoPath=resolveAgentWorkingDir(entry2,options.cwd),model=options.model;if(!model){let ctx=buildSpawnResolveContext(name,entry2);model=resolveField(entry2,"model",ctx)}return{entry:entry2,repoPath,identityPath,model}}function buildSpawnResolveContext(agentName,_entry){let ctx={};try{let ws=findWorkspace();if(ws){let wsConfig=getWorkspaceConfig(ws.root);ctx.workspaceDefaults=wsConfig.agents?.defaults}}catch{}if(agentName.includes("/")){let parentName=agentName.split("/")[0];try{let{readFileSync:readFileSync28,existsSync:existsSync43}=__require("fs"),{join:join51}=__require("path"),ws=findWorkspace();if(ws){let parentAgentsMd=join51(ws.root,"agents",parentName,"AGENTS.md");if(existsSync43(parentAgentsMd)){let{parseFrontmatter:parseFrontmatter3}=(init_frontmatter(),__toCommonJS(exports_frontmatter)),parentFm=parseFrontmatter3(readFileSync28(parentAgentsMd,"utf-8"));ctx.parent={name:parentName,fields:parentFm}}}}catch{}}return ctx}function resolveAgentWorkingDir(entry2,explicitCwd){if(explicitCwd)return explicitCwd;if(entry2.dir)return entry2.dir;let repo=entry2.repo;if(repo&&__require("fs").existsSync(repo))return repo;return process.cwd()}function buildDirectoryPermissionSpawnParams(entry2){let permissions=entry2.permissions?.allow?.length||entry2.permissions?.deny?.length?{allow:entry2.permissions.allow,deny:entry2.permissions.deny}:void 0;return{...permissions?{permissions}:{},...entry2.disallowedTools?{disallowedTools:entry2.disallowedTools}:{}}}async function buildSpawnParams2(name,team,options,agent,preassignedSessionId,agentTemplate){let resolvedProvider=options.provider??agent.entry.provider??"claude",params={provider:resolvedProvider,team,role:name,agentTemplate:agentTemplate??name,skill:options.skill,extraArgs:options.extraArgs,model:agent.model,systemPromptFile:agent.identityPath??void 0,promptMode:agent.entry.promptMode,initialPrompt:options.prompt??options.initialPrompt,newWindow:options.newWindow,windowTarget:options.window,...buildDirectoryPermissionSpawnParams(agent.entry)},isIdentitySpawn=options.role!==void 0&&options.role!==name,{parentSessionId,spawnColor,nativeTeam}=await resolveNativeTeam(team,agent.repoPath,{...options,provider:resolvedProvider,role:name,isIdentitySpawn});if(nativeTeam)params.nativeTeam=nativeTeam;try{let{injectTeamHooks:injectTeamHooks2}=await Promise.resolve().then(() => (init_inject(),exports_inject));if(await injectTeamHooks2(team))console.log(` Hooks: injected genie hook dispatch into team "${team}"`)}catch(err){console.warn(`Warning: could not inject hooks for team "${team}": ${err instanceof Error?err.message:err}`)}if(params.provider==="codex")try{let{injectCodexHooks:injectCodexHooks2}=await Promise.resolve().then(() => (init_codex_inject(),exports_codex_inject));if(await injectCodexHooks2())console.log(" Hooks: injected genie hook dispatch into ~/.codex/config.toml")}catch(err){console.warn(`Warning: could not inject codex hooks: ${err instanceof Error?err.message:err}`)}if(params.provider==="claude")params.sessionId=preassignedSessionId??crypto.randomUUID();if(params.provider==="claude"){if(await startOtelReceiver())params.otelPort=getOtelPort(),params.otelLogPrompts=!0}return{params,parentSessionId,spawnColor}}async function maybeStartOtelRelay(nt,validated,insideTmux){if(!nt?.enabled&&validated.provider==="codex"&&insideTmux)return ensureCodexOtelConfig(),await ensureOtelRelay(validated.team);return!1}function buildSdkRuntimeExtra(options){let extra={};if(options.sdkMaxTurns!=null)extra.maxTurns=options.sdkMaxTurns;if(options.sdkMaxBudget!=null)extra.maxBudgetUsd=options.sdkMaxBudget;if(options.sdkEffort)extra.effort=options.sdkEffort;if(options.sdkResume)extra.resume=options.sdkResume;return Object.keys(extra).length>0?extra:void 0}async function dispatchSpawn(ctx,validated,options,agent,insideTmux){if(validated.provider==="claude-sdk"){let streamFormat=options.streamFormat??"text",streamOpts=options.stream||options.sdkStream?{stream:!0,streamFormat}:void 0;return await launchSdkSpawn(ctx,agent.entry.permissions,streamOpts,agent.entry.sdk,buildSdkRuntimeExtra(options))}if(insideTmux)return await launchTmuxSpawn(ctx);return await launchInlineSpawn(ctx)}async function resolveTeamName3(opts){if(opts.explicitTeam)return opts.explicitTeam;if(opts.entryTeam)return opts.entryTeam;let env=opts.env??process.env;if(env.GENIE_TEAM)return env.GENIE_TEAM;return await(opts.discover??discoverTeamName)()??null}async function pickParallelShortId(baseName,team,uuid){if(!UUID_REGEX.test(uuid))throw Error(`pickParallelShortId: expected a well-formed UUID (8-4-4-4-12 hex), got ${JSON.stringify(uuid)}`);let{getConnection:getConnection2}=await Promise.resolve().then(() => (init_db(),exports_db)),sql=await getConnection2();for(let k=4;k<=uuid.length;k++){let slice=uuid.slice(0,k),id=`${baseName}-${slice}`;if((await sql`
2143
2143
  SELECT id FROM agents WHERE id = ${id} LIMIT 1
2144
- `).length===0)return slice}return uuid}async function resolveSpawnIdentity(name,team,uuidFactory=()=>crypto.randomUUID(),isAliveFn=(agent)=>resolveWorkerLivenessByTransport(agent)){if(!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(name))return{kind:"canonical",workerId:uuidFactory(),sessionUuid:uuidFactory()};let{getConnection:getConnection2}=await Promise.resolve().then(() => (init_db(),exports_db)),rows=await(await getConnection2())`
2144
+ `).length===0)return slice}return uuid}async function resolveSpawnIdentity(name,team,uuidFactory=()=>crypto.randomUUID(),isAliveFn=(agent)=>resolveWorkerLivenessByTransport(agent)){if(!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(name))return{kind:"canonical",workerId:name,sessionUuid:uuidFactory()};let{getConnection:getConnection2}=await Promise.resolve().then(() => (init_db(),exports_db)),rows=await(await getConnection2())`
2145
2145
  SELECT id, pane_id, team FROM agents WHERE id = ${name} LIMIT 1
2146
2146
  `;if(rows.length===0)return{kind:"canonical",workerId:name,sessionUuid:uuidFactory()};let existing=rows[0];if(existing.team!==null&&existing.team!==team){let sessionUuid2=uuidFactory(),shortId2=await pickParallelShortId(name,team,sessionUuid2);return{kind:"parallel",workerId:`${name}-${shortId2}`,sessionUuid:sessionUuid2,canonicalId:name}}let alive=!1;if(existing.pane_id)try{alive=await isAliveFn({id:existing.id,paneId:existing.pane_id})}catch(err){let message=err instanceof Error?err.message:String(err);if(err instanceof TmuxUnreachableError||message.includes("no server running")||message.includes("server exited")||message.includes("error connecting"))alive=!1;else throw err}if(!alive)return{kind:"canonical",workerId:name,sessionUuid:uuidFactory()};let sessionUuid=uuidFactory(),shortId=await pickParallelShortId(name,team,sessionUuid);return{kind:"parallel",workerId:`${name}-${shortId}`,sessionUuid,canonicalId:name}}async function resolveTeamAndResume(effectiveRole,options,agent){let teamWasExplicit=Boolean(options.team),team=await resolveTeamName3({explicitTeam:options.team,entryTeam:agent.entry?.team});if(!team){let candidates=await findTeamsContainingAgent(effectiveRole);if(candidates.length===1)team=candidates[0];else if(candidates.length>1)return console.error(`Error: agent "${effectiveRole}" is a member of multiple teams (${candidates.join(", ")}). Pass --team <name> to disambiguate.`),process.exit(1)}if(!team){if(await get2(effectiveRole))team=sanitizeTeamName(effectiveRole)}if(!team)return console.error(`Error: --team is required for agent "${effectiveRole}" (or set GENIE_TEAM, run inside a genie session, or register the agent in a team config).`),process.exit(1);let deadResumable=await findDeadResumable(team,effectiveRole);if(deadResumable){let executor=await getCurrentExecutor(deadResumable.id),sessionShort=executor?.claudeSessionId?.slice(0,8)??"unknown";console.log(`Resuming existing session for "${effectiveRole}" (session: ${sessionShort}...)`);try{return await resumeAgent(deadResumable),{team,teamWasExplicit,resumed:deadResumable.id}}catch(err){if(err instanceof ResumePaneVanishedError){if(console.warn(`\u26A0 Resume of "${effectiveRole}" produced a dead pane (${err.reason}). Clearing stale executor and falling through to fresh spawn.`),executor?.id)await updateExecutorState(executor.id,"terminated").catch(()=>{});return{team,teamWasExplicit}}throw err}}return{team,teamWasExplicit}}async function resolveTeamAndResumeOrExit(effectiveRole,options,agent){try{return await resolveTeamAndResume(effectiveRole,options,agent)}catch(err){if(err instanceof OwnerSpawnCollisionError)return console.error(`Error: owner agent "${err.ownerName}" already alive in team "${err.team}" (id: ${err.conflictId}, pane: ${err.conflictPaneId}, state: ${err.conflictState}).
2147
2147
  Owner identities are exclusive \u2014 to spawn a separate worker under the same template, use --role <custom-name>:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automagik/genie",
3
- "version": "4.260505.1",
3
+ "version": "4.260505.2",
4
4
  "description": "Collaborative terminal toolkit for human + AI workflows. NOTE: the npm distribution is being soft-deprecated — the canonical install is `curl -fsSL https://get.automagik.dev/genie | bash` (cosign + SLSA verified). See https://automagik.dev/genie/security/distribution-sovereignty",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genie",
3
- "version": "4.260505.1",
3
+ "version": "4.260505.2",
4
4
  "description": "Human-AI partnership for Claude Code. Share a terminal, orchestrate workers, evolve together. Brainstorm ideas, turn them into wishes, execute with /work, validate with /review, and ship as one team.",
5
5
  "author": {
6
6
  "name": "Namastex Labs"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genie-plugin",
3
- "version": "4.260505.1",
3
+ "version": "4.260505.2",
4
4
  "private": true,
5
5
  "description": "Runtime dependencies for genie bundled CLIs",
6
6
  "type": "module",
@@ -201,7 +201,7 @@ Report orchestrates multiple tools but must **never modify source code** — inv
201
201
 
202
202
  ```bash
203
203
  # Spawn a tracer subagent for investigation
204
- genie agent spawn tracer
204
+ genie agent spawn trace
205
205
  ```
206
206
 
207
207
  Browser dispatch uses direct `agent-browser` commands alongside the trace subagent.
@@ -240,7 +240,7 @@ The report agent:
240
240
  # Agent asks: "What did you see?" → "Engineers show welcome screen but empty prompt"
241
241
 
242
242
  # 2. Run /trace
243
- genie agent spawn tracer
243
+ genie agent spawn trace
244
244
  genie agent send 'Trace: genie work dispatches engineers but they start idle. Check dispatch.ts and protocol-router.ts.' --to tracer
245
245
  # Wait for diagnosis...
246
246
 
@@ -39,7 +39,7 @@ Trace must run in **isolation** — the subagent must not modify any source file
39
39
 
40
40
  ```bash
41
41
  # Spawn a tracer subagent (read-only investigation)
42
- genie agent spawn tracer
42
+ genie agent spawn trace
43
43
  ```
44
44
 
45
45
  ## Task Lifecycle Integration (v4)
@@ -63,7 +63,7 @@ An engineer reports that `genie work` dispatches engineers but they sit idle. Th
63
63
 
64
64
  ```bash
65
65
  # 1. Spawn a tracer (read-only — no code changes)
66
- genie agent spawn tracer
66
+ genie agent spawn trace
67
67
 
68
68
  # 2. Send the symptoms
69
69
  genie agent send 'Trace: genie work dispatches engineers but they start idle at the prompt. No task received. genie wish status shows in_progress but nothing happens. Check dispatch.ts workDispatchCommand and protocol-router.ts sendMessage.' --to tracer