gentle-pi 3.7.0 → 4.0.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 +37 -6
- package/assets/agents/gentle-ai-explore.md +4 -4
- package/assets/agents/gentle-ai-verify.md +6 -4
- package/assets/agents/gentle-ai-worker.md +7 -9
- package/assets/orchestrator-delegation.md +40 -41
- package/assets/orchestrator-memory.md +1 -22
- package/assets/orchestrator-skills.md +1 -1
- package/assets/orchestrator.md +12 -24
- package/assets/support/strict-tdd-verify.md +4 -266
- package/assets/support/strict-tdd.md +8 -360
- package/bin/gentle-shell.mjs +254 -29
- package/docs/delegated-verification.md +26 -1
- package/docs/gentle-agents-activity.md +24 -0
- package/docs/gentle-shell.md +92 -28
- package/docs/native-authority-architecture.md +2 -2
- package/docs/prompt-history.md +280 -0
- package/docs/readme-reference.md +112 -206
- package/docs/telemetry.md +1 -1
- package/docs/yolo-mode.md +86 -0
- package/extensions/child-context.ts +26 -0
- package/extensions/child-safety.ts +23 -0
- package/extensions/gentle-agents.ts +429 -262
- package/extensions/gentle-ai.ts +781 -683
- package/extensions/gentle-shell.ts +1375 -88
- package/extensions/gentle-stats.ts +101 -0
- package/extensions/gentle-todo.ts +18 -7
- package/extensions/history/atomic-write.ts +38 -0
- package/extensions/history/hide-prompts.ts +183 -0
- package/extensions/history/index.ts +1419 -0
- package/extensions/history/load-shared-history.ts +39 -0
- package/extensions/history/selector-helpers.ts +538 -0
- package/extensions/history/session-scan.ts +233 -0
- package/extensions/history/store.ts +1119 -0
- package/extensions/nan-provider.ts +6 -0
- package/extensions/quiet-tools.ts +179 -87
- package/extensions/resume-hint.ts +60 -0
- package/extensions/skill-registry.ts +16 -12
- package/extensions/startup-banner.ts +60 -31
- package/lib/agent-assets.ts +604 -0
- package/lib/agent-profile-pin.ts +12 -0
- package/lib/agents-message-delivery.ts +181 -0
- package/lib/agents-protocol.ts +60 -0
- package/lib/agents-runner.ts +96 -98
- package/lib/agents-view.ts +26 -3
- package/lib/agents-widget.ts +16 -9
- package/lib/append-system-prompt.ts +21 -0
- package/lib/bounded-writer-admission.ts +147 -0
- package/lib/card-style-policy.ts +60 -0
- package/lib/child-context-files.ts +166 -0
- package/lib/codemode-renderer.ts +185 -0
- package/lib/command-palette-catalog.ts +3 -9
- package/lib/command-palette.ts +25 -14
- package/lib/destructive-command-guard.ts +144 -0
- package/lib/gentle-ai-elapsed-store.ts +87 -0
- package/lib/gentle-ai-renderer.ts +196 -39
- package/lib/gentle-shell-launcher.ts +24 -13
- package/lib/gentle-shell-resume-hint.ts +176 -0
- package/lib/history-capture-policy.ts +95 -0
- package/lib/model-routing-authority.ts +5 -1
- package/lib/nan-provider.ts +227 -0
- package/lib/native-review-cli.ts +49 -108
- package/lib/odd-phase-inference.ts +231 -0
- package/lib/odd-phase.ts +141 -0
- package/lib/overlay-repaint.ts +26 -0
- package/lib/pi-tui-keys.ts +53 -0
- package/lib/review-candidate-view-owner.ts +67 -17
- package/lib/review-candidate-view.ts +112 -25
- package/lib/review-reminder-receipt.ts +48 -8
- package/lib/review-risk-assessment.ts +156 -11
- package/lib/review-sidebar-state.ts +223 -0
- package/lib/selection-engine.ts +515 -0
- package/lib/session-messaging-grants.ts +135 -0
- package/lib/session-worktree-registry.ts +14 -2
- package/lib/shell-bar.ts +179 -24
- package/lib/shell-card.ts +287 -18
- package/lib/shell-changes-view.ts +2 -1
- package/lib/shell-prompt.ts +102 -6
- package/lib/shell-sidebar-layout.ts +78 -14
- package/lib/shell-sidebar.ts +15 -1
- package/lib/shell-todo.ts +23 -13
- package/lib/shell-usage-view.ts +9 -4
- package/lib/shell-usage.ts +66 -10
- package/lib/stats-collector.ts +381 -0
- package/lib/stats-view.ts +431 -0
- package/lib/theme-customization.ts +52 -0
- package/lib/vim-editor-adapter.ts +379 -0
- package/lib/vim-normal-engine.ts +154 -0
- package/lib/vim-operator-engine.ts +416 -0
- package/lib/vim-policy.ts +49 -0
- package/lib/vim-visual-engine.ts +107 -0
- package/lib/visual-customization-policy.ts +108 -0
- package/lib/visual-customize-view.ts +330 -0
- package/lib/visual-profiles.ts +228 -0
- package/lib/yolo-session-policy.ts +240 -0
- package/package.json +20 -8
- package/runtime/gentle-shell-launcher.mjs +23 -12
- package/runtime/gentle-shell-resume-hint.mjs +177 -0
- package/runtime/native-review-cli.mjs +49 -108
- package/runtime/review-risk-assessment.mjs +154 -9
- package/scripts/build-runtime-modules.mjs +1 -0
- package/scripts/gentle-ai-installer.mjs +14 -13
- package/scripts/mirror-odd-routing.mjs +2 -2
- package/scripts/run-test-suite.mjs +76 -0
- package/scripts/test-packed-runner.mjs +31 -14
- package/scripts/verify-package-files.mjs +11 -22
- package/skills/branch-pr/SKILL.md +24 -52
- package/skills/chained-pr/SKILL.md +31 -15
- package/skills/chained-pr/references/chaining-details.md +31 -20
- package/skills/gentle-ai/SKILL.md +9 -15
- package/skills/issue-creation/SKILL.md +8 -2
- package/skills/issue-creation/references/delegated-workflow-actions.md +19 -0
- package/skills/work-unit-commits/SKILL.md +4 -3
- package/tests/agent-profiles.test.ts +18 -0
- package/tests/agents-fake-child.ts +2 -2
- package/tests/agents-message-delivery.test.ts +106 -0
- package/tests/agents-protocol.test.ts +40 -0
- package/tests/agents-runner.test.ts +378 -89
- package/tests/agents-view-thread-identity.test.ts +169 -0
- package/tests/agents-view.test.ts +8 -2
- package/tests/agents-widget.test.ts +154 -15
- package/tests/append-system-prompt-route.test.ts +160 -0
- package/tests/append-system-prompt.test.ts +46 -0
- package/tests/artifact-language.test.ts +19 -213
- package/tests/ask-user-question.test.ts +44 -1
- package/tests/asset-installation-runtime.test.ts +5 -16
- package/tests/autonomous-guard.test.ts +69 -1
- package/tests/bounded-writer-admission.test.ts +95 -0
- package/tests/branch-pr-skill.test.ts +43 -0
- package/tests/card-style-policy.test.ts +55 -0
- package/tests/chained-pr-skill.test.ts +124 -0
- package/tests/child-context-files.test.ts +255 -0
- package/tests/child-safety.test.ts +82 -0
- package/tests/codemode-rendering.test.ts +491 -0
- package/tests/command-palette.test.ts +39 -3
- package/tests/delegated-key-learnings-contract.test.ts +0 -76
- package/tests/destructive-command-guard.test.ts +84 -0
- package/tests/devbinary/native-review-parity.devtest.ts +170 -2
- package/tests/devbinary/non-git-subagent-bootstrap.devtest.ts +193 -0
- package/tests/fixtures/stats/sessions/--work-alpha--/2026-09-28T10-00-00-000Z_aaa.jsonl +7 -0
- package/tests/fixtures/stats/sessions/--work-alpha--/2026-09-29T23-00-00-000Z_bbb.jsonl +3 -0
- package/tests/fixtures/stats/sessions/--work-alpha--/2026-09-30T08-00-00-000Z_ddd.jsonl +2 -0
- package/tests/fixtures/stats/sessions/--work-alpha--/2026-09-30T09-00-00-000Z_eee.jsonl +3 -0
- package/tests/fixtures/stats/sessions/--work-alpha--/run-1/session.jsonl +2 -0
- package/tests/fixtures/stats/sessions/--work-beta--/2026-09-01T12-00-00-000Z_ccc.jsonl +2 -0
- package/tests/fixtures/stats/user-pi/sessions/--work-alpha--/2026-09-28T10-00-00-000Z_aaa.jsonl +2 -0
- package/tests/fixtures/stats/user-pi/sessions/--work-alpha--/2026-09-29T23-00-00-000Z_bbb.jsonl +4 -0
- package/tests/fixtures/stats/user-pi/sessions/--work-gamma--/2026-09-20T09-00-00-000Z_fff.jsonl +3 -0
- package/tests/generic-agent-tools.test.ts +54 -0
- package/tests/gentle-agents.test.ts +1047 -252
- package/tests/gentle-ai-binary.test.ts +3 -3
- package/tests/gentle-ai-elapsed-store.test.ts +68 -0
- package/tests/gentle-ai-installer.test.ts +68 -54
- package/tests/gentle-ai-renderer.test.ts +487 -8
- package/tests/gentle-ai.test.ts +288 -65
- package/tests/gentle-card-text.ts +2 -1
- package/tests/gentle-shell-bin.test.ts +651 -114
- package/tests/gentle-shell-launcher.test.ts +99 -52
- package/tests/gentle-shell-resume-hint.test.ts +270 -0
- package/tests/gentle-shell.test.ts +3839 -187
- package/tests/gentle-stats.test.ts +152 -0
- package/tests/gentle-theme.test.ts +4 -1
- package/tests/gentle-todo.test.ts +80 -8
- package/tests/history-atomic-write.test.ts +57 -0
- package/tests/history-capture-policy.test.ts +102 -0
- package/tests/history-command-registration.test.ts +164 -0
- package/tests/history-dedupe-entries.test.ts +123 -0
- package/tests/history-delete-backfill.test.ts +190 -0
- package/tests/history-delete-confirm.test.ts +460 -0
- package/tests/history-dispatch.test.ts +180 -0
- package/tests/history-drain-hidden.test.ts +110 -0
- package/tests/history-drain-order.test.ts +98 -0
- package/tests/history-expanded-globals.test.ts +62 -0
- package/tests/history-gc.test.ts +832 -0
- package/tests/history-header-layout.test.ts +265 -0
- package/tests/history-hide-prompts.test.ts +275 -0
- package/tests/history-lazy-windowing.test.ts +508 -0
- package/tests/history-legacy-migrate-v2.test.ts +297 -0
- package/tests/history-load-shared-history.test.ts +53 -0
- package/tests/history-max-results-cap.test.ts +76 -0
- package/tests/history-multi-reader.test.ts +203 -0
- package/tests/history-off-path.test.ts +170 -0
- package/tests/history-openflow-integration.test.ts +173 -0
- package/tests/history-overlay-margin.test.ts +326 -0
- package/tests/history-preview-layout.test.ts +93 -0
- package/tests/history-registry.test.ts +143 -0
- package/tests/history-scope-delete.test.ts +411 -0
- package/tests/history-search-caret-keys.test.ts +142 -0
- package/tests/history-seed-bootstrap.test.ts +170 -0
- package/tests/history-seed-regen.test.ts +129 -0
- package/tests/history-selector-windowing.test.ts +94 -0
- package/tests/history-session-scan-directory.test.ts +87 -0
- package/tests/history-session-scan-extract.test.ts +583 -0
- package/tests/history-session-writer.test.ts +351 -0
- package/tests/history-store-paths.test.ts +79 -0
- package/tests/history-tombstone-exact.test.ts +139 -0
- package/tests/history-wheel-mouse.test.ts +242 -0
- package/tests/inprocess-reviewer.test.ts +29 -19
- package/tests/issue-creation-skill.test.ts +61 -0
- package/tests/model-routing-authority.test.ts +16 -0
- package/tests/nan-provider.test.ts +471 -0
- package/tests/native-review-capability-contract.test.ts +7 -1
- package/tests/native-review-cli.test.ts +6 -120
- package/tests/native-review-parity-runtime.test.ts +100 -3
- package/tests/odd-integration.test.ts +67 -0
- package/tests/odd-phase-inference.test.ts +213 -0
- package/tests/odd-phase-loader.test.ts +253 -0
- package/tests/odd-phase.test.ts +307 -0
- package/tests/odd-routing-canonical-ratchet.test.ts +11 -6
- package/tests/odd-routing-contract.test.ts +86 -35
- package/tests/orchestrator-budget.test.ts +14 -39
- package/tests/orchestrator-rdd-ownership.test.ts +3 -3
- package/tests/overlay-repaint.test.ts +74 -0
- package/tests/package-manifest.test.ts +252 -115
- package/tests/packed-runner-owned-path.test.ts +46 -0
- package/tests/persona-single-channel.test.ts +6 -6
- package/tests/provider-defect-handoff.test.ts +3 -11
- package/tests/quiet-bash-runtime.test.ts +76 -0
- package/tests/quiet-tool-rendering.test.ts +409 -184
- package/tests/rdd-aware-verification-contract.test.ts +76 -1
- package/tests/rdd-status-line.test.ts +9 -4
- package/tests/resume-hint-extension.test.ts +122 -0
- package/tests/review-agent-end-preflight.test.ts +176 -12
- package/tests/review-candidate-owner-retry.test.ts +22 -1
- package/tests/review-candidate-view.test.ts +298 -0
- package/tests/review-contract-prompt.test.ts +108 -43
- package/tests/review-controller-lock-status.test.ts +0 -1
- package/tests/review-controller-native-routing.test.ts +611 -5
- package/tests/review-controller-workspace-root.test.ts +163 -4
- package/tests/review-host-relay-routing.test.ts +338 -2
- package/tests/review-integration-v2-forward.test.ts +200 -0
- package/tests/review-ledger-contract.test.ts +10 -34
- package/tests/review-reminder-receipt.test.ts +47 -1
- package/tests/review-risk-assessment.test.ts +498 -6
- package/tests/review-sidebar-state.test.ts +402 -0
- package/tests/run-test-suite.test.ts +124 -0
- package/tests/runtime-harness.mjs +145 -786
- package/tests/runtime-metrics-children.test.ts +16 -23
- package/tests/selection-engine.test.ts +421 -0
- package/tests/session-messaging-grants.test.ts +255 -0
- package/tests/session-worktree-registry.test.ts +77 -0
- package/tests/shell-bar.test.ts +382 -1
- package/tests/shell-card.test.ts +353 -1
- package/tests/shell-changes-view.test.ts +52 -0
- package/tests/shell-prompt.test.ts +94 -2
- package/tests/shell-sidebar-layout.test.ts +325 -21
- package/tests/shell-sidebar-scroll-benchmark.test.ts +255 -0
- package/tests/shell-todo.test.ts +87 -1
- package/tests/shell-usage-view.test.ts +27 -0
- package/tests/shell-usage.test.ts +73 -0
- package/tests/skill-registry.test.ts +50 -1
- package/tests/startup-banner.test.ts +130 -2
- package/tests/stats-collector.test.ts +195 -0
- package/tests/stats-view.test.ts +202 -0
- package/tests/telemetry-trigger.test.ts +81 -20
- package/tests/theme-customization.test.ts +72 -0
- package/tests/vim-editor-adapter-host-resolution.test.ts +37 -0
- package/tests/vim-editor-adapter.test.ts +804 -0
- package/tests/vim-normal-engine.test.ts +101 -0
- package/tests/vim-operator-engine.test.ts +215 -0
- package/tests/vim-policy.test.ts +19 -0
- package/tests/vim-visual-engine.test.ts +52 -0
- package/tests/visual-customization-policy.test.ts +110 -0
- package/tests/visual-customize-view.test.ts +418 -0
- package/tests/visual-profiles.test.ts +87 -0
- package/tests/yolo-customize.test.ts +256 -0
- package/tests/yolo-mode-runtime.test.ts +161 -0
- package/tests/yolo-mode.test.ts +261 -0
- package/tests/yolo-session-policy.test.ts +59 -0
- package/themes/Gentle.json +2 -1
- package/themes/Gentleman-Cute.json +2 -1
- package/themes/Gentleman-Sexy.json +2 -1
- package/assets/agents/sdd-apply.md +0 -159
- package/assets/agents/sdd-archive.md +0 -228
- package/assets/agents/sdd-design.md +0 -49
- package/assets/agents/sdd-explore.md +0 -48
- package/assets/agents/sdd-init.md +0 -56
- package/assets/agents/sdd-onboard.md +0 -52
- package/assets/agents/sdd-proposal.md +0 -64
- package/assets/agents/sdd-remediate.md +0 -37
- package/assets/agents/sdd-research.md +0 -49
- package/assets/agents/sdd-spec.md +0 -192
- package/assets/agents/sdd-status.md +0 -54
- package/assets/agents/sdd-tasks.md +0 -108
- package/assets/agents/sdd-verify.md +0 -124
- package/assets/chains/sdd-full.chain.md +0 -83
- package/assets/chains/sdd-plan.chain.md +0 -56
- package/assets/chains/sdd-verify.chain.md +0 -43
- package/assets/sdd-orchestrator-workflow.md +0 -319
- package/assets/support/sdd-status-contract.md +0 -77
- package/docs/assets/diagrams/sdd-cycle.svg +0 -14
- package/extensions/sdd-init.ts +0 -816
- package/lib/openspec-deltas.ts +0 -156
- package/lib/sdd-preflight.ts +0 -1066
- package/lib/sdd-research-capabilities.ts +0 -94
- package/lib/sdd-status.ts +0 -26
- package/tests/fixtures/legacy/sdd-research-v2.5.0.md +0 -54
- package/tests/fixtures/native-review-cli/v2.1.3/bind-sdd.json +0 -25
- package/tests/fixtures/v0.10.7/assets/agents/sdd-apply.md +0 -132
- package/tests/openspec-deltas.test.ts +0 -209
- package/tests/sdd-agent-tools.test.ts +0 -156
- package/tests/sdd-archive-replay.test.ts +0 -82
- package/tests/sdd-classical-continuation.test.ts +0 -74
- package/tests/sdd-execution-routing-contract.test.ts +0 -44
- package/tests/sdd-managed-runtime-settlement.test.ts +0 -155
- package/tests/sdd-native-managed-uptake.test.ts +0 -243
- package/tests/sdd-no-attempts-contract.test.ts +0 -15
- package/tests/sdd-odd-integration.test.ts +0 -33
- package/tests/sdd-optional-research.test.ts +0 -124
- package/tests/sdd-planning-routing-contract.test.ts +0 -45
- package/tests/sdd-preflight-rpc-input.test.ts +0 -125
- package/tests/sdd-preflight.test.ts +0 -541
- package/tests/sdd-research-capabilities.test.ts +0 -114
- package/tests/sdd-research-live.test.ts +0 -241
- package/tests/sdd-selection-transport.test.ts +0 -653
- package/tests/sdd-status.test.ts +0 -9
- package/tests/sdd-task-truth.test.ts +0 -43
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
|
+
import { execFileSync } from "node:child_process";
|
|
2
3
|
import { createHash } from "node:crypto";
|
|
3
4
|
import {
|
|
4
5
|
existsSync,
|
|
@@ -16,7 +17,10 @@ import ts from "typescript";
|
|
|
16
17
|
import { fileURLToPath } from "node:url";
|
|
17
18
|
import { applyModelConfig } from "../extensions/gentle-ai.ts";
|
|
18
19
|
import { resolveGentlePiAgentHome } from "../lib/agent-home.ts";
|
|
19
|
-
import { getPackageAssetOwner, installPackageAssets,
|
|
20
|
+
import { getPackageAssetOwner, installPackageAssets, type PackageAssetOwner } from "../lib/agent-assets.ts";
|
|
21
|
+
import { AUDITED_PI_EDITOR_VERSIONS } from "../lib/vim-editor-adapter.ts";
|
|
22
|
+
import { resolveProjectPiSdkVersion } from "../scripts/test-packed-runner.mjs";
|
|
23
|
+
// Package installation is owned by lib/agent-assets.ts, not the retired SDD preflight.
|
|
20
24
|
|
|
21
25
|
const PACKAGE_ROOT = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
22
26
|
const MANAGED_EXEMPLAR_FILE = "gentle-ai-explore.md";
|
|
@@ -76,13 +80,22 @@ interface PackageJsonPiManifest {
|
|
|
76
80
|
extensions?: string[];
|
|
77
81
|
}
|
|
78
82
|
|
|
83
|
+
interface PackageJsonPeerMetadata {
|
|
84
|
+
optional?: boolean;
|
|
85
|
+
}
|
|
86
|
+
|
|
79
87
|
interface PackageJson {
|
|
88
|
+
description?: string;
|
|
89
|
+
keywords?: string[];
|
|
80
90
|
version?: string;
|
|
81
91
|
files?: string[];
|
|
82
92
|
scripts?: Record<string, string>;
|
|
83
93
|
dependencies?: Record<string, string>;
|
|
84
94
|
peerDependencies?: Record<string, string>;
|
|
95
|
+
peerDependenciesMeta?: Record<string, PackageJsonPeerMetadata>;
|
|
96
|
+
optionalDependencies?: Record<string, string>;
|
|
85
97
|
devDependencies?: Record<string, string>;
|
|
98
|
+
engines?: Record<string, string>;
|
|
86
99
|
bundledDependencies?: string[];
|
|
87
100
|
bundleDependencies?: string[];
|
|
88
101
|
repository?: {
|
|
@@ -102,16 +115,106 @@ function readPackageJson(): PackageJson {
|
|
|
102
115
|
}
|
|
103
116
|
}
|
|
104
117
|
|
|
118
|
+
test("public docs and metadata advertise ODD and review without retired phase workflow", () => {
|
|
119
|
+
const manifest = readPackageJson();
|
|
120
|
+
assert.match(manifest.description ?? "", /ODD|Organic Driven Development/);
|
|
121
|
+
assert.match(manifest.description ?? "", /review/i);
|
|
122
|
+
assert.ok(manifest.keywords?.includes("odd"));
|
|
123
|
+
assert.ok(manifest.keywords?.includes("code-review"));
|
|
124
|
+
assert.ok(manifest.keywords?.every(keyword => !/sdd|openspec/i.test(keyword)));
|
|
125
|
+
for (const path of ["README.md", "docs/gentle-shell.md", "docs/readme-reference.md"]) {
|
|
126
|
+
const source = readFileSync(join(PACKAGE_ROOT, path), "utf8");
|
|
127
|
+
assert.match(source, /ODD|Organic Driven Development/, path);
|
|
128
|
+
assert.match(source, /review/i, path);
|
|
129
|
+
assert.doesNotMatch(source, /\bSDD\b|OpenSpec|\/gentle-sdd-init|\/gentle:install-sdd|\/gentle:sdd-preflight|\/sdd-/i, path);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
105
133
|
test("technical reference declares the tested Pi minimum required for agent_settled", () => {
|
|
106
134
|
const manifest = readPackageJson();
|
|
107
|
-
assert.equal(manifest.peerDependencies?.["@earendil-works/pi-coding-agent"], ">=0.
|
|
108
|
-
assert.equal(manifest.devDependencies?.["@earendil-works/pi-coding-agent"], "0.
|
|
135
|
+
assert.equal(manifest.peerDependencies?.["@earendil-works/pi-coding-agent"], ">=0.99.1");
|
|
136
|
+
assert.equal(manifest.devDependencies?.["@earendil-works/pi-coding-agent"], ">=1.0.0");
|
|
137
|
+
assert.equal(manifest.peerDependenciesMeta?.["@earendil-works/pi-coding-agent"]?.optional, true);
|
|
138
|
+
assert.equal(manifest.engines?.node, ">=22.19.0");
|
|
139
|
+
for (const path of ["docs/readme-reference.md", "docs/gentle-shell.md"]) {
|
|
140
|
+
const source = readFileSync(join(PACKAGE_ROOT, path), "utf8");
|
|
141
|
+
assert.match(source, /Pi 0\.99\.1 or newer/, path);
|
|
142
|
+
assert.match(source, /open `>=1\.0\.0` development range/, path);
|
|
143
|
+
assert.doesNotMatch(source, /development tests pin Pi/, path);
|
|
144
|
+
// Docs name exactly the audited Vim editor releases, never a future one.
|
|
145
|
+
const auditedReleases = new Intl.ListFormat("en", { style: "long", type: "conjunction" })
|
|
146
|
+
.format(AUDITED_PI_EDITOR_VERSIONS.map(v => `\`${v.replace(/\./g, "\\.")}\``));
|
|
147
|
+
assert.match(source, new RegExp(`audited Pi ${auditedReleases}`), path);
|
|
148
|
+
}
|
|
109
149
|
const reference = readFileSync(join(PACKAGE_ROOT, "docs", "readme-reference.md"), "utf8");
|
|
110
|
-
assert.match(reference, /Pi 0\.85\.1 or newer/);
|
|
111
150
|
assert.match(reference, /agent_settled/);
|
|
112
151
|
assert.match(readFileSync(join(PACKAGE_ROOT, "README.md"), "utf8"), /\]\(docs\/readme-reference\.md(?:#[^)]+)?\)/);
|
|
113
152
|
});
|
|
114
153
|
|
|
154
|
+
test("packed runtime uses optional Pi host peers with one open development range and no duplicate direct dependencies", () => {
|
|
155
|
+
const manifest = readPackageJson();
|
|
156
|
+
for (const name of ["@earendil-works/pi-ai", "@earendil-works/pi-tui"]) {
|
|
157
|
+
assert.equal(manifest.peerDependencies?.[name], "*", name);
|
|
158
|
+
assert.equal(manifest.peerDependenciesMeta?.[name]?.optional, true, name);
|
|
159
|
+
}
|
|
160
|
+
// The devDependency specifier is policy (a range); the resolved install is
|
|
161
|
+
// one exact release shared by every Pi host package.
|
|
162
|
+
const installed = new Set<string>();
|
|
163
|
+
for (const name of ["@earendil-works/pi-coding-agent", "@earendil-works/pi-ai", "@earendil-works/pi-tui"]) {
|
|
164
|
+
assert.equal(manifest.devDependencies?.[name], ">=1.0.0", name);
|
|
165
|
+
const metadata = JSON.parse(readFileSync(join(PACKAGE_ROOT, "node_modules", name, "package.json"), "utf8")) as { name: string; version: string };
|
|
166
|
+
assert.equal(metadata.name, name);
|
|
167
|
+
installed.add(metadata.version);
|
|
168
|
+
}
|
|
169
|
+
assert.deepEqual([...installed], [resolveProjectPiSdkVersion(PACKAGE_ROOT)]);
|
|
170
|
+
for (const name of ["@earendil-works/pi-coding-agent", "@earendil-works/pi-ai", "@earendil-works/pi-tui"]) {
|
|
171
|
+
assert.equal(manifest.dependencies?.[name], undefined, name);
|
|
172
|
+
assert.equal(manifest.optionalDependencies?.[name], undefined, name);
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// Fixture project roots let the resolver's range policy be tested without
|
|
177
|
+
// touching the real install.
|
|
178
|
+
function withPiSdkProject(range: unknown, installed: unknown, run: (root: string) => void): void {
|
|
179
|
+
const root = mkdtempSync(join(tmpdir(), "gentle-pi-sdk-version-"));
|
|
180
|
+
try {
|
|
181
|
+
const sdk = join(root, "node_modules", "@earendil-works", "pi-coding-agent");
|
|
182
|
+
mkdirSync(sdk, { recursive: true });
|
|
183
|
+
writeFileSync(join(root, "package.json"), JSON.stringify({ devDependencies: { "@earendil-works/pi-coding-agent": range } }));
|
|
184
|
+
writeFileSync(join(sdk, "package.json"), JSON.stringify(installed));
|
|
185
|
+
run(root);
|
|
186
|
+
} finally {
|
|
187
|
+
rmSync(root, { recursive: true, force: true });
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
test("packed probes install the project-resolved Pi SDK release, never the devDependency specifier", () => {
|
|
192
|
+
const sdk = (version: unknown) => ({ name: "@earendil-works/pi-coding-agent", version });
|
|
193
|
+
for (const [range, version] of [[">=0.99.2", "0.99.2"], [">=0.99.2", "0.99.10"], [">=0.99.2", "1.0.0"], ["0.99.2", "0.99.2"]]) {
|
|
194
|
+
withPiSdkProject(range, sdk(version), (root) => assert.equal(resolveProjectPiSdkVersion(root), version, `${range} ${version}`));
|
|
195
|
+
}
|
|
196
|
+
for (const [range, installed, error] of [
|
|
197
|
+
[">=0.99.2", sdk("0.99.1"), /0\.99\.1 does not satisfy >=0\.99\.2/],
|
|
198
|
+
["0.99.1", sdk("0.99.2"), /0\.99\.2 does not satisfy 0\.99\.1/],
|
|
199
|
+
["*", sdk("0.99.2"), /exact or >= Pi SDK development range/],
|
|
200
|
+
["^0.99.2", sdk("0.99.2"), /exact or >= Pi SDK development range/],
|
|
201
|
+
[undefined, sdk("0.99.2"), /exact or >= Pi SDK development range/],
|
|
202
|
+
[">=0.99.2", sdk(">=0.99.2"), /exact release version/],
|
|
203
|
+
[">=0.99.2", sdk("0.99.3-rc.1"), /exact release version/],
|
|
204
|
+
[">=0.99.2", { name: "impostor", version: "0.99.2" }, /exact release version/],
|
|
205
|
+
] as const) {
|
|
206
|
+
withPiSdkProject(range, installed, (root) => assert.throws(() => resolveProjectPiSdkVersion(root), error, String(range)));
|
|
207
|
+
}
|
|
208
|
+
const installed = JSON.parse(readFileSync(join(PACKAGE_ROOT, "node_modules", "@earendil-works", "pi-coding-agent", "package.json"), "utf8")) as { version: string };
|
|
209
|
+
assert.equal(resolveProjectPiSdkVersion(PACKAGE_ROOT), installed.version);
|
|
210
|
+
const packedRunner = readFileSync(join(PACKAGE_ROOT, "scripts", "test-packed-runner.mjs"), "utf8");
|
|
211
|
+
for (const name of ["testSdkLifecyclePackedSession", "testWindowsStartupTimingPackedHelper", "testWindowsStartupTimingEnvironmentExperiment", "testUnhookedPackedImports"]) {
|
|
212
|
+
const probe = readNamedFunction(packedRunner, name);
|
|
213
|
+
assert.match(probe, /const sdkVersion = resolveProjectPiSdkVersion\(root, "[^"]+"\);/, name);
|
|
214
|
+
assert.doesNotMatch(probe, /devDependencies/, name);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
|
|
115
218
|
test("package manifest has no obsolete native activation build surface", () => {
|
|
116
219
|
const packageJson = readPackageJson();
|
|
117
220
|
const manifest = JSON.stringify(packageJson);
|
|
@@ -123,6 +226,16 @@ test("package manifest has no obsolete native activation build surface", () => {
|
|
|
123
226
|
assert.doesNotMatch(packageJson.scripts?.prepublishOnly ?? "", /native:build/);
|
|
124
227
|
});
|
|
125
228
|
|
|
229
|
+
test("package verification excludes the retired init extension while retaining ODD and review resources", () => {
|
|
230
|
+
const verifier = readFileSync(join(PACKAGE_ROOT, "scripts", "verify-package-files.mjs"), "utf8");
|
|
231
|
+
assert.equal(existsSync(join(PACKAGE_ROOT, "extensions", "sdd-init.ts")), false);
|
|
232
|
+
assert.doesNotMatch(verifier, /^\s*"extensions\/sdd-init\.ts",?$/m);
|
|
233
|
+
assert.match(verifier, /existsSync\(join\(root, "extensions\/sdd-init\.ts"\)\)/);
|
|
234
|
+
for (const resource of ["extensions/gentle-ai.ts", "extensions/skill-registry.ts", "assets/orchestrator.md", "assets/orchestrator-delegation.md", "assets/agents/gentle-ai-worker.md", "assets/agents/review-risk.md", "assets/chains/4r-review.chain.md"]) {
|
|
235
|
+
assert.ok(verifier.includes(`"${resource}"`), `${resource} must remain required`);
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
|
|
126
239
|
test("package verification names the native review runtime boundary and packaged fixtures", () => {
|
|
127
240
|
const verifier = readFileSync(join(PACKAGE_ROOT, "scripts", "verify-package-files.mjs"), "utf8");
|
|
128
241
|
const manifest = readPackageJson();
|
|
@@ -298,20 +411,20 @@ test("package manifest installs pi-pretty through a wrapper without bundling nat
|
|
|
298
411
|
);
|
|
299
412
|
});
|
|
300
413
|
|
|
301
|
-
test("package verification binds the published Gentle AI
|
|
414
|
+
test("package verification binds the published Gentle AI v4.0.0 runtime pin", () => {
|
|
302
415
|
const installer = readFileSync(join(PACKAGE_ROOT, "scripts", "gentle-ai-installer.mjs"), "utf8");
|
|
303
416
|
const binary = readFileSync(join(PACKAGE_ROOT, "lib", "gentle-ai-binary.ts"), "utf8");
|
|
304
417
|
const verifier = readFileSync(join(PACKAGE_ROOT, "scripts", "verify-package-files.mjs"), "utf8");
|
|
305
418
|
|
|
306
|
-
assert.match(installer, /INSTALLER_VERSION = "
|
|
419
|
+
assert.match(installer, /INSTALLER_VERSION = "4\.0\.0"/);
|
|
307
420
|
assert.match(installer, /GENTLE_AI_WINDOWS_SOURCE_PACKAGE.*GENTLE_AI_WINDOWS_SOURCE_MODULE/);
|
|
308
|
-
assert.match(installer, /GENTLE_AI_WINDOWS_SOURCE_MODULE_CHECKSUM = "h1:
|
|
421
|
+
assert.match(installer, /GENTLE_AI_WINDOWS_SOURCE_MODULE_CHECKSUM = "h1:pZ\/XZ2Pk3U9lgXigOTY62zlxxFOHnc9CjQhLgaV\/Hfc="/);
|
|
309
422
|
assert.match(installer, /GOTOOLCHAIN: "local"/);
|
|
310
423
|
assert.match(installer, /GOSUMDB: "sum\.golang\.org"/);
|
|
311
424
|
assert.match(binary, /GENTLE_AI_VERSION = INSTALLER_VERSION/);
|
|
312
425
|
assert.match(binary, /GO_SUMDB_SOURCE_BUILD/);
|
|
313
426
|
assert.match(binary, /GENTLE_AI_WINDOWS_SOURCE_MODULE_CHECKSUM/);
|
|
314
|
-
assert.match(verifier, /
|
|
427
|
+
assert.match(verifier, /v4\.0\.0/);
|
|
315
428
|
});
|
|
316
429
|
|
|
317
430
|
|
|
@@ -551,6 +664,36 @@ function installedAssetManifest(agentHome: string): ManagedAssetsManifest {
|
|
|
551
664
|
return JSON.parse(readFileSync(join(agentHome, "gentle-ai", "managed-assets.json"), "utf8"));
|
|
552
665
|
}
|
|
553
666
|
|
|
667
|
+
test("ODD delegation assets retain applicable test-first checks and independent review boundaries without SDD routing", () => {
|
|
668
|
+
const support = readFileSync(join(PACKAGE_ROOT, "assets/support/strict-tdd.md"), "utf8");
|
|
669
|
+
const explorer = readFileSync(join(PACKAGE_ROOT, "assets/agents/gentle-ai-explore.md"), "utf8");
|
|
670
|
+
const verifier = readFileSync(join(PACKAGE_ROOT, "assets/agents/gentle-ai-verify.md"), "utf8");
|
|
671
|
+
const worker = readFileSync(join(PACKAGE_ROOT, "assets/agents/gentle-ai-worker.md"), "utf8");
|
|
672
|
+
for (const source of [support, explorer, verifier, worker]) {
|
|
673
|
+
assert.doesNotMatch(source, /openspec\/config\.yaml|sdd-init|SDD phase protocols|generic non-SDD|sdd-verify|sdd\/\{project\}/i);
|
|
674
|
+
}
|
|
675
|
+
assert.match(support, /RED[\s\S]*GREEN[\s\S]*REFACTOR/);
|
|
676
|
+
assert.match(support, /behavior changes with applicable runnable deterministic tests and a clear expected outcome/i);
|
|
677
|
+
assert.match(support, /A test file merely existing is not proof of applicability or RED/i);
|
|
678
|
+
assert.match(support, /no meaningful RED[\s\S]*proportionate ordinary functional or structural verification/i);
|
|
679
|
+
assert.match(support, /Use only exact commands authorized by the parent/i);
|
|
680
|
+
assert.match(explorer, /read-only explorer for generic ODD work/);
|
|
681
|
+
assert.match(verifier, /read-only technical verifier for generic ODD work/);
|
|
682
|
+
assert.match(worker, /allowed edit surfaces/i);
|
|
683
|
+
assert.match(worker, /work-unit commit/i);
|
|
684
|
+
assert.match(worker, /review lifecycle.*parent/i);
|
|
685
|
+
});
|
|
686
|
+
|
|
687
|
+
test("delegation installation retains strict TDD support without installing SDD assets", () => {
|
|
688
|
+
withIsolatedAssetHome((agentHome) => {
|
|
689
|
+
installPackageAssets(agentHome, false, ["delegation"]);
|
|
690
|
+
const keys = Object.keys(installedAssetManifest(agentHome).assets);
|
|
691
|
+
assert.ok(keys.includes("gentle-ai/support/strict-tdd.md"));
|
|
692
|
+
assert.ok(keys.includes("gentle-ai/support/strict-tdd-verify.md"));
|
|
693
|
+
assert.ok(keys.every(key => !key.startsWith("agents/sdd-") && !key.startsWith("chains/sdd-") && !key.includes("sdd-status-contract")));
|
|
694
|
+
});
|
|
695
|
+
});
|
|
696
|
+
|
|
554
697
|
test("selective delegation installation owns only generic agents", () => {
|
|
555
698
|
withIsolatedAssetHome((agentHome) => {
|
|
556
699
|
const result = installPackageAssets(agentHome, false, ["delegation"]);
|
|
@@ -558,19 +701,21 @@ test("selective delegation installation owns only generic agents", () => {
|
|
|
558
701
|
"agents/gentle-ai-explore.md",
|
|
559
702
|
"agents/gentle-ai-verify.md",
|
|
560
703
|
"agents/gentle-ai-worker.md",
|
|
704
|
+
"gentle-ai/support/strict-tdd-verify.md",
|
|
705
|
+
"gentle-ai/support/strict-tdd.md",
|
|
561
706
|
]);
|
|
562
|
-
assert.deepEqual(result, { agents: 3, chains: 0, support:
|
|
707
|
+
assert.deepEqual(result, { agents: 3, chains: 0, support: 2, skipped: 0 });
|
|
563
708
|
assert.deepEqual(readdirSync(join(agentHome, "agents")).sort(), [
|
|
564
709
|
"gentle-ai-explore.md", "gentle-ai-verify.md", "gentle-ai-worker.md",
|
|
565
710
|
]);
|
|
566
711
|
assert.equal(existsSync(join(agentHome, "chains")), false);
|
|
567
|
-
assert.
|
|
712
|
+
assert.deepEqual(readdirSync(join(agentHome, "gentle-ai", "support")).sort(), ["strict-tdd-verify.md", "strict-tdd.md"]);
|
|
568
713
|
});
|
|
569
714
|
});
|
|
570
715
|
|
|
571
716
|
test("selective installation retires only assets belonging to the selected owner", () => {
|
|
572
717
|
withIsolatedAssetHome((agentHome) => {
|
|
573
|
-
|
|
718
|
+
installPackageAssets(agentHome, false);
|
|
574
719
|
const manifestPath = join(agentHome, "gentle-ai", "managed-assets.json");
|
|
575
720
|
const manifest = installedAssetManifest(agentHome);
|
|
576
721
|
for (const name of RETIRED_ADVERSARIAL_AGENTS) {
|
|
@@ -578,7 +723,7 @@ test("selective installation retires only assets belonging to the selected owner
|
|
|
578
723
|
manifest.assets[`agents/${name}`] = sha256("Previously managed review agent\n");
|
|
579
724
|
}
|
|
580
725
|
writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
|
|
581
|
-
for (const owner of ["delegation"
|
|
726
|
+
for (const owner of ["delegation"] as const) {
|
|
582
727
|
installPackageAssets(agentHome, true, [owner]);
|
|
583
728
|
assert.deepEqual(installedAssetManifest(agentHome), manifest);
|
|
584
729
|
for (const name of RETIRED_ADVERSARIAL_AGENTS) {
|
|
@@ -598,21 +743,13 @@ test("selective installation retires only assets belonging to the selected owner
|
|
|
598
743
|
const EXPECTED_OWNER_ASSETS: Record<PackageAssetOwner, readonly string[]> = {
|
|
599
744
|
delegation: [
|
|
600
745
|
"agents/gentle-ai-explore.md", "agents/gentle-ai-verify.md", "agents/gentle-ai-worker.md",
|
|
746
|
+
"gentle-ai/support/strict-tdd.md", "gentle-ai/support/strict-tdd-verify.md",
|
|
601
747
|
],
|
|
602
748
|
review: [
|
|
603
749
|
"agents/jd-fix-agent.md", "agents/jd-judge-a.md", "agents/jd-judge-b.md",
|
|
604
750
|
"agents/review-readability.md", "agents/review-reliability.md",
|
|
605
751
|
"agents/review-resilience.md", "agents/review-risk.md", "chains/4r-review.chain.md",
|
|
606
752
|
],
|
|
607
|
-
sdd: [
|
|
608
|
-
"agents/sdd-apply.md", "agents/sdd-archive.md", "agents/sdd-design.md",
|
|
609
|
-
"agents/sdd-explore.md", "agents/sdd-init.md", "agents/sdd-onboard.md",
|
|
610
|
-
"agents/sdd-proposal.md", "agents/sdd-remediate.md", "agents/sdd-research.md", "agents/sdd-spec.md",
|
|
611
|
-
"agents/sdd-status.md", "agents/sdd-tasks.md", "agents/sdd-verify.md",
|
|
612
|
-
"chains/sdd-full.chain.md", "chains/sdd-plan.chain.md", "chains/sdd-verify.chain.md",
|
|
613
|
-
"gentle-ai/support/sdd-status-contract.md", "gentle-ai/support/strict-tdd-verify.md",
|
|
614
|
-
"gentle-ai/support/strict-tdd.md",
|
|
615
|
-
],
|
|
616
753
|
};
|
|
617
754
|
|
|
618
755
|
function assetFileKeys(root: string, prefix = ""): string[] {
|
|
@@ -641,7 +778,7 @@ for (const owner of Object.keys(EXPECTED_OWNER_ASSETS) as PackageAssetOwner[]) {
|
|
|
641
778
|
});
|
|
642
779
|
}
|
|
643
780
|
|
|
644
|
-
test("
|
|
781
|
+
test("all-assets installation covers every retained packaged file with explicit ownership", () => {
|
|
645
782
|
const packaged = ["agents", "chains", "support"].flatMap(group =>
|
|
646
783
|
assetFileKeys(join(PACKAGE_ROOT, "assets", group), group === "support" ? "gentle-ai/support/" : `${group}/`),
|
|
647
784
|
).sort();
|
|
@@ -651,24 +788,24 @@ test("legacy all-assets installation covers every packaged file with explicit ow
|
|
|
651
788
|
assert.equal(getPackageAssetOwner(key), undefined, "unknown assets must not default to SDD");
|
|
652
789
|
}
|
|
653
790
|
withIsolatedAssetHome((agentHome) => {
|
|
654
|
-
assert.deepEqual(
|
|
791
|
+
assert.deepEqual(installPackageAssets(agentHome, false), { agents: 10, chains: 1, support: 2, skipped: 0 });
|
|
655
792
|
assert.deepEqual(Object.keys(installedAssetManifest(agentHome).assets).sort(), packaged);
|
|
656
|
-
assert.deepEqual(
|
|
657
|
-
assert.deepEqual(
|
|
793
|
+
assert.deepEqual(installPackageAssets(agentHome, false), { agents: 0, chains: 0, support: 0, skipped: 13 });
|
|
794
|
+
assert.deepEqual(installPackageAssets(agentHome, true), { agents: 10, chains: 1, support: 2, skipped: 0 });
|
|
658
795
|
});
|
|
659
796
|
});
|
|
660
797
|
|
|
661
798
|
test("selective refresh preserves unselected ownership and selected user changes after an all-assets install", () => {
|
|
662
799
|
withIsolatedAssetHome((agentHome) => {
|
|
663
|
-
|
|
800
|
+
installPackageAssets(agentHome, false);
|
|
664
801
|
const manifest = installedAssetManifest(agentHome);
|
|
665
802
|
const selectedUserKey = "agents/gentle-ai-explore.md";
|
|
666
|
-
const unselectedUserKey = "agents/
|
|
803
|
+
const unselectedUserKey = "agents/review-risk.md";
|
|
667
804
|
for (const key of [selectedUserKey, unselectedUserKey, "agents/custom.md"]) {
|
|
668
805
|
writeFileSync(join(agentHome, key), "User-authored instructions\n");
|
|
669
806
|
}
|
|
670
807
|
const before = new Map(assetFileKeys(agentHome).map(key => [key, readFileSync(join(agentHome, key), "utf8")]));
|
|
671
|
-
assert.deepEqual(installPackageAssets(agentHome, true, ["delegation"]), { agents: 2, chains: 0, support:
|
|
808
|
+
assert.deepEqual(installPackageAssets(agentHome, true, ["delegation"]), { agents: 2, chains: 0, support: 2, skipped: 1 });
|
|
672
809
|
delete manifest.assets[selectedUserKey];
|
|
673
810
|
assert.deepEqual(installedAssetManifest(agentHome), manifest);
|
|
674
811
|
for (const [key, content] of before) {
|
|
@@ -705,42 +842,45 @@ test("selective review migration adopts only untouched legacy copies and preserv
|
|
|
705
842
|
assert.equal(manifest.assets["agents/review-risk.md"], sha256(actual));
|
|
706
843
|
}
|
|
707
844
|
assert.equal(existsSync(join(agentHome, "agents", "sdd-apply.md")), false);
|
|
708
|
-
assert.equal(existsSync(join(agentHome, "gentle-ai", "support")),
|
|
845
|
+
assert.equal(existsSync(join(agentHome, "gentle-ai", "support", "strict-tdd.md")), true);
|
|
709
846
|
});
|
|
710
847
|
}
|
|
711
848
|
});
|
|
712
849
|
|
|
713
|
-
test("
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
const
|
|
717
|
-
assert.equal(sha256(legacy), manifest.assets["agents/sdd-research.md"], "fixture reconstruction must match observed old package bytes");
|
|
718
|
-
const temporary = mkdtempSync(join(tmpdir(), "gentle-research-migration-"));
|
|
719
|
-
const previous = process.env.GENTLE_PI_AGENT_HOME;
|
|
850
|
+
test("packed tarball excludes retired workflow paths while source retains legacy migration proof", () => {
|
|
851
|
+
const fixture = "tests/fixtures/legacy/sdd-research-v2.5.0.md";
|
|
852
|
+
assert.ok(existsSync(join(PACKAGE_ROOT, fixture)), "the historical source fixture must remain available to migration tests");
|
|
853
|
+
const destination = mkdtempSync(join(tmpdir(), "gentle-pi-pack-manifest-"));
|
|
720
854
|
try {
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
855
|
+
const output = execFileSync("npm", ["pack", "--ignore-scripts", "--offline", "--json", "--pack-destination", destination], {
|
|
856
|
+
cwd: PACKAGE_ROOT,
|
|
857
|
+
encoding: "utf8",
|
|
858
|
+
maxBuffer: 8 * 1024 * 1024,
|
|
859
|
+
});
|
|
860
|
+
const [packed] = JSON.parse(output) as [{ files: { path: string }[] }];
|
|
861
|
+
assert.ok(packed?.files?.length, "npm pack must return a nonempty tar manifest");
|
|
862
|
+
assert.ok(packed.files.some(file => file.path === "tests/package-manifest.test.ts"), "other tests remain packed");
|
|
863
|
+
assert.deepEqual(packed.files.filter(file => /sdd|openspec/i.test(file.path)).map(file => file.path), []);
|
|
864
|
+
} finally {
|
|
865
|
+
rmSync(destination, { recursive: true, force: true });
|
|
866
|
+
}
|
|
867
|
+
});
|
|
868
|
+
|
|
869
|
+
test("legacy research retirement requires exact ownership and preserves edited copies", () => {
|
|
870
|
+
const legacy = readFileSync(join(PACKAGE_ROOT, "tests/fixtures/legacy/sdd-research-v2.5.0.md"), "utf8");
|
|
871
|
+
const history = JSON.parse(readFileSync(join(PACKAGE_ROOT, "assets", "migrations", "managed-assets-v2.5.0.json"), "utf8"));
|
|
872
|
+
assert.equal(sha256(legacy), history.assets["agents/sdd-research.md"]);
|
|
873
|
+
for (const edited of [false, true]) {
|
|
874
|
+
withIsolatedAssetHome((agentHome) => {
|
|
724
875
|
mkdirSync(join(agentHome, "agents"), { recursive: true });
|
|
725
876
|
const target = join(agentHome, "agents", "sdd-research.md");
|
|
726
|
-
const
|
|
727
|
-
writeFileSync(target,
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
if (edited) assert.equal(
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
assert.match(actual, /model: custom\/model\nthinking: high/);
|
|
734
|
-
const ownership = JSON.parse(readFileSync(join(agentHome, "gentle-ai", "managed-assets.json"), "utf8"));
|
|
735
|
-
assert.equal(ownership.assets["agents/sdd-research.md"], sha256(actual));
|
|
736
|
-
installSddAssets(temporary, true);
|
|
737
|
-
assert.equal(readFileSync(target, "utf8"), actual, "subsequent refresh keeps adopted model routing");
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
} finally {
|
|
741
|
-
if (previous === undefined) delete process.env.GENTLE_PI_AGENT_HOME;
|
|
742
|
-
else process.env.GENTLE_PI_AGENT_HOME = previous;
|
|
743
|
-
rmSync(temporary, { recursive: true, force: true });
|
|
877
|
+
const content = edited ? `${legacy}\nUser research restrictions.\n` : legacy;
|
|
878
|
+
writeFileSync(target, content);
|
|
879
|
+
installPackageAssets(agentHome, true);
|
|
880
|
+
assert.equal(existsSync(target), edited);
|
|
881
|
+
if (edited) assert.equal(readFileSync(target, "utf8"), content);
|
|
882
|
+
assert.equal(installedAssetManifest(agentHome).assets["agents/sdd-research.md"], undefined);
|
|
883
|
+
});
|
|
744
884
|
}
|
|
745
885
|
});
|
|
746
886
|
|
|
@@ -783,7 +923,7 @@ test("forced package installation preserves same-path user-authored agents and s
|
|
|
783
923
|
mkdirSync(dirname(samePathUserAgent), { recursive: true });
|
|
784
924
|
writeFileSync(samePathUserAgent, userAgentSource);
|
|
785
925
|
|
|
786
|
-
|
|
926
|
+
installPackageAssets(temporaryProject, true);
|
|
787
927
|
|
|
788
928
|
assert.deepEqual(
|
|
789
929
|
readFileSync(samePathUserAgent),
|
|
@@ -861,7 +1001,7 @@ test("first forced sync migrates untouched v0.13 assets, preserves routing, and
|
|
|
861
1001
|
writeFileSync(installedReviewRisk, routedLegacySource);
|
|
862
1002
|
assert.equal(existsSync(managedAssetsManifest), false, "v0.13 had no ownership manifest");
|
|
863
1003
|
|
|
864
|
-
|
|
1004
|
+
installPackageAssets(PACKAGE_ROOT, true);
|
|
865
1005
|
|
|
866
1006
|
const migrated = readFileSync(installedReviewRisk, "utf8");
|
|
867
1007
|
const currentPackageSource = readFileSync(
|
|
@@ -897,7 +1037,7 @@ test("first forced sync migrates untouched v0.13 assets, preserves routing, and
|
|
|
897
1037
|
);
|
|
898
1038
|
assert.notEqual(userEditedMigration, migrated, "the fixture must exercise post-migration drift");
|
|
899
1039
|
writeFileSync(installedReviewRisk, userEditedMigration);
|
|
900
|
-
|
|
1040
|
+
installPackageAssets(PACKAGE_ROOT, true);
|
|
901
1041
|
assert.deepEqual(
|
|
902
1042
|
readFileSync(installedReviewRisk),
|
|
903
1043
|
Buffer.from(userEditedMigration),
|
|
@@ -932,7 +1072,7 @@ test("first forced sync migrates untouched v0.14 review contracts and preserves
|
|
|
932
1072
|
mkdirSync(dirname(installedReviewRisk), { recursive: true });
|
|
933
1073
|
writeFileSync(installedReviewRisk, routedLegacySource);
|
|
934
1074
|
|
|
935
|
-
|
|
1075
|
+
installPackageAssets(PACKAGE_ROOT, true);
|
|
936
1076
|
|
|
937
1077
|
const migrated = readFileSync(installedReviewRisk, "utf8");
|
|
938
1078
|
assert.notEqual(migrated, routedLegacySource);
|
|
@@ -969,7 +1109,7 @@ test("first forced sync preserves a body-edited v0.13 asset byte-for-byte", () =
|
|
|
969
1109
|
mkdirSync(dirname(installedReviewRisk), { recursive: true });
|
|
970
1110
|
writeFileSync(installedReviewRisk, editedLegacySource);
|
|
971
1111
|
|
|
972
|
-
|
|
1112
|
+
installPackageAssets(PACKAGE_ROOT, true);
|
|
973
1113
|
|
|
974
1114
|
assert.deepEqual(readFileSync(installedReviewRisk), Buffer.from(editedLegacySource));
|
|
975
1115
|
const manifest = JSON.parse(
|
|
@@ -1004,7 +1144,7 @@ test("forced package installation refreshes an asset recorded as package-managed
|
|
|
1004
1144
|
|
|
1005
1145
|
try {
|
|
1006
1146
|
process.env.GENTLE_PI_AGENT_HOME = temporaryAgentHome;
|
|
1007
|
-
|
|
1147
|
+
installPackageAssets(PACKAGE_ROOT, true);
|
|
1008
1148
|
assert.ok(existsSync(installedExemplar), "a missing package asset must install");
|
|
1009
1149
|
assert.ok(
|
|
1010
1150
|
existsSync(managedAssetsManifest),
|
|
@@ -1020,7 +1160,7 @@ test("forced package installation refreshes an asset recorded as package-managed
|
|
|
1020
1160
|
);
|
|
1021
1161
|
writeFileSync(managedAssetsManifest, JSON.stringify(manifest, null, 2));
|
|
1022
1162
|
|
|
1023
|
-
|
|
1163
|
+
installPackageAssets(PACKAGE_ROOT, true);
|
|
1024
1164
|
|
|
1025
1165
|
const refreshed = readAgentDefinition(installedExemplar);
|
|
1026
1166
|
assert.deepEqual(refreshed.tools, MANAGED_EXEMPLAR_TOOLS);
|
|
@@ -1050,13 +1190,13 @@ function assertManagedAgentUserEditIsPreserved(
|
|
|
1050
1190
|
|
|
1051
1191
|
try {
|
|
1052
1192
|
process.env.GENTLE_PI_AGENT_HOME = temporaryAgentHome;
|
|
1053
|
-
|
|
1193
|
+
installPackageAssets(PACKAGE_ROOT, true);
|
|
1054
1194
|
const installedSource = readFileSync(installedExemplar, "utf8");
|
|
1055
1195
|
const userEditedSource = editSource(installedSource);
|
|
1056
1196
|
assert.notEqual(userEditedSource, installedSource, `${editLabel} must alter the asset`);
|
|
1057
1197
|
writeFileSync(installedExemplar, userEditedSource);
|
|
1058
1198
|
|
|
1059
|
-
|
|
1199
|
+
installPackageAssets(PACKAGE_ROOT, true);
|
|
1060
1200
|
|
|
1061
1201
|
assert.deepEqual(
|
|
1062
1202
|
readFileSync(installedExemplar),
|
|
@@ -1102,8 +1242,8 @@ test("forced package installation preserves a thinking-only edit to a managed ag
|
|
|
1102
1242
|
test("forced package installation preserves an ordinary body edit to a managed agent", () => {
|
|
1103
1243
|
assertManagedAgentUserEditIsPreserved("an ordinary body edit", (source) =>
|
|
1104
1244
|
source.replace(
|
|
1105
|
-
"You are the read-only explorer for generic
|
|
1106
|
-
"Preserve this user-authored body change. You are the read-only explorer for generic
|
|
1245
|
+
"You are the read-only explorer for generic ODD work.",
|
|
1246
|
+
"Preserve this user-authored body change. You are the read-only explorer for generic ODD work.",
|
|
1107
1247
|
),
|
|
1108
1248
|
);
|
|
1109
1249
|
});
|
|
@@ -1122,7 +1262,7 @@ test("package model assignment keeps only package-managed agents owned", () => {
|
|
|
1122
1262
|
|
|
1123
1263
|
try {
|
|
1124
1264
|
process.env.GENTLE_PI_AGENT_HOME = temporaryAgentHome;
|
|
1125
|
-
|
|
1265
|
+
installPackageAssets(PACKAGE_ROOT, true);
|
|
1126
1266
|
writeFileSync(userAgent, userAgentSource);
|
|
1127
1267
|
|
|
1128
1268
|
applyModelConfig(PACKAGE_ROOT, {
|
|
@@ -1151,7 +1291,7 @@ test("package model assignment keeps only package-managed agents owned", () => {
|
|
|
1151
1291
|
"routing an arbitrary user agent must not relabel it as package-owned",
|
|
1152
1292
|
);
|
|
1153
1293
|
|
|
1154
|
-
|
|
1294
|
+
installPackageAssets(PACKAGE_ROOT, true);
|
|
1155
1295
|
assert.equal(
|
|
1156
1296
|
readFileSync(installedExemplar, "utf8"),
|
|
1157
1297
|
readFileSync(join(PACKAGE_ROOT, "assets", "agents", MANAGED_EXEMPLAR_FILE), "utf8"),
|
|
@@ -1182,20 +1322,23 @@ test("jd-fix-agent packaged allowlist includes write tools", () => {
|
|
|
1182
1322
|
}
|
|
1183
1323
|
});
|
|
1184
1324
|
|
|
1185
|
-
test("
|
|
1186
|
-
const
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
"
|
|
1192
|
-
"
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1325
|
+
test("deleted SDD definitions remain absent from the installed catalog", () => {
|
|
1326
|
+
const retired = [
|
|
1327
|
+
...[
|
|
1328
|
+
"apply", "archive", "design", "explore", "init", "onboard", "proposal",
|
|
1329
|
+
"remediate", "research", "spec", "status", "tasks", "verify",
|
|
1330
|
+
].map(name => `agents/sdd-${name}.md`),
|
|
1331
|
+
"chains/sdd-full.chain.md", "chains/sdd-plan.chain.md", "chains/sdd-verify.chain.md",
|
|
1332
|
+
"gentle-ai/support/sdd-status-contract.md",
|
|
1333
|
+
];
|
|
1334
|
+
withIsolatedAssetHome(agentHome => {
|
|
1335
|
+
installPackageAssets(agentHome, false);
|
|
1336
|
+
for (const key of retired) {
|
|
1337
|
+
assert.equal(getPackageAssetOwner(key), undefined, key);
|
|
1338
|
+
assert.equal(installedAssetManifest(agentHome).assets[key], undefined, key);
|
|
1339
|
+
assert.equal(existsSync(join(agentHome, key)), false, key);
|
|
1340
|
+
}
|
|
1341
|
+
});
|
|
1199
1342
|
});
|
|
1200
1343
|
|
|
1201
1344
|
test("gentle-ai-worker packages the exact scoped writer contract", () => {
|
|
@@ -1296,8 +1439,11 @@ test("gentle-ai-worker packages the exact scoped writer contract", () => {
|
|
|
1296
1439
|
assert.match(memorySafety, /raw untrusted repository/);
|
|
1297
1440
|
|
|
1298
1441
|
const testDiscipline = readMarkdownSection(source, "Test discipline");
|
|
1299
|
-
assert.match(testDiscipline, /
|
|
1300
|
-
assert.match(testDiscipline, /not
|
|
1442
|
+
assert.match(testDiscipline, /Apply the ODD test-first policy by default for behavior changes with applicable runnable deterministic tests and a clear expected outcome/);
|
|
1443
|
+
assert.match(testDiscipline, /Test presence alone does not establish applicability; no TUI toggle or per-task chat choice is needed/);
|
|
1444
|
+
assert.match(testDiscipline, /RED[\s\S]*GREEN[\s\S]*TRIANGULATE[\s\S]*REFACTOR/);
|
|
1445
|
+
assert.match(testDiscipline, /no meaningful RED[\s\S]*proportionate ordinary functional or structural verification/);
|
|
1446
|
+
assert.match(testDiscipline, /Never claim RED\/GREEN evidence that was not observed/);
|
|
1301
1447
|
assert.match(
|
|
1302
1448
|
testDiscipline,
|
|
1303
1449
|
/Broad suites, builds, formatters, or linters may run only when explicitly authorized by the parent\./,
|
|
@@ -1306,13 +1452,13 @@ test("gentle-ai-worker packages the exact scoped writer contract", () => {
|
|
|
1306
1452
|
assert.doesNotMatch(testDiscipline, /clearly required by the repository contract/);
|
|
1307
1453
|
});
|
|
1308
1454
|
|
|
1309
|
-
test("
|
|
1455
|
+
test("package installation gives gentle-ai-worker a loader-compatible scoped identity", () => {
|
|
1310
1456
|
const temporaryAgentHome = mkdtempSync(join(tmpdir(), "gentle-pi-agent-home-"));
|
|
1311
1457
|
const previousAgentHome = process.env.GENTLE_PI_AGENT_HOME;
|
|
1312
1458
|
|
|
1313
1459
|
try {
|
|
1314
1460
|
process.env.GENTLE_PI_AGENT_HOME = temporaryAgentHome;
|
|
1315
|
-
|
|
1461
|
+
installPackageAssets(PACKAGE_ROOT, true, ["delegation"]);
|
|
1316
1462
|
|
|
1317
1463
|
const installedAgentsDir = join(temporaryAgentHome, "agents");
|
|
1318
1464
|
const installedAgentPath = join(installedAgentsDir, "gentle-ai-worker.md");
|
|
@@ -1398,7 +1544,7 @@ test("asset installation uses PI_CODING_AGENT_DIR as the Pi agent home when no e
|
|
|
1398
1544
|
delete process.env.GENTLE_PI_AGENT_HOME;
|
|
1399
1545
|
process.env.PI_CODING_AGENT_DIR = temporaryPiAgentDir;
|
|
1400
1546
|
|
|
1401
|
-
|
|
1547
|
+
installPackageAssets(PACKAGE_ROOT, true, ["delegation"]);
|
|
1402
1548
|
|
|
1403
1549
|
const installedPath = join(temporaryPiAgentDir, "agents", "gentle-ai-explore.md");
|
|
1404
1550
|
assert.ok(existsSync(installedPath), "managed agents must install where Pi Subagents reads global definitions");
|
|
@@ -1409,7 +1555,7 @@ test("asset installation uses PI_CODING_AGENT_DIR as the Pi agent home when no e
|
|
|
1409
1555
|
);
|
|
1410
1556
|
|
|
1411
1557
|
process.env.GENTLE_PI_AGENT_HOME = explicitGentleHome;
|
|
1412
|
-
|
|
1558
|
+
installPackageAssets(PACKAGE_ROOT, true, ["delegation"]);
|
|
1413
1559
|
assert.ok(
|
|
1414
1560
|
existsSync(join(explicitGentleHome, "agents", "gentle-ai-explore.md")),
|
|
1415
1561
|
"GENTLE_PI_AGENT_HOME remains the explicit test/operator override",
|
|
@@ -1433,7 +1579,7 @@ test("global model routing uses PI_CODING_AGENT_DIR for package-installed agents
|
|
|
1433
1579
|
try {
|
|
1434
1580
|
delete process.env.GENTLE_PI_AGENT_HOME;
|
|
1435
1581
|
process.env.PI_CODING_AGENT_DIR = temporaryPiAgentDir;
|
|
1436
|
-
|
|
1582
|
+
installPackageAssets(PACKAGE_ROOT, true, ["delegation"]);
|
|
1437
1583
|
|
|
1438
1584
|
const result = applyModelConfig(temporaryProject, {
|
|
1439
1585
|
"gentle-ai-explore": { model: "provider/model", thinking: "high" },
|
|
@@ -1467,7 +1613,7 @@ test("normal and forced installation copy generic agents with complete role cont
|
|
|
1467
1613
|
const temporaryAgentHome = mkdtempSync(join(tmpdir(), "gentle-pi-generic-agents-"));
|
|
1468
1614
|
process.env.GENTLE_PI_AGENT_HOME = temporaryAgentHome;
|
|
1469
1615
|
try {
|
|
1470
|
-
|
|
1616
|
+
installPackageAssets(PACKAGE_ROOT, force, ["delegation"]);
|
|
1471
1617
|
|
|
1472
1618
|
for (const [name, tools] of Object.entries(expectedTools)) {
|
|
1473
1619
|
const packagedPath = join(PACKAGE_ROOT, "assets", "agents", `${name}.md`);
|
|
@@ -1476,7 +1622,7 @@ test("normal and forced installation copy generic agents with complete role cont
|
|
|
1476
1622
|
assert.equal(source, readFileSync(packagedPath, "utf8"));
|
|
1477
1623
|
assert.equal(installedName, name);
|
|
1478
1624
|
assert.deepEqual(installedTools, tools);
|
|
1479
|
-
assert.match(source, /generic
|
|
1625
|
+
assert.match(source, /generic ODD work/);
|
|
1480
1626
|
assert.match(source, /Do not (?:fix findings, delegate to child agents|delegate to child agents, commit)/);
|
|
1481
1627
|
if (name === "gentle-ai-explore") {
|
|
1482
1628
|
assert.match(source, /cwd-scoped `codegraph` tool/);
|
|
@@ -1488,7 +1634,7 @@ test("normal and forced installation copy generic agents with complete role cont
|
|
|
1488
1634
|
}
|
|
1489
1635
|
assert.match(source, /Do not (?:edit, write|edit, write, or fix findings)/);
|
|
1490
1636
|
assert.match(source, /compressed (?:handoff|evidence handoff)/);
|
|
1491
|
-
assert.match(source, /Do not use
|
|
1637
|
+
assert.match(source, /Do not use review lenses\. RDD review remains independent and parent-owned\./);
|
|
1492
1638
|
if (name === "gentle-ai-verify") {
|
|
1493
1639
|
assert.match(source, /exact test, build, or lint commands explicitly authorized by the parent/);
|
|
1494
1640
|
assert.match(source, /only outputs the parent explicitly identified as expected/);
|
|
@@ -1531,14 +1677,10 @@ test("bounded implementation routing uses the same explicit fallback in both pol
|
|
|
1531
1677
|
test("orchestrator routes generic roles without static RDD lens routing", () => {
|
|
1532
1678
|
for (const file of ["orchestrator.md", "orchestrator-delegation.md"]) {
|
|
1533
1679
|
const routing = readFileSync(join(PACKAGE_ROOT, "assets", file), "utf8");
|
|
1534
|
-
assert.match(routing,
|
|
1535
|
-
assert.match(
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
);
|
|
1539
|
-
assert.match(routing, /generic non-SDD (?:technical )?verification[\s\S]*`gentle-ai-verify`/);
|
|
1540
|
-
assert.match(routing, /SDD roles stay inside SDD|Use `sdd-explore` and `sdd-verify` only inside SDD/);
|
|
1541
|
-
assert.match(routing, /(?:truly local )?read-only check(?:ing)? of (?:known )?1[-–]3 known files|1[-–]3-file read-only check/);
|
|
1680
|
+
assert.match(routing, /`gentle-ai-explore`/);
|
|
1681
|
+
assert.match(routing, /`gentle-ai-worker`/);
|
|
1682
|
+
assert.match(routing, /`gentle-ai-verify`/);
|
|
1683
|
+
assert.match(routing, /read-only check within the evidence budget/);
|
|
1542
1684
|
assert.match(routing, /(?:verification that |verification commands →).*executes? or delegates?|executing\/delegating verification commands/);
|
|
1543
1685
|
assert.match(routing, /missing(?: or |\/)unusable[\s\S]*native `Agent`[\s\S]*(?:the )?same read-only/);
|
|
1544
1686
|
assert.match(routing, /report (?:the )?fallback/);
|
|
@@ -1563,13 +1705,10 @@ test("pi-pretty wrapper uses cached ESM loading for compiled and pnpm symlink in
|
|
|
1563
1705
|
assert.match(wrapper, /quietToolsEnabled/);
|
|
1564
1706
|
});
|
|
1565
1707
|
|
|
1566
|
-
test("Gentle Shell
|
|
1708
|
+
test("Gentle Shell v4.0.0 package manifest declares the release version", () => {
|
|
1567
1709
|
const packageJson = readPackageJson();
|
|
1568
|
-
assert.equal(packageJson.version, "
|
|
1569
|
-
assert.equal(
|
|
1570
|
-
packageJson.scripts?.test,
|
|
1571
|
-
"node --experimental-strip-types --test tests/*.test.ts && pnpm run check:provider-contract && pnpm run test:harness",
|
|
1572
|
-
);
|
|
1710
|
+
assert.equal(packageJson.version, "4.0.0", "the release manifest must be explicitly pinned to v4.0.0");
|
|
1711
|
+
assert.equal(packageJson.scripts?.test, "node scripts/run-test-suite.mjs");
|
|
1573
1712
|
assert.ok(packageJson.files?.includes("assets/"));
|
|
1574
1713
|
assert.ok(packageJson.files?.includes("contracts/"));
|
|
1575
1714
|
|
|
@@ -1610,13 +1749,13 @@ test("technical reference documents dynamic Gentle AI RDD ownership and the inst
|
|
|
1610
1749
|
});
|
|
1611
1750
|
|
|
1612
1751
|
|
|
1613
|
-
test("package verification
|
|
1614
|
-
assert.
|
|
1752
|
+
test("package verification no longer requires the retired remediation actor", () => {
|
|
1753
|
+
assert.doesNotMatch(readFileSync(join(PACKAGE_ROOT, "scripts/verify-package-files.mjs"), "utf8"), /^\s*"assets\/agents\/sdd-remediate\.md",?$/m);
|
|
1615
1754
|
});
|
|
1616
1755
|
|
|
1617
|
-
test("
|
|
1756
|
+
test("package installation retires owned sync but preserves modified copies and unrelated owners", () => {
|
|
1618
1757
|
withIsolatedAssetHome((agentHome) => {
|
|
1619
|
-
|
|
1758
|
+
installPackageAssets(agentHome, false);
|
|
1620
1759
|
const path = join(agentHome, "agents/sdd-sync.md");
|
|
1621
1760
|
const manifestPath = join(agentHome, "gentle-ai/managed-assets.json");
|
|
1622
1761
|
const legacy = "Previously managed sync executor\n";
|
|
@@ -1625,13 +1764,11 @@ test("SDD installation retires owned sync but preserves modified copies and unre
|
|
|
1625
1764
|
writeFileSync(path, legacy);
|
|
1626
1765
|
writeFileSync(manifestPath, JSON.stringify(manifest));
|
|
1627
1766
|
installPackageAssets(agentHome, true, ["delegation"]);
|
|
1628
|
-
assert.equal(readFileSync(path, "utf8"), legacy);
|
|
1629
|
-
installPackageAssets(agentHome, true, ["sdd"]);
|
|
1630
1767
|
assert.equal(existsSync(path), false);
|
|
1631
1768
|
assert.equal(installedAssetManifest(agentHome).assets["agents/sdd-sync.md"], undefined);
|
|
1632
1769
|
writeFileSync(path, "User-modified sync instructions\n");
|
|
1633
1770
|
writeFileSync(manifestPath, JSON.stringify(manifest));
|
|
1634
|
-
installPackageAssets(agentHome, true, ["
|
|
1771
|
+
installPackageAssets(agentHome, true, ["delegation"]);
|
|
1635
1772
|
assert.equal(readFileSync(path, "utf8"), "User-modified sync instructions\n");
|
|
1636
1773
|
assert.equal(installedAssetManifest(agentHome).assets["agents/sdd-sync.md"], undefined);
|
|
1637
1774
|
});
|