apcore-js 0.1.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.
Files changed (142) hide show
  1. package/.claude/settings.local.json +11 -0
  2. package/.gitmessage +60 -0
  3. package/.pre-commit-config.yaml +28 -0
  4. package/CHANGELOG.md +47 -0
  5. package/CLAUDE.md +68 -0
  6. package/README.md +131 -0
  7. package/apcore-logo.svg +79 -0
  8. package/package.json +37 -0
  9. package/planning/acl-system/overview.md +54 -0
  10. package/planning/acl-system/plan.md +92 -0
  11. package/planning/acl-system/state.json +76 -0
  12. package/planning/acl-system/tasks/acl-core.md +226 -0
  13. package/planning/acl-system/tasks/acl-rule.md +92 -0
  14. package/planning/acl-system/tasks/conditional-rules.md +259 -0
  15. package/planning/acl-system/tasks/pattern-matching.md +152 -0
  16. package/planning/acl-system/tasks/yaml-loading.md +271 -0
  17. package/planning/core-executor/overview.md +53 -0
  18. package/planning/core-executor/plan.md +88 -0
  19. package/planning/core-executor/state.json +76 -0
  20. package/planning/core-executor/tasks/async-support.md +106 -0
  21. package/planning/core-executor/tasks/execution-pipeline.md +113 -0
  22. package/planning/core-executor/tasks/redaction.md +85 -0
  23. package/planning/core-executor/tasks/safety-checks.md +65 -0
  24. package/planning/core-executor/tasks/setup.md +75 -0
  25. package/planning/decorator-bindings/overview.md +62 -0
  26. package/planning/decorator-bindings/plan.md +104 -0
  27. package/planning/decorator-bindings/state.json +87 -0
  28. package/planning/decorator-bindings/tasks/binding-directory.md +79 -0
  29. package/planning/decorator-bindings/tasks/binding-loader.md +148 -0
  30. package/planning/decorator-bindings/tasks/explicit-schemas.md +85 -0
  31. package/planning/decorator-bindings/tasks/function-module.md +127 -0
  32. package/planning/decorator-bindings/tasks/module-factory.md +89 -0
  33. package/planning/decorator-bindings/tasks/schema-modes.md +142 -0
  34. package/planning/middleware-system/overview.md +48 -0
  35. package/planning/middleware-system/plan.md +102 -0
  36. package/planning/middleware-system/state.json +65 -0
  37. package/planning/middleware-system/tasks/adapters.md +170 -0
  38. package/planning/middleware-system/tasks/base.md +115 -0
  39. package/planning/middleware-system/tasks/logging-middleware.md +304 -0
  40. package/planning/middleware-system/tasks/manager.md +313 -0
  41. package/planning/observability/overview.md +53 -0
  42. package/planning/observability/plan.md +119 -0
  43. package/planning/observability/state.json +98 -0
  44. package/planning/observability/tasks/context-logger.md +201 -0
  45. package/planning/observability/tasks/exporters.md +121 -0
  46. package/planning/observability/tasks/metrics-collector.md +162 -0
  47. package/planning/observability/tasks/metrics-middleware.md +141 -0
  48. package/planning/observability/tasks/obs-logging-middleware.md +179 -0
  49. package/planning/observability/tasks/span-model.md +120 -0
  50. package/planning/observability/tasks/tracing-middleware.md +179 -0
  51. package/planning/overview.md +81 -0
  52. package/planning/registry-system/overview.md +57 -0
  53. package/planning/registry-system/plan.md +114 -0
  54. package/planning/registry-system/state.json +109 -0
  55. package/planning/registry-system/tasks/dependencies.md +157 -0
  56. package/planning/registry-system/tasks/entry-point.md +148 -0
  57. package/planning/registry-system/tasks/metadata.md +198 -0
  58. package/planning/registry-system/tasks/registry-core.md +323 -0
  59. package/planning/registry-system/tasks/scanner.md +172 -0
  60. package/planning/registry-system/tasks/schema-export.md +261 -0
  61. package/planning/registry-system/tasks/types.md +124 -0
  62. package/planning/registry-system/tasks/validation.md +177 -0
  63. package/planning/schema-system/overview.md +56 -0
  64. package/planning/schema-system/plan.md +121 -0
  65. package/planning/schema-system/state.json +98 -0
  66. package/planning/schema-system/tasks/exporter.md +153 -0
  67. package/planning/schema-system/tasks/loader.md +106 -0
  68. package/planning/schema-system/tasks/ref-resolver.md +133 -0
  69. package/planning/schema-system/tasks/strict-mode.md +140 -0
  70. package/planning/schema-system/tasks/typebox-generation.md +133 -0
  71. package/planning/schema-system/tasks/types-and-annotations.md +160 -0
  72. package/planning/schema-system/tasks/validator.md +149 -0
  73. package/src/acl.ts +188 -0
  74. package/src/bindings.ts +208 -0
  75. package/src/config.ts +24 -0
  76. package/src/context.ts +75 -0
  77. package/src/decorator.ts +110 -0
  78. package/src/errors.ts +369 -0
  79. package/src/executor.ts +348 -0
  80. package/src/index.ts +81 -0
  81. package/src/middleware/adapters.ts +54 -0
  82. package/src/middleware/base.ts +33 -0
  83. package/src/middleware/index.ts +6 -0
  84. package/src/middleware/logging.ts +103 -0
  85. package/src/middleware/manager.ts +105 -0
  86. package/src/module.ts +41 -0
  87. package/src/observability/context-logger.ts +201 -0
  88. package/src/observability/index.ts +4 -0
  89. package/src/observability/metrics.ts +212 -0
  90. package/src/observability/tracing.ts +187 -0
  91. package/src/registry/dependencies.ts +99 -0
  92. package/src/registry/entry-point.ts +64 -0
  93. package/src/registry/index.ts +8 -0
  94. package/src/registry/metadata.ts +111 -0
  95. package/src/registry/registry.ts +314 -0
  96. package/src/registry/scanner.ts +150 -0
  97. package/src/registry/schema-export.ts +177 -0
  98. package/src/registry/types.ts +32 -0
  99. package/src/registry/validation.ts +38 -0
  100. package/src/schema/annotations.ts +67 -0
  101. package/src/schema/exporter.ts +93 -0
  102. package/src/schema/index.ts +14 -0
  103. package/src/schema/loader.ts +270 -0
  104. package/src/schema/ref-resolver.ts +235 -0
  105. package/src/schema/strict.ts +128 -0
  106. package/src/schema/types.ts +73 -0
  107. package/src/schema/validator.ts +82 -0
  108. package/src/utils/index.ts +1 -0
  109. package/src/utils/pattern.ts +30 -0
  110. package/tests/helpers.ts +30 -0
  111. package/tests/integration/test-acl-safety.test.ts +268 -0
  112. package/tests/integration/test-binding-executor.test.ts +194 -0
  113. package/tests/integration/test-e2e-flow.test.ts +117 -0
  114. package/tests/integration/test-error-propagation.test.ts +259 -0
  115. package/tests/integration/test-middleware-chain.test.ts +120 -0
  116. package/tests/integration/test-observability-integration.test.ts +438 -0
  117. package/tests/observability/test-context-logger.test.ts +123 -0
  118. package/tests/observability/test-metrics.test.ts +89 -0
  119. package/tests/observability/test-tracing.test.ts +131 -0
  120. package/tests/registry/test-dependencies.test.ts +70 -0
  121. package/tests/registry/test-entry-point.test.ts +133 -0
  122. package/tests/registry/test-metadata.test.ts +265 -0
  123. package/tests/registry/test-registry.test.ts +140 -0
  124. package/tests/registry/test-scanner.test.ts +257 -0
  125. package/tests/registry/test-schema-export.test.ts +224 -0
  126. package/tests/registry/test-validation.test.ts +75 -0
  127. package/tests/schema/test-loader.test.ts +97 -0
  128. package/tests/schema/test-ref-resolver.test.ts +105 -0
  129. package/tests/schema/test-strict.test.ts +139 -0
  130. package/tests/schema/test-validator.test.ts +64 -0
  131. package/tests/test-acl.test.ts +206 -0
  132. package/tests/test-bindings.test.ts +227 -0
  133. package/tests/test-config.test.ts +76 -0
  134. package/tests/test-context.test.ts +151 -0
  135. package/tests/test-decorator.test.ts +173 -0
  136. package/tests/test-errors.test.ts +204 -0
  137. package/tests/test-executor.test.ts +252 -0
  138. package/tests/test-middleware-manager.test.ts +185 -0
  139. package/tests/test-middleware.test.ts +86 -0
  140. package/tsconfig.build.json +8 -0
  141. package/tsconfig.json +20 -0
  142. package/vitest.config.ts +18 -0
@@ -0,0 +1,11 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(npx vitest run:*)",
5
+ "Bash(npm test:*)",
6
+ "Bash(npx tsc:*)",
7
+ "Bash(wc:*)",
8
+ "Bash(ls:*)"
9
+ ]
10
+ }
11
+ }
package/.gitmessage ADDED
@@ -0,0 +1,60 @@
1
+ # <type>(<scope>): <subject>
2
+ #
3
+ # <body>
4
+ #
5
+ # <footer>
6
+
7
+ # Type must be one of the following:
8
+ # feat: A new feature
9
+ # fix: A bug fix
10
+ # docs: Documentation only changes
11
+ # style: Changes that do not affect the meaning of the code
12
+ # refactor: A code change that neither fixes a bug nor adds a feature
13
+ # perf: A code change that improves performance
14
+ # test: Adding missing tests or correcting existing tests
15
+ # chore: Changes to the build process or auxiliary tools
16
+ # ci: Changes to CI configuration files and scripts
17
+
18
+ # Scope is optional and can be anything specifying the place of the commit change.
19
+ # Examples: api, core, storage, cli, stdio, etc.
20
+
21
+ # Subject should be:
22
+ # - Use imperative, present tense: "change" not "changed" nor "changes"
23
+ # - Don't capitalize first letter
24
+ # - No dot (.) at the end
25
+ # - Maximum 72 characters
26
+
27
+ # Body should include:
28
+ # - Motivation for the change and contrast with previous behavior
29
+ # - What changed and why
30
+ # - Any breaking changes
31
+
32
+ # Footer should contain:
33
+ # - Breaking changes (start with BREAKING CHANGE:)
34
+ # - Issue references (Closes #123, Fixes #456)
35
+
36
+ # Examples:
37
+ # feat(stdio): add stdio executor for process execution
38
+ #
39
+ # Implement a new stdio executor that allows executing system commands
40
+ # and processes via stdin/stdout communication, similar to MCP stdio
41
+ # transport mode. This enables flexible task execution through shell
42
+ # commands and Python scripts.
43
+ #
44
+ # - Add StdioExecutor class with command execution support
45
+ # - Add system resource monitoring (CPU, memory, disk)
46
+ # - Support async process communication
47
+ # - Add comprehensive error handling and logging
48
+ #
49
+ # Closes #123
50
+
51
+ # refactor(core): extract shared types to core.types module
52
+ #
53
+ # Move common type definitions from various modules to a centralized
54
+ # core.types module to avoid circular dependencies and improve code
55
+ # organization.
56
+ #
57
+ # - Add TaskPreHook and TaskPostHook type aliases
58
+ # - Move TaskStatus enum to core.types
59
+ # - Update imports across affected modules
60
+
@@ -0,0 +1,28 @@
1
+ repos:
2
+
3
+ # apdev-js hooks
4
+ - repo: local
5
+ hooks:
6
+ - id: check-chars
7
+ name: apdev-js check-chars
8
+ entry: apdev-js check-chars
9
+ language: system
10
+ types_or: [text, ts, javascript]
11
+
12
+ - id: check-imports
13
+ name: apdev-js check-imports
14
+ entry: apdev-js check-imports
15
+ language: system
16
+ pass_filenames: false
17
+ always_run: true
18
+
19
+ # TypeScript type checking
20
+ - repo: local
21
+ hooks:
22
+ - id: typecheck
23
+ name: tsc --noEmit
24
+ entry: npx tsc --noEmit
25
+ language: system
26
+ pass_filenames: false
27
+ always_run: true
28
+ files: \.(ts|tsx)$
package/CHANGELOG.md ADDED
@@ -0,0 +1,47 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.1.0] - 2026-02-16
9
+
10
+ ### Added
11
+
12
+ - **Core executor** — 10-step async execution pipeline with timeout support via `Promise.race`
13
+ - **Context system** — Execution context with trace IDs, call chains, identity, and redacted inputs
14
+ - **Config** — Dot-path configuration accessor
15
+ - **Registry system**
16
+ - File-based module discovery (`scanExtensions`, `scanMultiRoot`)
17
+ - Dynamic entry point resolution with duck-type validation
18
+ - YAML metadata loading and merging (code values + YAML overrides)
19
+ - Dependency parsing with topological sort (Kahn's algorithm) and cycle detection
20
+ - ID map support for custom module IDs
21
+ - Schema export in JSON/YAML with strict and compact modes
22
+ - **FunctionModule** — Schema-driven module wrapper with TypeBox schemas
23
+ - **Binding loader** — YAML-based module registration with three schema modes (inline, external ref, permissive fallback)
24
+ - **ACL (Access Control List)**
25
+ - Pattern-based rules with glob matching
26
+ - Identity type and role-based conditions
27
+ - Call depth conditions
28
+ - Dynamic rule management (`addRule`, `removeRule`, `reload`)
29
+ - YAML configuration loading
30
+ - **Middleware system**
31
+ - Onion-model execution (before forward, after reverse)
32
+ - Error recovery via `onError` hooks
33
+ - `BeforeMiddleware` and `AfterMiddleware` adapters
34
+ - `LoggingMiddleware` for structured execution logging
35
+ - **Observability**
36
+ - **Tracing** — Span creation, `InMemoryExporter`, `StdoutExporter`, `TracingMiddleware` with sampling strategies (full, off, proportional, error_first)
37
+ - **Metrics** — `MetricsCollector` with counters, histograms, Prometheus text format export, `MetricsMiddleware`
38
+ - **Logging** — `ContextLogger` with JSON/text formats, level filtering, `_secret_` field redaction, `ObsLoggingMiddleware`
39
+ - **Schema system**
40
+ - JSON Schema to TypeBox conversion
41
+ - `$ref` resolution
42
+ - Schema validation
43
+ - Strict transforms (`additionalProperties: false`)
44
+ - LLM description injection and extension stripping
45
+ - **Error hierarchy** — 20+ typed error classes with error codes, details, trace IDs, and timestamps
46
+ - **Pattern matching** — Glob-style pattern matching for ACL rules and module targeting
47
+ - **Comprehensive test suite** — 385 tests across 29 test files
package/CLAUDE.md ADDED
@@ -0,0 +1,68 @@
1
+ # High-Quality Code Specification – Simplicity, Readability, and Maintainability First
2
+
3
+ ## Project Overview
4
+ The core of `apcore` is **task orchestration and execution specifications**. It provides a unified task orchestration framework that supports execution of multiple task types.
5
+
6
+ ## Core Principles
7
+ - Prioritize **simplicity, readability, and maintainability** above all.
8
+ - Avoid premature abstraction, optimization, or over-engineering.
9
+ - Code should be understandable in ≤10 seconds; favor straightforward over clever.
10
+ - Always follow: Understand → Plan → Implement minimally → Test/Validate → Commit.
11
+
12
+ ## TypeScript Code Quality
13
+
14
+ ### Readability
15
+ - Use precise, full-word names (standard abbreviations only when conventional).
16
+ - Functions ≤50 lines, single responsibility, verb-named.
17
+ - Avoid obscure tricks, excessive generics, or unnecessary abstraction layers.
18
+ - Break complex logic into small, well-named helpers.
19
+
20
+ ### Types (Mandatory)
21
+ - Full type annotations on all public APIs and function signatures.
22
+ - Avoid `any` except for dynamic/external data; prefer `unknown` with narrowing.
23
+ - Prefer `interface` for object shapes, `type` for unions/intersections.
24
+ - Use `readonly` for immutable data structures.
25
+
26
+ ### Design
27
+ - Favor functional style + plain objects; minimize class inheritance.
28
+ - Composition > inheritance; use `interface` only for true contracts.
29
+ - No circular imports.
30
+ - Dependency injection for config, logging, external services, etc.
31
+
32
+ ### Errors & Resources
33
+ - Explicit error handling; no bare `catch {}` that swallows errors silently.
34
+ - Use `try/finally` or equivalent cleanup patterns for resources.
35
+ - Validate/sanitize all public inputs.
36
+
37
+ ### Logging
38
+ - Use `console.warn` for warnings in library code.
39
+ - Prefix log messages with `[apcore:<subsystem>]` for traceability.
40
+ - No `console.log` in production code paths.
41
+
42
+ ### Testing
43
+ - Unit tests in `tests/`, ≥90% coverage on core logic.
44
+ - Test files named: `test-<unit>.test.ts`.
45
+ - Test cases named descriptively: `it('throws X when Y', ...)`.
46
+ - Never change production code without updating tests.
47
+ - Use `vitest` as test runner.
48
+
49
+ ### Build & Checks
50
+ - After changes, always run:
51
+ - `npx tsc --noEmit` (type checking)
52
+ - `npx vitest run` (tests)
53
+ - Zero errors before commit.
54
+
55
+ ### Module System
56
+ - ESM only (`"type": "module"` in package.json).
57
+ - All imports must use `.js` extension (NodeNext resolution).
58
+ - Use `@sinclair/typebox` for runtime schema definitions.
59
+
60
+ ### Security & Performance
61
+ - Never hardcode secrets; use env/config.
62
+ - Validate/sanitize inputs at system boundaries.
63
+ - Avoid unjustified quadratic+ complexity in hot paths.
64
+
65
+ ## General Guidelines
66
+ - English ONLY for comments, JSDoc, logs, errors, commit messages.
67
+ - Fully understand surrounding code before changes.
68
+ - Do not generate unnecessary documentation, examples, or stubs unless explicitly requested.
package/README.md ADDED
@@ -0,0 +1,131 @@
1
+ <div align="center">
2
+ <img src="./apcore-logo.svg" alt="apcore logo" width="200"/>
3
+ </div>
4
+
5
+ # apcore
6
+
7
+ **AI-Perceivable Core** — A schema-driven module development framework for TypeScript.
8
+
9
+ apcore provides a unified task orchestration framework with schema validation, access control, middleware pipelines, and observability built in.
10
+
11
+ ## Features
12
+
13
+ - **Schema-driven modules** — Define input/output schemas with TypeBox for runtime validation
14
+ - **Executor pipeline** — 10-step execution pipeline: context → safety checks → lookup → ACL → validation → middleware before → execute → output validation → middleware after → return
15
+ - **Registry system** — File-based module discovery with metadata, dependencies, and topological ordering
16
+ - **Binding loader** — YAML-based module registration for no-code integration
17
+ - **Access control (ACL)** — Pattern-based rules with identity types, roles, and call-depth conditions
18
+ - **Middleware** — Onion-model middleware with before/after/onError hooks and error recovery
19
+ - **Observability** — Tracing (spans + exporters), metrics (counters + histograms + Prometheus export), structured logging with redaction
20
+ - **Schema export** — JSON/YAML schema export with strict and compact modes
21
+
22
+ ## Requirements
23
+
24
+ - Node.js >= 18.0.0
25
+ - TypeScript >= 5.5
26
+
27
+ ## Installation
28
+
29
+ ```bash
30
+ npm install apcore-js
31
+ ```
32
+
33
+ ## Quick Start
34
+
35
+ ```typescript
36
+ import { Type } from '@sinclair/typebox';
37
+ import { FunctionModule, Registry, Executor } from 'apcore-js';
38
+
39
+ // Define a module
40
+ const greet = new FunctionModule({
41
+ execute: (inputs) => ({ greeting: `Hello, ${inputs.name}!` }),
42
+ moduleId: 'example.greet',
43
+ inputSchema: Type.Object({ name: Type.String() }),
44
+ outputSchema: Type.Object({ greeting: Type.String() }),
45
+ description: 'Greet a user',
46
+ });
47
+
48
+ // Register and execute
49
+ const registry = new Registry();
50
+ registry.register('example.greet', greet);
51
+
52
+ const executor = new Executor({ registry });
53
+ const result = await executor.call('example.greet', { name: 'World' });
54
+ // => { greeting: 'Hello, World!' }
55
+ ```
56
+
57
+ ## Architecture
58
+
59
+ ```
60
+ src/
61
+ index.ts # Public API exports
62
+ executor.ts # 10-step execution pipeline
63
+ context.ts # Execution context and identity
64
+ config.ts # Dot-path configuration accessor
65
+ acl.ts # Access control with pattern matching
66
+ decorator.ts # FunctionModule class and helpers
67
+ bindings.ts # YAML binding loader
68
+ errors.ts # Error hierarchy (20+ typed errors)
69
+ module.ts # Module types and annotations
70
+ middleware/
71
+ base.ts # Middleware base class
72
+ manager.ts # MiddlewareManager (onion model)
73
+ adapters.ts # BeforeMiddleware, AfterMiddleware adapters
74
+ logging.ts # LoggingMiddleware
75
+ registry/
76
+ registry.ts # Registry with discover() pipeline
77
+ scanner.ts # File-based module discovery
78
+ entry-point.ts # Dynamic import and entry point resolution
79
+ metadata.ts # YAML metadata and ID map loading
80
+ dependencies.ts # Topological sort with cycle detection
81
+ validation.ts # Module duck-type validation
82
+ schema-export.ts # Schema export (JSON/YAML, strict/compact)
83
+ types.ts # Registry type definitions
84
+ schema/
85
+ loader.ts # JSON Schema to TypeBox conversion
86
+ validator.ts # Schema validation
87
+ exporter.ts # Schema serialization
88
+ ref-resolver.ts # $ref resolution
89
+ strict.ts # Strict schema transforms
90
+ types.ts # Schema type definitions
91
+ observability/
92
+ tracing.ts # Span, SpanExporter, TracingMiddleware
93
+ metrics.ts # MetricsCollector, MetricsMiddleware
94
+ context-logger.ts # ContextLogger, ObsLoggingMiddleware
95
+ utils/
96
+ pattern.ts # Glob-style pattern matching
97
+ ```
98
+
99
+ ## Development
100
+
101
+ ```bash
102
+ # Install dependencies
103
+ npm install
104
+
105
+ # Type check
106
+ npm run typecheck
107
+
108
+ # Run tests
109
+ npm test
110
+
111
+ # Run tests in watch mode
112
+ npm run test:watch
113
+
114
+ # Build
115
+ npm run build
116
+ ```
117
+
118
+ ## Testing
119
+
120
+ - Core executor pipeline
121
+ - Schema validation (strict mode, type coercion)
122
+ - Middleware chain (ordering, transforms, error recovery)
123
+ - ACL enforcement (patterns, conditions, identity types)
124
+ - Registry system (scanner, metadata, entry points, dependencies)
125
+ - Binding loader (YAML loading, target resolution, schema modes)
126
+ - Observability (tracing, metrics, structured logging)
127
+ - Integration tests (end-to-end flows, error propagation, safety checks)
128
+
129
+ ## License
130
+
131
+ MIT
@@ -0,0 +1,79 @@
1
+ <svg width="512" height="512" viewBox="46 70 420 420" xmlns="http://www.w3.org/2000/svg">
2
+ <!-- apcore jellyfish logo - cartoon ocean mascot -->
3
+
4
+ <defs>
5
+ <!-- Bell radial gradient: bright center → deep indigo edge -->
6
+ <radialGradient id="bellGrad" cx="50%" cy="45%" r="50%">
7
+ <stop offset="0%" stop-color="#818CF8"/>
8
+ <stop offset="100%" stop-color="#4338CA"/>
9
+ </radialGradient>
10
+
11
+ <!-- Bioluminescence glow -->
12
+ <radialGradient id="glowGrad" cx="50%" cy="50%" r="50%">
13
+ <stop offset="0%" stop-color="#67E8F9" stop-opacity="0.4"/>
14
+ <stop offset="100%" stop-color="#67E8F9" stop-opacity="0"/>
15
+ </radialGradient>
16
+
17
+ <!-- Tentacle gradients (top solid → bottom fade) -->
18
+ <linearGradient id="tentGrad1" x1="0" y1="0" x2="0" y2="1">
19
+ <stop offset="0%" stop-color="#6366F1"/>
20
+ <stop offset="100%" stop-color="#4F46E5" stop-opacity="0"/>
21
+ </linearGradient>
22
+ <linearGradient id="tentGrad2" x1="0" y1="0" x2="0" y2="1">
23
+ <stop offset="0%" stop-color="#818CF8"/>
24
+ <stop offset="100%" stop-color="#6366F1" stop-opacity="0"/>
25
+ </linearGradient>
26
+ </defs>
27
+
28
+ <!-- Tentacles (behind bell) - 6 flowing tentacles -->
29
+ <!-- Outer left tentacle -->
30
+ <path d="M 175,300 C 160,350 145,390 155,430 Q 162,455 150,470"
31
+ stroke="url(#tentGrad1)" stroke-width="8" fill="none" stroke-linecap="round"/>
32
+ <!-- Inner left tentacle -->
33
+ <path d="M 210,310 C 200,360 188,400 195,445 Q 200,465 190,480"
34
+ stroke="url(#tentGrad2)" stroke-width="7" fill="none" stroke-linecap="round"/>
35
+ <!-- Center left tentacle -->
36
+ <path d="M 245,310 C 240,365 235,410 242,455 Q 248,475 240,490"
37
+ stroke="url(#tentGrad1)" stroke-width="6" fill="none" stroke-linecap="round"/>
38
+ <!-- Center right tentacle -->
39
+ <path d="M 267,310 C 272,365 277,410 270,455 Q 264,475 272,490"
40
+ stroke="url(#tentGrad1)" stroke-width="6" fill="none" stroke-linecap="round"/>
41
+ <!-- Inner right tentacle -->
42
+ <path d="M 302,310 C 312,360 324,400 317,445 Q 312,465 322,480"
43
+ stroke="url(#tentGrad2)" stroke-width="7" fill="none" stroke-linecap="round"/>
44
+ <!-- Outer right tentacle -->
45
+ <path d="M 337,300 C 352,350 367,390 357,430 Q 350,455 362,470"
46
+ stroke="url(#tentGrad1)" stroke-width="8" fill="none" stroke-linecap="round"/>
47
+
48
+ <!-- Bell (dome body) -->
49
+ <path d="M 130,290 C 130,150 190,80 256,80 C 322,80 382,150 382,290 Q 382,310 256,310 Q 130,310 130,290 Z"
50
+ fill="url(#bellGrad)"/>
51
+
52
+ <!-- Bell rim / ruffle -->
53
+ <path d="M 130,290 Q 150,318 175,298 Q 200,318 225,298 Q 250,318 268,298 Q 290,318 312,298 Q 335,318 355,298 Q 375,318 382,290"
54
+ fill="#4338CA" opacity="0.6"/>
55
+
56
+ <!-- Bioluminescence glow overlay -->
57
+ <ellipse cx="256" cy="210" rx="100" ry="90" fill="url(#glowGrad)"/>
58
+
59
+ <!-- Bell highlight (specular) -->
60
+ <ellipse cx="230" cy="160" rx="55" ry="35" fill="#A5B4FC" opacity="0.3"/>
61
+
62
+ <!-- Eyes -->
63
+ <ellipse cx="222" cy="215" rx="22" ry="24" fill="white"/>
64
+ <ellipse cx="290" cy="215" rx="22" ry="24" fill="white"/>
65
+ <!-- Pupils -->
66
+ <circle cx="228" cy="220" r="13" fill="#1E1B4B"/>
67
+ <circle cx="296" cy="220" r="13" fill="#1E1B4B"/>
68
+ <!-- Eye highlights -->
69
+ <circle cx="233" cy="212" r="6" fill="white"/>
70
+ <circle cx="301" cy="212" r="6" fill="white"/>
71
+
72
+ <!-- Smile -->
73
+ <path d="M 240,252 Q 256,268 272,252"
74
+ stroke="#312E81" stroke-width="3.5" fill="none" stroke-linecap="round"/>
75
+
76
+ <!-- Cheek blush -->
77
+ <ellipse cx="205" cy="242" rx="14" ry="9" fill="#C4B5FD" opacity="0.45"/>
78
+ <ellipse cx="307" cy="242" rx="14" ry="9" fill="#C4B5FD" opacity="0.45"/>
79
+ </svg>
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "apcore-js",
3
+ "version": "0.1.0",
4
+ "description": "AI-Perceivable Core — schema-driven module development framework",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "scripts": {
15
+ "build": "tsc -p tsconfig.build.json",
16
+ "typecheck": "tsc --noEmit",
17
+ "test": "vitest run",
18
+ "test:watch": "vitest",
19
+ "test:coverage": "vitest run --coverage"
20
+ },
21
+ "engines": {
22
+ "node": ">=18.0.0"
23
+ },
24
+ "license": "MIT",
25
+ "dependencies": {
26
+ "@sinclair/typebox": "^0.34.0",
27
+ "js-yaml": "^4.1.0"
28
+ },
29
+ "devDependencies": {
30
+ "typescript": "^5.5.0",
31
+ "@types/node": "^20.0.0",
32
+ "@types/js-yaml": "^4.0.9",
33
+ "apdev-js": "^0.1.1",
34
+ "vitest": "^2.0.0",
35
+ "@vitest/coverage-v8": "^2.0.0"
36
+ }
37
+ }
@@ -0,0 +1,54 @@
1
+ # Feature: ACL System
2
+
3
+ ## Overview
4
+
5
+ The ACL (Access Control List) system provides pattern-based access control for apcore module calls. It evaluates caller-to-target permissions using a first-match-wins strategy over an ordered rule list. Each rule specifies caller patterns, target patterns, an effect (allow/deny), and optional conditions (identity types, roles, call depth). The `ACL` class supports runtime rule mutation (`addRule`, `removeRule`), YAML-based configuration loading via a static `load()` factory, and live `reload()` for configuration hot-swapping. Pattern matching uses a wildcard algorithm (Algorithm A08) that supports `*` globs in module IDs.
6
+
7
+ ## Scope
8
+
9
+ ### Included
10
+
11
+ - `ACLRule` interface defining the structure of access control rules (callers, targets, effect, description, conditions)
12
+ - `ACL` class with `check()` for first-match-wins evaluation, `addRule()` for prepending rules, `removeRule()` for removal by caller/target match via `JSON.stringify` comparison
13
+ - Static `ACL.load()` factory for loading rules from YAML configuration files with strict validation
14
+ - `reload()` method for hot-reloading YAML-based configuration without reconstructing the ACL instance
15
+ - `matchPattern()` wildcard utility (Algorithm A08) for glob-style module ID matching
16
+ - Special caller tokens: `@external` (null caller substitution), `@system` (identity type check)
17
+ - Conditional rule evaluation: `identity_types`, `roles`, `max_call_depth` with AND logic
18
+ - Error types: `ACLDeniedError` (thrown by executor on denial), `ACLRuleError` (invalid rules/config), `ConfigNotFoundError` (missing YAML)
19
+
20
+ ### Excluded
21
+
22
+ - Executor integration (the executor consumes `ACL.check()` as a dependency)
23
+ - Thread locking or concurrency guards (Node.js single-threaded event loop eliminates the need)
24
+ - Debug logging (identified gap vs. Python implementation; not included in current scope)
25
+ - Role or identity management (consumed from `Context.identity`)
26
+
27
+ ## Technology Stack
28
+
29
+ - **TypeScript 5.5+** with strict mode
30
+ - **js-yaml** for YAML configuration parsing
31
+ - **Node.js >= 18.0.0** with ES Module support (`node:fs` for file I/O)
32
+ - **vitest** for unit and integration testing
33
+
34
+ ## Task Execution Order
35
+
36
+ | # | Task File | Description | Status |
37
+ |---|-----------|-------------|--------|
38
+ | 1 | [acl-rule](./tasks/acl-rule.md) | ACLRule interface definition | completed |
39
+ | 2 | [acl-core](./tasks/acl-core.md) | ACL class with check(), addRule(), removeRule(), default effect | completed |
40
+ | 3 | [pattern-matching](./tasks/pattern-matching.md) | matchPattern() wildcard matching (Algorithm A08) | completed |
41
+ | 4 | [yaml-loading](./tasks/yaml-loading.md) | ACL.load() from YAML with strict validation, reload() support | completed |
42
+ | 5 | [conditional-rules](./tasks/conditional-rules.md) | _checkConditions() with identity_types, roles, max_call_depth | completed |
43
+
44
+ ## Progress
45
+
46
+ | Total | Completed | In Progress | Pending |
47
+ |-------|-----------|-------------|---------|
48
+ | 5 | 5 | 0 | 0 |
49
+
50
+ ## Reference Documents
51
+
52
+ - `src/acl.ts` -- ACL class and ACLRule interface (~188 lines)
53
+ - `src/utils/pattern.ts` -- matchPattern wildcard utility (~30 lines)
54
+ - `src/errors.ts` -- ACLDeniedError, ACLRuleError, ConfigNotFoundError
@@ -0,0 +1,92 @@
1
+ # Implementation Plan: ACL System
2
+
3
+ ## Goal
4
+
5
+ Implement a pattern-based access control list that evaluates caller-to-target module permissions using first-match-wins semantics, supporting wildcard patterns, conditional rules, YAML-based configuration, and runtime rule mutation.
6
+
7
+ ## Architecture Design
8
+
9
+ ### Component Structure
10
+
11
+ - **ACL** (`acl.ts`, ~188 lines) -- Main access control class. Holds an ordered array of `ACLRule` objects and a `_defaultEffect` (default `'deny'`). Provides `check(callerId, targetId, context?)` for permission evaluation, `addRule(rule)` to prepend a rule, `removeRule(callers, targets)` to remove by JSON-stringified comparison, and `reload()` for hot-swapping YAML-loaded rules. Static `load(yamlPath)` factory parses and validates YAML configuration files.
12
+
13
+ - **ACLRule** (`acl.ts`) -- Interface defining a single access control rule: `callers` (string array of patterns), `targets` (string array of patterns), `effect` (`'allow'` or `'deny'`), `description` (string), and optional `conditions` record. Conditions are evaluated with AND logic across all present keys.
14
+
15
+ - **matchPattern** (`utils/pattern.ts`, ~30 lines) -- Standalone wildcard pattern matcher implementing Algorithm A08. Splits the pattern on `*` delimiters and verifies each segment appears in order within the module ID string. Handles edge cases: bare `*` matches everything, no `*` means exact match.
16
+
17
+ - **Error Types** (`errors.ts`) -- `ACLDeniedError` (raised by executor when `check()` returns `false`), `ACLRuleError` (invalid rule structure, bad YAML, missing keys), `ConfigNotFoundError` (YAML file does not exist). All extend `ModuleError` base class.
18
+
19
+ ### Data Flow
20
+
21
+ The `check()` method evaluates permissions through this pipeline:
22
+
23
+ 1. **Caller Normalization** -- `null` caller is replaced with `'@external'`
24
+ 2. **Rule Snapshot** -- Shallow copy of `_rules` array (safe iteration)
25
+ 3. **First-Match-Wins Scan** -- Iterate rules in order:
26
+ a. **Caller Pattern Match** -- `rule.callers.some(p => _matchPattern(p, caller, context))`
27
+ b. **Target Pattern Match** -- `rule.targets.some(p => _matchPattern(p, target, context))`
28
+ c. **Condition Evaluation** -- If `rule.conditions != null`, apply `_checkConditions()`
29
+ d. **Effect Return** -- If all checks pass, return `rule.effect === 'allow'`
30
+ 4. **Default Effect** -- If no rule matches, return `_defaultEffect === 'allow'`
31
+
32
+ Pattern matching handles three special patterns:
33
+ - `'@external'` -- Exact match against the `@external` sentinel
34
+ - `'@system'` -- Checks `context.identity.type === 'system'`
35
+ - Wildcard patterns -- Delegated to `matchPattern()` from `utils/pattern.ts`
36
+
37
+ ### Technical Choices and Rationale
38
+
39
+ - **First-match-wins over priority scores**: Simpler mental model; rule ordering in YAML is explicit and deterministic. No conflict resolution needed.
40
+ - **`JSON.stringify` for rule comparison in `removeRule()`**: Pragmatic approach for comparing string arrays without deep-equal dependencies. Suitable since callers/targets are always `string[]`.
41
+ - **No thread locking**: Node.js single-threaded event loop means no concurrent mutation of the rules array. The shallow copy in `check()` guards against mid-iteration `addRule`/`removeRule` calls from synchronous code, but no mutex is needed.
42
+ - **Synchronous YAML loading via `readFileSync`**: ACL configuration is loaded at startup or explicit reload. Synchronous I/O is appropriate for initialization-time config loading.
43
+ - **AND logic for conditions**: All present condition keys must pass for the rule to match. This provides a restrictive-by-default composition model (conditions narrow access rather than broaden it).
44
+ - **No debug logging**: Identified gap vs. Python implementation. The TypeScript ACL omits `debug` flag logging to keep the implementation lean. Can be added later via middleware or observability hooks.
45
+
46
+ ## Task Breakdown
47
+
48
+ ```mermaid
49
+ graph TD
50
+ T1[acl-rule] --> T2[acl-core]
51
+ T1 --> T5[conditional-rules]
52
+ T3[pattern-matching] --> T2
53
+ T2 --> T4[yaml-loading]
54
+ T5 --> T2
55
+ ```
56
+
57
+ | Task ID | Title | Estimated Time | Dependencies |
58
+ |---------|-------|---------------|--------------|
59
+ | acl-rule | ACLRule interface definition | 1h | none |
60
+ | acl-core | ACL class with check, addRule, removeRule | 3h | acl-rule, pattern-matching, conditional-rules |
61
+ | pattern-matching | matchPattern() wildcard matching (Algorithm A08) | 2h | none |
62
+ | yaml-loading | ACL.load() from YAML, reload() support | 2h | acl-core |
63
+ | conditional-rules | _checkConditions() with identity_types, roles, max_call_depth | 2h | acl-rule |
64
+
65
+ ## Risks and Considerations
66
+
67
+ - **Rule ordering sensitivity**: First-match-wins means a broadly-scoped rule placed early can shadow more specific rules. Documentation should emphasize that more specific rules should appear before general rules.
68
+ - **`JSON.stringify` ordering dependency**: `removeRule` relies on `JSON.stringify` producing identical output for identical arrays. This holds for simple `string[]` but would break for arrays containing objects with non-deterministic key order. Current usage is safe since callers/targets are always string arrays.
69
+ - **Synchronous file I/O in `load()`/`reload()`**: Blocks the event loop during YAML parsing. Acceptable for startup configuration but could be problematic if `reload()` is called frequently with large config files.
70
+ - **No validation of condition values at load time**: Condition values (e.g., `identity_types` expected as `string[]`) are validated at match time via type assertions, not at YAML load time. Malformed conditions will only surface when a rule is evaluated.
71
+ - **Debug flag exists but is unused**: The `debug` property is declared on the `ACL` class but no logging is wired up, representing a gap from the Python implementation.
72
+
73
+ ## Acceptance Criteria
74
+
75
+ - [x] `ACLRule` interface defines callers, targets, effect, description, and optional conditions
76
+ - [x] `ACL.check()` implements first-match-wins evaluation returning `boolean`
77
+ - [x] Null caller is normalized to `'@external'`
78
+ - [x] `@system` pattern checks `context.identity.type === 'system'`
79
+ - [x] `matchPattern()` handles exact, wildcard, prefix, suffix, and multi-segment patterns
80
+ - [x] `ACL.load()` parses YAML, validates structure, and returns configured ACL instance
81
+ - [x] `reload()` re-reads YAML and replaces rules in-place; throws `ACLRuleError` if not loaded from YAML
82
+ - [x] `addRule()` prepends rules; `removeRule()` finds and removes by JSON-stringified caller/target match
83
+ - [x] Conditions (`identity_types`, `roles`, `max_call_depth`) are evaluated with AND logic
84
+ - [x] `ACLRuleError` thrown for invalid config structure; `ConfigNotFoundError` for missing YAML files
85
+ - [x] All tests pass with `vitest`; zero errors from `tsc --noEmit`
86
+
87
+ ## References
88
+
89
+ - `src/acl.ts` -- ACL class and ACLRule interface
90
+ - `src/utils/pattern.ts` -- matchPattern wildcard utility
91
+ - `src/errors.ts` -- ACLDeniedError, ACLRuleError, ConfigNotFoundError
92
+ - `src/context.ts` -- Context and Identity types (consumed by ACL)