@pencil-agent/nano-pencil 2.0.0-beta.0 → 2.0.0-beta.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.
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "2.0.0-beta.0",
3
- "commitHash": "5ad87db",
2
+ "version": "2.0.0-beta.2",
3
+ "commitHash": "4afe936",
4
4
  "branch": "refactor/arch-candidate-d",
5
- "builtAt": "2026-06-05T10:02:01.628Z"
5
+ "builtAt": "2026-06-05T15:33:54.463Z"
6
6
  }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * [WHO]: Barrel for @pencil-agent/extension-sdk — the stable protocol surface for extensions
3
+ * [FROM]: Re-exports the per-protocol modules (tools + lifecycle today; themes/hooks/commands/permissions in later P3 checkpoints)
4
+ * [TO]: Consumed by third-party extensions, packages/mem-core, packages/soul-core, and the host (adopting these contracts)
5
+ * [HERE]: packages/extension-sdk/src/index.ts - extension-sdk public entry
6
+ *
7
+ * Scope (this round / P3): tools (S1), lifecycle (ExtensionAPI/ExtensionContext/SessionManagerContract, S3),
8
+ * then themes/hooks/commands/permissions. Explicitly NOT here (EVOLUTION-RESERVED): agent-profile,
9
+ * host-adapter, tool-runtime, a2a-bridge, memory/soul providers — see evolution/PARP.md.
10
+ */
11
+ export * from "./tools.js";
12
+ export * from "./lifecycle.js";
@@ -0,0 +1,12 @@
1
+ /**
2
+ * [WHO]: Barrel for @pencil-agent/extension-sdk — the stable protocol surface for extensions
3
+ * [FROM]: Re-exports the per-protocol modules (tools + lifecycle today; themes/hooks/commands/permissions in later P3 checkpoints)
4
+ * [TO]: Consumed by third-party extensions, packages/mem-core, packages/soul-core, and the host (adopting these contracts)
5
+ * [HERE]: packages/extension-sdk/src/index.ts - extension-sdk public entry
6
+ *
7
+ * Scope (this round / P3): tools (S1), lifecycle (ExtensionAPI/ExtensionContext/SessionManagerContract, S3),
8
+ * then themes/hooks/commands/permissions. Explicitly NOT here (EVOLUTION-RESERVED): agent-profile,
9
+ * host-adapter, tool-runtime, a2a-bridge, memory/soul providers — see evolution/PARP.md.
10
+ */
11
+ export * from "./tools.js";
12
+ export * from "./lifecycle.js";
@@ -0,0 +1,73 @@
1
+ /**
2
+ * [WHO]: Provides ExtensionAPI, ExtensionContext, ExtensionFactory, ExtensionUi, ExtensionCommand,
3
+ * SessionManagerContract, HookEventName, HookHandler — the extension lifecycle protocol
4
+ * [FROM]: No dependencies — minimal structural protocol owned by extension-sdk (S3 dependency-inversion target)
5
+ * [TO]: Consumed by packages/mem-core (extension adapter) and third-party extensions; the host's
6
+ * richer ExtensionContext/ExtensionAPI satisfy these structurally (extensions load dynamically)
7
+ * [HERE]: packages/extension-sdk/src/lifecycle.ts - the stable extension entry contract
8
+ *
9
+ * Scope note: event payloads are intentionally loose (HookHandler's event is `unknown`) this round;
10
+ * per-event typed payloads land in hooks.ts during P3.1. This file carries only the surface that
11
+ * lets a host-agnostic extension (e.g. mem-core) compile against the SDK instead of the host package.
12
+ */
13
+ import type { TSchema } from "@sinclair/typebox";
14
+ import type { ToolContract } from "./tools.js";
15
+ /** Read-only session info an extension may consult via `ctx.sessionManager`. */
16
+ export interface SessionManagerContract {
17
+ /** Absolute path to the active session's JSONL file, if any. */
18
+ getSessionFile(): string | undefined;
19
+ /** Count sessions under `cwd` whose file mtime is newer than `sinceMs`. */
20
+ countTouchedSince(cwd: string, sinceMs: number, options?: {
21
+ sessionDir?: string;
22
+ excludeBasename?: string;
23
+ concurrency?: number;
24
+ }): Promise<number>;
25
+ }
26
+ /** UI affordances available to an extension (no-ops / undefined-safe when `hasUI` is false). */
27
+ export interface ExtensionUi {
28
+ /** Surface a transient message to the user. */
29
+ notify(message: string, type?: "info" | "warning" | "error"): void;
30
+ /** Set (or clear with `undefined`) a keyed status line owned by this extension. */
31
+ setStatus(key: string, text: string | undefined): void;
32
+ }
33
+ /** Runtime context handed to extension hooks, commands, and tools. */
34
+ export interface ExtensionContext {
35
+ /** Current working directory. */
36
+ cwd: string;
37
+ /** Whether an interactive UI is attached (false in print/RPC mode). */
38
+ hasUI: boolean;
39
+ /** Read-only session manager. */
40
+ sessionManager: SessionManagerContract;
41
+ /** User-facing UI affordances. */
42
+ ui: ExtensionUi;
43
+ }
44
+ /** Lifecycle hook names an extension may subscribe to via `api.on(...)`. */
45
+ export type HookEventName = "session_start" | "session_ready" | "session_shutdown" | "before_agent_start" | "agent_start" | "agent_end" | "agent_result" | "turn_start" | "turn_end" | "tool_execution_start" | "tool_execution_end";
46
+ /**
47
+ * Hook callback. The event payload is intentionally `any` this round so host-agnostic
48
+ * extensions compile without per-event payload types; typed payloads land in hooks.ts (P3.1).
49
+ */
50
+ export type HookHandler = (event: any, ctx: ExtensionContext) => void | Promise<void>;
51
+ /** A slash command an extension registers via `api.registerCommand(...)`. */
52
+ export interface ExtensionCommand {
53
+ /** Help text shown in command lists. */
54
+ description?: string;
55
+ /** Optional argument-completion provider. */
56
+ getArgumentCompletions?: (argumentPrefix: string) => Array<{
57
+ value: string;
58
+ label: string;
59
+ }> | null;
60
+ /** Command body. `args` is the raw argument string (may be empty/undefined). */
61
+ handler: (args: string | undefined, ctx: ExtensionContext) => void | Promise<void>;
62
+ }
63
+ /** The registration surface a host passes to an extension factory. */
64
+ export interface ExtensionAPI {
65
+ /** Subscribe to a lifecycle hook. */
66
+ on(event: HookEventName, handler: HookHandler): void;
67
+ /** Register a slash command. */
68
+ registerCommand(name: string, command: ExtensionCommand): void;
69
+ /** Register a model-facing tool. Generic so each call infers its own parameter schema. */
70
+ registerTool<TParams extends TSchema = TSchema, TDetails = unknown>(tool: ToolContract<TParams, TDetails>): void;
71
+ }
72
+ /** An extension's default export: receives the host API and wires up hooks/commands/tools. */
73
+ export type ExtensionFactory = (api: ExtensionAPI) => void;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * [WHO]: Provides ExtensionAPI, ExtensionContext, ExtensionFactory, ExtensionUi, ExtensionCommand,
3
+ * SessionManagerContract, HookEventName, HookHandler — the extension lifecycle protocol
4
+ * [FROM]: No dependencies — minimal structural protocol owned by extension-sdk (S3 dependency-inversion target)
5
+ * [TO]: Consumed by packages/mem-core (extension adapter) and third-party extensions; the host's
6
+ * richer ExtensionContext/ExtensionAPI satisfy these structurally (extensions load dynamically)
7
+ * [HERE]: packages/extension-sdk/src/lifecycle.ts - the stable extension entry contract
8
+ *
9
+ * Scope note: event payloads are intentionally loose (HookHandler's event is `unknown`) this round;
10
+ * per-event typed payloads land in hooks.ts during P3.1. This file carries only the surface that
11
+ * lets a host-agnostic extension (e.g. mem-core) compile against the SDK instead of the host package.
12
+ */
13
+ export {};
@@ -0,0 +1,77 @@
1
+ /**
2
+ * [WHO]: Provides ToolRuntime, ToolPermissions, ToolRuntimeDescriptor (S1 seam) + ToolResult, ToolContract
3
+ * [FROM]: Depends on @sinclair/typebox (schema) and ./lifecycle (ExtensionContext, type-only)
4
+ * [TO]: Consumed by the host ToolDefinition (adopts the S1 fields) and by extensions registering tools
5
+ * [HERE]: packages/extension-sdk/src/tools.ts - tool runtime seam (S1) + the stable tool contract
6
+ *
7
+ * S1 seam (refactor-plan §接缝预留): a tool may optionally declare its execution runtime and
8
+ * permission needs. Omitting both keeps today's behavior (local, host-policy). The host
9
+ * ToolOrchestrator stays the single dispatch point; browser/remote/mcp runtimes are NOT
10
+ * implemented this round — only the contract shape is reserved so adding them is additive.
11
+ */
12
+ import type { Static, TSchema } from "@sinclair/typebox";
13
+ import type { ExtensionContext } from "./lifecycle.js";
14
+ /** Where a tool's execute() runs. Omitted ⇒ "local" (in the host process). */
15
+ export type ToolRuntime = "local" | "mcp" | "remote" | "browser";
16
+ /** Declarative permission requirements a tool may request; the host decides enforcement. */
17
+ export interface ToolPermissions {
18
+ /** Filesystem paths the tool intends to read / write, if constrained. */
19
+ filesystem?: {
20
+ read?: string[];
21
+ write?: string[];
22
+ };
23
+ /** Whether the tool may spawn shell/processes. */
24
+ process?: boolean;
25
+ /** Network hosts the tool may reach, if constrained. */
26
+ network?: string[];
27
+ }
28
+ /** S1 seam: optional runtime/permission descriptors a tool definition may carry. */
29
+ export interface ToolRuntimeDescriptor {
30
+ /** Execution runtime. Omitted ⇒ "local". */
31
+ runtime?: ToolRuntime;
32
+ /** Declared permissions. Omitted ⇒ unconstrained (host policy applies). */
33
+ permissions?: ToolPermissions;
34
+ }
35
+ /** A single content block a tool returns. */
36
+ export type ToolResultContent = {
37
+ type: "text";
38
+ text: string;
39
+ } | {
40
+ type: "image";
41
+ data: string;
42
+ mimeType?: string;
43
+ };
44
+ /** The result of executing a tool. */
45
+ export interface ToolResult<TDetails = unknown> {
46
+ /** Model-facing content blocks. */
47
+ content: ToolResultContent[];
48
+ /** Structured details for custom rendering / downstream use. */
49
+ details?: TDetails;
50
+ /** Whether this result represents an error. */
51
+ isError?: boolean;
52
+ }
53
+ /** Callback a tool may invoke to stream partial progress. */
54
+ export type ToolUpdateCallback<TDetails = unknown> = (details: TDetails) => void;
55
+ /**
56
+ * The stable tool contract an extension registers. The host's richer ToolDefinition is a
57
+ * superset (adds renderCall/renderResult and tighter agent-core result types); a contract
58
+ * authored against this interface remains valid there because extensions load dynamically.
59
+ */
60
+ export interface ToolContract<TParams extends TSchema = TSchema, TDetails = unknown> extends ToolRuntimeDescriptor {
61
+ /** Tool name used in LLM tool calls. */
62
+ name: string;
63
+ /** Human-readable label for UI. */
64
+ label?: string;
65
+ /** Description for the model. */
66
+ description: string;
67
+ /** Parameter schema (TypeBox). */
68
+ parameters: TParams;
69
+ /** Alternative model-facing names accepted for compatibility. */
70
+ aliases?: string[];
71
+ /** Whether the tool can safely run alongside other concurrency-safe tools. */
72
+ isConcurrencySafe?: boolean;
73
+ /** Optional usage guidance injected into the system prompt. */
74
+ guidance?: string;
75
+ /** Execute the tool. Trailing parameters are optional for simple tools. */
76
+ execute(toolCallId: string, params: Static<TParams>, signal?: AbortSignal, onUpdate?: ToolUpdateCallback<TDetails>, ctx?: ExtensionContext): Promise<ToolResult<TDetails>>;
77
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * [WHO]: Provides ToolRuntime, ToolPermissions, ToolRuntimeDescriptor (S1 seam) + ToolResult, ToolContract
3
+ * [FROM]: Depends on @sinclair/typebox (schema) and ./lifecycle (ExtensionContext, type-only)
4
+ * [TO]: Consumed by the host ToolDefinition (adopts the S1 fields) and by extensions registering tools
5
+ * [HERE]: packages/extension-sdk/src/tools.ts - tool runtime seam (S1) + the stable tool contract
6
+ *
7
+ * S1 seam (refactor-plan §接缝预留): a tool may optionally declare its execution runtime and
8
+ * permission needs. Omitting both keeps today's behavior (local, host-policy). The host
9
+ * ToolOrchestrator stays the single dispatch point; browser/remote/mcp runtimes are NOT
10
+ * implemented this round — only the contract shape is reserved so adding them is additive.
11
+ */
12
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pencil-agent/nano-pencil",
3
- "version": "2.0.0-beta.0",
3
+ "version": "2.0.0-beta.2",
4
4
  "description": "CLI writing agent with read, bash, edit, write tools and session management. Supports DashScope and Ali Token Plan. Soul enabled by default for AI personality evolution.",
5
5
  "type": "module",
6
6
  "bin": {