@danypops/papyrus 0.59.2 → 0.60.0

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": "@danypops/papyrus",
3
- "version": "0.59.2",
3
+ "version": "0.60.0",
4
4
  "description": "Daemon-backed graph artifacts, evidence-bearing tasks, rules, skills, and native TUI workflows for Pi",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -57,9 +57,9 @@
57
57
  },
58
58
  "files": ["src", "README.md"],
59
59
  "dependencies": {
60
- "@danypops/vehicle-client": "^0.10.1",
60
+ "@danypops/vehicle-client": "^0.10.3",
61
61
  "@danypops/vehicle-core": "^0.17.1",
62
- "@danypops/vehicle-server": "^0.24.5",
62
+ "@danypops/vehicle-server": "^0.25.2",
63
63
  "@stricli/core": "^1.3.0"
64
64
  }
65
65
  }
package/src/constants.ts CHANGED
@@ -93,7 +93,7 @@ export const RULE_TEXT_HARD_LIMIT_CHARACTERS = 4000;
93
93
  /** Compact task-context limits keep recurring prompt injection bounded. */
94
94
  export const TASK_CONTEXT_CURRENT_LIMIT = 3;
95
95
  export const TASK_CONTEXT_REJECTED_LIMIT = 3;
96
- export const TASK_WIDGET_OPEN_LIMIT = 3;
96
+ export const TASK_WIDGET_OPEN_LIMIT = 9;
97
97
  export const TASK_DETAIL_MIN_VISIBLE_LINES = 8;
98
98
  /**
99
99
  * Event-triggered refresh (tool_execution_end, session_compact/tree) can't see a Task
@@ -103,6 +103,14 @@ export const TASK_DETAIL_MIN_VISIBLE_LINES = 8;
103
103
  export const TASK_WIDGET_POLL_INTERVAL_MS = 20_000;
104
104
  /** Same fallback purpose as TASK_WIDGET_POLL_INTERVAL_MS, for the Notes widget's own count. */
105
105
  export const NOTE_WIDGET_POLL_INTERVAL_MS = 20_000;
106
+ /** Max note titles kept for the Notes widget card. */
107
+ export const NOTE_WIDGET_OPEN_LIMIT = 8;
108
+ /** Visible rows per page in the Notes card. */
109
+ export const NOTE_WIDGET_VISIBLE_ROWS = 3;
110
+ /** Visible rows per page in the Tasks card. */
111
+ export const TASK_WIDGET_VISIBLE_ROWS = 3;
112
+ /** How often a paging widget card advances to its next page. */
113
+ export const WIDGET_CARD_ROTATION_INTERVAL_MS = 6_000;
106
114
  export const TASK_DETAIL_MAX_VISIBLE_LINES = 24;
107
115
  export const TASK_DETAIL_RESERVED_ROWS = 8;
108
116
  export const TASK_DETAIL_HORIZONTAL_PAN_COLUMNS = 4;
@@ -363,6 +371,12 @@ export function dbPath(): string {
363
371
  return `${xdg}/papyrus/papyrus.db`;
364
372
  }
365
373
 
374
+ /** $XDG_DATA_HOME/papyrus/metrics.sqlite -- vehicle-server's own tool/operation usage metrics store, sibling of dbPath() above. */
375
+ export function metricsPath(): string {
376
+ const xdg = process.env.XDG_DATA_HOME || `${process.env.HOME}/.local/share`;
377
+ return `${xdg}/papyrus/metrics.sqlite`;
378
+ }
379
+
366
380
  /**
367
381
  * The initial status a newly created artifact of a kind gets when no caller-supplied
368
382
  * status is given. This must be an explicit, named mapping — never derived from row order
@@ -3,9 +3,12 @@ import { join } from "node:path";
3
3
  import { createNodeAtomicJsonFsAdapter } from "@danypops/vehicle-server/atomic-json";
4
4
  import { readLaunchProvenance } from "@danypops/vehicle-server/daemon";
5
5
  import { diagnoseDaemon, openDaemonLifecycleLog } from "@danypops/vehicle-server/daemon-lifecycle";
6
+ import { openVehicleMetricsStore } from "@danypops/vehicle-server/metrics";
7
+ import { createVehicleMetricsMiddleware } from "@danypops/vehicle-server/metrics-middleware";
8
+ import { registerVehicleMetricsOperations } from "@danypops/vehicle-server/metrics-operations";
6
9
  import { acquireDaemonLock, releaseDaemonLock } from "@danypops/vehicle-server/paths";
7
10
  import { PushChannel } from "@danypops/vehicle-server/push-channel";
8
- import { DAEMON_HOST, DB_OPTIMIZE_INTERVAL_MS, dbPath, WAL_CHECKPOINT_INTERVAL_MS } from "../constants.ts";
11
+ import { DAEMON_HOST, DB_OPTIMIZE_INTERVAL_MS, dbPath, metricsPath, WAL_CHECKPOINT_INTERVAL_MS } from "../constants.ts";
9
12
  import { logEvent, logger } from "../log/log.ts";
10
13
  import { createApp, createPapyrusService } from "../service.ts";
11
14
  import {
@@ -69,6 +72,14 @@ export async function serveMain(): Promise<void> {
69
72
  const startedAt = new Date().toISOString();
70
73
  const token = loadOrCreateToken(stateDir);
71
74
  const service = createPapyrusService(dbPath());
75
+ // Records how often each real operation is invoked (server-side, every caller) plus, via
76
+ // metrics.recordClientEvent, client-observed Vehicle Shell meta-tool calls -- see
77
+ // @danypops/vehicle-server's own metrics README section. Wired directly onto the same registry
78
+ // every real papyrus operation is already registered on, so it's discoverable through the exact
79
+ // same tools_list/tools_man path as any other operation.
80
+ const vehicleMetrics = openVehicleMetricsStore(metricsPath());
81
+ service.vehicle.useExecutionMiddleware(createVehicleMetricsMiddleware(vehicleMetrics, "papyrus"));
82
+ registerVehicleMetricsOperations(service.vehicle, vehicleMetrics, "papyrus");
72
83
  const pushChannel = new PushChannel({ token });
73
84
  const app = createApp({
74
85
  service,
@@ -106,6 +117,7 @@ export async function serveMain(): Promise<void> {
106
117
  });
107
118
  if (!server.port) {
108
119
  service.close();
120
+ vehicleMetrics.close();
109
121
  releaseDaemonLock(lockPath);
110
122
  throw new Error("Papyrus daemon failed to bind a listener");
111
123
  }
@@ -168,6 +180,7 @@ export async function serveMain(): Promise<void> {
168
180
  }
169
181
  releaseDaemonLock(lockPath);
170
182
  service.close();
183
+ vehicleMetrics.close();
171
184
  // .finally() re-throws rather than handling a rejection -- catching it first turns a bare
172
185
  // unhandled-rejection warning into a real, queryable shutdown-failure log line.
173
186
  void recordLifecycle("stopped", signal)