acstack 0.48.2 → 0.48.5

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/cli/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "acstack-cli",
3
- "version": "0.48.2",
3
+ "version": "0.48.5",
4
4
  "description": "CLI for the ACStack agentic coding stack",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -9,7 +9,7 @@
9
9
  },
10
10
  "repository": {
11
11
  "type": "git",
12
- "url": "git+https://github.com/ac8318740/spechub.git",
12
+ "url": "git+https://github.com/ac8318740/acstack.git",
13
13
  "directory": "cli"
14
14
  },
15
15
  "bin": {
@@ -55,7 +55,7 @@
55
55
  "yaml": "^2.7.0",
56
56
  "zod": "^3.24.0"
57
57
  },
58
- "homepage": "https://github.com/ac8318740/spechub/tree/main/cli",
58
+ "homepage": "https://github.com/ac8318740/acstack/tree/main/cli",
59
59
  "keywords": [
60
60
  "agentic-coding",
61
61
  "acstack",
@@ -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
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "acstack",
3
- "version": "0.48.2",
3
+ "version": "0.48.5",
4
4
  "private": false,
5
5
  "description": "Agentic coding stack with first-class Claude Code and pi support: skills, orchestrator instructions, and verification agents.",
6
6
  "license": "MIT",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "git+https://github.com/ac8318740/spechub.git"
9
+ "url": "git+https://github.com/ac8318740/acstack.git"
10
10
  },
11
11
  "keywords": [
12
12
  "pi-package",
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 when
14
- * the user turned it on (hooks/ac-writing-style-reminder.sh)
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 on|off. Those two forms are the only way a user
23
- * runs an ACStack skill on pi: package.json lists no skills, so pi adds no
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
- if (!readSettings().writingStyle) return;
620
- const style = readText(styleFile);
621
- if (!style) return;
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
  }