glimmervoid 0.30.0 → 0.32.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 +1 -1
- package/dist/bin/glimmervoid.js +144 -57
- package/dist/chunks/{adapters-Dho1VSY5.js → adapters-BU74M4QZ.js} +1 -1
- package/dist/chunks/{adapters-zPDx1Xox.js → adapters-CoC18rdt.js} +56 -31
- package/dist/chunks/agent-api-cli-V_BkYhBI.js +142 -0
- package/dist/chunks/agent-api-core-B3YI8SYs.js +192 -0
- package/dist/chunks/{agent-setup-cli-B5Atxr3F.js → agent-setup-cli-D4956BfN.js} +11 -28
- package/dist/chunks/backoff-DjVpfHk7.js +14 -0
- package/dist/chunks/child-process-safe-B3zcPdFM.js +2 -0
- package/dist/chunks/{child-process-safe-DRGsp0TE.js → child-process-safe-DDELk9XC.js} +3 -2
- package/dist/chunks/coerce-NSst8oRP.js +32 -0
- package/dist/chunks/{contracts-DGkKNh9W.js → config-CZ4H51D0.js} +374 -1684
- package/dist/chunks/{config-store-mm7MgzoL.js → config-store-BVtdHkDK.js} +594 -329
- package/dist/chunks/config-store-Cp62jN1O.js +2 -0
- package/dist/chunks/contracts-DXujp-Zn.js +2131 -0
- package/dist/chunks/git-version-CrLW4a6r.js +58 -0
- package/dist/chunks/{grok-DuU8xVLZ.js → grok-C4lzPFEg.js} +24 -21
- package/dist/chunks/{hook-relay-core-BHfYFnYV.js → hook-relay-core-DA_bz2KA.js} +10 -5
- package/dist/chunks/{hook-tools-pSJia7ks.js → hook-tools-UX2fmt81.js} +3 -5
- package/dist/chunks/{ingest-editor-core-BuI1gMF_.js → ingest-editor-core-vR6Wv6bP.js} +24 -13
- package/dist/chunks/json-core-dfa_7Fak.js +23 -0
- package/dist/chunks/json-file-oEH9vt-0.js +352 -0
- package/dist/chunks/knowledge-graph-cli-Bjy9_kv5.js +1354 -0
- package/dist/chunks/{loopback-post-C7C22eYi.js → loopback-post-DepQfdcM.js} +40 -26
- package/dist/chunks/{main-CuIZQPhZ.js → main-DSbpYn2Y.js} +27880 -19139
- package/dist/chunks/{node-pty-preflight-CK1knGIR.js → node-pty-preflight-C8QIlrtU.js} +4 -6
- package/dist/chunks/{pair-cli-w-gCAF-1.js → pair-cli-CKn-wUw9.js} +4 -3
- package/dist/chunks/paths-CeJl2Vcg.js +55 -0
- package/dist/chunks/{remote-config-C2ytQwrs.js → remote-config-DP44Ybt9.js} +37 -41
- package/dist/chunks/{rtk-hook-core-Bl6gYHPN.js → rtk-hook-core-BmEz2aq9.js} +3 -5
- package/dist/chunks/rtk-resolver-CIVLE_xk.js +2 -0
- package/dist/chunks/{rtk-resolver-CLo-gZzw.js → rtk-resolver-jJxy_Mrt.js} +2 -2
- package/dist/chunks/{runtime-paths-Ci_ksSkj.js → runtime-paths-BPoxENmK.js} +2 -6
- package/dist/chunks/runtime-paths-DU5jBEEO.js +2 -0
- package/dist/chunks/{sandbox-deps-Dd5-kZnf.js → sandbox-deps-DuaNFq7n.js} +16 -13
- package/dist/chunks/sandbox-proxy-core-hnQgKR0T.js +27 -0
- package/dist/chunks/{session-Cez8aIWg.js → session-B8fJb_Or.js} +25 -2
- package/dist/chunks/text-DoirglWV.js +21 -0
- package/dist/chunks/timer-deps-u2DAQLok.js +15 -0
- package/dist/chunks/{visions-cli-BXQFIBCX.js → visions-cli-BhFdym5n.js} +1 -1
- package/dist/chunks/{visions-setup-CvVnOe1r.js → visions-setup-CfgNHiG3.js} +20 -357
- package/dist/client/assets/index-C_XKsDFx.css +1 -0
- package/dist/client/assets/index-CoqWjYxP.js +254 -0
- package/dist/client/fonts/CommitMono-OFL.txt +92 -0
- package/dist/client/fonts/commit-mono-400-italic.woff2 +0 -0
- package/dist/client/fonts/commit-mono-400-regular.woff2 +0 -0
- package/dist/client/fonts/commit-mono-700-italic.woff2 +0 -0
- package/dist/client/fonts/commit-mono-700-regular.woff2 +0 -0
- package/dist/client/index.html +7 -24
- package/dist/client/octicons-LICENSE.txt +21 -0
- package/dist/scripts/postinstall-path-check.js +1 -1
- package/dist/server/index.js +3 -3
- package/dist/session/command-hook-relay.js +1 -1
- package/dist/session/hook-relay.js +3 -3
- package/dist/session/hook-tool-relay.js +2 -2
- package/dist/session/sandbox-open-launcher.js +79 -0
- package/dist/session/statusline-relay.js +8 -18
- package/dist/session/visions-relay.js +20 -11
- package/package.json +4 -1
- package/dist/chunks/agent-api-cli-D0MmtEdz.js +0 -71
- package/dist/chunks/agent-api-core-Dz0r21y9.js +0 -103
- package/dist/chunks/child-process-safe-DvQjXsgz.js +0 -2
- package/dist/chunks/config-store-CC8T3okC.js +0 -2
- package/dist/chunks/ingest-core-DWI1Mbu4.js +0 -342
- package/dist/chunks/rtk-resolver-CMQAidlI.js +0 -2
- package/dist/chunks/runtime-paths-JLrZ3wyi.js +0 -2
- package/dist/client/assets/index-B1MFijjb.css +0 -1
- package/dist/client/assets/index-CU1iPPdn.js +0 -249
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { a as AgentDispatchRequest, c as ORCHESTRATOR_AGENT_VERBS, i as AgentAttentionRequest, o as AgentSpawnRequest, t as AGENT_API_VERBS } from "./session-B8fJb_Or.js";
|
|
2
|
+
import crypto from "node:crypto";
|
|
3
|
+
var MAX_SPAWNS_IN_FLIGHT = 1;
|
|
4
|
+
var SPAWNABLE_DEPTH = 0;
|
|
5
|
+
var REFUSAL_REASON = "unknown session";
|
|
6
|
+
var INVALID_BODY_STATUS = 400;
|
|
7
|
+
var PUSH_REFUSED_STATUS = 409;
|
|
8
|
+
var PUSH_UNAVAILABLE_REASON = "not-operator-session";
|
|
9
|
+
var PUSH_REFUSAL_COPY = Object.freeze({
|
|
10
|
+
[PUSH_UNAVAILABLE_REASON]: () => "only an operator session or a session it spawned can push",
|
|
11
|
+
"no-worktree": () => "this session has no worktree of its own, so there is nothing of its own to land",
|
|
12
|
+
"merge-in-progress": () => "a merge for this session is already running, so try again when it ends",
|
|
13
|
+
"not-continuable": () => "this session cannot be merged in its current state",
|
|
14
|
+
destroyed: () => "this session is ending",
|
|
15
|
+
"nothing-to-commit": () => "no commit on this branch is missing from the integration branch, so commit your work first",
|
|
16
|
+
"rebase-conflict": ({ base, conflicts = [] }) => `this branch conflicts with ${base} in ${conflicts.join(", ") || "one or more files"}, so rebase onto ${base}, resolve the conflicts, commit, then push again`,
|
|
17
|
+
"not-fast-forward": ({ base }) => `${base} could not be fast-forwarded to this branch, and a push is never forced`,
|
|
18
|
+
"base-diverged": ({ base }) => `the local ${base} and origin/${base} have diverged, which the operator has to reconcile`
|
|
19
|
+
});
|
|
20
|
+
function tokensMatch(presented, expected) {
|
|
21
|
+
if (presented.length !== expected.length) return false;
|
|
22
|
+
try {
|
|
23
|
+
return crypto.timingSafeEqual(Buffer.from(presented, "utf8"), Buffer.from(expected, "utf8"));
|
|
24
|
+
} catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function refused() {
|
|
29
|
+
return {
|
|
30
|
+
ok: false,
|
|
31
|
+
status: 404,
|
|
32
|
+
reason: REFUSAL_REASON
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function decideAgentRequest({ sessionId, presentedToken, expectedToken, isLoopback }) {
|
|
36
|
+
if (!isLoopback) return refused();
|
|
37
|
+
if (!sessionId) return refused();
|
|
38
|
+
if (!expectedToken) return refused();
|
|
39
|
+
if (!presentedToken) return refused();
|
|
40
|
+
if (!tokensMatch(presentedToken, expectedToken)) return refused();
|
|
41
|
+
return { ok: true };
|
|
42
|
+
}
|
|
43
|
+
function decideSpawnAllowance({ liveChildren, lifetimeSpawns, inFlight, depth }) {
|
|
44
|
+
if (depth !== SPAWNABLE_DEPTH) return {
|
|
45
|
+
ok: false,
|
|
46
|
+
status: 403,
|
|
47
|
+
reason: "a spawned session may not spawn another"
|
|
48
|
+
};
|
|
49
|
+
if (inFlight >= MAX_SPAWNS_IN_FLIGHT) return {
|
|
50
|
+
ok: false,
|
|
51
|
+
status: 429,
|
|
52
|
+
reason: "a spawn is already in flight"
|
|
53
|
+
};
|
|
54
|
+
if (liveChildren >= 3) return {
|
|
55
|
+
ok: false,
|
|
56
|
+
status: 429,
|
|
57
|
+
reason: `at most 3 spawned sessions may be live at once`
|
|
58
|
+
};
|
|
59
|
+
if (lifetimeSpawns >= 10) return {
|
|
60
|
+
ok: false,
|
|
61
|
+
status: 429,
|
|
62
|
+
reason: `this session has used its 10 spawns`
|
|
63
|
+
};
|
|
64
|
+
return { ok: true };
|
|
65
|
+
}
|
|
66
|
+
function isAgentApiVerb(verb) {
|
|
67
|
+
return AGENT_API_VERBS.includes(verb);
|
|
68
|
+
}
|
|
69
|
+
function isOrchestratorAgentVerb(verb) {
|
|
70
|
+
return ORCHESTRATOR_AGENT_VERBS.includes(verb);
|
|
71
|
+
}
|
|
72
|
+
var TICKET_ACTION_STATES = Object.freeze({
|
|
73
|
+
reopen: Object.freeze(["blocked"]),
|
|
74
|
+
cancel: Object.freeze(["open", "blocked"])
|
|
75
|
+
});
|
|
76
|
+
function decideTicketAction({ verb, intentId, ticket }) {
|
|
77
|
+
if (!ticket) return {
|
|
78
|
+
ok: false,
|
|
79
|
+
reason: "no such ticket"
|
|
80
|
+
};
|
|
81
|
+
if (ticket.parent !== intentId) return {
|
|
82
|
+
ok: false,
|
|
83
|
+
reason: "the ticket is not a child of the active intent"
|
|
84
|
+
};
|
|
85
|
+
const allowed = TICKET_ACTION_STATES[verb];
|
|
86
|
+
if (!allowed.includes(ticket.state)) return {
|
|
87
|
+
ok: false,
|
|
88
|
+
reason: `only a ${allowed.join(" or ")} ticket can be ${verb === "reopen" ? "reopened" : "cancelled"}, and this one is ${ticket.state}`
|
|
89
|
+
};
|
|
90
|
+
if (verb === "reopen") return {
|
|
91
|
+
ok: true,
|
|
92
|
+
kind: "transition",
|
|
93
|
+
to: "open"
|
|
94
|
+
};
|
|
95
|
+
return {
|
|
96
|
+
ok: true,
|
|
97
|
+
kind: "close",
|
|
98
|
+
outcome: "cancelled"
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function refuseInvalidBody(issues) {
|
|
102
|
+
return {
|
|
103
|
+
ok: false,
|
|
104
|
+
status: INVALID_BODY_STATUS,
|
|
105
|
+
error: issues[0]?.message || "invalid request"
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function parseAgentVerb(verb, payload) {
|
|
109
|
+
if (!isAgentApiVerb(verb)) return {
|
|
110
|
+
ok: false,
|
|
111
|
+
status: 404,
|
|
112
|
+
error: REFUSAL_REASON
|
|
113
|
+
};
|
|
114
|
+
if (verb === "dispatch") {
|
|
115
|
+
const parsed = AgentDispatchRequest.safeParse(payload);
|
|
116
|
+
if (!parsed.success) return refuseInvalidBody(parsed.error.issues);
|
|
117
|
+
return {
|
|
118
|
+
ok: true,
|
|
119
|
+
verb,
|
|
120
|
+
request: parsed.data
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
if (verb === "reopen" || verb === "cancel") return {
|
|
124
|
+
ok: false,
|
|
125
|
+
status: 403,
|
|
126
|
+
error: `${verb} requires a live factory orchestrator`
|
|
127
|
+
};
|
|
128
|
+
if (verb === "board" || verb === "push") return {
|
|
129
|
+
ok: true,
|
|
130
|
+
verb
|
|
131
|
+
};
|
|
132
|
+
if (verb === "attention") {
|
|
133
|
+
const parsed = AgentAttentionRequest.safeParse(payload);
|
|
134
|
+
if (!parsed.success) return refuseInvalidBody(parsed.error.issues);
|
|
135
|
+
return {
|
|
136
|
+
ok: true,
|
|
137
|
+
verb,
|
|
138
|
+
request: parsed.data
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
const parsed = AgentSpawnRequest.safeParse(payload);
|
|
142
|
+
if (!parsed.success) return refuseInvalidBody(parsed.error.issues);
|
|
143
|
+
return {
|
|
144
|
+
ok: true,
|
|
145
|
+
verb,
|
|
146
|
+
request: parsed.data
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
function describePushLanding(landing) {
|
|
150
|
+
if (!landing.merged) {
|
|
151
|
+
const reason = landing.reason || "unknown";
|
|
152
|
+
const explain = PUSH_REFUSAL_COPY[reason];
|
|
153
|
+
return {
|
|
154
|
+
status: PUSH_REFUSED_STATUS,
|
|
155
|
+
body: {
|
|
156
|
+
ok: false,
|
|
157
|
+
reason,
|
|
158
|
+
error: explain ? explain(landing) : `the merge stopped: ${reason}`
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
if (landing.pushed) return {
|
|
163
|
+
status: 200,
|
|
164
|
+
body: {
|
|
165
|
+
ok: true,
|
|
166
|
+
landedOn: landing.base ?? null,
|
|
167
|
+
pushed: true
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
return {
|
|
171
|
+
status: 200,
|
|
172
|
+
body: {
|
|
173
|
+
ok: true,
|
|
174
|
+
landedOn: landing.base ?? null,
|
|
175
|
+
pushed: false,
|
|
176
|
+
note: "landed locally and nothing was pushed, because the repository has no origin remote or origin did not take a fast-forward"
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
function deriveChildSessionName(parentName, existingNames) {
|
|
181
|
+
const base = `${String(parentName || "").trim() || "session"} agent`;
|
|
182
|
+
const taken = new Set(existingNames);
|
|
183
|
+
let candidate = base;
|
|
184
|
+
let suffix = 1;
|
|
185
|
+
while (taken.has(candidate)) {
|
|
186
|
+
suffix += 1;
|
|
187
|
+
candidate = `${base} ${suffix}`;
|
|
188
|
+
}
|
|
189
|
+
return candidate;
|
|
190
|
+
}
|
|
191
|
+
//#endregion
|
|
192
|
+
export { decideTicketAction as a, isAgentApiVerb as c, decideSpawnAllowance as i, isOrchestratorAgentVerb as l, REFUSAL_REASON as n, deriveChildSessionName as o, decideAgentRequest as r, describePushLanding as s, PUSH_UNAVAILABLE_REASON as t, parseAgentVerb as u };
|
|
@@ -1,16 +1,10 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as isMissingFileError, r as errorMessage } from "./text-DoirglWV.js";
|
|
2
|
+
import { a as classifyGrokHooksFile, o as renderGrokHooksFile, t as grok } from "./grok-C4lzPFEg.js";
|
|
3
|
+
import { p as writeTextAtomicSync } from "./json-file-oEH9vt-0.js";
|
|
2
4
|
import fs from "node:fs";
|
|
3
5
|
import path from "node:path";
|
|
4
|
-
import crypto from "node:crypto";
|
|
5
6
|
//#region server/agent-setup-cli.ts
|
|
6
7
|
var USAGE = "Usage: glimmervoid agent setup grok";
|
|
7
|
-
function errorCode(error) {
|
|
8
|
-
const code = error?.code;
|
|
9
|
-
return typeof code === "string" ? code : void 0;
|
|
10
|
-
}
|
|
11
|
-
function errorMessage(error) {
|
|
12
|
-
return error instanceof Error ? error.message : String(error);
|
|
13
|
-
}
|
|
14
8
|
function setupInputs(env = process.env) {
|
|
15
9
|
return {
|
|
16
10
|
filePath: grok.hooksFilePath(env),
|
|
@@ -26,7 +20,7 @@ function inspectGrokAgentSetup({ env = process.env, readFileSync = fs.readFileSy
|
|
|
26
20
|
try {
|
|
27
21
|
contents = readFileSync(inputs.filePath, "utf8");
|
|
28
22
|
} catch (error) {
|
|
29
|
-
if (
|
|
23
|
+
if (isMissingFileError(error, { includeNotDir: false })) return {
|
|
30
24
|
filePath: inputs.filePath,
|
|
31
25
|
classification: "absent"
|
|
32
26
|
};
|
|
@@ -59,7 +53,7 @@ function ensureWritableHooksDirectory(directory, fileSystem) {
|
|
|
59
53
|
assertRealDirectory(currentDirectory, fileSystem);
|
|
60
54
|
continue;
|
|
61
55
|
} catch (directoryError) {
|
|
62
|
-
if (
|
|
56
|
+
if (!isMissingFileError(directoryError, { includeNotDir: false })) throw directoryError;
|
|
63
57
|
}
|
|
64
58
|
fileSystem.mkdirSync(currentDirectory, { mode: 448 });
|
|
65
59
|
assertRealDirectory(currentDirectory, fileSystem);
|
|
@@ -69,23 +63,12 @@ function ensureWritableHooksDirectory(directory, fileSystem) {
|
|
|
69
63
|
} catch {}
|
|
70
64
|
}
|
|
71
65
|
function replaceFileAtomically(filePath, contents, fileSystem) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
});
|
|
79
|
-
fileSystem.renameSync(temporaryPath, filePath);
|
|
80
|
-
} catch (writeError) {
|
|
81
|
-
try {
|
|
82
|
-
fileSystem.rmSync(temporaryPath, { force: true });
|
|
83
|
-
} catch {}
|
|
84
|
-
throw writeError;
|
|
85
|
-
}
|
|
86
|
-
try {
|
|
87
|
-
fileSystem.chmodSync(filePath, 384);
|
|
88
|
-
} catch {}
|
|
66
|
+
writeTextAtomicSync(filePath, contents, {
|
|
67
|
+
mode: 384,
|
|
68
|
+
exclusive: true,
|
|
69
|
+
enforceMode: true,
|
|
70
|
+
fsSync: fileSystem
|
|
71
|
+
});
|
|
89
72
|
}
|
|
90
73
|
function runGrokSetup({ env, fileSystem, log, error }) {
|
|
91
74
|
const inputs = setupInputs(env);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region shared/backoff.ts
|
|
2
|
+
var DEFAULT_BASE_MS = 6e4;
|
|
3
|
+
var DEFAULT_MAX_MS = 18e5;
|
|
4
|
+
var MAX_DOUBLING_ATTEMPT = 20;
|
|
5
|
+
function nextBackoffMs({ attempt = 1, baseMs = DEFAULT_BASE_MS, maxMs = DEFAULT_MAX_MS, retryAfterMs = null, random = Math.random, jitter = "full" } = {}) {
|
|
6
|
+
if (typeof retryAfterMs === "number" && Number.isFinite(retryAfterMs) && retryAfterMs > 0) return Math.min(retryAfterMs, maxMs);
|
|
7
|
+
const exponent = Math.max(0, Math.min(attempt, MAX_DOUBLING_ATTEMPT) - 1);
|
|
8
|
+
const ceiling = Math.min(maxMs, baseMs * 2 ** exponent);
|
|
9
|
+
if (jitter === "none") return ceiling;
|
|
10
|
+
if (jitter === "half") return Math.round(ceiling * (.5 + .5 * random()));
|
|
11
|
+
return Math.round(random() * ceiling);
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
export { DEFAULT_MAX_MS as n, nextBackoffMs as r, DEFAULT_BASE_MS as t };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import cp from "node:child_process";
|
|
2
1
|
import { promisify } from "node:util";
|
|
2
|
+
import cp from "node:child_process";
|
|
3
3
|
//#region server/child-process-safe.ts
|
|
4
4
|
function hide(options) {
|
|
5
5
|
if (!options || typeof options !== "object") return { windowsHide: true };
|
|
@@ -13,7 +13,8 @@ function split(rest) {
|
|
|
13
13
|
let options;
|
|
14
14
|
let callback;
|
|
15
15
|
for (const v of rest) {
|
|
16
|
-
if (Array.isArray(v) && v.every((entry) => typeof entry === "string"))
|
|
16
|
+
if (Array.isArray(v) && !v.every((entry) => typeof entry === "string")) throw new TypeError("command arguments must all be strings");
|
|
17
|
+
if (Array.isArray(v)) args = v;
|
|
17
18
|
if (typeof v === "function") callback = v;
|
|
18
19
|
if (v && typeof v === "object" && !Array.isArray(v)) options = v;
|
|
19
20
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
//#region shared/coerce.ts
|
|
2
|
+
function isRecord(value) {
|
|
3
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4
|
+
}
|
|
5
|
+
function textOr(value, fallback) {
|
|
6
|
+
return typeof value === "string" && value.trim() ? value.trim() : fallback;
|
|
7
|
+
}
|
|
8
|
+
function rawTextOr(value, fallback) {
|
|
9
|
+
return typeof value === "string" && value.length > 0 ? value : fallback;
|
|
10
|
+
}
|
|
11
|
+
function numberOr(value, fallback) {
|
|
12
|
+
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
13
|
+
}
|
|
14
|
+
function positiveNumberOr(value, fallback) {
|
|
15
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback;
|
|
16
|
+
}
|
|
17
|
+
function nonNegativeIntOr(value, fallback) {
|
|
18
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) return fallback;
|
|
19
|
+
return Math.floor(value);
|
|
20
|
+
}
|
|
21
|
+
function coercedNumberOr(value, fallback) {
|
|
22
|
+
const number = Number(value);
|
|
23
|
+
if (!Number.isFinite(number)) return fallback;
|
|
24
|
+
return number;
|
|
25
|
+
}
|
|
26
|
+
function positiveIntOr(value, fallback) {
|
|
27
|
+
const number = Number(value);
|
|
28
|
+
if (!Number.isFinite(number) || number <= 0) return fallback;
|
|
29
|
+
return Math.floor(number);
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
export { positiveIntOr as a, textOr as c, numberOr as i, isRecord as n, positiveNumberOr as o, nonNegativeIntOr as r, rawTextOr as s, coercedNumberOr as t };
|