alchemylab 2.0.2 → 2.1.1
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/111.js +14 -0
- package/dist/24.js +37 -0
- package/dist/293.js +58 -0
- package/dist/{491.js → 356.js} +11 -11
- package/dist/414.js +18 -0
- package/dist/478.js +89 -0
- package/dist/{636.js → 579.js} +7 -7
- package/dist/{565.js → 60.js} +8 -8
- package/dist/729.js +46 -88
- package/dist/{129.js → 776.js} +2 -2
- package/dist/{237.js → 800.js} +3 -3
- package/dist/816.js +3 -0
- package/dist/939.js +17 -0
- package/dist/{554.js → 991.js} +12 -12
- package/dist/{301.js → 994.js} +23 -23
- package/dist/cli.js +7423 -7151
- package/dist/document-textconv.js +307 -265
- package/dist/http-server.js +7530 -7524
- package/dist/index.js +7642 -7636
- package/dist/mcp-direct.js +7527 -7521
- package/dist/plugins/hooks/plugin.js +1 -1
- package/dist/plugins/system-logger.js +1 -1
- package/package.json +5 -2
- package/dist/19.js +0 -244
- package/dist/380.js +0 -17
- package/dist/403.js +0 -4
- package/dist/540.js +0 -56
- package/dist/603.js +0 -18
- package/dist/674.js +0 -15
- package/dist/796.js +0 -47
package/dist/{237.js → 800.js}
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use strict"
|
|
2
|
-
exports.
|
|
2
|
+
exports.ids=[800],exports.modules={93800(e,exports,t){var r,o=this&&this.__createBinding||(Object.create?function(e,t,r,o){void 0===o&&(o=r)
|
|
3
3
|
var i=Object.getOwnPropertyDescriptor(t,r)
|
|
4
4
|
i&&!("get"in i?!t.__esModule:i.writable||i.configurable)||(i={enumerable:!0,get:function(){return t[r]}}),Object.defineProperty(e,o,i)}:function(e,t,r,o){void 0===o&&(o=r),e[o]=t[r]}),i=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),c=this&&this.__importStar||(r=function(e){return r=Object.getOwnPropertyNames||function(e){var t=[]
|
|
5
5
|
for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[t.length]=r)
|
|
@@ -8,7 +8,7 @@ var t={}
|
|
|
8
8
|
if(null!=e)for(var c=r(e),s=0;s<c.length;s++)"default"!==c[s]&&o(t,e,c[s])
|
|
9
9
|
return i(t,e),t})
|
|
10
10
|
Object.defineProperty(exports,"__esModule",{value:!0}),exports.SimpleProjectCreationLock=void 0
|
|
11
|
-
const s=c(t(91943)),a=c(t(16928)),n=t(
|
|
11
|
+
const s=c(t(91943)),a=c(t(16928)),n=t(14139)
|
|
12
12
|
exports.SimpleProjectCreationLock=class{constructor(e,t){this.maxWaitMs=3e4,this.checkIntervalMs=500,this.lockFilePath=a.join(e,".alchemy-project-creation.lock"),this.projectFilePath=a.join(e,n.ALCHEMY_DIR_NAME,"project.json"),this.logger=t.child({component:"simple-project-creation-lock"})}async acquireLock(){this.logger.info("Attempting to acquire project creation lock",{processId:process.pid,lockFile:this.lockFilePath})
|
|
13
13
|
const e=await this.loadExistingProject()
|
|
14
14
|
if(e)return this.logger.info("Project already exists, no creation needed",{projectId:e.id}),{acquired:!1,shouldCreate:!1,projectData:e}
|
|
@@ -19,4 +19,4 @@ for(let t=1;t<=e;t++){await this.sleep(this.checkIntervalMs)
|
|
|
19
19
|
const r=await this.loadExistingProject()
|
|
20
20
|
if(r)return this.logger.info("Project creation completed by another process",{projectId:r.id,attempt:t,processId:process.pid}),{acquired:!1,shouldCreate:!1,projectData:r}
|
|
21
21
|
if(!await this.lockFileExists()&&(this.logger.warn("Lock disappeared but no project found, creation may have failed",{attempt:t,processId:process.pid}),t>e/2))return this.logger.info("Attempting to acquire lock after apparent creation failure"),{acquired:!0,shouldCreate:!0}}return this.logger.error("Timeout waiting for project creation",{maxWaitMs:this.maxWaitMs,processId:process.pid}),{acquired:!0,shouldCreate:!0}}async loadExistingProject(){try{const e=await s.readFile(this.projectFilePath,"utf8"),t=JSON.parse(e)
|
|
22
|
-
if(t&&t.id)return t}catch(e){"ENOENT"!==e.code&&this.logger.debug("Failed to load existing project",{error:e.message})}return null}async lockFileExists(){try{return await s.access(this.lockFilePath),!0}catch{return!1}}sleep(e){return new Promise(
|
|
22
|
+
if(t&&t.id)return t}catch(e){"ENOENT"!==e.code&&this.logger.debug("Failed to load existing project",{error:e.message})}return null}async lockFileExists(){try{return await s.access(this.lockFilePath),!0}catch{return!1}}sleep(e){return new Promise(t=>setTimeout(t,e))}}}}
|
package/dist/816.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use strict"
|
|
2
|
+
exports.ids=[816],exports.modules={1816(t,exports){exports.formatCombinedOutput=function(t,o){const e=o.maxOut??3e3,u=t.length>e
|
|
3
|
+
return{output:u?"\u2026"+t.slice(-e):t,truncatedNote:u?`\n_(output truncated: view full with \`log:${o.invocationId}\`)_`:"",logFooter:`Log: \`log:${o.invocationId}\``}}}}
|
package/dist/939.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict"
|
|
2
|
+
exports.ids=[939],exports.modules={49939(e,exports,t){function r(e){return i.default.createHash("md5").update(e).digest("hex")}async function s(e){try{return r(await a.default.promises.readFile(e))}catch{return null}}var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}}
|
|
3
|
+
Object.defineProperty(exports,"__esModule",{value:!0}),exports.syncPluginsGlobal=async function(e,t,n){const i={synced:[],skipped:[],errors:[]},c=n||function(){const e=process.argv[1]
|
|
4
|
+
let t=e
|
|
5
|
+
try{t=a.default.realpathSync(e)}catch{}return o.default.dirname(t)}(),d=o.default.join((0,u.getGlobalConfigDir)(e),"plugin")
|
|
6
|
+
try{await a.default.promises.mkdir(d,{recursive:!0})}catch(e){return t.error("Failed to create global plugin directory",{destDir:d,error:e instanceof Error?e.message:"Unknown error"}),i}const f=o.default.join(d,"package.json"),p='{"type":"module"}\n'
|
|
7
|
+
try{await a.default.promises.readFile(f,"utf8").catch(()=>null)!==p&&await a.default.promises.writeFile(f,p,"utf8")}catch(e){t.warn("Failed to write global plugin package.json",{error:e instanceof Error?e.message:"Unknown error"})}for(const e of l){const n=o.default.join(c,e.sourceName),u=o.default.join(d,e.destName)
|
|
8
|
+
try{if(!a.default.existsSync(n)){t.warn(`Plugin source not found: ${e.sourceName}`,{sourcePath:n}),i.errors.push(e.destName)
|
|
9
|
+
continue}const o=await a.default.promises.readFile(n,"utf8").catch(()=>null)
|
|
10
|
+
if(null===o){t.warn(`Could not read plugin source: ${e.sourceName}`),i.errors.push(e.destName)
|
|
11
|
+
continue}const l=r(o),c=await s(u)
|
|
12
|
+
null===c||l!==c?(await a.default.promises.writeFile(u,o,"utf8"),t.info(`Synced plugin: ${e.destName}`,{destDir:d,reason:null===c?"not installed":"updated"}),i.synced.push(e.destName)):i.skipped.push(e.destName)}catch(r){t.error(`Failed to sync plugin: ${e.destName}`,{error:r instanceof Error?r.message:"Unknown error"}),i.errors.push(e.destName)}}return i.synced.length>0&&t.info("Synced global plugins",{destDir:d,synced:i.synced}),i},exports.cleanupLegacyProjectPlugins=async function(e,t){const r=o.default.join(e,".opencode","plugin"),s=[]
|
|
13
|
+
if(!a.default.existsSync(r))return{removed:s}
|
|
14
|
+
for(const e of c){const t=o.default.join(r,e)
|
|
15
|
+
if(a.default.existsSync(t))try{await a.default.promises.rm(t,{recursive:!0,force:!0}),s.push(e)}catch{}}s.length>0&&t.info("Removed legacy per-project plugin copies",{projectPluginDir:r,removed:s})
|
|
16
|
+
try{0===(await a.default.promises.readdir(r)).length&&await a.default.promises.rmdir(r)}catch{}return{removed:s}}
|
|
17
|
+
const a=n(t(79896)),o=n(t(16928)),i=n(t(76982)),u=t(35419),l=[{sourceName:"plugins/hooks/plugin.js",destName:"event-hooks.js"},{sourceName:"plugins/inject-session.js",destName:"inject-session.js"},{sourceName:"plugins/system-logger.js",destName:"system-logger.js"}],c=[...l.map(e=>e.destName),"package.json","lib"]}}
|
package/dist/{554.js → 991.js}
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use strict"
|
|
2
|
-
exports.
|
|
2
|
+
exports.ids=[991],exports.modules={18991(e,exports,n){async function t(e,t){const s=i.get(e)
|
|
3
3
|
if(s&&!s.checking){s.checking=!0
|
|
4
4
|
try{const r=(0,a.getOpenCodeUrlFromConfig)(s.context.projectPath)?.replace(/\/$/,"")
|
|
5
5
|
if(!r)return
|
|
@@ -7,20 +7,20 @@ if(await async function(e,n){try{const t=await fetch(`${e}/session/status`,{sign
|
|
|
7
7
|
if(!t.ok)return!1
|
|
8
8
|
const o=await t.json(),a=o?.[n]?.type
|
|
9
9
|
return!!a&&"idle"!==a}catch{return!1}}(r,e))return
|
|
10
|
-
if(!
|
|
11
|
-
if(
|
|
12
|
-
|
|
13
|
-
const{executeAction:
|
|
14
|
-
|
|
15
|
-
t&&(clearTimeout(t.expiry),t.poll&&clearInterval(t.poll),
|
|
16
|
-
const a=setTimeout((
|
|
10
|
+
if(!i.has(e))return
|
|
11
|
+
if(f.has(e))return void o(e,"already-nudged")
|
|
12
|
+
f.add(e),o(e,`nudging (${t})`)
|
|
13
|
+
const{executeAction:l}=await Promise.resolve().then(()=>n(5607)),c=s.planWritten?exports.vB:'[handoff nudge] This autonomous planning session went idle WITHOUT writing its plan. If you were waiting on a research subagent, its findings should have reached you by now -- proceed with what you have rather than waiting further. Fill in the plan document with plan_write, decompose it into requests, then call session_message_operations { operation: "offer-handoff", offerHandoff: { summary: "<one-line plan summary>", requestIds: ["req...", ...] } } and STOP. If you genuinely cannot plan this, say why in the plan document and offer handoff anyway. This reminder fires only once.',d=await l("inject-prompt",{sessionId:e,message:c},s.context)
|
|
14
|
+
d.success?s.context.logger.info("planner-handoff watch: nudge injected",{sessionId:e,trigger:t}):s.context.logger.warn("planner-handoff watch: nudge inject failed",{sessionId:e,trigger:t,error:d.error||d.message})}catch(n){s.context.logger.warn("planner-handoff watch: check failed",{sessionId:e,trigger:t,error:(0,r.getErrorMessage)(n)})}finally{s.checking=!1}}}function o(e,n){const t=i.get(e)
|
|
15
|
+
t&&(clearTimeout(t.expiry),t.poll&&clearInterval(t.poll),i.delete(e),t.context.logger.info("planner-handoff watch: stopped",{sessionId:e,reason:n}))}exports.vB=void 0,exports.trackAutonomousPlanner=function(e,n){if(!n||i.has(n)||f.has(n))return
|
|
16
|
+
const a=setTimeout(()=>{o(n,"ttl-expired")},216e5)
|
|
17
17
|
a.unref?.()
|
|
18
18
|
const r={context:e,planWritten:!1,checking:!1,expiry:a}
|
|
19
|
-
r.poll=setInterval((
|
|
19
|
+
r.poll=setInterval(()=>{t(n,"poll")},3e4),r.poll.unref?.(),i.set(n,r),e.logger.info("planner-handoff watch: watching autonomous planner (nudge armed at spawn)",{sessionId:n})},exports.notifyPlannerHandoffToolEvent=function(e,n,t){const a=i.get(e)
|
|
20
20
|
if(!a)return
|
|
21
21
|
const r=t&&"object"==typeof t?t.operation:void 0
|
|
22
|
-
n.includes("session_message_operations")&&"offer-handoff"===r?o(e,"offer-handoff observed"):!a.planWritten&&n.includes("plan_write")&&"string"==typeof r&&
|
|
22
|
+
n.includes("session_message_operations")&&"offer-handoff"===r?o(e,"offer-handoff observed"):!a.planWritten&&n.includes("plan_write")&&"string"==typeof r&&s.has(r)&&(a.planWritten=!0,a.context.logger.info("planner-handoff watch: plan written",{sessionId:e}))},exports.notifyPlannerHandoffSessionIdle=function(e){return i.has(e)?t(e,"idle-event"):Promise.resolve()},exports.hasParkVetoingPlannerHandoffWatches=function(){for(const e of i.values())if(e.planWritten)return!0
|
|
23
23
|
return!1}
|
|
24
|
-
const a=n(
|
|
24
|
+
const a=n(60833),r=n(58824),s=new Set(["create","update","append","replace"])
|
|
25
25
|
exports.vB='[handoff nudge] This autonomous planning session went idle after writing the plan without offering handoff -- the flow is waiting on that call. If the plan and its requests are complete, call session_message_operations { operation: "offer-handoff", offerHandoff: { summary: "<one-line plan summary>", requestIds: ["req...", ...] } } now, then STOP. If requests are not created yet, finish decomposing first, then offer. This reminder fires only once.'
|
|
26
|
-
const
|
|
26
|
+
const i=new Map,f=new Set}}
|
package/dist/{301.js → 994.js}
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict"
|
|
2
|
-
exports.
|
|
2
|
+
exports.ids=[994],exports.modules={75994(t,exports,e){var r=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}}
|
|
3
3
|
Object.defineProperty(exports,"__esModule",{value:!0}),exports.InteractiveShell=void 0
|
|
4
|
-
const s=r(e(23785)),a=e(35317),i=e(83807),o=r(e(16928)),n=r(e(79896)),l=r(e(96895)),c=e(
|
|
4
|
+
const s=r(e(23785)),a=e(35317),i=e(83807),o=r(e(16928)),n=r(e(79896)),l=r(e(96895)),c=e(14139),u=e(44192),h=e(41152),d=e(76634),f=e(79414)
|
|
5
5
|
exports.InteractiveShell=class{constructor(t){if(this.currentBranch="main",this.currentStatus=null,this.history=[],this.statusCache={map:new Map,ts:0},this.pathExecutableCache=null,this.projectPath=t.projectPath,this.currentSymlink=o.default.join(t.projectPath,c.ALCHEMY_DIR_NAME,"current"),this.currentDir=t.projectPath,this.logger=t.logger,this.historyFile=o.default.join(t.projectPath,c.ALCHEMY_DIR_NAME,"shell-history.txt"),this.projectId=t.projectId,this.remoteServerUrl=t.remoteServerUrl,this.authToken=t.authToken,t.remoteServerUrl){const e=(0,h.createMetricsCollector)(!1)
|
|
6
6
|
this.apiClient=new u.BaseApiClient(t.remoteServerUrl,t.logger,e,t.authToken)}}async publishPr(t,e){if(!t||!/^req\d{6}$/.test(t))return void console.log(l.default.red("Usage: publish req###### [base-branch]"))
|
|
7
7
|
if(!this.projectId||!this.remoteServerUrl)return void console.log(l.default.red("Project is not registered with the remote yet."))
|
|
@@ -13,11 +13,11 @@ return e?.data??e??null},fetchReceiptMarkdown:async t=>{const e=await fetch(`${t
|
|
|
13
13
|
if(!e.ok)throw new Error(`Receipt fetch failed: HTTP ${e.status}`)
|
|
14
14
|
return await e.text()}})
|
|
15
15
|
console.log(l.default.green(`${a.created?"PR created":"Receipt added to the existing PR"}: ${a.prUrl}`)),a.statusPosted&&console.log(l.default.gray("Commit status alchemylab/gates set on the head commit."))}catch(t){console.log(l.default.red(t instanceof Error?t.message:String(t)))}}async linearImport(t){if(t&&/^[A-Za-z][A-Za-z0-9]{1,9}-\d{1,6}$/.test(t))try{const e=(0,f.getActionServerBaseUrl)(),r=await fetch(`${e}/api/connections/linear/import`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({issueKey:t.toUpperCase()})}),s=await r.json()
|
|
16
|
-
s.success&&s.data?.requestId?console.log(l.default.green(`Imported ${s.data.issue} as ${s.data.requestId}.`)):console.log(l.default.red(s.error||"Import failed."))}catch(t){console.log(l.default.red(t instanceof Error?t.message:String(t)))}else console.log(l.default.red("Usage: linear <issue key> e.g. linear ENG-123"))}async start(t){return this.shutdownCallback=t,this.currentBranch="main",this.updateCurrentSymlink(),this.loadHistory(),this.rl=s.default.createInterface({input:process.stdin,output:process.stdout,prompt:this.buildPrompt(),historySize:500,removeHistoryDuplicates:!0,completer:t=>this.completer(t)}),this.history.length>0&&(this.rl.history=[...this.history].reverse()),this.printHelp(!0),this.rl.prompt(),new Promise(
|
|
16
|
+
s.success&&s.data?.requestId?console.log(l.default.green(`Imported ${s.data.issue} as ${s.data.requestId}.`)):console.log(l.default.red(s.error||"Import failed."))}catch(t){console.log(l.default.red(t instanceof Error?t.message:String(t)))}else console.log(l.default.red("Usage: linear <issue key> e.g. linear ENG-123"))}async start(t){return this.shutdownCallback=t,this.currentBranch="main",this.updateCurrentSymlink(),this.loadHistory(),this.rl=s.default.createInterface({input:process.stdin,output:process.stdout,prompt:this.buildPrompt(),historySize:500,removeHistoryDuplicates:!0,completer:t=>this.completer(t)}),this.history.length>0&&(this.rl.history=[...this.history].reverse()),this.printHelp(!0),this.rl.prompt(),new Promise(t=>{this.rl.on("line",async e=>{const r=e.trim()
|
|
17
17
|
if(r){if(this.appendHistory(r),await this.processCommand(r))return this.rl.close(),void t()
|
|
18
|
-
this.rl.prompt()}else this.rl.prompt()})
|
|
18
|
+
this.rl.prompt()}else this.rl.prompt()})
|
|
19
19
|
let e,r=!1
|
|
20
|
-
this.rl.on("SIGINT",(
|
|
20
|
+
this.rl.on("SIGINT",()=>{r?(e&&clearTimeout(e),this.rl.close()):(r=!0,console.log(""),console.log(l.default.gray("Press Ctrl+C again to exit, or continue typing.")),this.rl.prompt(),e=setTimeout(()=>{r=!1},2e3))}),this.rl.on("close",async()=>{this.shutdownCallback&&await this.shutdownCallback(),t()})})}buildPrompt(){const t=l.default.green(this.currentBranch),e=this.currentStatus&&"main"!==this.currentBranch?` ${l.default.gray("|")} ${this.colorStatus(this.currentStatus)}`:""
|
|
21
21
|
return`${l.default.cyan("[")}${t}${e}${l.default.cyan("]")} ${l.default.yellow("alchemy")}${l.default.gray(">")} `}colorStatus(t){switch(t){case"completed":return l.default.green(t)
|
|
22
22
|
case"in_progress":return l.default.yellow(t)
|
|
23
23
|
case"open":return l.default.blue(t)
|
|
@@ -33,14 +33,14 @@ return this.statusCache={map:r,ts:Date.now()},r}catch{return this.statusCache.ma
|
|
|
33
33
|
const t=new Set,e=(process.env.PATH||"").split(o.default.delimiter)
|
|
34
34
|
for(const r of e)try{if(!n.default.existsSync(r))continue
|
|
35
35
|
for(const e of n.default.readdirSync(r))t.add(e)}catch{}return this.pathExecutableCache=Array.from(t).sort(),this.pathExecutableCache}completer(t){const e=["br","branch","logs","pwd","cd ","publish ","linear ","help","exit","quit"],r=t.includes(" "),s=t.indexOf(" "),a=r?t.slice(0,s).toLowerCase():""
|
|
36
|
-
if(r&&("br"===a||"branch"===a))return setImmediate((
|
|
37
|
-
if(!r){const r=e.filter(
|
|
36
|
+
if(r&&("br"===a||"branch"===a))return setImmediate(()=>this.rl.write("\n")),[[],""]
|
|
37
|
+
if(!r){const r=e.filter(e=>e.startsWith(t)),s=t?this.getPathExecutables().filter(e=>e.startsWith(t)):[],a=[...new Set([...r,...s])]
|
|
38
38
|
if(a.length>0)return[a,t]
|
|
39
39
|
if(!t)return[e,t]}const i=t.lastIndexOf(" "),l=i>=0?t.slice(i+1):t,c=i>=0?t.slice(0,i+1):""
|
|
40
40
|
try{const e=l.includes(o.default.sep)||l.includes("/"),r=e?o.default.resolve(this.currentDir,o.default.dirname(l)):this.currentDir,s=e?o.default.basename(l):l,a=e?o.default.dirname(l)+"/":""
|
|
41
41
|
if(!n.default.existsSync(r))return[[],t]
|
|
42
|
-
const i=n.default.readdirSync(r,{withFileTypes:!0}).filter(
|
|
43
|
-
return c+a+e})
|
|
42
|
+
const i=n.default.readdirSync(r,{withFileTypes:!0}).filter(t=>t.name.startsWith(s)&&!t.name.startsWith(".")).map(t=>{const e=t.isDirectory()?t.name+"/":t.name
|
|
43
|
+
return c+a+e})
|
|
44
44
|
if(i.length>0)return[i,t]}catch{}return[[],t]}async detectCurrentBranch(){try{const t=(0,i.simpleGit)(this.currentDir),e=(await t.branch()).current||"main"
|
|
45
45
|
this.currentBranch=this.extractRequestId(e)||e}catch{this.currentBranch="main"}}async processCommand(t){const e=t.split(/\s+/),r=e[0].toLowerCase(),s=e.slice(1)
|
|
46
46
|
switch(r){case"exit":case"quit":return this.shutdownCallback&&await this.shutdownCallback(),!0
|
|
@@ -57,12 +57,12 @@ this.currentDir=e}catch(t){console.log(l.default.red(`cd: ${t.message}`))}}async
|
|
|
57
57
|
if(!n.default.existsSync(r))return void console.log(l.default.gray("No log file found yet. Logs will appear once the server processes requests."))
|
|
58
58
|
const s=t[0]&&/^\d+$/.test(t[0])?parseInt(t[0],10):50
|
|
59
59
|
console.log(l.default.gray(`Tailing ${r} (last ${s} lines, Ctrl+C to stop)`))
|
|
60
|
-
const{spawn:a}=await Promise.resolve().then(e.t
|
|
61
|
-
return new Promise(
|
|
60
|
+
const{spawn:a}=await Promise.resolve().then(()=>e.t(35317,23)),i=a("tail",["-n",String(s),"-f",r],{stdio:["ignore","inherit","inherit"]})
|
|
61
|
+
return new Promise(t=>{const e=process.stdin,r=e.isRaw
|
|
62
62
|
this.rl.pause(),e.setRawMode(!0),e.resume()
|
|
63
63
|
const s=()=>{e.removeListener("data",a)
|
|
64
64
|
try{i.kill("SIGTERM")}catch{}try{e.setRawMode(r??!1)}catch{}this.rl.resume()},a=t=>{3!==t[0]&&"q"!==t.toString()||i.kill("SIGTERM")}
|
|
65
|
-
e.on("data",a),i.on("close",(
|
|
65
|
+
e.on("data",a),i.on("close",()=>{s(),t()})})}updateCurrentSymlink(){try{let t
|
|
66
66
|
if("main"===this.currentBranch)t=this.projectPath
|
|
67
67
|
else{const e=o.default.join(this.projectPath,c.ALCHEMY_DIR_NAME,"worktrees",this.currentBranch)
|
|
68
68
|
t=n.default.existsSync(e)?e:this.projectPath}try{n.default.unlinkSync(this.currentSymlink)}catch{}n.default.symlinkSync(t,this.currentSymlink),this.currentDir=this.currentSymlink}catch(t){this.logger.warn("Failed to update current symlink",{error:t.message})}}getVirtualCwd(){return this.currentDir}executeCommand(t){try{(0,a.execSync)(t,{cwd:this.currentDir,stdio:"inherit",env:{...process.env,PWD:this.currentDir,GIT_DIR:void 0,GIT_WORK_TREE:void 0}})}catch(t){void 0!==t.status&&null!==t.status||console.log(l.default.red(`Error: ${t.message}`))}}getWorktreeRequestIds(){const t=o.default.join(this.projectPath,c.ALCHEMY_DIR_NAME,"worktrees"),e=new Set
|
|
@@ -73,7 +73,7 @@ for(const t of r.all){if(t.startsWith("remotes/"))continue
|
|
|
73
73
|
if("main"===t)continue
|
|
74
74
|
const e=this.extractRequestId(t)
|
|
75
75
|
e&&!o.has(e)&&(o.add(e),n.push(e))}for(const t of s)o.has(t)||(o.add(t),n.push(t))
|
|
76
|
-
n.sort((
|
|
76
|
+
n.sort((t,e)=>t.localeCompare(e))
|
|
77
77
|
for(const t of n){const e=this.currentBranch===t||this.currentBranch===`requests/${t}`
|
|
78
78
|
c.push(this.formatRequestWithStatus(t,a.get(t),e))}if(n.push("main"),c.push("main"===this.currentBranch?l.default.green("main"):"main"),0===n.length)return void console.log(l.default.gray("No branches found."))
|
|
79
79
|
if(t&&n.includes(t))return void(t!==this.currentBranch&&await this.switchBranch(t))
|
|
@@ -85,14 +85,14 @@ if(n.default.existsSync(s)&&n.default.statSync(s).isDirectory())return s
|
|
|
85
85
|
console.log(l.default.gray(`Creating worktree for ${t}...`)),n.default.mkdirSync(r,{recursive:!0})
|
|
86
86
|
const a=(0,i.simpleGit)(this.projectPath)
|
|
87
87
|
return await a.raw(["worktree","add",s,e]),console.log(l.default.gray(`Worktree created at ${s}`)),s}async selectFromList(t,e,r,s,a,i){const o=t,n=r||t
|
|
88
|
-
return new Promise(
|
|
88
|
+
return new Promise(t=>{let r=0
|
|
89
89
|
const c=process.stdin,u=c.isRaw
|
|
90
|
-
let h=!1,d=i||"",f=o.map((
|
|
90
|
+
let h=!1,d=i||"",f=o.map((t,e)=>e)
|
|
91
91
|
null!=s&&s>=0&&s<o.length&&(r=s)
|
|
92
|
-
const p=()=>{if(!d)return void(f=o.map((
|
|
92
|
+
const p=()=>{if(!d)return void(f=o.map((t,e)=>e))
|
|
93
93
|
const t=d.toLowerCase()
|
|
94
|
-
let e=o.map((
|
|
95
|
-
0===e.length&&/^\d+$/.test(t)&&(e=o.map((
|
|
94
|
+
let e=o.map((t,e)=>({item:t,i:e})).filter(({item:e})=>e.toLowerCase().startsWith(t))
|
|
95
|
+
0===e.length&&/^\d+$/.test(t)&&(e=o.map((t,e)=>({item:t,i:e})).filter(({item:e})=>e.replace(/\D/g,"").endsWith(t))),0===e.length&&(e=o.map((t,e)=>({item:t,i:e})).filter(({item:e})=>e.toLowerCase().includes(t))),f=e.map(t=>t.i)},g=process.stdout.rows||24,y=Math.max(3,g-4)
|
|
96
96
|
let m=0,w=0,$=0
|
|
97
97
|
this.rl.pause()
|
|
98
98
|
const S=()=>{const t=f.length,s=t>y
|
|
@@ -116,23 +116,23 @@ S(),c.setRawMode(!0),c.resume()
|
|
|
116
116
|
const b=()=>{if(!h){h=!0,c.removeListener("data",v)
|
|
117
117
|
try{c.setRawMode(u??!1)}catch{}C&&$>1&&process.stdout.write(`\r\x1b[${$-1}A\r`),process.stdout.write("\x1b[J"),this.rl.resume()}},v=e=>{if(!h)try{const s=e.toString()
|
|
118
118
|
"\x1b[A"===s?f.length>0&&(r=Math.max(0,r-1),S()):"\x1b[B"===s?f.length>0&&(r=Math.min(f.length-1,r+1),S()):"\r"===s||"\n"===s?f.length>0&&(b(),t(o[f[r]])):"\x1b"===s||"\x03"===s?(b(),t(null)):a&&"\x7f"===s?d.length>0&&(d=d.slice(0,-1),p(),r=0,m=0,S()):a&&1===s.length&&s>=" "&&s<="~"&&(d+=s,p(),r=0,m=0,S())}catch{b(),t(null)}}
|
|
119
|
-
c.on("data",v)})
|
|
119
|
+
c.on("data",v)})}findMatchingBranches(t,e,r){const s=new Set
|
|
120
120
|
for(const t of e){const e=this.extractRequestId(t)
|
|
121
121
|
e&&s.add(e)}for(const t of r)s.add(t)
|
|
122
122
|
const a=Array.from(s)
|
|
123
123
|
if(s.has(t))return[t]
|
|
124
|
-
const i=a.filter(
|
|
124
|
+
const i=a.filter(e=>e.startsWith(t))
|
|
125
125
|
if(i.length>0)return i.sort()
|
|
126
|
-
if(/^\d+$/.test(t)){const e=a.filter(
|
|
126
|
+
if(/^\d+$/.test(t)){const e=a.filter(e=>e.replace(/\D/g,"").endsWith(t))
|
|
127
127
|
if(e.length>0)return e.sort()}return[]}async switchBranch(t){try{if("main"===t)return this.currentBranch="main",this.currentStatus=null,this.updateCurrentSymlink(),this.updatePrompt(),console.log(l.default.green("Switched to main")),void console.log(l.default.gray(` ${this.currentDir}`))
|
|
128
128
|
const e=(0,i.simpleGit)(this.projectPath),r=await e.branch(),s=this.getWorktreeRequestIds(),a=this.findMatchingBranches(t,r.all,s)
|
|
129
129
|
if(0===a.length)return console.log(l.default.red(`No branch matching: ${t}`)),void console.log(l.default.gray(' Use "branches" to see available branches'))
|
|
130
130
|
let o
|
|
131
131
|
if(1===a.length)o=a[0]
|
|
132
|
-
else{const e=await this.fetchBulkStatuses(),r=a.map(
|
|
132
|
+
else{const e=await this.fetchBulkStatuses(),r=a.map(t=>this.formatRequestWithStatus(t,e.get(t),!1)),s=await this.selectFromList(a,`Multiple matches for "${t}" \u2014 select one:`,r,void 0,!0)
|
|
133
133
|
if(!s)return void console.log(l.default.gray("Cancelled."))
|
|
134
134
|
o=s}const n=r.all.includes(`requests/${o}`)?`requests/${o}`:o
|
|
135
135
|
await this.ensureWorktree(o,n),this.currentBranch=o,this.updateCurrentSymlink(),this.currentStatus=await this.fetchRequestStatus(o),this.updatePrompt()
|
|
136
136
|
const c=this.currentStatus?` ${l.default.gray("|")} ${this.colorStatus(this.currentStatus)}`:""
|
|
137
137
|
console.log(l.default.green(`Switched to ${o}`)+c),console.log(l.default.gray(` ${this.getVirtualCwd()}`))}catch(t){console.log(l.default.red(`Failed to switch: ${t.message}`))}}printHelp(t){t?(console.log(""),console.log(l.default.gray('Type "help" for available commands. Commands run in the current branch directory.')),console.log("")):(console.log(""),console.log(l.default.bold("Interactive Shell Commands:")),console.log(` ${l.default.yellow("branch")} / ${l.default.yellow("br")} Browse and switch branches`),console.log(` ${l.default.yellow("logs")} ${l.default.gray("[N]")} Tail action server log (Ctrl+C to stop, N = lines of history)`),console.log(` ${l.default.yellow("cd")} ${l.default.gray("<dir>")} Change directory within current branch`),console.log(` ${l.default.yellow("pwd")} Show current working directory`),console.log(` ${l.default.yellow("publish")} ${l.default.gray("<req id>")} Push the request branch and open a GitHub PR with its receipt`),console.log(` ${l.default.yellow("linear")} ${l.default.gray("<ENG-123>")} Import a Linear issue as a request`),console.log(` ${l.default.yellow("help")} Show this help`),console.log(` ${l.default.yellow("exit")} / ${l.default.yellow("quit")} Stop the server and exit`),console.log(""),console.log(l.default.gray(" Any other input is executed as a shell command in the current directory.")),console.log(""))}loadHistory(){try{if(n.default.existsSync(this.historyFile)){const t=n.default.readFileSync(this.historyFile,"utf-8")
|
|
138
|
-
this.history=t.split("\n").filter(
|
|
138
|
+
this.history=t.split("\n").filter(t=>""!==t.trim()),this.history.length>500&&(this.history=this.history.slice(-500))}}catch{}}appendHistory(t){try{this.history.push(t),n.default.appendFileSync(this.historyFile,t+"\n")}catch{}}}}}
|