lsd-pi 1.1.2 → 1.1.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.
Files changed (183) hide show
  1. package/README.md +2 -1
  2. package/dist/bedrock-auth.d.ts +25 -0
  3. package/dist/bedrock-auth.js +59 -0
  4. package/dist/headless.js +8 -3
  5. package/dist/loader.js +1 -0
  6. package/dist/onboarding-llm.d.ts +37 -0
  7. package/dist/onboarding-llm.js +64 -0
  8. package/dist/onboarding.d.ts +2 -14
  9. package/dist/onboarding.js +146 -71
  10. package/dist/pi-migration.js +1 -0
  11. package/dist/resources/extensions/memory/auto-extract.js +21 -3
  12. package/dist/resources/extensions/memory/dream.js +703 -0
  13. package/dist/resources/extensions/memory/extension-manifest.json +2 -2
  14. package/dist/resources/extensions/memory/index.js +115 -8
  15. package/dist/resources/extensions/slash-commands/extension-manifest.json +10 -10
  16. package/dist/resources/extensions/slash-commands/index.js +0 -4
  17. package/dist/resources/extensions/slash-commands/plan.js +181 -45
  18. package/dist/resources/extensions/subagent/agents.js +14 -1
  19. package/dist/resources/extensions/subagent/configured-model.js +3 -2
  20. package/dist/resources/extensions/subagent/index.js +34 -28
  21. package/dist/resources/extensions/subagent/launch-helpers.js +24 -0
  22. package/dist/resources/extensions/subagent/model-resolution.js +41 -3
  23. package/dist/resources/extensions/usage/extension-manifest.json +11 -0
  24. package/dist/resources/extensions/usage/index.js +346 -0
  25. package/{src/resources/skills/create-gsd-extension → dist/resources/skills/create-lsd-extension}/SKILL.md +6 -6
  26. package/{src/resources/skills/create-gsd-extension → dist/resources/skills/create-lsd-extension}/references/custom-tools.md +1 -1
  27. package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/references/extension-lifecycle.md +2 -2
  28. package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/references/extensioncontext-reference.md +1 -1
  29. package/{src/resources/skills/create-gsd-extension → dist/resources/skills/create-lsd-extension}/references/key-rules-gotchas.md +4 -4
  30. package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/references/packaging-distribution.md +6 -6
  31. package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/workflows/create-extension.md +3 -3
  32. package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/workflows/debug-extension.md +5 -5
  33. package/dist/resources/skills/teams-debug/SKILL.md +5 -6
  34. package/dist/resources/skills/teams-document/SKILL.md +1 -2
  35. package/dist/resources/skills/teams-plan/SKILL.md +3 -4
  36. package/dist/resources/skills/teams-run/SKILL.md +3 -4
  37. package/dist/resources/skills/teams-verify/SKILL.md +4 -5
  38. package/dist/startup-model-validation.js +1 -0
  39. package/dist/welcome-screen.js +13 -11
  40. package/dist/wizard.js +12 -0
  41. package/package.json +1 -1
  42. package/packages/pi-ai/dist/models.generated.d.ts +688 -409
  43. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  44. package/packages/pi-ai/dist/models.generated.js +761 -488
  45. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  46. package/packages/pi-ai/scripts/generate-models.ts +40 -18
  47. package/packages/pi-ai/src/models.generated.ts +759 -486
  48. package/packages/pi-coding-agent/dist/cli/config-selector.js +1 -1
  49. package/packages/pi-coding-agent/dist/cli/config-selector.js.map +1 -1
  50. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +1 -2
  51. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  52. package/packages/pi-coding-agent/dist/core/agent-session.js +6 -30
  53. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  54. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +6 -0
  55. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  56. package/packages/pi-coding-agent/dist/core/settings-manager.js +44 -1
  57. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  58. package/packages/pi-coding-agent/dist/core/skill-tool.test.js +9 -5
  59. package/packages/pi-coding-agent/dist/core/skill-tool.test.js.map +1 -1
  60. package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
  61. package/packages/pi-coding-agent/dist/core/skills.js +3 -2
  62. package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
  63. package/packages/pi-coding-agent/dist/index.d.ts +1 -1
  64. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  65. package/packages/pi-coding-agent/dist/index.js +1 -1
  66. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  67. package/packages/pi-coding-agent/dist/main.js +1 -1
  68. package/packages/pi-coding-agent/dist/main.js.map +1 -1
  69. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js +2 -2
  70. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js.map +1 -1
  71. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  72. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +15 -12
  73. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  74. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +6 -0
  75. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  76. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +25 -1
  77. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
  78. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +1 -1
  79. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  80. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  81. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +10 -0
  82. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  83. package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js +1 -1
  84. package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js.map +1 -1
  85. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  86. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +31 -22
  87. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  88. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts +18 -5
  89. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  90. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +139 -20
  91. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  92. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  93. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +4 -0
  94. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
  95. package/packages/pi-coding-agent/package.json +1 -1
  96. package/packages/pi-coding-agent/src/cli/config-selector.ts +1 -1
  97. package/packages/pi-coding-agent/src/core/agent-session.ts +5 -28
  98. package/packages/pi-coding-agent/src/core/settings-manager.ts +52 -1
  99. package/packages/pi-coding-agent/src/core/skill-tool.test.ts +18 -5
  100. package/packages/pi-coding-agent/src/core/skills.ts +3 -2
  101. package/packages/pi-coding-agent/src/index.ts +1 -1
  102. package/packages/pi-coding-agent/src/main.ts +1 -1
  103. package/packages/pi-coding-agent/src/modes/interactive/components/bash-execution.ts +2 -2
  104. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +12 -13
  105. package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +39 -1
  106. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +1 -1
  107. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +10 -0
  108. package/packages/pi-coding-agent/src/modes/interactive/controllers/extension-ui-controller.ts +1 -1
  109. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +46 -20
  110. package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +171 -20
  111. package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +4 -0
  112. package/packages/pi-tui/dist/components/editor.d.ts +1 -0
  113. package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
  114. package/packages/pi-tui/dist/components/editor.js +23 -0
  115. package/packages/pi-tui/dist/components/editor.js.map +1 -1
  116. package/packages/pi-tui/src/components/editor.ts +23 -0
  117. package/pkg/dist/modes/interactive/theme/theme.d.ts +18 -5
  118. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  119. package/pkg/dist/modes/interactive/theme/theme.js +139 -20
  120. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
  121. package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  122. package/pkg/dist/modes/interactive/theme/themes.js +4 -0
  123. package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
  124. package/pkg/package.json +1 -1
  125. package/src/resources/extensions/memory/auto-extract.ts +23 -3
  126. package/src/resources/extensions/memory/dream.ts +814 -0
  127. package/src/resources/extensions/memory/extension-manifest.json +2 -2
  128. package/src/resources/extensions/memory/index.ts +134 -13
  129. package/src/resources/extensions/memory/tests/auto-extract.test.ts +10 -2
  130. package/src/resources/extensions/memory/tests/dream.test.ts +142 -0
  131. package/src/resources/extensions/slash-commands/extension-manifest.json +10 -10
  132. package/src/resources/extensions/slash-commands/index.ts +3 -7
  133. package/src/resources/extensions/slash-commands/plan.ts +192 -46
  134. package/src/resources/extensions/subagent/agents.ts +11 -1
  135. package/src/resources/extensions/subagent/configured-model.ts +3 -2
  136. package/src/resources/extensions/subagent/index.ts +38 -30
  137. package/src/resources/extensions/subagent/launch-helpers.ts +30 -0
  138. package/src/resources/extensions/subagent/model-resolution.ts +40 -3
  139. package/src/resources/extensions/usage/extension-manifest.json +11 -0
  140. package/src/resources/extensions/usage/index.ts +441 -0
  141. package/{dist/resources/skills/create-gsd-extension → src/resources/skills/create-lsd-extension}/SKILL.md +6 -6
  142. package/{dist/resources/skills/create-gsd-extension → src/resources/skills/create-lsd-extension}/references/custom-tools.md +1 -1
  143. package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/references/extension-lifecycle.md +2 -2
  144. package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/references/extensioncontext-reference.md +1 -1
  145. package/{dist/resources/skills/create-gsd-extension → src/resources/skills/create-lsd-extension}/references/key-rules-gotchas.md +4 -4
  146. package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/references/packaging-distribution.md +6 -6
  147. package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/workflows/create-extension.md +3 -3
  148. package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/workflows/debug-extension.md +5 -5
  149. package/src/resources/skills/teams-debug/SKILL.md +5 -6
  150. package/src/resources/skills/teams-document/SKILL.md +1 -2
  151. package/src/resources/skills/teams-plan/SKILL.md +3 -4
  152. package/src/resources/skills/teams-run/SKILL.md +3 -4
  153. package/src/resources/skills/teams-verify/SKILL.md +4 -5
  154. package/dist/resources/extensions/slash-commands/create-extension.js +0 -264
  155. package/dist/resources/extensions/slash-commands/create-slash-command.js +0 -208
  156. package/src/resources/extensions/slash-commands/create-extension.ts +0 -297
  157. package/src/resources/extensions/slash-commands/create-slash-command.ts +0 -234
  158. /package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/references/compaction-session-control.md +0 -0
  159. /package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/references/custom-commands.md +0 -0
  160. /package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/references/custom-rendering.md +0 -0
  161. /package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/references/custom-ui.md +0 -0
  162. /package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/references/events-reference.md +0 -0
  163. /package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/references/extensionapi-reference.md +0 -0
  164. /package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/references/mode-behavior.md +0 -0
  165. /package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/references/model-provider-management.md +0 -0
  166. /package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/references/remote-execution-overrides.md +0 -0
  167. /package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/references/state-management.md +0 -0
  168. /package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/references/system-prompt-modification.md +0 -0
  169. /package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/workflows/add-capability.md +0 -0
  170. /package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/references/compaction-session-control.md +0 -0
  171. /package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/references/custom-commands.md +0 -0
  172. /package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/references/custom-rendering.md +0 -0
  173. /package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/references/custom-ui.md +0 -0
  174. /package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/references/events-reference.md +0 -0
  175. /package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/references/extensionapi-reference.md +0 -0
  176. /package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/references/mode-behavior.md +0 -0
  177. /package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/references/model-provider-management.md +0 -0
  178. /package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/references/remote-execution-overrides.md +0 -0
  179. /package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/references/state-management.md +0 -0
  180. /package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/references/system-prompt-modification.md +0 -0
  181. /package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/templates/extension-skeleton.ts +0 -0
  182. /package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/templates/stateful-tool-skeleton.ts +0 -0
  183. /package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/workflows/add-capability.md +0 -0
@@ -115,6 +115,7 @@ export interface Settings {
115
115
  defaultProvider?: string;
116
116
  defaultModel?: string;
117
117
  budgetSubagentModel?: string;
118
+ planModeReasoningModel?: string;
118
119
  permissionMode?: "danger-full-access" | "accept-on-edit" | "auto" | "plan";
119
120
  classifierModel?: string;
120
121
  defaultThinkingLevel?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
@@ -122,6 +123,7 @@ export interface Settings {
122
123
  steeringMode?: "all" | "one-at-a-time";
123
124
  followUpMode?: "all" | "one-at-a-time";
124
125
  theme?: string;
126
+ themeAccent?: string;
125
127
  compaction?: CompactionSettings;
126
128
  branchSummary?: BranchSummarySettings;
127
129
  retry?: RetrySettings;
@@ -164,6 +166,14 @@ export interface Settings {
164
166
  rtk?: boolean; // default: false — enable RTK shell-command compression (requires restart)
165
167
  }
166
168
 
169
+ function isQualifiedProviderModelRef(value: unknown): value is string {
170
+ if (typeof value !== "string") return false;
171
+ const trimmed = value.trim();
172
+ if (!trimmed) return false;
173
+ const parts = trimmed.split("/");
174
+ return parts.length === 2 && parts.every((part) => part.trim().length > 0);
175
+ }
176
+
167
177
  /** Deep merge settings: project/overrides take precedence, nested objects merge recursively */
168
178
  function deepMergeSettings(base: Settings, overrides: Settings): Settings {
169
179
  const result: Settings = { ...base };
@@ -415,6 +425,14 @@ export class SettingsManager {
415
425
  }
416
426
  }
417
427
 
428
+ if (
429
+ "planModeReasoningModel" in settings &&
430
+ settings.planModeReasoningModel !== undefined &&
431
+ !isQualifiedProviderModelRef(settings.planModeReasoningModel)
432
+ ) {
433
+ delete settings.planModeReasoningModel;
434
+ }
435
+
418
436
  return settings as Settings;
419
437
  }
420
438
 
@@ -670,6 +688,12 @@ export class SettingsManager {
670
688
  return this.settings.budgetSubagentModel;
671
689
  }
672
690
 
691
+ getPlanModeReasoningModel(): string | undefined {
692
+ return isQualifiedProviderModelRef(this.settings.planModeReasoningModel)
693
+ ? this.settings.planModeReasoningModel.trim()
694
+ : undefined;
695
+ }
696
+
673
697
  getPermissionMode(): "danger-full-access" | "accept-on-edit" | "auto" | "plan" {
674
698
  return this.settings.permissionMode ?? "accept-on-edit";
675
699
  }
@@ -696,6 +720,19 @@ export class SettingsManager {
696
720
  this.setGlobalSetting("budgetSubagentModel", modelRef);
697
721
  }
698
722
 
723
+ setPlanModeReasoningModel(modelRef: string | undefined): void {
724
+ if (modelRef === undefined) {
725
+ delete this.globalSettings.planModeReasoningModel;
726
+ this.markModified("planModeReasoningModel");
727
+ this.save();
728
+ return;
729
+ }
730
+ if (!isQualifiedProviderModelRef(modelRef)) {
731
+ throw new Error(`planModeReasoningModel must be in provider/id format. Received: ${modelRef}`);
732
+ }
733
+ this.setGlobalSetting("planModeReasoningModel", modelRef.trim());
734
+ }
735
+
699
736
  setPermissionMode(mode: "danger-full-access" | "accept-on-edit" | "auto" | "plan"): void {
700
737
  this.setGlobalSetting("permissionMode", mode);
701
738
  }
@@ -750,6 +787,20 @@ export class SettingsManager {
750
787
  this.setGlobalSetting("theme", theme);
751
788
  }
752
789
 
790
+ getThemeAccent(): string | undefined {
791
+ return this.settings.themeAccent;
792
+ }
793
+
794
+ setThemeAccent(accent: string | undefined): void {
795
+ if (accent === undefined) {
796
+ delete this.globalSettings.themeAccent;
797
+ this.markModified("themeAccent");
798
+ this.save();
799
+ return;
800
+ }
801
+ this.setGlobalSetting("themeAccent", accent);
802
+ }
803
+
753
804
  getDefaultThinkingLevel(): "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | undefined {
754
805
  return this.settings.defaultThinkingLevel;
755
806
  }
@@ -828,7 +879,7 @@ export class SettingsManager {
828
879
  }
829
880
 
830
881
  getHideThinkingBlock(): boolean {
831
- return this.settings.hideThinkingBlock ?? false;
882
+ return this.settings.hideThinkingBlock ?? true;
832
883
  }
833
884
 
834
885
  setHideThinkingBlock(hide: boolean): void {
@@ -97,7 +97,7 @@ describe("Skill tool", () => {
97
97
  assert.match(message, /swift-testing/);
98
98
  });
99
99
 
100
- it("supports direct slash aliases for user-invocable skills", async () => {
100
+ it("expands explicit /skill:name invocations", async () => {
101
101
  writeSkill(
102
102
  testDir,
103
103
  "teams-plan",
@@ -106,16 +106,29 @@ describe("Skill tool", () => {
106
106
  "user-invocable: true",
107
107
  );
108
108
  const session = await createSession();
109
- const loadedSkill = session.resourceLoader.getSkills().skills.find((skill) => skill.name === "teams-plan");
110
- assert.equal(loadedSkill?.userInvocable, true);
111
109
  const expanded = (session as unknown as { _expandSkillCommand: (text: string) => string })._expandSkillCommand(
112
- "/teams-plan build auth",
110
+ "/skill:teams-plan build auth",
113
111
  );
114
112
  assert.match(expanded, /<skill name="teams-plan"/);
115
113
  assert.match(expanded, /build auth/);
116
114
  });
117
115
 
118
- it("does not treat non-invocable skills as direct slash aliases", async () => {
116
+ it("does not expand bare /name aliases even when user-invocable is set", async () => {
117
+ writeSkill(
118
+ testDir,
119
+ "teams-plan",
120
+ "Plan and build a feature.",
121
+ "# Teams Plan\nUse this skill.\n",
122
+ "user-invocable: true",
123
+ );
124
+ const session = await createSession();
125
+ const expanded = (session as unknown as { _expandSkillCommand: (text: string) => string })._expandSkillCommand(
126
+ "/teams-plan build auth",
127
+ );
128
+ assert.equal(expanded, "/teams-plan build auth");
129
+ });
130
+
131
+ it("does not treat bare /name skill invocations as commands when no skill: prefix is used", async () => {
119
132
  writeSkill(testDir, "internal-skill", "Internal only.", "# Internal\n");
120
133
  const session = await createSession();
121
134
  const expanded = (session as unknown as { _expandSkillCommand: (text: string) => string })._expandSkillCommand(
@@ -425,10 +425,11 @@ export function loadSkills(options: LoadSkillsOptions = {}): LoadSkillsResult {
425
425
  }
426
426
 
427
427
  if (includeDefaults) {
428
- // Primary global location for LSD.
429
- addSkills(loadSkillsFromDirInternal(ECOSYSTEM_SKILLS_DIR, "user", true));
430
428
  // Preferred project-local location for LSD repos.
429
+ // Load this first so project skills shadow user/global skills with the same name.
431
430
  addSkills(loadSkillsFromDirInternal(resolve(cwd, ECOSYSTEM_PROJECT_SKILLS_DIR, "skills"), "project", true));
431
+ // Primary global location for LSD.
432
+ addSkills(loadSkillsFromDirInternal(ECOSYSTEM_SKILLS_DIR, "user", true));
432
433
  // Compatibility fallback: shared Agent Skills ecosystem directory.
433
434
  if (COMPAT_ECOSYSTEM_SKILLS_DIR !== ECOSYSTEM_SKILLS_DIR) {
434
435
  addSkills(loadSkillsFromDirInternal(COMPAT_ECOSYSTEM_SKILLS_DIR, "user", true));
@@ -1,7 +1,7 @@
1
1
  // Core session management
2
2
 
3
3
  // Config paths
4
- export { getAgentDir, VERSION } from "./config.js";
4
+ export { CONFIG_DIR_NAME, getAgentDir, VERSION } from "./config.js";
5
5
  export { resetStdinForTui } from "./utils/reset-stdin.js";
6
6
  export {
7
7
  AgentSession,
@@ -523,7 +523,7 @@ export async function main(args: string[]) {
523
523
  const { initialMessage, initialImages } = await prepareInitialMessage(parsed, settingsManager.getImageAutoResize());
524
524
  const isInteractive = !parsed.print && parsed.mode === undefined;
525
525
  const mode = parsed.mode || "text";
526
- initTheme(settingsManager.getTheme(), isInteractive);
526
+ initTheme(settingsManager.getTheme(), isInteractive, settingsManager.getThemeAccent());
527
527
 
528
528
  // Show deprecation warnings in interactive mode
529
529
  if (isInteractive && deprecationWarnings.length > 0) {
@@ -95,8 +95,8 @@ export class BashExecutionComponent extends Container {
95
95
  let text = theme.fg(this.colorKey, theme.bold(`$ ${this.command}`));
96
96
  if (this.rtkActive) {
97
97
  const badge = this.rtkFlashOn
98
- ? theme.fg("accent", " RTK")
99
- : theme.fg("dim", " RTK");
98
+ ? theme.fg("accent", "$ RTK")
99
+ : theme.fg("dim", "$ RTK");
100
100
  text = `${text} ${badge}`;
101
101
  }
102
102
  return text;
@@ -169,13 +169,10 @@ export class FooterComponent implements Component {
169
169
 
170
170
  // Colorize context percentage based on usage
171
171
  let contextPercentStr: string;
172
- const autoIndicator = this.autoCompactEnabled ? " (auto)" : "";
173
172
  const contextPercentDisplay =
174
173
  contextPercent === "?"
175
- ? `?/${formatTokens(contextWindow)}${autoIndicator}`
176
- : contextTokens !== null
177
- ? `${formatTokens(contextTokens)} ${contextPercent}%/${formatTokens(contextWindow)}${autoIndicator}`
178
- : `${contextPercent}%/${formatTokens(contextWindow)}${autoIndicator}`;
174
+ ? `?/${formatTokens(contextWindow)}`
175
+ : `${contextPercent}%/${formatTokens(contextWindow)}`;
179
176
  if (contextPercentValue > 90) {
180
177
  contextPercentStr = theme.fg("error", contextPercentDisplay);
181
178
  } else if (contextPercentValue > 70) {
@@ -186,14 +183,16 @@ export class FooterComponent implements Component {
186
183
  statsParts.push(contextPercentStr);
187
184
 
188
185
  const currentPermissionMode = getPermissionMode();
189
- const permissionModeLabel =
190
- currentPermissionMode === "danger-full-access"
191
- ? "⚡ full-access"
192
- : currentPermissionMode === "accept-on-edit"
193
- ? "✓ accept-edit"
194
- : currentPermissionMode === "auto"
195
- ? "🤖 auto"
196
- : "📝 plan";
186
+ let permissionModeLabel: string;
187
+ if (currentPermissionMode === "danger-full-access") {
188
+ permissionModeLabel = theme.fg("error", "⚡ full-access");
189
+ } else if (currentPermissionMode === "accept-on-edit") {
190
+ permissionModeLabel = theme.fg("success", "✓ accept-edit");
191
+ } else if (currentPermissionMode === "auto") {
192
+ permissionModeLabel = theme.fg("warning", "🤖 auto");
193
+ } else {
194
+ permissionModeLabel = theme.fg("violet", "📝 plan");
195
+ }
197
196
  statsParts.push(permissionModeLabel);
198
197
 
199
198
  let statsLeft = statsParts.join(" ");
@@ -11,7 +11,7 @@ import {
11
11
  Spacer,
12
12
  Text,
13
13
  } from "@gsd/pi-tui";
14
- import { getSelectListTheme, getSettingsListTheme, theme } from "../theme/theme.js";
14
+ import { getSelectListTheme, getSettingsListTheme, getThemeAccentInfo, getThemeAccentLabel, theme } from "../theme/theme.js";
15
15
  import { DynamicBorder } from "./dynamic-border.js";
16
16
 
17
17
  export const THINKING_DESCRIPTIONS: Record<ThinkingLevel, string> = {
@@ -28,6 +28,7 @@ export interface SettingsConfig {
28
28
  autoCompactThresholdPercent: number;
29
29
  classifierModel: string;
30
30
  budgetSubagentModel: string;
31
+ planModeReasoningModel: string;
31
32
  showImages: boolean;
32
33
  autoResizeImages: boolean;
33
34
  blockImages: boolean;
@@ -41,6 +42,8 @@ export interface SettingsConfig {
41
42
  availableThinkingLevels: ThinkingLevel[];
42
43
  currentTheme: string;
43
44
  availableThemes: string[];
45
+ currentThemeAccent: string;
46
+ availableThemeAccents: string[];
44
47
  hideThinkingBlock: boolean;
45
48
  collapseChangelog: boolean;
46
49
  doubleEscapeAction: "fork" | "tree" | "none";
@@ -56,6 +59,7 @@ export interface SettingsConfig {
56
59
  rtk: boolean;
57
60
  classifierModelSubmenu?: (currentValue: string, done: (selectedValue?: string) => void) => Component;
58
61
  budgetSubagentModelSubmenu?: (currentValue: string, done: (selectedValue?: string) => void) => Component;
62
+ planModeReasoningModelSubmenu?: (currentValue: string, done: (selectedValue?: string) => void) => Component;
59
63
  }
60
64
 
61
65
  export interface SettingsCallbacks {
@@ -63,6 +67,7 @@ export interface SettingsCallbacks {
63
67
  onAutoCompactThresholdPercentChange: (percent: number) => void;
64
68
  onClassifierModelChange: (modelRef: string) => void;
65
69
  onBudgetSubagentModelChange: (modelRef: string) => void;
70
+ onPlanModeReasoningModelChange: (modelRef: string) => void;
66
71
  onShowImagesChange: (enabled: boolean) => void;
67
72
  onAutoResizeImagesChange: (enabled: boolean) => void;
68
73
  onBlockImagesChange: (blocked: boolean) => void;
@@ -75,6 +80,7 @@ export interface SettingsCallbacks {
75
80
  onThinkingLevelChange: (level: ThinkingLevel) => void;
76
81
  onThemeChange: (theme: string) => void;
77
82
  onThemePreview?: (theme: string) => void;
83
+ onThemeAccentChange: (accent: string) => void;
78
84
  onHideThinkingBlockChange: (hidden: boolean) => void;
79
85
  onCollapseChangelogChange: (collapsed: boolean) => void;
80
86
  onDoubleEscapeActionChange: (action: "fork" | "tree" | "none") => void;
@@ -193,6 +199,13 @@ export class SettingsSelectorComponent extends Container {
193
199
  currentValue: config.budgetSubagentModel,
194
200
  submenu: config.budgetSubagentModelSubmenu,
195
201
  },
202
+ {
203
+ id: "plan-mode-reasoning-model",
204
+ label: "Plan reasoning model",
205
+ description: "Optional provider/id model to switch to after plan approval",
206
+ currentValue: config.planModeReasoningModel,
207
+ submenu: config.planModeReasoningModelSubmenu,
208
+ },
196
209
  {
197
210
  id: "steering-mode",
198
211
  label: "Steering mode",
@@ -309,6 +322,28 @@ export class SettingsSelectorComponent extends Container {
309
322
  },
310
323
  ),
311
324
  },
325
+ {
326
+ id: "theme-accent",
327
+ label: "Main accent",
328
+ description: "Primary accent color used by the interface",
329
+ currentValue: config.currentThemeAccent,
330
+ submenu: (currentValue, done) =>
331
+ new SelectSubmenu(
332
+ "Main Accent",
333
+ "Select the primary accent color",
334
+ config.availableThemeAccents.map((accent) => ({
335
+ value: accent,
336
+ label: getThemeAccentLabel(accent as Parameters<typeof getThemeAccentInfo>[0]),
337
+ description: getThemeAccentInfo(accent as Parameters<typeof getThemeAccentInfo>[0]).description,
338
+ })),
339
+ currentValue,
340
+ (value) => {
341
+ callbacks.onThemeAccentChange(value);
342
+ done(value);
343
+ },
344
+ () => done(),
345
+ ),
346
+ },
312
347
  ];
313
348
 
314
349
  // Only show image toggle if terminal supports it
@@ -463,6 +498,9 @@ export class SettingsSelectorComponent extends Container {
463
498
  case "budget-subagent-model":
464
499
  callbacks.onBudgetSubagentModelChange(newValue);
465
500
  break;
501
+ case "plan-mode-reasoning-model":
502
+ callbacks.onPlanModeReasoningModelChange(newValue);
503
+ break;
466
504
  case "show-images":
467
505
  callbacks.onShowImagesChange(newValue === "true");
468
506
  break;
@@ -562,7 +562,7 @@ export class ToolExecutionComponent extends Container {
562
562
  const commandDisplay =
563
563
  command === null ? theme.fg("error", "[invalid arg]") : command ? command : theme.fg("toolOutput", "...");
564
564
  const rtkBadge = rtkActive
565
- ? " " + (this.rtkFlashOn ? theme.fg("accent", " RTK") : theme.fg("dim", " RTK"))
565
+ ? " " + (this.rtkFlashOn ? theme.fg("accent", "$ RTK") : theme.fg("dim", "$ RTK"))
566
566
  : "";
567
567
  this.contentBox.addChild(
568
568
  new Text(theme.fg("toolTitle", theme.bold(`$ ${commandDisplay}`)) + timeoutSuffix + rtkBadge, 0, 0),
@@ -78,6 +78,14 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
78
78
  host.defaultWorkingMessage,
79
79
  );
80
80
  host.statusContainer.addChild(host.loadingAnimation);
81
+ // Show steer/queue hint in editor bottom border while agent is running
82
+ {
83
+ const enterKey = theme.fg("dim", "↵");
84
+ const followUpKey = theme.fg("dim", appKey(host.keybindings, "followUp"));
85
+ const steerLabel = theme.fg("muted", " steer");
86
+ const queueLabel = theme.fg("muted", " queue");
87
+ host.defaultEditor.bottomHint = `${enterKey}${steerLabel} ${followUpKey}${queueLabel}`;
88
+ }
81
89
  if (host.pendingWorkingMessage !== undefined) {
82
90
  if (host.pendingWorkingMessage) {
83
91
  host.loadingAnimation.setMessage(host.pendingWorkingMessage);
@@ -254,6 +262,8 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
254
262
  host.streamingMessage = undefined;
255
263
  }
256
264
  host.pendingTools.clear();
265
+ // Clear the steer/queue hint when agent finishes
266
+ host.defaultEditor.bottomHint = "";
257
267
  await host.checkShutdownRequested();
258
268
  host.ui.requestRender();
259
269
  break;
@@ -43,7 +43,7 @@ export function createExtensionUIContext(host: any): ExtensionUIContext {
43
43
  host.ui.requestRender();
44
44
  return { success: true };
45
45
  }
46
- const result = setTheme(themeOrName, true);
46
+ const result = setTheme(themeOrName, true, host.settingsManager.getThemeAccent());
47
47
  if (result.success) {
48
48
  if (host.settingsManager.getTheme() !== themeOrName) {
49
49
  host.settingsManager.setTheme(themeOrName);
@@ -109,6 +109,7 @@ import {
109
109
  updateAvailableProviderCount as updateAvailableProviderCountController,
110
110
  } from "./controllers/model-controller.js";
111
111
  import {
112
+ getAvailableThemeAccents,
112
113
  getAvailableThemes,
113
114
  getAvailableThemesWithPaths,
114
115
  getEditorTheme,
@@ -311,7 +312,7 @@ export class InteractiveMode {
311
312
 
312
313
  // Register themes from resource loader and initialize
313
314
  setRegisteredThemes(this.session.resourceLoader.getThemes().themes);
314
- initTheme(this.settingsManager.getTheme(), true);
315
+ initTheme(this.settingsManager.getTheme(), true, this.settingsManager.getThemeAccent());
315
316
  }
316
317
 
317
318
  private setupAutocomplete(): void {
@@ -389,23 +390,10 @@ export class InteractiveMode {
389
390
  this.skillCommands.clear();
390
391
  const skillCommandList: SlashCommand[] = [];
391
392
  if (this.settingsManager.getEnableSkillCommands()) {
392
- const reservedSkillNames = new Set<string>([
393
- ...slashCommands.map((command) => command.name),
394
- ...templateCommands.map((command) => command.name),
395
- ...extensionCommands.map((command) => command.name),
396
- ]);
397
393
  for (const skill of this.session.resourceLoader.getSkills().skills) {
398
394
  const commandName = `skill:${skill.name}`;
399
395
  this.skillCommands.set(commandName, skill.filePath);
400
- if (skill.userInvocable && !reservedSkillNames.has(skill.name)) {
401
- // Register short name in the map and show only the short name in autocomplete
402
- // to avoid showing both "teams-plan" and "skill:teams-plan" as duplicates
403
- this.skillCommands.set(skill.name, skill.filePath);
404
- skillCommandList.push({ name: skill.name, description: skill.description });
405
- } else {
406
- // Not user-invocable or name is reserved — show only the skill: prefixed version
407
- skillCommandList.push({ name: commandName, description: skill.description });
408
- }
396
+ skillCommandList.push({ name: commandName, description: skill.description });
409
397
  }
410
398
  }
411
399
 
@@ -475,7 +463,7 @@ export class InteractiveMode {
475
463
 
476
464
  // Add changelog if provided
477
465
  if (this.changelogMarkdown) {
478
- this.headerContainer.addChild(new DynamicBorder());
466
+ this.headerContainer.addChild(new DynamicBorder((text) => theme.fg("borderAccent", text)));
479
467
  if (this.settingsManager.getCollapseChangelog()) {
480
468
  const versionMatch = this.changelogMarkdown.match(/##\s+\[?(\d+\.\d+\.\d+)\]?/);
481
469
  const latestVersion = versionMatch ? versionMatch[1] : this.version;
@@ -489,7 +477,7 @@ export class InteractiveMode {
489
477
  );
490
478
  this.headerContainer.addChild(new Spacer(1));
491
479
  }
492
- this.headerContainer.addChild(new DynamicBorder());
480
+ this.headerContainer.addChild(new DynamicBorder((text) => theme.fg("borderAccent", text)));
493
481
  }
494
482
  } else {
495
483
  // Minimal header when silenced
@@ -2961,6 +2949,7 @@ export class InteractiveMode {
2961
2949
  autoCompactThresholdPercent: this.settingsManager.getCompactionThresholdPercent(),
2962
2950
  classifierModel: this.settingsManager.getClassifierModel() ?? "default",
2963
2951
  budgetSubagentModel: this.settingsManager.getBudgetSubagentModel() ?? "default",
2952
+ planModeReasoningModel: this.settingsManager.getPlanModeReasoningModel() ?? "default",
2964
2953
  showImages: this.settingsManager.getShowImages(),
2965
2954
  autoResizeImages: this.settingsManager.getImageAutoResize(),
2966
2955
  blockImages: this.settingsManager.getBlockImages(),
@@ -2973,7 +2962,9 @@ export class InteractiveMode {
2973
2962
  thinkingLevel: this.session.thinkingLevel,
2974
2963
  availableThinkingLevels: this.session.getAvailableThinkingLevels(),
2975
2964
  currentTheme: this.settingsManager.getTheme() || "dark",
2965
+ currentThemeAccent: this.settingsManager.getThemeAccent() || "default",
2976
2966
  availableThemes: getAvailableThemes(),
2967
+ availableThemeAccents: getAvailableThemeAccents(),
2977
2968
  hideThinkingBlock: this.hideThinkingBlock,
2978
2969
  collapseChangelog: this.settingsManager.getCollapseChangelog(),
2979
2970
  doubleEscapeAction: this.settingsManager.getDoubleEscapeAction(),
@@ -3007,6 +2998,16 @@ export class InteractiveMode {
3007
2998
  (model) => submenuDone(`${model.provider}/${model.id}`),
3008
2999
  () => submenuDone(),
3009
3000
  ),
3001
+ planModeReasoningModelSubmenu: (_currentValue, submenuDone) =>
3002
+ new ModelSelectorComponent(
3003
+ this.ui,
3004
+ undefined,
3005
+ this.settingsManager,
3006
+ this.session.modelRegistry,
3007
+ [],
3008
+ (model) => submenuDone(`${model.provider}/${model.id}`),
3009
+ () => submenuDone(),
3010
+ ),
3010
3011
  },
3011
3012
  {
3012
3013
  onAutoCompactChange: (enabled) => {
@@ -3027,6 +3028,12 @@ export class InteractiveMode {
3027
3028
  `Budget subagent model: ${modelRef === "default" ? "use current/default model" : modelRef}`,
3028
3029
  );
3029
3030
  },
3031
+ onPlanModeReasoningModelChange: (modelRef) => {
3032
+ this.settingsManager.setPlanModeReasoningModel(modelRef === "default" ? undefined : modelRef);
3033
+ this.showStatus(
3034
+ `Plan reasoning model: ${modelRef === "default" ? "use current model" : modelRef}`,
3035
+ );
3036
+ },
3030
3037
  onShowImagesChange: (enabled) => {
3031
3038
  this.settingsManager.setShowImages(enabled);
3032
3039
  for (const child of this.chatContainer.children) {
@@ -3073,16 +3080,32 @@ export class InteractiveMode {
3073
3080
  this.updateEditorBorderColor();
3074
3081
  },
3075
3082
  onThemeChange: (themeName) => {
3076
- const result = setTheme(themeName, true);
3083
+ const result = setTheme(themeName, true, this.settingsManager.getThemeAccent());
3077
3084
  this.settingsManager.setTheme(themeName);
3085
+ this.updateEditorBorderColor();
3078
3086
  this.ui.invalidate();
3079
3087
  if (!result.success) {
3080
3088
  this.showError(`Failed to load theme "${themeName}": ${result.error}\nFell back to dark theme.`);
3081
3089
  }
3082
3090
  },
3091
+ onThemeAccentChange: (accent) => {
3092
+ this.settingsManager.setThemeAccent(accent === "default" ? undefined : accent);
3093
+ const result = setTheme(
3094
+ this.settingsManager.getTheme() || "dark",
3095
+ true,
3096
+ this.settingsManager.getThemeAccent(),
3097
+ );
3098
+ this.updateEditorBorderColor();
3099
+ this.ui.invalidate();
3100
+ this.ui.requestRender();
3101
+ if (!result.success) {
3102
+ this.showError(`Failed to apply theme accent "${accent}": ${result.error}`);
3103
+ }
3104
+ },
3083
3105
  onThemePreview: (themeName) => {
3084
- const result = setTheme(themeName, true);
3106
+ const result = setTheme(themeName, true, this.settingsManager.getThemeAccent());
3085
3107
  if (result.success) {
3108
+ this.updateEditorBorderColor();
3086
3109
  this.ui.invalidate();
3087
3110
  this.ui.requestRender();
3088
3111
  }
@@ -3785,7 +3808,10 @@ export class InteractiveMode {
3785
3808
  setRegisteredThemes(this.session.resourceLoader.getThemes().themes);
3786
3809
  this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();
3787
3810
  const themeName = this.settingsManager.getTheme();
3788
- const themeResult = themeName ? setTheme(themeName, true) : { success: true };
3811
+ const themeResult = themeName
3812
+ ? setTheme(themeName, true, this.settingsManager.getThemeAccent())
3813
+ : { success: true };
3814
+ this.updateEditorBorderColor();
3789
3815
  if (!themeResult.success) {
3790
3816
  this.showError(`Failed to load theme "${themeName}": ${themeResult.error}\nFell back to dark theme.`);
3791
3817
  }