@docyrus/docyrus 0.0.33 → 0.0.35

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 (67) hide show
  1. package/README.md +25 -0
  2. package/agent-loader.js +3 -2
  3. package/agent-loader.js.map +2 -2
  4. package/main.js +82252 -46058
  5. package/main.js.map +4 -4
  6. package/package.json +12 -3
  7. package/resources/chrome-tools/browser-content.js +46 -46
  8. package/resources/chrome-tools/browser-cookies.js +16 -16
  9. package/resources/chrome-tools/browser-eval.js +27 -27
  10. package/resources/chrome-tools/browser-hn-scraper.js +1 -1
  11. package/resources/chrome-tools/browser-nav.js +23 -23
  12. package/resources/chrome-tools/browser-pick.js +127 -127
  13. package/resources/chrome-tools/browser-screenshot.js +10 -10
  14. package/resources/chrome-tools/browser-start.js +38 -38
  15. package/resources/pi-agent/extensions/answer.ts +392 -384
  16. package/resources/pi-agent/extensions/context.ts +415 -415
  17. package/resources/pi-agent/extensions/control.ts +1287 -1287
  18. package/resources/pi-agent/extensions/diff.ts +171 -171
  19. package/resources/pi-agent/extensions/files.ts +155 -155
  20. package/resources/pi-agent/extensions/knowledge.ts +664 -0
  21. package/resources/pi-agent/extensions/loop.ts +375 -375
  22. package/resources/pi-agent/extensions/pi-bash-live-view/index.ts +1 -1
  23. package/resources/pi-agent/extensions/pi-bash-live-view/package.json +22 -22
  24. package/resources/pi-agent/extensions/pi-bash-live-view/pty-execute.ts +2 -2
  25. package/resources/pi-agent/extensions/pi-bash-live-view/pty-session.ts +2 -2
  26. package/resources/pi-agent/extensions/pi-bash-live-view/spawn-helper.ts +2 -2
  27. package/resources/pi-agent/extensions/pi-bash-live-view/terminal-emulator.ts +18 -18
  28. package/resources/pi-agent/extensions/pi-bash-live-view/truncate.ts +1 -1
  29. package/resources/pi-agent/extensions/pi-bash-live-view/widget.ts +4 -4
  30. package/resources/pi-agent/extensions/pi-custom-compaction/package.json +4 -4
  31. package/resources/pi-agent/extensions/pi-mcp-adapter/app-bridge.bundle.js +14 -14
  32. package/resources/pi-agent/extensions/pi-mcp-adapter/commands.ts +6 -6
  33. package/resources/pi-agent/extensions/pi-mcp-adapter/config.ts +9 -9
  34. package/resources/pi-agent/extensions/pi-mcp-adapter/consent-manager.ts +4 -4
  35. package/resources/pi-agent/extensions/pi-mcp-adapter/direct-tools.ts +13 -13
  36. package/resources/pi-agent/extensions/pi-mcp-adapter/glimpse-ui.ts +5 -5
  37. package/resources/pi-agent/extensions/pi-mcp-adapter/host-html-template.ts +13 -13
  38. package/resources/pi-agent/extensions/pi-mcp-adapter/index.ts +14 -14
  39. package/resources/pi-agent/extensions/pi-mcp-adapter/init.ts +17 -17
  40. package/resources/pi-agent/extensions/pi-mcp-adapter/lifecycle.ts +2 -2
  41. package/resources/pi-agent/extensions/pi-mcp-adapter/logger.ts +2 -2
  42. package/resources/pi-agent/extensions/pi-mcp-adapter/mcp-panel.ts +17 -17
  43. package/resources/pi-agent/extensions/pi-mcp-adapter/metadata-cache.ts +9 -9
  44. package/resources/pi-agent/extensions/pi-mcp-adapter/npx-resolver.ts +35 -35
  45. package/resources/pi-agent/extensions/pi-mcp-adapter/oauth-handler.ts +1 -1
  46. package/resources/pi-agent/extensions/pi-mcp-adapter/proxy-modes.ts +12 -12
  47. package/resources/pi-agent/extensions/pi-mcp-adapter/server-manager.ts +6 -6
  48. package/resources/pi-agent/extensions/pi-mcp-adapter/tool-metadata.ts +4 -4
  49. package/resources/pi-agent/extensions/pi-mcp-adapter/types.ts +2 -2
  50. package/resources/pi-agent/extensions/pi-mcp-adapter/ui-resource-handler.ts +6 -6
  51. package/resources/pi-agent/extensions/pi-mcp-adapter/ui-server.ts +17 -17
  52. package/resources/pi-agent/extensions/pi-mcp-adapter/ui-session.ts +22 -22
  53. package/resources/pi-agent/extensions/pi-mcp-adapter/utils.ts +2 -2
  54. package/resources/pi-agent/extensions/prompt-editor.ts +900 -900
  55. package/resources/pi-agent/extensions/prompt-url-widget.ts +122 -122
  56. package/resources/pi-agent/extensions/redraws.ts +14 -14
  57. package/resources/pi-agent/extensions/review.ts +1533 -1533
  58. package/resources/pi-agent/extensions/todos.ts +1735 -1735
  59. package/resources/pi-agent/extensions/tps.ts +40 -40
  60. package/resources/pi-agent/extensions/whimsical.ts +3 -3
  61. package/resources/pi-agent/prompts/agent-system.md +2 -0
  62. package/resources/pi-agent/prompts/coder-system.md +2 -0
  63. package/resources/pi-agent/skills/officecli/SKILL.md +113 -0
  64. package/server-loader.js +82 -1
  65. package/server-loader.js.map +3 -3
  66. package/tui.mjs +2 -0
  67. package/tui.mjs.map +1 -1
@@ -2,46 +2,46 @@ import type { AssistantMessage } from "@mariozechner/pi-ai";
2
2
  import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
3
3
 
4
4
  function isAssistantMessage(message: unknown): message is AssistantMessage {
5
- if (!message || typeof message !== "object") return false;
6
- const role = (message as { role?: unknown }).role;
7
- return role === "assistant";
5
+ if (!message || typeof message !== "object") {return false;}
6
+ const role = (message as { role?: unknown }).role;
7
+ return role === "assistant";
8
8
  }
9
9
 
10
- export default function (pi: ExtensionAPI) {
11
- let agentStartMs: number | null = null;
12
-
13
- pi.on("agent_start", () => {
14
- agentStartMs = Date.now();
15
- });
16
-
17
- pi.on("agent_end", (event, ctx) => {
18
- if (!ctx.hasUI) return;
19
- if (agentStartMs === null) return;
20
-
21
- const elapsedMs = Date.now() - agentStartMs;
22
- agentStartMs = null;
23
- if (elapsedMs <= 0) return;
24
-
25
- let input = 0;
26
- let output = 0;
27
- let cacheRead = 0;
28
- let cacheWrite = 0;
29
- let totalTokens = 0;
30
-
31
- for (const message of event.messages) {
32
- if (!isAssistantMessage(message)) continue;
33
- input += message.usage.input || 0;
34
- output += message.usage.output || 0;
35
- cacheRead += message.usage.cacheRead || 0;
36
- cacheWrite += message.usage.cacheWrite || 0;
37
- totalTokens += message.usage.totalTokens || 0;
38
- }
39
-
40
- if (output <= 0) return;
41
-
42
- const elapsedSeconds = elapsedMs / 1000;
43
- const tokensPerSecond = output / elapsedSeconds;
44
- const message = `TPS ${tokensPerSecond.toFixed(1)} tok/s. out ${output.toLocaleString()}, in ${input.toLocaleString()}, cache r/w ${cacheRead.toLocaleString()}/${cacheWrite.toLocaleString()}, total ${totalTokens.toLocaleString()}, ${elapsedSeconds.toFixed(1)}s`;
45
- ctx.ui.notify(message, "info");
46
- });
10
+ export default function(pi: ExtensionAPI) {
11
+ let agentStartMs: number | null = null;
12
+
13
+ pi.on("agent_start", () => {
14
+ agentStartMs = Date.now();
15
+ });
16
+
17
+ pi.on("agent_end", (event, ctx) => {
18
+ if (!ctx.hasUI) {return;}
19
+ if (agentStartMs === null) {return;}
20
+
21
+ const elapsedMs = Date.now() - agentStartMs;
22
+ agentStartMs = null;
23
+ if (elapsedMs <= 0) {return;}
24
+
25
+ let input = 0;
26
+ let output = 0;
27
+ let cacheRead = 0;
28
+ let cacheWrite = 0;
29
+ let totalTokens = 0;
30
+
31
+ for (const message of event.messages) {
32
+ if (!isAssistantMessage(message)) {continue;}
33
+ input += message.usage.input || 0;
34
+ output += message.usage.output || 0;
35
+ cacheRead += message.usage.cacheRead || 0;
36
+ cacheWrite += message.usage.cacheWrite || 0;
37
+ totalTokens += message.usage.totalTokens || 0;
38
+ }
39
+
40
+ if (output <= 0) {return;}
41
+
42
+ const elapsedSeconds = elapsedMs / 1000;
43
+ const tokensPerSecond = output / elapsedSeconds;
44
+ const message = `TPS ${tokensPerSecond.toFixed(1)} tok/s. out ${output.toLocaleString()}, in ${input.toLocaleString()}, cache r/w ${cacheRead.toLocaleString()}/${cacheWrite.toLocaleString()}, total ${totalTokens.toLocaleString()}, ${elapsedSeconds.toFixed(1)}s`;
45
+ ctx.ui.notify(message, "info");
46
+ });
47
47
  }
@@ -463,12 +463,12 @@ function pickRandom(): string {
463
463
  return messages[Math.floor(Math.random() * messages.length)];
464
464
  }
465
465
 
466
- export default function (pi: ExtensionAPI) {
467
- pi.on("turn_start", async (_event, ctx) => {
466
+ export default function(pi: ExtensionAPI) {
467
+ pi.on("turn_start", async(_event, ctx) => {
468
468
  ctx.ui.setWorkingMessage(pickRandom());
469
469
  });
470
470
 
471
- pi.on("turn_end", async (_event, ctx) => {
471
+ pi.on("turn_end", async(_event, ctx) => {
472
472
  ctx.ui.setWorkingMessage(); // Reset for next time
473
473
  });
474
474
  }
@@ -7,6 +7,8 @@ Core behavior:
7
7
  - Prefer the local `docyrus` CLI for Docyrus operations instead of guessing undocumented HTTP endpoints.
8
8
  - When you need structured command output, prefer `--json`.
9
9
  - Start by inspecting real tenant state before making claims about apps, data sources, users, environments, auth state, or API shape.
10
+ - If the repository contains `docyrus/knowledge/`, use `docyrus knowledge search`, `docyrus knowledge section`, and `docyrus knowledge expand` before broader repo exploration.
11
+ - When `docyrus/knowledge/` exists, keep it updated and finish local work with `docyrus knowledge check`.
10
12
  - Use the installed Docyrus skills as your command and workflow reference.
11
13
  - Be careful with tenant-scoped mutations. Confirm real identifiers and current context before changing state.
12
14
  - Treat auth files, tokens, and `.docyrus` contents as sensitive.
@@ -18,6 +18,8 @@ Core behavior:
18
18
 
19
19
  - Use repository files and coding tools for implementation work.
20
20
  - Use the local `docyrus` CLI for Docyrus platform state, tenant context, schema inspection, app and data-source operations, API discovery, and data verification.
21
+ - If the repository contains `docyrus/knowledge/`, use `docyrus knowledge search`, `docyrus knowledge section`, and `docyrus knowledge expand` before coding so you start from documented repo intent rather than only source inspection.
22
+ - When `docyrus/knowledge/` exists, keep it in sync with behavior changes and finish with `docyrus knowledge check`.
21
23
  - Prefer `--json` whenever command output needs to be parsed, compared, or fed back into reasoning.
22
24
  - Start from real state before making claims about apps, data sources, users, fields, enums, environments, auth state, API shape, or deployment context.
23
25
  - Distinguish clearly between local code changes and remote Docyrus platform mutations.
@@ -0,0 +1,113 @@
1
+ ---
2
+ name: officecli
3
+ description: Use OfficeCLI to create, inspect, validate, and modify Office documents (.docx, .xlsx, .pptx) from the terminal. Use when the user wants Office document automation, extraction, validation, or editing.
4
+ ---
5
+
6
+ # OfficeCLI
7
+
8
+ OfficeCLI is available in Docyrus pi sessions as a local command-line tool for Word, Excel, and PowerPoint files.
9
+
10
+ Use the CLI directly in this environment. Do not run `officecli mcp ...` unless the user explicitly asks to register OfficeCLI with another editor or agent.
11
+
12
+ ## First Principles
13
+
14
+ - Prefer structured output by adding `--json` whenever you need to inspect or transform results.
15
+ - Work from higher-level commands down:
16
+ - L1 read and inspection: `view`, `get`, `query`, `validate`
17
+ - L2 DOM edits: `set`, `add`, `remove`, `move`, `batch`
18
+ - L3 raw XML fallback: `raw`, `raw-set`, `add-part`
19
+ - When unsure about element names, property names, or allowed value formats, run help instead of guessing.
20
+ - After making changes, run `officecli validate <file>` and, when useful, `officecli view <file> issues`.
21
+ - For multi-step edits on a single file, use `open` and `close` to keep the document in memory.
22
+
23
+ ## Verify Availability
24
+
25
+ ```bash
26
+ officecli --version
27
+ officecli --help
28
+ ```
29
+
30
+ If a command fails unexpectedly, inspect the help for the specific document type before trying alternatives.
31
+
32
+ ## Help-First Workflow
33
+
34
+ ```bash
35
+ officecli docx set
36
+ officecli docx set paragraph
37
+ officecli xlsx set cell.value
38
+ officecli pptx add chart
39
+ officecli pptx query
40
+ ```
41
+
42
+ Use the deepest help entry you already know. One help lookup is better than guessing and retrying.
43
+
44
+ ## Common Commands
45
+
46
+ Create a new document:
47
+
48
+ ```bash
49
+ officecli create report.docx
50
+ officecli create model.xlsx
51
+ officecli create deck.pptx
52
+ ```
53
+
54
+ Inspect document structure or extracted text:
55
+
56
+ ```bash
57
+ officecli view report.docx outline
58
+ officecli view report.docx text --max-lines 80
59
+ officecli view deck.pptx issues
60
+ officecli get deck.pptx /slide[1] --depth 1 --json
61
+ officecli query model.xlsx 'cell[value~=Revenue]' --json
62
+ ```
63
+
64
+ Modify content:
65
+
66
+ ```bash
67
+ officecli set report.docx /body/p[1] --prop style=Heading1 --prop text="Executive Summary"
68
+ officecli add deck.pptx / --type slide --prop title="Q4 Report"
69
+ officecli add deck.pptx /slide[1] --type shape --prop text="Revenue grew 25%" --prop x=2cm --prop y=5cm
70
+ officecli set model.xlsx /Sheet1/A1 --prop value="Name" --prop bold=true
71
+ ```
72
+
73
+ Batch related changes:
74
+
75
+ ```bash
76
+ echo '[{"command":"set","path":"/Sheet1/A1","props":{"value":"Name","bold":"true"}},{"command":"set","path":"/Sheet1/B1","props":{"value":"Score","bold":"true"}}]' | officecli batch model.xlsx --json
77
+ ```
78
+
79
+ Keep a document open for a longer edit session:
80
+
81
+ ```bash
82
+ officecli open report.docx
83
+ officecli set report.docx /body/p[2] --prop text="Updated paragraph"
84
+ officecli close report.docx
85
+ ```
86
+
87
+ ## Practical Guidance
88
+
89
+ - Prefer `view`, `get`, or `query` to understand the document before editing it.
90
+ - Use `query` to locate matching elements instead of hard-coding guessed paths.
91
+ - Keep outputs bounded for large files with flags such as `--max-lines`, `--start`, or `--end`.
92
+ - Path indexing is 1-based: `/body/p[3]` means the third paragraph.
93
+ - Use `batch` when several changes should be applied in one save cycle.
94
+ - Use `watch` for PowerPoint only when the user explicitly wants a live preview flow.
95
+
96
+ ## When Raw XML Is Appropriate
97
+
98
+ Only fall back to `raw` or `raw-set` when:
99
+
100
+ - the higher-level commands cannot express the change,
101
+ - you already inspected the target part with `get` or `raw`,
102
+ - and you are prepared to validate immediately afterwards.
103
+
104
+ ## Validation Checklist
105
+
106
+ After editing:
107
+
108
+ ```bash
109
+ officecli validate <file>
110
+ officecli view <file> issues
111
+ ```
112
+
113
+ If validation fails, fix the issue before presenting the result as complete.
package/server-loader.js CHANGED
@@ -723,6 +723,7 @@ var AgentEnvStore = class {
723
723
  constructor(filePath) {
724
724
  this.filePath = filePath;
725
725
  }
726
+ filePath;
726
727
  getFilePath() {
727
728
  return this.filePath;
728
729
  }
@@ -4059,6 +4060,9 @@ function validateProviderLoginInput(params) {
4059
4060
  if (field.required && !normalized) {
4060
4061
  return { ok: false, error: `Missing required field: ${field.name}` };
4061
4062
  }
4063
+ if (normalized && field.options && !field.options.some((option) => option.value === normalized)) {
4064
+ return { ok: false, error: `Invalid value for ${field.name}: ${normalized}` };
4065
+ }
4062
4066
  if (normalized) {
4063
4067
  values[field.name] = normalized;
4064
4068
  } else if (field.defaultValue) {
@@ -6521,6 +6525,60 @@ function parseServerLoaderRequest(payload) {
6521
6525
  return JSON.parse(payload);
6522
6526
  }
6523
6527
 
6528
+ // src/server/restrictedModelRegistry.ts
6529
+ var SERVER_MODE_ALLOWED_MODEL_IDS_BY_PROVIDER = {
6530
+ anthropic: [
6531
+ "claude-opus-4-6",
6532
+ "claude-sonnet-4-6",
6533
+ "claude-haiku-4-5"
6534
+ ],
6535
+ openai: [
6536
+ "gpt-5.4",
6537
+ "gpt-5.4-mini",
6538
+ "gpt-5.4-nano"
6539
+ ],
6540
+ "azure-openai-responses": [
6541
+ "gpt-5.4",
6542
+ "gpt-5.4-mini",
6543
+ "gpt-5.4-nano"
6544
+ ]
6545
+ };
6546
+ var ALLOWED_MODEL_IDS_BY_PROVIDER = Object.fromEntries(
6547
+ Object.entries(SERVER_MODE_ALLOWED_MODEL_IDS_BY_PROVIDER).map(([provider, modelIds]) => [provider, new Set(modelIds)])
6548
+ );
6549
+ function isServerSelectableModel(model) {
6550
+ const allowedModelIds = ALLOWED_MODEL_IDS_BY_PROVIDER[model.provider];
6551
+ if (!allowedModelIds) {
6552
+ return true;
6553
+ }
6554
+ return allowedModelIds.has(model.id);
6555
+ }
6556
+ function filterModels(models) {
6557
+ return models.filter((model) => isServerSelectableModel(model));
6558
+ }
6559
+ function createServerRestrictedModelRegistry(modelRegistry) {
6560
+ return new Proxy(modelRegistry, {
6561
+ get(target, property, receiver) {
6562
+ if (property === "getAll") {
6563
+ return () => filterModels(target.getAll());
6564
+ }
6565
+ if (property === "getAvailable") {
6566
+ return () => filterModels(target.getAvailable());
6567
+ }
6568
+ if (property === "find") {
6569
+ return (provider, modelId) => {
6570
+ if (!isServerSelectableModel({ provider, id: modelId })) {
6571
+ return void 0;
6572
+ }
6573
+ return target.find(provider, modelId);
6574
+ };
6575
+ }
6576
+ const value = Reflect.get(target, property, receiver);
6577
+ return typeof value === "function" ? value.bind(target) : value;
6578
+ }
6579
+ });
6580
+ }
6581
+
6524
6582
  // src/services/spinner.ts
6525
6583
  var import_picocolors = __toESM(require_picocolors());
6526
6584
  var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
@@ -6679,6 +6737,17 @@ function createServerSessionAdapter(params) {
6679
6737
  }
6680
6738
  };
6681
6739
  }
6740
+ async function ensureServerSelectableSessionModel(params) {
6741
+ const availableModels = params.modelRegistry.getAvailable();
6742
+ if (availableModels.length === 0) {
6743
+ return;
6744
+ }
6745
+ const currentModel = params.session.model;
6746
+ const currentModelIsSelectable = currentModel ? availableModels.some((model) => model.provider === currentModel.provider && model.id === currentModel.id) : false;
6747
+ if (!currentModelIsSelectable) {
6748
+ await params.session.setModel(availableModels[0]);
6749
+ }
6750
+ }
6682
6751
  async function main() {
6683
6752
  const request = readLoaderRequest();
6684
6753
  const pi = await loadPiExports();
@@ -6697,7 +6766,7 @@ async function main() {
6697
6766
  const authStorage = pi.AuthStorage.create((0, import_node_path7.join)(agentDir, "auth.json"));
6698
6767
  const settingsManager = pi.SettingsManager.create(cwd, agentDir);
6699
6768
  const modelsJsonPath = (0, import_node_path7.join)(agentDir, "models.json");
6700
- const modelRegistry = new pi.ModelRegistry(authStorage, modelsJsonPath);
6769
+ const modelRegistry = createServerRestrictedModelRegistry(pi.ModelRegistry.create(authStorage, modelsJsonPath));
6701
6770
  const quietStartup = !request.verbose;
6702
6771
  if (quietStartup) {
6703
6772
  process.env.PI_SKIP_VERSION_CHECK = "1";
@@ -6752,6 +6821,10 @@ async function main() {
6752
6821
  if (hasPackagedMcpAdapter) {
6753
6822
  extensionsResult.runtime.flagValues.set("mcp-config", mcpConfigPath);
6754
6823
  }
6824
+ await ensureServerSelectableSessionModel({
6825
+ session,
6826
+ modelRegistry
6827
+ });
6755
6828
  spinner.stop();
6756
6829
  if (!session.model) {
6757
6830
  throw new Error(
@@ -6799,6 +6872,10 @@ Or create ${modelsJsonPath}`
6799
6872
  model: requestedModel,
6800
6873
  thinkingLevel: request.thinking
6801
6874
  });
6875
+ await ensureServerSelectableSessionModel({
6876
+ session: freshSession,
6877
+ modelRegistry
6878
+ });
6802
6879
  return createServerSessionAdapter({
6803
6880
  session: freshSession,
6804
6881
  extensionsResult: freshExtensionsResult
@@ -6827,6 +6904,10 @@ Or create ${modelsJsonPath}`
6827
6904
  model: requestedModel,
6828
6905
  thinkingLevel: request.thinking
6829
6906
  });
6907
+ await ensureServerSelectableSessionModel({
6908
+ session: resumedSession,
6909
+ modelRegistry
6910
+ });
6830
6911
  return createServerSessionAdapter({
6831
6912
  session: resumedSession,
6832
6913
  extensionsResult: resumedExtensionsResult