@ikenga/contract 0.7.0 → 0.9.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 +56 -11
- package/dist/canvas/Canvas.d.ts +7 -0
- package/dist/canvas/Canvas.d.ts.map +1 -0
- package/dist/canvas/Canvas.js +115 -0
- package/dist/canvas/Canvas.js.map +1 -0
- package/dist/canvas/canvas.css +579 -0
- package/dist/canvas/index.d.ts +7 -0
- package/dist/canvas/index.d.ts.map +1 -0
- package/dist/canvas/index.js +4 -0
- package/dist/canvas/index.js.map +1 -0
- package/dist/canvas/types.d.ts +45 -0
- package/dist/canvas/types.d.ts.map +1 -0
- package/dist/canvas/types.js +2 -0
- package/dist/canvas/types.js.map +1 -0
- package/dist/canvas/use-drag-snap.d.ts +33 -0
- package/dist/canvas/use-drag-snap.d.ts.map +1 -0
- package/dist/canvas/use-drag-snap.js +73 -0
- package/dist/canvas/use-drag-snap.js.map +1 -0
- package/dist/canvas/use-pan-zoom.d.ts +32 -0
- package/dist/canvas/use-pan-zoom.d.ts.map +1 -0
- package/dist/canvas/use-pan-zoom.js +161 -0
- package/dist/canvas/use-pan-zoom.js.map +1 -0
- package/dist/host-verbs.d.ts +194 -0
- package/dist/host-verbs.d.ts.map +1 -0
- package/dist/host-verbs.js +15 -0
- package/dist/host-verbs.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/manifest.d.ts +376 -19
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.js +95 -4
- package/dist/manifest.js.map +1 -1
- package/dist/registry.d.ts +364 -36
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +9 -0
- package/dist/registry.js.map +1 -1
- package/dist/scopes.js +1 -1
- package/dist/scopes.js.map +1 -1
- package/package.json +24 -2
- package/schemas/registry/index-v1.json +11 -0
- package/src/canvas/Canvas.tsx +161 -0
- package/src/canvas/canvas.css +579 -0
- package/src/canvas/index.ts +14 -0
- package/src/canvas/types.ts +48 -0
- package/src/canvas/use-drag-snap.ts +107 -0
- package/src/canvas/use-pan-zoom.ts +211 -0
- package/src/host-verbs.ts +207 -0
- package/src/index.ts +1 -0
- package/src/manifest.test.ts +97 -0
- package/src/manifest.ts +109 -4
- package/src/registry.ts +9 -0
- package/src/scopes.ts +1 -1
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// Scale-aware grid-snap drag for the <Canvas> primitive.
|
|
2
|
+
//
|
|
3
|
+
// Owns the in-flight drag gesture (which item, where it started) and the
|
|
4
|
+
// pointer math that moves it: cursor delta is divided by the current viewport
|
|
5
|
+
// scale (so a 10px screen move at scale 0.5 becomes a 20px canvas move, and at
|
|
6
|
+
// scale 2.0 a 5px canvas move), then snapped to the `gridSnap` lattice.
|
|
7
|
+
//
|
|
8
|
+
// nx = round((startPos.x + dx / scale) / gridSnap) * gridSnap
|
|
9
|
+
//
|
|
10
|
+
// Does NOT own `layout` — it reads the current placement to seed the gesture
|
|
11
|
+
// and emits the moved layout through `onLayoutChange`. The parent stays the
|
|
12
|
+
// source of truth.
|
|
13
|
+
//
|
|
14
|
+
// Extracted verbatim (behavior-preserving) from shell home.tsx's canvas block.
|
|
15
|
+
import { useCallback, useEffect, useRef } from 'react';
|
|
16
|
+
export function useDragSnap(args) {
|
|
17
|
+
const { layout, gridSnap, scale, onLayoutChange, stageRef } = args;
|
|
18
|
+
const dragState = useRef(null);
|
|
19
|
+
// Keep the freshest layout/scale/snap reachable from the global listener
|
|
20
|
+
// without re-subscribing it on every render.
|
|
21
|
+
const layoutRef = useRef(layout);
|
|
22
|
+
layoutRef.current = layout;
|
|
23
|
+
const scaleRef = useRef(scale);
|
|
24
|
+
scaleRef.current = scale;
|
|
25
|
+
const gridSnapRef = useRef(gridSnap);
|
|
26
|
+
gridSnapRef.current = gridSnap;
|
|
27
|
+
const onLayoutChangeRef = useRef(onLayoutChange);
|
|
28
|
+
onLayoutChangeRef.current = onLayoutChange;
|
|
29
|
+
const beginDrag = useCallback((id, clientX, clientY) => {
|
|
30
|
+
const w = layoutRef.current[id];
|
|
31
|
+
if (!w)
|
|
32
|
+
return;
|
|
33
|
+
dragState.current = {
|
|
34
|
+
id,
|
|
35
|
+
startMouse: { x: clientX, y: clientY },
|
|
36
|
+
startPos: { x: w.x, y: w.y },
|
|
37
|
+
};
|
|
38
|
+
stageRef.current?.classList.add('is-dragging');
|
|
39
|
+
}, [stageRef]);
|
|
40
|
+
const isDragging = useCallback(() => dragState.current != null, []);
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
const onMove = (e) => {
|
|
43
|
+
if (!dragState.current)
|
|
44
|
+
return;
|
|
45
|
+
const s = scaleRef.current || 1;
|
|
46
|
+
const snap = gridSnapRef.current;
|
|
47
|
+
const dx = e.clientX - dragState.current.startMouse.x;
|
|
48
|
+
const dy = e.clientY - dragState.current.startMouse.y;
|
|
49
|
+
const nx = Math.round((dragState.current.startPos.x + dx / s) / snap) * snap;
|
|
50
|
+
const ny = Math.round((dragState.current.startPos.y + dy / s) / snap) * snap;
|
|
51
|
+
const id = dragState.current.id;
|
|
52
|
+
const cur = layoutRef.current;
|
|
53
|
+
const prev = cur[id];
|
|
54
|
+
if (!prev || (prev.x === nx && prev.y === ny))
|
|
55
|
+
return;
|
|
56
|
+
onLayoutChangeRef.current?.({ ...cur, [id]: { ...prev, x: nx, y: ny } });
|
|
57
|
+
};
|
|
58
|
+
const onUp = () => {
|
|
59
|
+
if (dragState.current) {
|
|
60
|
+
dragState.current = null;
|
|
61
|
+
stageRef.current?.classList.remove('is-dragging');
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
window.addEventListener('mousemove', onMove);
|
|
65
|
+
window.addEventListener('mouseup', onUp);
|
|
66
|
+
return () => {
|
|
67
|
+
window.removeEventListener('mousemove', onMove);
|
|
68
|
+
window.removeEventListener('mouseup', onUp);
|
|
69
|
+
};
|
|
70
|
+
}, [stageRef]);
|
|
71
|
+
return { dragState, beginDrag, isDragging };
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=use-drag-snap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-drag-snap.js","sourceRoot":"","sources":["../../src/canvas/use-drag-snap.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ItemId, Placement, Viewport } from './types.js';
|
|
2
|
+
export interface UsePanZoomArgs {
|
|
3
|
+
/** Controlled layout (id → placement) the auto-fit bounding box reads. */
|
|
4
|
+
layout: Record<ItemId, Placement>;
|
|
5
|
+
/** Controlled edit-mode flag — auto-fit reserves palette width when true. */
|
|
6
|
+
editMode: boolean;
|
|
7
|
+
/** Re-fit on window resize. Default true. */
|
|
8
|
+
autoFitOnResize?: boolean;
|
|
9
|
+
/** Notified whenever the viewport pan/scale changes (controlled mirror). */
|
|
10
|
+
onViewportChange?: (viewport: Viewport) => void;
|
|
11
|
+
/** Escape exits edit mode → parent owns the state flip. */
|
|
12
|
+
onEditModeChange?: (editMode: boolean) => void;
|
|
13
|
+
/** Escape clears selection. */
|
|
14
|
+
onSelectionChange?: (selectedId: ItemId | null) => void;
|
|
15
|
+
}
|
|
16
|
+
export interface UsePanZoom {
|
|
17
|
+
/** Live viewport (x/y/scale). Mirrors `pan` in the original home code. */
|
|
18
|
+
pan: Viewport;
|
|
19
|
+
setPan: React.Dispatch<React.SetStateAction<Viewport>>;
|
|
20
|
+
/** Imperative re-fit. `animate=false` snaps without the transition. */
|
|
21
|
+
autoFit: (animate?: boolean) => void;
|
|
22
|
+
canvasRef: React.RefObject<HTMLDivElement | null>;
|
|
23
|
+
stageRef: React.RefObject<HTMLDivElement | null>;
|
|
24
|
+
/** True while Space is held — drag/pan branch reads this. */
|
|
25
|
+
spaceDown: React.MutableRefObject<boolean>;
|
|
26
|
+
/** Begin a pan gesture from a mousedown at screen (clientX, clientY). */
|
|
27
|
+
beginPan: (clientX: number, clientY: number) => void;
|
|
28
|
+
/** Is a pan gesture in flight? */
|
|
29
|
+
isPanning: () => boolean;
|
|
30
|
+
}
|
|
31
|
+
export declare function usePanZoom(args: UsePanZoomArgs): UsePanZoom;
|
|
32
|
+
//# sourceMappingURL=use-pan-zoom.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-pan-zoom.d.ts","sourceRoot":"","sources":["../../src/canvas/use-pan-zoom.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE9D,MAAM,WAAW,cAAc;IAC7B,0EAA0E;IAC1E,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAClC,6EAA6E;IAC7E,QAAQ,EAAE,OAAO,CAAC;IAClB,6CAA6C;IAC7C,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAC;IAChD,2DAA2D;IAC3D,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;IAC/C,+BAA+B;IAC/B,iBAAiB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CACzD;AAED,MAAM,WAAW,UAAU;IACzB,0EAA0E;IAC1E,GAAG,EAAE,QAAQ,CAAC;IACd,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC;IACvD,uEAAuE;IACvE,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACrC,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IAClD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IACjD,6DAA6D;IAC7D,SAAS,EAAE,KAAK,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAC3C,yEAAyE;IACzE,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD,kCAAkC;IAClC,SAAS,EAAE,MAAM,OAAO,CAAC;CAC1B;AAID,wBAAgB,UAAU,CAAC,IAAI,EAAE,cAAc,GAAG,UAAU,CAoK3D"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
// Pan / zoom / auto-fit for the <Canvas> primitive.
|
|
2
|
+
//
|
|
3
|
+
// Owns the viewport pan offset + scale, the imperative auto-fit math, the
|
|
4
|
+
// pan gesture (Space-drag / middle-mouse / empty-canvas drag), and the
|
|
5
|
+
// Space/Escape keyboard affordances + window-resize re-fit. It deliberately
|
|
6
|
+
// does NOT own `layout`, `selectedId`, or `editMode` — those stay parent-held
|
|
7
|
+
// and are threaded in as values so the auto-fit closure can read them.
|
|
8
|
+
//
|
|
9
|
+
// Extracted verbatim (behavior-preserving) from shell home.tsx's canvas block.
|
|
10
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
11
|
+
const RESERVED_PALETTE_WIDTH = 320;
|
|
12
|
+
export function usePanZoom(args) {
|
|
13
|
+
const { layout, editMode, autoFitOnResize = true, onViewportChange, onEditModeChange, onSelectionChange, } = args;
|
|
14
|
+
const [pan, setPan] = useState({ x: 0, y: 0, scale: 1 });
|
|
15
|
+
const canvasRef = useRef(null);
|
|
16
|
+
const stageRef = useRef(null);
|
|
17
|
+
const spaceDown = useRef(false);
|
|
18
|
+
const panStart = useRef(null);
|
|
19
|
+
// Latest pan reachable synchronously (for beginPan's offset seed) without
|
|
20
|
+
// adding `pan` to the gesture callbacks' deps.
|
|
21
|
+
const panRef = useRef(pan);
|
|
22
|
+
panRef.current = pan;
|
|
23
|
+
// Mirror viewport changes to the controlled parent in an effect (never
|
|
24
|
+
// inside a setState updater — that would setState-during-render the parent
|
|
25
|
+
// and trip React's "Cannot update a component while rendering a different
|
|
26
|
+
// component" warning). The ref skips the initial mount so the parent isn't
|
|
27
|
+
// notified of the default {0,0,1} before any real fit.
|
|
28
|
+
const viewportCbRef = useRef(onViewportChange);
|
|
29
|
+
viewportCbRef.current = onViewportChange;
|
|
30
|
+
const mountedViewport = useRef(false);
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
if (!mountedViewport.current) {
|
|
33
|
+
mountedViewport.current = true;
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
viewportCbRef.current?.(pan);
|
|
37
|
+
}, [pan]);
|
|
38
|
+
// Auto-fit: scale the bounding box of all items into the visible area,
|
|
39
|
+
// scaling down only (never up). Reserves the palette gutter in edit mode.
|
|
40
|
+
// Threads `layout` + `editMode` as deps so the closure never goes stale.
|
|
41
|
+
const autoFit = useCallback((animate = true) => {
|
|
42
|
+
const canvas = canvasRef.current;
|
|
43
|
+
const items = Object.values(layout);
|
|
44
|
+
if (!canvas || !items.length)
|
|
45
|
+
return;
|
|
46
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
47
|
+
for (const w of items) {
|
|
48
|
+
if (w.x < minX)
|
|
49
|
+
minX = w.x;
|
|
50
|
+
if (w.y < minY)
|
|
51
|
+
minY = w.y;
|
|
52
|
+
if (w.x + w.w > maxX)
|
|
53
|
+
maxX = w.x + w.w;
|
|
54
|
+
if (w.y + w.h > maxY)
|
|
55
|
+
maxY = w.y + w.h;
|
|
56
|
+
}
|
|
57
|
+
const cw = canvas.clientWidth - (editMode ? RESERVED_PALETTE_WIDTH : 0) - 40;
|
|
58
|
+
const ch = canvas.clientHeight - 44 - 32;
|
|
59
|
+
const bw = maxX - minX;
|
|
60
|
+
const bh = maxY - minY;
|
|
61
|
+
const sx = bw > 0 ? cw / bw : 1;
|
|
62
|
+
const sy = bh > 0 ? ch / bh : 1;
|
|
63
|
+
const scale = Math.min(1, sx, sy);
|
|
64
|
+
const offX = Math.round((cw + 40 - bw * scale) / 2 - minX * scale);
|
|
65
|
+
const offY = Math.round((ch + 32 - bh * scale) / 2 - minY * scale + 22);
|
|
66
|
+
setPan({ x: offX, y: offY, scale });
|
|
67
|
+
if (stageRef.current)
|
|
68
|
+
stageRef.current.classList.toggle('is-dragging', !animate);
|
|
69
|
+
}, [layout, editMode, setPan]);
|
|
70
|
+
// Initial fit + window-resize re-fit. Empty dep array on purpose — autoFit
|
|
71
|
+
// is read through the ref-stable callback, matching the original effect.
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
requestAnimationFrame(() => autoFit(false));
|
|
74
|
+
if (!autoFitOnResize)
|
|
75
|
+
return;
|
|
76
|
+
const onResize = () => autoFit(true);
|
|
77
|
+
window.addEventListener('resize', onResize);
|
|
78
|
+
return () => window.removeEventListener('resize', onResize);
|
|
79
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
80
|
+
}, []);
|
|
81
|
+
// Re-fit whenever edit mode toggles (palette gutter changes the fit box).
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
autoFit(true);
|
|
84
|
+
}, [editMode, autoFit]);
|
|
85
|
+
// Keyboard — Escape exits edit, Space arms the pan-grab cursor.
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
const down = (e) => {
|
|
88
|
+
if (e.key === 'Escape' && editMode) {
|
|
89
|
+
onEditModeChange?.(false);
|
|
90
|
+
onSelectionChange?.(null);
|
|
91
|
+
}
|
|
92
|
+
if (e.code === 'Space' &&
|
|
93
|
+
!e.repeat &&
|
|
94
|
+
document.activeElement === document.body &&
|
|
95
|
+
canvasRef.current) {
|
|
96
|
+
spaceDown.current = true;
|
|
97
|
+
canvasRef.current.style.cursor = 'grab';
|
|
98
|
+
e.preventDefault();
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
const up = (e) => {
|
|
102
|
+
if (e.code === 'Space') {
|
|
103
|
+
spaceDown.current = false;
|
|
104
|
+
if (canvasRef.current)
|
|
105
|
+
canvasRef.current.style.cursor = '';
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
window.addEventListener('keydown', down);
|
|
109
|
+
window.addEventListener('keyup', up);
|
|
110
|
+
return () => {
|
|
111
|
+
window.removeEventListener('keydown', down);
|
|
112
|
+
window.removeEventListener('keyup', up);
|
|
113
|
+
};
|
|
114
|
+
}, [editMode, onEditModeChange, onSelectionChange]);
|
|
115
|
+
const beginPan = useCallback((clientX, clientY) => {
|
|
116
|
+
const p = panRef.current;
|
|
117
|
+
panStart.current = { x: clientX - p.x, y: clientY - p.y };
|
|
118
|
+
stageRef.current?.classList.add('is-dragging');
|
|
119
|
+
if (canvasRef.current)
|
|
120
|
+
canvasRef.current.style.cursor = 'grabbing';
|
|
121
|
+
}, []);
|
|
122
|
+
const isPanning = useCallback(() => panStart.current != null, []);
|
|
123
|
+
// Global pan move/up. Drag (item) move/up lives in use-drag-snap so this
|
|
124
|
+
// effect only owns the pan branch + its own cleanup.
|
|
125
|
+
useEffect(() => {
|
|
126
|
+
const onMove = (e) => {
|
|
127
|
+
if (panStart.current) {
|
|
128
|
+
setPan((p) => ({
|
|
129
|
+
...p,
|
|
130
|
+
x: e.clientX - panStart.current.x,
|
|
131
|
+
y: e.clientY - panStart.current.y,
|
|
132
|
+
}));
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
const onUp = () => {
|
|
136
|
+
if (panStart.current) {
|
|
137
|
+
panStart.current = null;
|
|
138
|
+
stageRef.current?.classList.remove('is-dragging');
|
|
139
|
+
if (canvasRef.current)
|
|
140
|
+
canvasRef.current.style.cursor = spaceDown.current ? 'grab' : '';
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
window.addEventListener('mousemove', onMove);
|
|
144
|
+
window.addEventListener('mouseup', onUp);
|
|
145
|
+
return () => {
|
|
146
|
+
window.removeEventListener('mousemove', onMove);
|
|
147
|
+
window.removeEventListener('mouseup', onUp);
|
|
148
|
+
};
|
|
149
|
+
}, [setPan]);
|
|
150
|
+
return {
|
|
151
|
+
pan,
|
|
152
|
+
setPan,
|
|
153
|
+
autoFit,
|
|
154
|
+
canvasRef,
|
|
155
|
+
stageRef,
|
|
156
|
+
spaceDown,
|
|
157
|
+
beginPan,
|
|
158
|
+
isPanning,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=use-pan-zoom.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-pan-zoom.js","sourceRoot":"","sources":["../../src/canvas/use-pan-zoom.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host-bridge verb shapes for the agent-ops pkg — the **G-TRIGGER** freeze gate.
|
|
3
|
+
*
|
|
4
|
+
* Unlike the kernel RPC methods in `rpc.ts`, `host.*` verbs are dispatched
|
|
5
|
+
* FE-side in the iframe host (`shell/src/components/pkg/pkg-iframe-host.tsx`)
|
|
6
|
+
* and invoked from the iframe via `app.callServerTool({ name, arguments })`,
|
|
7
|
+
* returning their payload on `res.structuredContent`. These types are the
|
|
8
|
+
* shared contract the shell (WP-09) produces and the agent-ops pkg
|
|
9
|
+
* (WP-08 reads, WP-12 writes) consumes. Frozen so changing them after both
|
|
10
|
+
* sides exist forces a cross-repo re-sync.
|
|
11
|
+
*
|
|
12
|
+
* Gated by `capabilities.agentOps` (see `AgentOpsCapabilitySchema`).
|
|
13
|
+
*/
|
|
14
|
+
/** Typed failure codes a host.agentOps verb returns on the `{ ok: false }`
|
|
15
|
+
* branch, so the pkg UI can render a specific state rather than a raw string.
|
|
16
|
+
* - `daemon_down` — `~/.agent-ops/daemon.lock` missing or daemon not alive
|
|
17
|
+
* - `unauthorized` — the daemon rejected the token (401) — should not happen
|
|
18
|
+
* in normal operation (the shell reads the live lock)
|
|
19
|
+
* - `not_found` — no job with that id (daemon 404 / config miss)
|
|
20
|
+
* - `disabled` — job is disabled, cannot run-now (daemon 409)
|
|
21
|
+
* - `forbidden` — daemon rejected host/origin/method (403/405)
|
|
22
|
+
* - `io_error` — lock/config file unreadable or unwritable
|
|
23
|
+
* - `error` — any other failure */
|
|
24
|
+
export type AgentOpsErrorCode = 'daemon_down' | 'unauthorized' | 'not_found' | 'disabled' | 'forbidden' | 'io_error' | 'error';
|
|
25
|
+
export interface AgentOpsErrorResult {
|
|
26
|
+
ok: false;
|
|
27
|
+
code: AgentOpsErrorCode;
|
|
28
|
+
/** HTTP status from the daemon when applicable, else null. */
|
|
29
|
+
status: number | null;
|
|
30
|
+
error: string;
|
|
31
|
+
}
|
|
32
|
+
/** `host.agentOps.runNow({ jobId })` — fire an out-of-schedule run via the
|
|
33
|
+
* daemon's localhost trigger endpoint. The shell reads the 0600
|
|
34
|
+
* `~/.agent-ops/daemon.lock` for `{ port, secret }` and POSTs
|
|
35
|
+
* `127.0.0.1:<port>/jobs/<jobId>/trigger` with BOTH required headers
|
|
36
|
+
* (`x-agent-ops-token: <secret>` + `x-agent-ops-trigger: 1`). */
|
|
37
|
+
export interface AgentOpsRunNowArgs {
|
|
38
|
+
jobId: string;
|
|
39
|
+
}
|
|
40
|
+
export type AgentOpsRunNowResult = {
|
|
41
|
+
ok: true;
|
|
42
|
+
status: number;
|
|
43
|
+
message: string;
|
|
44
|
+
} | AgentOpsErrorResult;
|
|
45
|
+
/** `host.agentOps.setEnabled({ jobId, enabled })` — flip a job's `enabled`
|
|
46
|
+
* flag in the project-scoped config (`~/.atelier/skill-agent-ops/jobs.json`).
|
|
47
|
+
* The daemon honors it on next config load. Does NOT touch the executor. */
|
|
48
|
+
export interface AgentOpsSetEnabledArgs {
|
|
49
|
+
jobId: string;
|
|
50
|
+
enabled: boolean;
|
|
51
|
+
}
|
|
52
|
+
export type AgentOpsSetEnabledResult = {
|
|
53
|
+
ok: true;
|
|
54
|
+
jobId: string;
|
|
55
|
+
enabled: boolean;
|
|
56
|
+
} | AgentOpsErrorResult;
|
|
57
|
+
/** The editable job fields the CRUD form sends to `host.agentOps.upsertJob`.
|
|
58
|
+
* The host fills JobDefinition defaults (schedule_dialect, timeout_ms, retries,
|
|
59
|
+
* backoff, concurrency_policy) for any omitted field; the daemon's Zod loader
|
|
60
|
+
* is the final validation backstop on next config load. */
|
|
61
|
+
export interface AgentOpsJobInput {
|
|
62
|
+
id: string;
|
|
63
|
+
label: string;
|
|
64
|
+
schedule: string;
|
|
65
|
+
timezone?: string;
|
|
66
|
+
enabled?: boolean;
|
|
67
|
+
mode?: 'agent' | 'script';
|
|
68
|
+
command: string;
|
|
69
|
+
model?: string | null;
|
|
70
|
+
agent?: string | null;
|
|
71
|
+
schedule_dialect?: '5f' | '6f';
|
|
72
|
+
timeout_ms?: number;
|
|
73
|
+
}
|
|
74
|
+
/** `host.agentOps.upsertJob({ job })` — create-or-update a job in the
|
|
75
|
+
* project-scoped config (atomic rewrite; replace by id if present, else
|
|
76
|
+
* append). The daemon honors it on next config load. Validating-only write —
|
|
77
|
+
* the shell does NOT run the job, never becomes the executor. */
|
|
78
|
+
export interface AgentOpsUpsertJobArgs {
|
|
79
|
+
job: AgentOpsJobInput;
|
|
80
|
+
}
|
|
81
|
+
export type AgentOpsUpsertJobResult = {
|
|
82
|
+
ok: true;
|
|
83
|
+
jobId: string;
|
|
84
|
+
created: boolean;
|
|
85
|
+
} | AgentOpsErrorResult;
|
|
86
|
+
/** `host.agentOps.deleteJob({ jobId })` — remove a job from the project-scoped
|
|
87
|
+
* config (atomic rewrite). The daemon stops scheduling it on next load. */
|
|
88
|
+
export interface AgentOpsDeleteJobArgs {
|
|
89
|
+
jobId: string;
|
|
90
|
+
}
|
|
91
|
+
export type AgentOpsDeleteJobResult = {
|
|
92
|
+
ok: true;
|
|
93
|
+
jobId: string;
|
|
94
|
+
} | AgentOpsErrorResult;
|
|
95
|
+
/** `host.agentOps.tailRun({ jobId, offset? })` — read the live (or last-completed)
|
|
96
|
+
* run output for a job by byte-range, for the pkg's Live-output view.
|
|
97
|
+
*
|
|
98
|
+
* Unlike the other agent-ops verbs (which reach the daemon's localhost endpoint
|
|
99
|
+
* or rewrite its config), tailRun is a pure **filesystem read on the shell's own
|
|
100
|
+
* event loop**: it opens the per-job marker (`~/.agent-ops/runs/<slug>.marker.json`)
|
|
101
|
+
* to learn the current run's `tailPath` + `status` + `pid`, then reads that tail
|
|
102
|
+
* file from `offset` forward (capped per call). Because it never touches the
|
|
103
|
+
* daemon, the daemon being blocked mid-run (synchronously executing a job) is
|
|
104
|
+
* irrelevant — the shell still streams whatever the child has teed to disk so far.
|
|
105
|
+
*
|
|
106
|
+
* Mechanism is **script-mode only**: the daemon tees a script job's combined
|
|
107
|
+
* stdout/stderr to the tail file as it runs. Agent jobs (`claude -p`) stay
|
|
108
|
+
* byte-for-byte unchanged and have no tail file, so tailRun returns an empty
|
|
109
|
+
* chunk with `mode:'agent'` (the pkg renders 'live output not available for
|
|
110
|
+
* agent jobs' + a spinner driven off the marker's `status`).
|
|
111
|
+
*
|
|
112
|
+
* Polling loop: call with `offset:0` first, then feed the returned `nextOffset`
|
|
113
|
+
* back on each poll. `eof` true means the reader caught up to the current end of
|
|
114
|
+
* file; keep polling while `running` is true. After a run completes the marker
|
|
115
|
+
* still points at the final tail, so `running:false` STILL returns the final
|
|
116
|
+
* chunk for scrollback — the view shows the completed output, not an empty pane.
|
|
117
|
+
*
|
|
118
|
+
* - `running` — `status === 'running'` AND the marker's `pid` is alive.
|
|
119
|
+
* - `status` — the marker's `status` (`'running' | 'done'`), or `null` when
|
|
120
|
+
* no marker exists yet (job has never produced a run).
|
|
121
|
+
* - `startedAtMs` — the run's start epoch-ms from the marker, else `null`.
|
|
122
|
+
* - `mode` — `'script'` (has a tail) / `'agent'` (no tail) / `null` (no marker).
|
|
123
|
+
* - `chunk` — lossy-utf8 decode of the bytes read this call (may be empty).
|
|
124
|
+
* - `nextOffset` — `offset + bytesRead`; pass back on the next poll.
|
|
125
|
+
* - `eof` — reached the current end of the tail file.
|
|
126
|
+
*
|
|
127
|
+
* Best-effort + non-throwing on the shell side: a missing marker / missing tail /
|
|
128
|
+
* unreadable file resolves to `{ ok:true, chunk:'', eof:true, ... }` rather than
|
|
129
|
+
* an error, so the view degrades to 'no output yet'. Only a path-escape attempt
|
|
130
|
+
* (marker.tailPath pointing outside `~/.agent-ops/runs/`) maps to an
|
|
131
|
+
* `{ ok:false, code:'io_error' }`. */
|
|
132
|
+
export interface AgentOpsTailRunArgs {
|
|
133
|
+
jobId: string;
|
|
134
|
+
/** Byte offset into the tail file to read from. Defaults to 0. */
|
|
135
|
+
offset?: number;
|
|
136
|
+
}
|
|
137
|
+
export type AgentOpsTailRunResult = {
|
|
138
|
+
ok: true;
|
|
139
|
+
running: boolean;
|
|
140
|
+
status: 'running' | 'done' | null;
|
|
141
|
+
startedAtMs: number | null;
|
|
142
|
+
mode: 'agent' | 'script' | null;
|
|
143
|
+
chunk: string;
|
|
144
|
+
nextOffset: number;
|
|
145
|
+
eof: boolean;
|
|
146
|
+
} | AgentOpsErrorResult;
|
|
147
|
+
/** A merged config+state row as returned by `host.agentOps.listJobs`. Config
|
|
148
|
+
* fields come from `~/.atelier/skill-agent-ops/jobs.json` (a JobDefinition);
|
|
149
|
+
* `state` is that job's entry in `.company/cron/jobs-state.json` (or null if
|
|
150
|
+
* it has never run). Field casing matches the on-disk files (camelCase state);
|
|
151
|
+
* the pkg's data layer (WP-08) maps this into the snake_case G-VIEW. */
|
|
152
|
+
export interface AgentOpsRawJobState {
|
|
153
|
+
nextRunAtMs: number | null;
|
|
154
|
+
lastRunAtMs: number | null;
|
|
155
|
+
lastStatus: string | null;
|
|
156
|
+
consecutiveErrors: number;
|
|
157
|
+
lastDurationMs: number | null;
|
|
158
|
+
totalCostUsd: number | null;
|
|
159
|
+
totalRuns: number | null;
|
|
160
|
+
lastUsage: {
|
|
161
|
+
costUsd: number | null;
|
|
162
|
+
numTurns: number | null;
|
|
163
|
+
inputTokens: number | null;
|
|
164
|
+
outputTokens: number | null;
|
|
165
|
+
cacheReadTokens: number | null;
|
|
166
|
+
sessionId: string | null;
|
|
167
|
+
} | null;
|
|
168
|
+
}
|
|
169
|
+
export interface AgentOpsRawJob {
|
|
170
|
+
id: string;
|
|
171
|
+
label: string;
|
|
172
|
+
schedule: string;
|
|
173
|
+
schedule_dialect: '5f' | '6f';
|
|
174
|
+
timezone: string;
|
|
175
|
+
enabled: boolean;
|
|
176
|
+
command: string;
|
|
177
|
+
mode: 'agent' | 'script';
|
|
178
|
+
model: string | null;
|
|
179
|
+
agent: string | null;
|
|
180
|
+
_disabledReason: string | null;
|
|
181
|
+
state: AgentOpsRawJobState | null;
|
|
182
|
+
}
|
|
183
|
+
/** `host.agentOps.listJobs({})` — read the project-scoped job config + the
|
|
184
|
+
* daemon's runtime state file and return both, merged per job, plus daemon
|
|
185
|
+
* liveness. Run history (cron_job_runs / agent_runs) is NOT included here —
|
|
186
|
+
* the pkg reads that directly via `host.dbQuery`. */
|
|
187
|
+
export type AgentOpsListJobsArgs = Record<string, never>;
|
|
188
|
+
export type AgentOpsListJobsResult = {
|
|
189
|
+
ok: true;
|
|
190
|
+
daemon_up: boolean;
|
|
191
|
+
daemon_pid: number | null;
|
|
192
|
+
jobs: AgentOpsRawJob[];
|
|
193
|
+
} | AgentOpsErrorResult;
|
|
194
|
+
//# sourceMappingURL=host-verbs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-verbs.d.ts","sourceRoot":"","sources":["../src/host-verbs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host-bridge verb shapes for the agent-ops pkg — the **G-TRIGGER** freeze gate.
|
|
3
|
+
*
|
|
4
|
+
* Unlike the kernel RPC methods in `rpc.ts`, `host.*` verbs are dispatched
|
|
5
|
+
* FE-side in the iframe host (`shell/src/components/pkg/pkg-iframe-host.tsx`)
|
|
6
|
+
* and invoked from the iframe via `app.callServerTool({ name, arguments })`,
|
|
7
|
+
* returning their payload on `res.structuredContent`. These types are the
|
|
8
|
+
* shared contract the shell (WP-09) produces and the agent-ops pkg
|
|
9
|
+
* (WP-08 reads, WP-12 writes) consumes. Frozen so changing them after both
|
|
10
|
+
* sides exist forces a cross-repo re-sync.
|
|
11
|
+
*
|
|
12
|
+
* Gated by `capabilities.agentOps` (see `AgentOpsCapabilitySchema`).
|
|
13
|
+
*/
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=host-verbs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-verbs.js","sourceRoot":"","sources":["../src/host-verbs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAE7B,kCAAkC;AAClC,eAAO,MAAM,wBAAwB,EAAG,OAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAE7B,kCAAkC;AAClC,eAAO,MAAM,wBAAwB,EAAG,OAAgB,CAAC"}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAE7B,kCAAkC;AAClC,MAAM,CAAC,MAAM,wBAAwB,GAAG,OAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAE7B,kCAAkC;AAClC,MAAM,CAAC,MAAM,wBAAwB,GAAG,OAAgB,CAAC"}
|