pi-code 1.0.0 → 1.0.1

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/README.md CHANGED
@@ -13,6 +13,8 @@
13
13
 
14
14
  Claude Code experience for the [pi](https://pi.dev) coding agent, in one package. Point pi at a project that already has a `.claude/` directory and it reads your existing config: rules, commands, skills, hooks, output styles, MCP servers, and agents. It also adds the Claude Code features pi lacks: a todo overlay, checkpoints, memory, web search, and subagents.
15
15
 
16
+ What a repository ships is treated as untrusted until you approve it: project MCP servers, hooks, agents, rules, output styles, commands and skills load only once you say yes.
17
+
16
18
  ![pi-code demo](demos/hero.gif)
17
19
 
18
20
  ## Install
@@ -42,12 +44,12 @@ One `pi install` and everything below loads on the next start. `pi list` shows w
42
44
  | Output styles | `.claude/output-styles` + active `outputStyle`; Claude replace semantics with `keep-coding-instructions`; bundled Explanatory/Learning/Proactive; `/output-style [name]` | `output-styles.ts` |
43
45
  | CLAUDE.md `@imports` | resolves `@path` imports pi's native loader skips; loads `CLAUDE.local.md` (approval-gated) | `context-imports.ts` |
44
46
  | MCP servers | user `~/.claude.json` (incl. per-project `projects[cwd]` local scope), `~/.pi/agent/mcp.json`; project `.mcp.json`, `.pi/mcp.json` (once approved; `enabledMcpjsonServers`/`disabledMcpjsonServers`/`enableAllProjectMcpServers` honored, consent keys only from non-repo settings); stdio/HTTP/SSE by `type`; `${VAR:-default}` expansion; `MCP_TIMEOUT`/`MCP_TOOL_TIMEOUT`; tools refresh on `list_changed` | `mcp.ts` |
45
- | Project trust | prompts before loading project config (MCP servers, hooks, agents, rules, output styles) that pi would otherwise trust silently | `internal/project-approval.ts` |
47
+ | Project trust | prompts before loading project config (MCP servers, hooks, agents, rules, output styles, commands, skills) that pi would otherwise trust silently | `internal/project-approval.ts` |
46
48
  | Subagents / Task | builtin Explore/Plan/general-purpose agents, `~/.claude/agents` and `~/.pi/agent/agents`, plus project `.claude/agents` and `.pi/agents`; agent roster with descriptions in the system prompt; `skills` preload; background runs with cancel and resume | `subagent/` |
47
49
  | Plan mode | `plan_mode_complete` tool, exact tool snapshot/restore | `plan-mode/` |
48
50
  | Todo list | persistent overlay, status machine, compaction-safe | `todo.ts` |
49
- | Checkpoints / rewind | shadow-repo snapshots; restore overwrites checkpointed files, keeps files created later | `git-checkpoint.ts` |
50
- | Persistent memory | per-project memories, index injected each session | `memory.ts` |
51
+ | Checkpoints / rewind | shadow-repo snapshots; restore overwrites checkpointed files, keeps files created later; 100 per session, repos pruned after 30 days | `git-checkpoint.ts` |
52
+ | Persistent memory | per-project memories, index injected each session within Claude's 200-line/25KB bound; a save that would overflow it reports why | `memory.ts` |
51
53
  | WebSearch / WebFetch | key-free DuckDuckGo search, SSRF-guarded fetch | `web.ts` |
52
54
  | AskUserQuestion | 1-4 questions per call (asked in sequence), each with `header`, single- or `multiSelect` options, plus free-text | `question.ts` |
53
55
  | Statusline | Claude `statusLine` command contract (stdin JSON, `padding`, `refreshInterval`); built-in turn state + session cost fallback | `status-line.ts` |
@@ -34,7 +34,7 @@ const OptionSchema = Type.Object({
34
34
 
35
35
  const SingleQuestion = Type.Object({
36
36
  question: Type.String({ description: 'The question to ask the user' }),
37
- header: Type.Optional(Type.String({ description: 'Short label for the question, shown above it (max 12 characters)', maxLength: 12 })),
37
+ header: Type.Optional(Type.String({ description: 'Short label for the question, shown above it, kept to 12 characters' })),
38
38
  options: Type.Array(OptionSchema, { description: 'Options for the user to choose from (1-4)', minItems: 1, maxItems: 4 }),
39
39
  multiSelect: Type.Optional(Type.Boolean({ description: 'Allow selecting several options (space toggles, enter confirms)' })),
40
40
  })
@@ -45,7 +45,7 @@ const SingleQuestion = Type.Object({
45
45
  export const QuestionParams = Type.Object({
46
46
  question: Type.Optional(Type.String({ description: 'The question to ask. Required, unless asking several via questions.' })),
47
47
  options: Type.Optional(Type.Array(OptionSchema, { description: 'The 1-4 choices for this question, each {label, description?}. Required with question.', minItems: 1, maxItems: 4 })),
48
- header: Type.Optional(Type.String({ description: 'Optional short label shown above the question (max 12 characters)', maxLength: 12 })),
48
+ header: Type.Optional(Type.String({ description: 'Optional short label shown above the question, kept to 12 characters' })),
49
49
  multiSelect: Type.Optional(Type.Boolean({ description: 'Optional: allow selecting several options (space toggles, enter confirms)' })),
50
50
  questions: Type.Optional(Type.Array(SingleQuestion, { description: 'Only to ask 2-4 questions in one call: each entry takes the same fields as above. Leave unset for a single question.', minItems: 1, maxItems: 4 })),
51
51
  })
@@ -60,10 +60,16 @@ export interface QuestionSpec {
60
60
  /** Normalize either accepted shape into the list of questions to ask. */
61
61
  export function questionList(params: Partial<QuestionSpec> & { questions?: QuestionSpec[] }): QuestionSpec[] {
62
62
  if (params.questions && params.questions.length > 0) return params.questions
63
- if (typeof params.question === 'string') return [{ question: params.question, header: params.header, options: params.options ?? [], multiSelect: params.multiSelect }]
63
+ if (typeof params.question === 'string') return [{ question: params.question, header: shortHeader(params.header), options: params.options ?? [], multiSelect: params.multiSelect }]
64
64
  return []
65
65
  }
66
66
 
67
+ /** Claude keeps a header short for the label slot. Truncating is the forgiving read:
68
+ * rejecting the call costs a turn while the model recovers from a validation error,
69
+ * which is a poor trade for a display detail. */
70
+ export const HEADER_MAX = 12
71
+ export const shortHeader = (header: string | undefined): string | undefined => (header === undefined ? undefined : header.slice(0, HEADER_MAX))
72
+
67
73
  function checkbox(checked: boolean | undefined): string {
68
74
  if (checked === undefined) return ''
69
75
  return checked ? '[x] ' : '[ ] '
@@ -320,7 +326,7 @@ async function askOne(params: QuestionSpec, ctx: ExtensionContext): Promise<{ co
320
326
  function render(width: number): string[] {
321
327
  if (cachedLines && cachedWidth === width) return cachedLines
322
328
  cachedWidth = width
323
- cachedLines = buildQuestionLines({ width, question: params.question, header: params.header, options: allOptions, optionIndex, editMode, multiSelect, checked, editor, theme })
329
+ cachedLines = buildQuestionLines({ width, question: params.question, header: shortHeader(params.header), options: allOptions, optionIndex, editMode, multiSelect, checked, editor, theme })
324
330
  return cachedLines
325
331
  }
326
332
 
@@ -337,7 +343,7 @@ async function askOne(params: QuestionSpec, ctx: ExtensionContext): Promise<{ co
337
343
  // Build simple options list for details; header/multiSelect appear only when set,
338
344
  // so single-select details are unchanged.
339
345
  const simpleOptions = params.options.map((o) => o.label)
340
- const base = { question: params.question, options: simpleOptions, ...(params.header ? { header: params.header } : {}), ...(multiSelect ? { multiSelect: true } : {}) }
346
+ const base = { question: params.question, options: simpleOptions, ...(params.header ? { header: shortHeader(params.header) } : {}), ...(multiSelect ? { multiSelect: true } : {}) }
341
347
 
342
348
  if (!result) {
343
349
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-code",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Claude Code experience for the pi coding agent: reads your .claude config (rules, commands, skills, hooks, output styles, MCP servers, agents) and adds todo, checkpoints, memory, web, and subagents",
5
5
  "keywords": [
6
6
  "pi",