@tryinget/pi-agent-vent 0.1.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/LICENSE +78 -0
- package/README.md +188 -0
- package/biome.jsonc +43 -0
- package/docs/adr/2026-05-22-agent-vent-retention-delete-policy.md +65 -0
- package/docs/engineering.local.md +57 -0
- package/docs/project/2026-05-21-agent-vent-design.md +182 -0
- package/docs/project/2026-05-21-agent-vent-implementation-plan.md +66 -0
- package/docs/project/extension-sop.md +52 -0
- package/docs/project/product-posture.md +191 -0
- package/docs/project/trusted-publishing.md +53 -0
- package/docs/project/vision.md +70 -0
- package/examples/.gitkeep +0 -0
- package/extensions/agent-vent.ts +1384 -0
- package/package.json +95 -0
- package/policy/engineering-lane.json +22 -0
- package/policy/security-policy.json +10 -0
- package/prompts/implementation-planning.md +20 -0
- package/prompts/security-review.md +20 -0
- package/scripts/docs-list.sh +50 -0
- package/scripts/quality-gate.sh +168 -0
- package/scripts/release-artifact-check.mjs +221 -0
- package/scripts/release-check.sh +196 -0
- package/scripts/release-smoke-check.mjs +367 -0
- package/scripts/release-smoke.sh +90 -0
- package/scripts/validate-structure.mjs +248 -0
- package/scripts/validate-structure.sh +145 -0
- package/src/vent-store.js +2839 -0
- package/tests/.gitkeep +0 -0
- package/tests/agent-vent-extension.test.js +762 -0
- package/tests/release-artifact-check.test.js +168 -0
- package/tests/release-smoke-check.test.js +235 -0
- package/tests/vent-store.test.js +1972 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import test from "node:test";
|
|
6
|
+
import {
|
|
7
|
+
collectPackagedMarkdownLinkFailures,
|
|
8
|
+
parsePackJson,
|
|
9
|
+
runReleaseArtifactCheck,
|
|
10
|
+
validatePackageFilesWhitelist,
|
|
11
|
+
} from "../scripts/release-artifact-check.mjs";
|
|
12
|
+
|
|
13
|
+
const readFrom = (files) => (filePath) => files[filePath] ?? "";
|
|
14
|
+
|
|
15
|
+
test("packaged markdown link validation accepts packaged local, directory, query, fragment, and external links", () => {
|
|
16
|
+
const actualFiles = ["README.md", "docs/guide.md", "docs/nested/index.md", "package.json"];
|
|
17
|
+
const markdown = [
|
|
18
|
+
"[guide](docs/guide.md)",
|
|
19
|
+
"[guide with query](docs/guide.md?view=full#intro)",
|
|
20
|
+
'[guide with title](<docs/guide.md> "maintainer guide")',
|
|
21
|
+
"[reference][guide-ref]",
|
|
22
|
+
'[guide-ref]: docs/guide.md "reference title"',
|
|
23
|
+
"[directory](docs/nested/)",
|
|
24
|
+
"[fragment](#local-section)",
|
|
25
|
+
"[external](https://example.invalid/docs)",
|
|
26
|
+
"[mailto](mailto:maintainer@example.invalid)",
|
|
27
|
+
].join("\n");
|
|
28
|
+
|
|
29
|
+
const result = collectPackagedMarkdownLinkFailures({
|
|
30
|
+
actualFiles,
|
|
31
|
+
readFile: readFrom({ "README.md": markdown, "docs/guide.md": "# Guide" }),
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
assert.deepEqual(result, { failures: [], packagedMarkdownCount: 3 });
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("packaged markdown link validation fails closed for missing local and reference links", () => {
|
|
38
|
+
const result = collectPackagedMarkdownLinkFailures({
|
|
39
|
+
actualFiles: ["README.md", "package.json"],
|
|
40
|
+
readFile: readFrom({
|
|
41
|
+
"README.md": ["[missing](docs/missing.md)", "[missing-ref]: docs/also-missing.md"].join("\n"),
|
|
42
|
+
}),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
assert.deepEqual(result.failures, [
|
|
46
|
+
"README.md: local link missing from npm artifact: docs/missing.md",
|
|
47
|
+
"README.md: local link missing from npm artifact: docs/also-missing.md",
|
|
48
|
+
]);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("packaged markdown link validation fails closed for path escapes", () => {
|
|
52
|
+
const result = collectPackagedMarkdownLinkFailures({
|
|
53
|
+
actualFiles: ["README.md", "docs/guide.md", "package.json"],
|
|
54
|
+
readFile: readFrom({
|
|
55
|
+
"README.md": ["[parent](../outside.md)", "[absolute](/etc/passwd)"].join("\n"),
|
|
56
|
+
"docs/guide.md": "[nested parent](../../outside.md)",
|
|
57
|
+
}),
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
assert.deepEqual(result.failures, [
|
|
61
|
+
"README.md: local link escapes package root: ../outside.md",
|
|
62
|
+
"README.md: local link escapes package root: /etc/passwd",
|
|
63
|
+
"docs/guide.md: local link escapes package root: ../../outside.md",
|
|
64
|
+
]);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test("pack json parser fails closed for malformed, stale, or unsafe pack output", () => {
|
|
68
|
+
assert.throws(() => parsePackJson("not json"), /Could not parse npm pack/);
|
|
69
|
+
assert.throws(() => parsePackJson(JSON.stringify([{ files: null }])), /Could not parse npm pack/);
|
|
70
|
+
assert.throws(
|
|
71
|
+
() => parsePackJson(JSON.stringify([{ files: [{ path: "../outside.md" }] }])),
|
|
72
|
+
/unsafe package path/,
|
|
73
|
+
);
|
|
74
|
+
assert.throws(
|
|
75
|
+
() => parsePackJson(JSON.stringify([{ files: [{ path: "/etc/passwd" }] }])),
|
|
76
|
+
/unsafe package path/,
|
|
77
|
+
);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("package files whitelist fails closed for wildcard entries", () => {
|
|
81
|
+
assert.throws(
|
|
82
|
+
() =>
|
|
83
|
+
validatePackageFilesWhitelist({
|
|
84
|
+
cwd: process.cwd(),
|
|
85
|
+
filesEntries: ["docs/*.md"],
|
|
86
|
+
actualFiles: ["package.json", "docs/readme.txt"],
|
|
87
|
+
}),
|
|
88
|
+
/Unsupported files\[\] wildcard entry/,
|
|
89
|
+
);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test("package files whitelist detects missing and extra artifact entries", () => {
|
|
93
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "agent-vent-artifact-check-"));
|
|
94
|
+
try {
|
|
95
|
+
fs.writeFileSync(path.join(dir, "package.json"), "{}\n");
|
|
96
|
+
fs.mkdirSync(path.join(dir, "docs"));
|
|
97
|
+
fs.writeFileSync(path.join(dir, "docs", "guide.md"), "# Guide\n");
|
|
98
|
+
|
|
99
|
+
const result = validatePackageFilesWhitelist({
|
|
100
|
+
cwd: dir,
|
|
101
|
+
filesEntries: ["docs/guide.md"],
|
|
102
|
+
actualFiles: ["README.md", "package.json", "unexpected.txt"],
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
assert.deepEqual(result, {
|
|
106
|
+
missing: ["docs/guide.md"],
|
|
107
|
+
extra: ["unexpected.txt"],
|
|
108
|
+
});
|
|
109
|
+
} finally {
|
|
110
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test("release artifact check accepts directory files entries and always-included metadata", () => {
|
|
115
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "agent-vent-release-check-ok-"));
|
|
116
|
+
try {
|
|
117
|
+
fs.writeFileSync(path.join(dir, "package.json"), JSON.stringify({ files: ["docs"] }));
|
|
118
|
+
fs.writeFileSync(path.join(dir, "README.md"), "[guide](docs/guide.md)\n");
|
|
119
|
+
fs.writeFileSync(path.join(dir, "LICENSE"), "local test license\n");
|
|
120
|
+
fs.mkdirSync(path.join(dir, "docs"));
|
|
121
|
+
fs.writeFileSync(path.join(dir, "docs", "guide.md"), "# Guide\n");
|
|
122
|
+
const packJsonText = JSON.stringify([
|
|
123
|
+
{
|
|
124
|
+
files: [
|
|
125
|
+
{ path: "README.md" },
|
|
126
|
+
{ path: "LICENSE" },
|
|
127
|
+
{ path: "docs/guide.md" },
|
|
128
|
+
{ path: "package.json" },
|
|
129
|
+
],
|
|
130
|
+
},
|
|
131
|
+
]);
|
|
132
|
+
const logs = [];
|
|
133
|
+
|
|
134
|
+
runReleaseArtifactCheck({ cwd: dir, packJsonText, log: (message) => logs.push(message) });
|
|
135
|
+
|
|
136
|
+
assert.deepEqual(logs, [
|
|
137
|
+
"File whitelist OK (4 files).",
|
|
138
|
+
"Packaged Markdown links OK (2 files).",
|
|
139
|
+
]);
|
|
140
|
+
} finally {
|
|
141
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test("release artifact check reports packaged markdown failures with actionable wording", () => {
|
|
146
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "agent-vent-release-check-"));
|
|
147
|
+
try {
|
|
148
|
+
fs.writeFileSync(
|
|
149
|
+
path.join(dir, "package.json"),
|
|
150
|
+
JSON.stringify({ files: ["README.md", "docs/guide.md"] }),
|
|
151
|
+
);
|
|
152
|
+
fs.mkdirSync(path.join(dir, "docs"));
|
|
153
|
+
fs.writeFileSync(path.join(dir, "README.md"), "[missing](docs/missing.md)\n");
|
|
154
|
+
fs.writeFileSync(path.join(dir, "docs", "guide.md"), "# Guide\n");
|
|
155
|
+
const packJsonText = JSON.stringify([
|
|
156
|
+
{
|
|
157
|
+
files: [{ path: "README.md" }, { path: "docs/guide.md" }, { path: "package.json" }],
|
|
158
|
+
},
|
|
159
|
+
]);
|
|
160
|
+
|
|
161
|
+
assert.throws(
|
|
162
|
+
() => runReleaseArtifactCheck({ cwd: dir, packJsonText, log: () => {} }),
|
|
163
|
+
/Packaged Markdown link check failed\.\n- README\.md: local link missing from npm artifact: docs\/missing\.md/,
|
|
164
|
+
);
|
|
165
|
+
} finally {
|
|
166
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
167
|
+
}
|
|
168
|
+
});
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import test from "node:test";
|
|
6
|
+
import {
|
|
7
|
+
assertAgentVentPathSmokeOutput,
|
|
8
|
+
assertInstalledArtifactPackage,
|
|
9
|
+
assertLocalTarballInstallSource,
|
|
10
|
+
assertPackageSpecInstalled,
|
|
11
|
+
buildLocalPathArtifactSettings,
|
|
12
|
+
executeInstalledArtifactToolPathSmoke,
|
|
13
|
+
packageSourcesFromSettings,
|
|
14
|
+
} from "../scripts/release-smoke-check.mjs";
|
|
15
|
+
|
|
16
|
+
test("release smoke settings check accepts only unfiltered string package entries", () => {
|
|
17
|
+
const settings = {
|
|
18
|
+
packages: [
|
|
19
|
+
"npm:/tmp/pkg-a.tgz",
|
|
20
|
+
{ source: "npm:/tmp/pi-agent-vent.tgz", extensions: ["extensions/agent-vent.ts"] },
|
|
21
|
+
{ source: 42 },
|
|
22
|
+
null,
|
|
23
|
+
],
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
assert.deepEqual(packageSourcesFromSettings(settings), [
|
|
27
|
+
"npm:/tmp/pkg-a.tgz",
|
|
28
|
+
"npm:/tmp/pi-agent-vent.tgz",
|
|
29
|
+
]);
|
|
30
|
+
assert.doesNotThrow(() =>
|
|
31
|
+
assertPackageSpecInstalled({ settings, packageSpec: "npm:/tmp/pkg-a.tgz" }),
|
|
32
|
+
);
|
|
33
|
+
assert.throws(
|
|
34
|
+
() => assertPackageSpecInstalled({ settings, packageSpec: "npm:/tmp/pi-agent-vent.tgz" }),
|
|
35
|
+
/requires an unfiltered package entry/,
|
|
36
|
+
);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test("release smoke settings check fails closed when package spec is missing", () => {
|
|
40
|
+
assert.throws(
|
|
41
|
+
() => assertPackageSpecInstalled({ settings: { packages: [] }, packageSpec: "" }),
|
|
42
|
+
/PACKAGE_SPEC is required/,
|
|
43
|
+
);
|
|
44
|
+
assert.throws(
|
|
45
|
+
() =>
|
|
46
|
+
assertPackageSpecInstalled({
|
|
47
|
+
settings: { packages: ["npm:/tmp/other.tgz"] },
|
|
48
|
+
packageSpec: "npm:/tmp/pi-agent-vent.tgz",
|
|
49
|
+
}),
|
|
50
|
+
/Installed package spec not found/,
|
|
51
|
+
);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("release smoke validates local npm tarball specs as install sources only", () => {
|
|
55
|
+
assert.deepEqual(assertLocalTarballInstallSource({ packageSpec: "npm:/tmp/pi-agent-vent.tgz" }), {
|
|
56
|
+
tarballPath: "/tmp/pi-agent-vent.tgz",
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
assert.throws(
|
|
60
|
+
() => assertLocalTarballInstallSource({ packageSpec: "" }),
|
|
61
|
+
/PACKAGE_SPEC is required/,
|
|
62
|
+
);
|
|
63
|
+
assert.throws(
|
|
64
|
+
() => assertLocalTarballInstallSource({ packageSpec: "/tmp/pi-agent-vent.tgz" }),
|
|
65
|
+
/expected an npm: tarball install source/,
|
|
66
|
+
);
|
|
67
|
+
assert.throws(
|
|
68
|
+
() => assertLocalTarballInstallSource({ packageSpec: "npm:../pi-agent-vent.tgz" }),
|
|
69
|
+
/expected npm:<absolute \.tgz path>/,
|
|
70
|
+
);
|
|
71
|
+
assert.throws(
|
|
72
|
+
() => assertLocalTarballInstallSource({ packageSpec: "npm:/tmp/pi-agent-vent.zip" }),
|
|
73
|
+
/expected npm:<absolute \.tgz path>/,
|
|
74
|
+
);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("release smoke installed artifact check verifies package identity and extension entrypoint", () => {
|
|
78
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "agent-vent-installed-artifact-"));
|
|
79
|
+
try {
|
|
80
|
+
fs.mkdirSync(path.join(dir, "extensions"));
|
|
81
|
+
fs.writeFileSync(
|
|
82
|
+
path.join(dir, "extensions", "agent-vent.ts"),
|
|
83
|
+
"export default function() {}\n",
|
|
84
|
+
);
|
|
85
|
+
fs.writeFileSync(
|
|
86
|
+
path.join(dir, "package.json"),
|
|
87
|
+
JSON.stringify({
|
|
88
|
+
name: "@tryinget/pi-agent-vent",
|
|
89
|
+
version: "0.1.0",
|
|
90
|
+
pi: { extensions: ["./extensions/agent-vent.ts"] },
|
|
91
|
+
}),
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
assert.deepEqual(
|
|
95
|
+
assertInstalledArtifactPackage({
|
|
96
|
+
packageRoot: dir,
|
|
97
|
+
packageName: "@tryinget/pi-agent-vent",
|
|
98
|
+
packageVersion: "0.1.0",
|
|
99
|
+
}),
|
|
100
|
+
{
|
|
101
|
+
packageJsonPath: path.join(dir, "package.json"),
|
|
102
|
+
extensionPath: path.join(dir, "extensions", "agent-vent.ts"),
|
|
103
|
+
},
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
assert.throws(
|
|
107
|
+
() =>
|
|
108
|
+
assertInstalledArtifactPackage({
|
|
109
|
+
packageRoot: dir,
|
|
110
|
+
packageName: "@tryinget/pi-agent-vent",
|
|
111
|
+
packageVersion: "0.2.0",
|
|
112
|
+
}),
|
|
113
|
+
/Installed package version mismatch/,
|
|
114
|
+
);
|
|
115
|
+
} finally {
|
|
116
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test("release smoke can rewrite isolated settings to load installed artifact through local-path package discovery", () => {
|
|
121
|
+
assert.deepEqual(
|
|
122
|
+
buildLocalPathArtifactSettings({
|
|
123
|
+
settings: {
|
|
124
|
+
defaultProvider: "openai",
|
|
125
|
+
defaultModel: "gpt-4o",
|
|
126
|
+
packages: ["npm:/tmp/pi-agent-vent.tgz"],
|
|
127
|
+
extensions: ["/tmp/escape.ts"],
|
|
128
|
+
},
|
|
129
|
+
packageRoot: "/tmp/isolated-prefix/lib/node_modules/@tryinget/pi-agent-vent",
|
|
130
|
+
}),
|
|
131
|
+
{
|
|
132
|
+
defaultProvider: "openai",
|
|
133
|
+
defaultModel: "gpt-4o",
|
|
134
|
+
packages: ["/tmp/isolated-prefix/lib/node_modules/@tryinget/pi-agent-vent"],
|
|
135
|
+
extensions: [],
|
|
136
|
+
},
|
|
137
|
+
);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test("release smoke command output check accepts isolated agent vent path output", () => {
|
|
141
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "agent-vent-smoke-ok-"));
|
|
142
|
+
try {
|
|
143
|
+
const output = [
|
|
144
|
+
`Agent vent store: ${dir}/vents.jsonl`,
|
|
145
|
+
`Agent vent review events: ${dir}/review-events.jsonl`,
|
|
146
|
+
`Agent vent curation events: ${dir}/curation-events.jsonl`,
|
|
147
|
+
`Agent vent retention events: ${dir}/retention-events.jsonl`,
|
|
148
|
+
`Agent vent retention backups: ${dir}/backups`,
|
|
149
|
+
"Schema: append-only JSONL events plus confirmation-gated local retention backup artifacts.",
|
|
150
|
+
"Override: set PI_AGENT_VENT_DIR to use a different private directory.",
|
|
151
|
+
"Authority boundary: records, review states, and curation projections are local diagnostics, not tasks, issues, incidents, evidence, telemetry, or ASC/self state; retention receipts and backups are local diagnostics too.",
|
|
152
|
+
].join("\n");
|
|
153
|
+
|
|
154
|
+
assert.doesNotThrow(() => assertAgentVentPathSmokeOutput({ output, ventDir: dir }));
|
|
155
|
+
} finally {
|
|
156
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test("release smoke installed shadow registered-tool path stays isolated and does not read active stores", async () => {
|
|
161
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "agent-vent-tool-smoke-"));
|
|
162
|
+
try {
|
|
163
|
+
const unsafeTarget = path.join(dir, "unsafe-target.jsonl");
|
|
164
|
+
fs.writeFileSync(unsafeTarget, "", "utf8");
|
|
165
|
+
fs.symlinkSync(unsafeTarget, path.join(dir, "vents.jsonl"));
|
|
166
|
+
|
|
167
|
+
const result = await executeInstalledArtifactToolPathSmoke({
|
|
168
|
+
packageRoot: process.cwd(),
|
|
169
|
+
ventDir: dir,
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
assert.equal(result.executionMode, "shadow-copy");
|
|
173
|
+
assert.match(result.output, /Agent vent store:/);
|
|
174
|
+
assert.match(result.output, /not tasks, issues, incidents, evidence/);
|
|
175
|
+
assert.equal(fs.lstatSync(path.join(dir, "vents.jsonl")).isSymbolicLink(), true);
|
|
176
|
+
assert.equal(fs.existsSync(path.join(dir, "review-events.jsonl")), false);
|
|
177
|
+
assert.equal(fs.existsSync(path.join(dir, "curation-events.jsonl")), false);
|
|
178
|
+
assert.equal(fs.existsSync(path.join(dir, "retention-events.jsonl")), false);
|
|
179
|
+
assert.equal(fs.existsSync(path.join(dir, "backups")), false);
|
|
180
|
+
} finally {
|
|
181
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test("release smoke installed shadow registered-tool path fails closed when tool is not registered", async () => {
|
|
186
|
+
const packageRoot = fs.mkdtempSync(path.join(os.tmpdir(), "agent-vent-no-tool-"));
|
|
187
|
+
const ventDir = fs.mkdtempSync(path.join(os.tmpdir(), "agent-vent-no-tool-store-"));
|
|
188
|
+
try {
|
|
189
|
+
fs.mkdirSync(path.join(packageRoot, "extensions"));
|
|
190
|
+
fs.writeFileSync(
|
|
191
|
+
path.join(packageRoot, "extensions", "agent-vent.ts"),
|
|
192
|
+
"export default function(pi) { pi.registerCommand('agent_vent', { handler() {} }); }\n",
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
await assert.rejects(
|
|
196
|
+
() => executeInstalledArtifactToolPathSmoke({ packageRoot, ventDir }),
|
|
197
|
+
/did not register executable agent_vent tool/,
|
|
198
|
+
);
|
|
199
|
+
} finally {
|
|
200
|
+
fs.rmSync(packageRoot, { recursive: true, force: true });
|
|
201
|
+
fs.rmSync(ventDir, { recursive: true, force: true });
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
test("release smoke command output check fails closed for wrong store, missing boundary, or default store", () => {
|
|
206
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "agent-vent-smoke-bad-"));
|
|
207
|
+
try {
|
|
208
|
+
assert.throws(
|
|
209
|
+
() =>
|
|
210
|
+
assertAgentVentPathSmokeOutput({
|
|
211
|
+
output: "Agent vent store: /tmp/other/vents.jsonl",
|
|
212
|
+
ventDir: dir,
|
|
213
|
+
}),
|
|
214
|
+
/did not match the expected local diagnostic contract/,
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
const defaultStoreOutput = [
|
|
218
|
+
`Agent vent store: ${dir}/vents.jsonl`,
|
|
219
|
+
`Agent vent review events: ${dir}/review-events.jsonl`,
|
|
220
|
+
`Agent vent curation events: ${dir}/curation-events.jsonl`,
|
|
221
|
+
`Agent vent retention events: ${dir}/retention-events.jsonl`,
|
|
222
|
+
`Agent vent retention backups: ${dir}/backups`,
|
|
223
|
+
"Override: set PI_AGENT_VENT_DIR to use a different private directory.",
|
|
224
|
+
"Authority boundary: records, review states, and curation projections are local diagnostics, not tasks, issues, incidents, evidence, telemetry, or ASC/self state; retention receipts and backups are local diagnostics too.",
|
|
225
|
+
"accidental /.pi/agent/agent-vent/vents.jsonl leak",
|
|
226
|
+
].join("\n");
|
|
227
|
+
|
|
228
|
+
assert.throws(
|
|
229
|
+
() => assertAgentVentPathSmokeOutput({ output: defaultStoreOutput, ventDir: dir }),
|
|
230
|
+
/default operator vent store/,
|
|
231
|
+
);
|
|
232
|
+
} finally {
|
|
233
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
234
|
+
}
|
|
235
|
+
});
|