acstack 0.47.0 → 0.47.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.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "acstack",
|
|
3
3
|
"description": "Agentic coding stack where planning grows only as far as needed: a map of decisions, tasks, checks, and handoffs behind a pluggable tracker.",
|
|
4
|
-
"version": "0.47.
|
|
4
|
+
"version": "0.47.1",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "ac8318740"
|
|
7
7
|
},
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# ACStack terminal workspace.
|
|
2
|
-
# Copy to ~/.config/acstack/terminal-workspace.yaml, edit, then run
|
|
2
|
+
# Copy to ~/.config/acstack/terminal-workspace.yaml, edit, then run
|
|
3
|
+
# setup.sh apply.
|
|
3
4
|
#
|
|
4
5
|
# This is machine-level, not per-project. It installs binaries and writes
|
|
5
6
|
# keybindings for your user, so it does not belong in acstack/project.yaml.
|
|
@@ -225,6 +226,10 @@ pi:
|
|
|
225
226
|
# pi.settings.install_telemetry, which controls pi's anonymous install and
|
|
226
227
|
# update reporting and stays false in this example.
|
|
227
228
|
web_access: true
|
|
229
|
+
# pi-lens, which adds diagnostics, code-intelligence tools and local
|
|
230
|
+
# observability logs to pi. Off by default because it is a heavier dev-tool
|
|
231
|
+
# layer and may download helper tools when pi-lens needs them.
|
|
232
|
+
lens: false
|
|
228
233
|
# pi-slash-anywhere, which lets slash commands run from any prompt.
|
|
229
234
|
slash_anywhere: true
|
|
230
235
|
# agentic-retro's pi extension, which queues each finished pi session for a
|
|
@@ -3520,6 +3520,79 @@ find_pi() {
|
|
|
3520
3520
|
have pi || ! have npm || PATH="$PATH:$(npm prefix -g 2>/dev/null)/bin"
|
|
3521
3521
|
}
|
|
3522
3522
|
|
|
3523
|
+
|
|
3524
|
+
# Pi's bundled TUI does not always receive Windows Terminal paste as plain
|
|
3525
|
+
# text. Through Herdr and ConPTY it can arrive as Win32 input records such as
|
|
3526
|
+
# ESC[13;28;13;1;0;1_. Patch the installed bundle after install or update.
|
|
3527
|
+
patch_pi_win32_paste() {
|
|
3528
|
+
have pi || return 0
|
|
3529
|
+
local pi_bin pi_real root chunks
|
|
3530
|
+
pi_bin=$(command -v pi) || return 0
|
|
3531
|
+
pi_real=$(readlink -f "$pi_bin" 2>/dev/null || printf '%s' "$pi_bin")
|
|
3532
|
+
case "$pi_real" in
|
|
3533
|
+
*/dist/bundle/cli.js) root=${pi_real%/dist/bundle/cli.js} ;;
|
|
3534
|
+
*)
|
|
3535
|
+
root="${pi_real%/bin/pi}/lib/node_modules/@earendil-works/pi-coding-agent"
|
|
3536
|
+
if [ ! -d "$root/dist/bundle/chunks" ]; then
|
|
3537
|
+
have npm || { say "pi: npm not on PATH, so Win32 paste patch was skipped"; return 0; }
|
|
3538
|
+
root="$(npm root -g 2>/dev/null)/@earendil-works/pi-coding-agent"
|
|
3539
|
+
fi
|
|
3540
|
+
;;
|
|
3541
|
+
esac
|
|
3542
|
+
chunks="$root/dist/bundle/chunks"
|
|
3543
|
+
[ -d "$chunks" ] || { say "pi: bundle chunks not found, so Win32 paste patch was skipped"; return 0; }
|
|
3544
|
+
SPECHUB_PI_CHUNKS="$chunks" py <<'PI_PATCH_PY'
|
|
3545
|
+
import os, pathlib
|
|
3546
|
+
chunks = pathlib.Path(os.environ["SPECHUB_PI_CHUNKS"])
|
|
3547
|
+
target = None
|
|
3548
|
+
for p in chunks.glob("*.js"):
|
|
3549
|
+
try:
|
|
3550
|
+
s = p.read_text()
|
|
3551
|
+
except (OSError, UnicodeDecodeError):
|
|
3552
|
+
continue
|
|
3553
|
+
if "function decodePrintableKey(data)" in s and "handlePaste(pastedText)" in s:
|
|
3554
|
+
target = p
|
|
3555
|
+
break
|
|
3556
|
+
if target is None:
|
|
3557
|
+
print(" pi: TUI bundle not found, so Win32 paste patch was skipped")
|
|
3558
|
+
raise SystemExit
|
|
3559
|
+
s = target.read_text()
|
|
3560
|
+
changed = False
|
|
3561
|
+
repls = [
|
|
3562
|
+
('function isKeyRelease(data){return data.includes("\\x1B[200~")?!1:!!(data.includes(":3u")||data.includes(":3~")||data.includes(":3A")||data.includes(":3B")||data.includes(":3C")||data.includes(":3D")||data.includes(":3H")||data.includes(":3F"))}',
|
|
3563
|
+
'function isKeyRelease(data){let win32=parseWin32InputRecord(data);if(win32)return!win32.keyDown;return data.includes("\\x1B[200~")?!1:!!(data.includes(":3u")||data.includes(":3~")||data.includes(":3A")||data.includes(":3B")||data.includes(":3C")||data.includes(":3D")||data.includes(":3H")||data.includes(":3F"))}'),
|
|
3564
|
+
('function parseModifyOtherKeysSequence(data){let match=data.match(/^\\x1b\\[27;(\\d+);(\\d+)~$/);if(!match)return null;let modValue=parseInt(match[1],10);return{codepoint:parseInt(match[2],10),modifier:modValue-1}}',
|
|
3565
|
+
'function parseModifyOtherKeysSequence(data){let match=data.match(/^\\x1b\\[27;(\\d+);(\\d+)~$/);if(!match)return null;let modValue=parseInt(match[1],10);return{codepoint:parseInt(match[2],10),modifier:modValue-1}}function parseWin32InputRecord(data){let match=data.match(/^\\x1b\\[(\\d+);(\\d+);(-?\\d+);([01]);(\\d+);(\\d+)_$/);if(!match)return null;let virtualKey=Number.parseInt(match[1],10),scanCode=Number.parseInt(match[2],10),codepoint=Number.parseInt(match[3],10),keyDown=match[4]==="1",controlState=Number.parseInt(match[5],10),modifier=0;if((controlState&16)!==0)modifier|=MODIFIERS.shift;if((controlState&(1|2))!==0)modifier|=MODIFIERS.alt;if((controlState&(4|8))!==0)modifier|=MODIFIERS.ctrl;if((controlState&32)!==0)modifier|=128;if((controlState&128)!==0)modifier|=64;return{virtualKey,scanCode,codepoint,keyDown,modifier}}'),
|
|
3566
|
+
('function parseKey(data){let kitty=parseKittySequence(data);',
|
|
3567
|
+
'function parseKey(data){let win32=parseWin32InputRecord(data);if(win32){_lastEventType=win32.keyDown?"press":"release";if(!win32.keyDown)return;let codepoint=win32.codepoint;if(win32.virtualKey===46)codepoint=FUNCTIONAL_CODEPOINTS.delete;else if(win32.virtualKey===45)codepoint=FUNCTIONAL_CODEPOINTS.insert;else if(win32.virtualKey===33)codepoint=FUNCTIONAL_CODEPOINTS.pageUp;else if(win32.virtualKey===34)codepoint=FUNCTIONAL_CODEPOINTS.pageDown;else if(win32.virtualKey===35)codepoint=FUNCTIONAL_CODEPOINTS.end;else if(win32.virtualKey===36)codepoint=FUNCTIONAL_CODEPOINTS.home;else if(win32.virtualKey===37)codepoint=ARROW_CODEPOINTS.left;else if(win32.virtualKey===38)codepoint=ARROW_CODEPOINTS.up;else if(win32.virtualKey===39)codepoint=ARROW_CODEPOINTS.right;else if(win32.virtualKey===40)codepoint=ARROW_CODEPOINTS.down;else if(win32.virtualKey===8)codepoint=CODEPOINTS.backspace;else if(win32.virtualKey===9)codepoint=CODEPOINTS.tab;else if(win32.virtualKey===13)codepoint=CODEPOINTS.enter;else if(win32.virtualKey===27)codepoint=CODEPOINTS.escape;return formatParsedKey(codepoint,win32.modifier)}let kitty=parseKittySequence(data);'),
|
|
3568
|
+
('function decodeModifyOtherKeysPrintable(data){let parsed=parseModifyOtherKeysSequence(data);if(!(!parsed||(parsed.modifier&~LOCK_MASK&~MODIFIERS.shift)!==0)&&!(!Number.isFinite(parsed.codepoint)||parsed.codepoint<32))try{return String.fromCodePoint(parsed.codepoint)}catch{return}}function decodePrintableKey(data){return decodeKittyPrintable(data)??decodeModifyOtherKeysPrintable(data)}',
|
|
3569
|
+
'function decodeModifyOtherKeysPrintable(data){let parsed=parseModifyOtherKeysSequence(data);if(!(!parsed||(parsed.modifier&~LOCK_MASK&~MODIFIERS.shift)!==0)&&!(!Number.isFinite(parsed.codepoint)||parsed.codepoint<32))try{return String.fromCodePoint(parsed.codepoint)}catch{return}}function decodeWin32Printable(data){let parsed=parseWin32InputRecord(data);if(!parsed||!parsed.keyDown)return;let modifier=parsed.modifier&~LOCK_MASK;if((modifier&(MODIFIERS.ctrl|MODIFIERS.alt|MODIFIERS.super))!==0)return;if(!Number.isFinite(parsed.codepoint)||parsed.codepoint<32)return;try{return String.fromCodePoint(parsed.codepoint)}catch{return}}function decodePrintableKey(data){return decodeKittyPrintable(data)??decodeModifyOtherKeysPrintable(data)??decodeWin32Printable(data)}'),
|
|
3570
|
+
('let decodedText=pastedText.replace(/\\x1b\\[(\\d+);5u/g,(match,code)=>{let cp=Number(code);return cp>=97&&cp<=122?String.fromCharCode(cp-96):cp>=65&&cp<=90?String.fromCharCode(cp-64):match}),filteredText=this.normalizeText(decodedText).split("").filter(char=>char===`\n`||char.charCodeAt(0)>=32).join("");',
|
|
3571
|
+
'let decodedText=pastedText.replace(/\\x1b\\[(\\d+);(\\d+);(-?\\d+);([01]);(\\d+);(\\d+)_/g,(match,vk,sc,uc,kd)=>{if(kd!=="1")return "";let cp=Number(uc),key=Number(vk);if(key===13||cp===13)return `\n`;if(cp>=32)try{return String.fromCodePoint(cp)}catch{return ""}return ""}).replace(/\\x1b\\[(\\d+);5u/g,(match,code)=>{let cp=Number(code);return cp>=97&&cp<=122?String.fromCharCode(cp-96):cp>=65&&cp<=90?String.fromCharCode(cp-64):match}),filteredText=this.normalizeText(decodedText).split("").filter(char=>char===`\n`||char.charCodeAt(0)>=32).join("");')]
|
|
3572
|
+
missing = []
|
|
3573
|
+
for old, new in repls:
|
|
3574
|
+
if new in s:
|
|
3575
|
+
continue
|
|
3576
|
+
if old not in s:
|
|
3577
|
+
missing.append(old[:80])
|
|
3578
|
+
continue
|
|
3579
|
+
s = s.replace(old, new, 1)
|
|
3580
|
+
changed = True
|
|
3581
|
+
if missing:
|
|
3582
|
+
print(" pi: Win32 paste patch did not match this Pi bundle")
|
|
3583
|
+
raise SystemExit
|
|
3584
|
+
if changed:
|
|
3585
|
+
try:
|
|
3586
|
+
target.write_text(s)
|
|
3587
|
+
except OSError as exc:
|
|
3588
|
+
print(f" pi: could not patch {target} ({exc})")
|
|
3589
|
+
raise SystemExit
|
|
3590
|
+
print(" pi: Win32 paste patch applied")
|
|
3591
|
+
else:
|
|
3592
|
+
print(" pi: Win32 paste patch already applied")
|
|
3593
|
+
PI_PATCH_PY
|
|
3594
|
+
}
|
|
3595
|
+
|
|
3523
3596
|
# The ACStack version running this script, which is the one pi should pin.
|
|
3524
3597
|
acstack_version() {
|
|
3525
3598
|
json_field "$(dirname "$0")/../../.claude-plugin/plugin.json" version
|
|
@@ -3670,6 +3743,8 @@ apply_pi() {
|
|
|
3670
3743
|
return 0
|
|
3671
3744
|
fi
|
|
3672
3745
|
|
|
3746
|
+
patch_pi_win32_paste
|
|
3747
|
+
|
|
3673
3748
|
# ACStack cannot launch a subagent on pi without pi-subagents.
|
|
3674
3749
|
pi_add npm:pi-subagents npm:pi-subagents
|
|
3675
3750
|
if [ "$(cfg_get pi.todo true)" = "true" ]; then
|
|
@@ -3703,6 +3778,11 @@ apply_pi() {
|
|
|
3703
3778
|
else
|
|
3704
3779
|
pi_drop npm:pi-web-access
|
|
3705
3780
|
fi
|
|
3781
|
+
if [ "$(cfg_get pi.lens false)" = "true" ]; then
|
|
3782
|
+
pi_add npm:pi-lens npm:pi-lens
|
|
3783
|
+
else
|
|
3784
|
+
pi_drop npm:pi-lens
|
|
3785
|
+
fi
|
|
3706
3786
|
if [ "$(cfg_get pi.slash_anywhere true)" = "true" ]; then
|
|
3707
3787
|
pi_add "$PI_SLASH_ANYWHERE" "$PI_SLASH_ANYWHERE"
|
|
3708
3788
|
else
|
|
@@ -3749,6 +3829,7 @@ apply_pi() {
|
|
|
3749
3829
|
pi_state merge "$PI_KEYBINDINGS" keybindings '{"app.message.dequeue": "ctrl+enter"}'
|
|
3750
3830
|
pi_state merge "$PI_SUBAGENT_CFG" subagent '{"toolActivation": "eager"}'
|
|
3751
3831
|
pi_state md write
|
|
3832
|
+
patch_pi_win32_paste
|
|
3752
3833
|
|
|
3753
3834
|
# Logging in is interactive and stores a credential, so it stays the user's.
|
|
3754
3835
|
[ -f "$PI_DIR/auth.json" ] || say "pi: not logged in yet. Run pi, then /login"
|
|
@@ -3771,6 +3852,7 @@ remove_pi() {
|
|
|
3771
3852
|
pi_drop npm:pi-compact-tools
|
|
3772
3853
|
pi_drop npm:@juicesharp/rpiv-ask-user-question
|
|
3773
3854
|
pi_drop npm:pi-web-access
|
|
3855
|
+
pi_drop npm:pi-lens
|
|
3774
3856
|
pi_drop "$PI_SLASH_ANYWHERE"
|
|
3775
3857
|
pi_drop npm:pi-subagents
|
|
3776
3858
|
else
|
|
@@ -3814,6 +3896,7 @@ billion-context pi npm billion-context -
|
|
|
3814
3896
|
pi-plugin-manager pi npm pi-plugin-manager -
|
|
3815
3897
|
@juicesharp/rpiv-ask-user-question pi npm @juicesharp/rpiv-ask-user-question -
|
|
3816
3898
|
pi-web-access pi npm pi-web-access -
|
|
3899
|
+
pi-lens pi npm pi-lens -
|
|
3817
3900
|
pi-slash-anywhere pi npm pi-slash-anywhere -
|
|
3818
3901
|
pi-compact-tools pi npm pi-compact-tools -
|
|
3819
3902
|
T
|
|
@@ -3847,7 +3930,7 @@ installed_version() { # installed_version <name> -> a bare version, or nothing
|
|
|
3847
3930
|
# 1.1.0
|
|
3848
3931
|
pi) find_pi; v=$(pi --version 2>/dev/null | awk '{print $NF}') ;;
|
|
3849
3932
|
# pi installs npm packages under its own directory, not npm's global one.
|
|
3850
|
-
pi-subagents|pi-compact-tools|pi-web-access|pi-slash-anywhere|@juicesharp/rpiv-ask-user-question|billion-context|@juicesharp/rpiv-todo|pi-plugin-manager)
|
|
3933
|
+
pi-subagents|pi-compact-tools|pi-web-access|pi-lens|pi-slash-anywhere|@juicesharp/rpiv-ask-user-question|billion-context|@juicesharp/rpiv-todo|pi-plugin-manager)
|
|
3851
3934
|
v=$(json_field "$PI_DIR/npm/node_modules/$1/package.json" version) ;;
|
|
3852
3935
|
esac
|
|
3853
3936
|
printf '%s' "${v#v}"
|
|
@@ -3991,9 +4074,13 @@ upgrade_one() { # upgrade_one <name>
|
|
|
3991
4074
|
harlequin) uv tool upgrade harlequin >/dev/null 2>&1 \
|
|
3992
4075
|
&& say "harlequin upgraded" || say "harlequin upgrade failed" ;;
|
|
3993
4076
|
# With no target, pi update updates pi itself and no package.
|
|
3994
|
-
pi) pi update >/dev/null 2>&1
|
|
3995
|
-
|
|
3996
|
-
|
|
4077
|
+
pi) if pi update >/dev/null 2>&1; then
|
|
4078
|
+
say "pi updated"
|
|
4079
|
+
patch_pi_win32_paste
|
|
4080
|
+
else
|
|
4081
|
+
say "pi update failed"
|
|
4082
|
+
fi ;;
|
|
4083
|
+
pi-subagents|pi-compact-tools|pi-web-access|pi-lens|pi-slash-anywhere|@juicesharp/rpiv-ask-user-question|billion-context|@juicesharp/rpiv-todo|pi-plugin-manager)
|
|
3997
4084
|
if pi_npm_pin "$1"; then
|
|
3998
4085
|
say "$1 is pinned to $(pi_state pkg "npm:$1") in pi, which pi update never moves"
|
|
3999
4086
|
return 0
|
|
@@ -4078,7 +4165,7 @@ case "$ACTION" in
|
|
|
4078
4165
|
if have pi || [ "$(cfg_get pi.enabled false)" = "true" ]; then
|
|
4079
4166
|
echo
|
|
4080
4167
|
have pi && say "pi: $(installed_version pi)" || say "pi: not installed"
|
|
4081
|
-
for id in npm:pi-subagents "$PI_ACSTACK" "$PI_BILLION" npm:@juicesharp/rpiv-todo npm:pi-plugin-manager npm:@juicesharp/rpiv-ask-user-question npm:pi-web-access "$PI_SLASH_ANYWHERE" npm:pi-compact-tools; do
|
|
4168
|
+
for id in npm:pi-subagents "$PI_ACSTACK" "$PI_BILLION" npm:@juicesharp/rpiv-todo npm:pi-plugin-manager npm:@juicesharp/rpiv-ask-user-question npm:pi-web-access npm:pi-lens "$PI_SLASH_ANYWHERE" npm:pi-compact-tools; do
|
|
4082
4169
|
src=$(pi_state pkg "$id") && say "pi package: $src" || say "pi package: $id not installed"
|
|
4083
4170
|
done
|
|
4084
4171
|
[ -e "$PI_RETRO_EXT" ] && say "pi agentic-retro extension: present" \
|
package/cli/package.json
CHANGED
|
@@ -370,6 +370,9 @@ What `apply` does:
|
|
|
370
370
|
- It adds web search, URL fetching, GitHub repo cloning, PDF extraction and media understanding tools to pi
|
|
371
371
|
- This is separate from pi's anonymous install and update reporting; `pi.settings.install_telemetry: false` still controls that telemetry setting
|
|
372
372
|
- Set `pi.web_access: false` to leave it out, or to remove it later if this setup installed it
|
|
373
|
+
- It can install `pi-lens` for diagnostics and code-intelligence tools
|
|
374
|
+
- It is off by default because it is a heavier dev-tool layer
|
|
375
|
+
- Set `pi.lens: true` to install it, or `pi.lens: false` to remove it later if this setup installed it
|
|
373
376
|
- It installs `pi-slash-anywhere` by default, so slash commands work from any prompt
|
|
374
377
|
- Set `pi.slash_anywhere: false` to leave it out, or to remove it later if this setup installed it
|
|
375
378
|
- It installs `pi-compact-tools` and runs `agentic-retro install-pi`, each behind its own toggle
|
|
@@ -380,6 +383,8 @@ What `apply` does:
|
|
|
380
383
|
- It sets `"toolActivation": "eager"` in `~/.pi/agent/extensions/subagent/config.json`
|
|
381
384
|
- It binds `"app.message.dequeue"` to `"ctrl+enter"` in `~/.pi/agent/keybindings.json`
|
|
382
385
|
- It writes the four keys under `pi.settings` into `~/.pi/agent/settings.json`
|
|
386
|
+
- It patches pi's bundled TUI so Windows Terminal Win32 input records paste as text
|
|
387
|
+
- `pi update` can replace the bundle, so `setup.sh upgrade pi` reapplies the patch
|
|
383
388
|
|
|
384
389
|
How it treats pi's files:
|
|
385
390
|
|
|
@@ -396,7 +401,7 @@ How it treats pi's files:
|
|
|
396
401
|
- `apply` never touches `auth.json`
|
|
397
402
|
- Run `pi`, then `/login`, yourself
|
|
398
403
|
- `setup.sh status` reports pi's version, its packages, the delegation line, `toolActivation`, and whether `auth.json` exists
|
|
399
|
-
- `setup.sh outdated` and `setup.sh upgrade` include `billion-context`, `@juicesharp/rpiv-todo`, `pi-plugin-manager`, `@juicesharp/rpiv-ask-user-question`, `pi-web-access`, and `pi-slash-anywhere` like pi's other npm packages
|
|
404
|
+
- `setup.sh outdated` and `setup.sh upgrade` include `billion-context`, `@juicesharp/rpiv-todo`, `pi-plugin-manager`, `@juicesharp/rpiv-ask-user-question`, `pi-web-access`, `pi-lens`, and `pi-slash-anywhere` like pi's other npm packages
|
|
400
405
|
|
|
401
406
|
## 4. How you attach
|
|
402
407
|
|
|
@@ -472,6 +477,7 @@ The two paths deliver keys by different routes.
|
|
|
472
477
|
- The two routes do not carry the same set
|
|
473
478
|
- The `ctrl+alt` family survives the escape-sequence route and dies on the native one
|
|
474
479
|
- `ctrl+<digit>` does the opposite
|
|
480
|
+
|
|
475
481
|
- Either way herdr accepts the binding and then never sees the key
|
|
476
482
|
- A chord that does not cross is therefore silently dead, and herdr reports no error
|
|
477
483
|
- `alt+<key>` is the only family that crossed both
|
package/package.json
CHANGED