@danypops/papyrus 0.44.2 → 0.44.4
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 +2 -2
- package/src/client.ts +12 -6
- package/src/task-service.ts +21 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@danypops/papyrus",
|
|
3
|
-
"version": "0.44.
|
|
3
|
+
"version": "0.44.4",
|
|
4
4
|
"description": "Daemon-backed graph artifacts, evidence-bearing tasks, rules, skills, and native TUI workflows for Pi",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": ["pi-package"],
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
},
|
|
35
35
|
"files": ["src", "README.md"],
|
|
36
36
|
"dependencies": {
|
|
37
|
+
"@danypops/vehicle-client": "^0.6.1",
|
|
37
38
|
"@danypops/vehicle-core": "^0.10.0",
|
|
38
|
-
"@danypops/vehicle-client": "^0.5.0",
|
|
39
39
|
"@danypops/vehicle-server": "^0.13.0"
|
|
40
40
|
}
|
|
41
41
|
}
|
package/src/client.ts
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import { spawn as spawnProcess } from "node:child_process";
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
-
import { connectWithVersionCheck, spawnDetachedDaemon } from "@danypops/vehicle-client/daemon-client";
|
|
4
|
-
import {
|
|
3
|
+
import { connectWithVersionCheck, type ExpectedVersion, spawnDetachedDaemon } from "@danypops/vehicle-client/daemon-client";
|
|
4
|
+
import { createLiveVersionExpectation } from "@danypops/vehicle-client/version";
|
|
5
5
|
import { DAEMON_CLIENT_TIMEOUT_MS, DAEMON_DIR_ENV, DAEMON_PROBE_TIMEOUT_MS } from "./constants.ts";
|
|
6
6
|
import { type DaemonHandle, daemonStateDir, readDaemonHandle } from "./daemon-state.ts";
|
|
7
7
|
import type { OperationName, SchemaState } from "./service.ts";
|
|
8
8
|
|
|
9
|
-
/**
|
|
10
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Compared against the running daemon's /health-reported version by connectWithVersionCheck
|
|
11
|
+
* below. Re-read fresh on every call, not cached -- a module-level `const` here was the exact
|
|
12
|
+
* bug that caused repeated, never-self-healing daemon kill/respawn churn on any process that
|
|
13
|
+
* outlived an `npm update` (a respawned daemon runs the same source and reports the same real
|
|
14
|
+
* version, so a stale cached expectation never converges).
|
|
15
|
+
*/
|
|
16
|
+
const papyrusExpectedVersion = createLiveVersionExpectation(new URL("../package.json", import.meta.url), "Papyrus");
|
|
11
17
|
|
|
12
18
|
export type FetchAdapter = (request: Request) => Promise<Response>;
|
|
13
19
|
|
|
@@ -89,7 +95,7 @@ export interface ConnectPapyrusClientOptions {
|
|
|
89
95
|
*/
|
|
90
96
|
env?: Record<string, string | undefined>;
|
|
91
97
|
/** Overrides the version connectWithVersionCheck compares against. Defaults to PAPYRUS_VERSION; test-only -- lets a test force a mismatch against a real daemon without a second build. */
|
|
92
|
-
expectedVersion?:
|
|
98
|
+
expectedVersion?: ExpectedVersion;
|
|
93
99
|
}
|
|
94
100
|
|
|
95
101
|
/**
|
|
@@ -126,7 +132,7 @@ export async function connectPapyrusClient(
|
|
|
126
132
|
fallbackMessage: "Papyrus daemon failed to start automatically; run `papyrus service install` or `papyrus serve` manually.",
|
|
127
133
|
},
|
|
128
134
|
{
|
|
129
|
-
expectedVersion: options.expectedVersion ??
|
|
135
|
+
expectedVersion: options.expectedVersion ?? papyrusExpectedVersion,
|
|
130
136
|
readVersion: async (client) => (await client.health()).version,
|
|
131
137
|
killStaleProcess: killStalePapyrusDaemon,
|
|
132
138
|
},
|
package/src/task-service.ts
CHANGED
|
@@ -329,11 +329,17 @@ export class Tasks {
|
|
|
329
329
|
throw new Error(`task graph limit must be between 1 and ${TASK_EXECUTION_MAX_NODES + 1}`);
|
|
330
330
|
}
|
|
331
331
|
const tasks = this.list({ ...filter, limit: requestedLimit });
|
|
332
|
+
return this.buildGraph(tasks, scope, filter.sessionId);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/** Shared by graph() and dependencyCheckGraph() -- the latter builds a graph from an
|
|
336
|
+
* explicitly assembled task list (a union of two projects) rather than one filter's own scope. */
|
|
337
|
+
private buildGraph(tasks: Artifact[], scope: TaskViewSelection, sessionId?: string): TaskGraph {
|
|
332
338
|
if (tasks.length > TASK_EXECUTION_MAX_NODES) {
|
|
333
|
-
throw new
|
|
339
|
+
throw new TaskExecutionBoundExceededError(`task execution graph exceeds ${TASK_EXECUTION_MAX_NODES} nodes`);
|
|
334
340
|
}
|
|
335
341
|
const byId = new Map(tasks.map((task) => [task.id, task]));
|
|
336
|
-
const focus = this.focusStore.get(
|
|
342
|
+
const focus = this.focusStore.get(sessionId);
|
|
337
343
|
const focusedId = focus?.taskId;
|
|
338
344
|
const focusStatus = focus?.status;
|
|
339
345
|
const nodes = new Map(
|
|
@@ -355,7 +361,7 @@ export class Tasks {
|
|
|
355
361
|
limit: TASK_EXECUTION_MAX_EDGES + 1,
|
|
356
362
|
});
|
|
357
363
|
if (relationships.length > TASK_EXECUTION_MAX_EDGES) {
|
|
358
|
-
throw new
|
|
364
|
+
throw new TaskExecutionBoundExceededError(`task execution graph exceeds ${TASK_EXECUTION_MAX_EDGES} relationships`);
|
|
359
365
|
}
|
|
360
366
|
for (const edge of relationships) {
|
|
361
367
|
if (!byId.has(edge.from) || !byId.has(edge.to)) continue;
|
|
@@ -656,6 +662,18 @@ export class Tasks {
|
|
|
656
662
|
if (sourceProject !== undefined && sourceProject === targetProject) {
|
|
657
663
|
return this.graph({ projectRoot: sourceProject, scope: "project" });
|
|
658
664
|
}
|
|
665
|
+
if (sourceProject !== undefined && targetProject !== undefined) {
|
|
666
|
+
// A genuine cross-project pair: the union of both endpoints' own project scopes
|
|
667
|
+
// covers every prerequisite/successor edge relevant to THIS pair's own cycle check,
|
|
668
|
+
// without pulling in every unrelated project's tasks -- those can push the daemon-wide
|
|
669
|
+
// total over TASK_EXECUTION_MAX_NODES for reasons that have nothing to do with these
|
|
670
|
+
// two tasks. A cycle threading through a third, uninvolved project is not covered by
|
|
671
|
+
// this union; falls back to the fully unscoped graph only when a project is unknown.
|
|
672
|
+
const limit = TASK_EXECUTION_MAX_NODES + 1;
|
|
673
|
+
const merged = new Map(this.list({ projectRoot: sourceProject, scope: "project", limit }).map((task) => [task.id, task]));
|
|
674
|
+
for (const task of this.list({ projectRoot: targetProject, scope: "project", limit })) merged.set(task.id, task);
|
|
675
|
+
return this.buildGraph([...merged.values()], { mode: "all", label: taskScopeLabel("all") });
|
|
676
|
+
}
|
|
659
677
|
return this.graph();
|
|
660
678
|
}
|
|
661
679
|
|