acstack 0.48.1 → 0.48.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/.claude-plugin/plugin.json +1 -1
- package/README.md +4 -3
- package/assets/terminal-workspace/config.example.yaml +4 -1
- package/assets/terminal-workspace/setup.sh +12 -0
- package/cli/package.json +1 -1
- package/docs/terminal-workspace.md +1 -0
- package/package.json +1 -1
- package/pi/extension.ts +86 -40
|
@@ -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.48.
|
|
4
|
+
"version": "0.48.3",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "ac8318740"
|
|
7
7
|
},
|
package/README.md
CHANGED
|
@@ -101,9 +101,10 @@ Then, in your project, run `/acstack:setup`.
|
|
|
101
101
|
```
|
|
102
102
|
|
|
103
103
|
- Set `"toolActivation": "eager"` in `~/.pi/agent/extensions/subagent/config.json` to offer the `subagent` tool from the first turn (restart pi after)
|
|
104
|
-
- pi
|
|
105
|
-
- Run `/acstack-writing-style
|
|
106
|
-
- Run `/acstack-writing-style off` to
|
|
104
|
+
- pi gets the ACStack writing style from the extension by default
|
|
105
|
+
- Run `/acstack-writing-style default` to use the bundled style again
|
|
106
|
+
- Run `/acstack-writing-style off` to disable style injection
|
|
107
|
+
- Run `/acstack-writing-style custom <path>` to use a user-owned style file
|
|
107
108
|
|
|
108
109
|
## 2. The three commands, and which one to use
|
|
109
110
|
|
|
@@ -217,7 +217,10 @@ pi:
|
|
|
217
217
|
# markdown, code and artifact previews beside a decision, accepts freeform
|
|
218
218
|
# answers and notes, and does not require a full-event telemetry env var.
|
|
219
219
|
question_tool: true
|
|
220
|
-
# rpiv-todo, which adds a todo tool to pi.
|
|
220
|
+
# rpiv-todo, which adds a todo tool to pi. When this is on, apply also
|
|
221
|
+
# suggests a line for the user's global ~/.pi/agent/AGENTS.md if their Pi
|
|
222
|
+
# context file does not already mention todo discipline. It never edits that
|
|
223
|
+
# user-owned file for them.
|
|
221
224
|
todo: true
|
|
222
225
|
# pi-plugin-manager, which adds pi plugin management commands.
|
|
223
226
|
plugin_manager: true
|
|
@@ -3886,6 +3886,17 @@ pi_npm_pin() { # pi_npm_pin <name>
|
|
|
3886
3886
|
[ "$src" != "npm:$1" ]
|
|
3887
3887
|
}
|
|
3888
3888
|
|
|
3889
|
+
pi_suggest_todo_discipline() {
|
|
3890
|
+
local needle="When using a todo list, keep it current as work completes."
|
|
3891
|
+
grep -qsF "$needle" "$PI_DIR"/AGENTS.override.md "$PI_DIR"/AGENTS.md "$PI_DIR"/AGENTS.MD \
|
|
3892
|
+
"$PI_DIR"/CLAUDE.md "$PI_DIR"/CLAUDE.MD && return 0
|
|
3893
|
+
say "pi: todo tool installed. For stricter todo discipline, ask the agent"
|
|
3894
|
+
say "pi: running this setup to hand-edit $PI_DIR/AGENTS.md and add:"
|
|
3895
|
+
say "pi: $needle Before reporting a task as done, check the todo list"
|
|
3896
|
+
say "pi: and mark every completed step completed. Do not leave stale"
|
|
3897
|
+
say "pi: in-progress or pending todos after a commit, PR, merge or workflow gate."
|
|
3898
|
+
}
|
|
3899
|
+
|
|
3889
3900
|
# The pin apply would move to, or nothing when the installed one is current
|
|
3890
3901
|
# or newer. A newer pin is one the user chose, so it is never moved back.
|
|
3891
3902
|
pi_acstack_behind() {
|
|
@@ -3977,6 +3988,7 @@ apply_pi() {
|
|
|
3977
3988
|
pi_add npm:pi-subagents npm:pi-subagents
|
|
3978
3989
|
if [ "$(cfg_get pi.todo true)" = "true" ]; then
|
|
3979
3990
|
pi_add npm:@juicesharp/rpiv-todo npm:@juicesharp/rpiv-todo
|
|
3991
|
+
pi_suggest_todo_discipline
|
|
3980
3992
|
else
|
|
3981
3993
|
pi_drop npm:@juicesharp/rpiv-todo
|
|
3982
3994
|
fi
|
package/cli/package.json
CHANGED
|
@@ -359,6 +359,7 @@ What `apply` does:
|
|
|
359
359
|
- Setup leaves Claude Code and Codex alone, and removes bili from them if an older setup added it
|
|
360
360
|
- Set `pi.billion_context: false` to leave it out, or to remove it later if this setup installed it
|
|
361
361
|
- It installs `@juicesharp/rpiv-todo` and `pi-plugin-manager` by default
|
|
362
|
+
- When todo is on, `apply` suggests a todo-discipline line for the user's global Pi context file if it is missing
|
|
362
363
|
- Set `pi.todo: false` or `pi.plugin_manager: false` to leave either package out
|
|
363
364
|
- It installs `@juicesharp/rpiv-ask-user-question` as pi's question tool by default
|
|
364
365
|
- ACStack uses it because decisions can include markdown, code and artifact previews
|
package/package.json
CHANGED
package/pi/extension.ts
CHANGED
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
* before_agent_start list ACStack's skills in the system prompt in every
|
|
11
11
|
* session, and add orchestrator/AGENTS.md in a
|
|
12
12
|
* acstack project (hooks/session-start.sh)
|
|
13
|
-
* add the writing style and its per-turn reminder
|
|
14
|
-
* the
|
|
13
|
+
* add the writing style and its per-turn reminder
|
|
14
|
+
* from the SSOT style file (hooks/ac-writing-style-reminder.sh)
|
|
15
15
|
* agent_before_settle nudge with a continuity-versus-freshness checkpoint
|
|
16
16
|
* as context fills (hooks/context-pressure.sh)
|
|
17
17
|
* session_compact re-inject acstack/HANDOFF.md after a compaction, and
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
* hooks/context-pressure.sh)
|
|
20
20
|
*
|
|
21
21
|
* It also registers /acstack <skill>, a /acstack:<skill> command per skill,
|
|
22
|
-
* and /acstack-writing-style
|
|
23
|
-
*
|
|
24
|
-
* /skill:<name> commands for them.
|
|
22
|
+
* and /acstack-writing-style for the bundled/default/custom style choice.
|
|
23
|
+
* The first two forms are the only way a user runs an ACStack skill on pi:
|
|
24
|
+
* package.json lists no skills, so pi adds no /skill:<name> commands for them.
|
|
25
25
|
*
|
|
26
26
|
* Only type imports come from pi, so Node can strip the types and load this
|
|
27
27
|
* file in tests/test-pi-extension.sh with a stub API.
|
|
@@ -45,6 +45,12 @@ function agentDir(): string {
|
|
|
45
45
|
return process.env.PI_CODING_AGENT_DIR || path.join(os.homedir(), ".pi", "agent");
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
const settingsFile = (): string => path.join(agentDir(), "acstack.json");
|
|
49
|
+
|
|
50
|
+
type WritingStyleMode = "default" | "off" | "custom";
|
|
51
|
+
type WritingStyleSettings = { mode?: WritingStyleMode; path?: string };
|
|
52
|
+
type AcstackSettings = { writingStyle?: boolean | WritingStyleSettings };
|
|
53
|
+
|
|
48
54
|
function readText(file: string): string | undefined {
|
|
49
55
|
try {
|
|
50
56
|
return fs.readFileSync(file, "utf-8");
|
|
@@ -53,6 +59,34 @@ function readText(file: string): string | undefined {
|
|
|
53
59
|
}
|
|
54
60
|
}
|
|
55
61
|
|
|
62
|
+
function readSettings(): AcstackSettings {
|
|
63
|
+
try {
|
|
64
|
+
const parsed = JSON.parse(readText(settingsFile()) ?? "{}");
|
|
65
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
66
|
+
} catch {
|
|
67
|
+
return {};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function writeSettings(settings: AcstackSettings): void {
|
|
72
|
+
fs.mkdirSync(path.dirname(settingsFile()), { recursive: true });
|
|
73
|
+
fs.writeFileSync(settingsFile(), `${JSON.stringify(settings, null, 2)}\n`, "utf-8");
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function writingStyleSettings(settings: AcstackSettings = readSettings()): WritingStyleSettings {
|
|
77
|
+
const value = settings.writingStyle;
|
|
78
|
+
if (value === false) return { mode: "off" };
|
|
79
|
+
if (value === true || value === undefined) return { mode: "default" };
|
|
80
|
+
if (value && typeof value === "object") return { mode: value.mode ?? "default", path: value.path };
|
|
81
|
+
return { mode: "default" };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function expandUserPath(file: string, cwd = process.cwd()): string {
|
|
85
|
+
if (file === "~") return os.homedir();
|
|
86
|
+
if (file.startsWith(`~${path.sep}`)) return path.join(os.homedir(), file.slice(2));
|
|
87
|
+
return path.isAbsolute(file) ? file : path.resolve(cwd, file);
|
|
88
|
+
}
|
|
89
|
+
|
|
56
90
|
function report(ctx: ExtensionContext, message: string, level: "info" | "warning" | "error" = "info"): void {
|
|
57
91
|
if (ctx.hasUI) ctx.ui.notify(message, level);
|
|
58
92
|
else process.stderr.write(`${message}\n`);
|
|
@@ -172,22 +206,6 @@ function linkClis(ctx: ExtensionContext): void {
|
|
|
172
206
|
// Writing style
|
|
173
207
|
// --------------------------------------------------------------------------
|
|
174
208
|
|
|
175
|
-
const settingsFile = (): string => path.join(agentDir(), "acstack.json");
|
|
176
|
-
|
|
177
|
-
function readSettings(): { writingStyle?: boolean } {
|
|
178
|
-
try {
|
|
179
|
-
const parsed = JSON.parse(readText(settingsFile()) ?? "{}");
|
|
180
|
-
return parsed && typeof parsed === "object" ? parsed : {};
|
|
181
|
-
} catch {
|
|
182
|
-
return {};
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
function writeSettings(settings: { writingStyle?: boolean }): void {
|
|
187
|
-
fs.mkdirSync(path.dirname(settingsFile()), { recursive: true });
|
|
188
|
-
fs.writeFileSync(settingsFile(), `${JSON.stringify(settings, null, 2)}\n`, "utf-8");
|
|
189
|
-
}
|
|
190
|
-
|
|
191
209
|
function stripFrontmatter(text: string): string {
|
|
192
210
|
const match = /^---\n[\s\S]*?\n---\n/.exec(text);
|
|
193
211
|
return (match ? text.slice(match[0].length) : text).trim();
|
|
@@ -616,10 +634,16 @@ export default function acstack(pi: ExtensionAPI): void {
|
|
|
616
634
|
else report(ctx, `acstack: could not read ${orchestratorFile}`, "warning");
|
|
617
635
|
}
|
|
618
636
|
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
637
|
+
const styleCfg = writingStyleSettings();
|
|
638
|
+
if (styleCfg.mode === "off") return;
|
|
639
|
+
const resolvedStyleFile = styleCfg.mode === "custom" && styleCfg.path ? expandUserPath(styleCfg.path) : styleFile;
|
|
640
|
+
const style = readText(resolvedStyleFile);
|
|
641
|
+
if (!style) {
|
|
642
|
+
report(ctx, `acstack: could not read writing style at ${resolvedStyleFile}`, "warning");
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
622
645
|
sections["acstack-writing-style"] = stripFrontmatter(style);
|
|
646
|
+
if (event.messageType !== "user") return;
|
|
623
647
|
const reminder = extractWritingReminder(style);
|
|
624
648
|
if (!reminder) return;
|
|
625
649
|
return { message: { customType: "acstack-writing-style-reminder", content: reminder, display: false } };
|
|
@@ -686,6 +710,44 @@ export default function acstack(pi: ExtensionAPI): void {
|
|
|
686
710
|
else pi.sendUserMessage(message, { deliverAs: "followUp" });
|
|
687
711
|
};
|
|
688
712
|
|
|
713
|
+
pi.registerCommand("acstack-writing-style", {
|
|
714
|
+
description: "Configure ACStack writing style injection: default | off | custom <path>",
|
|
715
|
+
handler: async (args, ctx) => {
|
|
716
|
+
const [choice = "", ...rest] = args.trim().split(/\s+/).filter(Boolean);
|
|
717
|
+
const settings = readSettings();
|
|
718
|
+
const current = writingStyleSettings(settings);
|
|
719
|
+
if (!choice || choice === "show") {
|
|
720
|
+
report(ctx, `acstack: writing style is ${current.mode}${current.path ? ` (${current.path})` : ""} (${settingsFile()}).`);
|
|
721
|
+
return;
|
|
722
|
+
}
|
|
723
|
+
if (choice === "default") {
|
|
724
|
+
settings.writingStyle = { mode: "default" };
|
|
725
|
+
writeSettings(settings);
|
|
726
|
+
report(ctx, `acstack: writing style is default (${settingsFile()}).`);
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
if (choice === "off") {
|
|
730
|
+
settings.writingStyle = { mode: "off" };
|
|
731
|
+
writeSettings(settings);
|
|
732
|
+
report(ctx, `acstack: writing style is off (${settingsFile()}).`);
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
if (choice === "custom") {
|
|
736
|
+
const customPath = rest.join(" ").trim();
|
|
737
|
+
if (!customPath) {
|
|
738
|
+
report(ctx, "acstack: usage is /acstack-writing-style custom <path>", "warning");
|
|
739
|
+
return;
|
|
740
|
+
}
|
|
741
|
+
const resolvedPath = expandUserPath(customPath, ctx.cwd);
|
|
742
|
+
settings.writingStyle = { mode: "custom", path: resolvedPath };
|
|
743
|
+
writeSettings(settings);
|
|
744
|
+
report(ctx, `acstack: writing style is custom (${resolvedPath}) (${settingsFile()}).`);
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
747
|
+
report(ctx, "acstack: usage is /acstack-writing-style [show|default|off|custom <path>]", "warning");
|
|
748
|
+
},
|
|
749
|
+
});
|
|
750
|
+
|
|
689
751
|
pi.registerCommand("acstack", {
|
|
690
752
|
description: "Run an ACStack skill: /acstack <skill> [args], e.g. /acstack map",
|
|
691
753
|
handler: async (args, ctx) => {
|
|
@@ -704,20 +766,4 @@ export default function acstack(pi: ExtensionAPI): void {
|
|
|
704
766
|
handler: async (args, ctx) => runSkill(name, args, ctx),
|
|
705
767
|
});
|
|
706
768
|
}
|
|
707
|
-
|
|
708
|
-
pi.registerCommand("acstack-writing-style", {
|
|
709
|
-
description: "Turn the ACStack writing style on or off for every pi session (on | off)",
|
|
710
|
-
handler: async (args, ctx) => {
|
|
711
|
-
const choice = args.trim().toLowerCase();
|
|
712
|
-
const settings = readSettings();
|
|
713
|
-
if (choice === "on" || choice === "off") {
|
|
714
|
-
settings.writingStyle = choice === "on";
|
|
715
|
-
writeSettings(settings);
|
|
716
|
-
} else if (choice) {
|
|
717
|
-
report(ctx, "acstack: usage is /acstack-writing-style on|off", "warning");
|
|
718
|
-
return;
|
|
719
|
-
}
|
|
720
|
-
report(ctx, `acstack: writing style is ${settings.writingStyle ? "on" : "off"} (${settingsFile()}).`);
|
|
721
|
-
},
|
|
722
|
-
});
|
|
723
769
|
}
|