pi-apexlang 0.2.2 → 0.3.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 CHANGED
@@ -76,6 +76,11 @@ The registered `apexlang` tool supports:
76
76
  | `runtime_doctor` | Diagnoses runtime configuration. |
77
77
  | `runtime_validate` | Runs Oracle's live check gate, then offers an interactive check-only or same-session validate-and-import choice. |
78
78
 
79
+ `local_validate` preserves Oracle's complete validator and report semantics.
80
+ The extension accelerates its repeated block and nesting queries in a
81
+ process-local cache; the vendored Oracle skill remains unchanged and no checks
82
+ are skipped.
83
+
79
84
  The model cannot request import as a standalone action. Oracle's skill defaults
80
85
  to checking code; only after authoritative live validation passes does the
81
86
  extension offer a separate GUI choice. Selecting **Check and import APEXlang
@@ -21,6 +21,7 @@ export const APEXLANG_ACTIONS = Object.freeze([
21
21
 
22
22
  const apexctlPath = resolve(APEXLANG_SKILL_ROOT, "tools/apexctl.mjs");
23
23
  const queryValidPropsPath = resolve(APEXLANG_SKILL_ROOT, "tools/query-valid-props.mjs");
24
+ const localValidatePath = resolve(moduleDirectory, "apexlang-local-validate.mjs");
24
25
  const runtimeRoundtripPath = resolve(moduleDirectory, "apexlang-runtime-roundtrip.mjs");
25
26
  const sqlclPtyProxyPath = resolve(moduleDirectory, "apexlang-sqlcl-pty.py");
26
27
  const CONTROL_CHARACTER_PATTERN = /[\u0000-\u001f\u007f]/;
@@ -214,9 +215,9 @@ export function buildApexlangCommand(input) {
214
215
  }
215
216
 
216
217
  if (action === "local_validate") {
217
- const args = ["apexlang", "validate", "--app-path", requirePath(input, "app_path", action)];
218
+ const args = ["--app-path", requirePath(input, "app_path", action)];
218
219
  addFlag(args, "--fix-vocab", input.fix_vocab);
219
- return apexctl(args);
220
+ return { scriptPath: localValidatePath, args, prelude: [] };
220
221
  }
221
222
 
222
223
  if (action === "compiler_truth_audit") {
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { spawnSync } from "node:child_process";
4
+ import { mkdirSync } from "node:fs";
5
+ import { dirname, join, resolve } from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+
8
+ const moduleDirectory = dirname(fileURLToPath(import.meta.url));
9
+ const skillRoot = resolve(moduleDirectory, "../../skills/apexlang");
10
+ const runtimeRoot = resolve(skillRoot, "runtime");
11
+ const pythonRoot = resolve(runtimeRoot, "internal/python");
12
+ const optimizedDslValidator = resolve(moduleDirectory, "apexlang-local-validator.py");
13
+
14
+ function readOption(args, name) {
15
+ const index = args.indexOf(name);
16
+ return index >= 0 && index + 1 < args.length ? String(args[index + 1]).trim() : "";
17
+ }
18
+
19
+ function main() {
20
+ const args = process.argv.slice(2);
21
+ const appPath = readOption(args, "--app-path");
22
+ if (!appPath) {
23
+ console.error("Missing required --app-path");
24
+ return 1;
25
+ }
26
+
27
+ const outputRoot = String(process.env.APEXLANG_OUTPUT_ROOT ?? "").trim();
28
+ if (!outputRoot) {
29
+ console.error("APEXLANG_OUTPUT_ROOT is required in packaged apexlang runtime");
30
+ return 1;
31
+ }
32
+
33
+ const reportDir = resolve(outputRoot, "logs");
34
+ mkdirSync(reportDir, { recursive: true });
35
+ const fixVocab = args.includes("--fix-vocab");
36
+ const commands = [
37
+ [
38
+ resolve(pythonRoot, "validate_apexlang_vocab.py"),
39
+ [
40
+ "--app-path",
41
+ appPath,
42
+ "--report-path",
43
+ join(reportDir, "apexlang-vocab-report.json"),
44
+ fixVocab ? "--rewrite" : "--check-only"
45
+ ]
46
+ ],
47
+ [
48
+ optimizedDslValidator,
49
+ ["--report-path", join(reportDir, "apexlang-dsl-report.json"), appPath]
50
+ ],
51
+ [
52
+ resolve(pythonRoot, "validate_validations.py"),
53
+ ["--report-path", join(reportDir, "apexlang-validations-report.json"), appPath]
54
+ ]
55
+ ];
56
+
57
+ let failures = 0;
58
+ for (const [scriptPath, scriptArgs] of commands) {
59
+ const result = spawnSync("python3", [scriptPath, ...scriptArgs], {
60
+ cwd: process.cwd(),
61
+ encoding: "utf8",
62
+ env: {
63
+ ...process.env,
64
+ APEXLANG_EMBEDDED_TOOLS_ROOT: resolve(skillRoot, "tools"),
65
+ APEXLANG_PACKAGE_ROOT: skillRoot,
66
+ APEXLANG_RUNTIME_ROOT: runtimeRoot,
67
+ PYTHONDONTWRITEBYTECODE: "1"
68
+ }
69
+ });
70
+ if (result.stdout) process.stdout.write(result.stdout);
71
+ if (result.stderr) process.stderr.write(result.stderr);
72
+ if (typeof result.status !== "number" || result.status !== 0) failures += 1;
73
+ }
74
+
75
+ if (failures > 0) {
76
+ console.log("APEXLANG_LOCAL_CHECK_FAILED");
77
+ return 1;
78
+ }
79
+ console.log("APEXLANG_LOCAL_CHECK_OK");
80
+ return 0;
81
+ }
82
+
83
+ process.exitCode = main();
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env python3
2
+ """Run Oracle's DSL validator with per-process parser acceleration.
3
+
4
+ The vendored Oracle skill stays byte-for-byte unchanged. This launcher imports
5
+ its validator, replaces only pure parsing helpers with equivalent cached
6
+ implementations, and then calls the original command-line entry point.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from bisect import bisect_right
12
+ from functools import lru_cache, wraps
13
+ import importlib.util
14
+ import os
15
+ from pathlib import Path
16
+ import sys
17
+ from types import ModuleType
18
+ from typing import Any, Callable
19
+
20
+
21
+ class _SparseDepthIndex:
22
+ """Store lexical depth checkpoints only at offsets requested by validators."""
23
+
24
+ __slots__ = ("positions", "states")
25
+
26
+ def __init__(self) -> None:
27
+ self.positions: list[int] = [0]
28
+ self.states: list[tuple[int, int, bool]] = [(0, 0, False)]
29
+
30
+
31
+ _DEPTH_INDEXES: dict[str, _SparseDepthIndex] = {}
32
+
33
+
34
+ def _sparse_nesting_depth(text: str, idx: int) -> tuple[int, int]:
35
+ """Return Oracle-compatible nesting depth using the closest prior checkpoint."""
36
+ target_idx = min(len(text), idx) if idx >= 0 else max(0, len(text) + idx)
37
+ index = _DEPTH_INDEXES.setdefault(text, _SparseDepthIndex())
38
+ checkpoint_slot = bisect_right(index.positions, target_idx) - 1
39
+ start = index.positions[checkpoint_slot]
40
+ paren_depth, brace_depth, in_string = index.states[checkpoint_slot]
41
+
42
+ for pos in range(start, target_idx):
43
+ ch = text[pos]
44
+ if ch == '"' and (pos == 0 or text[pos - 1] != "\\"):
45
+ in_string = not in_string
46
+ continue
47
+ if in_string:
48
+ continue
49
+ if ch == "(":
50
+ paren_depth += 1
51
+ elif ch == ")":
52
+ paren_depth = max(0, paren_depth - 1)
53
+ elif ch == "{":
54
+ brace_depth += 1
55
+ elif ch == "}":
56
+ brace_depth = max(0, brace_depth - 1)
57
+
58
+ if start != target_idx:
59
+ insert_at = checkpoint_slot + 1
60
+ index.positions.insert(insert_at, target_idx)
61
+ index.states.insert(insert_at, (paren_depth, brace_depth, in_string))
62
+ return paren_depth, brace_depth
63
+
64
+
65
+ def _validator_path() -> Path:
66
+ runtime_override = os.environ.get("APEXLANG_RUNTIME_ROOT", "").strip()
67
+ runtime_root = (
68
+ Path(runtime_override).resolve()
69
+ if runtime_override
70
+ else Path(__file__).resolve().parents[2] / "skills" / "apexlang" / "runtime"
71
+ )
72
+ return runtime_root / "internal" / "python" / "validate_apexlang.py"
73
+
74
+
75
+ def _load_oracle_validator(path: Path) -> ModuleType:
76
+ sys.path.insert(0, str(path.parent))
77
+ spec = importlib.util.spec_from_file_location("_pi_apexlang_oracle_validator", path)
78
+ if spec is None or spec.loader is None:
79
+ raise RuntimeError(f"Cannot load Oracle APEXlang validator: {path}")
80
+ module = importlib.util.module_from_spec(spec)
81
+ sys.modules[spec.name] = module
82
+ spec.loader.exec_module(module)
83
+ return module
84
+
85
+
86
+ def _cache_list_function(function: Callable[..., list[Any]]) -> Callable[..., list[Any]]:
87
+ """Cache immutable results while preserving Oracle's fresh-list return type."""
88
+ cached = lru_cache(maxsize=None)(lambda *args: tuple(function(*args)))
89
+
90
+ @wraps(function)
91
+ def wrapper(*args: Any) -> list[Any]:
92
+ return list(cached(*args))
93
+
94
+ return wrapper
95
+
96
+
97
+ def _accelerate(module: ModuleType) -> None:
98
+ module.nesting_depth = _sparse_nesting_depth
99
+ for name in (
100
+ "find_component_blocks",
101
+ "find_named_brace_blocks",
102
+ "find_immediate_component_blocks",
103
+ "find_immediate_named_brace_blocks",
104
+ ):
105
+ setattr(module, name, _cache_list_function(getattr(module, name)))
106
+ module.block_body = lru_cache(maxsize=None)(module.block_body)
107
+
108
+
109
+ def main(argv: list[str]) -> int:
110
+ validator = _load_oracle_validator(_validator_path())
111
+ _accelerate(validator)
112
+ return int(validator.main(argv))
113
+
114
+
115
+ if __name__ == "__main__":
116
+ sys.exit(main(sys.argv[1:]))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-apexlang",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "description": "APEXlang support for pi, powered by Oracle's public APEXlang skill.",
5
5
  "type": "module",
6
6
  "license": "UPL-1.0",