@acpfx/core 0.2.0 → 0.4.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,41 @@
1
1
  # @acpfx/core
2
2
 
3
+ ## 0.4.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 05c4208: Embed manifest.yaml via include_str in native binaries (no hardcoded inline). Fix realpathSync for npx symlink manifest resolution. Remove speaker dep from audio-player.
8
+
9
+ ## 0.4.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 0e6838e: Add local on-device STT and TTS nodes (no API keys required). Introduces --acpfx-\* flag convention with setup phase for first-time model downloads, dynamic release pipeline with dual CPU/CUDA builds, MLX acceleration on Mac, and TUI improvements for speech event display.
14
+
15
+ ## 0.3.0
16
+
17
+ ### Minor Changes
18
+
19
+ - a0320a1: Add manifest argument/env schema, config system, pipeline resolver, and onboarding TUI
20
+
21
+ - **Manifest schema**: Node manifests now declare typed `arguments` (string/number/boolean with defaults, enums, required) and `env` var requirements. Codegen produces TypeScript types + Zod schemas.
22
+ - **All 12 node manifests updated** with arguments and env declarations derived from source code audit.
23
+ - **Build-time validation**: `scripts/validate-manifests.ts` validates against generated Zod schema. Orchestrator validates settings at startup.
24
+ - **Config system**: `~/.acpfx/config.json` (global) and `.acpfx/config.json` (project) with env var layering. New CLI: `acpfx config`, `acpfx config set/get`.
25
+ - **Pipeline resolver**: `acpfx run [name]` resolves pipelines from .acpfx/pipelines/, ~/.acpfx/pipelines/, or bundled examples. `acpfx pipelines` lists available pipelines.
26
+ - **Onboarding TUI**: `acpfx onboard` for interactive pipeline creation from templates or scratch. Auto-triggered on first `acpfx run` with no default pipeline.
27
+
28
+ ### Patch Changes
29
+
30
+ - 79c6694: Consolidate mic-aec and mic-sox into unified mic-speaker node
31
+
32
+ - **Remove `node-mic-aec` and `node-mic-sox`**: Replaced by the native `node-mic-speaker` package with built-in AEC support.
33
+ - **Add `node-mic-speaker`**: Rust-based mic capture + speaker output with acoustic echo cancellation in a single node.
34
+ - **Simplify pipeline configs**: Remove deprecated AEC/sysvoice pipeline variants; update remaining configs to use `@acpfx/mic-speaker`.
35
+ - **Update audio-player**: Streamline to work with the new mic-speaker node.
36
+ - **Update orchestrator**: Onboarding, templates, and node runner adjusted for consolidated mic node.
37
+ - **Update tests**: Reflect removed packages and new node structure.
38
+
3
39
  ## 0.2.0
4
40
 
5
41
  ### Minor Changes
package/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2024-2026 acpfx contributors
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
14
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15
+ PERFORMANCE OF THIS SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # @acpfx/core
2
+
3
+ Shared types, Zod schemas, and manifest utilities for acpfx nodes. This package contains the generated TypeScript types and validation schemas derived from the canonical Rust schema definitions.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @acpfx/core
9
+ ```
10
+
11
+ ## What's Included
12
+
13
+ - **Generated types** -- TypeScript interfaces for all event types (`audio.chunk`, `speech.final`, `agent.delta`, etc.)
14
+ - **Zod schemas** -- Runtime validation for events
15
+ - **Manifest utilities** -- Helpers for loading and validating `manifest.yaml` files
16
+ - **Protocol helpers** -- Event construction and parsing
17
+
18
+ ## Usage
19
+
20
+ ```typescript
21
+ import { AudioChunkEvent, SpeechFinalEvent } from "@acpfx/core";
22
+ ```
23
+
24
+ Types are generated from the Rust schema crate via `cargo run -p acpfx-schema --bin acpfx-codegen`.
25
+
26
+ ## License
27
+
28
+ ISC
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acpfx/core",
3
- "version": "0.2.0",
3
+ "version": "0.4.1",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -0,0 +1,51 @@
1
+ /**
2
+ * acpfx flag protocol types and handler.
3
+ *
4
+ * All orchestrator-reserved flags use the `--acpfx-` prefix.
5
+ * Nodes that receive an unrecognized `--acpfx-*` flag should emit
6
+ * an UnsupportedFlagResponse and exit 0 (forward compatibility).
7
+ */
8
+
9
+ import { z } from "zod";
10
+
11
+ // ---- Types ----
12
+
13
+ /** Response from `--acpfx-setup-check`. */
14
+ export interface SetupCheckResponse {
15
+ needed: boolean;
16
+ description?: string;
17
+ }
18
+
19
+ /** Progress line from `--acpfx-setup` (NDJSON on stdout). */
20
+ export type SetupProgress =
21
+ | { type: "progress"; message: string; pct?: number }
22
+ | { type: "complete"; message: string }
23
+ | { type: "error"; message: string };
24
+
25
+ /** Response for unrecognized `--acpfx-*` flags (forward compatibility). */
26
+ export interface UnsupportedFlagResponse {
27
+ unsupported: boolean;
28
+ flag: string;
29
+ }
30
+
31
+ // ---- Zod Schemas ----
32
+
33
+ export const SetupCheckResponseSchema = z.object({
34
+ needed: z.boolean(),
35
+ description: z.string().optional(),
36
+ });
37
+
38
+ export const SetupProgressSchema = z.discriminatedUnion("type", [
39
+ z.object({
40
+ type: z.literal("progress"),
41
+ message: z.string(),
42
+ pct: z.number().optional(),
43
+ }),
44
+ z.object({ type: z.literal("complete"), message: z.string() }),
45
+ z.object({ type: z.literal("error"), message: z.string() }),
46
+ ]);
47
+
48
+ export const UnsupportedFlagResponseSchema = z.object({
49
+ unsupported: z.boolean(),
50
+ flag: z.string(),
51
+ });
package/src/manifest.ts CHANGED
@@ -1,48 +1,141 @@
1
1
  /**
2
- * Manifest utilities for acpfx nodes.
2
+ * Manifest types, Zod schemas, and acpfx flag handling for nodes.
3
3
  *
4
- * Call `handleManifestFlag()` at the top of your node's entry point.
5
- * If `--manifest` is in argv, it prints the manifest as JSON and exits.
4
+ * Call `handleAcpfxFlags()` at the top of your node's entry point.
5
+ * It handles all `--acpfx-*` convention flags:
6
+ * --acpfx-manifest Print manifest JSON and exit
7
+ * --acpfx-setup-check Print {"needed": false} and exit (TS nodes don't need setup)
8
+ * --acpfx-* (unknown) Print {"unsupported": true, "flag": "..."} and exit
6
9
  */
7
10
 
8
11
  import { readFileSync } from "node:fs";
9
12
  import { join, dirname } from "node:path";
13
+ import { fileURLToPath } from "node:url";
14
+ import { z } from "zod";
15
+
16
+ // ---- Manifest Types ----
17
+
18
+ export type ArgumentType = "string" | "number" | "boolean";
19
+
20
+ export interface ManifestArgument {
21
+ type: ArgumentType;
22
+ default?: unknown;
23
+ description?: string;
24
+ required?: boolean;
25
+ enum?: unknown[];
26
+ }
27
+
28
+ export interface ManifestEnvField {
29
+ required?: boolean;
30
+ description?: string;
31
+ }
10
32
 
11
33
  export interface NodeManifest {
12
34
  name: string;
13
35
  description?: string;
14
36
  consumes: string[];
15
37
  emits: string[];
38
+ arguments?: Record<string, ManifestArgument>;
39
+ additional_arguments?: boolean;
40
+ env?: Record<string, ManifestEnvField>;
16
41
  }
17
42
 
43
+ // ---- Manifest Zod Schemas ----
44
+
45
+ export const ArgumentTypeSchema = z.enum(["string", "number", "boolean"]);
46
+
47
+ export const ManifestArgumentSchema = z.object({
48
+ type: ArgumentTypeSchema,
49
+ default: z.unknown().optional(),
50
+ description: z.string().optional(),
51
+ required: z.boolean().optional(),
52
+ enum: z.array(z.unknown()).optional(),
53
+ });
54
+
55
+ export const ManifestEnvFieldSchema = z.object({
56
+ required: z.boolean().optional(),
57
+ description: z.string().optional(),
58
+ });
59
+
60
+ export const NodeManifestSchema = z.object({
61
+ name: z.string(),
62
+ description: z.string().optional(),
63
+ consumes: z.array(z.string()),
64
+ emits: z.array(z.string()),
65
+ arguments: z.record(z.string(), ManifestArgumentSchema).optional(),
66
+ additional_arguments: z.boolean().optional(),
67
+ env: z.record(z.string(), ManifestEnvFieldSchema).optional(),
68
+ });
69
+
70
+ // ---- acpfx Flag Protocol Types ----
71
+
72
+ export type {
73
+ SetupCheckResponse,
74
+ SetupProgress,
75
+ UnsupportedFlagResponse,
76
+ } from "./acpfx-flags.js";
77
+
78
+ export {
79
+ SetupCheckResponseSchema,
80
+ SetupProgressSchema,
81
+ UnsupportedFlagResponseSchema,
82
+ } from "./acpfx-flags.js";
83
+
84
+ // ---- Flag Handling ----
85
+
18
86
  /**
19
- * If `--manifest` is in process.argv, read the co-located manifest.json,
20
- * print it to stdout, and exit(0).
87
+ * Handle all `--acpfx-*` convention flags.
21
88
  *
22
- * Resolution order:
23
- * 1. Explicit `manifestPath` if provided
24
- * 2. `<script-base>.manifest.json` (bundled: dist/nodes/foo.js -> foo.manifest.json)
25
- * 3. `manifest.json` in the script's directory
89
+ * Must be called at the top of every node's entry point (before any async work).
90
+ * Also supports legacy `--manifest` for backward compatibility.
91
+ */
92
+ export function handleAcpfxFlags(manifestPath?: string): void {
93
+ const acpfxFlag = process.argv.find((a) => a.startsWith("--acpfx-"));
94
+ const legacyManifest = process.argv.includes("--manifest");
95
+
96
+ if (!acpfxFlag && !legacyManifest) return;
97
+
98
+ const flag = acpfxFlag ?? "--acpfx-manifest";
99
+
100
+ switch (flag) {
101
+ case "--acpfx-manifest":
102
+ printManifest(manifestPath);
103
+ break;
104
+
105
+ case "--acpfx-setup-check":
106
+ process.stdout.write(JSON.stringify({ needed: false }) + "\n");
107
+ process.exit(0);
108
+ break;
109
+
110
+ default:
111
+ process.stdout.write(
112
+ JSON.stringify({ unsupported: true, flag }) + "\n"
113
+ );
114
+ process.exit(0);
115
+ }
116
+ }
117
+
118
+ /**
119
+ * @deprecated Use `handleAcpfxFlags()` instead.
26
120
  */
27
121
  export function handleManifestFlag(manifestPath?: string): void {
28
- if (!process.argv.includes("--manifest")) return;
122
+ handleAcpfxFlags(manifestPath);
123
+ }
29
124
 
125
+ /**
126
+ * Print the co-located manifest JSON to stdout and exit.
127
+ */
128
+ function printManifest(manifestPath?: string): void {
30
129
  if (!manifestPath) {
31
- const script = process.argv[1];
32
- const scriptDir = dirname(script);
33
- const scriptBase = script.replace(/\.[^.]+$/, "");
34
- const colocated = `${scriptBase}.manifest.json`;
35
- try {
36
- readFileSync(colocated);
37
- manifestPath = colocated;
38
- } catch {
39
- manifestPath = join(scriptDir, "manifest.json");
40
- }
130
+ // Use import.meta.url to find the bundle's real location on disk.
131
+ // This works even when invoked via npx symlinks in .bin/ because
132
+ // import.meta.url resolves to the actual file, not the symlink.
133
+ const bundleDir = dirname(fileURLToPath(import.meta.url));
134
+ manifestPath = join(bundleDir, "manifest.json");
41
135
  }
42
136
 
43
137
  try {
44
138
  const content = readFileSync(manifestPath, "utf8");
45
- // Already JSON — just write it out
46
139
  process.stdout.write(content.trim() + "\n");
47
140
  process.exit(0);
48
141
  } catch (err) {