@stravica-ai/digital-operator-pa 0.1.28 → 0.1.30
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/dist/engineering-pa-cli/bin/estate-sync +0 -0
- package/dist/engineering-pa-cli/bin/launch +0 -0
- package/dist/engineering-pa-cli/bin/pa +0 -0
- package/dist/engineering-pa-cli/bin/pa-coordinator-hook +0 -0
- package/dist/engineering-pa-cli/bin/research +0 -0
- package/dist/engineering-pa-cli/bin/scheduler +0 -0
- package/dist/engineering-pa-cli/bin/secrets +0 -0
- package/dist/engineering-pa-cli/bin/smoke +0 -0
- package/dist/engineering-pa-cli/bin/sync +0 -0
- package/dist/engineering-pa-cli/scripts/migrate-doc-paths.mjs +0 -0
- package/dist/engineering-pa-core/bin/desk +0 -0
- package/dist/engineering-pa-core/bin/distill +0 -0
- package/dist/engineering-pa-core/bin/memory-sync +0 -0
- package/dist/engineering-pa-core/bin/slice +0 -0
- package/dist/engineering-pa-library-cli/bin/library +0 -0
- package/dist/engineering-pa-library-cli/src/config.mjs +86 -10
- package/dist/engineering-pa-library-cli/src/envelope.mjs +55 -1
- package/dist/engineering-pa-library-tunnel/bin/library-tunnel +0 -0
- package/dist/engineering-pa-library-tunnel/src/config.mjs +61 -9
- package/dist/engineering-pa-migrate-inspect/bin/migrate-inspect +0 -0
- package/dist/engineering-pa-scaffold/bin/pa-init +0 -0
- package/dist/engineering-pa-workspace/src/ws.mjs +0 -0
- package/package.json +6 -5
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -15,15 +15,89 @@
|
|
|
15
15
|
// - Consumers pass `{ repoRoot }` or the resolved paths; both surfaces
|
|
16
16
|
// are seams for tests.
|
|
17
17
|
|
|
18
|
-
import { readFileSync } from 'node:fs';
|
|
18
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
19
19
|
import { resolve, join, dirname } from 'node:path';
|
|
20
20
|
import { fileURLToPath } from 'node:url';
|
|
21
21
|
import { execFileSync } from 'node:child_process';
|
|
22
22
|
|
|
23
23
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
24
24
|
|
|
25
|
-
// operator/extensions/tools/library-cli/src/
|
|
26
|
-
|
|
25
|
+
// Legacy in-tree assumption: operator/extensions/tools/library-cli/src/ up
|
|
26
|
+
// five levels to the repo root. That assumption held while this CLI lived
|
|
27
|
+
// inside the operator repo tree; once shipped through
|
|
28
|
+
// `@stravica-ai/digital-operator-pa`'s bundled `dist/`, the same five-up walk
|
|
29
|
+
// lands INSIDE node_modules and preferences.json is never found — the
|
|
30
|
+
// consumer silently boots SIMPLE and every put/flush is refused (see
|
|
31
|
+
// w-2026-08-24-dave-021, Stream 5 P0). Kept only as the fallback for the
|
|
32
|
+
// in-tree/test invocation shape.
|
|
33
|
+
const IN_TREE_FIVE_UP = resolve(__dirname, '..', '..', '..', '..', '..');
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Layered repo-root resolution. Called each time a default is needed so
|
|
37
|
+
* the answer reflects the CURRENT environment / cwd, never a value frozen
|
|
38
|
+
* at module import.
|
|
39
|
+
*
|
|
40
|
+
* Order:
|
|
41
|
+
* (a) DAVE_ROOT env override (estate standard — CLAUDE.md Bucket 7 rule 8)
|
|
42
|
+
* (b) LIBRARY_REPO_ROOT env override (explicit CLI-scoped opt-in)
|
|
43
|
+
* (c) Walk upward from process.cwd() until a directory containing
|
|
44
|
+
* operator/config/preferences.json is found — this is the shape that
|
|
45
|
+
* proves we are inside an operator repo, and works whether the CLI
|
|
46
|
+
* ships from node_modules or lives in-tree.
|
|
47
|
+
* (d) Legacy five-up from the module directory (in-tree / test fallback).
|
|
48
|
+
*
|
|
49
|
+
* Injectable {@link opts} exists so unit tests can pin cwd + env without
|
|
50
|
+
* mutating the surrounding process.
|
|
51
|
+
*
|
|
52
|
+
* @param {object} [opts]
|
|
53
|
+
* @param {NodeJS.ProcessEnv} [opts.env] defaults to process.env
|
|
54
|
+
* @param {string} [opts.cwd] defaults to process.cwd()
|
|
55
|
+
* @returns {string} resolved repo root
|
|
56
|
+
*/
|
|
57
|
+
export function resolveDefaultRepoRoot(opts = {}) {
|
|
58
|
+
const env = opts.env ?? process.env;
|
|
59
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
60
|
+
|
|
61
|
+
// (a) DAVE_ROOT — the estate-standard project-root env (CLAUDE.md B7 R8).
|
|
62
|
+
const daveRoot = env.DAVE_ROOT;
|
|
63
|
+
if (typeof daveRoot === 'string' && daveRoot.trim() !== '') {
|
|
64
|
+
return resolve(daveRoot);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// (b) LIBRARY_REPO_ROOT — subsystem-scoped override.
|
|
68
|
+
const libRoot = env.LIBRARY_REPO_ROOT;
|
|
69
|
+
if (typeof libRoot === 'string' && libRoot.trim() !== '') {
|
|
70
|
+
return resolve(libRoot);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// (c) Walk up from cwd looking for operator/config/preferences.json.
|
|
74
|
+
let dir = resolve(cwd);
|
|
75
|
+
// Belt-and-braces guard: 64 levels is far beyond any real filesystem depth.
|
|
76
|
+
for (let i = 0; i < 64; i += 1) {
|
|
77
|
+
if (existsSync(join(dir, 'operator', 'config', 'preferences.json'))) {
|
|
78
|
+
return dir;
|
|
79
|
+
}
|
|
80
|
+
const parent = dirname(dir);
|
|
81
|
+
if (parent === dir) break;
|
|
82
|
+
dir = parent;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// (d) Legacy in-tree five-up — kept for the checkout-and-run test shape.
|
|
86
|
+
return IN_TREE_FIVE_UP;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Deprecated export retained for backwards compatibility. Points at the
|
|
91
|
+
* legacy in-tree five-up value — which is exactly the shape that fails
|
|
92
|
+
* once shipped from `node_modules`. New callers MUST use
|
|
93
|
+
* {@link resolveDefaultRepoRoot} (live) or pass an explicit `repoRoot`.
|
|
94
|
+
*
|
|
95
|
+
* Left in place because dropping the export would surface as an
|
|
96
|
+
* ImportError on any consumer that pinned the old name; the retained
|
|
97
|
+
* value never reaches the CLI's default-parameter path any more — those
|
|
98
|
+
* now call `resolveDefaultRepoRoot()` at invocation time.
|
|
99
|
+
*/
|
|
100
|
+
export const DEFAULT_REPO_ROOT = IN_TREE_FIVE_UP;
|
|
27
101
|
|
|
28
102
|
export class LibraryConfigError extends Error {
|
|
29
103
|
constructor(message, code) {
|
|
@@ -146,15 +220,16 @@ const REMOTE_KEY_REF_RE = /^([a-z0-9-]+)\/([A-Z][A-Z0-9_]*)$/;
|
|
|
146
220
|
*/
|
|
147
221
|
export function resolveRemoteKeyRef(
|
|
148
222
|
refOrLiteral,
|
|
149
|
-
{ repoRoot
|
|
223
|
+
{ repoRoot, secretsGet = defaultSecretsGet } = {},
|
|
150
224
|
) {
|
|
151
225
|
if (typeof refOrLiteral !== 'string') return refOrLiteral;
|
|
152
226
|
const m = REMOTE_KEY_REF_RE.exec(refOrLiteral);
|
|
153
227
|
if (!m) return refOrLiteral;
|
|
154
228
|
const [, scope, key] = m;
|
|
229
|
+
const root = repoRoot ?? resolveDefaultRepoRoot();
|
|
155
230
|
let resolved;
|
|
156
231
|
try {
|
|
157
|
-
resolved = secretsGet({ scope, key, repoRoot });
|
|
232
|
+
resolved = secretsGet({ scope, key, repoRoot: root });
|
|
158
233
|
} catch (err) {
|
|
159
234
|
throw new LibraryConfigError(
|
|
160
235
|
`library.remoteKey vault reference "${refOrLiteral}" failed to resolve ` +
|
|
@@ -215,9 +290,10 @@ function defaultSecretsGet({ scope, key, repoRoot }) {
|
|
|
215
290
|
* @param {string} [opts.repoRoot] defaults to DEFAULT_REPO_ROOT
|
|
216
291
|
* @returns {{mode: 'simple'|'remote', remoteEndpoint?: string, remoteKey?: string, repoRoot: string, preferences: object}}
|
|
217
292
|
*/
|
|
218
|
-
export function loadLibraryConfig({ repoRoot
|
|
219
|
-
const
|
|
220
|
-
const
|
|
293
|
+
export function loadLibraryConfig({ repoRoot } = {}) {
|
|
294
|
+
const root = repoRoot ?? resolveDefaultRepoRoot();
|
|
295
|
+
const base = join(root, 'operator', 'config', 'preferences.json');
|
|
296
|
+
const local = join(root, 'operator', 'config', 'preferences.local.json');
|
|
221
297
|
const preferences = readMergedPreferences({ base, local });
|
|
222
298
|
// Vault-ref resolution runs BEFORE resolveLibraryConfig's shape check
|
|
223
299
|
// so a ref value never reaches the `<subkeyId>:<secret>` validator.
|
|
@@ -229,11 +305,11 @@ export function loadLibraryConfig({ repoRoot = DEFAULT_REPO_ROOT } = {}) {
|
|
|
229
305
|
typeof preferences.library.remoteKey === 'string'
|
|
230
306
|
) {
|
|
231
307
|
const original = preferences.library.remoteKey;
|
|
232
|
-
const resolved = resolveRemoteKeyRef(original, { repoRoot });
|
|
308
|
+
const resolved = resolveRemoteKeyRef(original, { repoRoot: root });
|
|
233
309
|
if (resolved !== original) {
|
|
234
310
|
preferences.library = { ...preferences.library, remoteKey: resolved };
|
|
235
311
|
}
|
|
236
312
|
}
|
|
237
313
|
const resolved = resolveLibraryConfig(preferences);
|
|
238
|
-
return { ...resolved, repoRoot, preferences };
|
|
314
|
+
return { ...resolved, repoRoot: root, preferences };
|
|
239
315
|
}
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
import { createHash, randomUUID } from 'node:crypto';
|
|
15
15
|
import { hostname } from 'node:os';
|
|
16
|
-
import { relative,
|
|
16
|
+
import { isAbsolute, normalize, relative, sep } from 'node:path';
|
|
17
17
|
|
|
18
18
|
import { EVENT_KINDS, canonicalJson } from '@stravica-ai/remote-library';
|
|
19
19
|
|
|
@@ -31,6 +31,47 @@ export function contentShaOf(payload) {
|
|
|
31
31
|
return `sha256:${createHash('sha256').update(canonical).digest('hex')}`;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Refuse a source path that would encode as an escape from the repo root.
|
|
36
|
+
* Root-cause cure for the poison-event wedge Stream 5 re-verify Scope C
|
|
37
|
+
* surfaced (w-2026-08-24-dave-025, SA14). Called by buildEnvelope after
|
|
38
|
+
* relPath is computed. Semantics match the server's assertPathSafe
|
|
39
|
+
* (spec §4 apply gate): reject empty, absolute, NUL, drive-letter,
|
|
40
|
+
* root-backslash, `..`-segments, and any string that normalises to a
|
|
41
|
+
* path starting with `..`. The error names the input sourcePath and
|
|
42
|
+
* repoRoot so an operator can see immediately why the encoding refused.
|
|
43
|
+
*
|
|
44
|
+
* @param {string} relPath candidate repo-relative path
|
|
45
|
+
* @param {string} sourcePath original input (for the error message)
|
|
46
|
+
* @param {string} repoRoot resolved repo root (for the error message)
|
|
47
|
+
* @throws {Error} with exitCode=1 if the path is unsafe
|
|
48
|
+
*/
|
|
49
|
+
export function assertRepoRelativeSafe(relPath, sourcePath, repoRoot) {
|
|
50
|
+
const fail = (reason) => {
|
|
51
|
+
const err = new Error(
|
|
52
|
+
`refusing to encode source path outside repo root (${reason}): ` +
|
|
53
|
+
`sourcePath=${JSON.stringify(sourcePath)}, repoRoot=${JSON.stringify(repoRoot)}, ` +
|
|
54
|
+
`resolvedRelative=${JSON.stringify(relPath)}. ` +
|
|
55
|
+
`Move the file into the repo or stage it under a repo-resident path before calling library put.`,
|
|
56
|
+
);
|
|
57
|
+
err.exitCode = 1;
|
|
58
|
+
throw err;
|
|
59
|
+
};
|
|
60
|
+
if (typeof relPath !== 'string') fail('path must be a string');
|
|
61
|
+
if (relPath.length === 0) fail('path resolves empty');
|
|
62
|
+
if (relPath.includes('\0')) fail('path contains NUL byte');
|
|
63
|
+
if (isAbsolute(relPath)) fail('resolved path is absolute');
|
|
64
|
+
if (/^[A-Za-z]:[\\/]/.test(relPath) || relPath.startsWith('\\')) {
|
|
65
|
+
fail('drive-letter or root-backslash path');
|
|
66
|
+
}
|
|
67
|
+
const parts = relPath.split(/[/\\]/);
|
|
68
|
+
if (parts.some((seg) => seg === '..')) fail("'..' segments not permitted");
|
|
69
|
+
const normalised = normalize(relPath);
|
|
70
|
+
if (normalised === '..' || normalised.startsWith('..' + sep) || normalised.startsWith('../')) {
|
|
71
|
+
fail('path normalises outside repo root');
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
34
75
|
/**
|
|
35
76
|
* Guess the event kind from a staging file path when the operator did
|
|
36
77
|
* not supply one via `--kind`. Falls back to
|
|
@@ -77,9 +118,22 @@ export function buildEnvelope({
|
|
|
77
118
|
sourceKind = 'manual',
|
|
78
119
|
clock = () => new Date(),
|
|
79
120
|
}) {
|
|
121
|
+
// Repo-relative resolution + refusal for anything that would encode as
|
|
122
|
+
// a `..`-segment or otherwise escape the repo root. This is the root
|
|
123
|
+
// cause cure for the Stream 5 re-verify Scope C poison-event wedge
|
|
124
|
+
// (w-2026-08-24-dave-025). Before this cure `relative(repoRoot, abs)`
|
|
125
|
+
// silently produced `../../etc/...` for files sitting outside the
|
|
126
|
+
// repo and the envelope was posted with a payload path the worker's
|
|
127
|
+
// apply gate would later refuse — halting single-writer propagation
|
|
128
|
+
// for the whole estate. Refusing here (client-side, at encoding time)
|
|
129
|
+
// stops the poison at source; SA14's ingest-side check is the second
|
|
130
|
+
// line; the worker's apply gate remains the third.
|
|
80
131
|
const relPath = sourcePath
|
|
81
132
|
? isAbsolute(sourcePath) ? relative(repoRoot, sourcePath) : sourcePath
|
|
82
133
|
: undefined;
|
|
134
|
+
if (relPath !== undefined) {
|
|
135
|
+
assertRepoRelativeSafe(relPath, sourcePath, repoRoot);
|
|
136
|
+
}
|
|
83
137
|
|
|
84
138
|
const resolvedKind = kind ?? guessKindFromPath(relPath ?? sourcePath ?? '') ?? null;
|
|
85
139
|
if (!resolvedKind) {
|
|
File without changes
|
|
@@ -12,8 +12,60 @@ import { fileURLToPath } from 'node:url';
|
|
|
12
12
|
import { homedir } from 'node:os';
|
|
13
13
|
|
|
14
14
|
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
|
|
16
|
+
// Legacy in-tree assumption: operator/extensions/tools/library-tunnel/src/ up
|
|
17
|
+
// five levels to repo root. Held while the tool lived in-tree; once shipped
|
|
18
|
+
// through `@stravica-ai/digital-operator-pa`, the same walk lands INSIDE
|
|
19
|
+
// node_modules and state files spray into the platform tarball instead of
|
|
20
|
+
// the consumer's .cache/. Same defect class as library-cli
|
|
21
|
+
// (w-2026-08-24-dave-021); layered resolution below fixes both.
|
|
22
|
+
const IN_TREE_FIVE_UP = resolve(HERE, '..', '..', '..', '..', '..');
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Layered repo-root resolution. See library-cli/src/config.mjs for the
|
|
26
|
+
* full rationale; short version: (a) DAVE_ROOT env, (b) LIBRARY_REPO_ROOT
|
|
27
|
+
* env, (c) walk cwd upward until operator/config/preferences.json is
|
|
28
|
+
* found, (d) fall back to the legacy five-up for in-tree/test invocations.
|
|
29
|
+
*
|
|
30
|
+
* @param {object} [opts]
|
|
31
|
+
* @param {NodeJS.ProcessEnv} [opts.env] defaults to process.env
|
|
32
|
+
* @param {string} [opts.cwd] defaults to process.cwd()
|
|
33
|
+
* @returns {string} resolved repo root
|
|
34
|
+
*/
|
|
35
|
+
export function resolveDefaultRepoRoot(opts = {}) {
|
|
36
|
+
const env = opts.env ?? process.env;
|
|
37
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
38
|
+
|
|
39
|
+
const daveRoot = env.DAVE_ROOT;
|
|
40
|
+
if (typeof daveRoot === 'string' && daveRoot.trim() !== '') {
|
|
41
|
+
return resolve(daveRoot);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const libRoot = env.LIBRARY_REPO_ROOT;
|
|
45
|
+
if (typeof libRoot === 'string' && libRoot.trim() !== '') {
|
|
46
|
+
return resolve(libRoot);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
let dir = resolve(cwd);
|
|
50
|
+
for (let i = 0; i < 64; i += 1) {
|
|
51
|
+
if (existsSync(join(dir, 'operator', 'config', 'preferences.json'))) {
|
|
52
|
+
return dir;
|
|
53
|
+
}
|
|
54
|
+
const parent = dirname(dir);
|
|
55
|
+
if (parent === dir) break;
|
|
56
|
+
dir = parent;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return IN_TREE_FIVE_UP;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Deprecated export retained for backwards compatibility. Points at the
|
|
64
|
+
* legacy in-tree five-up value (which is exactly the shape that fails
|
|
65
|
+
* once shipped from node_modules). New callers use
|
|
66
|
+
* {@link resolveDefaultRepoRoot} or pass an explicit `repoRoot`.
|
|
67
|
+
*/
|
|
68
|
+
export const DEFAULT_REPO_ROOT = IN_TREE_FIVE_UP;
|
|
17
69
|
|
|
18
70
|
function readJsonObject(path) {
|
|
19
71
|
try {
|
|
@@ -30,7 +82,7 @@ function readJsonObject(path) {
|
|
|
30
82
|
* @param {string} repoRoot
|
|
31
83
|
* @returns {string|null}
|
|
32
84
|
*/
|
|
33
|
-
export function readPaName(repoRoot =
|
|
85
|
+
export function readPaName(repoRoot = resolveDefaultRepoRoot()) {
|
|
34
86
|
const base = readJsonObject(join(repoRoot, 'operator', 'config', 'preferences.json')) || {};
|
|
35
87
|
const local = readJsonObject(join(repoRoot, 'operator', 'config', 'preferences.local.json')) || {};
|
|
36
88
|
const merged = { ...base, ...local };
|
|
@@ -65,13 +117,13 @@ export function plistPath(host) {
|
|
|
65
117
|
* @param {string} host
|
|
66
118
|
* @param {string} repoRoot
|
|
67
119
|
*/
|
|
68
|
-
export function stateDir(repoRoot =
|
|
120
|
+
export function stateDir(repoRoot = resolveDefaultRepoRoot()) {
|
|
69
121
|
return join(repoRoot, '.cache', 'library-tunnel');
|
|
70
122
|
}
|
|
71
|
-
export function statePath(host, repoRoot =
|
|
123
|
+
export function statePath(host, repoRoot = resolveDefaultRepoRoot()) {
|
|
72
124
|
return join(stateDir(repoRoot), `${host}.json`);
|
|
73
125
|
}
|
|
74
|
-
export function logPath(host, repoRoot =
|
|
126
|
+
export function logPath(host, repoRoot = resolveDefaultRepoRoot()) {
|
|
75
127
|
return join(stateDir(repoRoot), `${host}.log`);
|
|
76
128
|
}
|
|
77
129
|
|
|
@@ -88,7 +140,7 @@ export function logPath(host, repoRoot = DEFAULT_REPO_ROOT) {
|
|
|
88
140
|
* installedAt: string
|
|
89
141
|
* }}
|
|
90
142
|
*/
|
|
91
|
-
export function readState(host, repoRoot =
|
|
143
|
+
export function readState(host, repoRoot = resolveDefaultRepoRoot()) {
|
|
92
144
|
return readJsonObject(statePath(host, repoRoot));
|
|
93
145
|
}
|
|
94
146
|
|
|
@@ -98,7 +150,7 @@ export function readState(host, repoRoot = DEFAULT_REPO_ROOT) {
|
|
|
98
150
|
* @param {object} state
|
|
99
151
|
* @param {string} [repoRoot]
|
|
100
152
|
*/
|
|
101
|
-
export function writeState(host, state, repoRoot =
|
|
153
|
+
export function writeState(host, state, repoRoot = resolveDefaultRepoRoot()) {
|
|
102
154
|
const dir = stateDir(repoRoot);
|
|
103
155
|
mkdirSync(dir, { recursive: true });
|
|
104
156
|
const path = statePath(host, repoRoot);
|
|
@@ -111,7 +163,7 @@ export function writeState(host, state, repoRoot = DEFAULT_REPO_ROOT) {
|
|
|
111
163
|
* @param {string} host
|
|
112
164
|
* @param {string} [repoRoot]
|
|
113
165
|
*/
|
|
114
|
-
export function removeState(host, repoRoot =
|
|
166
|
+
export function removeState(host, repoRoot = resolveDefaultRepoRoot()) {
|
|
115
167
|
const path = statePath(host, repoRoot);
|
|
116
168
|
if (existsSync(path)) unlinkSync(path);
|
|
117
169
|
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stravica-ai/digital-operator-pa",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Digital Operator PA
|
|
3
|
+
"version": "0.1.30",
|
|
4
|
+
"description": "Digital Operator PA \u2014 single-bundled public package surface (bins + library) for the platform.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.mjs",
|
|
7
7
|
"exports": {
|
|
@@ -52,10 +52,11 @@
|
|
|
52
52
|
"engines": {
|
|
53
53
|
"node": ">=24"
|
|
54
54
|
},
|
|
55
|
-
"//": "test pins --test-isolation=none: default process-isolation mode silently undercounts (drops passed tests from totals) when a test awaits async work while stdout is patched by a capture() helper — see packages/cli/test/secrets. Counts must never lie.",
|
|
56
55
|
"scripts": {
|
|
57
56
|
"build": "node build.mjs",
|
|
57
|
+
"prepack": "node build.mjs",
|
|
58
58
|
"test": "node --test --test-isolation=none test/*.test.mjs",
|
|
59
59
|
"dry-publish": "node build.mjs && node scripts/dry-publish.mjs"
|
|
60
|
-
}
|
|
61
|
-
|
|
60
|
+
},
|
|
61
|
+
"//": "test pins --test-isolation=none: default process-isolation mode silently undercounts (drops passed tests from totals) when a test awaits async work while stdout is patched by a capture() helper \u2014 see packages/cli/test/secrets. Counts must never lie."
|
|
62
|
+
}
|