@trim21/personal-pi-extensions 0.1.621 → 0.1.624

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trim21/personal-pi-extensions",
3
- "version": "0.1.621",
3
+ "version": "0.1.624",
4
4
  "type": "module",
5
5
  "description": "Custom pi coding-agent extensions: bwrap sandbox, workspace guard, opencode edit, and more",
6
6
  "keywords": [
package/src/aft/config.ts CHANGED
@@ -24,7 +24,7 @@ import { parseWithSchema } from "../lib/parse-with-schema.js";
24
24
  /** aft 侧走 HTTP embeddings 端点的后端;fastembed(本地 ONNX)有意排除在外。 */
25
25
  const REMOTE_SEMANTIC_BACKENDS = ["openai_compatible", "ollama"] as const;
26
26
 
27
- export type RemoteSemanticBackend = (typeof REMOTE_SEMANTIC_BACKENDS)[number];
27
+ type RemoteSemanticBackend = (typeof REMOTE_SEMANTIC_BACKENDS)[number];
28
28
 
29
29
  /** 就绪的外部 embedding 后端:类型受支持且配了 base_url。 */
30
30
  export interface SemanticRemote {
package/src/aft/tools.ts CHANGED
@@ -61,7 +61,7 @@ export interface AftToolContext {
61
61
  getState(): AftState;
62
62
  }
63
63
 
64
- export function bridgeFor(ctx: AftToolContext): AftProjectTransport {
64
+ function bridgeFor(ctx: AftToolContext): AftProjectTransport {
65
65
  return ctx.getState().pool.pool.getBridge(ctx.cwd);
66
66
  }
67
67
 
@@ -79,7 +79,7 @@ export function compactArgs(args: Record<string, unknown>): Record<string, unkno
79
79
  }
80
80
 
81
81
  /** 人类视角的调用记录:input params + 与 LLM 相同的输出结果。 */
82
- export function buildPendantMarkdown(params: {
82
+ function buildPendantMarkdown(params: {
83
83
  title: string;
84
84
  input: unknown;
85
85
  output: string;
@@ -327,7 +327,7 @@ const CALLGRAPH_SOFT_CODES = new Set(["symbol_not_found", "callgraph_building"])
327
327
  * 以及冷构建本身超过内联窗口。这里在扩展侧重试,预算耗尽才把 building
328
328
  * 文本交给模型。
329
329
  */
330
- export const CALLGRAPH_BUILD_RETRY_BUDGET_MS = 90_000;
330
+ const CALLGRAPH_BUILD_RETRY_BUDGET_MS = 90_000;
331
331
  const CALLGRAPH_BUILD_RETRY_INTERVAL_MS = 3_000;
332
332
 
333
333
  export async function callCallgraphWithBuildRetry(
@@ -434,7 +434,7 @@ interface StatusSubscribableBridge {
434
434
  * 运行时能力探测:`AftProjectTransport` 接口没声明 subscribeStatus,但实际实现
435
435
  * (BinaryBridge)有。用 in 收窄做真检查,而不是断言成「一定支持」。
436
436
  */
437
- export function isStatusSubscribable(
437
+ function isStatusSubscribable(
438
438
  bridge: AftProjectTransport,
439
439
  ): bridge is AftProjectTransport & StatusSubscribableBridge {
440
440
  return "subscribeStatus" in bridge && typeof bridge.subscribeStatus === "function";
package/src/bwrap/core.ts CHANGED
@@ -85,7 +85,7 @@ const bwrapConfigProperties = {
85
85
 
86
86
  // 配置文件容忍未知字段:schema 之外的字段(如新版本扩展新增的配置)会被忽略,
87
87
  // 避免整个 bwrap 配置因单个未知字段失效;已声明字段仍做类型/取值校验。
88
- export const bwrapConfigSchema = Type.Object(bwrapConfigProperties, {
88
+ const bwrapConfigSchema = Type.Object(bwrapConfigProperties, {
89
89
  additionalProperties: true,
90
90
  });
91
91
 
@@ -18,7 +18,9 @@ function tap0Exists() {
18
18
  }
19
19
  async function waitFor(attempts, delayMs, predicate) {
20
20
  for (let i = 0; i < attempts; i++) {
21
- if (await predicate()) return true;
21
+ if (await predicate()) {
22
+ return true;
23
+ }
22
24
  await sleep(delayMs);
23
25
  }
24
26
  return false;
@@ -31,7 +31,7 @@ export interface NetworkStackOptions {
31
31
  readonly onHolderOutput?: (chunk: string) => void;
32
32
  }
33
33
 
34
- export interface NetworkStackExecOptions {
34
+ interface NetworkStackExecOptions {
35
35
  readonly command: string;
36
36
  readonly cwd: string;
37
37
  readonly bwrapPath: string;
@@ -368,7 +368,7 @@ export function describeSandbox(
368
368
  * 状态块不再附——提权请求刚被用户拒绝,再提示 dangerouslyDisableSandbox 只会
369
369
  * 诱导重复请求,作用域描述由本提醒承担。
370
370
  */
371
- export function describeSandboxChoice(resolved: ResolvedBwrap): string {
371
+ function describeSandboxChoice(resolved: ResolvedBwrap): string {
372
372
  return [
373
373
  "<system-reminder>",
374
374
  `The user ran this command in the sandbox instead of approving unsandboxed execution: ${describeLimits(resolved)}.`,
@@ -71,7 +71,7 @@ const IMAGE_MIMES = new Map<string, string>([
71
71
  [".webp", "image/webp"],
72
72
  ]);
73
73
 
74
- export interface FileToolDetails {
74
+ interface FileToolDetails {
75
75
  diff?: string;
76
76
  patch?: string;
77
77
  firstChangedLine?: number;
@@ -16,7 +16,6 @@ export function registerSearchTools(pi: ExtensionAPI): void {
16
16
  registerGrepTool(pi);
17
17
  }
18
18
 
19
- // Re-exported for tests and other modules that import pure functions from
20
- // "./search.js"; the implementations live in the split files above.
21
- export { globFiles } from "./glob.js";
19
+ // Re-exported for tests that import pure functions from "./search.js"; the
20
+ // implementations live in the split files above.
22
21
  export { buildGrepArguments, pageGrepOutput } from "./grep.js";
@@ -34,7 +34,7 @@ const todoSchema = Type.Object(
34
34
  { additionalProperties: false },
35
35
  );
36
36
 
37
- export type ClaudeCodeTodo = Static<typeof todoItemSchema>;
37
+ type ClaudeCodeTodo = Static<typeof todoItemSchema>;
38
38
 
39
39
  const optionSchema = Type.Object(
40
40
  {
@@ -72,7 +72,7 @@ function appendTruncationNotice(
72
72
  * 截断时追加 `[Showing lines X-Y of N. Full output: path]` 提示。
73
73
  * opencode 套件的 bash 工具复用同一逻辑。
74
74
  */
75
- export function formatBashSuccess(result: Awaited<ReturnType<BwrapRuntime["execute"]>>): {
75
+ function formatBashSuccess(result: Awaited<ReturnType<BwrapRuntime["execute"]>>): {
76
76
  content: { type: "text"; text: string }[];
77
77
  details: BashToolDetails | undefined;
78
78
  } {
package/src/lib/cli.ts CHANGED
@@ -39,7 +39,7 @@ import { shlexSplit } from "./cli-args.js";
39
39
  import { isRecord, isUnknownArray } from "./narrow.js";
40
40
 
41
41
  /** Per-flag CLI metadata on top of the typebox schema. */
42
- export interface FlagMeta {
42
+ interface FlagMeta {
43
43
  /** Optional short alias (single character), e.g. "n" for `-n`. */
44
44
  short?: string;
45
45
  /** Help line for this flag; defaults to the schema `description`. */
@@ -86,7 +86,7 @@ export async function readStateKey(filePath: string): Promise<string> {
86
86
  }
87
87
  }
88
88
 
89
- export function snapshotsEqual(left: FileSnapshot, right: FileSnapshot): boolean {
89
+ function snapshotsEqual(left: FileSnapshot, right: FileSnapshot): boolean {
90
90
  return left.digest === right.digest;
91
91
  }
92
92
 
package/src/lib/github.ts CHANGED
@@ -254,7 +254,7 @@ function ghAuthToken(): Promise<string> {
254
254
  * Error thrown when the GitHub search API rejects the request. Carries the
255
255
  * original toolcall params so the model can see the exact input.
256
256
  */
257
- export class GithubSearchError extends Error {
257
+ class GithubSearchError extends Error {
258
258
  readonly params: SearchParams;
259
259
  readonly status: number | undefined;
260
260
 
@@ -279,7 +279,7 @@ function describeHttpError(status: number | undefined): string {
279
279
  return `GitHub API error${status === undefined ? "" : ` (HTTP ${status})`}`;
280
280
  }
281
281
 
282
- export interface GithubApi {
282
+ interface GithubApi {
283
283
  /** Run an octokit request; retries once with a fresh token on 401. */
284
284
  call<T>(fn: (octokit: Octokit) => Promise<T>): Promise<T>;
285
285
  }
@@ -299,7 +299,7 @@ export interface GithubClientOptions {
299
299
  * module-level state. A stale cached token can produce 401s; the cache is
300
300
  * dropped and the request retried once in that case.
301
301
  */
302
- export function createGithubApi(options: GithubClientOptions = {}): GithubApi {
302
+ function createGithubApi(options: GithubClientOptions = {}): GithubApi {
303
303
  let client: Octokit | undefined;
304
304
 
305
305
  async function getClient(): Promise<Octokit> {
@@ -400,7 +400,7 @@ export interface ActionJob {
400
400
  }
401
401
 
402
402
  /** One step of a workflow run job, as the REST API reports it. */
403
- export interface RunJobStep {
403
+ interface RunJobStep {
404
404
  readonly name: string;
405
405
  readonly number: number;
406
406
  readonly status: string;
@@ -48,7 +48,7 @@ export const WATCH_KIND_DELETE = 4;
48
48
  const WATCH_KIND_ALL = WATCH_KIND_CREATE | WATCH_KIND_CHANGE | WATCH_KIND_DELETE;
49
49
 
50
50
  /** 服务器通过 client/registerCapability 注册的单个 watcher。 */
51
- export interface WatcherGlob {
51
+ interface WatcherGlob {
52
52
  pattern: string;
53
53
  kind: number;
54
54
  }
@@ -168,7 +168,7 @@ interface PrepareRenameResponse {
168
168
  }
169
169
 
170
170
  /** renameSymbol 的请求与结果(line / character 为 0-based LSP position)。 */
171
- export interface RenameSymbolRequest {
171
+ interface RenameSymbolRequest {
172
172
  path: string;
173
173
  line: number;
174
174
  character: number;
@@ -177,14 +177,14 @@ export interface RenameSymbolRequest {
177
177
  signal?: AbortSignal;
178
178
  }
179
179
 
180
- export interface RenameSymbolResult {
180
+ interface RenameSymbolResult {
181
181
  edit: WorkspaceEdit;
182
182
  /** prepareRename 返回的符号当前名;服务器未提供 prepare 时缺省。 */
183
183
  placeholder?: string;
184
184
  }
185
185
 
186
186
  /** definition / references / hover 请求的输入(line / character 为 0-based LSP position)。 */
187
- export interface InspectPositionRequest {
187
+ interface InspectPositionRequest {
188
188
  path: string;
189
189
  line: number;
190
190
  character: number;
@@ -272,7 +272,7 @@ function describeStartupFailure(
272
272
  return parts.join("; ");
273
273
  }
274
274
 
275
- export class InitializeError extends Error {
275
+ class InitializeError extends Error {
276
276
  readonly serverID: string;
277
277
  constructor(serverID: string, cause: unknown, detail?: string) {
278
278
  super(`Failed to initialize LSP server ${serverID}${detail ? `: ${detail}` : ""}`, { cause });
@@ -103,7 +103,7 @@ export type LspConfig = Static<typeof lspConfigSchema>;
103
103
  * 解析期缺省(单一来源)。超时/LRU 与 client.create 共用 clientDefaults;
104
104
  * watch 无 client 对应项,数值在此集中。
105
105
  */
106
- export const configDefaults = {
106
+ const configDefaults = {
107
107
  watch: {
108
108
  enabled: true,
109
109
  debounceMs: 300,
@@ -119,7 +119,7 @@ const RETRY_COOLDOWN_MS = 60_000;
119
119
  const NOTIFY_INTERVAL_MS = 5 * 60_000;
120
120
 
121
121
  /** 生效的工作区监听配置(缺省值已应用)。 */
122
- export interface EffectiveWatchConfig {
122
+ interface EffectiveWatchConfig {
123
123
  enabled: boolean;
124
124
  debounceMs: number;
125
125
  flushMs: number;
@@ -388,21 +388,21 @@ interface LspState {
388
388
  }
389
389
 
390
390
  /** 渲染 LSP status 文本的回调(传入 undefined 表示清除)。 */
391
- export type StatusRenderer = (text: string | undefined) => void;
391
+ type StatusRenderer = (text: string | undefined) => void;
392
392
 
393
- export type LspInspectQuery = "definition" | "references" | "hover";
393
+ type LspInspectQuery = "definition" | "references" | "hover";
394
394
 
395
395
  /**
396
396
  * 返回类型与 query 关联:query 为 "hover" 时返回 hover 内容,否则返回位置列表。
397
397
  * 关联由 `inspect` 的重载签名建立(泛型参数下 TS 无法验证分支与返回体的对应关系,
398
398
  * 所以接口按 query 分重载,实现体只需返回这个联合)。
399
399
  */
400
- export type LspInspectResult<Q extends LspInspectQuery = LspInspectQuery> = Q extends "hover"
400
+ type LspInspectResult<Q extends LspInspectQuery = LspInspectQuery> = Q extends "hover"
401
401
  ? { serverID: string; query: "hover"; hover: Hover | null }
402
402
  : { serverID: string; query: "definition" | "references"; locations: InspectLocation[] };
403
403
 
404
404
  /** 只读符号查询的入参:query 决定返回体(见 LspInspectResult)。line / character 为 0-based。 */
405
- export interface LspInspectRequest<Q extends LspInspectQuery = LspInspectQuery> {
405
+ interface LspInspectRequest<Q extends LspInspectQuery = LspInspectQuery> {
406
406
  file: string;
407
407
  cwd: string;
408
408
  line: number;
@@ -411,7 +411,7 @@ export interface LspInspectRequest<Q extends LspInspectQuery = LspInspectQuery>
411
411
  options?: LspRequestOptions;
412
412
  }
413
413
 
414
- export interface LspRequestOptions {
414
+ interface LspRequestOptions {
415
415
  notify?: ExtensionUIContext["notify"];
416
416
  /** 中止时提前结束诊断等待(已中止时直接跳过诊断)。 */
417
417
  signal?: AbortSignal;
@@ -196,7 +196,7 @@ export function canonicalizeEdit(edit: WorkspaceEdit): string {
196
196
  const WORD_PATTERN = /[\p{L}\p{N}_$]+/gu;
197
197
 
198
198
  /** 两个路径集合是否一致(用于判断 references 结果是否收敛)。 */
199
- export function samePathSet(a: ReadonlySet<string>, b: ReadonlySet<string>): boolean {
199
+ function samePathSet(a: ReadonlySet<string>, b: ReadonlySet<string>): boolean {
200
200
  if (a.size !== b.size) {
201
201
  return false;
202
202
  }
@@ -36,7 +36,7 @@ export interface FileChange {
36
36
  isDirectory: boolean;
37
37
  }
38
38
 
39
- export const DEFAULT_IGNORE = [
39
+ const DEFAULT_IGNORE = [
40
40
  "**/node_modules/**",
41
41
  "**/.git/**",
42
42
  "**/dist/**",
package/src/lib/path.ts CHANGED
@@ -73,7 +73,7 @@ export function formatDisplayPath(cwd: string, filePath: string): string {
73
73
  }
74
74
 
75
75
  /** subtitle 中路径的最大显示长度,超过时退化为 `parent/basename`。 */
76
- export const MAX_SUBTITLE_PATH_LENGTH = 30;
76
+ const MAX_SUBTITLE_PATH_LENGTH = 30;
77
77
 
78
78
  function shortenSubtitlePath(filePath: string, display: string): string {
79
79
  if (display.length <= MAX_SUBTITLE_PATH_LENGTH) {
package/src/lib/proxy.ts CHANGED
@@ -37,7 +37,7 @@ export interface HttpProxySettings {
37
37
  noProxy?: string;
38
38
  }
39
39
 
40
- export function proxyConfigPath(): string {
40
+ function proxyConfigPath(): string {
41
41
  return join(homedir(), ".pi", "agent", "proxy.json");
42
42
  }
43
43
 
@@ -89,7 +89,7 @@ function normalizeProxy(value: string): string {
89
89
  * 这里是仓库里允许的同步例外)。文件不存在 = 未配置;文件读不了、JSON 非法或
90
90
  * 字段不符都直接抛。
91
91
  */
92
- export function readProxySettings(
92
+ function readProxySettings(
93
93
  configPath: string = proxyConfigPath(),
94
94
  env: NodeJS.ProcessEnv = process.env,
95
95
  ): HttpProxySettings {
@@ -20,7 +20,7 @@ export const REQUEST_POLICY_CHANNEL = "bwrap:request-policy";
20
20
 
21
21
  const requestPolicyMessageSchema = Type.Object({ denyRequests: Type.Boolean() });
22
22
 
23
- export type RequestPolicyMessage = Static<typeof requestPolicyMessageSchema>;
23
+ type RequestPolicyMessage = Static<typeof requestPolicyMessageSchema>;
24
24
 
25
25
  export interface RequestPolicy {
26
26
  /** 是否拒绝一切非沙盒请求(不弹审批框,直接拒绝)。 */
@@ -9,9 +9,9 @@ import { join } from "node:path";
9
9
  import { type Static, Type } from "typebox";
10
10
  import { Value } from "typebox/value";
11
11
 
12
- export const DEFAULT_PROVIDER_ID = "openai-cost";
13
- export const DEFAULT_PROVIDER_NAME = "OpenAI Cost";
14
- export const DEFAULT_API_KEY_ENV = "OPENAI_COST_API_KEY";
12
+ const DEFAULT_PROVIDER_ID = "openai-cost";
13
+ const DEFAULT_PROVIDER_NAME = "OpenAI Cost";
14
+ const DEFAULT_API_KEY_ENV = "OPENAI_COST_API_KEY";
15
15
  export const DEFAULT_CONTEXT_WINDOW = 128000;
16
16
  export const DEFAULT_MAX_TOKENS = 8192;
17
17
  export const ZERO_COST = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 } as const;
@@ -54,7 +54,7 @@ export interface OpenaiCostConfig {
54
54
  models?: OpenaiCostModelConfig[];
55
55
  }
56
56
 
57
- export function openaiCostConfigPath(): string {
57
+ function openaiCostConfigPath(): string {
58
58
  return join(homedir(), ".pi", "agent", "openai-cost.json");
59
59
  }
60
60
 
@@ -98,7 +98,7 @@ export function costFromSseLine(line: string): number | undefined {
98
98
  }
99
99
  }
100
100
 
101
- export async function scanSseCost(body: ReadableStream<Uint8Array>): Promise<number | undefined> {
101
+ async function scanSseCost(body: ReadableStream<Uint8Array>): Promise<number | undefined> {
102
102
  const reader = body.getReader();
103
103
  const decoder = new TextDecoder();
104
104
  let buffer = "";
@@ -196,7 +196,7 @@ function messageOf(event: AssistantMessageEvent): AssistantMessage {
196
196
  return event.partial;
197
197
  }
198
198
 
199
- export function applyCostToEvent(
199
+ function applyCostToEvent(
200
200
  event: AssistantMessageEvent,
201
201
  reported: number | undefined,
202
202
  ): AssistantMessageEvent {
@@ -200,7 +200,7 @@ function isBinaryFileBySample(sample: Uint8Array): boolean {
200
200
  return nonPrintableCount / sample.length > 0.3;
201
201
  }
202
202
 
203
- export interface TruncationResult {
203
+ interface TruncationResult {
204
204
  content: string;
205
205
  truncated: boolean;
206
206
  truncatedBy: "lines" | "bytes" | null;
@@ -872,7 +872,7 @@ function registerWriteTool(
872
872
 
873
873
  // ── 入口 ─────────────────────────────────────────────────────────────────────
874
874
 
875
- export function registerFileTools(
875
+ function registerFileTools(
876
876
  pi: ExtensionAPI,
877
877
  getService: () => LspService,
878
878
  policy: RequestPolicy,
@@ -130,7 +130,7 @@ export function renderGrepOutput(matches: readonly GrepMatch[], truncated: boole
130
130
  }
131
131
 
132
132
  /** 搜索根:绝对路径原样,相对路径按调用 cwd 解析。 */
133
- export function resolveSearchRoot(path: string | undefined, cwd: string): string {
133
+ function resolveSearchRoot(path: string | undefined, cwd: string): string {
134
134
  if (path === undefined || path === "") {
135
135
  return cwd;
136
136
  }
@@ -2,9 +2,7 @@
2
2
  * opencode —— 统一注册 opencode 风格工具扩展。
3
3
  *
4
4
  * 聚合 files(read / edit / write 统一构建,共享 LSP service)、grep /
5
- * glob(ripgrep 搜索)、todo / question / bash,一次加载全部注册;各工具的
6
- * 公开 API(匹配引擎、纯函数等)也从这里重新导出,方便测试与其他模块
7
- * (如 lib/write-guard)引用。
5
+ * glob(ripgrep 搜索)、todo / question / bash,一次加载全部注册。
8
6
  *
9
7
  * Usage:
10
8
  * pi -e ./opencode/index.ts
@@ -24,28 +22,6 @@ import opencodeGrep from "./grep.js";
24
22
  import opencodeQuestion from "./question.js";
25
23
  import opencodeTodo from "./todo.js";
26
24
 
27
- export { default as opencodeBash } from "./bash.js";
28
- export {
29
- applyEdit,
30
- convertToLineEnding,
31
- detectLineEnding,
32
- normalizeForEdit,
33
- normalizeToLF,
34
- replace,
35
- restoreLineEndings,
36
- stripBom,
37
- } from "./edit-engine.js";
38
- export {
39
- default as opencodeFileTools,
40
- readLines,
41
- resolveBom,
42
- type TruncationResult,
43
- } from "./files.js";
44
- export { default as opencodeGlob } from "./glob.js";
45
- export { default as opencodeGrep } from "./grep.js";
46
- export { default as opencodeQuestion } from "./question.js";
47
- export { default as opencodeTodo } from "./todo.js";
48
-
49
25
  export default function opencode(pi: ExtensionAPI) {
50
26
  // 非沙盒请求策略由本入口创建,注入文件工具与 bash runtime 共享同一份;
51
27
  // 独立入口(web/fetch.ts 等)各自创建一份并经 pi.events 保持同步。
@@ -35,7 +35,7 @@ export const CUSTOM_LABEL = "Type your own answer.";
35
35
  export const DONE_LABEL = "✓ Done";
36
36
 
37
37
  /** 与 opencode question.txt 语义一致的描述 */
38
- export const QUESTION_DESCRIPTION = [
38
+ const QUESTION_DESCRIPTION = [
39
39
  "Use this tool when you need to ask the user questions during execution. This allows you to:",
40
40
  "1. Gather user preferences or requirements",
41
41
  "2. Clarify ambiguous instructions",
@@ -68,8 +68,6 @@ export const questionParamsSchema = Type.Object({
68
68
 
69
69
  // ── types ────────────────────────────────────────────────────────────────────
70
70
 
71
- export type QuestionOption = Static<typeof optionSchema>;
72
-
73
71
  /** 与 schema 对齐的输入形状(multiple 可选) */
74
72
  export type QuestionInput = Static<typeof questionSchema>;
75
73
 
@@ -32,14 +32,13 @@ import { type ToolPendant } from "../lib/pendant.js";
32
32
 
33
33
  export const TOOL_NAME = "todowrite";
34
34
 
35
- export const TODO_STATUSES = ["pending", "in_progress", "completed", "cancelled"] as const;
36
- export const TODO_PRIORITIES = ["high", "medium", "low"] as const;
35
+ const TODO_STATUSES = ["pending", "in_progress", "completed", "cancelled"] as const;
36
+ const TODO_PRIORITIES = ["high", "medium", "low"] as const;
37
37
 
38
- export type TodoStatus = (typeof TODO_STATUSES)[number];
39
- export type TodoPriority = (typeof TODO_PRIORITIES)[number];
38
+ type TodoStatus = (typeof TODO_STATUSES)[number];
40
39
 
41
40
  /** opencode 的 todowrite 描述(语义等价),补上「整体替换」这一关键规则 */
42
- export const TODOWRITE_DESCRIPTION = [
41
+ const TODOWRITE_DESCRIPTION = [
43
42
  "Create and maintain a structured task list for the current coding session. Tracks progress, organizes multi-step work, and surfaces status to the user.",
44
43
  "",
45
44
  "This tool REPLACES the entire todo list: pass the full updated list of todos on every call.",
@@ -35,7 +35,7 @@ export function formatDelivery(letter: Letter, now: number = Date.now()): string
35
35
  /** One agent as the model sees it in a listing. `id` is the stable pi
36
36
  * agent uuid; `name` is the display name when one was set; `self` marks
37
37
  * the calling agent itself. */
38
- export interface AgentListItem {
38
+ interface AgentListItem {
39
39
  status: string;
40
40
  work_dir: string;
41
41
  id: string;
package/src/talk/group.ts CHANGED
@@ -20,7 +20,7 @@ import { Value } from "typebox/value";
20
20
 
21
21
  import type { TalkStorage } from "./storage.js";
22
22
 
23
- export const GroupSchema = Type.Object({
23
+ const GroupSchema = Type.Object({
24
24
  id: Type.String(),
25
25
  /** pi agent uuids of the members. */
26
26
  members: Type.Array(Type.String()),
@@ -29,7 +29,7 @@ export const GroupSchema = Type.Object({
29
29
  });
30
30
  export type Group = Static<typeof GroupSchema>;
31
31
 
32
- export const GROUPS_NS = "groups";
32
+ const GROUPS_NS = "groups";
33
33
 
34
34
  /**
35
35
  * Group names are user-facing and become storage keys, so they are
@@ -38,7 +38,7 @@ export const GROUPS_NS = "groups";
38
38
  */
39
39
  const GROUP_ID_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$/;
40
40
 
41
- export function assertGroupId(id: string): void {
41
+ function assertGroupId(id: string): void {
42
42
  if (!GROUP_ID_PATTERN.test(id)) {
43
43
  throw new TypeError(`Invalid group name: ${id}`);
44
44
  }
@@ -22,7 +22,7 @@ import { isRecord } from "../lib/narrow.js";
22
22
  import { asksNs, assertAddress, inboxNs } from "./registry.js";
23
23
  import type { TalkStorage } from "./storage.js";
24
24
 
25
- export const LetterSchema = Type.Object({
25
+ const LetterSchema = Type.Object({
26
26
  id: Type.String(),
27
27
  from: Type.Object({
28
28
  addr: Type.String(),
@@ -48,7 +48,7 @@ export type LetterKind = Letter["kind"];
48
48
  * sender's pi session id as `from.sessionId`. Current letters pass through
49
49
  * unchanged; anything else returns null.
50
50
  */
51
- export function normalizeLetter(value: unknown): Letter | null {
51
+ function normalizeLetter(value: unknown): Letter | null {
52
52
  if (Value.Check(LetterSchema, value)) {
53
53
  return value;
54
54
  }
@@ -69,7 +69,7 @@ export function normalizeLetter(value: unknown): Letter | null {
69
69
  return Value.Check(LetterSchema, migrated) ? migrated : null;
70
70
  }
71
71
 
72
- export const OutAskSchema = Type.Object({
72
+ const OutAskSchema = Type.Object({
73
73
  askId: Type.String(),
74
74
  toAddr: Type.String(),
75
75
  body: Type.String(),
@@ -77,7 +77,7 @@ export const OutAskSchema = Type.Object({
77
77
  });
78
78
  export type OutAsk = Static<typeof OutAskSchema>;
79
79
 
80
- export const AuditRecordSchema = Type.Object({
80
+ const AuditRecordSchema = Type.Object({
81
81
  ts: Type.Number(),
82
82
  event: Type.Union([
83
83
  Type.Literal("deposit"),
@@ -112,7 +112,7 @@ function assertMessageId(id: string): void {
112
112
  }
113
113
 
114
114
  /** The storage key for a letter: `<ts>-<id>.json`, sorted oldest-first. */
115
- export function letterFileName(letter: Letter): string {
115
+ function letterFileName(letter: Letter): string {
116
116
  assertMessageId(letter.id);
117
117
  if (!Number.isSafeInteger(letter.ts) || letter.ts < 0) {
118
118
  throw new TypeError(`Invalid talk letter timestamp: ${letter.ts}`);
@@ -121,7 +121,7 @@ export function letterFileName(letter: Letter): string {
121
121
  }
122
122
 
123
123
  /** Structural validation plus filename safety (id/timestamp shape). */
124
- export function isValidLetter(value: unknown): value is Letter {
124
+ function isValidLetter(value: unknown): value is Letter {
125
125
  if (!Value.Check(LetterSchema, value)) {
126
126
  return false;
127
127
  }
@@ -8,9 +8,9 @@
8
8
 
9
9
  import { MAX_BODY_CHARS } from "./mailbox.js";
10
10
 
11
- export const DEDUPE_WINDOW_MS = 10_000;
12
- export const RATE_LIMIT_MAX = 8;
13
- export const RATE_LIMIT_WINDOW_MS = 30_000;
11
+ const DEDUPE_WINDOW_MS = 10_000;
12
+ const RATE_LIMIT_MAX = 8;
13
+ const RATE_LIMIT_WINDOW_MS = 30_000;
14
14
  export const BACKLOG_CAP = 50;
15
15
 
16
16
  export type OutboundVerdict = { ok: true } | { ok: false; reason: string };
@@ -32,7 +32,7 @@ const STATUS_SCHEMA = Type.Union([
32
32
  Type.Literal("waiting-talk-message"),
33
33
  ]);
34
34
 
35
- export const AgentRecordSchema = Type.Object({
35
+ const AgentRecordSchema = Type.Object({
36
36
  addr: Type.String(),
37
37
  agentId: Type.String(),
38
38
  name: Type.String(),
@@ -69,9 +69,9 @@ const LegacyAgentRecordSchema = Type.Object({
69
69
  export type Presence = "live" | "offline";
70
70
 
71
71
  /** Sweep leaves a record alone until its last activity was this long ago. */
72
- export const SWEEP_OFFLINE_GRACE_MS = 24 * 60 * 60 * 1000;
72
+ const SWEEP_OFFLINE_GRACE_MS = 24 * 60 * 60 * 1000;
73
73
  /** A mailbox holding undelivered mail is kept this long after last contact. */
74
- export const SWEEP_MAIL_KEEP_MS = 30 * 24 * 60 * 60 * 1000;
74
+ const SWEEP_MAIL_KEEP_MS = 30 * 24 * 60 * 60 * 1000;
75
75
 
76
76
  const ADDRESS_PATTERN = /^[a-f0-9]{12}$/;
77
77
 
@@ -88,7 +88,7 @@ export function assertAddress(addr: string): void {
88
88
 
89
89
  // ── Storage namespaces ───────────────────────────────────────────────────
90
90
 
91
- export const RECORDS_NS = "records";
91
+ const RECORDS_NS = "records";
92
92
 
93
93
  export function inboxNs(addr: string): string {
94
94
  assertAddress(addr);
package/src/web/config.ts CHANGED
@@ -13,7 +13,7 @@ const webSearchSchema = Type.Object({
13
13
  search1apiApiKey: Type.Optional(Type.String()),
14
14
  });
15
15
 
16
- export function webSearchConfigPath(): string {
16
+ function webSearchConfigPath(): string {
17
17
  return join(homedir(), ".pi", "web-search.json");
18
18
  }
19
19