gentle-pi 4.3.0 → 4.4.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/README.md +8 -5
- package/assets/agents/gentle-ai-worker.md +1 -1
- package/assets/design-canvas/canvas.css +648 -0
- package/assets/design-canvas/canvas.js +1497 -0
- package/assets/design-canvas/index.html +88 -0
- package/assets/design-canvas/inspector.js +290 -0
- package/assets/orchestrator-delegation-reference.md +2 -2
- package/assets/orchestrator-verification.md +1 -1
- package/assets/orchestrator.md +2 -2
- package/bin/engram-guard +1 -1
- package/bin/gentle-shell.mjs +101 -151
- package/docs/bundled-install.md +47 -42
- package/docs/delegated-verification.md +6 -0
- package/docs/gentle-agents-activity.md +5 -1
- package/docs/gentle-music.md +61 -0
- package/docs/gentle-shell.md +77 -7
- package/docs/install-wizard.md +30 -6
- package/docs/permission-modes.md +7 -2
- package/docs/readme-reference.md +19 -15
- package/docs/session-profile-format.md +26 -0
- package/docs/voice.md +259 -0
- package/docs/yolo-mode.md +17 -2
- package/extensions/ask-user-choice.ts +4 -1
- package/extensions/gentle-agents.ts +173 -38
- package/extensions/gentle-ai.ts +214 -69
- package/extensions/gentle-design.ts +158 -0
- package/extensions/gentle-music.ts +289 -0
- package/extensions/gentle-shell.ts +332 -73
- package/extensions/gentle-voice.ts +11 -0
- package/extensions/session-scratch.ts +41 -22
- package/extensions/skill-registry.ts +63 -8
- package/lib/agent-profiles.ts +26 -0
- package/lib/agents-config.ts +35 -0
- package/lib/agents-protocol.ts +57 -1
- package/lib/agents-runner.ts +52 -3
- package/lib/agents-session-transport.ts +101 -6
- package/lib/agents-widget.ts +14 -1
- package/lib/auto-permission-memory.ts +48 -18
- package/lib/auto-permission-runtime.ts +21 -6
- package/lib/clipboard-image.ts +147 -0
- package/lib/command-palette-catalog.ts +2 -0
- package/lib/commit-slice-signal.ts +1 -1
- package/lib/context-backstop.ts +36 -0
- package/lib/design-canvas-server.ts +947 -0
- package/lib/design-comments.ts +437 -0
- package/lib/design-handoffs.ts +313 -0
- package/lib/design-open-browser.ts +58 -0
- package/lib/design-sources.ts +120 -0
- package/lib/external-editor.ts +31 -0
- package/lib/gentle-design.ts +513 -0
- package/lib/gentle-shell-bundled.ts +123 -49
- package/lib/gentle-shell-launcher.ts +9 -4
- package/lib/gentle-shell-startup-update.ts +61 -9
- package/lib/gentle-shell-uninstall.ts +33 -1
- package/lib/image-attachments.ts +150 -0
- package/lib/inprocess-reviewer.ts +33 -2
- package/lib/nan-provider.ts +3 -0
- package/lib/native-review-cli.ts +11 -4
- package/lib/notification-audio-native.ts +149 -13
- package/lib/notification-audio.ts +4 -0
- package/lib/notification-pulse-worker.ts +82 -18
- package/lib/notification-service.ts +5 -1
- package/lib/orchestrator-presence.ts +78 -8
- package/lib/orchestrator-scope.ts +10 -0
- package/lib/orchestrator-state.ts +11 -3
- package/lib/permission-mode-policy.ts +2 -2
- package/lib/review-host-relay.ts +11 -2
- package/lib/review-reminder-receipt.ts +24 -1
- package/lib/session-profile-append-controller.ts +713 -0
- package/lib/session-profile-disk-reader.ts +182 -0
- package/lib/session-profile-persistence.ts +15 -7
- package/lib/session-scratch.ts +52 -3
- package/lib/session-worktree-registry.ts +7 -0
- package/lib/shell-bar.ts +4 -3
- package/lib/shell-changes.ts +81 -5
- package/lib/shell-prompt.ts +4 -4
- package/lib/shell-sidebar-layout.ts +26 -6
- package/lib/shell-todo.ts +1 -1
- package/lib/verifier-admission.ts +5 -4
- package/lib/vim-editor-adapter.ts +11 -8
- package/lib/voice-artifacts.ts +188 -0
- package/lib/voice-command.ts +576 -0
- package/lib/voice-install.ts +455 -0
- package/lib/voice-platform.ts +99 -0
- package/lib/voice-push-to-talk.ts +262 -0
- package/lib/voice-session.ts +460 -0
- package/lib/voice-settings.ts +50 -0
- package/lib/voice-ui.ts +158 -0
- package/lib/yolo-session-policy.ts +58 -22
- package/package.json +1 -1
- package/runtime/gentle-shell-bundled.mjs +122 -48
- package/runtime/gentle-shell-launcher.mjs +9 -4
- package/runtime/gentle-shell-startup-update.mjs +61 -9
- package/runtime/gentle-shell-uninstall.mjs +33 -1
- package/runtime/native-review-cli.mjs +11 -4
- package/scripts/bundled-engram-migration.mjs +0 -6
- package/scripts/gentle-ai-installer.mjs +10 -10
- package/scripts/installer-downloads.mjs +7 -7
- package/scripts/installer-preflight.mjs +5 -3
- package/scripts/installer-windows.mjs +37 -7
- package/scripts/main-channel.mjs +91 -17
- package/scripts/pi-update.mjs +34 -6
- package/scripts/verify-package-files.mjs +26 -2
- package/scripts/voice-worker.cjs +476 -0
- package/skills/design/SKILL.md +110 -0
- package/tests/agent-profiles.test.ts +24 -0
- package/tests/agents-config.test.ts +61 -0
- package/tests/agents-fake-child.ts +8 -1
- package/tests/agents-protocol.test.ts +32 -0
- package/tests/agents-runner.test.ts +226 -5
- package/tests/agents-session-transport.test.ts +53 -3
- package/tests/ask-user-choice.test.ts +30 -0
- package/tests/auto-mode.test.ts +17 -0
- package/tests/auto-permission-memory-diagnostics.test.ts +56 -0
- package/tests/auto-permission-runtime.test.ts +85 -1
- package/tests/autonomous-guard.test.ts +20 -0
- package/tests/bundled-install.test.ts +3 -3
- package/tests/clipboard-image.test.ts +114 -0
- package/tests/command-palette.test.ts +1 -1
- package/tests/context-backstop.test.ts +70 -4
- package/tests/delegate-for-reason-contract.test.ts +2 -1
- package/tests/design-canvas-assets.test.ts +710 -0
- package/tests/design-canvas-server.test.ts +1096 -0
- package/tests/design-comments.test.ts +201 -0
- package/tests/design-handoffs.test.ts +282 -0
- package/tests/design-open-browser.test.ts +70 -0
- package/tests/design-sources.test.ts +132 -0
- package/tests/engram-safety.test.ts +132 -57
- package/tests/external-editor.test.ts +84 -0
- package/tests/fixtures/primary-session-prompt/gentleman.golden.md +3 -3
- package/tests/gentle-agents.test.ts +365 -20
- package/tests/gentle-ai-binary.test.ts +1 -1
- package/tests/gentle-ai-installer.test.ts +51 -51
- package/tests/gentle-ai.test.ts +292 -13
- package/tests/gentle-design.test.ts +1313 -0
- package/tests/gentle-music.test.ts +335 -0
- package/tests/gentle-shell-bundled.test.ts +301 -248
- package/tests/gentle-shell-launcher.test.ts +28 -2
- package/tests/gentle-shell-startup-update.test.ts +77 -1
- package/tests/gentle-shell-uninstall.test.ts +59 -0
- package/tests/gentle-shell.test.ts +183 -8
- package/tests/gentle-todo.test.ts +11 -0
- package/tests/image-attachments.test.ts +119 -0
- package/tests/image-paste-chips.test.ts +236 -0
- package/tests/inprocess-reviewer.test.ts +55 -2
- package/tests/installer-bundles.test.ts +12 -6
- package/tests/installer-posix-bootstrap.test.ts +8 -8
- package/tests/installer-preflight.test.ts +16 -0
- package/tests/installer-server.test.ts +2 -2
- package/tests/installer-windows-bootstrap.test.ts +61 -3
- package/tests/installer-windows-diagnostics.test.ts +111 -0
- package/tests/main-channel-upgrade.test.ts +232 -2
- package/tests/main-channel.test.ts +140 -21
- package/tests/nan-provider.test.ts +36 -0
- package/tests/native-review-capability-contract.test.ts +11 -4
- package/tests/native-review-parity.test.ts +1 -1
- package/tests/notification-audio-native.test.ts +128 -9
- package/tests/notification-customize.test.ts +17 -5
- package/tests/odd-routing-canonical-ratchet.test.ts +2 -1
- package/tests/orchestrator-budget.test.ts +5 -2
- package/tests/orchestrator-presence.test.ts +100 -2
- package/tests/orchestrator-rdd-ownership.test.ts +2 -2
- package/tests/orchestrator-scope.test.ts +14 -0
- package/tests/orchestrator-state.test.ts +29 -0
- package/tests/package-files.test.ts +34 -0
- package/tests/package-manifest.test.ts +6 -6
- package/tests/permission-mode-policy.test.ts +10 -1
- package/tests/pi-update.test.ts +99 -4
- package/tests/rdd-aware-verification-contract.test.ts +1 -1
- package/tests/review-host-relay-routing.test.ts +88 -1
- package/tests/review-host-relay.test.ts +9 -2
- package/tests/review-json-arguments.test.ts +20 -3
- package/tests/review-loadout-rdd-off-sdk.test.ts +23 -2
- package/tests/review-relay-transport-agent.test.ts +26 -0
- package/tests/review-reminder-receipt.test.ts +31 -1
- package/tests/session-changes.test.ts +2 -1
- package/tests/session-profile-append-controller-fork.test.ts +458 -0
- package/tests/session-profile-append-controller-pi.test.ts +290 -0
- package/tests/session-profile-append-controller.test.ts +731 -0
- package/tests/session-profile-disk-reader-pi.test.ts +183 -0
- package/tests/session-profile-disk-reader.test.ts +311 -0
- package/tests/session-scratch.test.ts +68 -2
- package/tests/session-worktree-registry.test.ts +13 -1
- package/tests/shell-bar.test.ts +14 -2
- package/tests/shell-changes.test.ts +148 -1
- package/tests/shell-prompt.test.ts +3 -3
- package/tests/shell-render-cache.test.ts +134 -1
- package/tests/shell-sidebar-layout.test.ts +50 -0
- package/tests/short-check-routing-contract.test.ts +1 -1
- package/tests/skill-collision-prefixes.test.ts +3 -1
- package/tests/skill-registry-watcher.test.ts +17 -5
- package/tests/skill-registry.test.ts +47 -3
- package/tests/task-size-routing-contract.test.ts +1 -1
- package/tests/test-strength-contract.test.ts +1 -1
- package/tests/verifier-admission.test.ts +18 -1
- package/tests/voice-command.test.ts +773 -0
- package/tests/voice-install.test.ts +323 -0
- package/tests/voice-platform.test.ts +176 -0
- package/tests/voice-push-to-talk.test.ts +444 -0
- package/tests/voice-session.test.ts +434 -0
- package/tests/voice-settings.test.ts +49 -0
- package/tests/voice-ui.test.ts +97 -0
- package/tests/voice-worker.test.ts +445 -0
- package/tests/weak-model-economy-prompt.test.ts +32 -0
- package/tests/windows-hidden-processes.test.ts +25 -2
- package/tests/yolo-customize.test.ts +5 -1
- package/tests/yolo-mode.test.ts +1 -1
- package/tests/yolo-session-policy-capture.test.ts +104 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<meta name="referrer" content="no-referrer">
|
|
7
|
+
<title>Gentle Design</title>
|
|
8
|
+
<link rel="stylesheet" href="{{BASE}}assets/canvas.css">
|
|
9
|
+
<script id="gd-config" type="application/json">{{CONFIG}}</script>
|
|
10
|
+
<script src="{{BASE}}assets/canvas.js" defer></script>
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<header class="gd-bar" role="toolbar" aria-label="Design canvas controls">
|
|
14
|
+
<h1 class="gd-title" id="gd-title">Gentle Design</h1>
|
|
15
|
+
<label class="gd-field" id="gd-design-field">
|
|
16
|
+
<span class="gd-visually-hidden">Design</span>
|
|
17
|
+
<select id="gd-design" aria-label="Design"></select>
|
|
18
|
+
</label>
|
|
19
|
+
<p id="gd-feature" class="gd-feature" hidden></p>
|
|
20
|
+
<div class="gd-group" role="group" aria-label="Zoom">
|
|
21
|
+
<button type="button" id="gd-zoom-out" aria-label="Zoom out">−</button>
|
|
22
|
+
<output id="gd-zoom-level" aria-live="polite" aria-label="Zoom level">100%</output>
|
|
23
|
+
<button type="button" id="gd-zoom-in" aria-label="Zoom in">+</button>
|
|
24
|
+
<button type="button" id="gd-fit">Fit</button>
|
|
25
|
+
</div>
|
|
26
|
+
<p id="gd-nav-mode" class="gd-nav-mode" role="status" aria-live="polite">Navigating</p>
|
|
27
|
+
<button type="button" id="gd-comment" class="gd-toggle" aria-pressed="false">Comment</button>
|
|
28
|
+
<div class="gd-group" role="radiogroup" aria-label="When a comment is sent to the session">
|
|
29
|
+
<label class="gd-radio"><input type="radio" name="gd-send-mode" id="gd-mode-send" value="send"> Send now</label>
|
|
30
|
+
<label class="gd-radio"><input type="radio" name="gd-send-mode" id="gd-mode-collect" value="collect"> Collect</label>
|
|
31
|
+
</div>
|
|
32
|
+
<button type="button" id="gd-send-all" disabled>Send all (0)</button>
|
|
33
|
+
<button type="button" id="gd-panel-toggle" class="gd-toggle" aria-pressed="true" aria-controls="gd-panel">Comments</button>
|
|
34
|
+
<p id="gd-status" class="gd-status" role="status" aria-live="polite"></p>
|
|
35
|
+
</header>
|
|
36
|
+
<div class="gd-main">
|
|
37
|
+
<main id="gd-viewport" class="gd-viewport" aria-label="Artboards" tabindex="0">
|
|
38
|
+
<div id="gd-world" class="gd-world"></div>
|
|
39
|
+
<p id="gd-empty" class="gd-empty" hidden></p>
|
|
40
|
+
<button type="button" id="gd-back" class="gd-back" aria-keyshortcuts="Shift+Escape" title="Back to canvas (Shift+Esc)" hidden>Back to canvas</button>
|
|
41
|
+
</main>
|
|
42
|
+
<aside id="gd-panel" class="gd-panel" aria-labelledby="gd-panel-title">
|
|
43
|
+
<h2 id="gd-panel-title" class="gd-panel-title">Comments</h2>
|
|
44
|
+
<div class="gd-group gd-filter" role="group" aria-label="Show comments">
|
|
45
|
+
<button type="button" id="gd-filter-open" aria-pressed="true">Open (0)</button>
|
|
46
|
+
<button type="button" id="gd-filter-resolved" aria-pressed="false">Resolved (0)</button>
|
|
47
|
+
</div>
|
|
48
|
+
<p id="gd-panel-empty" class="gd-panel-empty">No comments yet. Turn on Comment mode and click an element.</p>
|
|
49
|
+
<ol id="gd-comment-list" class="gd-comment-list" aria-label="Comments"></ol>
|
|
50
|
+
</aside>
|
|
51
|
+
<section id="gd-compare" class="gd-compare" aria-labelledby="gd-compare-title" hidden>
|
|
52
|
+
<div class="gd-compare-bar">
|
|
53
|
+
<h2 id="gd-compare-title" class="gd-compare-title">Compare</h2>
|
|
54
|
+
<label class="gd-radio" id="gd-compare-fit-field" hidden><input type="checkbox" id="gd-compare-fit"> Scale to fit</label>
|
|
55
|
+
<a id="gd-compare-open" class="gd-compare-open" target="_blank" rel="noopener noreferrer">Open in new tab</a>
|
|
56
|
+
<button type="button" id="gd-compare-back" class="gd-primary" aria-keyshortcuts="Shift+Escape" title="Back to canvas (Shift+Esc)">Back to canvas</button>
|
|
57
|
+
</div>
|
|
58
|
+
<p id="gd-compare-message" class="gd-compare-message" role="status" aria-live="polite"></p>
|
|
59
|
+
<div id="gd-compare-stage" class="gd-compare-stage">
|
|
60
|
+
<div id="gd-compare-sizer" class="gd-compare-sizer">
|
|
61
|
+
<div id="gd-compare-panes" class="gd-compare-panes"></div>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
</section>
|
|
65
|
+
</div>
|
|
66
|
+
<div id="gd-toast" class="gd-toast" role="status" aria-live="polite" hidden></div>
|
|
67
|
+
<div id="gd-popover" class="gd-popover" role="dialog" aria-modal="false" aria-labelledby="gd-popover-title" hidden>
|
|
68
|
+
<form id="gd-popover-form">
|
|
69
|
+
<p class="gd-popover-title" id="gd-popover-title">Comment on <code id="gd-popover-target"></code></p>
|
|
70
|
+
<label class="gd-visually-hidden" for="gd-popover-text">Comment</label>
|
|
71
|
+
<textarea id="gd-popover-text" rows="4" maxlength="2000" required placeholder="What should change?"></textarea>
|
|
72
|
+
<div class="gd-shot">
|
|
73
|
+
<input type="file" id="gd-shot-input" accept="image/png,image/jpeg,image/webp,image/gif" tabindex="-1" aria-hidden="true" hidden>
|
|
74
|
+
<button type="button" id="gd-shot-attach" title="Or paste an image, or drop one here (PNG, JPEG, WebP or GIF, up to 5 MB)">Attach screenshot</button>
|
|
75
|
+
<figure id="gd-shot-preview" class="gd-shot-preview" hidden>
|
|
76
|
+
<img id="gd-shot-image" alt="Attached screenshot">
|
|
77
|
+
<button type="button" id="gd-shot-remove">Remove</button>
|
|
78
|
+
</figure>
|
|
79
|
+
</div>
|
|
80
|
+
<div class="gd-popover-actions">
|
|
81
|
+
<span id="gd-popover-message" class="gd-popover-message" role="status" aria-live="polite"></span>
|
|
82
|
+
<button type="button" id="gd-popover-cancel">Cancel</button>
|
|
83
|
+
<button type="submit" id="gd-popover-send" class="gd-primary">Send</button>
|
|
84
|
+
</div>
|
|
85
|
+
</form>
|
|
86
|
+
</div>
|
|
87
|
+
</body>
|
|
88
|
+
</html>
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
// Gentle Design artboard inspector, injected by the canvas server into every
|
|
2
|
+
// artboard. In comment mode it highlights the hovered element and reports the
|
|
3
|
+
// clicked one to the canvas; otherwise it only forwards canvas zoom and pan.
|
|
4
|
+
// It also reports where each commented element is, so the canvas can pin it.
|
|
5
|
+
// In navigation mode the canvas covers the artboard with a shield and routes
|
|
6
|
+
// comment-mode hovers and clicks here as points; in focus mode the artboard
|
|
7
|
+
// owns the wheel and the keyboard, and Shift+Esc asks the canvas to leave.
|
|
8
|
+
(() => {
|
|
9
|
+
"use strict";
|
|
10
|
+
|
|
11
|
+
if (window.parent === window) return;
|
|
12
|
+
const MAX_SELECTOR = 500;
|
|
13
|
+
const MAX_EXCERPT = 300;
|
|
14
|
+
const MARK = "data-gd-inspector";
|
|
15
|
+
const MAX_PINS = 500;
|
|
16
|
+
let enabled = false;
|
|
17
|
+
let focused = false;
|
|
18
|
+
let pins = [];
|
|
19
|
+
let reportQueued = false;
|
|
20
|
+
let hovered = null;
|
|
21
|
+
let selected = null;
|
|
22
|
+
|
|
23
|
+
function makeBox(color) {
|
|
24
|
+
const box = document.createElement("div");
|
|
25
|
+
box.setAttribute(MARK, "");
|
|
26
|
+
box.setAttribute("aria-hidden", "true");
|
|
27
|
+
Object.assign(box.style, {
|
|
28
|
+
position: "fixed",
|
|
29
|
+
pointerEvents: "none",
|
|
30
|
+
zIndex: "2147483647",
|
|
31
|
+
border: `2px solid ${color}`,
|
|
32
|
+
background: "rgba(138, 180, 255, 0.12)",
|
|
33
|
+
borderRadius: "2px",
|
|
34
|
+
display: "none",
|
|
35
|
+
margin: "0",
|
|
36
|
+
padding: "0",
|
|
37
|
+
});
|
|
38
|
+
return box;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Attached to <html>, not <body>, so body child positions (and selectors) stay unchanged.
|
|
42
|
+
const hoverBox = makeBox("#8ab4ff");
|
|
43
|
+
const selectedBox = makeBox("#ffd479");
|
|
44
|
+
|
|
45
|
+
function place(box, element) {
|
|
46
|
+
if (!element || !element.isConnected) {
|
|
47
|
+
box.style.display = "none";
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const rect = element.getBoundingClientRect();
|
|
51
|
+
Object.assign(box.style, {
|
|
52
|
+
display: "block",
|
|
53
|
+
left: `${rect.left - 2}px`,
|
|
54
|
+
top: `${rect.top - 2}px`,
|
|
55
|
+
width: `${rect.width + 4}px`,
|
|
56
|
+
height: `${rect.height + 4}px`,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function refresh() {
|
|
61
|
+
place(hoverBox, enabled ? hovered : null);
|
|
62
|
+
place(selectedBox, selected);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function ensureBoxes() {
|
|
66
|
+
if (!hoverBox.isConnected) document.documentElement.append(hoverBox, selectedBox);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function setEnabled(next) {
|
|
70
|
+
enabled = next;
|
|
71
|
+
if (enabled) ensureBoxes();
|
|
72
|
+
document.documentElement.style.cursor = enabled ? "crosshair" : "";
|
|
73
|
+
if (!enabled) {
|
|
74
|
+
hovered = null;
|
|
75
|
+
selected = null;
|
|
76
|
+
}
|
|
77
|
+
refresh();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function isOwn(node) {
|
|
81
|
+
return node instanceof Element && node.hasAttribute(MARK);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function elementOf(node) {
|
|
85
|
+
if (!(node instanceof Element) || isOwn(node)) return null;
|
|
86
|
+
return node === document.documentElement ? document.body : node;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function targetOf(event) {
|
|
90
|
+
return elementOf(event.target);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** The element under a point the canvas routed from its shield, in artboard coordinates. */
|
|
94
|
+
function elementAt(data) {
|
|
95
|
+
if (typeof data.x !== "number" || typeof data.y !== "number" || !Number.isFinite(data.x) || !Number.isFinite(data.y)) return null;
|
|
96
|
+
return elementOf(document.elementFromPoint(data.x, data.y));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function hasUniqueId(element) {
|
|
100
|
+
if (!element.id) return false;
|
|
101
|
+
try {
|
|
102
|
+
return document.querySelectorAll(`#${CSS.escape(element.id)}`).length === 1;
|
|
103
|
+
} catch {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** Stable selector: a unique id when there is one, else a tag:nth-of-type chain up to body. */
|
|
109
|
+
function cssSelector(element) {
|
|
110
|
+
if (!element || element === document.body || element === document.documentElement) return "body";
|
|
111
|
+
const parts = [];
|
|
112
|
+
let anchored = false;
|
|
113
|
+
for (let node = element; node && node !== document.body && node !== document.documentElement; node = node.parentElement) {
|
|
114
|
+
if (hasUniqueId(node)) {
|
|
115
|
+
parts.unshift(`#${CSS.escape(node.id)}`);
|
|
116
|
+
anchored = true;
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
const tag = node.localName;
|
|
120
|
+
const parent = node.parentElement;
|
|
121
|
+
const siblings = parent ? Array.from(parent.children).filter((child) => child.localName === tag) : [];
|
|
122
|
+
parts.unshift(siblings.length > 1 ? `${tag}:nth-of-type(${siblings.indexOf(node) + 1})` : tag);
|
|
123
|
+
}
|
|
124
|
+
if (!anchored) parts.unshift("body");
|
|
125
|
+
while (parts.join(" > ").length > MAX_SELECTOR && parts.length > 1) parts.shift();
|
|
126
|
+
return parts.join(" > ").slice(0, MAX_SELECTOR);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function excerptOf(element) {
|
|
130
|
+
const text = element.innerText || element.textContent || element.getAttribute("aria-label") || element.getAttribute("alt") || element.getAttribute("title") || "";
|
|
131
|
+
return text.replace(/\s+/g, " ").trim().slice(0, MAX_EXCERPT);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function post(message) {
|
|
135
|
+
window.parent.postMessage(message, "*");
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function find(selector) {
|
|
139
|
+
try {
|
|
140
|
+
return document.querySelector(selector);
|
|
141
|
+
} catch {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** Where each pinned comment's element is now; null when its selector no longer matches. */
|
|
147
|
+
function reportPins() {
|
|
148
|
+
reportQueued = false;
|
|
149
|
+
post({
|
|
150
|
+
type: "gd:pin-rects",
|
|
151
|
+
rects: pins.map((pin) => {
|
|
152
|
+
const element = find(pin.selector);
|
|
153
|
+
if (!element) return { id: pin.id, rect: null };
|
|
154
|
+
const rect = element.getBoundingClientRect();
|
|
155
|
+
return { id: pin.id, rect: { x: rect.left, y: rect.top, width: rect.width, height: rect.height } };
|
|
156
|
+
}),
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function queueReport() {
|
|
161
|
+
if (reportQueued || pins.length === 0) return;
|
|
162
|
+
reportQueued = true;
|
|
163
|
+
requestAnimationFrame(reportPins);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function setPins(value) {
|
|
167
|
+
if (!Array.isArray(value)) return;
|
|
168
|
+
pins = value.slice(0, MAX_PINS).filter((pin) => pin && typeof pin.id === "string" && pin.id.length <= 32 && typeof pin.selector === "string" && pin.selector.length <= MAX_SELECTOR)
|
|
169
|
+
.map((pin) => ({ id: pin.id, selector: pin.selector }));
|
|
170
|
+
// An empty list still answers, so the canvas learns there is nothing to pin.
|
|
171
|
+
reportQueued = true;
|
|
172
|
+
requestAnimationFrame(reportPins);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function highlight(id) {
|
|
176
|
+
const pin = pins.find((candidate) => candidate.id === id);
|
|
177
|
+
const element = pin ? find(pin.selector) : null;
|
|
178
|
+
if (!element) return;
|
|
179
|
+
ensureBoxes();
|
|
180
|
+
selected = element;
|
|
181
|
+
element.scrollIntoView({ block: "nearest", inline: "nearest" });
|
|
182
|
+
refresh();
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
window.addEventListener("message", (event) => {
|
|
186
|
+
if (event.source !== window.parent || !event.data || typeof event.data !== "object") return;
|
|
187
|
+
if (event.data.type === "gd:mode") setEnabled(event.data.enabled === true);
|
|
188
|
+
else if (event.data.type === "gd:pins") setPins(event.data.pins);
|
|
189
|
+
else if (event.data.type === "gd:highlight") highlight(event.data.id);
|
|
190
|
+
else if (event.data.type === "gd:focus") focused = event.data.enabled === true;
|
|
191
|
+
else if (event.data.type === "gd:pick-at") {
|
|
192
|
+
if (enabled) pick(elementAt(event.data));
|
|
193
|
+
} else if (event.data.type === "gd:hover-at") {
|
|
194
|
+
if (!enabled) return;
|
|
195
|
+
hovered = elementAt(event.data);
|
|
196
|
+
refresh();
|
|
197
|
+
} else if (event.data.type === "gd:clear") {
|
|
198
|
+
selected = null;
|
|
199
|
+
refresh();
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
function pick(element) {
|
|
204
|
+
if (!element) return;
|
|
205
|
+
selected = element;
|
|
206
|
+
refresh();
|
|
207
|
+
const rect = element.getBoundingClientRect();
|
|
208
|
+
post({
|
|
209
|
+
type: "gd:pick",
|
|
210
|
+
selector: cssSelector(element),
|
|
211
|
+
excerpt: excerptOf(element),
|
|
212
|
+
rect: { x: rect.left, y: rect.top, width: rect.width, height: rect.height },
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
window.addEventListener("pointerover", (event) => {
|
|
217
|
+
if (!enabled) return;
|
|
218
|
+
hovered = targetOf(event);
|
|
219
|
+
refresh();
|
|
220
|
+
}, true);
|
|
221
|
+
|
|
222
|
+
window.addEventListener("click", (event) => {
|
|
223
|
+
if (!enabled) return;
|
|
224
|
+
event.preventDefault();
|
|
225
|
+
event.stopPropagation();
|
|
226
|
+
event.stopImmediatePropagation();
|
|
227
|
+
pick(targetOf(event));
|
|
228
|
+
}, true);
|
|
229
|
+
|
|
230
|
+
// While commenting, the artboard's own handlers, links and forms stay inert.
|
|
231
|
+
for (const type of ["pointerdown", "mousedown", "pointerup", "mouseup", "dblclick", "auxclick", "contextmenu", "submit"]) {
|
|
232
|
+
window.addEventListener(type, (event) => {
|
|
233
|
+
if (!enabled) return;
|
|
234
|
+
event.preventDefault();
|
|
235
|
+
event.stopPropagation();
|
|
236
|
+
event.stopImmediatePropagation();
|
|
237
|
+
}, true);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Shift+Esc is reserved for leaving focus mode, even while typing; plain Esc stays with the design.
|
|
241
|
+
// The canvas accepts the request only from the focused artboard.
|
|
242
|
+
window.addEventListener("keydown", (event) => {
|
|
243
|
+
if (event.key !== "Escape") return;
|
|
244
|
+
if (event.shiftKey) {
|
|
245
|
+
event.preventDefault();
|
|
246
|
+
event.stopImmediatePropagation();
|
|
247
|
+
post({ type: "gd:exit-focus" });
|
|
248
|
+
} else if (enabled) post({ type: "gd:escape" });
|
|
249
|
+
}, true);
|
|
250
|
+
|
|
251
|
+
function scrollableBy(element, dx, dy) {
|
|
252
|
+
if (!element) return false;
|
|
253
|
+
const root = element === document.scrollingElement;
|
|
254
|
+
const style = getComputedStyle(element);
|
|
255
|
+
const scrolls = (overflow) => root ? overflow !== "hidden" && overflow !== "clip" : overflow === "auto" || overflow === "scroll";
|
|
256
|
+
if (dy !== 0 && scrolls(style.overflowY) && (dy > 0 ? element.scrollTop + element.clientHeight < element.scrollHeight - 1 : element.scrollTop > 0)) return true;
|
|
257
|
+
if (dx !== 0 && scrolls(style.overflowX) && (dx > 0 ? element.scrollLeft + element.clientWidth < element.scrollWidth - 1 : element.scrollLeft > 0)) return true;
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function canScroll(node, dx, dy) {
|
|
262
|
+
for (let element = node instanceof Element ? node : null; element; element = element.parentElement) {
|
|
263
|
+
if (element !== document.scrollingElement && scrollableBy(element, dx, dy)) return true;
|
|
264
|
+
}
|
|
265
|
+
return scrollableBy(document.scrollingElement, dx, dy);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Ctrl/Cmd + wheel (and trackpad pinch) always zooms the canvas; a plain wheel
|
|
269
|
+
// pans the canvas only when the artboard itself cannot scroll that way.
|
|
270
|
+
// In focus mode the canvas stays put: the artboard scrolls natively, and
|
|
271
|
+
// Ctrl/Cmd + wheel is swallowed so it never zooms the browser page.
|
|
272
|
+
window.addEventListener("wheel", (event) => {
|
|
273
|
+
const zoom = event.ctrlKey || event.metaKey;
|
|
274
|
+
if (focused) {
|
|
275
|
+
if (zoom) event.preventDefault();
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
if (!zoom && canScroll(event.target, event.deltaX, event.deltaY)) return;
|
|
279
|
+
event.preventDefault();
|
|
280
|
+
post({ type: "gd:wheel", deltaX: event.deltaX, deltaY: event.deltaY, deltaMode: event.deltaMode, zoom, shift: event.shiftKey, x: event.clientX, y: event.clientY });
|
|
281
|
+
}, { passive: false, capture: true });
|
|
282
|
+
|
|
283
|
+
window.addEventListener("scroll", () => { refresh(); queueReport(); }, true);
|
|
284
|
+
window.addEventListener("resize", () => { refresh(); queueReport(); });
|
|
285
|
+
window.addEventListener("load", queueReport);
|
|
286
|
+
// Layout changes (late images, artboard scripts) move pinned elements; the inspector's own boxes do not count.
|
|
287
|
+
new MutationObserver((records) => {
|
|
288
|
+
if (records.some((record) => !(record.target instanceof Element && record.target.hasAttribute(MARK)))) queueReport();
|
|
289
|
+
}).observe(document.documentElement, { childList: true, subtree: true, attributes: true, characterData: true });
|
|
290
|
+
})();
|
|
@@ -52,7 +52,7 @@ Progress is published automatically from the todo list: never call `orchestrator
|
|
|
52
52
|
| Write a large task with no Writer rule reason | ✅ following the logbook | — |
|
|
53
53
|
| Write a unit with a Writer rule reason | — | ✅ one bounded writer per unit |
|
|
54
54
|
| Bash for state (`git`, `gh`) | ✅ | — |
|
|
55
|
-
| Focused test and suite of the change being made | ✅
|
|
55
|
+
| Focused test and suite of the change being made | ✅ in one command | — |
|
|
56
56
|
| Named high-risk item (assess `escalate`), or long suites, builds, or installs of a large task | — | ✅ independent `gentle-ai-verify` |
|
|
57
57
|
|
|
58
58
|
Use the platform's native bounded worker for delegated-direct work.
|
|
@@ -77,7 +77,7 @@ Route work through the smallest harness that is safe. "Smallest" means minimal s
|
|
|
77
77
|
|
|
78
78
|
#### 1. Inline Direct
|
|
79
79
|
|
|
80
|
-
Use inline execution when the task is small by the always-on Task Size section: read, edit (one understood change may span files), run its focused test and suite
|
|
80
|
+
Use inline execution when the task is small by the always-on Task Size section: read, edit (one understood change may span files), run its focused test and suite in one command, or bash for state. Keep the ODD path proportionate. When a mechanism's own trigger fires, turn on only that mechanism, then re-evaluate.
|
|
81
81
|
|
|
82
82
|
#### 2. Simple Delegation
|
|
83
83
|
|
|
@@ -13,7 +13,7 @@ Bind this to the parent Pi session only. Load it when the Verification rule fire
|
|
|
13
13
|
| high | only through `escalate` naming a Task Size high-risk item: writer self-verification plus one separate `gentle-ai-verify` run |
|
|
14
14
|
| native high, unknown, or assess failed | informs only: writer self-verification stands; escalate when a named high-risk item applies |
|
|
15
15
|
|
|
16
|
-
The independent verifier runs only when the change touches a named Task Size high-risk item, passed as `escalate` (
|
|
16
|
+
The independent verifier runs only when the change touches a named Task Size high-risk item, passed as `escalate` (runtime admits its launch on a `Risk: item N` line or sentence, a feature-document task line, or past the context backstop); never for size, a native tier alone, a failed assessment, or the model or effort that wrote the change. An unknown `Receipt-driven development:` line never lowers a tier below `off`. The parent spot check (re-running one reported command before delivery) stays required in every tier. ASSESS takes the writer profile from the runtime-recorded model and effort of the pending mutations for the root; caller `writerModelId`/`writerEffort` are only a fallback when no runtime evidence exists; the writer profile is reported but never adds a verifier. When native reports them, ASSESS also projects `reviewDue`, `reviewDueReason`, `candidate.consumed`, and the native continuation verbatim; relay that continuation unchanged and never rebuild it. A native code review is not a substitute for applicable functional checks: tests, builds, and functional verification such as browser checks for UI changes still run when applicable, and review outcomes never authorize delivery. The change's own focused test and suite run inline.
|
|
17
17
|
|
|
18
18
|
## Agent escalation (gentle-shell#1494)
|
|
19
19
|
|
package/assets/orchestrator.md
CHANGED
|
@@ -36,9 +36,9 @@ A task is **small** when all three hold:
|
|
|
36
36
|
|
|
37
37
|
The number of files, commands or tests, fixes, or a requested `todo` list never decides size. A task is **large** only when the resume test fails (several sessions, external waits, deliverables the user wants apart (never several features asked at once), requirements compaction could lose); large tasks get ODD tracking and workers only by the Writer rule, else inline.
|
|
38
38
|
|
|
39
|
-
Small path: inline (parent; `bash_background` policy); observe RED inline before the fix; run the focused test and the suite inline
|
|
39
|
+
Small path: inline (parent; `bash_background` policy); read only what you change and its helpers, in one batch; observe RED inline before the fix; run the focused test and the suite inline in one command. No explore, worker, or verifier; no feature document, mirror, or commits unless the user asks; no `todo`. It needs no lazy asset.
|
|
40
40
|
|
|
41
|
-
**High risk**: a mistake would be hard to detect, hard to undo, or reaches beyond the change: (1) data or irreversible effects (migrations, rewriting or deleting stored data, format changes, writing data without validation; not saving new records); (2) security (auth, permissions, credentials, secrets, guards, sandbox); (3) changing or removing contracts others already consume (public API, CLI flags, config formats, exports, mirrored prompts; not adding a flag, command or optional field; requested changes are not; unrequested breaks in shared code are); (4) concurrency; (5) delivery or environment (installers, release, CI, deploy, dependencies); (6) no test would catch a regression in what changes. Count "unclear" as high only when a bounded look cannot tell whether (1)-(5) apply. When RDD is on and native assess returns a tier, that tier wins.
|
|
41
|
+
**High risk**: a mistake would be hard to detect, hard to undo, or reaches beyond the change: (1) data or irreversible effects that cannot be rebuilt (migrations, rewriting or deleting stored data, format changes, writing data without validation; not saving new records, nor a dev or test database a seed or backup rebuilds); (2) security (auth, permissions, credentials, secrets, guards, sandbox); (3) changing or removing contracts others already consume (public API, CLI flags, config formats, exports, mirrored prompts; not adding a flag, command or optional field; requested changes are not; unrequested breaks in shared code are); (4) concurrency; (5) delivery or environment (installers, release, CI, deploy, dependencies); (6) no test would catch a regression in what changes. Count "unclear" as high only when a bounded look cannot tell whether (1)-(5) apply. When RDD is on and native assess returns a tier, that tier wins.
|
|
42
42
|
|
|
43
43
|
**Risk line**: close every code change, small path or delegated, with `Risk: item N (reason)` or `Risk: none` per the list; any item → Verification rule.
|
|
44
44
|
|
package/bin/engram-guard
CHANGED
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
# local Engram data only by running ENGRAM_BIN, so failing here stops them
|
|
6
6
|
# before any store is opened, created or migrated. It never runs Engram and
|
|
7
7
|
# never reads or writes Engram data; the notice is printed as data, not run.
|
|
8
|
-
printf '%s\n' "${ENGRAM_STARTUP_NOTICE:-Engram memory disabled: Shell could not verify safe
|
|
8
|
+
printf '%s\n' "${ENGRAM_STARTUP_NOTICE:-Engram memory disabled: Shell could not verify safe server reuse. Matching versions or updating alone do not prove compatibility. Reuse requires a server on 127.0.0.1:7437 with verified /compatibility evidence; Shell never stops or replaces a server already listening there. Back up existing Engram data before manual changes; do not delete it or bypass the safety check. Shell rechecks on every launch and remains usable without memory.}" >&2
|
|
9
9
|
exit 78
|