@pencil-agent/nano-pencil 1.14.1 → 1.14.2

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 (126) hide show
  1. package/dist/build-meta.json +3 -3
  2. package/dist/builtin-extensions.d.ts +13 -1
  3. package/dist/builtin-extensions.js +36 -23
  4. package/dist/core/config/settings-manager.d.ts +6 -0
  5. package/dist/core/config/settings-manager.js +21 -0
  6. package/dist/core/extensions/runner.d.ts +1 -0
  7. package/dist/core/extensions/runner.js +3 -0
  8. package/dist/core/extensions/types.d.ts +10 -6
  9. package/dist/core/i18n/slash-commands.js +1 -1
  10. package/dist/core/i18n/slash-commands.zh.js +1 -1
  11. package/dist/core/model-registry.d.ts +2 -2
  12. package/dist/core/model-registry.js +6 -5
  13. package/dist/core/runtime/agent-session.d.ts +1 -1
  14. package/dist/core/runtime/extension-core-bindings.js +1 -0
  15. package/dist/core/runtime/sdk.js +1 -0
  16. package/dist/extensions/defaults/AGENT.md +32 -9
  17. package/dist/extensions/defaults/btw/index.js +8 -1
  18. package/dist/extensions/defaults/discipline/index.d.ts +8 -0
  19. package/dist/extensions/defaults/discipline/index.js +117 -0
  20. package/dist/extensions/defaults/discipline/skills/brainstorming/SKILL.md +33 -0
  21. package/dist/extensions/defaults/discipline/skills/executing-plans/SKILL.md +25 -0
  22. package/dist/extensions/defaults/discipline/skills/finishing-development-branch/SKILL.md +25 -0
  23. package/dist/extensions/defaults/discipline/skills/receiving-code-review/SKILL.md +22 -0
  24. package/dist/extensions/defaults/discipline/skills/requesting-code-review/SKILL.md +31 -0
  25. package/dist/extensions/defaults/discipline/skills/systematic-debugging/SKILL.md +28 -0
  26. package/dist/extensions/defaults/discipline/skills/test-driven-development/SKILL.md +32 -0
  27. package/dist/extensions/defaults/discipline/skills/using-git-worktrees/SKILL.md +25 -0
  28. package/dist/extensions/defaults/discipline/skills/verification-before-completion/SKILL.md +27 -0
  29. package/dist/extensions/defaults/discipline/skills/writing-plans/SKILL.md +26 -0
  30. package/dist/extensions/defaults/grub/README.md +9 -4
  31. package/dist/extensions/defaults/grub/grub-controller.d.ts +14 -2
  32. package/dist/extensions/defaults/grub/grub-controller.js +102 -76
  33. package/dist/extensions/defaults/grub/grub-decision.d.ts +8 -0
  34. package/dist/extensions/defaults/grub/grub-decision.js +42 -0
  35. package/dist/extensions/defaults/grub/grub-feature-list.d.ts +1 -0
  36. package/dist/extensions/defaults/grub/grub-feature-list.js +8 -3
  37. package/dist/extensions/defaults/grub/grub-format.d.ts +13 -0
  38. package/dist/extensions/defaults/grub/grub-format.js +87 -0
  39. package/dist/extensions/defaults/grub/grub-harness.d.ts +9 -0
  40. package/dist/extensions/defaults/grub/grub-harness.js +71 -0
  41. package/dist/extensions/defaults/grub/grub-i18n.d.ts +50 -12
  42. package/dist/extensions/defaults/grub/grub-i18n.js +86 -55
  43. package/dist/extensions/defaults/grub/grub-parser.js +58 -36
  44. package/dist/extensions/defaults/grub/grub-persistence.js +75 -10
  45. package/dist/extensions/defaults/grub/grub-prompts.d.ts +12 -0
  46. package/dist/extensions/defaults/grub/grub-prompts.js +155 -0
  47. package/dist/extensions/defaults/grub/grub-turn.d.ts +16 -0
  48. package/dist/extensions/defaults/grub/grub-turn.js +61 -0
  49. package/dist/extensions/defaults/grub/grub-types.d.ts +1 -0
  50. package/dist/extensions/defaults/grub/index.d.ts +1 -1
  51. package/dist/extensions/defaults/grub/index.js +11 -314
  52. package/dist/extensions/defaults/idle-think/idle-think-runtime.d.ts +46 -0
  53. package/dist/extensions/defaults/idle-think/idle-think-runtime.js +148 -0
  54. package/dist/extensions/defaults/idle-think/index.d.ts +1 -1
  55. package/dist/extensions/defaults/idle-think/index.js +5 -130
  56. package/dist/extensions/defaults/idle-think/insights.d.ts +10 -23
  57. package/dist/extensions/defaults/idle-think/insights.js +52 -44
  58. package/dist/extensions/defaults/interview/index.d.ts +2 -2
  59. package/dist/extensions/defaults/interview/index.js +3 -570
  60. package/dist/extensions/defaults/interview/interview-runtime.d.ts +55 -0
  61. package/dist/extensions/defaults/interview/interview-runtime.js +551 -0
  62. package/dist/extensions/defaults/presence/index.d.ts +3 -47
  63. package/dist/extensions/defaults/presence/index.js +27 -179
  64. package/dist/extensions/defaults/presence/presence-memory.d.ts +46 -0
  65. package/dist/extensions/defaults/presence/presence-memory.js +167 -0
  66. package/dist/extensions/defaults/recap/index.js +6 -1
  67. package/dist/extensions/defaults/sal/index.d.ts +2 -37
  68. package/dist/extensions/defaults/sal/index.js +9 -371
  69. package/dist/extensions/defaults/sal/sal-config.d.ts +41 -0
  70. package/dist/extensions/defaults/sal/sal-config.js +166 -0
  71. package/dist/extensions/defaults/sal/sal-context.d.ts +11 -0
  72. package/dist/extensions/defaults/sal/sal-context.js +94 -0
  73. package/dist/extensions/defaults/sal/sal-runtime.d.ts +70 -0
  74. package/dist/extensions/defaults/sal/sal-runtime.js +7 -0
  75. package/dist/extensions/defaults/sal/sal-trace.d.ts +11 -0
  76. package/dist/extensions/defaults/sal/sal-trace.js +129 -0
  77. package/dist/extensions/defaults/security-audit/index.d.ts +1 -1
  78. package/dist/extensions/defaults/security-audit/index.js +15 -87
  79. package/dist/extensions/defaults/team/AGENT.md +3 -1
  80. package/dist/extensions/defaults/team/index.js +6 -283
  81. package/dist/extensions/defaults/team/team-runtime-helpers.d.ts +48 -0
  82. package/dist/extensions/defaults/team/team-runtime-helpers.js +324 -0
  83. package/dist/extensions/defaults/team/team-runtime.d.ts +2 -66
  84. package/dist/extensions/defaults/team/team-runtime.js +39 -391
  85. package/dist/extensions/defaults/team/team-ui.d.ts +50 -0
  86. package/dist/extensions/defaults/team/team-ui.js +280 -0
  87. package/dist/extensions/optional/export-html/index.js +0 -8
  88. package/dist/extensions/optional/simplify/index.d.ts +21 -0
  89. package/dist/extensions/optional/simplify/index.js +44 -20
  90. package/dist/modes/acp/acp-mode.js +4 -4
  91. package/dist/modes/interactive/components/settings-selector.d.ts +4 -0
  92. package/dist/modes/interactive/components/settings-selector.js +10 -0
  93. package/dist/modes/interactive/interactive-mode.js +11 -3
  94. package/dist/modes/rpc/rpc-client.d.ts +1 -1
  95. package/dist/modes/rpc/rpc-types.d.ts +1 -1
  96. package/dist/node_modules/@pencil-agent/agent-core/agent.d.ts +1 -1
  97. package/dist/node_modules/@pencil-agent/agent-core/agent.js +2 -2
  98. package/dist/node_modules/@pencil-agent/agent-core/claude-agent-loop.d.ts +15 -0
  99. package/dist/node_modules/@pencil-agent/agent-core/claude-agent-loop.js +342 -0
  100. package/dist/node_modules/@pencil-agent/agent-core/claude-tool-orchestration.d.ts +23 -0
  101. package/dist/node_modules/@pencil-agent/agent-core/claude-tool-orchestration.js +220 -0
  102. package/dist/node_modules/@pencil-agent/agent-core/types.d.ts +8 -8
  103. package/dist/node_modules/@pencil-agent/agent-core/types.js +4 -4
  104. package/dist/node_modules/@pencil-agent/ai/cli.js +0 -0
  105. package/dist/node_modules/@pencil-agent/ai/models.generated.d.ts +7 -24
  106. package/dist/node_modules/@pencil-agent/ai/models.generated.js +52 -69
  107. package/dist/node_modules/@pencil-agent/ai/types.d.ts +3 -3
  108. package/dist/node_modules/@pencil-agent/tui/tui.js +4 -2
  109. package/dist/packages/mem-core/engine-archive.js +19 -17
  110. package/dist/packages/mem-core/engine.d.ts +0 -2
  111. package/dist/packages/mem-core/engine.js +2 -117
  112. package/dist/packages/mem-core/src/store.d.ts +21 -0
  113. package/dist/packages/mem-core/src/store.js +120 -0
  114. package/dist/packages/mem-core/src/types.d.ts +329 -0
  115. package/dist/packages/mem-core/src/types.js +7 -0
  116. package/dist/packages/mem-core/store.js +15 -1
  117. package/docs/agent-loop-frameworks.md +14 -14
  118. package/docs/loop /351/207/215/346/236/204/345/256/214/346/210/220/346/200/273/347/273/223.md" +251 -0
  119. package/docs/loop /351/207/215/346/236/204/345/256/214/346/210/220/346/212/245/345/221/212.md" +123 -0
  120. package/docs/loop /351/207/215/346/236/204/346/226/271/346/241/210.md" +1222 -0
  121. package/docs/loop /351/207/215/346/236/204/346/226/271/346/241/210/345/256/236/347/216/260/346/212/245/345/221/212.md" +158 -0
  122. package/docs/loop /351/207/215/346/236/204/346/226/271/346/241/210/345/257/271/346/257/224/345/210/206/346/236/220.md" +128 -0
  123. package/docs/loop /351/207/215/346/236/204/350/256/241/345/210/222.md" +321 -0
  124. package/docs/loop-usage-examples.md +215 -0
  125. package/docs/planmode.md +1987 -0
  126. package/package.json +8 -3
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "1.14.1",
3
- "commitHash": "b4f6f24",
2
+ "version": "1.14.2",
3
+ "commitHash": "62cd264",
4
4
  "branch": "main",
5
- "builtAt": "2026-05-23T15:05:06.541Z"
5
+ "builtAt": "2026-05-26T18:24:58.388Z"
6
6
  }
@@ -4,6 +4,18 @@
4
4
  * [TO]: Consumed by main.ts, test files
5
5
  * [HERE]: builtin-extensions.ts - built-in extension registry for NanoPencil
6
6
  */
7
+ export type BuiltinExtensionRiskLevel = "passive" | "command" | "tool" | "background" | "write-capable";
8
+ export interface BuiltinExtension {
9
+ id: string;
10
+ category: "default" | "optional" | "package";
11
+ defaultEnabled: boolean;
12
+ riskLevel: BuiltinExtensionRiskLevel;
13
+ requiresUI: boolean;
14
+ startsTimers: boolean;
15
+ writesWorkspace: boolean;
16
+ externalProcess: boolean;
17
+ }
18
+ export declare const builtInExtensions: readonly BuiltinExtension[];
7
19
  /**
8
20
  * Get the list of built-in extension paths that NanoPencil loads by default
9
21
  *
@@ -14,7 +26,7 @@
14
26
  * - SecurityAudit (security audit)
15
27
  * - MCP (MCP protocol adapter)
16
28
  *
17
- * Optional extensions need to be enabled via configuration:
29
+ * Optional extensions need to be enabled via configuration or --extension:
18
30
  * - Simplify (code simplification) - extensions/optional/simplify/
19
31
  * - export-html (HTML export) - extensions/optional/export-html/
20
32
  */
@@ -12,7 +12,6 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
12
12
  const require = createRequire(import.meta.url);
13
13
  /** Built-in extension paths */
14
14
  const BUNDLED_NANOMEM_EXTENSION_PACKAGES = join(__dirname, "packages", "mem-core", "extension.js");
15
- const BUNDLED_SIMPLIFY_EXTENSION = join(__dirname, "extensions", "optional", "simplify", "index.js");
16
15
  const BUNDLED_LINK_WORLD_EXTENSION = join(__dirname, "extensions", "defaults", "link-world", "index.js");
17
16
  const BUNDLED_BROWSER_EXTENSION = join(__dirname, "extensions", "defaults", "browser", "index.js");
18
17
  const BUNDLED_SECURITY_AUDIT_EXTENSION = join(__dirname, "extensions", "defaults", "security-audit", "index.js");
@@ -21,6 +20,7 @@ const BUNDLED_PRESENCE_EXTENSION = join(__dirname, "extensions", "defaults", "pr
21
20
  const BUNDLED_INTERVIEW_EXTENSION = join(__dirname, "extensions", "defaults", "interview", "index.js");
22
21
  const BUNDLED_LOOP_EXTENSION = join(__dirname, "extensions", "defaults", "loop", "index.js");
23
22
  const BUNDLED_PLAN_EXTENSION = join(__dirname, "extensions", "defaults", "plan", "index.js");
23
+ const BUNDLED_DISCIPLINE_EXTENSION = join(__dirname, "extensions", "defaults", "discipline", "index.js");
24
24
  const BUNDLED_DIAGNOSTICS_EXTENSION = join(__dirname, "extensions", "defaults", "diagnostics", "index.js");
25
25
  const BUNDLED_SAL_EXTENSION = join(__dirname, "extensions", "defaults", "sal", "index.js");
26
26
  const BUNDLED_TOKEN_SAVE_EXTENSION = join(__dirname, "extensions", "defaults", "token-save", "index.js");
@@ -32,7 +32,31 @@ const BUNDLED_BTW_EXTENSION = join(__dirname, "extensions", "defaults", "btw", "
32
32
  const BUNDLED_RECAP_EXTENSION = join(__dirname, "extensions", "defaults", "recap", "index.js");
33
33
  const BUNDLED_DEBUG_EXTENSION = join(__dirname, "extensions", "defaults", "debug", "index.js");
34
34
  const BUNDLED_MCP_EXTENSION = join(__dirname, "extensions", "defaults", "mcp", "index.js");
35
- const BUNDLED_EXPORT_HTML_EXTENSION = join(__dirname, "extensions", "optional", "export-html", "index.js");
35
+ export const builtInExtensions = [
36
+ { id: "diagnostics", category: "default", defaultEnabled: true, riskLevel: "background", requiresUI: false, startsTimers: true, writesWorkspace: false, externalProcess: false },
37
+ { id: "sal", category: "default", defaultEnabled: true, riskLevel: "background", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: false },
38
+ { id: "token-save", category: "default", defaultEnabled: true, riskLevel: "tool", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: false },
39
+ { id: "nanomem", category: "package", defaultEnabled: true, riskLevel: "background", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: false },
40
+ { id: "link-world", category: "default", defaultEnabled: true, riskLevel: "tool", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: true },
41
+ { id: "browser", category: "default", defaultEnabled: true, riskLevel: "tool", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: true },
42
+ { id: "security-audit", category: "default", defaultEnabled: true, riskLevel: "tool", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: false },
43
+ { id: "soul", category: "default", defaultEnabled: true, riskLevel: "background", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: false },
44
+ { id: "presence", category: "default", defaultEnabled: true, riskLevel: "background", requiresUI: true, startsTimers: true, writesWorkspace: false, externalProcess: false },
45
+ { id: "interview", category: "default", defaultEnabled: true, riskLevel: "tool", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: false },
46
+ { id: "grub", category: "default", defaultEnabled: true, riskLevel: "background", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: true },
47
+ { id: "loop", category: "default", defaultEnabled: true, riskLevel: "background", requiresUI: false, startsTimers: true, writesWorkspace: false, externalProcess: false },
48
+ { id: "plan", category: "default", defaultEnabled: true, riskLevel: "tool", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: false },
49
+ { id: "discipline", category: "default", defaultEnabled: true, riskLevel: "tool", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: false },
50
+ { id: "subagent", category: "default", defaultEnabled: true, riskLevel: "tool", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: true },
51
+ { id: "team", category: "default", defaultEnabled: true, riskLevel: "background", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: true },
52
+ { id: "idle-think", category: "default", defaultEnabled: true, riskLevel: "background", requiresUI: true, startsTimers: true, writesWorkspace: false, externalProcess: true },
53
+ { id: "btw", category: "default", defaultEnabled: true, riskLevel: "command", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: false },
54
+ { id: "recap", category: "default", defaultEnabled: true, riskLevel: "command", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: false },
55
+ { id: "debug", category: "default", defaultEnabled: true, riskLevel: "command", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: false },
56
+ { id: "mcp", category: "default", defaultEnabled: true, riskLevel: "command", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: true },
57
+ { id: "simplify", category: "optional", defaultEnabled: false, riskLevel: "write-capable", requiresUI: false, startsTimers: false, writesWorkspace: true, externalProcess: true },
58
+ { id: "export-html", category: "optional", defaultEnabled: false, riskLevel: "write-capable", requiresUI: false, startsTimers: false, writesWorkspace: true, externalProcess: false },
59
+ ];
36
60
  /** Find package root from current module location (containing package.json with nano-pencil related name) */
37
61
  function findPackageRoot(startDir) {
38
62
  let dir = startDir;
@@ -66,7 +90,7 @@ function findPackageRoot(startDir) {
66
90
  * - SecurityAudit (security audit)
67
91
  * - MCP (MCP protocol adapter)
68
92
  *
69
- * Optional extensions need to be enabled via configuration:
93
+ * Optional extensions need to be enabled via configuration or --extension:
70
94
  * - Simplify (code simplification) - extensions/optional/simplify/
71
95
  * - export-html (HTML export) - extensions/optional/export-html/
72
96
  */
@@ -135,16 +159,6 @@ export function getBuiltinExtensionPaths() {
135
159
  }
136
160
  }
137
161
  }
138
- // === Simplify extension (optional source, compiled to dist/extensions/optional/simplify) ===
139
- if (existsSync(BUNDLED_SIMPLIFY_EXTENSION)) {
140
- paths.push(BUNDLED_SIMPLIFY_EXTENSION);
141
- }
142
- else {
143
- // Development mode: try .ts source file
144
- const simplifyTs = join(__dirname, "extensions", "optional", "simplify", "index.ts");
145
- if (existsSync(simplifyTs))
146
- paths.push(simplifyTs);
147
- }
148
162
  // === link-world extension (built-in source, compiled to dist/extensions/defaults/link-world) ===
149
163
  if (existsSync(BUNDLED_LINK_WORLD_EXTENSION)) {
150
164
  paths.push(BUNDLED_LINK_WORLD_EXTENSION);
@@ -226,7 +240,15 @@ export function getBuiltinExtensionPaths() {
226
240
  if (existsSync(planTs))
227
241
  paths.push(planTs);
228
242
  }
229
- // === MCP extension (MCP tool protocol adapter) ===
243
+ // === Discipline extension (default engineering workflow skills and bootstrap) ===
244
+ if (existsSync(BUNDLED_DISCIPLINE_EXTENSION)) {
245
+ paths.push(BUNDLED_DISCIPLINE_EXTENSION);
246
+ }
247
+ else {
248
+ const disciplineTs = join(__dirname, "extensions", "defaults", "discipline", "index.ts");
249
+ if (existsSync(disciplineTs))
250
+ paths.push(disciplineTs);
251
+ }
230
252
  // Built-in SubAgent extension
231
253
  if (existsSync(BUNDLED_SUBAGENT_EXTENSION)) {
232
254
  paths.push(BUNDLED_SUBAGENT_EXTENSION);
@@ -290,15 +312,6 @@ export function getBuiltinExtensionPaths() {
290
312
  if (existsSync(mcpTs))
291
313
  paths.push(mcpTs);
292
314
  }
293
- // === export-html extension (optional, HTML export functionality) ===
294
- if (existsSync(BUNDLED_EXPORT_HTML_EXTENSION)) {
295
- paths.push(BUNDLED_EXPORT_HTML_EXTENSION);
296
- }
297
- else {
298
- const exportHtmlTs = join(__dirname, "extensions", "optional", "export-html", "index.ts");
299
- if (existsSync(exportHtmlTs))
300
- paths.push(exportHtmlTs);
301
- }
302
315
  return paths;
303
316
  }
304
317
  /**
@@ -43,6 +43,9 @@ export interface MarkdownSettings {
43
43
  codeBlockIndent?: string;
44
44
  }
45
45
  export type TransportSetting = Transport;
46
+ export type AgentLoopFrameworkSetting = "standard" | "weak-model-compatible";
47
+ export type AgentLoopFrameworkSettingInput = AgentLoopFrameworkSetting | "high-intelligence" | "low-intelligence" | "structured-adaptive";
48
+ export declare function normalizeAgentLoopFrameworkSetting(value: AgentLoopFrameworkSettingInput | undefined): AgentLoopFrameworkSetting | undefined;
46
49
  /**
47
50
  * Package source for npm/git packages.
48
51
  * - String form: load all resources from the package
@@ -61,6 +64,7 @@ export interface Settings {
61
64
  defaultProvider?: string;
62
65
  defaultModel?: string;
63
66
  defaultThinkingLevel?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
67
+ agentLoopFramework?: AgentLoopFrameworkSettingInput;
64
68
  transport?: TransportSetting;
65
69
  steeringMode?: "all" | "one-at-a-time";
66
70
  followUpMode?: "all" | "one-at-a-time";
@@ -213,6 +217,8 @@ export declare class SettingsManager {
213
217
  setTheme(theme: string): void;
214
218
  getDefaultThinkingLevel(): "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | undefined;
215
219
  setDefaultThinkingLevel(level: "off" | "minimal" | "low" | "medium" | "high" | "xhigh"): void;
220
+ getAgentLoopFramework(): AgentLoopFrameworkSetting | undefined;
221
+ setAgentLoopFramework(framework: AgentLoopFrameworkSettingInput | undefined): void;
216
222
  getTransport(): TransportSetting;
217
223
  setTransport(transport: TransportSetting): void;
218
224
  getCompactionEnabled(): boolean;
@@ -4,6 +4,13 @@ import lockfile from "proper-lockfile";
4
4
  import { APP_NAME, CONFIG_DIR_NAME } from "../../config.js";
5
5
  import { defaultAgentDirContext } from "../agent-dir/agent-dir-context.js";
6
6
  import { readFile, writeFile, mkdir } from "node:fs/promises";
7
+ export function normalizeAgentLoopFrameworkSetting(value) {
8
+ if (value === "high-intelligence")
9
+ return "standard";
10
+ if (value === "low-intelligence" || value === "structured-adaptive")
11
+ return "weak-model-compatible";
12
+ return value;
13
+ }
7
14
  /** Deep merge settings: project/overrides take precedence, nested objects merge recursively */
8
15
  function deepMergeSettings(base, overrides) {
9
16
  const result = { ...base };
@@ -564,6 +571,20 @@ export class SettingsManager {
564
571
  this.markModified("defaultThinkingLevel");
565
572
  this.save();
566
573
  }
574
+ getAgentLoopFramework() {
575
+ return normalizeAgentLoopFrameworkSetting(this.settings.agentLoopFramework);
576
+ }
577
+ setAgentLoopFramework(framework) {
578
+ const normalized = normalizeAgentLoopFrameworkSetting(framework);
579
+ if (normalized === undefined) {
580
+ delete this.globalSettings.agentLoopFramework;
581
+ }
582
+ else {
583
+ this.globalSettings.agentLoopFramework = normalized;
584
+ }
585
+ this.markModified("agentLoopFramework");
586
+ this.save();
587
+ }
567
588
  getTransport() {
568
589
  return this.settings.transport ?? "sse";
569
590
  }
@@ -81,6 +81,7 @@ export declare class ExtensionRunner {
81
81
  private getSystemPromptFn;
82
82
  private getSoulManagerFn;
83
83
  private getSettingsFn;
84
+ private getSkillsFn;
84
85
  private newSessionHandler;
85
86
  private forkHandler;
86
87
  private navigateTreeHandler;
@@ -99,6 +99,7 @@ export class ExtensionRunner {
99
99
  getSystemPromptFn = () => "";
100
100
  getSoulManagerFn = () => undefined;
101
101
  getSettingsFn = () => ({});
102
+ getSkillsFn = () => [];
102
103
  newSessionHandler = async () => ({ cancelled: false });
103
104
  forkHandler = async () => ({ cancelled: false });
104
105
  navigateTreeHandler = async () => ({ cancelled: false });
@@ -175,6 +176,7 @@ export class ExtensionRunner {
175
176
  this.getSystemPromptFn = contextActions.getSystemPrompt;
176
177
  this.getSoulManagerFn = contextActions.getSoulManager;
177
178
  this.getSettingsFn = contextActions.getSettings;
179
+ this.getSkillsFn = contextActions.getSkills;
178
180
  // Process provider registrations queued during extension loading
179
181
  for (const { name, config } of this.runtime.pendingProviderRegistrations) {
180
182
  this.modelRegistry.registerProvider(name, config);
@@ -413,6 +415,7 @@ export class ExtensionRunner {
413
415
  getSystemPrompt: () => this.getSystemPromptFn(),
414
416
  getSoulManager: () => this.getSoulManagerFn(),
415
417
  getSettings: () => this.getSettingsFn(),
418
+ getSkills: () => this.getSkillsFn(),
416
419
  };
417
420
  }
418
421
  createCommandContext() {
@@ -18,6 +18,7 @@ import type { KeybindingsManager } from "../keybindings.js";
18
18
  import type { CustomMessage } from "../messages.js";
19
19
  import type { ModelRegistry } from "../model-registry.js";
20
20
  import type { BranchSummaryEntry, CompactionEntry, ReadonlySessionManager, SessionEntry, SessionManager } from "../session/session-manager.js";
21
+ import type { Skill } from "../skills.js";
21
22
  import type { SlashCommandInfo } from "../slash-commands.js";
22
23
  import type { BashOperations } from "../tools/bash.js";
23
24
  import type { EditToolDetails } from "../tools/edit.js";
@@ -232,6 +233,8 @@ export interface ExtensionContext {
232
233
  getSoulManager(): unknown | undefined;
233
234
  /** Get current merged settings (project overrides global). */
234
235
  getSettings(): import("../config/settings-manager.js").Settings;
236
+ /** Get currently loaded skills after user/project/default resource precedence is applied. */
237
+ getSkills(): readonly Skill[];
235
238
  }
236
239
  /**
237
240
  * Extended context for command handlers.
@@ -294,7 +297,7 @@ export interface ToolDefinition<TParams extends TSchema = TSchema, TDetails = un
294
297
  interruptBehavior?: "cancel" | "block";
295
298
  /** Optional semantic validation after schema validation and before execute. */
296
299
  validateInput?: (params: Static<TParams>) => void | string | Promise<void | string>;
297
- /** Optional maximum text result size enforced by low-intelligence-adaptation tool orchestration. */
300
+ /** Optional maximum text result size enforced by weak-model-compatible tool orchestration. */
298
301
  maxResultSizeChars?: number;
299
302
  /** Usage guidance for system prompt (optional) */
300
303
  guidance?: string;
@@ -802,14 +805,14 @@ export interface ExtensionAPI {
802
805
  * api: "anthropic-messages",
803
806
  * models: [
804
807
  * {
805
- * id: "high-intelligence-model",
806
- * name: "High Intelligence Model (proxy)",
808
+ * id: "example-model",
809
+ * name: "Example Model (proxy)",
807
810
  * reasoning: false,
808
811
  * input: ["text", "image"],
809
812
  * cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
810
813
  * contextWindow: 200000,
811
814
  * maxTokens: 16384,
812
- * agentLoopFramework: "low-intelligence"
815
+ * agentLoopFramework: "weak-model-compatible"
813
816
  * }
814
817
  * ]
815
818
  * });
@@ -870,9 +873,9 @@ export interface ProviderConfig {
870
873
  }
871
874
  /** Configuration for a model within a provider. */
872
875
  export interface ProviderModelConfig {
873
- /** Model ID (e.g., "high-intelligence-model"). */
876
+ /** Model ID (e.g., "example-model"). */
874
877
  id: string;
875
- /** Display name (e.g., "High Intelligence Model"). */
878
+ /** Display name (e.g., "Example Model"). */
876
879
  name: string;
877
880
  /** API type override for this model. */
878
881
  api?: Api;
@@ -994,6 +997,7 @@ export interface ExtensionContextActions {
994
997
  getSystemPrompt: () => string;
995
998
  getSoulManager: () => unknown | undefined;
996
999
  getSettings: () => import("../config/settings-manager.js").Settings;
1000
+ getSkills: () => readonly Skill[];
997
1001
  }
998
1002
  /**
999
1003
  * Actions for ExtensionCommandContext (ctx.* in command handlers).
@@ -7,7 +7,7 @@
7
7
  export const slashCommands = {
8
8
  settings: "Open settings menu",
9
9
  model: "Select model (opens selector UI)",
10
- "agent-loop": "Set high/low-intelligence agent loop adaptation for this session",
10
+ "agent-loop": "Set standard or weak-model-compatible agent loop for this session",
11
11
  "scoped-models": "Enable/disable models for Ctrl+P cycling",
12
12
  apikey: "Update API key for current provider",
13
13
  mcp: "Manage MCP servers (list, enable, disable)",
@@ -7,7 +7,7 @@
7
7
  export const slashCommands = {
8
8
  settings: "打开设置菜单",
9
9
  model: "选择模型(打开选择器界面)",
10
- "agent-loop": "设置本会话的高智能/低智能 agent loop 适配",
10
+ "agent-loop": "设置本会话的 standard/弱模型兼容 agent loop",
11
11
  "scoped-models": "启用/禁用 Ctrl+P 循环的模型",
12
12
  apikey: "更新当前提供商的 API 密钥",
13
13
  mcp: "管理 MCP 服务器(列出、启用、禁用)",
@@ -7,8 +7,8 @@
7
7
  import { type Api, type AssistantMessageEventStream, type Context, type Model, type OAuthProviderInterface, type SimpleStreamOptions } from "@pencil-agent/ai";
8
8
  import type { AuthStorage } from "./config/auth-storage.js";
9
9
  import { clearConfigValueCache } from "./config/resolve-config-value.js";
10
- type AgentLoopFramework = "high-intelligence" | "low-intelligence";
11
- type AgentLoopFrameworkInput = AgentLoopFramework | "standard" | "structured-adaptive";
10
+ type AgentLoopFramework = "standard" | "weak-model-compatible";
11
+ type AgentLoopFrameworkInput = AgentLoopFramework | "high-intelligence" | "low-intelligence" | "structured-adaptive";
12
12
  /** Clear the config value command cache. Exported for testing. */
13
13
  export declare const clearApiKeyCache: typeof clearConfigValueCache;
14
14
  /**
@@ -42,9 +42,10 @@ const OpenAIResponsesCompatSchema = Type.Object({
42
42
  });
43
43
  const OpenAICompatSchema = Type.Union([OpenAICompletionsCompatSchema, OpenAIResponsesCompatSchema]);
44
44
  const AgentLoopFrameworkSchema = Type.Union([
45
+ Type.Literal("standard"),
46
+ Type.Literal("weak-model-compatible"),
45
47
  Type.Literal("high-intelligence"),
46
48
  Type.Literal("low-intelligence"),
47
- Type.Literal("standard"),
48
49
  Type.Literal("structured-adaptive"),
49
50
  ]);
50
51
  // Schema for custom model definition
@@ -85,10 +86,10 @@ const ModelOverrideSchema = Type.Object({
85
86
  compat: Type.Optional(OpenAICompatSchema),
86
87
  });
87
88
  function normalizeAgentLoopFramework(value) {
88
- if (value === "standard")
89
- return "high-intelligence";
90
- if (value === "structured-adaptive")
91
- return "low-intelligence";
89
+ if (value === "high-intelligence")
90
+ return "standard";
91
+ if (value === "low-intelligence" || value === "structured-adaptive")
92
+ return "weak-model-compatible";
92
93
  return value;
93
94
  }
94
95
  const ProviderConfigSchema = Type.Object({
@@ -24,7 +24,7 @@ import { AgentDirContext } from "../agent-dir/agent-dir-context.js";
24
24
  import type { BashOperations } from "../tools/bash.js";
25
25
  import { type SessionSlashCommandDescriptor } from "./slash-command-catalog.js";
26
26
  export type { SessionSlashCommandDescriptor } from "./slash-command-catalog.js";
27
- type AgentLoopFrameworkInput = AgentLoopFramework | "standard" | "structured-adaptive";
27
+ type AgentLoopFrameworkInput = AgentLoopFramework | "high-intelligence" | "low-intelligence" | "structured-adaptive";
28
28
  /** Parsed skill block from a user message */
29
29
  export interface ParsedSkillBlock {
30
30
  name: string;
@@ -173,5 +173,6 @@ export function bindExtensionCore(runner, host) {
173
173
  },
174
174
  getSystemPrompt: () => host.systemPrompt,
175
175
  getSoulManager: () => host.soulManager,
176
+ getSkills: () => host.resourceLoader.getSkills().skills,
176
177
  });
177
178
  }
@@ -247,6 +247,7 @@ export async function createAgentSession(options = {}) {
247
247
  steeringMode: settingsManager.getSteeringMode(),
248
248
  followUpMode: settingsManager.getFollowUpMode(),
249
249
  transport: settingsManager.getTransport(),
250
+ agentLoopFramework: settingsManager.getAgentLoopFramework(),
250
251
  thinkingBudgets: settingsManager.getThinkingBudgets(),
251
252
  maxRetryDelayMs: settingsManager.getRetrySettings().maxDelayMs,
252
253
  getApiKey: async (provider) => {
@@ -14,12 +14,20 @@ browser/install.md: Browser Harness setup and troubleshooting instructions, expo
14
14
  browser/src/browser_harness/: Vendored Browser Harness Python package, CDP daemon, IPC bridge, admin commands, and helper functions
15
15
  browser/interaction-skills/: Reusable Browser Harness mechanics guides for browser interactions
16
16
  browser/agent-workspace/: Seed workspace copied to .nanopencil/browser-workspace for editable helpers and domain skills
17
+ discipline/index.ts: Engineering discipline extension entry, registers skill tool, default workflow skills, and lightweight before_agent_start bootstrap prompt
18
+ discipline/skills/: Built-in engineering workflow skills for brainstorming, debugging, TDD, verification, planning, code review, worktrees, and branch finishing
19
+ idle-think/index.ts: IdleThink extension entry, session lifecycle registration, activity tracking, and persistent insight prompt injection
20
+ idle-think/idle-think-runtime.ts: IdleThink runtime boundary - state, budget reset, interval ownership, abort cleanup, exploration orchestration, insight persistence, and diagnostic reporting
21
+ idle-think/thinker.ts: IdleThink read-only SubAgent exploration runner, project context collection, network capability detection, and exploration prompt construction
22
+ idle-think/insights.ts: IdleThink nanomem-backed project-scoped insight storage and system prompt injection
23
+ idle-think/curiosity.ts: IdleThink curiosity queue persistence, topic selection, dedupe, and explored-topic pruning
17
24
  link-world/index.ts: Internet access integration entry, registers link_world_admin/link_world_exec/web_search/web_fetch tools, /link-world status/doctor/version/install commands, and bundled internet-search resources
18
25
  link-world/link-world-agent.md: Agent-facing skill that tells models to prefer web_search/web_fetch and link_world_admin/link_world_exec over bash for internet tasks
19
26
  link-world/network-routing.md: Routing skill that tells models when to use web_search/web_fetch/link-world versus browser automation
20
27
  link-world/agent-workspace/: Seed workspace copied to .nanopencil/link-world-workspace for project-local domain skills and notes
21
28
  mcp/index.ts: MCP protocol integration extension, MCP guidance resources
22
- presence/index.ts: AI-driven opening + idle presence lines, uses NanoMemEngine episodes/preferences/lessons + git/cwd snapshot, injects latest line into agent systemPrompt every turn for main-conversation perception, 30s debounce + idle in-flight lock, configurable via settings.presence.enabled, PRESENCE_MESSAGE_TYPE renderer
29
+ presence/index.ts: AI-driven opening + idle presence lines, git/cwd snapshot, systemPrompt injection of recent presence lines, timers/debounce/idle in-flight lock, settings.presence.enabled guard, PRESENCE_MESSAGE_TYPE renderer
30
+ presence/presence-memory.ts: Presence memory boundary - NanoMem directory/project discovery, memory-derived locale detection, randomized preference/lesson highlight selection for greeting prompts
23
31
  plan/index.ts: Plan Mode extension entry, /plan /plan:validate /plan:approve commands, EnterPlanMode/ExitPlanMode tools, permission gating, TUI status/widget, workflow prompt injection
24
32
  plan/types.ts: Plan mode types, persisted state payload, attachment variants, permission result model
25
33
  plan/plan-file-manager.ts: Plan file path management, slug generation, settings-aware plans directory, plan state hydration/serialization, resume/fork copy helpers
@@ -34,24 +42,37 @@ subagent/index.ts: SubAgent extension entry, /subagent:/subagent:run/:stop/:stat
34
42
  subagent/subagent-parser.ts: SubAgent command parsing, parseSubAgentCommand/buildSubAgentHelp
35
43
  subagent/subagent-runner.ts: SubAgent orchestration — research (read-only) and implement (isolated worktree) roles, diff preview and apply flow
36
44
  subagent/subagent-types.ts: SubAgent extension types — SubAgentPhase, SubAgentWorkerInfo, SubAgentRunState, SubAgentRunReport
37
- interview/index.ts: Requirement clarification extension, /interview command, lightweight before_agent_start hook
45
+ interview/index.ts: Requirement clarification extension entry, /interview and /grill-me commands, interview tool registration, custom message renderers, lightweight before_agent_start hook
46
+ interview/interview-runtime.ts: Interview probe/runtime boundary - synchronous prompt heuristics, workspace context collection, LLM probe coercion, UI follow-up loop, refined intent injection text
38
47
  security-audit/interface.ts: Security audit interface, SecurityCheckResult/AuditEvent/SecurityEngine
39
48
  security-audit/index.ts: Security extension entry, audit logging and dangerous pattern detection
40
49
  security-audit/engine/interceptor.ts: Request/response interception, InterceptorResult confirmation flow
41
50
  security-audit/engine/logger.ts: Security event logging, JSON file audit trail
42
51
  security-audit/engine/detector.ts: Vulnerability detection, pattern matching for dangerous commands
43
52
  soul/index.ts: AI personality evolution extension, persistent personality across sessions
44
- grub/index.ts: Grub extension entry - autonomous iterative task runner extracted from legacy loop, /grub command + GRUB_MESSAGE_TYPE renderer
45
- grub/grub-controller.ts: GrubController - drives autonomous grub iterations, state machine for LoopTaskState
53
+ grub/index.ts: Grub extension entry - autonomous iterative task runner, /grub command, dual-phase prompt injection, feature-list guard dispatch, GRUB_MESSAGE_TYPE renderer
54
+ grub/grub-controller.ts: GrubController - drives autonomous grub iterations, durable GrubTaskState, initializer baseline capture, feature-list mutation validation
55
+ grub/grub-decision.ts: Grub assistant protocol parser, extracts validated loop-state decisions from assistant text
46
56
  grub/grub-parser.ts: Grub command parsing, parseGrubCommand/buildGrubHelp
47
- grub/grub-types.ts: Grub types, GrubStatus/GrubDecisionStatus/GrubDecision/GrubTaskState/GrubTaskSnapshot
48
- grub/README.md: Grub extension documentation - autonomous "keep digging until done" runner
57
+ grub/grub-prompts.ts: Grub prompt construction boundary, initializer/coding system prompts and per-task dispatch prompts
58
+ grub/grub-harness.ts: Grub harness artifact boundary, .grub/<id>/ feature-list/progress-log/init.sh creation
59
+ grub/grub-format.ts: Grub user-facing status/result formatter for readable TUI messages
60
+ grub/grub-turn.ts: Grub turn-end coordinator, parsing assistant output, checklist gates, retry/terminal update events
61
+ grub/grub-i18n.ts: Grub localization helper, English/Chinese prompts and TUI strings
62
+ grub/grub-feature-list.ts: feature-list.json IO, initializer skeleton, legacy checklist migration, passes/evidence-only diff validation
63
+ grub/grub-persistence.ts: Cross-session .grub/<id>/state.json persistence, active task discovery, stale harness pruning
64
+ grub/grub-types.ts: Grub types, GrubStatus/GrubDecisionStatus/GrubDecision/GrubTaskState/GrubTaskSnapshot/FeatureList/PersistedGrubState
65
+ grub/README.md: Grub extension documentation - autonomous "keep digging until done" runner without default git commits
49
66
  loop/index.ts: Loop extension entry - session-scoped recurring prompt/command scheduler with pause/resume/run-now/max-runs/quiet, /loop command + LOOP_MESSAGE_TYPE renderer
50
67
  loop/scheduler-controller.ts: SchedulerController - in-memory recurring task store with pause/resume/run-now/max-runs, MAX_SCHEDULED_TASKS=50
51
68
  loop/scheduler-parser.ts: Loop command parsing with flags/subcommands, parseSchedulerCommand/parseDurationSpec/buildSchedulerHelp, --name/--max/--quiet
52
69
  loop/scheduler-types.ts: Scheduled loop types, LoopPayloadKind/ScheduledLoopTask/LoopStartSpec/ParsedSchedulerCommand
53
70
  loop/README.md: Loop extension documentation - recurring scheduler usage and flags
54
- sal/index.ts: SAL extension entry, enabled by default, registers --nosal/--sal-ab/--sal-rebuild-terrain flags, /sal:coverage /sal:status /sal:setup commands, before_agent_start/tool_execution_start/agent_end hooks; /sal:setup writes ~/.memory-experiments/credentials.json with adapter inference (insforge/jsonl/noop); publishes structuralAnchor via core/runtime/turn-context (no SAL-specific globals); emits run_start/turn_anchor/run_end eval events through pluggable EvalSink with best-effort shutdown flushing; publishes SAL eval background failures to diagnostic:event; writes local .memory-experiments sidecar anchors only when --sal-ab or NANOPENCIL_SAL_AB=1 is enabled; runtime no-op when --nosal is set
71
+ sal/index.ts: SAL extension entry, enabled by default, registers flags, /sal:* commands, lifecycle hooks, terrain snapshot refresh, eval event emission, and stale-run cleanup scheduling; delegates config, context, runtime contracts, and tool_trace analytics to focused SAL modules
72
+ sal/sal-config.ts: SAL build metadata, eval environment constants, credential loading, truthy parsing, stale-cleanup/A-B flag resolution, experiment id normalization, and sidecar directory resolution
73
+ sal/sal-context.ts: SAL anchor system-prompt injection formatting plus A/B sidecar turn-record persistence
74
+ sal/sal-runtime.ts: SAL shared BuildMeta/TurnState/SalRuntime contracts used across config, context, trace, and entry modules
75
+ sal/sal-trace.ts: SAL tool path extraction, task intent inference, and bounded tool_trace payload construction
55
76
  sal/terrain.ts: TerrainSnapshot/TerrainNode/TerrainEdge model, buildTerrainIndex(), checkDipCoverage(), isSnapshotStale(), moduleIdForPath(), parses P2 AGENT.md and P3 file headers
56
77
  sal/anchors.ts: StructuralAnchor/AnchorResolution model, locateTask(), locateAction(), evidence-driven scoring with tunable SalWeights, CJK bigram tokenization
57
78
  sal/weights.ts: SalWeights interface, SAL_DEFAULT_WEIGHTS, loadSalWeights() reads sal-config.json from workspace or .memory-experiments/sal/
@@ -61,11 +82,13 @@ sal/eval/noop-sink.ts: noopSink — silent EvalSink used when eval disabled or n
61
82
  sal/eval/insforge-sink.ts: InsForgeEvalSink — PostgREST adapter, routes run_start→eval_runs INSERT (merge-duplicates) with legacy-schema fallback, writes turn_anchor/tool_trace/memory_recalls/run_end only after parent run confirmation, tool_trace→eval_tool_traces with PGRST204 fallback, memory_recalls→eval_memory_recalls batch INSERT, run_end→eval_runs PATCH; allowSelfSigned TLS option logs only in development runtime, batching with default 2000ms interval
62
83
  sal/eval/jsonl-sink.ts: JsonlEvalSink — append-only filesystem adapter, one JSON object per line, accepts file:// URLs or plain paths, auto-creates parent dir, batched writes
63
84
  sal/README.md: SAL extension usage, sidecar output layout, weights override, pluggability contract
64
- team/index.ts: AgentTeam extension entry, /team <task>, /team:spawn/:preset/:send/:status/:progress/:psyche/:dashboard/:task/:mail/:allow-path/:stop/:terminate/:approve/:mode commands, TEAM_MESSAGE_TYPE speaker-stream renderer, realtime status/dashboard updates
85
+ team/index.ts: AgentTeam extension entry, /team <task>, /team:spawn/:preset/:send/:status/:progress/:psyche/:dashboard/:task/:mail/:allow-path/:stop/:terminate/:approve/:mode command registration and dispatch
86
+ team/team-ui.ts: AgentTeam message renderer, list/status/task formatting, dashboard visibility/timer ownership, realtime observer, speaker-stream emission helpers
65
87
  team/team-types.ts: TeammateRole/TeammateMode/TeammateStatus/TeamTask/HarnessState/PsycheWeights/TeamUtterance/Handoff/LeaderPlan/AgentLiveView/TeammateIdentity/PersistedTeammate/TeamSpawnSpec/TeamSendResult types
66
88
  team/team-state-store.ts: TeamStateStore class - durable teammate persistence via JSON files in <agentDir>/teams/
67
89
  team/team-parser.ts: Team command parser - parseTeamCommand/buildTeamHelp for /team:* subcommands
68
- team/team-runtime.ts: TeamRuntime class - teammate registry, stable internal labels plus visible teammate names, per-teammate send queue, task/mailbox prompt context, lifecycle, realtime status/live events, durable tasks, mailbox + permission + transcript wiring
90
+ team/team-runtime.ts: TeamRuntime class - teammate registry, stable internal labels plus visible teammate names, per-teammate send queue, lifecycle, durable tasks, mailbox + permission + transcript wiring
91
+ team/team-runtime-helpers.ts: TeamRuntime helper boundary - teammate prompt construction, harness turn preparation, live event projection, tool selection, path guards, label/role/text helpers
69
92
  team/team-orchestrator.ts: Leader orchestration helpers - plan building, speaker utterance creation, @mention parsing, and handoff execution
70
93
  team/team-task-store.ts: TeamTaskStore class - durable shared task list in <storageDir>/tasks.json
71
94
  team/team-harness.ts: Harness protocol helpers - context files, phase instructions, checkpoint/revert, feature validation
@@ -62,10 +62,13 @@ async function handleBtwCommand(args, ctx, api) {
62
62
  const userMessage = contextText
63
63
  ? `Previous conversation:\n${contextText}\n\nUser's question: ${question}`
64
64
  : `User's question: ${question}`;
65
+ let timeout;
65
66
  try {
66
67
  const response = await Promise.race([
67
68
  ctx.completeSimple(BTW_SYSTEM_PROMPT, userMessage),
68
- new Promise((resolve) => setTimeout(() => resolve(undefined), BTW_TIMEOUT_MS)),
69
+ new Promise((resolve) => {
70
+ timeout = setTimeout(() => resolve(undefined), BTW_TIMEOUT_MS);
71
+ }),
69
72
  ]);
70
73
  if (response) {
71
74
  api.sendMessage({
@@ -82,6 +85,10 @@ async function handleBtwCommand(args, ctx, api) {
82
85
  const message = error instanceof Error ? error.message : String(error);
83
86
  ctx.ui.notify(`BTW error: ${message}`, "error");
84
87
  }
88
+ finally {
89
+ if (timeout)
90
+ clearTimeout(timeout);
91
+ }
85
92
  }
86
93
  // ============================================================================
87
94
  // Extension entry
@@ -0,0 +1,8 @@
1
+ /**
2
+ * [WHO]: disciplineExtension - registers skill tool, nanoPencil engineering discipline skills, and lightweight bootstrap prompt
3
+ * [FROM]: Depends on node:path, node:url, node:fs, core/extensions/types
4
+ * [TO]: Auto-loaded by builtin-extensions.ts as a default extension; consumed by ResourceLoader via resources_discover
5
+ * [HERE]: extensions/defaults/discipline/index.ts - default engineering workflow discipline package
6
+ */
7
+ import type { ExtensionAPI } from "../../../core/extensions/types.js";
8
+ export default function disciplineExtension(api: ExtensionAPI): Promise<void>;