allwright 1.33.0 → 1.34.0
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/bin/allwright.js +1 -1
- package/package.json +1 -1
package/bin/allwright.js
CHANGED
|
@@ -940,7 +940,7 @@ _Created via Allwright Compose`+(!g.authored&&d.requestedBy?` by ${d.requestedBy
|
|
|
940
940
|
_(requested by ${d.requestedBy} via Allwright)_`:"")),y.info(`Compose created ${M}`+(d.requestedBy?` for ${d.requestedBy}`:"")+(d.triggerComment?` with trigger "${d.triggerComment.trim()}"`:"")),v.sendChatCreateTicketResult(d.requestId,{ok:!0,issueKey:M})}catch(g){v.sendChatCreateTicketResult(d.requestId,{ok:!1,issueKey:"",error:g instanceof Error?g.message:String(g)})}},onAuditStart:async d=>{let m=x(d.projectId);if(!m){v.sendAuditStartResult(d.requestId,{ok:!1,error:A(d.projectId)});return}try{y.info(`Audit (${d.role}) starting on ${m.project.repoName}`+(d.scope.kind!=="repo"?` scoped to ${d.scope.kind}:${d.scope.ref}`:""));let g=Ke(t,m.project,"assist");if("error"in g){v.sendAuditStartResult(d.requestId,{ok:!1,error:g.error});return}let C=await Yr({projectId:d.projectId,repoPath:m.repoPath,role:d.role,scope:d.scope,detailLevel:d.detailLevel,model:d.model,agent:g,jira:s(m.project.repoName)});if(!C.ok){v.sendAuditStartResult(d.requestId,{ok:!1,error:C.error});return}v.sendAuditStartResult(d.requestId,{ok:!0,audit:C.audit})}catch(g){v.sendAuditStartResult(d.requestId,{ok:!1,error:g instanceof Error?g.message:String(g)})}},onAuditList:async d=>{try{v.sendAuditListResult(d.requestId,{ok:!0,audits:cc(d.projectId)})}catch(m){v.sendAuditListResult(d.requestId,{ok:!1,error:m instanceof Error?m.message:String(m)})}},onAuditGet:async d=>{try{let m=fc(d.projectId,d.auditId);if(!m){v.sendAuditGetResult(d.requestId,{ok:!1,error:"audit not found on this runner"});return}v.sendAuditGetResult(d.requestId,{ok:!0,audit:m})}catch(m){v.sendAuditGetResult(d.requestId,{ok:!1,error:m instanceof Error?m.message:String(m)})}},onAuditReview:async d=>{try{let m=fa(d.projectId,d.auditId,{selected:d.selected,ticketed:d.ticketed,verdicts:d.verdicts,verdictBy:d.verdictBy});if(!m){v.sendAuditReviewResult(d.requestId,{ok:!1,error:"audit not found on this runner"});return}let g=x(d.projectId);if(g&&d.verdicts.length){let C=[];for(let M of d.verdicts){if(M.verdict==="valid"||m.lessonsWritten.includes(M.findingId))continue;let V=m.findings.find(W=>W.id===M.findingId);V&&(ba(g.repoPath,m.role,wc(V,M.verdict,M.note,d.verdictBy)),C.push(M.findingId),y.info(`Lesson written (${m.role}): ${M.verdict} - ${V.title.slice(0,60)}`))}C.length&&(m=fa(d.projectId,d.auditId,{markLessonsWritten:C})??m)}v.sendAuditReviewResult(d.requestId,{ok:!0,audit:m})}catch(m){v.sendAuditReviewResult(d.requestId,{ok:!1,error:m instanceof Error?m.message:String(m)})}},onKnowledgeList:async d=>{let m=x(d.projectId);if(!m){v.sendKnowledgeListResult(d.requestId,{ok:!1,error:A(d.projectId)});return}try{v.sendKnowledgeListResult(d.requestId,{ok:!0,files:kc(m.repoPath)})}catch(g){v.sendKnowledgeListResult(d.requestId,{ok:!1,error:g instanceof Error?g.message:String(g)})}},onKnowledgeSave:async d=>{let m=x(d.projectId);if(!m){v.sendKnowledgeSaveResult(d.requestId,{ok:!1,error:A(d.projectId)});return}try{d.append?ba(m.repoPath,d.role,_c(d.content,d.by),d.level):Sc(m.repoPath,d.role,d.level,d.source,d.name,d.content),y.info(`Knowledge ${d.append?"taught":"saved"}: ${d.role}/${d.level}/${d.name}`),v.sendKnowledgeSaveResult(d.requestId,{ok:!0})}catch(g){v.sendKnowledgeSaveResult(d.requestId,{ok:!1,error:g instanceof Error?g.message:String(g)})}},onEpicList:async d=>{let m=x(d.projectId);if(!m){v.sendEpicListResult(d.requestId,{ok:!1,error:A(d.projectId)});return}try{let g=s(m.project.repoName);if(d.epicKey){let C=await g.epicChildren(d.epicKey);v.sendEpicListResult(d.requestId,{ok:!0,children:C})}else{let C=await g.searchEpics(m.project.jiraProjectKey);v.sendEpicListResult(d.requestId,{ok:!0,epics:C})}}catch(g){v.sendEpicListResult(d.requestId,{ok:!1,error:g instanceof Error?g.message:String(g)})}},onEpicSuggest:async d=>{let m=x(d.projectId);if(!m){v.sendEpicSuggestResult(d.requestId,{ok:!1,error:A(d.projectId)});return}try{let g=s(m.project.repoName),C=await g.epicChildren(d.epicKey),M=Qu(C);if(!M.length){v.sendEpicSuggestResult(d.requestId,{ok:!1,error:`every child of ${d.epicKey} is already done or in an agent's hands - nothing to sequence`});return}if(M.length===1){v.sendEpicSuggestResult(d.requestId,{ok:!0,issueKey:M[0].key,reason:"It's the only pending ticket left in this epic.",considered:1});return}let V=await Promise.all(M.slice(0,12).map(async ne=>{try{let de=await g.getIssue(ne.key);return{...ne,description:de.description}}catch{return{...ne,description:""}}})),W=(await g.getIssue(d.epicKey).catch(()=>null))?.summary??"";y.info(`Epic suggest: weighing ${V.length} pending children of ${d.epicKey}`);let ee=Ke(t,m.project,"assist");if("error"in ee){v.sendEpicSuggestResult(d.requestId,{ok:!1,error:ee.error});return}let L=await ee.adapter.run({repoPath:m.repoPath,prompt:ec(d.epicKey,W,V),timeoutSeconds:150,bin:ee.bin,mode:"read_only",maxTurns:20,sessionId:(0,Zs.randomUUID)(),model:d.model||"claude-sonnet-5",onLog:()=>{}}),D=tc(L.resultText,V.map(ne=>ne.key));if("error"in D){v.sendEpicSuggestResult(d.requestId,{ok:!1,error:D.error});return}y.info(`Epic suggest: ${d.epicKey} -> do ${D.issueKey} first`),v.sendEpicSuggestResult(d.requestId,{ok:!0,issueKey:D.issueKey,reason:D.reason,considered:V.length})}catch(g){v.sendEpicSuggestResult(d.requestId,{ok:!1,error:g instanceof Error?g.message:String(g)})}},onTeamCreds:async d=>{try{let m=ye()??t;if(m.github?.token&&!m.github.login)try{let{GitHubClient:C}=await Promise.resolve().then(()=>(ut(),or));m.github.login=await new C(m.github.token).whoami(),ge(m)}catch{}let g=Gu(m,d.emails);v.sendTeamCredsResult(d.requestId,{ok:!0,...g})}catch(m){v.sendTeamCredsResult(d.requestId,{ok:!1,error:m instanceof Error?m.message:String(m)})}},onSetupStatus:async d=>{try{let m=ye()??t,{buildSetupReport:g}=await Promise.resolve().then(()=>(gf(),mf)),C=await g(m,d.repoNames,t);v.sendSetupStatusResult(d.requestId,{ok:!0,...C})}catch(m){v.sendSetupStatusResult(d.requestId,{ok:!1,error:m instanceof Error?m.message:String(m)})}},onSetupClaudeMdGenerate:async d=>{try{let m=x(d.projectId);if(!m){v.sendSetupClaudeMdGenerateResult(d.requestId,{ok:!1,error:"no local checkout mapped for that project"});return}let g=d.kind==="deploy"?"DEPLOY.md":d.kind==="design"?"DESIGN.md":"CLAUDE.md";y.info(`Setup: drafting ${g} for ${m.project.repoName}`);let C="Explore this repository and draft the content of a CLAUDE.md file for its repo root - the memory file AI agents read before working on tickets here. Cover: what the product does (one paragraph), the tech stack, how the code is organized (key directories and what lives in them), exact commands to install dependencies / build / run tests, code conventions worth following, and gotchas a newcomer would trip over. Under 150 lines, factual, no marketing language, nothing you cannot verify from the code. Reply with ONLY the file content - no preamble, no fences around the whole thing.",M=`Inspect this repository (deploy scripts, CI files, server configs, package scripts) and draft the content of a DEPLOY.md deploy contract for its repo root. An automation tool will follow it LITERALLY, so only write what you can verify from the repo. IMPORTANT: you are running ON the machine where deploys will execute - commands are plain local commands, no ssh wrapper, unless the repo clearly documents a different target machine. For each environment that VERIFIABLY exists: name, branch, exact deploy commands, secrets as $NAMES only (never values), pre/post checks (post-restart checks must wait and retry - services report active before their port binds). Where you cannot verify something (hosts, service names, ports), write it with a clear "VERIFY:" marker so the human fills it in during review, instead of guessing. State explicitly which environments do NOT exist.
|
|
941
941
|
|
|
942
942
|
Seven things decide whether this document can actually be run:
|
|
943
|
-
1. Open with a "## Blockers" section listing what STOPS an automated deploy today - no restart mechanism, no lockfile where the install command needs one, a secret with no home. Keep it separate from VERIFY: markers, which are questions. A blocker is "this cannot run"; a VERIFY: is "I could not confirm this". If there are none, write "None" - do not pad it.
|
|
943
|
+
1. Open with a "## Blockers" section listing what STOPS an automated deploy today - no restart mechanism, no lockfile where the install command needs one, a secret with no home. Keep it separate from VERIFY: markers, which are questions. A blocker is "this cannot run"; a VERIFY: is "I could not confirm this". Every blocker MUST end with a sentence starting "Fix:" naming the smallest concrete action that closes it and who can do it - someone with shell on that machine, or a code change that can become a ticket. A blocker without a fix is just bad news, and it is read by someone who cannot open the document to go looking for the answer. If there are none, write "None" - do not pad it.
|
|
944
944
|
2. Put every assertion in the step where it is TRUE. A check that only holds after the code is pulled does not belong in pre-checks: written there it fails every single deploy, because being behind the remote is the reason a deploy is running.
|
|
945
945
|
3. A check that cannot fail is not a check. Every verification must exit non-zero when it is wrong - a loop that prints "WARN" and moves on turns a broken release into a green one. If something genuinely should not block the deploy, say so explicitly and mark it a warning ON PURPOSE.
|
|
946
946
|
4. Behind a reverse proxy, HTTP 200 does not prove a page exists: a SPA fallback answers 200 for every path, including deleted ones. Check for something only the real page contains, and include one path that MUST 404 to prove 404s still work.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "allwright",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.34.0",
|
|
4
4
|
"description": "Allwright — the AI teammate that runs on YOUR machine. Polls your Jira, runs jailed agents in your local checkouts, opens PRs, executes approved deploys, and audits security/testing/architecture. Credentials and code never leave your host.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"allwright": "bin/allwright.js",
|