@pencil-agent/nano-pencil 1.13.11 → 1.13.13

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 (222) hide show
  1. package/README.md +1 -1
  2. package/dist/build-meta.json +3 -3
  3. package/dist/builtin-extensions.js +10 -0
  4. package/dist/core/extensions/runner.d.ts +1 -0
  5. package/dist/core/extensions/runner.js +5 -0
  6. package/dist/core/extensions/types.d.ts +10 -0
  7. package/dist/core/model-resolver.js +2 -0
  8. package/dist/core/runtime/agent-session.js +54 -0
  9. package/dist/core/runtime/sdk.js +22 -3
  10. package/dist/core/tools/bash.d.ts +2 -0
  11. package/dist/core/tools/bash.js +125 -1
  12. package/dist/core/tools/edit.d.ts +2 -0
  13. package/dist/core/tools/edit.js +1 -0
  14. package/dist/core/tools/index.d.ts +6 -0
  15. package/dist/core/tools/index.js +4 -4
  16. package/dist/core/tools/write.d.ts +2 -0
  17. package/dist/core/tools/write.js +1 -0
  18. package/dist/extensions/defaults/AGENT.md +20 -9
  19. package/dist/extensions/defaults/browser/AGENT.md +17 -0
  20. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/amazon/product-search.md +198 -0
  21. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/archive-org/scraping.md +341 -0
  22. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/arxiv/scraping.md +311 -0
  23. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/arxiv-bulk/scraping.md +333 -0
  24. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/atlas/overview.md +70 -0
  25. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/booking-com/scraping.md +578 -0
  26. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/capterra/scraping.md +440 -0
  27. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/centilebrain/generate-estimates.md +110 -0
  28. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/coingecko/scraping.md +325 -0
  29. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/coinmarketcap/scraping.md +463 -0
  30. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/coursera/scraping.md +360 -0
  31. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/craigslist/scraping.md +390 -0
  32. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/crossref/scraping.md +568 -0
  33. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/dev-to/scraping.md +323 -0
  34. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/duckduckgo/scraping.md +349 -0
  35. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/ebay/scraping.md +435 -0
  36. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/etsy/scraping.md +506 -0
  37. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/eventbrite/scraping.md +363 -0
  38. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/expedia/automation.md +168 -0
  39. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/facebook/groups.md +236 -0
  40. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/facebook/pages.md +295 -0
  41. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/framer/editor.md +108 -0
  42. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/fred/scraping.md +493 -0
  43. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/g2/scraping.md +580 -0
  44. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/genius/scraping.md +511 -0
  45. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/github/repo-actions.md +65 -0
  46. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/github/scraping.md +184 -0
  47. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/glassdoor/scraping.md +543 -0
  48. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/gmail/compose.md +122 -0
  49. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/goodreads/scraping.md +461 -0
  50. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/gutenberg/scraping.md +383 -0
  51. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/hackernews/scraping.md +243 -0
  52. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/howlongtobeat/scraping.md +473 -0
  53. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/imdb/scraping.md +271 -0
  54. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/itch-io/scraping.md +436 -0
  55. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/job-boards/indeed-glassdoor.md +1021 -0
  56. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/letterboxd/scraping.md +349 -0
  57. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/linkedin/invitation-manager.md +109 -0
  58. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/loom/folder-enumeration.md +170 -0
  59. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/macrotrends/scraping.md +537 -0
  60. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/medium/article-hydration.md +120 -0
  61. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/medium/scraping.md +414 -0
  62. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/metacritic/scraping.md +477 -0
  63. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/musicbrainz/scraping.md +478 -0
  64. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/nasa/scraping.md +339 -0
  65. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/news-aggregation/multi-source.md +205 -0
  66. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/open-library/scraping.md +472 -0
  67. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/openalex/scraping.md +470 -0
  68. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/openstreetmap/scraping.md +490 -0
  69. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/package-registries/npm-pypi.md +478 -0
  70. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/polymarket/scraping.md +234 -0
  71. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/producthunt/scraping.md +307 -0
  72. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/pubmed/scraping.md +421 -0
  73. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/quora/scraping.md +364 -0
  74. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/rawg/scraping.md +352 -0
  75. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/reddit/scraping.md +124 -0
  76. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/rest-countries/scraping.md +233 -0
  77. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/sec-edgar/scraping.md +361 -0
  78. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/shopify-admin/README.md +36 -0
  79. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/shopify-admin/embedded-apps.md +72 -0
  80. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/shopify-admin/knowledge-base.md +109 -0
  81. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/shopify-admin/polaris-inputs.md +137 -0
  82. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/soundcloud/scraping.md +362 -0
  83. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/spotify/scraping.md +339 -0
  84. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/stackoverflow/scraping.md +435 -0
  85. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/steam/scraping.md +575 -0
  86. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/substack/scraping.md +338 -0
  87. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/thetechgeeks/pricing.md +52 -0
  88. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/tiktok/upload.md +107 -0
  89. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/tradingview/scraping.md +309 -0
  90. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/trello/boards-and-lists.md +88 -0
  91. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/trustpilot/scraping.md +375 -0
  92. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/walmart/scraping.md +444 -0
  93. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/wayback-machine/scraping.md +306 -0
  94. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/weather/scraping.md +398 -0
  95. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/wellfound/scraping.md +596 -0
  96. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/world-bank/scraping.md +356 -0
  97. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/xiaohongshu/scraping.md +84 -0
  98. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/youtube/scraping.md +418 -0
  99. package/dist/extensions/defaults/browser/agent-workspace/domain-skills/zillow/scraping.md +433 -0
  100. package/dist/extensions/defaults/browser/browser.md +73 -0
  101. package/dist/extensions/defaults/browser/index.d.ts +8 -0
  102. package/dist/extensions/defaults/browser/index.js +395 -0
  103. package/dist/extensions/defaults/browser/install.md +142 -0
  104. package/dist/extensions/defaults/browser/interaction-skills/connection.md +48 -0
  105. package/dist/extensions/defaults/browser/interaction-skills/cookies.md +3 -0
  106. package/dist/extensions/defaults/browser/interaction-skills/cross-origin-iframes.md +3 -0
  107. package/dist/extensions/defaults/browser/interaction-skills/dialogs.md +64 -0
  108. package/dist/extensions/defaults/browser/interaction-skills/downloads.md +3 -0
  109. package/dist/extensions/defaults/browser/interaction-skills/drag-and-drop.md +3 -0
  110. package/dist/extensions/defaults/browser/interaction-skills/dropdowns.md +3 -0
  111. package/dist/extensions/defaults/browser/interaction-skills/iframes.md +3 -0
  112. package/dist/extensions/defaults/browser/interaction-skills/network-requests.md +3 -0
  113. package/dist/extensions/defaults/browser/interaction-skills/print-as-pdf.md +3 -0
  114. package/dist/extensions/defaults/browser/interaction-skills/profile-sync.md +90 -0
  115. package/dist/extensions/defaults/browser/interaction-skills/screenshots.md +17 -0
  116. package/dist/extensions/defaults/browser/interaction-skills/scrolling.md +3 -0
  117. package/dist/extensions/defaults/browser/interaction-skills/shadow-dom.md +3 -0
  118. package/dist/extensions/defaults/browser/interaction-skills/tabs.md +69 -0
  119. package/dist/extensions/defaults/browser/interaction-skills/uploads.md +1 -0
  120. package/dist/extensions/defaults/browser/interaction-skills/viewport.md +3 -0
  121. package/dist/extensions/defaults/browser/src/browser_harness/AGENT.md +15 -0
  122. package/dist/extensions/defaults/diagnostics/diagnostic-buffer.js +18 -4
  123. package/dist/extensions/defaults/diagnostics/index.d.ts +1 -1
  124. package/dist/extensions/defaults/diagnostics/index.js +30 -23
  125. package/dist/extensions/defaults/diagnostics/types.d.ts +1 -0
  126. package/dist/extensions/defaults/interview/index.js +515 -147
  127. package/dist/extensions/defaults/link-world/agent-workspace/README.md +16 -0
  128. package/dist/extensions/defaults/link-world/index.d.ts +3 -7
  129. package/dist/extensions/defaults/link-world/index.js +373 -39
  130. package/dist/extensions/defaults/link-world/link-world-agent.md +82 -0
  131. package/dist/extensions/defaults/link-world/network-routing.md +67 -0
  132. package/dist/extensions/defaults/team/AGENT.md +39 -20
  133. package/dist/extensions/defaults/team/TESTING.md +52 -0
  134. package/dist/extensions/defaults/team/index.d.ts +3 -0
  135. package/dist/extensions/defaults/team/index.js +246 -40
  136. package/dist/extensions/defaults/team/team-dashboard.d.ts +6 -2
  137. package/dist/extensions/defaults/team/team-dashboard.js +65 -90
  138. package/dist/extensions/defaults/team/team-mailbox.d.ts +13 -9
  139. package/dist/extensions/defaults/team/team-mailbox.js +55 -9
  140. package/dist/extensions/defaults/team/team-orchestrator.d.ts +39 -0
  141. package/dist/extensions/defaults/team/team-orchestrator.js +458 -0
  142. package/dist/extensions/defaults/team/team-parser.d.ts +16 -1
  143. package/dist/extensions/defaults/team/team-parser.js +87 -2
  144. package/dist/extensions/defaults/team/team-permissions.js +6 -2
  145. package/dist/extensions/defaults/team/team-presets.js +47 -30
  146. package/dist/extensions/defaults/team/team-psyche.js +5 -0
  147. package/dist/extensions/defaults/team/team-runtime.d.ts +17 -1
  148. package/dist/extensions/defaults/team/team-runtime.js +490 -178
  149. package/dist/extensions/defaults/team/team-task-store.d.ts +35 -0
  150. package/dist/extensions/defaults/team/team-task-store.js +93 -0
  151. package/dist/extensions/defaults/team/team-types.d.ts +97 -7
  152. package/dist/extensions/defaults/team/team-types.js +3 -3
  153. package/dist/main.js +14 -1
  154. package/dist/modes/interactive/components/custom-message.d.ts +1 -0
  155. package/dist/modes/interactive/components/custom-message.js +4 -0
  156. package/dist/modes/interactive/interactive-mode.d.ts +3 -0
  157. package/dist/modes/interactive/interactive-mode.js +96 -15
  158. package/dist/nanopencil-defaults.d.ts +84 -1
  159. package/dist/nanopencil-defaults.js +171 -4
  160. package/dist/node_modules/@pencil-agent/ai/env-api-keys.js +2 -0
  161. package/dist/node_modules/@pencil-agent/ai/models.generated.d.ts +143 -17
  162. package/dist/node_modules/@pencil-agent/ai/models.generated.js +131 -21
  163. package/dist/node_modules/@pencil-agent/ai/providers/amazon-bedrock.js +5 -1
  164. package/dist/node_modules/@pencil-agent/ai/providers/anthropic.js +4 -1
  165. package/dist/node_modules/@pencil-agent/ai/providers/azure-openai-responses.d.ts +1 -0
  166. package/dist/node_modules/@pencil-agent/ai/providers/azure-openai-responses.js +4 -0
  167. package/dist/node_modules/@pencil-agent/ai/providers/google-gemini-cli.js +4 -0
  168. package/dist/node_modules/@pencil-agent/ai/providers/google-vertex.js +4 -0
  169. package/dist/node_modules/@pencil-agent/ai/providers/google.js +4 -1
  170. package/dist/node_modules/@pencil-agent/ai/providers/openai-responses.d.ts +1 -0
  171. package/dist/node_modules/@pencil-agent/ai/providers/openai-responses.js +4 -0
  172. package/dist/node_modules/@pencil-agent/ai/types.d.ts +3 -1
  173. package/dist/packages/mem-core/consolidation.d.ts +1 -1
  174. package/dist/packages/mem-core/consolidation.js +5 -2
  175. package/dist/packages/mem-core/diagnostics.d.ts +1 -1
  176. package/dist/packages/mem-core/diagnostics.js +3 -8
  177. package/dist/packages/mem-core/engine-insights.d.ts +1 -1
  178. package/dist/packages/mem-core/engine-insights.js +3 -6
  179. package/dist/packages/mem-core/engine.d.ts +1 -1
  180. package/dist/packages/mem-core/engine.js +3 -6
  181. package/dist/packages/mem-core/extension.js +85 -7
  182. package/dist/packages/mem-core/extraction.d.ts +1 -1
  183. package/dist/packages/mem-core/extraction.js +71 -15
  184. package/dist/packages/mem-core/full-insights.d.ts +1 -1
  185. package/dist/packages/mem-core/full-insights.js +3 -3
  186. package/dist/packages/mem-core/human-insights.d.ts +1 -1
  187. package/dist/packages/mem-core/human-insights.js +3 -3
  188. package/dist/packages/mem-core/llm-json.d.ts +10 -0
  189. package/dist/packages/mem-core/llm-json.js +101 -0
  190. package/dist/packages/soul-core/diagnostics.d.ts +1 -1
  191. package/dist/packages/soul-core/diagnostics.js +3 -8
  192. package/dist/packages/soul-core/evolution.d.ts +5 -3
  193. package/dist/packages/soul-core/evolution.js +23 -5
  194. package/dist/packages/soul-core/manager.js +3 -2
  195. package/dist/packages/soul-core/src/diagnostics.d.ts +1 -1
  196. package/dist/packages/soul-core/src/diagnostics.js +3 -8
  197. package/dist/packages/soul-core/src/evolution.d.ts +5 -3
  198. package/dist/packages/soul-core/src/evolution.js +23 -5
  199. package/dist/packages/soul-core/src/manager.js +3 -2
  200. package/dist/utils/diagnostics.d.ts +4 -5
  201. package/dist/utils/diagnostics.js +6 -12
  202. package/dist/utils/startup-profiler.d.ts +59 -3
  203. package/dist/utils/startup-profiler.js +105 -3
  204. package/docs/eval/AGENT.md +36 -0
  205. package/docs/eval/README.md +72 -0
  206. package/docs/eval/decision-log-template.md +51 -0
  207. package/docs/eval/experiment-protocol.md +77 -0
  208. package/docs/eval/issue-usage/README.md +32 -0
  209. package/docs/eval/issue-usage/cases.md +31 -0
  210. package/docs/eval/issue-usage/metrics.md +23 -0
  211. package/docs/eval/issue-usage/workflow.md +39 -0
  212. package/docs/eval/sal-memory-anchor/README.md +32 -0
  213. package/docs/eval/sal-memory-anchor/hypothesis.md +45 -0
  214. package/docs/eval/sal-memory-anchor/metrics.md +24 -0
  215. package/docs/eval/sal-memory-anchor/runs.md +29 -0
  216. package/docs/eval/tool-usage-analysis/README.md +32 -0
  217. package/docs/eval/tool-usage-analysis/invalid-data-rules.md +29 -0
  218. package/docs/eval/tool-usage-analysis/metrics.md +35 -0
  219. package/docs/eval/tool-usage-analysis/report-template.md +49 -0
  220. package/docs/eval/tool-usage-analysis/sop.md +63 -0
  221. package/docs//346/226/207/346/241/243/344/270/255/345/277/203.md +10 -0
  222. package/package.json +5 -2
package/README.md CHANGED
@@ -104,7 +104,7 @@ Built-in tools include:
104
104
  ### 🌐 Multi-Model Support
105
105
  Use the best model for each task.
106
106
 
107
- - 🇨🇳 **Alibaba DashScope** — Qwen series (optimized for coding)
107
+ - 🇨🇳 **Alibaba DashScope / Token Plan** — Qwen, GLM, MiniMax, DeepSeek text models
108
108
  - 🤖 **OpenAI** — GPT-4, GPT-3.5
109
109
  - 💬 **Anthropic** — Claude 3 Opus/Sonnet/Haiku
110
110
  - 🔍 **Google** — Gemini Pro/Ultra
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "1.13.11",
3
- "commitHash": "95e42e3",
2
+ "version": "1.13.13",
3
+ "commitHash": "9c2e846",
4
4
  "branch": "main",
5
- "builtAt": "2026-05-01T07:29:27.895Z"
5
+ "builtAt": "2026-05-02T12:45:01.834Z"
6
6
  }
@@ -14,6 +14,7 @@ const require = createRequire(import.meta.url);
14
14
  const BUNDLED_NANOMEM_EXTENSION_PACKAGES = join(__dirname, "packages", "mem-core", "extension.js");
15
15
  const BUNDLED_SIMPLIFY_EXTENSION = join(__dirname, "extensions", "optional", "simplify", "index.js");
16
16
  const BUNDLED_LINK_WORLD_EXTENSION = join(__dirname, "extensions", "defaults", "link-world", "index.js");
17
+ const BUNDLED_BROWSER_EXTENSION = join(__dirname, "extensions", "defaults", "browser", "index.js");
17
18
  const BUNDLED_SECURITY_AUDIT_EXTENSION = join(__dirname, "extensions", "defaults", "security-audit", "index.js");
18
19
  const BUNDLED_SOUL_EXTENSION = join(__dirname, "extensions", "defaults", "soul", "index.js");
19
20
  const BUNDLED_PRESENCE_EXTENSION = join(__dirname, "extensions", "defaults", "presence", "index.js");
@@ -142,6 +143,15 @@ export function getBuiltinExtensionPaths() {
142
143
  if (existsSync(linkWorldTs))
143
144
  paths.push(linkWorldTs);
144
145
  }
146
+ // === Browser Harness extension (built-in CDP browser automation) ===
147
+ if (existsSync(BUNDLED_BROWSER_EXTENSION)) {
148
+ paths.push(BUNDLED_BROWSER_EXTENSION);
149
+ }
150
+ else {
151
+ const browserTs = join(__dirname, "extensions", "defaults", "browser", "index.ts");
152
+ if (existsSync(browserTs))
153
+ paths.push(browserTs);
154
+ }
145
155
  // === Security Audit extension (built-in source, compiled to dist/extensions/defaults/security-audit) ===
146
156
  if (existsSync(BUNDLED_SECURITY_AUDIT_EXTENSION)) {
147
157
  paths.push(BUNDLED_SECURITY_AUDIT_EXTENSION);
@@ -69,6 +69,7 @@ export declare class ExtensionRunner {
69
69
  private errorListeners;
70
70
  private getModel;
71
71
  private completeSimpleFn;
72
+ private completeJsonFn;
72
73
  private isIdleFn;
73
74
  private waitForIdleFn;
74
75
  private abortFn;
@@ -87,6 +87,7 @@ export class ExtensionRunner {
87
87
  errorListeners = new Set();
88
88
  getModel = () => undefined;
89
89
  completeSimpleFn = async () => undefined;
90
+ completeJsonFn;
90
91
  isIdleFn = () => true;
91
92
  waitForIdleFn = async () => { };
92
93
  abortFn = () => { };
@@ -159,6 +160,7 @@ export class ExtensionRunner {
159
160
  // Context actions (required)
160
161
  this.getModel = contextActions.getModel;
161
162
  this.completeSimpleFn = contextActions.completeSimple;
163
+ this.completeJsonFn = contextActions.completeJson;
162
164
  this.isIdleFn = contextActions.isIdle;
163
165
  this.runtime.isIdle = () => this.isIdleFn();
164
166
  this.abortFn = contextActions.abort;
@@ -393,6 +395,9 @@ export class ExtensionRunner {
393
395
  return getModel();
394
396
  },
395
397
  completeSimple: (systemPrompt, userMessage) => this.completeSimpleFn(systemPrompt, userMessage),
398
+ completeJson: this.completeJsonFn
399
+ ? (systemPrompt, userMessage, schema, options) => this.completeJsonFn(systemPrompt, userMessage, schema, options)
400
+ : undefined,
396
401
  isIdle: () => this.isIdleFn(),
397
402
  abort: () => this.abortFn(),
398
403
  hasPendingMessages: () => this.hasPendingMessagesFn(),
@@ -190,6 +190,11 @@ export interface ExtensionContext {
190
190
  model: Model<any> | undefined;
191
191
  /** One-shot LLM completion with current model (e.g. for memory extraction). Undefined when no model or no API key. */
192
192
  completeSimple(systemPrompt: string, userMessage: string): Promise<string | undefined>;
193
+ /** One-shot structured JSON completion with current model. Uses provider tool-calling when available. */
194
+ completeJson?(systemPrompt: string, userMessage: string, schema: Record<string, unknown>, options?: {
195
+ toolName?: string;
196
+ resultKey?: string;
197
+ }): Promise<string | undefined>;
193
198
  /** Whether the agent is idle (not streaming) */
194
199
  isIdle(): boolean;
195
200
  /** Abort the current agent operation */
@@ -937,6 +942,11 @@ export interface ExtensionContextActions {
937
942
  getModel: () => Model<any> | undefined;
938
943
  /** One-shot completion with current model for extensions (e.g. memory extraction). Returns undefined if no model or no API key. */
939
944
  completeSimple: (systemPrompt: string, userMessage: string) => Promise<string | undefined>;
945
+ /** One-shot structured JSON completion with current model. Returns undefined if no model, no API key, or no structured payload. */
946
+ completeJson?: (systemPrompt: string, userMessage: string, schema: Record<string, unknown>, options?: {
947
+ toolName?: string;
948
+ resultKey?: string;
949
+ }) => Promise<string | undefined>;
940
950
  isIdle: () => boolean;
941
951
  abort: () => void;
942
952
  hasPendingMessages: () => boolean;
@@ -28,6 +28,8 @@ export const defaultModelPerProvider = {
28
28
  opencode: "claude-opus-4-6",
29
29
  "opencode-go": "claude-opus-4-6",
30
30
  "kimi-coding": "kimi-k2-thinking",
31
+ "ali-token-plan-openai": "qwen3.6-plus",
32
+ "ali-token-plan-anthropic": "qwen3.6-plus",
31
33
  };
32
34
  /**
33
35
  * Helper to check if a model ID looks like an alias (no date suffix)
@@ -10,6 +10,21 @@ import { completeSimple, isContextOverflow, modelsAreEqual, resetApiProviders, s
10
10
  import { getDocsPath } from "../../config.js";
11
11
  import { theme } from "../../modes/interactive/theme/theme.js";
12
12
  import { stripFrontmatter } from "../../utils/frontmatter.js";
13
+ function getStructuredToolChoice(model, toolName) {
14
+ switch (model.api) {
15
+ case "openai-completions":
16
+ return { type: "function", function: { name: toolName } };
17
+ case "anthropic-messages":
18
+ case "bedrock-converse-stream":
19
+ return { type: "tool", name: toolName };
20
+ case "google-generative-ai":
21
+ case "google-gemini-cli":
22
+ case "google-vertex":
23
+ return "any";
24
+ default:
25
+ return "required";
26
+ }
27
+ }
13
28
  /**
14
29
  * Custom error for model cycling with additional context.
15
30
  */
@@ -1949,6 +1964,45 @@ export class AgentSession {
1949
1964
  return undefined;
1950
1965
  }
1951
1966
  },
1967
+ completeJson: async (systemPrompt, userMessage, schema, options) => {
1968
+ const model = this.model;
1969
+ if (!model)
1970
+ return undefined;
1971
+ const apiKey = await this.modelRegistry.getApiKey(model);
1972
+ if (!apiKey)
1973
+ return undefined;
1974
+ const toolName = options?.toolName || "submit_json";
1975
+ try {
1976
+ const response = await completeSimple(model, {
1977
+ systemPrompt: `${systemPrompt}\n\nYou must call the ${toolName} tool exactly once with the final structured JSON payload. Do not answer in prose.`,
1978
+ messages: [
1979
+ { role: "user", content: userMessage, timestamp: Date.now() },
1980
+ ],
1981
+ tools: [
1982
+ {
1983
+ name: toolName,
1984
+ description: "Submit the final structured JSON payload.",
1985
+ parameters: schema,
1986
+ },
1987
+ ],
1988
+ }, {
1989
+ maxTokens: 1500,
1990
+ temperature: 0,
1991
+ apiKey,
1992
+ toolChoice: getStructuredToolChoice(model, toolName),
1993
+ });
1994
+ const toolCall = response.content?.find((b) => b.type === "toolCall" && b.name === toolName);
1995
+ if (!toolCall)
1996
+ return undefined;
1997
+ const payload = options?.resultKey
1998
+ ? toolCall.arguments?.[options.resultKey]
1999
+ : toolCall.arguments;
2000
+ return JSON.stringify(payload);
2001
+ }
2002
+ catch {
2003
+ return undefined;
2004
+ }
2005
+ },
1952
2006
  getSettings: () => this.settingsManager.getSettings(),
1953
2007
  isIdle: () => !this.isStreaming,
1954
2008
  abort: () => this.abort(),
@@ -42,6 +42,26 @@ export {
42
42
  readTool, bashTool, editTool, writeTool, grepTool, findTool, lsTool, codingTools, readOnlyTools, allTools as allBuiltInTools,
43
43
  // Tool factories (for custom cwd)
44
44
  createCodingTools, createReadOnlyTools, createReadTool, createBashTool, createEditTool, createWriteTool, createGrepTool, createFindTool, createLsTool, };
45
+ function normalizeSettingsManager(candidate, cwd, agentDir) {
46
+ if (candidate instanceof SettingsManager) {
47
+ return candidate;
48
+ }
49
+ const fallback = SettingsManager.create(cwd, agentDir);
50
+ if (!candidate || typeof candidate !== "object") {
51
+ return fallback;
52
+ }
53
+ if (typeof candidate.getSettings !== "function") {
54
+ return fallback;
55
+ }
56
+ const wrapper = fallback;
57
+ for (const key of Object.keys(candidate)) {
58
+ const value = candidate[key];
59
+ if (typeof value === "function") {
60
+ wrapper[key] = value.bind(candidate);
61
+ }
62
+ }
63
+ return fallback;
64
+ }
45
65
  // Helper Functions
46
66
  function getDefaultAgentDir() {
47
67
  return getAgentDir();
@@ -91,9 +111,9 @@ export async function createAgentSession(options = {}) {
91
111
  const cwd = options.cwd ?? process.cwd();
92
112
  const agentDir = options.agentDir ?? getDefaultAgentDir();
93
113
  let resourceLoader = options.resourceLoader;
114
+ const settingsManager = normalizeSettingsManager(options.settingsManager, cwd, agentDir);
94
115
  // Initialize i18n with locale from settings (or default to English)
95
- const tempSettingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);
96
- const locale = tempSettingsManager.getSettings().locale ?? "en";
116
+ const locale = settingsManager.getSettings().locale ?? "en";
97
117
  const { setLocale } = await import("../i18n/index.js");
98
118
  setLocale(locale);
99
119
  // Use provided or create AuthStorage and ModelRegistry
@@ -103,7 +123,6 @@ export async function createAgentSession(options = {}) {
103
123
  : undefined;
104
124
  const authStorage = options.authStorage ?? AuthStorage.create(authPath);
105
125
  const modelRegistry = options.modelRegistry ?? new ModelRegistry(authStorage, modelsPath);
106
- const settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);
107
126
  const sessionManager = options.sessionManager ?? SessionManager.create(cwd);
108
127
  if (!resourceLoader) {
109
128
  resourceLoader = new DefaultResourceLoader({
@@ -56,6 +56,8 @@ export interface BashSandboxOptions {
56
56
  additionalBlockedPatterns?: RegExp[];
57
57
  /** Custom error message for blocked commands */
58
58
  blockedMessage?: string;
59
+ /** Optional path allowlist hook for simple write commands. Defaults to denying all writes. */
60
+ allowWritePath?: (absolutePath: string) => boolean;
59
61
  }
60
62
  /**
61
63
  * Create a sandboxed bash hook that blocks dangerous write operations.
@@ -7,7 +7,7 @@
7
7
  import { randomBytes } from "node:crypto";
8
8
  import { createWriteStream, existsSync } from "node:fs";
9
9
  import { tmpdir } from "node:os";
10
- import { join } from "node:path";
10
+ import { isAbsolute, join, resolve } from "node:path";
11
11
  import { Type } from "@sinclair/typebox";
12
12
  import { spawn } from "child_process";
13
13
  import { getShellConfig, getShellEnv, killProcessTree } from "../utils/shell.js";
@@ -284,6 +284,23 @@ export function createSandboxHook(options) {
284
284
  const blockedMessage = options?.blockedMessage ?? "Write operations are not allowed in sandbox mode";
285
285
  return (context) => {
286
286
  const command = context.command.trim();
287
+ const writePaths = extractSimpleWritePaths(command, context.cwd);
288
+ if (writePaths === null) {
289
+ return {
290
+ ...context,
291
+ command: `echo "${blockedMessage}" >&2; exit 1`,
292
+ };
293
+ }
294
+ if (writePaths.length > 0) {
295
+ const allAllowed = writePaths.every((path) => options?.allowWritePath?.(path) === true);
296
+ if (!allAllowed) {
297
+ return {
298
+ ...context,
299
+ command: `echo "${blockedMessage}" >&2; exit 1`,
300
+ };
301
+ }
302
+ return context;
303
+ }
287
304
  // Check if command contains any blocked patterns
288
305
  for (const pattern of blockedPatterns) {
289
306
  if (pattern.test(command)) {
@@ -296,3 +313,110 @@ export function createSandboxHook(options) {
296
313
  return context;
297
314
  };
298
315
  }
316
+ function extractSimpleWritePaths(command, cwd) {
317
+ if (/[;&|`$()]/.test(command))
318
+ return null;
319
+ const tokens = tokenizeSimpleShell(command);
320
+ if (tokens.length === 0)
321
+ return [];
322
+ const paths = [];
323
+ for (let index = 0; index < tokens.length; index++) {
324
+ const token = tokens[index];
325
+ if (token === ">" || token === ">>" || /^&?\d?>&?\d?$/.test(token)) {
326
+ const next = tokens[index + 1];
327
+ if (!next)
328
+ return null;
329
+ paths.push(resolveSandboxPath(next, cwd));
330
+ index++;
331
+ continue;
332
+ }
333
+ const redirectMatch = /^(?:\d?>|>>)(.+)$/.exec(token);
334
+ if (redirectMatch?.[1]) {
335
+ paths.push(resolveSandboxPath(redirectMatch[1], cwd));
336
+ continue;
337
+ }
338
+ }
339
+ const cmd = tokens[0];
340
+ if (cmd === "mkdir") {
341
+ const targets = tokens.slice(1).filter((token) => !token.startsWith("-"));
342
+ if (targets.length === 0)
343
+ return null;
344
+ paths.push(...targets.map((target) => resolveSandboxPath(target, cwd)));
345
+ }
346
+ else if (cmd === "cp" || cmd === "mv") {
347
+ const operands = tokens.slice(1).filter((token) => !token.startsWith("-"));
348
+ if (operands.length < 2)
349
+ return null;
350
+ paths.push(resolveSandboxPath(operands[operands.length - 1], cwd));
351
+ }
352
+ else if (cmd === "rm") {
353
+ const targets = tokens.slice(1).filter((token) => !token.startsWith("-"));
354
+ if (targets.length === 0)
355
+ return null;
356
+ paths.push(...targets.map((target) => resolveSandboxPath(target, cwd)));
357
+ }
358
+ else if (cmd === "tee") {
359
+ const targets = tokens.slice(1).filter((token) => !token.startsWith("-"));
360
+ if (targets.length === 0)
361
+ return null;
362
+ paths.push(...targets.map((target) => resolveSandboxPath(target, cwd)));
363
+ }
364
+ else if (cmd === "touch") {
365
+ const targets = tokens.slice(1).filter((token) => !token.startsWith("-"));
366
+ if (targets.length === 0)
367
+ return null;
368
+ paths.push(...targets.map((target) => resolveSandboxPath(target, cwd)));
369
+ }
370
+ return paths;
371
+ }
372
+ function tokenizeSimpleShell(command) {
373
+ const tokens = [];
374
+ let current = "";
375
+ let quote;
376
+ let escaped = false;
377
+ for (let index = 0; index < command.length; index++) {
378
+ const ch = command[index];
379
+ if (escaped) {
380
+ current += ch;
381
+ escaped = false;
382
+ continue;
383
+ }
384
+ if (ch === "\\") {
385
+ const next = command[index + 1];
386
+ if (!quote && next && (/\s/.test(next) || next === "\"" || next === "'" || next === "\\")) {
387
+ escaped = true;
388
+ }
389
+ else {
390
+ current += ch;
391
+ }
392
+ continue;
393
+ }
394
+ if (quote) {
395
+ if (ch === quote) {
396
+ quote = undefined;
397
+ }
398
+ else {
399
+ current += ch;
400
+ }
401
+ continue;
402
+ }
403
+ if (ch === "'" || ch === "\"") {
404
+ quote = ch;
405
+ continue;
406
+ }
407
+ if (/\s/.test(ch)) {
408
+ if (current) {
409
+ tokens.push(current);
410
+ current = "";
411
+ }
412
+ continue;
413
+ }
414
+ current += ch;
415
+ }
416
+ if (current)
417
+ tokens.push(current);
418
+ return tokens;
419
+ }
420
+ function resolveSandboxPath(path, cwd) {
421
+ return resolve(isAbsolute(path) ? path : join(cwd, path));
422
+ }
@@ -33,6 +33,8 @@ export interface EditOperations {
33
33
  export interface EditToolOptions {
34
34
  /** Custom operations for file editing. Default: local filesystem */
35
35
  operations?: EditOperations;
36
+ /** Optional guard called with the resolved absolute path before writing. */
37
+ beforeWrite?: (absolutePath: string) => void | Promise<void>;
36
38
  }
37
39
  export declare function createEditTool(cwd: string, options?: EditToolOptions): AgentTool<typeof editSchema>;
38
40
  /** Default edit tool using process.cwd() - for backwards compatibility */
@@ -22,6 +22,7 @@ export function createEditTool(cwd, options) {
22
22
  parameters: editSchema,
23
23
  execute: async (_toolCallId, { path, oldText, newText }, signal) => {
24
24
  const absolutePath = resolveToCwd(path, cwd);
25
+ await options?.beforeWrite?.(absolutePath);
25
26
  return new Promise((resolve, reject) => {
26
27
  // Check if already aborted
27
28
  if (signal?.aborted) {
@@ -15,7 +15,9 @@ export { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, type TruncationOption
15
15
  export { createWriteTool, type WriteOperations, type WriteToolInput, type WriteToolOptions, writeTool, } from "./write.js";
16
16
  import type { AgentTool } from "@pencil-agent/agent-core";
17
17
  import { type BashToolOptions } from "./bash.js";
18
+ import { type EditToolOptions } from "./edit.js";
18
19
  import { type ReadToolOptions } from "./read.js";
20
+ import { type WriteToolOptions } from "./write.js";
19
21
  /** Tool type (AgentTool from nanopencil-ai) */
20
22
  export type Tool = AgentTool<any>;
21
23
  export declare const codingTools: Tool[];
@@ -68,6 +70,10 @@ export interface ToolsOptions {
68
70
  read?: ReadToolOptions;
69
71
  /** Options for the bash tool */
70
72
  bash?: BashToolOptions;
73
+ /** Options for the edit tool */
74
+ edit?: EditToolOptions;
75
+ /** Options for the write tool */
76
+ write?: WriteToolOptions;
71
77
  }
72
78
  /**
73
79
  * Create coding tools configured for a specific working directory.
@@ -43,8 +43,8 @@ export function createCodingTools(cwd, options) {
43
43
  return [
44
44
  createReadTool(cwd, options?.read),
45
45
  createBashTool(cwd, options?.bash),
46
- createEditTool(cwd),
47
- createWriteTool(cwd),
46
+ createEditTool(cwd, options?.edit),
47
+ createWriteTool(cwd, options?.write),
48
48
  createTimeTool(),
49
49
  ];
50
50
  }
@@ -61,8 +61,8 @@ export function createAllTools(cwd, options) {
61
61
  return {
62
62
  read: createReadTool(cwd, options?.read),
63
63
  bash: createBashTool(cwd, options?.bash),
64
- edit: createEditTool(cwd),
65
- write: createWriteTool(cwd),
64
+ edit: createEditTool(cwd, options?.edit),
65
+ write: createWriteTool(cwd, options?.write),
66
66
  grep: createGrepTool(cwd),
67
67
  find: createFindTool(cwd),
68
68
  ls: createLsTool(cwd),
@@ -24,6 +24,8 @@ export interface WriteOperations {
24
24
  export interface WriteToolOptions {
25
25
  /** Custom operations for file writing. Default: local filesystem */
26
26
  operations?: WriteOperations;
27
+ /** Optional guard called with the resolved absolute path before writing. */
28
+ beforeWrite?: (absolutePath: string) => void | Promise<void>;
27
29
  }
28
30
  export declare function createWriteTool(cwd: string, options?: WriteToolOptions): AgentTool<typeof writeSchema>;
29
31
  /** Default write tool using process.cwd() - for backwards compatibility */
@@ -20,6 +20,7 @@ export function createWriteTool(cwd, options) {
20
20
  execute: async (_toolCallId, { path, content }, signal) => {
21
21
  const absolutePath = resolveToCwd(path, cwd);
22
22
  const dir = dirname(absolutePath);
23
+ await options?.beforeWrite?.(absolutePath);
23
24
  return new Promise((resolve, reject) => {
24
25
  // Check if already aborted
25
26
  if (signal?.aborted) {
@@ -8,7 +8,16 @@ diagnostics/types.ts: Diagnostic event/report type contract and diagnostic:event
8
8
  diagnostics/diagnostic-buffer.ts: DiagnosticBuffer, event coercion, fingerprint dedupe, prompt gating
9
9
  diagnostics/reporter.ts: User-approved InsForge pencil_issue_events reporter, configured via NANOPENCIL_ISSUE_* env vars
10
10
  diagnostics/redaction.ts: Diagnostic message normalization and secret/path redaction helpers
11
- link-world/index.ts: Internet access extension, provides internet-search Skill after setup
11
+ browser/index.ts: Browser Harness extension entry, registers browser/browser_admin tools, /browser command, Browser Harness resource discovery, project-local browser workspace seeding
12
+ browser/browser.md: Browser Harness day-to-day skill instructions for NanoPencil tool use and workspace contribution
13
+ browser/install.md: Browser Harness setup and troubleshooting instructions, exposed as a skill resource
14
+ browser/src/browser_harness/: Vendored Browser Harness Python package, CDP daemon, IPC bridge, admin commands, and helper functions
15
+ browser/interaction-skills/: Reusable Browser Harness mechanics guides for browser interactions
16
+ browser/agent-workspace/: Seed workspace copied to .nanopencil/browser-workspace for editable helpers and domain skills
17
+ 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
+ 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
+ link-world/network-routing.md: Routing skill that tells models when to use web_search/web_fetch/link-world versus browser automation
20
+ link-world/agent-workspace/: Seed workspace copied to .nanopencil/link-world-workspace for project-local domain skills and notes
12
21
  mcp/index.ts: MCP protocol integration extension, MCP guidance resources
13
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
14
23
  plan/index.ts: Plan Mode extension entry, /plan /plan:validate /plan:approve commands, EnterPlanMode/ExitPlanMode tools, permission gating, TUI status/widget, workflow prompt injection
@@ -52,18 +61,20 @@ sal/eval/noop-sink.ts: noopSink — silent EvalSink used when eval disabled or n
52
61
  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
53
62
  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
54
63
  sal/README.md: SAL extension usage, sidecar output layout, weights override, pluggability contract
55
- team/index.ts: AgentTeam extension entry, /team <task>, /team:spawn/:preset/:send/:status/:progress/:psyche/:dashboard/:stop/:terminate/:approve/:mode commands, TEAM_MESSAGE_TYPE renderer, realtime status/dashboard updates
56
- team/team-types.ts: TeammateRole/TeammateMode/TeammateStatus/HarnessState/PsycheWeights/TeammateLiveState/TeammateIdentity/TeammateMessage/PersistedTeammate/TeamSpawnSpec/TeamSendResult types
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
65
+ team/team-types.ts: TeammateRole/TeammateMode/TeammateStatus/TeamTask/HarnessState/PsycheWeights/TeamUtterance/Handoff/LeaderPlan/AgentLiveView/TeammateIdentity/PersistedTeammate/TeamSpawnSpec/TeamSendResult types
57
66
  team/team-state-store.ts: TeamStateStore class - durable teammate persistence via JSON files in <agentDir>/teams/
58
67
  team/team-parser.ts: Team command parser - parseTeamCommand/buildTeamHelp for /team:* subcommands
59
- team/team-runtime.ts: TeamRuntime class - teammate registry, lifecycle, realtime status/live events, mailbox + permission + transcript wiring
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
69
+ team/team-orchestrator.ts: Leader orchestration helpers - plan building, speaker utterance creation, @mention parsing, and handoff execution
70
+ team/team-task-store.ts: TeamTaskStore class - durable shared task list in <storageDir>/tasks.json
60
71
  team/team-harness.ts: Harness protocol helpers - context files, phase instructions, checkpoint/revert, feature validation
61
72
  team/team-presets.ts: Preset definitions and executor - solo/duo/squad spawning, model-assisted auto team selection, heuristic fallback
62
- team/team-dashboard.ts: Text dashboard/status rendering - teammate cards, live stream preview, progress bars, footer summary
63
- team/team-psyche.ts: Psyche prompt layer - role/phase weighted Id/Ego/Superego prompt construction
64
- team/team-permissions.ts: PermissionStore - pending permission request queue, approve/deny, path allowlists
65
- team/team-mailbox.ts: TeamMailbox - typed append-only message log for leader↔teammate
66
- team/team-transcript.ts: TeamTranscriptWriter - per-teammate JSONL transcripts
73
+ team/team-dashboard.ts: Text dashboard/status rendering - teammate workbench cards, current task, last utterance, progress bars, footer summary
74
+ team/team-psyche.ts: Psyche prompt layer - role/phase weighted Id/Ego/Superego prompt construction
75
+ team/team-permissions.ts: PermissionStore - pending permission request queue, approve/deny, path allowlists
76
+ team/team-mailbox.ts: TeamMailbox - typed JSONL-backed append-only message log for leader↔teammate and teammate↔teammate
77
+ team/team-transcript.ts: TeamTranscriptWriter - per-teammate JSONL transcripts
67
78
  team/TESTING.md: Manual & smoke-test guide for Phase B AgentTeam
68
79
 
69
80
  Rule: Members complete, one item per line, parent links valid, precise terms first
@@ -0,0 +1,17 @@
1
+ # extensions/defaults/browser/
2
+
3
+ > P2 | Parent: ../AGENT.md
4
+
5
+ Member List
6
+ index.ts: Browser Harness extension entry, registers browser/browser_admin tools, /browser command, Browser Harness resource discovery for core/interaction/domain skills, project-local browser workspace seeding
7
+ browser.md: Browser Harness day-to-day skill instructions for NanoPencil tool use and workspace contribution
8
+ install.md: Browser Harness setup and troubleshooting instructions, exposed as a skill resource
9
+ src/browser_harness/: Vendored Browser Harness Python package, CDP daemon, IPC bridge, admin commands, and helper functions
10
+ src/browser_harness/AGENT.md: P2 module map for the vendored Browser Harness Python package
11
+ interaction-skills/: Reusable Browser Harness mechanics guides for tabs, screenshots, iframes, cookies, uploads, dialogs, scrolling, and related browser interactions
12
+ agent-workspace/: Seed workspace copied to .nanopencil/browser-workspace for editable helpers and domain skills
13
+ .env.example: Browser Harness environment variable template for Browser Use cloud integration
14
+
15
+ Rule: Members complete, one item per line, parent links valid, precise terms first
16
+
17
+ [COVENANT]: Update this file header on changes and verify against parent AGENT.md