@askexenow/exe-os 0.9.69 → 0.9.71
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/deploy/stack-manifests/v0.9.json +96 -16
- package/dist/bin/agentic-ontology-backfill.js +33 -0
- package/dist/bin/agentic-reflection-backfill.js +33 -0
- package/dist/bin/agentic-semantic-label.js +33 -0
- package/dist/bin/backfill-conversations.js +33 -0
- package/dist/bin/backfill-responses.js +33 -0
- package/dist/bin/backfill-vectors.js +33 -0
- package/dist/bin/bulk-sync-postgres.js +33 -0
- package/dist/bin/cleanup-stale-review-tasks.js +33 -0
- package/dist/bin/cli.js +1284 -178
- package/dist/bin/exe-agent.js +6 -0
- package/dist/bin/exe-assign.js +33 -0
- package/dist/bin/exe-boot.js +33 -0
- package/dist/bin/exe-call.js +6 -0
- package/dist/bin/exe-cloud.js +33 -0
- package/dist/bin/exe-dispatch.js +33 -0
- package/dist/bin/exe-doctor.js +33 -0
- package/dist/bin/exe-export-behaviors.js +33 -0
- package/dist/bin/exe-forget.js +33 -0
- package/dist/bin/exe-gateway.js +178 -110
- package/dist/bin/exe-heartbeat.js +33 -0
- package/dist/bin/exe-kill.js +33 -0
- package/dist/bin/exe-launch-agent.js +33 -0
- package/dist/bin/exe-new-employee.js +6 -0
- package/dist/bin/exe-pending-messages.js +33 -0
- package/dist/bin/exe-pending-notifications.js +33 -0
- package/dist/bin/exe-pending-reviews.js +33 -0
- package/dist/bin/exe-rename.js +40 -4
- package/dist/bin/exe-review.js +33 -0
- package/dist/bin/exe-search.js +33 -0
- package/dist/bin/exe-session-cleanup.js +33 -0
- package/dist/bin/exe-start-codex.js +33 -0
- package/dist/bin/exe-start-opencode.js +33 -0
- package/dist/bin/exe-status.js +33 -0
- package/dist/bin/exe-team.js +33 -0
- package/dist/bin/git-sweep.js +33 -0
- package/dist/bin/graph-backfill.js +177 -110
- package/dist/bin/graph-export.js +33 -0
- package/dist/bin/intercom-check.js +33 -0
- package/dist/bin/registry-proxy.js +207 -0
- package/dist/bin/scan-tasks.js +33 -0
- package/dist/bin/setup.js +33 -0
- package/dist/bin/shard-migrate.js +33 -0
- package/dist/bin/stack-update.js +128 -0
- package/dist/gateway/index.js +178 -110
- package/dist/hooks/bug-report-worker.js +33 -0
- package/dist/hooks/codex-stop-task-finalizer.js +33 -0
- package/dist/hooks/commit-complete.js +33 -0
- package/dist/hooks/error-recall.js +33 -0
- package/dist/hooks/ingest.js +33 -0
- package/dist/hooks/instructions-loaded.js +33 -0
- package/dist/hooks/notification.js +33 -0
- package/dist/hooks/post-compact.js +33 -0
- package/dist/hooks/post-tool-combined.js +698 -17
- package/dist/hooks/pre-compact.js +33 -0
- package/dist/hooks/pre-tool-use.js +33 -0
- package/dist/hooks/prompt-submit.js +314 -0
- package/dist/hooks/session-end.js +33 -0
- package/dist/hooks/session-start.js +33 -0
- package/dist/hooks/stop.js +279 -12
- package/dist/hooks/subagent-stop.js +33 -0
- package/dist/hooks/summary-worker.js +33 -0
- package/dist/index.js +178 -110
- package/dist/lib/cloud-sync.js +27 -0
- package/dist/lib/database.js +27 -0
- package/dist/lib/db.js +27 -0
- package/dist/lib/device-registry.js +27 -0
- package/dist/lib/employee-templates.js +6 -0
- package/dist/lib/exe-daemon.js +639 -259
- package/dist/lib/hybrid-search.js +33 -0
- package/dist/lib/registry-proxy.js +162 -0
- package/dist/lib/schedules.js +33 -0
- package/dist/lib/store.js +33 -0
- package/dist/mcp/server.js +561 -244
- package/dist/runtime/index.js +33 -0
- package/dist/tui/App.js +33 -0
- package/package.json +3 -2
- package/stack.release.json +6 -4
- package/stack.release.schema.json +89 -18
|
@@ -2222,6 +2222,33 @@ async function ensureSchema() {
|
|
|
2222
2222
|
CREATE INDEX IF NOT EXISTS idx_chat_history_session
|
|
2223
2223
|
ON chat_history(session_id, id);
|
|
2224
2224
|
`);
|
|
2225
|
+
await client.executeMultiple(`
|
|
2226
|
+
CREATE TABLE IF NOT EXISTS session_events (
|
|
2227
|
+
id TEXT PRIMARY KEY,
|
|
2228
|
+
agent_id TEXT NOT NULL,
|
|
2229
|
+
agent_role TEXT NOT NULL,
|
|
2230
|
+
session_id TEXT NOT NULL,
|
|
2231
|
+
session_scope TEXT,
|
|
2232
|
+
project_name TEXT NOT NULL,
|
|
2233
|
+
event_index INTEGER NOT NULL,
|
|
2234
|
+
event_type TEXT NOT NULL,
|
|
2235
|
+
tool_name TEXT,
|
|
2236
|
+
tool_use_id TEXT,
|
|
2237
|
+
content TEXT NOT NULL,
|
|
2238
|
+
payload_json TEXT,
|
|
2239
|
+
has_error INTEGER NOT NULL DEFAULT 0,
|
|
2240
|
+
created_at TEXT NOT NULL
|
|
2241
|
+
);
|
|
2242
|
+
|
|
2243
|
+
CREATE INDEX IF NOT EXISTS idx_session_events_agent_time
|
|
2244
|
+
ON session_events(agent_id, created_at DESC);
|
|
2245
|
+
|
|
2246
|
+
CREATE INDEX IF NOT EXISTS idx_session_events_session_index
|
|
2247
|
+
ON session_events(session_id, event_index);
|
|
2248
|
+
|
|
2249
|
+
CREATE INDEX IF NOT EXISTS idx_session_events_scope_agent_time
|
|
2250
|
+
ON session_events(session_scope, agent_id, created_at DESC);
|
|
2251
|
+
`);
|
|
2225
2252
|
await client.executeMultiple(`
|
|
2226
2253
|
CREATE TABLE IF NOT EXISTS workspaces (
|
|
2227
2254
|
id TEXT PRIMARY KEY,
|
|
@@ -3353,6 +3380,12 @@ var init_platform_procedures = __esm({
|
|
|
3353
3380
|
priority: "p0",
|
|
3354
3381
|
content: "exe-build-adv is MANDATORY for ALL work touching 3+ files. Run /exe-build-adv --auto BEFORE implementation. Pipeline: Spec \u2192 AC \u2192 Tests \u2192 Evaluate \u2192 Fix. No multi-file feature ships without pipeline artifacts. No exceptions \u2014 managers reject work without them."
|
|
3355
3382
|
},
|
|
3383
|
+
{
|
|
3384
|
+
title: "Code context first for repository orientation",
|
|
3385
|
+
domain: "workflow",
|
|
3386
|
+
priority: "p1",
|
|
3387
|
+
content: "Before broad repo exploration, symbol tracing, blast-radius review, or codebase Q&A, agents should use the consolidated code_context MCP tool instead of manual grep/read loops. Use action=index or stats to refresh/check the index; action=search with query, limit, offset, languages, paths, refresh_index for fresh multi-language code/doc search; action=trace for symbol imports/dependents; action=blast_radius for impact analysis before edits. CLI parity exists via exe-os code-context init|index|status|stats|search|doctor. Keep code_context separate from durable employee memory: promote only validated decisions, procedures, or lessons into store_memory/commit_memory."
|
|
3388
|
+
},
|
|
3356
3389
|
{
|
|
3357
3390
|
title: "Commit discipline \u2014 never leave verified work floating",
|
|
3358
3391
|
domain: "workflow",
|
|
@@ -4662,13 +4695,75 @@ import crypto2 from "crypto";
|
|
|
4662
4695
|
|
|
4663
4696
|
// src/lib/code-chunker.ts
|
|
4664
4697
|
import ts from "typescript";
|
|
4698
|
+
var LANGUAGE_BY_EXTENSION = {
|
|
4699
|
+
c: "c",
|
|
4700
|
+
cc: "cpp",
|
|
4701
|
+
cpp: "cpp",
|
|
4702
|
+
cxx: "cpp",
|
|
4703
|
+
h: "c",
|
|
4704
|
+
hh: "cpp",
|
|
4705
|
+
hpp: "cpp",
|
|
4706
|
+
cs: "csharp",
|
|
4707
|
+
css: "css",
|
|
4708
|
+
scss: "scss",
|
|
4709
|
+
f: "fortran",
|
|
4710
|
+
f90: "fortran",
|
|
4711
|
+
f95: "fortran",
|
|
4712
|
+
go: "go",
|
|
4713
|
+
html: "html",
|
|
4714
|
+
htm: "html",
|
|
4715
|
+
java: "java",
|
|
4716
|
+
js: "javascript",
|
|
4717
|
+
jsx: "javascript",
|
|
4718
|
+
json: "json",
|
|
4719
|
+
kt: "kotlin",
|
|
4720
|
+
kts: "kotlin",
|
|
4721
|
+
lua: "lua",
|
|
4722
|
+
md: "markdown",
|
|
4723
|
+
mdx: "mdx",
|
|
4724
|
+
pas: "pascal",
|
|
4725
|
+
php: "php",
|
|
4726
|
+
py: "python",
|
|
4727
|
+
r: "r",
|
|
4728
|
+
rb: "ruby",
|
|
4729
|
+
rs: "rust",
|
|
4730
|
+
scala: "scala",
|
|
4731
|
+
sc: "scala",
|
|
4732
|
+
sol: "solidity",
|
|
4733
|
+
sql: "sql",
|
|
4734
|
+
svelte: "svelte",
|
|
4735
|
+
swift: "swift",
|
|
4736
|
+
toml: "toml",
|
|
4737
|
+
ts: "typescript",
|
|
4738
|
+
tsx: "typescript",
|
|
4739
|
+
vue: "vue",
|
|
4740
|
+
xml: "xml",
|
|
4741
|
+
yaml: "yaml",
|
|
4742
|
+
yml: "yaml",
|
|
4743
|
+
sh: "shell",
|
|
4744
|
+
bash: "shell",
|
|
4745
|
+
zsh: "shell"
|
|
4746
|
+
};
|
|
4747
|
+
var TEXT_LIKE_LANGUAGES = /* @__PURE__ */ new Set(["json", "markdown", "mdx", "toml", "yaml", "xml", "html", "css", "scss", "sql"]);
|
|
4748
|
+
function languageForFile(filePath) {
|
|
4749
|
+
const base = filePath.split(/[\\/]/).pop()?.toLowerCase() ?? "";
|
|
4750
|
+
if (["dockerfile", "makefile", "rakefile", "gemfile"].includes(base)) return base;
|
|
4751
|
+
const ext = base.includes(".") ? base.split(".").pop() : void 0;
|
|
4752
|
+
return ext ? LANGUAGE_BY_EXTENSION[ext] : void 0;
|
|
4753
|
+
}
|
|
4665
4754
|
function chunkSourceFile(source, fileName = "file.ts") {
|
|
4755
|
+
const language = languageForFile(fileName);
|
|
4756
|
+
if (language === "typescript" || language === "javascript") {
|
|
4757
|
+
return chunkTypeScriptLike(source, fileName);
|
|
4758
|
+
}
|
|
4759
|
+
return chunkGenericSource(source, fileName, language);
|
|
4760
|
+
}
|
|
4761
|
+
function chunkTypeScriptLike(source, fileName) {
|
|
4666
4762
|
const sourceFile = ts.createSourceFile(
|
|
4667
4763
|
fileName,
|
|
4668
4764
|
source,
|
|
4669
4765
|
ts.ScriptTarget.Latest,
|
|
4670
4766
|
true,
|
|
4671
|
-
// setParentNodes
|
|
4672
4767
|
fileName.endsWith(".tsx") || fileName.endsWith(".jsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS
|
|
4673
4768
|
);
|
|
4674
4769
|
const chunks = [];
|
|
@@ -4690,149 +4785,121 @@ function chunkSourceFile(source, fileName = "file.ts") {
|
|
|
4690
4785
|
if (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node)) {
|
|
4691
4786
|
return node.name?.getText(sourceFile) ?? "(anonymous)";
|
|
4692
4787
|
}
|
|
4693
|
-
if (ts.isClassDeclaration(node))
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
if (ts.
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
if (ts.isTypeAliasDeclaration(node)) {
|
|
4700
|
-
return node.name.getText(sourceFile);
|
|
4701
|
-
}
|
|
4702
|
-
if (ts.isEnumDeclaration(node)) {
|
|
4703
|
-
return node.name.getText(sourceFile);
|
|
4704
|
-
}
|
|
4705
|
-
if (ts.isVariableStatement(node)) {
|
|
4706
|
-
const decls = node.declarationList.declarations;
|
|
4707
|
-
return decls.map((d) => d.name.getText(sourceFile)).join(", ");
|
|
4708
|
-
}
|
|
4709
|
-
if (ts.isExportAssignment(node)) {
|
|
4710
|
-
return "default export";
|
|
4711
|
-
}
|
|
4788
|
+
if (ts.isClassDeclaration(node)) return node.name?.getText(sourceFile) ?? "(anonymous class)";
|
|
4789
|
+
if (ts.isInterfaceDeclaration(node)) return node.name.getText(sourceFile);
|
|
4790
|
+
if (ts.isTypeAliasDeclaration(node)) return node.name.getText(sourceFile);
|
|
4791
|
+
if (ts.isEnumDeclaration(node)) return node.name.getText(sourceFile);
|
|
4792
|
+
if (ts.isVariableStatement(node)) return node.declarationList.declarations.map((d) => d.name.getText(sourceFile)).join(", ");
|
|
4793
|
+
if (ts.isExportAssignment(node)) return "default export";
|
|
4712
4794
|
return "(unknown)";
|
|
4713
4795
|
}
|
|
4714
4796
|
function visitTopLevel(node) {
|
|
4715
4797
|
if (ts.isImportDeclaration(node)) {
|
|
4716
|
-
importLines.push({
|
|
4717
|
-
start: getLineNumber(node.getStart(sourceFile)),
|
|
4718
|
-
end: getLineNumber(node.getEnd())
|
|
4719
|
-
});
|
|
4798
|
+
importLines.push({ start: getLineNumber(node.getStart(sourceFile)), end: getLineNumber(node.getEnd()) });
|
|
4720
4799
|
return;
|
|
4721
4800
|
}
|
|
4722
4801
|
if (ts.isFunctionDeclaration(node)) {
|
|
4723
|
-
chunks.push({
|
|
4724
|
-
kind: "function",
|
|
4725
|
-
name: getName(node),
|
|
4726
|
-
text: getNodeText(node),
|
|
4727
|
-
startLine: getLineNumber(node.getStart(sourceFile)),
|
|
4728
|
-
endLine: getLineNumber(node.getEnd()),
|
|
4729
|
-
comment: getLeadingComment(node)
|
|
4730
|
-
});
|
|
4802
|
+
chunks.push({ kind: "function", name: getName(node), text: getNodeText(node), startLine: getLineNumber(node.getStart(sourceFile)), endLine: getLineNumber(node.getEnd()), comment: getLeadingComment(node) });
|
|
4731
4803
|
return;
|
|
4732
4804
|
}
|
|
4733
4805
|
if (ts.isClassDeclaration(node)) {
|
|
4734
|
-
chunks.push({
|
|
4735
|
-
kind: "class",
|
|
4736
|
-
name: getName(node),
|
|
4737
|
-
text: getNodeText(node),
|
|
4738
|
-
startLine: getLineNumber(node.getStart(sourceFile)),
|
|
4739
|
-
endLine: getLineNumber(node.getEnd()),
|
|
4740
|
-
comment: getLeadingComment(node)
|
|
4741
|
-
});
|
|
4806
|
+
chunks.push({ kind: "class", name: getName(node), text: getNodeText(node), startLine: getLineNumber(node.getStart(sourceFile)), endLine: getLineNumber(node.getEnd()), comment: getLeadingComment(node) });
|
|
4742
4807
|
return;
|
|
4743
4808
|
}
|
|
4744
|
-
if (ts.isInterfaceDeclaration(node)) {
|
|
4745
|
-
chunks.push({
|
|
4746
|
-
kind: "type",
|
|
4747
|
-
name: getName(node),
|
|
4748
|
-
text: getNodeText(node),
|
|
4749
|
-
startLine: getLineNumber(node.getStart(sourceFile)),
|
|
4750
|
-
endLine: getLineNumber(node.getEnd()),
|
|
4751
|
-
comment: getLeadingComment(node)
|
|
4752
|
-
});
|
|
4753
|
-
return;
|
|
4754
|
-
}
|
|
4755
|
-
if (ts.isTypeAliasDeclaration(node)) {
|
|
4756
|
-
chunks.push({
|
|
4757
|
-
kind: "type",
|
|
4758
|
-
name: getName(node),
|
|
4759
|
-
text: getNodeText(node),
|
|
4760
|
-
startLine: getLineNumber(node.getStart(sourceFile)),
|
|
4761
|
-
endLine: getLineNumber(node.getEnd()),
|
|
4762
|
-
comment: getLeadingComment(node)
|
|
4763
|
-
});
|
|
4764
|
-
return;
|
|
4765
|
-
}
|
|
4766
|
-
if (ts.isEnumDeclaration(node)) {
|
|
4767
|
-
chunks.push({
|
|
4768
|
-
kind: "type",
|
|
4769
|
-
name: getName(node),
|
|
4770
|
-
text: getNodeText(node),
|
|
4771
|
-
startLine: getLineNumber(node.getStart(sourceFile)),
|
|
4772
|
-
endLine: getLineNumber(node.getEnd()),
|
|
4773
|
-
comment: getLeadingComment(node)
|
|
4774
|
-
});
|
|
4809
|
+
if (ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node) || ts.isEnumDeclaration(node)) {
|
|
4810
|
+
chunks.push({ kind: "type", name: getName(node), text: getNodeText(node), startLine: getLineNumber(node.getStart(sourceFile)), endLine: getLineNumber(node.getEnd()), comment: getLeadingComment(node) });
|
|
4775
4811
|
return;
|
|
4776
4812
|
}
|
|
4777
4813
|
if (ts.isVariableStatement(node)) {
|
|
4778
|
-
const
|
|
4779
|
-
|
|
4780
|
-
(d) => d.initializer && (ts.isArrowFunction(d.initializer) || ts.isFunctionExpression(d.initializer))
|
|
4781
|
-
);
|
|
4782
|
-
chunks.push({
|
|
4783
|
-
kind: isFnLike ? "function" : "variable",
|
|
4784
|
-
name: getName(node),
|
|
4785
|
-
text: getNodeText(node),
|
|
4786
|
-
startLine: getLineNumber(node.getStart(sourceFile)),
|
|
4787
|
-
endLine: getLineNumber(node.getEnd()),
|
|
4788
|
-
comment: getLeadingComment(node)
|
|
4789
|
-
});
|
|
4814
|
+
const isFnLike = node.declarationList.declarations.some((d) => d.initializer && (ts.isArrowFunction(d.initializer) || ts.isFunctionExpression(d.initializer)));
|
|
4815
|
+
chunks.push({ kind: isFnLike ? "function" : "variable", name: getName(node), text: getNodeText(node), startLine: getLineNumber(node.getStart(sourceFile)), endLine: getLineNumber(node.getEnd()), comment: getLeadingComment(node) });
|
|
4790
4816
|
return;
|
|
4791
4817
|
}
|
|
4792
4818
|
if (ts.isExportAssignment(node)) {
|
|
4793
|
-
chunks.push({
|
|
4794
|
-
kind: "export",
|
|
4795
|
-
name: "default export",
|
|
4796
|
-
text: getNodeText(node),
|
|
4797
|
-
startLine: getLineNumber(node.getStart(sourceFile)),
|
|
4798
|
-
endLine: getLineNumber(node.getEnd()),
|
|
4799
|
-
comment: getLeadingComment(node)
|
|
4800
|
-
});
|
|
4819
|
+
chunks.push({ kind: "export", name: "default export", text: getNodeText(node), startLine: getLineNumber(node.getStart(sourceFile)), endLine: getLineNumber(node.getEnd()), comment: getLeadingComment(node) });
|
|
4801
4820
|
return;
|
|
4802
4821
|
}
|
|
4803
4822
|
if (ts.isExpressionStatement(node)) {
|
|
4804
4823
|
const text = getNodeText(node);
|
|
4805
|
-
if (text.length > 10) {
|
|
4806
|
-
chunks.push({
|
|
4807
|
-
kind: "other",
|
|
4808
|
-
name: text.slice(0, 40).replace(/\n/g, " "),
|
|
4809
|
-
text,
|
|
4810
|
-
startLine: getLineNumber(node.getStart(sourceFile)),
|
|
4811
|
-
endLine: getLineNumber(node.getEnd())
|
|
4812
|
-
});
|
|
4813
|
-
}
|
|
4814
|
-
return;
|
|
4824
|
+
if (text.length > 10) chunks.push({ kind: "other", name: text.slice(0, 40).replace(/\n/g, " "), text, startLine: getLineNumber(node.getStart(sourceFile)), endLine: getLineNumber(node.getEnd()) });
|
|
4815
4825
|
}
|
|
4816
4826
|
}
|
|
4817
4827
|
sourceFile.statements.forEach(visitTopLevel);
|
|
4818
4828
|
if (importLines.length > 0) {
|
|
4819
4829
|
const startLine = importLines[0].start;
|
|
4820
4830
|
const endLine = importLines[importLines.length - 1].end;
|
|
4821
|
-
|
|
4822
|
-
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
|
|
4831
|
+
chunks.unshift({ kind: "import", name: `${importLines.length} imports`, text: lines.slice(startLine - 1, endLine).join("\n"), startLine, endLine });
|
|
4832
|
+
}
|
|
4833
|
+
chunks.sort((a, b) => a.startLine - b.startLine);
|
|
4834
|
+
return chunks.length > 0 ? chunks : chunkByWindows(source, 80);
|
|
4835
|
+
}
|
|
4836
|
+
function chunkGenericSource(source, _fileName, language) {
|
|
4837
|
+
const lines = source.split("\n");
|
|
4838
|
+
if (source.trim().length === 0) return [];
|
|
4839
|
+
if (language && TEXT_LIKE_LANGUAGES.has(language)) return chunkTextLike(lines, language);
|
|
4840
|
+
const chunks = [];
|
|
4841
|
+
const patterns = [
|
|
4842
|
+
{ kind: "function", regex: /^\s*(?:async\s+)?def\s+([A-Za-z_][\w]*)\s*\(/, name: (m) => m[1] },
|
|
4843
|
+
{ kind: "class", regex: /^\s*class\s+([A-Za-z_][\w]*)\b/, name: (m) => m[1] },
|
|
4844
|
+
{ kind: "function", regex: /^\s*(?:pub\s+)?fn\s+([A-Za-z_][\w]*)\s*[<(]/, name: (m) => m[1] },
|
|
4845
|
+
{ kind: "class", regex: /^\s*(?:pub\s+)?(?:struct|enum|trait)\s+([A-Za-z_][\w]*)\b/, name: (m) => m[1] },
|
|
4846
|
+
{ kind: "function", regex: /^\s*func\s+(?:\([^)]*\)\s*)?([A-Za-z_][\w]*)\s*\(/, name: (m) => m[1] },
|
|
4847
|
+
{ kind: "function", regex: /^\s*(?:public|private|protected|static|final|suspend|fun|override|open|internal|export|async|func|function|subroutine)\s+.*?([A-Za-z_][\w]*)\s*\(/, name: (m) => m[1] },
|
|
4848
|
+
{ kind: "function", regex: /^\s*function\s+([A-Za-z_][\w]*)\s*\(/, name: (m) => m[1] },
|
|
4849
|
+
{ kind: "type", regex: /^\s*(?:interface|type|enum|record|data\s+class|case\s+class|contract|library)\s+([A-Za-z_][\w]*)\b/, name: (m) => m[1] },
|
|
4850
|
+
{ kind: "section", regex: /^\s{0,3}#{1,6}\s+(.+)$/, name: (m) => m[1].trim() }
|
|
4851
|
+
];
|
|
4852
|
+
const starts = [];
|
|
4853
|
+
for (let i = 0; i < lines.length; i++) {
|
|
4854
|
+
const line = lines[i];
|
|
4855
|
+
for (const pattern of patterns) {
|
|
4856
|
+
const match = line.match(pattern.regex);
|
|
4857
|
+
if (match) {
|
|
4858
|
+
starts.push({ line: i + 1, kind: pattern.kind, name: pattern.name(match) });
|
|
4859
|
+
break;
|
|
4860
|
+
}
|
|
4861
|
+
}
|
|
4862
|
+
}
|
|
4863
|
+
if (starts.length === 0) return chunkByWindows(source, 80);
|
|
4864
|
+
for (let i = 0; i < starts.length; i++) {
|
|
4865
|
+
const start = starts[i];
|
|
4866
|
+
const next = starts[i + 1]?.line ?? lines.length + 1;
|
|
4867
|
+
const endLine = Math.max(start.line, next - 1);
|
|
4868
|
+
chunks.push({
|
|
4869
|
+
kind: start.kind,
|
|
4870
|
+
name: start.name,
|
|
4871
|
+
text: lines.slice(start.line - 1, endLine).join("\n"),
|
|
4872
|
+
startLine: start.line,
|
|
4827
4873
|
endLine
|
|
4828
4874
|
});
|
|
4829
4875
|
}
|
|
4830
|
-
chunks
|
|
4876
|
+
return chunks;
|
|
4877
|
+
}
|
|
4878
|
+
function chunkTextLike(lines, language) {
|
|
4879
|
+
if (language === "markdown" || language === "mdx") {
|
|
4880
|
+
const starts = lines.map((line, i) => ({ line, i })).filter(({ line }) => /^\s{0,3}#{1,6}\s+/.test(line));
|
|
4881
|
+
if (starts.length > 0) {
|
|
4882
|
+
return starts.map((start, idx) => {
|
|
4883
|
+
const end = starts[idx + 1]?.i ?? lines.length;
|
|
4884
|
+
const title = start.line.replace(/^\s{0,3}#{1,6}\s+/, "").trim();
|
|
4885
|
+
return { kind: "section", name: title, text: lines.slice(start.i, end).join("\n"), startLine: start.i + 1, endLine: end };
|
|
4886
|
+
});
|
|
4887
|
+
}
|
|
4888
|
+
}
|
|
4889
|
+
return chunkByWindows(lines.join("\n"), 80);
|
|
4890
|
+
}
|
|
4891
|
+
function chunkByWindows(source, windowLines) {
|
|
4892
|
+
const lines = source.split("\n");
|
|
4893
|
+
const chunks = [];
|
|
4894
|
+
for (let i = 0; i < lines.length; i += windowLines) {
|
|
4895
|
+
const end = Math.min(lines.length, i + windowLines);
|
|
4896
|
+
const text = lines.slice(i, end).join("\n");
|
|
4897
|
+
if (text.trim()) chunks.push({ kind: "other", name: `lines ${i + 1}-${end}`, text, startLine: i + 1, endLine: end });
|
|
4898
|
+
}
|
|
4831
4899
|
return chunks;
|
|
4832
4900
|
}
|
|
4833
4901
|
function isChunkable(filePath) {
|
|
4834
|
-
|
|
4835
|
-
return ext === "ts" || ext === "tsx" || ext === "js" || ext === "jsx";
|
|
4902
|
+
return Boolean(languageForFile(filePath));
|
|
4836
4903
|
}
|
|
4837
4904
|
|
|
4838
4905
|
// src/lib/graph-rag.ts
|
package/dist/bin/graph-export.js
CHANGED
|
@@ -2437,6 +2437,33 @@ async function ensureSchema() {
|
|
|
2437
2437
|
CREATE INDEX IF NOT EXISTS idx_chat_history_session
|
|
2438
2438
|
ON chat_history(session_id, id);
|
|
2439
2439
|
`);
|
|
2440
|
+
await client.executeMultiple(`
|
|
2441
|
+
CREATE TABLE IF NOT EXISTS session_events (
|
|
2442
|
+
id TEXT PRIMARY KEY,
|
|
2443
|
+
agent_id TEXT NOT NULL,
|
|
2444
|
+
agent_role TEXT NOT NULL,
|
|
2445
|
+
session_id TEXT NOT NULL,
|
|
2446
|
+
session_scope TEXT,
|
|
2447
|
+
project_name TEXT NOT NULL,
|
|
2448
|
+
event_index INTEGER NOT NULL,
|
|
2449
|
+
event_type TEXT NOT NULL,
|
|
2450
|
+
tool_name TEXT,
|
|
2451
|
+
tool_use_id TEXT,
|
|
2452
|
+
content TEXT NOT NULL,
|
|
2453
|
+
payload_json TEXT,
|
|
2454
|
+
has_error INTEGER NOT NULL DEFAULT 0,
|
|
2455
|
+
created_at TEXT NOT NULL
|
|
2456
|
+
);
|
|
2457
|
+
|
|
2458
|
+
CREATE INDEX IF NOT EXISTS idx_session_events_agent_time
|
|
2459
|
+
ON session_events(agent_id, created_at DESC);
|
|
2460
|
+
|
|
2461
|
+
CREATE INDEX IF NOT EXISTS idx_session_events_session_index
|
|
2462
|
+
ON session_events(session_id, event_index);
|
|
2463
|
+
|
|
2464
|
+
CREATE INDEX IF NOT EXISTS idx_session_events_scope_agent_time
|
|
2465
|
+
ON session_events(session_scope, agent_id, created_at DESC);
|
|
2466
|
+
`);
|
|
2440
2467
|
await client.executeMultiple(`
|
|
2441
2468
|
CREATE TABLE IF NOT EXISTS workspaces (
|
|
2442
2469
|
id TEXT PRIMARY KEY,
|
|
@@ -4125,6 +4152,12 @@ var init_platform_procedures = __esm({
|
|
|
4125
4152
|
priority: "p0",
|
|
4126
4153
|
content: "exe-build-adv is MANDATORY for ALL work touching 3+ files. Run /exe-build-adv --auto BEFORE implementation. Pipeline: Spec \u2192 AC \u2192 Tests \u2192 Evaluate \u2192 Fix. No multi-file feature ships without pipeline artifacts. No exceptions \u2014 managers reject work without them."
|
|
4127
4154
|
},
|
|
4155
|
+
{
|
|
4156
|
+
title: "Code context first for repository orientation",
|
|
4157
|
+
domain: "workflow",
|
|
4158
|
+
priority: "p1",
|
|
4159
|
+
content: "Before broad repo exploration, symbol tracing, blast-radius review, or codebase Q&A, agents should use the consolidated code_context MCP tool instead of manual grep/read loops. Use action=index or stats to refresh/check the index; action=search with query, limit, offset, languages, paths, refresh_index for fresh multi-language code/doc search; action=trace for symbol imports/dependents; action=blast_radius for impact analysis before edits. CLI parity exists via exe-os code-context init|index|status|stats|search|doctor. Keep code_context separate from durable employee memory: promote only validated decisions, procedures, or lessons into store_memory/commit_memory."
|
|
4160
|
+
},
|
|
4128
4161
|
{
|
|
4129
4162
|
title: "Commit discipline \u2014 never leave verified work floating",
|
|
4130
4163
|
domain: "workflow",
|
|
@@ -2546,6 +2546,33 @@ async function ensureSchema() {
|
|
|
2546
2546
|
CREATE INDEX IF NOT EXISTS idx_chat_history_session
|
|
2547
2547
|
ON chat_history(session_id, id);
|
|
2548
2548
|
`);
|
|
2549
|
+
await client.executeMultiple(`
|
|
2550
|
+
CREATE TABLE IF NOT EXISTS session_events (
|
|
2551
|
+
id TEXT PRIMARY KEY,
|
|
2552
|
+
agent_id TEXT NOT NULL,
|
|
2553
|
+
agent_role TEXT NOT NULL,
|
|
2554
|
+
session_id TEXT NOT NULL,
|
|
2555
|
+
session_scope TEXT,
|
|
2556
|
+
project_name TEXT NOT NULL,
|
|
2557
|
+
event_index INTEGER NOT NULL,
|
|
2558
|
+
event_type TEXT NOT NULL,
|
|
2559
|
+
tool_name TEXT,
|
|
2560
|
+
tool_use_id TEXT,
|
|
2561
|
+
content TEXT NOT NULL,
|
|
2562
|
+
payload_json TEXT,
|
|
2563
|
+
has_error INTEGER NOT NULL DEFAULT 0,
|
|
2564
|
+
created_at TEXT NOT NULL
|
|
2565
|
+
);
|
|
2566
|
+
|
|
2567
|
+
CREATE INDEX IF NOT EXISTS idx_session_events_agent_time
|
|
2568
|
+
ON session_events(agent_id, created_at DESC);
|
|
2569
|
+
|
|
2570
|
+
CREATE INDEX IF NOT EXISTS idx_session_events_session_index
|
|
2571
|
+
ON session_events(session_id, event_index);
|
|
2572
|
+
|
|
2573
|
+
CREATE INDEX IF NOT EXISTS idx_session_events_scope_agent_time
|
|
2574
|
+
ON session_events(session_scope, agent_id, created_at DESC);
|
|
2575
|
+
`);
|
|
2549
2576
|
await client.executeMultiple(`
|
|
2550
2577
|
CREATE TABLE IF NOT EXISTS workspaces (
|
|
2551
2578
|
id TEXT PRIMARY KEY,
|
|
@@ -4234,6 +4261,12 @@ var init_platform_procedures = __esm({
|
|
|
4234
4261
|
priority: "p0",
|
|
4235
4262
|
content: "exe-build-adv is MANDATORY for ALL work touching 3+ files. Run /exe-build-adv --auto BEFORE implementation. Pipeline: Spec \u2192 AC \u2192 Tests \u2192 Evaluate \u2192 Fix. No multi-file feature ships without pipeline artifacts. No exceptions \u2014 managers reject work without them."
|
|
4236
4263
|
},
|
|
4264
|
+
{
|
|
4265
|
+
title: "Code context first for repository orientation",
|
|
4266
|
+
domain: "workflow",
|
|
4267
|
+
priority: "p1",
|
|
4268
|
+
content: "Before broad repo exploration, symbol tracing, blast-radius review, or codebase Q&A, agents should use the consolidated code_context MCP tool instead of manual grep/read loops. Use action=index or stats to refresh/check the index; action=search with query, limit, offset, languages, paths, refresh_index for fresh multi-language code/doc search; action=trace for symbol imports/dependents; action=blast_radius for impact analysis before edits. CLI parity exists via exe-os code-context init|index|status|stats|search|doctor. Keep code_context separate from durable employee memory: promote only validated decisions, procedures, or lessons into store_memory/commit_memory."
|
|
4269
|
+
},
|
|
4237
4270
|
{
|
|
4238
4271
|
title: "Commit discipline \u2014 never leave verified work floating",
|
|
4239
4272
|
domain: "workflow",
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/lib/is-main.ts
|
|
4
|
+
import { realpathSync } from "fs";
|
|
5
|
+
import { fileURLToPath } from "url";
|
|
6
|
+
function isMainModule(importMetaUrl) {
|
|
7
|
+
if (process.argv[1] == null) return false;
|
|
8
|
+
if (process.argv[1].includes("mcp/server")) return false;
|
|
9
|
+
try {
|
|
10
|
+
const scriptPath = realpathSync(process.argv[1]);
|
|
11
|
+
const modulePath = realpathSync(fileURLToPath(importMetaUrl));
|
|
12
|
+
return scriptPath === modulePath;
|
|
13
|
+
} catch {
|
|
14
|
+
return importMetaUrl === `file://${process.argv[1]}` || importMetaUrl === new URL(process.argv[1], "file://").href;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// src/lib/registry-proxy.ts
|
|
19
|
+
import { createServer } from "http";
|
|
20
|
+
import { Readable } from "stream";
|
|
21
|
+
function parsePullTokens(raw) {
|
|
22
|
+
return (raw ?? "").split(/[\n,]/).map((s) => s.trim()).filter(Boolean);
|
|
23
|
+
}
|
|
24
|
+
function registryProxyOptionsFromEnv(env = process.env) {
|
|
25
|
+
const upstreamToken = env.EXE_REGISTRY_PROXY_UPSTREAM_TOKEN || env.GHCR_TOKEN || "";
|
|
26
|
+
const pullTokens = parsePullTokens(env.EXE_REGISTRY_PROXY_PULL_TOKENS);
|
|
27
|
+
return {
|
|
28
|
+
port: Number(env.EXE_REGISTRY_PROXY_PORT || 3201),
|
|
29
|
+
host: env.EXE_REGISTRY_PROXY_HOST || "0.0.0.0",
|
|
30
|
+
upstream: env.EXE_REGISTRY_PROXY_UPSTREAM || "https://ghcr.io",
|
|
31
|
+
upstreamUsername: env.EXE_REGISTRY_PROXY_UPSTREAM_USERNAME || env.GHCR_USERNAME || "askexe",
|
|
32
|
+
upstreamToken,
|
|
33
|
+
pullTokens,
|
|
34
|
+
allowedNamespace: env.EXE_REGISTRY_PROXY_ALLOWED_NAMESPACE || "askexe"
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function assertRegistryProxyConfig(options) {
|
|
38
|
+
if (!options.upstreamToken) throw new Error("EXE_REGISTRY_PROXY_UPSTREAM_TOKEN or GHCR_TOKEN is required");
|
|
39
|
+
if (options.pullTokens.length === 0) throw new Error("EXE_REGISTRY_PROXY_PULL_TOKENS is required");
|
|
40
|
+
if (!options.allowedNamespace || !/^[a-z0-9._-]+$/i.test(options.allowedNamespace)) {
|
|
41
|
+
throw new Error("EXE_REGISTRY_PROXY_ALLOWED_NAMESPACE must be a registry-safe namespace");
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function timingSafeIncludes(values, candidate) {
|
|
45
|
+
return values.some((value) => value === candidate);
|
|
46
|
+
}
|
|
47
|
+
function parseBasicAuth(header) {
|
|
48
|
+
if (!header?.startsWith("Basic ")) return null;
|
|
49
|
+
try {
|
|
50
|
+
const decoded = Buffer.from(header.slice("Basic ".length), "base64").toString("utf8");
|
|
51
|
+
const idx = decoded.indexOf(":");
|
|
52
|
+
if (idx < 0) return null;
|
|
53
|
+
return { username: decoded.slice(0, idx), password: decoded.slice(idx + 1) };
|
|
54
|
+
} catch {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function unauthorized(res) {
|
|
59
|
+
res.writeHead(401, {
|
|
60
|
+
"www-authenticate": 'Basic realm="AskExe Registry Proxy"',
|
|
61
|
+
"content-type": "application/json"
|
|
62
|
+
});
|
|
63
|
+
res.end(JSON.stringify({ error: "registry proxy authentication required" }));
|
|
64
|
+
}
|
|
65
|
+
function isAllowedPath(pathname, namespace) {
|
|
66
|
+
if (pathname === "/health") return true;
|
|
67
|
+
if (pathname === "/v2/" || pathname === "/v2") return true;
|
|
68
|
+
const prefix = `/v2/${namespace}/`;
|
|
69
|
+
if (!pathname.startsWith(prefix)) return false;
|
|
70
|
+
if (pathname.includes("..") || /%2f/i.test(pathname)) return false;
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
function parseBearerChallenge(header) {
|
|
74
|
+
if (!header?.toLowerCase().startsWith("bearer ")) return null;
|
|
75
|
+
const raw = header.slice("Bearer ".length);
|
|
76
|
+
const params = new URLSearchParams();
|
|
77
|
+
for (const part of raw.match(/(?:[^,"]+|"[^"]*")+/g) ?? []) {
|
|
78
|
+
const idx = part.indexOf("=");
|
|
79
|
+
if (idx < 0) continue;
|
|
80
|
+
const key = part.slice(0, idx).trim();
|
|
81
|
+
const value = part.slice(idx + 1).trim().replace(/^"|"$/g, "");
|
|
82
|
+
params.set(key, value);
|
|
83
|
+
}
|
|
84
|
+
const realm = params.get("realm");
|
|
85
|
+
if (!realm) return null;
|
|
86
|
+
params.delete("realm");
|
|
87
|
+
return { realm, params };
|
|
88
|
+
}
|
|
89
|
+
async function fetchUpstreamWithRegistryAuth(url, init, upstreamBasicAuth) {
|
|
90
|
+
const firstHeaders = new Headers(init.headers);
|
|
91
|
+
firstHeaders.set("authorization", `Basic ${upstreamBasicAuth}`);
|
|
92
|
+
const first = await fetch(url, { ...init, headers: firstHeaders });
|
|
93
|
+
if (first.status !== 401) return first;
|
|
94
|
+
const challenge = parseBearerChallenge(first.headers.get("www-authenticate"));
|
|
95
|
+
if (!challenge) return first;
|
|
96
|
+
const tokenUrl = new URL(challenge.realm);
|
|
97
|
+
for (const [key, value] of challenge.params.entries()) tokenUrl.searchParams.set(key, value);
|
|
98
|
+
const tokenRes = await fetch(tokenUrl, { headers: { authorization: `Basic ${upstreamBasicAuth}` } });
|
|
99
|
+
if (!tokenRes.ok) return first;
|
|
100
|
+
const tokenJson = await tokenRes.json();
|
|
101
|
+
const token = tokenJson.token ?? tokenJson.access_token;
|
|
102
|
+
if (!token) return first;
|
|
103
|
+
const retryHeaders = new Headers(init.headers);
|
|
104
|
+
retryHeaders.set("authorization", `Bearer ${token}`);
|
|
105
|
+
return fetch(url, { ...init, headers: retryHeaders });
|
|
106
|
+
}
|
|
107
|
+
function copyResponseHeaders(from, to) {
|
|
108
|
+
for (const [key, value] of from.entries()) {
|
|
109
|
+
const lower = key.toLowerCase();
|
|
110
|
+
if (["connection", "keep-alive", "transfer-encoding", "content-encoding"].includes(lower)) continue;
|
|
111
|
+
to.setHeader(key, value);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
function createRegistryProxyServer(options) {
|
|
115
|
+
assertRegistryProxyConfig(options);
|
|
116
|
+
const upstream = new URL(options.upstream ?? "https://ghcr.io");
|
|
117
|
+
const namespace = options.allowedNamespace ?? "askexe";
|
|
118
|
+
const upstreamAuth = Buffer.from(`${options.upstreamUsername ?? "askexe"}:${options.upstreamToken}`).toString("base64");
|
|
119
|
+
return createServer(async (req, res) => {
|
|
120
|
+
const requestUrl = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
|
|
121
|
+
if (requestUrl.pathname === "/health") {
|
|
122
|
+
res.writeHead(200, { "content-type": "application/json" });
|
|
123
|
+
res.end(JSON.stringify({ ok: true, service: "exe-registry-proxy", upstream: upstream.origin, namespace }));
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (!isAllowedPath(requestUrl.pathname, namespace)) {
|
|
127
|
+
res.writeHead(404, { "content-type": "application/json" });
|
|
128
|
+
res.end(JSON.stringify({ error: "registry path not allowed" }));
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const auth = parseBasicAuth(req.headers.authorization);
|
|
132
|
+
if (!auth || !timingSafeIncludes(options.pullTokens, auth.password)) {
|
|
133
|
+
unauthorized(res);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const upstreamUrl = new URL(requestUrl.pathname + requestUrl.search, upstream.origin);
|
|
137
|
+
const headers = new Headers();
|
|
138
|
+
for (const [key, value] of Object.entries(req.headers)) {
|
|
139
|
+
if (!value) continue;
|
|
140
|
+
const lower = key.toLowerCase();
|
|
141
|
+
if (["host", "connection", "authorization", "content-length"].includes(lower)) continue;
|
|
142
|
+
headers.set(key, Array.isArray(value) ? value.join(",") : value);
|
|
143
|
+
}
|
|
144
|
+
headers.set("authorization", `Basic ${upstreamAuth}`);
|
|
145
|
+
try {
|
|
146
|
+
const upstreamRes = await fetchUpstreamWithRegistryAuth(upstreamUrl, {
|
|
147
|
+
method: req.method,
|
|
148
|
+
headers,
|
|
149
|
+
body: req.method === "GET" || req.method === "HEAD" ? void 0 : req,
|
|
150
|
+
// Required by undici when streaming request bodies.
|
|
151
|
+
duplex: "half"
|
|
152
|
+
}, upstreamAuth);
|
|
153
|
+
res.statusCode = upstreamRes.status;
|
|
154
|
+
res.statusMessage = upstreamRes.statusText;
|
|
155
|
+
copyResponseHeaders(upstreamRes.headers, res);
|
|
156
|
+
if (!upstreamRes.body || req.method === "HEAD") {
|
|
157
|
+
res.end();
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
Readable.fromWeb(upstreamRes.body).pipe(res);
|
|
161
|
+
} catch (err) {
|
|
162
|
+
res.writeHead(502, { "content-type": "application/json" });
|
|
163
|
+
res.end(JSON.stringify({ error: "upstream registry proxy failed", detail: err instanceof Error ? err.message : String(err) }));
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
async function runRegistryProxy(options = registryProxyOptionsFromEnv()) {
|
|
168
|
+
const server = createRegistryProxyServer(options);
|
|
169
|
+
await new Promise((resolve) => server.listen(options.port, options.host, resolve));
|
|
170
|
+
console.log(`exe-registry-proxy listening on ${options.host ?? "0.0.0.0"}:${options.port}`);
|
|
171
|
+
console.log(`proxying /v2/${options.allowedNamespace ?? "askexe"}/* -> ${options.upstream ?? "https://ghcr.io"}`);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// src/bin/registry-proxy.ts
|
|
175
|
+
function printHelp() {
|
|
176
|
+
console.log(`exe-os registry-proxy \u2014 authenticated pull-through proxy for AskExe customer images
|
|
177
|
+
|
|
178
|
+
Environment:
|
|
179
|
+
EXE_REGISTRY_PROXY_PORT=3201
|
|
180
|
+
EXE_REGISTRY_PROXY_HOST=0.0.0.0
|
|
181
|
+
EXE_REGISTRY_PROXY_UPSTREAM=https://ghcr.io
|
|
182
|
+
EXE_REGISTRY_PROXY_UPSTREAM_USERNAME=<github-user>
|
|
183
|
+
EXE_REGISTRY_PROXY_UPSTREAM_TOKEN=<askexe-ghcr-read-token>
|
|
184
|
+
EXE_REGISTRY_PROXY_PULL_TOKENS=<customer-token-1,customer-token-2>
|
|
185
|
+
EXE_REGISTRY_PROXY_ALLOWED_NAMESPACE=askexe
|
|
186
|
+
|
|
187
|
+
Docker image shape for clients:
|
|
188
|
+
registry.askexe.com/askexe/exed:v0.9.3
|
|
189
|
+
registry.askexe.com/askexe/exe-crm:v0.9.3
|
|
190
|
+
`);
|
|
191
|
+
}
|
|
192
|
+
async function main(args = process.argv.slice(2)) {
|
|
193
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
194
|
+
printHelp();
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
await runRegistryProxy(registryProxyOptionsFromEnv());
|
|
198
|
+
}
|
|
199
|
+
if (isMainModule(import.meta.url)) {
|
|
200
|
+
main().catch((err) => {
|
|
201
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
202
|
+
process.exit(1);
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
export {
|
|
206
|
+
main
|
|
207
|
+
};
|