@danypops/papyrus 0.44.10 → 0.44.12
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 +1 -1
- package/src/artifact/artifact.ts +23 -0
- package/src/constants.ts +11 -0
- package/src/domain/gate.ts +11 -0
- package/src/handlers/docs.ts +3 -3
- package/src/handlers/playbooks.ts +3 -2
- package/src/handlers/rules.ts +3 -3
- package/src/handlers/shared.ts +12 -2
- package/src/handlers/tasks.ts +30 -2
- package/src/modules/docs.ts +6 -2
- package/src/modules/operation-input.ts +7 -0
- package/src/modules/playbooks.ts +6 -2
- package/src/modules/rules.ts +6 -2
- package/src/ops.ts +3 -2
package/package.json
CHANGED
package/src/artifact/artifact.ts
CHANGED
|
@@ -20,6 +20,29 @@ export interface Artifact {
|
|
|
20
20
|
edges?: ArtifactEdge[];
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* A list operation's default projection: everything needed to identify, browse, and pick
|
|
25
|
+
* one artifact out of many, without its body/extra -- the same fields show()'s own full
|
|
26
|
+
* Artifact carries minus the two that make listing dozens of rows as expensive as showing
|
|
27
|
+
* each one individually (a Playbook's full runbook body, a Rule's condition/action text).
|
|
28
|
+
*/
|
|
29
|
+
export interface ArtifactSummary {
|
|
30
|
+
id: string;
|
|
31
|
+
kind: string;
|
|
32
|
+
title: string;
|
|
33
|
+
status: string;
|
|
34
|
+
subtype: string;
|
|
35
|
+
labels: string[];
|
|
36
|
+
created_at: string;
|
|
37
|
+
updated_at: string;
|
|
38
|
+
alias: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function summarizeArtifact(artifact: Artifact): ArtifactSummary {
|
|
42
|
+
const { id, kind, title, status, subtype, labels, created_at, updated_at, alias } = artifact;
|
|
43
|
+
return { id, kind, title, status, subtype, labels, created_at, updated_at, alias };
|
|
44
|
+
}
|
|
45
|
+
|
|
23
46
|
export interface CreateArtifactInput {
|
|
24
47
|
kind?: string;
|
|
25
48
|
title?: string;
|
package/src/constants.ts
CHANGED
|
@@ -16,6 +16,17 @@ export const WAL_CHECKPOINT_INTERVAL_MS = 60_000;
|
|
|
16
16
|
export const DB_OPTIMIZE_INTERVAL_MS = 24 * 60 * 60_000;
|
|
17
17
|
export const GATE_COMMAND_TIMEOUT_MS = 30_000;
|
|
18
18
|
export const GATE_TEST_TIMEOUT_MS = 60_000;
|
|
19
|
+
/**
|
|
20
|
+
* Ceiling a Gate's own explicit `timeoutMs` (domain/gate.ts) may request, overriding
|
|
21
|
+
* GATE_COMMAND_TIMEOUT_MS/GATE_TEST_TIMEOUT_MS for that one gate -- e.g. a task whose gate is a
|
|
22
|
+
* full monorepo test run that legitimately takes longer than either type default. Real, confirmed
|
|
23
|
+
* bug this exists for: a caller had no way to declare a longer-than-default gate timeout at all --
|
|
24
|
+
* `tasks.set_gates` silently accepted and dropped an experimental `timeoutMs` field before this.
|
|
25
|
+
* handlers/tasks.ts's GATE_OPERATION_LIMITS derives its own outer Vehicle transport deadline from
|
|
26
|
+
* this same constant, so the outer deadline can never fire strictly before a single gate honoring
|
|
27
|
+
* this ceiling has had a chance to.
|
|
28
|
+
*/
|
|
29
|
+
export const GATE_TIMEOUT_MAX_MS = 300_000;
|
|
19
30
|
export const GATE_OUTPUT_LIMIT = 200;
|
|
20
31
|
export const GATE_MAX_BUFFER_BYTES = 1_048_576;
|
|
21
32
|
export const GATE_FILE_MAX_BYTES = 1_048_576;
|
package/src/domain/gate.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { GATE_TIMEOUT_MAX_MS } from "../constants.ts";
|
|
2
|
+
|
|
1
3
|
export const GATE_TYPES = ["file-exists", "command", "contains", "test"] as const;
|
|
2
4
|
export type GateType = (typeof GATE_TYPES)[number];
|
|
3
5
|
|
|
@@ -5,6 +7,8 @@ export interface Gate {
|
|
|
5
7
|
type: GateType;
|
|
6
8
|
target: string;
|
|
7
9
|
expect?: string;
|
|
10
|
+
/** Overrides GATE_COMMAND_TIMEOUT_MS/GATE_TEST_TIMEOUT_MS for this one "command"/"test" gate, bounded by GATE_TIMEOUT_MAX_MS (see its own doc comment). */
|
|
11
|
+
timeoutMs?: number;
|
|
8
12
|
}
|
|
9
13
|
|
|
10
14
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
@@ -29,10 +33,17 @@ export function validateGates(value: unknown): Gate[] {
|
|
|
29
33
|
if (entry.expect !== undefined && typeof entry.expect !== "string") {
|
|
30
34
|
throw new Error(`gate at index ${index} expect must be a string`);
|
|
31
35
|
}
|
|
36
|
+
if (
|
|
37
|
+
entry.timeoutMs !== undefined &&
|
|
38
|
+
(!Number.isInteger(entry.timeoutMs) || (entry.timeoutMs as number) < 1_000 || (entry.timeoutMs as number) > GATE_TIMEOUT_MAX_MS)
|
|
39
|
+
) {
|
|
40
|
+
throw new Error(`gate at index ${index} timeoutMs must be an integer between 1000 and ${GATE_TIMEOUT_MAX_MS}`);
|
|
41
|
+
}
|
|
32
42
|
return {
|
|
33
43
|
type: entry.type as GateType,
|
|
34
44
|
target: entry.target,
|
|
35
45
|
...(typeof entry.expect === "string" ? { expect: entry.expect } : {}),
|
|
46
|
+
...(typeof entry.timeoutMs === "number" ? { timeoutMs: entry.timeoutMs } : {}),
|
|
36
47
|
};
|
|
37
48
|
});
|
|
38
49
|
}
|
package/src/handlers/docs.ts
CHANGED
|
@@ -9,7 +9,7 @@ import type { ArtifactStore } from "../artifact/artifact-store.ts";
|
|
|
9
9
|
import type { AuthorityRegistry } from "../authority-registry.ts";
|
|
10
10
|
import { listDocuments } from "../domain-services.ts";
|
|
11
11
|
import { docsOperations } from "../modules/docs.ts";
|
|
12
|
-
import { createOperationDefiner, numberProp, resolveArtifactIdWidened, stringProp, validationError } from "./shared.ts";
|
|
12
|
+
import { booleanProp, createOperationDefiner, numberProp, resolveArtifactIdWidened, stringProp, validationError } from "./shared.ts";
|
|
13
13
|
|
|
14
14
|
const OWNER = "docs";
|
|
15
15
|
|
|
@@ -66,9 +66,9 @@ export function registerDocsVehicleOperations(
|
|
|
66
66
|
|
|
67
67
|
define(
|
|
68
68
|
"list",
|
|
69
|
-
"Lists Docs matching an optional status/text filter, scoped to project_root when given.",
|
|
69
|
+
"Lists Docs matching an optional status/text filter, scoped to project_root when given. Returns a lean summary (no body) by default -- pass full: true for the complete artifact.",
|
|
70
70
|
"read",
|
|
71
|
-
{ status: stringProp, text: stringProp, limit: numberProp, project_root: stringProp },
|
|
71
|
+
{ status: stringProp, text: stringProp, limit: numberProp, project_root: stringProp, full: booleanProp },
|
|
72
72
|
[],
|
|
73
73
|
(input) => input,
|
|
74
74
|
);
|
|
@@ -29,6 +29,7 @@ import type { TaskEventStore } from "../stores/task-event-store.ts";
|
|
|
29
29
|
import type { TaskScopeStore } from "../stores/task-scope-store.ts";
|
|
30
30
|
import type { Tasks } from "../task/task-service.ts";
|
|
31
31
|
import {
|
|
32
|
+
booleanProp,
|
|
32
33
|
buildWorkflowRunContent,
|
|
33
34
|
classifyPlaybookComposition,
|
|
34
35
|
classifySessionAuthorization,
|
|
@@ -107,9 +108,9 @@ export function registerPlaybooksVehicleOperations(registry: VehicleRegistry, de
|
|
|
107
108
|
|
|
108
109
|
define(
|
|
109
110
|
"list",
|
|
110
|
-
"Lists Playbooks matching an optional status/text filter, scoped to project_root when given.",
|
|
111
|
+
"Lists Playbooks matching an optional status/text filter, scoped to project_root when given. Returns a lean summary (no body/steps) by default -- pass full: true for the complete artifact.",
|
|
111
112
|
"read",
|
|
112
|
-
{ status: stringProp, text: stringProp, limit: numberProp, project_root: stringProp },
|
|
113
|
+
{ status: stringProp, text: stringProp, limit: numberProp, project_root: stringProp, full: booleanProp },
|
|
113
114
|
[],
|
|
114
115
|
(input) => input,
|
|
115
116
|
);
|
package/src/handlers/rules.ts
CHANGED
|
@@ -9,7 +9,7 @@ import type { ArtifactScopeStore } from "../artifact/artifact-scope-store.ts";
|
|
|
9
9
|
import type { ArtifactStore } from "../artifact/artifact-store.ts";
|
|
10
10
|
import { listRules } from "../domain-services.ts";
|
|
11
11
|
import { rulesOperations } from "../modules/rules.ts";
|
|
12
|
-
import { createOperationDefiner, numberProp, resolveArtifactIdWidened, stringProp, validationError } from "./shared.ts";
|
|
12
|
+
import { booleanProp, createOperationDefiner, numberProp, resolveArtifactIdWidened, stringProp, validationError } from "./shared.ts";
|
|
13
13
|
|
|
14
14
|
const OWNER = "rules";
|
|
15
15
|
|
|
@@ -70,9 +70,9 @@ export function registerRulesVehicleOperations(registry: VehicleRegistry, artifa
|
|
|
70
70
|
|
|
71
71
|
define(
|
|
72
72
|
"list",
|
|
73
|
-
"Lists Rules matching an optional status/text filter, scoped to project_root when given.",
|
|
73
|
+
"Lists Rules matching an optional status/text filter, scoped to project_root when given. Returns a lean summary (no condition/action/body) by default -- pass full: true for the complete artifact.",
|
|
74
74
|
"read",
|
|
75
|
-
{ status: stringProp, text: stringProp, limit: numberProp, project_root: stringProp },
|
|
75
|
+
{ status: stringProp, text: stringProp, limit: numberProp, project_root: stringProp, full: booleanProp },
|
|
76
76
|
[],
|
|
77
77
|
(input) => input,
|
|
78
78
|
);
|
package/src/handlers/shared.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
defineVehicleSchema,
|
|
10
10
|
type VehicleContentBlock,
|
|
11
11
|
VehicleError,
|
|
12
|
+
type VehicleLimits,
|
|
12
13
|
type VehicleOperationContext,
|
|
13
14
|
type VehicleSchemaCodec,
|
|
14
15
|
} from "@danypops/vehicle-core";
|
|
@@ -57,6 +58,7 @@ export const passthroughOutput: VehicleSchemaCodec<unknown> = defineVehicleSchem
|
|
|
57
58
|
|
|
58
59
|
export const stringProp = { type: "string" } as const;
|
|
59
60
|
export const numberProp = { type: "number" } as const;
|
|
61
|
+
export const booleanProp = { type: "boolean" } as const;
|
|
60
62
|
|
|
61
63
|
/**
|
|
62
64
|
* A plain `throw new Error(...)` inside any resolve()/execute() step here is caught by
|
|
@@ -243,6 +245,14 @@ export type DefineOperation = (
|
|
|
243
245
|
required: readonly string[],
|
|
244
246
|
resolve: (input: Record<string, unknown>) => Record<string, unknown>,
|
|
245
247
|
execute?: (input: Record<string, unknown>, context: VehicleOperationContext<Record<string, unknown>>) => unknown,
|
|
248
|
+
/**
|
|
249
|
+
* Overrides this one operation's own Vehicle transport limits, distinct from every other
|
|
250
|
+
* operation this same createOperationDefiner call produces. For an operation that shells out
|
|
251
|
+
* to and waits on a real external command (e.g. tasks.run_gates/tasks.complete) rather than an
|
|
252
|
+
* instant CRUD read/write -- see handlers/tasks.ts's GATE_OPERATION_LIMITS for the motivating
|
|
253
|
+
* case. Omit to keep the definer's own default limits, unchanged for every other action.
|
|
254
|
+
*/
|
|
255
|
+
limits?: VehicleLimits,
|
|
246
256
|
) => void;
|
|
247
257
|
|
|
248
258
|
const STANDARD_OPERATION_LIMITS = { defaultTimeoutMs: 5_000, maxTimeoutMs: 30_000, maxRequestBytes: 65_536, maxResponseBytes: 262_144 };
|
|
@@ -261,7 +271,7 @@ export function createOperationDefiner(
|
|
|
261
271
|
permissions: readonly [string, string],
|
|
262
272
|
defaultCall: (name: string, input: Record<string, unknown>) => unknown,
|
|
263
273
|
): DefineOperation {
|
|
264
|
-
return (action, description, effect, properties, required, resolve, execute) => {
|
|
274
|
+
return (action, description, effect, properties, required, resolve, execute, limits) => {
|
|
265
275
|
const operation = defineVehicleOperation({
|
|
266
276
|
name: `${domain}.${action}`,
|
|
267
277
|
version: 1,
|
|
@@ -271,7 +281,7 @@ export function createOperationDefiner(
|
|
|
271
281
|
permissions: [...permissions],
|
|
272
282
|
effect,
|
|
273
283
|
idempotency: { mode: effect === "read" ? "safe" : "unsafe" },
|
|
274
|
-
limits: STANDARD_OPERATION_LIMITS,
|
|
284
|
+
limits: limits ?? STANDARD_OPERATION_LIMITS,
|
|
275
285
|
});
|
|
276
286
|
registry.register(
|
|
277
287
|
owner,
|
package/src/handlers/tasks.ts
CHANGED
|
@@ -19,8 +19,10 @@
|
|
|
19
19
|
*
|
|
20
20
|
* remove/remove_subtree/restore are not duplicated here -- see ./artifact-trash-vehicle.ts.
|
|
21
21
|
*/
|
|
22
|
+
import type { VehicleLimits } from "@danypops/vehicle-core";
|
|
22
23
|
import type { VehicleRegistry } from "@danypops/vehicle-server";
|
|
23
24
|
import type { ArtifactStore } from "../artifact/artifact-store.ts";
|
|
25
|
+
import { GATE_TIMEOUT_MAX_MS } from "../constants.ts";
|
|
24
26
|
import type { TaskViewMode } from "../domain/task-scope.ts";
|
|
25
27
|
import { tasksOperations } from "../modules/tasks.ts";
|
|
26
28
|
import type { SessionIdentity } from "../session-identity/session-identity-service.ts";
|
|
@@ -40,7 +42,31 @@ import {
|
|
|
40
42
|
} from "./shared.ts";
|
|
41
43
|
|
|
42
44
|
const OWNER = "tasks";
|
|
43
|
-
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* tasks.run_gates/tasks.complete's own Vehicle transport limits, distinct from every other
|
|
48
|
+
* tasks.* CRUD action's shared STANDARD_OPERATION_LIMITS (createOperationDefiner's own default,
|
|
49
|
+
* 5s). Those two operations shell out to and wait on a real, caller-configured external command
|
|
50
|
+
* (domain/gate.ts's Gate.timeoutMs) -- the shared 5s CRUD default was an accidental inheritance,
|
|
51
|
+
* not a deliberate choice, and aborted the RPC call for any gate command that took longer than a
|
|
52
|
+
* few seconds, even a genuinely successful one (confirmed live, twice, with hard numbers: a real
|
|
53
|
+
* ~13s gate failed deterministically every time; a ~28s gate flapped around a separate, unrelated
|
|
54
|
+
* 30s inner per-gate-type default).
|
|
55
|
+
*
|
|
56
|
+
* defaultTimeoutMs is derived from GATE_TIMEOUT_MAX_MS (the longest a single gate's own explicit
|
|
57
|
+
* timeoutMs may request) plus a buffer for process-spawn/RPC/serialization overhead, so the outer
|
|
58
|
+
* transport deadline can never fire strictly before a single gate honoring that ceiling has had a
|
|
59
|
+
* chance to. A task with SEVERAL gates each near that ceiling can still exceed this default in
|
|
60
|
+
* aggregate (gates run sequentially -- see ops.ts's runGatesAsync); there is no aggregate
|
|
61
|
+
* task-level gate-time budget yet. maxTimeoutMs gives a caller who knows its gates are
|
|
62
|
+
* collectively slower room to explicitly request a longer deadline.
|
|
63
|
+
*/
|
|
64
|
+
const GATE_OPERATION_LIMITS: VehicleLimits = {
|
|
65
|
+
defaultTimeoutMs: GATE_TIMEOUT_MAX_MS + 60_000,
|
|
66
|
+
maxTimeoutMs: GATE_TIMEOUT_MAX_MS * 4,
|
|
67
|
+
maxRequestBytes: 65_536,
|
|
68
|
+
maxResponseBytes: 262_144,
|
|
69
|
+
};
|
|
44
70
|
|
|
45
71
|
const objectProp = { type: "object" } as unknown as { type: string };
|
|
46
72
|
const arrayProp = { type: "array" } as unknown as { type: string };
|
|
@@ -456,6 +482,7 @@ export function registerTasksVehicleOperations(registry: VehicleRegistry, deps:
|
|
|
456
482
|
const labels = labelsById(artifacts, dependencyIds);
|
|
457
483
|
return { ...result, content: [{ type: "text" as const, text: completionContentText(labels, result) }] };
|
|
458
484
|
},
|
|
485
|
+
GATE_OPERATION_LIMITS,
|
|
459
486
|
);
|
|
460
487
|
|
|
461
488
|
define(
|
|
@@ -484,6 +511,7 @@ export function registerTasksVehicleOperations(registry: VehicleRegistry, deps:
|
|
|
484
511
|
"No gates configured.";
|
|
485
512
|
return { gates, content: [{ type: "text" as const, text }] };
|
|
486
513
|
},
|
|
514
|
+
GATE_OPERATION_LIMITS,
|
|
487
515
|
);
|
|
488
516
|
|
|
489
517
|
define(
|
|
@@ -496,7 +524,7 @@ export function registerTasksVehicleOperations(registry: VehicleRegistry, deps:
|
|
|
496
524
|
);
|
|
497
525
|
define(
|
|
498
526
|
"set_gates",
|
|
499
|
-
"Replaces a Task's gate commands in full.",
|
|
527
|
+
"Replaces a Task's gate commands in full. Each gate is {type, target, expect?, timeoutMs?} -- timeoutMs overrides the default per-type command timeout (30s)/test timeout (60s) for a legitimately slower gate, up to a bounded ceiling.",
|
|
500
528
|
"local-write",
|
|
501
529
|
{ id: stringProp, name: stringProp, gates: arrayProp, project_root: stringProp },
|
|
502
530
|
["gates"],
|
package/src/modules/docs.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* ArtifactStore-based with no other module's concrete class dependency.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import { summarizeArtifact } from "../artifact/artifact.ts";
|
|
10
11
|
import type { ArtifactScopeStore } from "../artifact/artifact-scope-store.ts";
|
|
11
12
|
import type { ArtifactStore } from "../artifact/artifact-store.ts";
|
|
12
13
|
import type { AuthorityRegistry } from "../authority-registry.ts";
|
|
@@ -21,7 +22,7 @@ import {
|
|
|
21
22
|
updateDocument,
|
|
22
23
|
} from "../domain-services.ts";
|
|
23
24
|
import type { OperationDefinition } from "../module-registry.ts";
|
|
24
|
-
import { type OperationInput, optionalNumber, optionalString, string } from "./operation-input.ts";
|
|
25
|
+
import { type OperationInput, optionalBoolean, optionalNumber, optionalString, string } from "./operation-input.ts";
|
|
25
26
|
|
|
26
27
|
const MODULE_ID = "docs";
|
|
27
28
|
|
|
@@ -76,7 +77,10 @@ export function docsOperations(artifacts: ArtifactStore, scopes: ArtifactScopeSt
|
|
|
76
77
|
eventContext(input),
|
|
77
78
|
),
|
|
78
79
|
),
|
|
79
|
-
define("docs.list", (input: OperationInput) =>
|
|
80
|
+
define("docs.list", (input: OperationInput) => {
|
|
81
|
+
const docs = listDocuments(artifacts, scopes, artifactFilter(input));
|
|
82
|
+
return optionalBoolean(input, "full") === true ? docs : docs.map(summarizeArtifact);
|
|
83
|
+
}),
|
|
80
84
|
define("docs.show", (input: OperationInput) => showDocument(artifacts, string(input, "id"))),
|
|
81
85
|
define("docs.activate", (input: OperationInput) =>
|
|
82
86
|
transitionDocument(artifacts, string(input, "id"), "activate", authority, eventContext(input)),
|
|
@@ -33,3 +33,10 @@ export function optionalNumber(input: OperationInput, key: string): number | und
|
|
|
33
33
|
if (typeof value !== "number" || !Number.isFinite(value)) throw new Error(`${key} must be a number`);
|
|
34
34
|
return value;
|
|
35
35
|
}
|
|
36
|
+
|
|
37
|
+
export function optionalBoolean(input: OperationInput, key: string): boolean | undefined {
|
|
38
|
+
const value = input[key];
|
|
39
|
+
if (value === undefined) return undefined;
|
|
40
|
+
if (typeof value !== "boolean") throw new Error(`${key} must be a boolean`);
|
|
41
|
+
return value;
|
|
42
|
+
}
|
package/src/modules/playbooks.ts
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* playbook/playbook-definition.ts for the full rationale.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
import { summarizeArtifact } from "../artifact/artifact.ts";
|
|
13
14
|
import type { ArtifactScopeStore } from "../artifact/artifact-scope-store.ts";
|
|
14
15
|
import type { ArtifactStore } from "../artifact/artifact-store.ts";
|
|
15
16
|
import {
|
|
@@ -31,7 +32,7 @@ import type { SessionIdentity } from "../session-identity/session-identity-servi
|
|
|
31
32
|
import type { TaskEventStore } from "../stores/task-event-store.ts";
|
|
32
33
|
import type { TaskScopeStore } from "../stores/task-scope-store.ts";
|
|
33
34
|
import type { Tasks } from "../task/task-service.ts";
|
|
34
|
-
import { type OperationInput, optionalNumber, optionalString, string } from "./operation-input.ts";
|
|
35
|
+
import { type OperationInput, optionalBoolean, optionalNumber, optionalString, string } from "./operation-input.ts";
|
|
35
36
|
|
|
36
37
|
const MODULE_ID = "playbooks";
|
|
37
38
|
|
|
@@ -114,7 +115,10 @@ export function playbooksOperations({
|
|
|
114
115
|
eventContext(input),
|
|
115
116
|
),
|
|
116
117
|
),
|
|
117
|
-
define("playbooks.list", (input: OperationInput) =>
|
|
118
|
+
define("playbooks.list", (input: OperationInput) => {
|
|
119
|
+
const playbooks = listPlaybooks(artifacts, artifactScopes, artifactFilter(input));
|
|
120
|
+
return optionalBoolean(input, "full") === true ? playbooks : playbooks.map(summarizeArtifact);
|
|
121
|
+
}),
|
|
118
122
|
define("playbooks.show", (input: OperationInput) => showPlaybook(artifacts, string(input, "id"))),
|
|
119
123
|
define("playbooks.preview", (input: OperationInput) =>
|
|
120
124
|
playbookInvocation(artifacts, string(input, "id"), input.arguments as Record<string, unknown> | undefined),
|
package/src/modules/rules.ts
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* registry" convention.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
+
import { summarizeArtifact } from "../artifact/artifact.ts";
|
|
14
15
|
import type { ArtifactScopeStore } from "../artifact/artifact-scope-store.ts";
|
|
15
16
|
import type { ArtifactStore } from "../artifact/artifact-store.ts";
|
|
16
17
|
import {
|
|
@@ -24,7 +25,7 @@ import {
|
|
|
24
25
|
updateRule,
|
|
25
26
|
} from "../domain-services.ts";
|
|
26
27
|
import type { OperationDefinition } from "../module-registry.ts";
|
|
27
|
-
import { type OperationInput, optionalNumber, optionalString, string } from "./operation-input.ts";
|
|
28
|
+
import { type OperationInput, optionalBoolean, optionalNumber, optionalString, string } from "./operation-input.ts";
|
|
28
29
|
|
|
29
30
|
const MODULE_ID = "rules";
|
|
30
31
|
|
|
@@ -79,7 +80,10 @@ export function rulesOperations(artifacts: ArtifactStore, scopes: ArtifactScopeS
|
|
|
79
80
|
eventContext(input),
|
|
80
81
|
),
|
|
81
82
|
),
|
|
82
|
-
define("rules.list", (input: OperationInput) =>
|
|
83
|
+
define("rules.list", (input: OperationInput) => {
|
|
84
|
+
const rules = listRules(artifacts, scopes, artifactFilter(input));
|
|
85
|
+
return optionalBoolean(input, "full") === true ? rules : rules.map(summarizeArtifact);
|
|
86
|
+
}),
|
|
83
87
|
define("rules.show", (input: OperationInput) => showRule(artifacts, string(input, "id"))),
|
|
84
88
|
define("rules.preview", (input: OperationInput) => previewRule(artifacts, string(input, "id"))),
|
|
85
89
|
define("rules.enable", (input: OperationInput) => transitionRule(artifacts, string(input, "id"), "enable", eventContext(input))),
|
package/src/ops.ts
CHANGED
|
@@ -601,8 +601,9 @@ function readBoundedGateFile(path: string): string {
|
|
|
601
601
|
/** Shared by the sync and async process-gate runners so "test" is never a second, independently
|
|
602
602
|
* maintained copy of "command"'s own command-template/timeout selection. */
|
|
603
603
|
function processGateCommand(gate: Gate): { command: string; timeout: number } {
|
|
604
|
-
if (gate.type === "test")
|
|
605
|
-
|
|
604
|
+
if (gate.type === "test")
|
|
605
|
+
return { command: `npx vitest run ${gate.target} --reporter=dot`, timeout: gate.timeoutMs ?? GATE_TEST_TIMEOUT_MS };
|
|
606
|
+
return { command: gate.target, timeout: gate.timeoutMs ?? GATE_COMMAND_TIMEOUT_MS };
|
|
606
607
|
}
|
|
607
608
|
|
|
608
609
|
/**
|