@probelabs/visor 0.1.90 → 0.1.92
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 +68 -2
- package/action.yml +1 -1
- package/defaults/.visor.yaml +120 -154
- package/dist/13.index.js +82 -0
- package/dist/159.index.js +38 -0
- package/dist/168.index.js +82 -0
- package/dist/201.index.js +82 -0
- package/dist/262.index.js +48 -0
- package/dist/272.index.js +82 -0
- package/dist/273.index.js +48 -0
- package/dist/320.index.js +38 -0
- package/dist/34.index.js +81 -0
- package/dist/421.index.js +48 -0
- package/dist/437.index.js +82 -0
- package/dist/441.index.js +81 -0
- package/dist/450.index.js +82 -0
- package/dist/54.index.js +81 -0
- package/dist/544.index.js +38 -0
- package/dist/558.index.js +82 -0
- package/dist/715.index.js +38 -0
- package/dist/737.index.js +82 -0
- package/dist/834.index.js +48 -0
- package/dist/85.index.js +82 -0
- package/dist/861.index.js +48 -0
- package/dist/878.index.js +81 -0
- package/dist/940.index.js +38 -0
- package/dist/989.index.js +81 -0
- package/dist/996.index.js +82 -0
- package/dist/ai-review-service.d.ts +11 -1
- package/dist/ai-review-service.d.ts.map +1 -1
- package/dist/check-execution-engine.d.ts +9 -2
- package/dist/check-execution-engine.d.ts.map +1 -1
- package/dist/cli-main.d.ts.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/defaults/.visor.yaml +120 -154
- package/dist/failure-condition-evaluator.d.ts +3 -2
- package/dist/failure-condition-evaluator.d.ts.map +1 -1
- package/dist/generated/config-schema.d.ts +89 -2
- package/dist/generated/config-schema.d.ts.map +1 -1
- package/dist/generated/config-schema.json +109 -1
- package/dist/git-repository-analyzer.d.ts +17 -1
- package/dist/git-repository-analyzer.d.ts.map +1 -1
- package/dist/github-comments.d.ts.map +1 -1
- package/dist/github-reactions.d.ts +36 -0
- package/dist/github-reactions.d.ts.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +172824 -45634
- package/dist/liquid-extensions.d.ts +3 -0
- package/dist/liquid-extensions.d.ts.map +1 -1
- package/dist/memory-store.d.ts +129 -0
- package/dist/memory-store.d.ts.map +1 -0
- package/dist/output/issue-assistant/schema.json +29 -0
- package/dist/output/issue-assistant/template.liquid +1 -0
- package/dist/output/overview/schema.json +33 -0
- package/dist/output/overview/template.liquid +16 -0
- package/dist/output-formatters.d.ts +1 -0
- package/dist/output-formatters.d.ts.map +1 -1
- package/dist/pr-analyzer.d.ts +2 -0
- package/dist/pr-analyzer.d.ts.map +1 -1
- package/dist/proto/channelz.proto +564 -0
- package/dist/providers/check-provider-registry.d.ts.map +1 -1
- package/dist/providers/command-check-provider.d.ts.map +1 -1
- package/dist/providers/github-ops-provider.d.ts +18 -0
- package/dist/providers/github-ops-provider.d.ts.map +1 -0
- package/dist/providers/memory-check-provider.d.ts +56 -0
- package/dist/providers/memory-check-provider.d.ts.map +1 -0
- package/dist/reviewer.d.ts +2 -0
- package/dist/reviewer.d.ts.map +1 -1
- package/dist/sdk/check-execution-engine-L73PFZQY.mjs +11 -0
- package/dist/sdk/chunk-2U6BIWSY.mjs +748 -0
- package/dist/sdk/chunk-2U6BIWSY.mjs.map +1 -0
- package/dist/sdk/chunk-KVHVCGY6.mjs +103 -0
- package/dist/sdk/chunk-KVHVCGY6.mjs.map +1 -0
- package/dist/sdk/{chunk-N2PPFOSF.mjs → chunk-LJHRU3WQ.mjs} +2577 -250
- package/dist/sdk/chunk-LJHRU3WQ.mjs.map +1 -0
- package/dist/sdk/chunk-TWJKAYT6.mjs +1124 -0
- package/dist/sdk/chunk-TWJKAYT6.mjs.map +1 -0
- package/dist/sdk/liquid-extensions-AFKRYROF.mjs +14 -0
- package/dist/sdk/mermaid-telemetry-LZGDD35I.mjs +61 -0
- package/dist/sdk/mermaid-telemetry-LZGDD35I.mjs.map +1 -0
- package/dist/sdk/sdk.d.mts +48 -2
- package/dist/sdk/sdk.d.ts +48 -2
- package/dist/sdk/sdk.js +5352 -767
- package/dist/sdk/sdk.js.map +1 -1
- package/dist/sdk/sdk.mjs +112 -7
- package/dist/sdk/sdk.mjs.map +1 -1
- package/dist/sdk/tracer-init-O7RLXMJ3.mjs +10 -0
- package/dist/sdk/tracer-init-O7RLXMJ3.mjs.map +1 -0
- package/dist/session-registry.d.ts +19 -5
- package/dist/session-registry.d.ts.map +1 -1
- package/dist/telemetry/fallback-ndjson.d.ts +7 -0
- package/dist/telemetry/fallback-ndjson.d.ts.map +1 -0
- package/dist/telemetry/file-span-exporter.d.ts +17 -0
- package/dist/telemetry/file-span-exporter.d.ts.map +1 -0
- package/dist/telemetry/metrics.d.ts +13 -0
- package/dist/telemetry/metrics.d.ts.map +1 -0
- package/dist/telemetry/opentelemetry.d.ts +26 -0
- package/dist/telemetry/opentelemetry.d.ts.map +1 -0
- package/dist/telemetry/trace-helpers.d.ts +9 -0
- package/dist/telemetry/trace-helpers.d.ts.map +1 -0
- package/dist/telemetry/trace-report-exporter.d.ts +17 -0
- package/dist/telemetry/trace-report-exporter.d.ts.map +1 -0
- package/dist/traces/run-2025-10-15T07-21-47-696Z.ndjson +17 -0
- package/dist/traces/run-2025-10-15T07-21-58-106Z.ndjson +17 -0
- package/dist/traces/run-2025-10-15T07-21-58-693Z.ndjson +17 -0
- package/dist/traces/run-2025-10-15T07-21-59-167Z.ndjson +17 -0
- package/dist/traces/run-2025-10-15T07-21-59-629Z.ndjson +8 -0
- package/dist/types/cli.d.ts +4 -0
- package/dist/types/cli.d.ts.map +1 -1
- package/dist/types/config.d.ts +56 -2
- package/dist/types/config.d.ts.map +1 -1
- package/dist/utils/author-permissions.d.ts +74 -0
- package/dist/utils/author-permissions.d.ts.map +1 -0
- package/dist/utils/head-sha.d.ts +8 -0
- package/dist/utils/head-sha.d.ts.map +1 -0
- package/dist/utils/mermaid-telemetry.d.ts +3 -0
- package/dist/utils/mermaid-telemetry.d.ts.map +1 -0
- package/dist/utils/tracer-init.d.ts +12 -0
- package/dist/utils/tracer-init.d.ts.map +1 -0
- package/dist/utils/ui-helpers.d.ts +3 -0
- package/dist/utils/ui-helpers.d.ts.map +1 -0
- package/package.json +2 -2
- package/dist/sdk/check-execution-engine-Z2USLMN5.mjs +0 -9
- package/dist/sdk/chunk-FIL2OGF6.mjs +0 -68
- package/dist/sdk/chunk-FIL2OGF6.mjs.map +0 -1
- package/dist/sdk/chunk-N2PPFOSF.mjs.map +0 -1
- package/dist/sdk/liquid-extensions-KDECAJTV.mjs +0 -12
- /package/dist/sdk/{check-execution-engine-Z2USLMN5.mjs.map → check-execution-engine-L73PFZQY.mjs.map} +0 -0
- /package/dist/sdk/{liquid-extensions-KDECAJTV.mjs.map → liquid-extensions-AFKRYROF.mjs.map} +0 -0
|
@@ -0,0 +1,748 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__esm,
|
|
3
|
+
__export
|
|
4
|
+
} from "./chunk-WMJKH4XE.mjs";
|
|
5
|
+
|
|
6
|
+
// src/logger.ts
|
|
7
|
+
var logger_exports = {};
|
|
8
|
+
__export(logger_exports, {
|
|
9
|
+
configureLoggerFromCli: () => configureLoggerFromCli,
|
|
10
|
+
logger: () => logger
|
|
11
|
+
});
|
|
12
|
+
function levelToNumber(level) {
|
|
13
|
+
switch (level) {
|
|
14
|
+
case "silent":
|
|
15
|
+
return 0;
|
|
16
|
+
case "error":
|
|
17
|
+
return 10;
|
|
18
|
+
case "warn":
|
|
19
|
+
return 20;
|
|
20
|
+
case "info":
|
|
21
|
+
return 30;
|
|
22
|
+
case "verbose":
|
|
23
|
+
return 40;
|
|
24
|
+
case "debug":
|
|
25
|
+
return 50;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function configureLoggerFromCli(options) {
|
|
29
|
+
logger.configure({
|
|
30
|
+
outputFormat: options.output,
|
|
31
|
+
debug: options.debug,
|
|
32
|
+
verbose: options.verbose,
|
|
33
|
+
quiet: options.quiet
|
|
34
|
+
});
|
|
35
|
+
try {
|
|
36
|
+
if (options.output) process.env.VISOR_OUTPUT_FORMAT = String(options.output);
|
|
37
|
+
if (typeof options.debug === "boolean") {
|
|
38
|
+
process.env.VISOR_DEBUG = options.debug ? "true" : "false";
|
|
39
|
+
}
|
|
40
|
+
} catch {
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
var Logger, logger;
|
|
44
|
+
var init_logger = __esm({
|
|
45
|
+
"src/logger.ts"() {
|
|
46
|
+
"use strict";
|
|
47
|
+
Logger = class {
|
|
48
|
+
level = "info";
|
|
49
|
+
isJsonLike = false;
|
|
50
|
+
isTTY = typeof process !== "undefined" ? !!process.stderr.isTTY : false;
|
|
51
|
+
configure(opts = {}) {
|
|
52
|
+
let lvl = "info";
|
|
53
|
+
if (opts.debug || process.env.VISOR_DEBUG === "true") {
|
|
54
|
+
lvl = "debug";
|
|
55
|
+
} else if (opts.verbose || process.env.VISOR_LOG_LEVEL === "verbose") {
|
|
56
|
+
lvl = "verbose";
|
|
57
|
+
} else if (opts.quiet || process.env.VISOR_LOG_LEVEL === "quiet") {
|
|
58
|
+
lvl = "warn";
|
|
59
|
+
} else if (opts.level) {
|
|
60
|
+
lvl = opts.level;
|
|
61
|
+
} else if (process.env.VISOR_LOG_LEVEL) {
|
|
62
|
+
const envLvl = process.env.VISOR_LOG_LEVEL;
|
|
63
|
+
if (["silent", "error", "warn", "info", "verbose", "debug"].includes(envLvl)) {
|
|
64
|
+
lvl = envLvl;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
this.level = lvl;
|
|
68
|
+
const output = opts.outputFormat || process.env.VISOR_OUTPUT_FORMAT || "table";
|
|
69
|
+
this.isJsonLike = output === "json" || output === "sarif";
|
|
70
|
+
}
|
|
71
|
+
shouldLog(level) {
|
|
72
|
+
const desired = levelToNumber(level);
|
|
73
|
+
const current = levelToNumber(this.level);
|
|
74
|
+
if (desired > current) return false;
|
|
75
|
+
if (this.isJsonLike && desired < levelToNumber("error") && this.level !== "debug" && this.level !== "verbose") {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
write(msg) {
|
|
81
|
+
try {
|
|
82
|
+
process.stderr.write(msg + "\n");
|
|
83
|
+
} catch {
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
info(msg) {
|
|
87
|
+
if (this.shouldLog("info")) this.write(msg);
|
|
88
|
+
}
|
|
89
|
+
warn(msg) {
|
|
90
|
+
if (this.shouldLog("warn")) this.write(msg);
|
|
91
|
+
}
|
|
92
|
+
error(msg) {
|
|
93
|
+
if (this.shouldLog("error")) this.write(msg);
|
|
94
|
+
}
|
|
95
|
+
verbose(msg) {
|
|
96
|
+
if (this.shouldLog("verbose")) this.write(msg);
|
|
97
|
+
}
|
|
98
|
+
debug(msg) {
|
|
99
|
+
if (this.shouldLog("debug")) this.write(msg);
|
|
100
|
+
}
|
|
101
|
+
step(msg) {
|
|
102
|
+
if (this.shouldLog("info")) this.write(`\u25B6 ${msg}`);
|
|
103
|
+
}
|
|
104
|
+
success(msg) {
|
|
105
|
+
if (this.shouldLog("info")) this.write(`\u2714 ${msg}`);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
logger = new Logger();
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// src/liquid-extensions.ts
|
|
113
|
+
import { Liquid, Tag, Value } from "liquidjs";
|
|
114
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
115
|
+
import fs2 from "fs/promises";
|
|
116
|
+
import path2 from "path";
|
|
117
|
+
|
|
118
|
+
// src/utils/author-permissions.ts
|
|
119
|
+
var PERMISSION_HIERARCHY = [
|
|
120
|
+
"OWNER",
|
|
121
|
+
"MEMBER",
|
|
122
|
+
"COLLABORATOR",
|
|
123
|
+
"CONTRIBUTOR",
|
|
124
|
+
"FIRST_TIME_CONTRIBUTOR",
|
|
125
|
+
"FIRST_TIMER",
|
|
126
|
+
"NONE"
|
|
127
|
+
];
|
|
128
|
+
function getPermissionLevel(association) {
|
|
129
|
+
if (!association) return PERMISSION_HIERARCHY.length;
|
|
130
|
+
const index = PERMISSION_HIERARCHY.indexOf(association.toUpperCase());
|
|
131
|
+
return index === -1 ? PERMISSION_HIERARCHY.length : index;
|
|
132
|
+
}
|
|
133
|
+
function hasMinPermission(authorAssociation, minPermission, isLocalMode = false) {
|
|
134
|
+
if (isLocalMode) {
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
const authorLevel = getPermissionLevel(authorAssociation);
|
|
138
|
+
const minLevel = getPermissionLevel(minPermission);
|
|
139
|
+
return authorLevel <= minLevel;
|
|
140
|
+
}
|
|
141
|
+
function isOwner(authorAssociation, isLocalMode = false) {
|
|
142
|
+
if (isLocalMode) return true;
|
|
143
|
+
return authorAssociation?.toUpperCase() === "OWNER";
|
|
144
|
+
}
|
|
145
|
+
function isMember(authorAssociation, isLocalMode = false) {
|
|
146
|
+
if (isLocalMode) return true;
|
|
147
|
+
return hasMinPermission(authorAssociation, "MEMBER", isLocalMode);
|
|
148
|
+
}
|
|
149
|
+
function isCollaborator(authorAssociation, isLocalMode = false) {
|
|
150
|
+
if (isLocalMode) return true;
|
|
151
|
+
return hasMinPermission(authorAssociation, "COLLABORATOR", isLocalMode);
|
|
152
|
+
}
|
|
153
|
+
function isContributor(authorAssociation, isLocalMode = false) {
|
|
154
|
+
if (isLocalMode) return true;
|
|
155
|
+
return hasMinPermission(authorAssociation, "CONTRIBUTOR", isLocalMode);
|
|
156
|
+
}
|
|
157
|
+
function isFirstTimer(authorAssociation, isLocalMode = false) {
|
|
158
|
+
if (isLocalMode) return false;
|
|
159
|
+
const assoc = authorAssociation?.toUpperCase();
|
|
160
|
+
return assoc === "FIRST_TIME_CONTRIBUTOR" || assoc === "FIRST_TIMER";
|
|
161
|
+
}
|
|
162
|
+
function createPermissionHelpers(authorAssociation, isLocalMode = false) {
|
|
163
|
+
return {
|
|
164
|
+
hasMinPermission: (minPermission) => hasMinPermission(authorAssociation, minPermission, isLocalMode),
|
|
165
|
+
isOwner: () => isOwner(authorAssociation, isLocalMode),
|
|
166
|
+
isMember: () => isMember(authorAssociation, isLocalMode),
|
|
167
|
+
isCollaborator: () => isCollaborator(authorAssociation, isLocalMode),
|
|
168
|
+
isContributor: () => isContributor(authorAssociation, isLocalMode),
|
|
169
|
+
isFirstTimer: () => isFirstTimer(authorAssociation, isLocalMode)
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
function detectLocalMode() {
|
|
173
|
+
return !process.env.GITHUB_ACTIONS;
|
|
174
|
+
}
|
|
175
|
+
function resolveAssociationFromEvent(eventContext, fallback) {
|
|
176
|
+
try {
|
|
177
|
+
const ec = eventContext || {};
|
|
178
|
+
return ec?.comment?.author_association || ec?.issue?.author_association || ec?.pull_request?.author_association || fallback;
|
|
179
|
+
} catch {
|
|
180
|
+
return fallback;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// src/memory-store.ts
|
|
185
|
+
init_logger();
|
|
186
|
+
import fs from "fs/promises";
|
|
187
|
+
import path from "path";
|
|
188
|
+
var MemoryStore = class _MemoryStore {
|
|
189
|
+
static instance;
|
|
190
|
+
data;
|
|
191
|
+
// namespace -> key -> value
|
|
192
|
+
config;
|
|
193
|
+
initialized = false;
|
|
194
|
+
constructor(config) {
|
|
195
|
+
this.data = /* @__PURE__ */ new Map();
|
|
196
|
+
this.config = this.normalizeConfig(config);
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Get singleton instance
|
|
200
|
+
*/
|
|
201
|
+
static getInstance(config) {
|
|
202
|
+
if (!_MemoryStore.instance) {
|
|
203
|
+
_MemoryStore.instance = new _MemoryStore(config);
|
|
204
|
+
} else if (config && !_MemoryStore.instance.initialized) {
|
|
205
|
+
_MemoryStore.instance.config = _MemoryStore.instance.normalizeConfig(config);
|
|
206
|
+
}
|
|
207
|
+
return _MemoryStore.instance;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Reset singleton instance (for testing)
|
|
211
|
+
*/
|
|
212
|
+
static resetInstance() {
|
|
213
|
+
_MemoryStore.instance = void 0;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Initialize memory store (load from file if configured)
|
|
217
|
+
*/
|
|
218
|
+
async initialize() {
|
|
219
|
+
if (this.initialized) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
if (this.config.storage === "file" && this.config.auto_load && this.config.file) {
|
|
223
|
+
try {
|
|
224
|
+
await this.load();
|
|
225
|
+
logger.debug(`Memory store loaded from ${this.config.file}`);
|
|
226
|
+
} catch (error) {
|
|
227
|
+
if (error.code !== "ENOENT") {
|
|
228
|
+
logger.warn(
|
|
229
|
+
`Failed to load memory store from ${this.config.file}: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
this.initialized = true;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Normalize and apply defaults to config
|
|
238
|
+
*/
|
|
239
|
+
normalizeConfig(config) {
|
|
240
|
+
const storage = config?.storage || "memory";
|
|
241
|
+
return {
|
|
242
|
+
storage,
|
|
243
|
+
format: config?.format || "json",
|
|
244
|
+
file: config?.file,
|
|
245
|
+
namespace: config?.namespace || "default",
|
|
246
|
+
auto_load: config?.auto_load !== false,
|
|
247
|
+
auto_save: config?.auto_save !== false
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Get the default namespace
|
|
252
|
+
*/
|
|
253
|
+
getDefaultNamespace() {
|
|
254
|
+
return this.config.namespace || "default";
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Get a value from memory
|
|
258
|
+
*/
|
|
259
|
+
get(key, namespace) {
|
|
260
|
+
const ns = namespace || this.getDefaultNamespace();
|
|
261
|
+
const nsData = this.data.get(ns);
|
|
262
|
+
return nsData?.get(key);
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Check if a key exists in memory
|
|
266
|
+
*/
|
|
267
|
+
has(key, namespace) {
|
|
268
|
+
const ns = namespace || this.getDefaultNamespace();
|
|
269
|
+
const nsData = this.data.get(ns);
|
|
270
|
+
return nsData?.has(key) || false;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Set a value in memory (override existing)
|
|
274
|
+
*/
|
|
275
|
+
async set(key, value, namespace) {
|
|
276
|
+
const ns = namespace || this.getDefaultNamespace();
|
|
277
|
+
if (!this.data.has(ns)) {
|
|
278
|
+
this.data.set(ns, /* @__PURE__ */ new Map());
|
|
279
|
+
}
|
|
280
|
+
const nsData = this.data.get(ns);
|
|
281
|
+
nsData.set(key, value);
|
|
282
|
+
if (this.config.storage === "file" && this.config.auto_save) {
|
|
283
|
+
await this.save();
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Append a value to an array in memory
|
|
288
|
+
* If key doesn't exist, creates a new array
|
|
289
|
+
* If key exists but is not an array, converts it to an array
|
|
290
|
+
*/
|
|
291
|
+
async append(key, value, namespace) {
|
|
292
|
+
const ns = namespace || this.getDefaultNamespace();
|
|
293
|
+
const existing = this.get(key, ns);
|
|
294
|
+
let newValue;
|
|
295
|
+
if (existing === void 0) {
|
|
296
|
+
newValue = [value];
|
|
297
|
+
} else if (Array.isArray(existing)) {
|
|
298
|
+
newValue = [...existing, value];
|
|
299
|
+
} else {
|
|
300
|
+
newValue = [existing, value];
|
|
301
|
+
}
|
|
302
|
+
await this.set(key, newValue, ns);
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Increment a numeric value in memory
|
|
306
|
+
* If key doesn't exist, initializes to 0 before incrementing
|
|
307
|
+
* If key exists but is not a number, throws an error
|
|
308
|
+
*/
|
|
309
|
+
async increment(key, amount = 1, namespace) {
|
|
310
|
+
const ns = namespace || this.getDefaultNamespace();
|
|
311
|
+
const existing = this.get(key, ns);
|
|
312
|
+
let newValue;
|
|
313
|
+
if (existing === void 0 || existing === null) {
|
|
314
|
+
newValue = amount;
|
|
315
|
+
} else if (typeof existing === "number") {
|
|
316
|
+
newValue = existing + amount;
|
|
317
|
+
} else {
|
|
318
|
+
throw new Error(
|
|
319
|
+
`Cannot increment non-numeric value at key '${key}' (type: ${typeof existing})`
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
await this.set(key, newValue, ns);
|
|
323
|
+
return newValue;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Delete a key from memory
|
|
327
|
+
*/
|
|
328
|
+
async delete(key, namespace) {
|
|
329
|
+
const ns = namespace || this.getDefaultNamespace();
|
|
330
|
+
const nsData = this.data.get(ns);
|
|
331
|
+
if (!nsData) {
|
|
332
|
+
return false;
|
|
333
|
+
}
|
|
334
|
+
const deleted = nsData.delete(key);
|
|
335
|
+
if (deleted && this.config.storage === "file" && this.config.auto_save) {
|
|
336
|
+
await this.save();
|
|
337
|
+
}
|
|
338
|
+
return deleted;
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Clear all keys in a namespace (or all namespaces if none specified)
|
|
342
|
+
*/
|
|
343
|
+
async clear(namespace) {
|
|
344
|
+
if (namespace) {
|
|
345
|
+
this.data.delete(namespace);
|
|
346
|
+
} else {
|
|
347
|
+
this.data.clear();
|
|
348
|
+
}
|
|
349
|
+
if (this.config.storage === "file" && this.config.auto_save) {
|
|
350
|
+
await this.save();
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* List all keys in a namespace
|
|
355
|
+
*/
|
|
356
|
+
list(namespace) {
|
|
357
|
+
const ns = namespace || this.getDefaultNamespace();
|
|
358
|
+
const nsData = this.data.get(ns);
|
|
359
|
+
return nsData ? Array.from(nsData.keys()) : [];
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* List all namespaces
|
|
363
|
+
*/
|
|
364
|
+
listNamespaces() {
|
|
365
|
+
return Array.from(this.data.keys());
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Get all data in a namespace
|
|
369
|
+
*/
|
|
370
|
+
getAll(namespace) {
|
|
371
|
+
const ns = namespace || this.getDefaultNamespace();
|
|
372
|
+
const nsData = this.data.get(ns);
|
|
373
|
+
if (!nsData) {
|
|
374
|
+
return {};
|
|
375
|
+
}
|
|
376
|
+
const result = {};
|
|
377
|
+
for (const [key, value] of nsData.entries()) {
|
|
378
|
+
result[key] = value;
|
|
379
|
+
}
|
|
380
|
+
return result;
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Load data from file
|
|
384
|
+
*/
|
|
385
|
+
async load() {
|
|
386
|
+
if (!this.config.file) {
|
|
387
|
+
throw new Error("No file path configured for memory store");
|
|
388
|
+
}
|
|
389
|
+
const filePath = path.resolve(process.cwd(), this.config.file);
|
|
390
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
391
|
+
if (this.config.format === "json") {
|
|
392
|
+
await this.loadFromJson(content);
|
|
393
|
+
} else if (this.config.format === "csv") {
|
|
394
|
+
await this.loadFromCsv(content);
|
|
395
|
+
} else {
|
|
396
|
+
throw new Error(`Unsupported format: ${this.config.format}`);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Save data to file
|
|
401
|
+
*/
|
|
402
|
+
async save() {
|
|
403
|
+
if (!this.config.file) {
|
|
404
|
+
throw new Error("No file path configured for memory store");
|
|
405
|
+
}
|
|
406
|
+
const filePath = path.resolve(process.cwd(), this.config.file);
|
|
407
|
+
const dir = path.dirname(filePath);
|
|
408
|
+
await fs.mkdir(dir, { recursive: true });
|
|
409
|
+
let content;
|
|
410
|
+
if (this.config.format === "json") {
|
|
411
|
+
content = this.saveToJson();
|
|
412
|
+
} else if (this.config.format === "csv") {
|
|
413
|
+
content = this.saveToCsv();
|
|
414
|
+
} else {
|
|
415
|
+
throw new Error(`Unsupported format: ${this.config.format}`);
|
|
416
|
+
}
|
|
417
|
+
await fs.writeFile(filePath, content, "utf-8");
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Load data from JSON format
|
|
421
|
+
*/
|
|
422
|
+
async loadFromJson(content) {
|
|
423
|
+
const data = JSON.parse(content);
|
|
424
|
+
this.data.clear();
|
|
425
|
+
for (const [namespace, nsData] of Object.entries(data)) {
|
|
426
|
+
if (typeof nsData === "object" && nsData !== null && !Array.isArray(nsData)) {
|
|
427
|
+
const nsMap = /* @__PURE__ */ new Map();
|
|
428
|
+
for (const [key, value] of Object.entries(nsData)) {
|
|
429
|
+
nsMap.set(key, value);
|
|
430
|
+
}
|
|
431
|
+
this.data.set(namespace, nsMap);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Save data to JSON format
|
|
437
|
+
*/
|
|
438
|
+
saveToJson() {
|
|
439
|
+
const result = {};
|
|
440
|
+
for (const [namespace, nsData] of this.data.entries()) {
|
|
441
|
+
const nsObj = {};
|
|
442
|
+
for (const [key, value] of nsData.entries()) {
|
|
443
|
+
nsObj[key] = value;
|
|
444
|
+
}
|
|
445
|
+
result[namespace] = nsObj;
|
|
446
|
+
}
|
|
447
|
+
return JSON.stringify(result, null, 2);
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* Load data from CSV format
|
|
451
|
+
* CSV format: namespace,key,value,type
|
|
452
|
+
*/
|
|
453
|
+
async loadFromCsv(content) {
|
|
454
|
+
const lines = content.split("\n").filter((line) => line.trim());
|
|
455
|
+
let startIndex = 0;
|
|
456
|
+
if (lines[0]?.startsWith("namespace,")) {
|
|
457
|
+
startIndex = 1;
|
|
458
|
+
}
|
|
459
|
+
this.data.clear();
|
|
460
|
+
const arrays = /* @__PURE__ */ new Map();
|
|
461
|
+
for (let i = startIndex; i < lines.length; i++) {
|
|
462
|
+
const line = lines[i];
|
|
463
|
+
const parts = this.parseCsvLine(line);
|
|
464
|
+
if (parts.length < 3) {
|
|
465
|
+
logger.warn(`Invalid CSV line ${i + 1}: ${line}`);
|
|
466
|
+
continue;
|
|
467
|
+
}
|
|
468
|
+
const [namespace, key, valueStr, typeStr] = parts;
|
|
469
|
+
const value = this.parseCsvValue(valueStr, typeStr);
|
|
470
|
+
if (!this.data.has(namespace)) {
|
|
471
|
+
this.data.set(namespace, /* @__PURE__ */ new Map());
|
|
472
|
+
arrays.set(namespace, /* @__PURE__ */ new Map());
|
|
473
|
+
}
|
|
474
|
+
const nsData = this.data.get(namespace);
|
|
475
|
+
const nsArrays = arrays.get(namespace);
|
|
476
|
+
if (nsData.has(key)) {
|
|
477
|
+
if (!nsArrays.has(key)) {
|
|
478
|
+
const existingValue = nsData.get(key);
|
|
479
|
+
nsArrays.set(key, [existingValue]);
|
|
480
|
+
}
|
|
481
|
+
nsArrays.get(key).push(value);
|
|
482
|
+
nsData.set(key, nsArrays.get(key));
|
|
483
|
+
} else {
|
|
484
|
+
nsData.set(key, value);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Save data to CSV format
|
|
490
|
+
*/
|
|
491
|
+
saveToCsv() {
|
|
492
|
+
const lines = ["namespace,key,value,type"];
|
|
493
|
+
for (const [namespace, nsData] of this.data.entries()) {
|
|
494
|
+
for (const [key, value] of nsData.entries()) {
|
|
495
|
+
if (Array.isArray(value)) {
|
|
496
|
+
for (const item of value) {
|
|
497
|
+
lines.push(this.formatCsvLine(namespace, key, item));
|
|
498
|
+
}
|
|
499
|
+
} else {
|
|
500
|
+
lines.push(this.formatCsvLine(namespace, key, value));
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
return lines.join("\n") + "\n";
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Parse a CSV line, handling quoted values with commas
|
|
508
|
+
*/
|
|
509
|
+
parseCsvLine(line) {
|
|
510
|
+
const parts = [];
|
|
511
|
+
let current = "";
|
|
512
|
+
let inQuotes = false;
|
|
513
|
+
for (let i = 0; i < line.length; i++) {
|
|
514
|
+
const char = line[i];
|
|
515
|
+
if (char === '"') {
|
|
516
|
+
if (inQuotes && line[i + 1] === '"') {
|
|
517
|
+
current += '"';
|
|
518
|
+
i++;
|
|
519
|
+
} else {
|
|
520
|
+
inQuotes = !inQuotes;
|
|
521
|
+
}
|
|
522
|
+
} else if (char === "," && !inQuotes) {
|
|
523
|
+
parts.push(current);
|
|
524
|
+
current = "";
|
|
525
|
+
} else {
|
|
526
|
+
current += char;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
parts.push(current);
|
|
530
|
+
return parts;
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Format a CSV line with proper escaping
|
|
534
|
+
*/
|
|
535
|
+
formatCsvLine(namespace, key, value) {
|
|
536
|
+
const type = this.getValueType(value);
|
|
537
|
+
const valueStr = this.formatCsvValue(value);
|
|
538
|
+
return `${this.escapeCsv(namespace)},${this.escapeCsv(key)},${valueStr},${type}`;
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* Escape a CSV value
|
|
542
|
+
*/
|
|
543
|
+
escapeCsv(value) {
|
|
544
|
+
if (value.includes(",") || value.includes('"') || value.includes("\n")) {
|
|
545
|
+
return `"${value.replace(/"/g, '""')}"`;
|
|
546
|
+
}
|
|
547
|
+
return value;
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Format a value for CSV storage
|
|
551
|
+
*/
|
|
552
|
+
formatCsvValue(value) {
|
|
553
|
+
if (value === null) {
|
|
554
|
+
return '""';
|
|
555
|
+
}
|
|
556
|
+
if (value === void 0) {
|
|
557
|
+
return '""';
|
|
558
|
+
}
|
|
559
|
+
if (typeof value === "string") {
|
|
560
|
+
return this.escapeCsv(value);
|
|
561
|
+
}
|
|
562
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
563
|
+
return this.escapeCsv(String(value));
|
|
564
|
+
}
|
|
565
|
+
return this.escapeCsv(JSON.stringify(value));
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Parse a CSV value based on its type
|
|
569
|
+
*/
|
|
570
|
+
parseCsvValue(valueStr, typeStr) {
|
|
571
|
+
if (!typeStr || typeStr === "string") {
|
|
572
|
+
return valueStr;
|
|
573
|
+
}
|
|
574
|
+
if (typeStr === "number") {
|
|
575
|
+
return Number(valueStr);
|
|
576
|
+
}
|
|
577
|
+
if (typeStr === "boolean") {
|
|
578
|
+
return valueStr === "true";
|
|
579
|
+
}
|
|
580
|
+
if (typeStr === "object" || typeStr === "array") {
|
|
581
|
+
try {
|
|
582
|
+
return JSON.parse(valueStr);
|
|
583
|
+
} catch {
|
|
584
|
+
return valueStr;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
return valueStr;
|
|
588
|
+
}
|
|
589
|
+
/**
|
|
590
|
+
* Get the type of a value for CSV storage
|
|
591
|
+
*/
|
|
592
|
+
getValueType(value) {
|
|
593
|
+
if (value === null || value === void 0) {
|
|
594
|
+
return "string";
|
|
595
|
+
}
|
|
596
|
+
if (typeof value === "number") {
|
|
597
|
+
return "number";
|
|
598
|
+
}
|
|
599
|
+
if (typeof value === "boolean") {
|
|
600
|
+
return "boolean";
|
|
601
|
+
}
|
|
602
|
+
if (Array.isArray(value)) {
|
|
603
|
+
return "array";
|
|
604
|
+
}
|
|
605
|
+
if (typeof value === "object") {
|
|
606
|
+
return "object";
|
|
607
|
+
}
|
|
608
|
+
return "string";
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Get the current configuration
|
|
612
|
+
*/
|
|
613
|
+
getConfig() {
|
|
614
|
+
return { ...this.config };
|
|
615
|
+
}
|
|
616
|
+
};
|
|
617
|
+
|
|
618
|
+
// src/liquid-extensions.ts
|
|
619
|
+
var ReadFileTag = class extends Tag {
|
|
620
|
+
filepath;
|
|
621
|
+
constructor(token, remainTokens, liquid) {
|
|
622
|
+
super(token, remainTokens, liquid);
|
|
623
|
+
this.filepath = new Value(token.args, liquid);
|
|
624
|
+
}
|
|
625
|
+
*render(ctx, emitter) {
|
|
626
|
+
const filePath = yield this.filepath.value(ctx, false);
|
|
627
|
+
if (!filePath || typeof filePath !== "string") {
|
|
628
|
+
emitter.write("[Error: Invalid file path]");
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
const projectRoot = process.cwd();
|
|
632
|
+
const resolvedPath = path2.resolve(projectRoot, filePath.toString());
|
|
633
|
+
if (!resolvedPath.startsWith(projectRoot)) {
|
|
634
|
+
emitter.write("[Error: File path escapes project directory]");
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
try {
|
|
638
|
+
const content = yield fs2.readFile(resolvedPath, "utf-8");
|
|
639
|
+
emitter.write(content);
|
|
640
|
+
} catch (error) {
|
|
641
|
+
const errorMessage = error instanceof Error ? error.message : error?.code || "Unknown error";
|
|
642
|
+
emitter.write(`[Error reading file: ${errorMessage}]`);
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
};
|
|
646
|
+
var permissionsALS = new AsyncLocalStorage();
|
|
647
|
+
async function withPermissionsContext(ctx, fn) {
|
|
648
|
+
return await permissionsALS.run(ctx, fn);
|
|
649
|
+
}
|
|
650
|
+
function configureLiquidWithExtensions(liquid) {
|
|
651
|
+
liquid.registerTag("readfile", ReadFileTag);
|
|
652
|
+
liquid.registerFilter("parse_json", (value) => {
|
|
653
|
+
if (typeof value !== "string") {
|
|
654
|
+
return value;
|
|
655
|
+
}
|
|
656
|
+
try {
|
|
657
|
+
return JSON.parse(value);
|
|
658
|
+
} catch {
|
|
659
|
+
return value;
|
|
660
|
+
}
|
|
661
|
+
});
|
|
662
|
+
liquid.registerFilter("to_json", (value) => {
|
|
663
|
+
try {
|
|
664
|
+
return JSON.stringify(value);
|
|
665
|
+
} catch {
|
|
666
|
+
return "[Error: Unable to serialize to JSON]";
|
|
667
|
+
}
|
|
668
|
+
});
|
|
669
|
+
liquid.registerFilter("safe_label", (value) => {
|
|
670
|
+
if (value == null) return "";
|
|
671
|
+
const s = String(value);
|
|
672
|
+
return s.replace(/[^A-Za-z0-9:\/]/g, "").replace(/\/{2,}/g, "/");
|
|
673
|
+
});
|
|
674
|
+
liquid.registerFilter("safe_label_list", (value) => {
|
|
675
|
+
if (!Array.isArray(value)) return [];
|
|
676
|
+
return value.map((v) => v == null ? "" : String(v)).map((s) => s.replace(/[^A-Za-z0-9:\/]/g, "").replace(/\/{2,}/g, "/")).filter((s) => s.length > 0);
|
|
677
|
+
});
|
|
678
|
+
liquid.registerFilter("unescape_newlines", (value) => {
|
|
679
|
+
if (value == null) return "";
|
|
680
|
+
const s = String(value);
|
|
681
|
+
return s.replace(/\\n/g, "\n").replace(/\\r/g, "\r").replace(/\\t/g, " ");
|
|
682
|
+
});
|
|
683
|
+
const isLocal = detectLocalMode();
|
|
684
|
+
const resolveAssoc = (val) => {
|
|
685
|
+
if (typeof val === "string" && val.length > 0) return val;
|
|
686
|
+
const store = permissionsALS.getStore();
|
|
687
|
+
return store?.authorAssociation;
|
|
688
|
+
};
|
|
689
|
+
liquid.registerFilter("has_min_permission", (authorAssociation, level) => {
|
|
690
|
+
return hasMinPermission(resolveAssoc(authorAssociation), level, isLocal);
|
|
691
|
+
});
|
|
692
|
+
liquid.registerFilter("is_owner", (authorAssociation) => {
|
|
693
|
+
return isOwner(resolveAssoc(authorAssociation), isLocal);
|
|
694
|
+
});
|
|
695
|
+
liquid.registerFilter("is_member", (authorAssociation) => {
|
|
696
|
+
return isMember(resolveAssoc(authorAssociation), isLocal);
|
|
697
|
+
});
|
|
698
|
+
liquid.registerFilter("is_collaborator", (authorAssociation) => {
|
|
699
|
+
return isCollaborator(resolveAssoc(authorAssociation), isLocal);
|
|
700
|
+
});
|
|
701
|
+
liquid.registerFilter("is_contributor", (authorAssociation) => {
|
|
702
|
+
return isContributor(resolveAssoc(authorAssociation), isLocal);
|
|
703
|
+
});
|
|
704
|
+
liquid.registerFilter("is_first_timer", (authorAssociation) => {
|
|
705
|
+
return isFirstTimer(resolveAssoc(authorAssociation), isLocal);
|
|
706
|
+
});
|
|
707
|
+
const memoryStore = MemoryStore.getInstance();
|
|
708
|
+
liquid.registerFilter("memory_get", (key, namespace) => {
|
|
709
|
+
if (typeof key !== "string") {
|
|
710
|
+
return void 0;
|
|
711
|
+
}
|
|
712
|
+
return memoryStore.get(key, namespace);
|
|
713
|
+
});
|
|
714
|
+
liquid.registerFilter("memory_has", (key, namespace) => {
|
|
715
|
+
if (typeof key !== "string") {
|
|
716
|
+
return false;
|
|
717
|
+
}
|
|
718
|
+
return memoryStore.has(key, namespace);
|
|
719
|
+
});
|
|
720
|
+
liquid.registerFilter("memory_list", (namespace) => {
|
|
721
|
+
return memoryStore.list(namespace);
|
|
722
|
+
});
|
|
723
|
+
}
|
|
724
|
+
function createExtendedLiquid(options = {}) {
|
|
725
|
+
const liquid = new Liquid({
|
|
726
|
+
cache: false,
|
|
727
|
+
strictFilters: false,
|
|
728
|
+
strictVariables: false,
|
|
729
|
+
...options
|
|
730
|
+
});
|
|
731
|
+
configureLiquidWithExtensions(liquid);
|
|
732
|
+
return liquid;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
export {
|
|
736
|
+
logger,
|
|
737
|
+
logger_exports,
|
|
738
|
+
init_logger,
|
|
739
|
+
createPermissionHelpers,
|
|
740
|
+
detectLocalMode,
|
|
741
|
+
resolveAssociationFromEvent,
|
|
742
|
+
MemoryStore,
|
|
743
|
+
ReadFileTag,
|
|
744
|
+
withPermissionsContext,
|
|
745
|
+
configureLiquidWithExtensions,
|
|
746
|
+
createExtendedLiquid
|
|
747
|
+
};
|
|
748
|
+
//# sourceMappingURL=chunk-2U6BIWSY.mjs.map
|