@chiralkit/cli 0.1.0-alpha.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/LICENSE +21 -0
- package/README.md +97 -0
- package/dist/add.d.ts +4 -0
- package/dist/add.js +118 -0
- package/dist/add.js.map +1 -0
- package/dist/agents/subprocess.d.ts +10 -0
- package/dist/agents/subprocess.js +43 -0
- package/dist/agents/subprocess.js.map +1 -0
- package/dist/automation/index.d.ts +14 -0
- package/dist/automation/index.js +129 -0
- package/dist/automation/index.js.map +1 -0
- package/dist/automation/install.d.ts +19 -0
- package/dist/automation/install.js +116 -0
- package/dist/automation/install.js.map +1 -0
- package/dist/automation/parsers/audit-report.d.ts +2 -0
- package/dist/automation/parsers/audit-report.js +42 -0
- package/dist/automation/parsers/audit-report.js.map +1 -0
- package/dist/automation/parsers/exit-code.d.ts +2 -0
- package/dist/automation/parsers/exit-code.js +6 -0
- package/dist/automation/parsers/exit-code.js.map +1 -0
- package/dist/automation/parsers/index.d.ts +10 -0
- package/dist/automation/parsers/index.js +13 -0
- package/dist/automation/parsers/index.js.map +1 -0
- package/dist/automation/parsers/observer-snapshot.d.ts +2 -0
- package/dist/automation/parsers/observer-snapshot.js +30 -0
- package/dist/automation/parsers/observer-snapshot.js.map +1 -0
- package/dist/automation/parsers/plan-report.d.ts +2 -0
- package/dist/automation/parsers/plan-report.js +53 -0
- package/dist/automation/parsers/plan-report.js.map +1 -0
- package/dist/automation/parsers/refinement-report.d.ts +2 -0
- package/dist/automation/parsers/refinement-report.js +149 -0
- package/dist/automation/parsers/refinement-report.js.map +1 -0
- package/dist/automation/parsers/types.d.ts +7 -0
- package/dist/automation/parsers/types.js +2 -0
- package/dist/automation/parsers/types.js.map +1 -0
- package/dist/automation/run.d.ts +25 -0
- package/dist/automation/run.js +68 -0
- package/dist/automation/run.js.map +1 -0
- package/dist/automation/schema.d.ts +130 -0
- package/dist/automation/schema.js +46 -0
- package/dist/automation/schema.js.map +1 -0
- package/dist/automation/status.d.ts +16 -0
- package/dist/automation/status.js +56 -0
- package/dist/automation/status.js.map +1 -0
- package/dist/automation/verifiers/index.d.ts +7 -0
- package/dist/automation/verifiers/index.js +5 -0
- package/dist/automation/verifiers/index.js.map +1 -0
- package/dist/automation/verifiers/shell.d.ts +5 -0
- package/dist/automation/verifiers/shell.js +17 -0
- package/dist/automation/verifiers/shell.js.map +1 -0
- package/dist/automation/verifiers/types.d.ts +12 -0
- package/dist/automation/verifiers/types.js +2 -0
- package/dist/automation/verifiers/types.js.map +1 -0
- package/dist/backlog/add.d.ts +10 -0
- package/dist/backlog/add.js +30 -0
- package/dist/backlog/add.js.map +1 -0
- package/dist/backlog/index.d.ts +1 -0
- package/dist/backlog/index.js +53 -0
- package/dist/backlog/index.js.map +1 -0
- package/dist/config.d.ts +26 -0
- package/dist/config.js +110 -0
- package/dist/config.js.map +1 -0
- package/dist/detect.d.ts +2 -0
- package/dist/detect.js +26 -0
- package/dist/detect.js.map +1 -0
- package/dist/doctor-invariants.d.ts +6 -0
- package/dist/doctor-invariants.js +50 -0
- package/dist/doctor-invariants.js.map +1 -0
- package/dist/doctor.d.ts +13 -0
- package/dist/doctor.js +281 -0
- package/dist/doctor.js.map +1 -0
- package/dist/generate.d.ts +1 -0
- package/dist/generate.js +275 -0
- package/dist/generate.js.map +1 -0
- package/dist/generator/agent.d.ts +8 -0
- package/dist/generator/agent.js +66 -0
- package/dist/generator/agent.js.map +1 -0
- package/dist/generator/api.d.ts +7 -0
- package/dist/generator/api.js +42 -0
- package/dist/generator/api.js.map +1 -0
- package/dist/generator/config.d.ts +23 -0
- package/dist/generator/config.js +121 -0
- package/dist/generator/config.js.map +1 -0
- package/dist/generator/parse-response.d.ts +5 -0
- package/dist/generator/parse-response.js +58 -0
- package/dist/generator/parse-response.js.map +1 -0
- package/dist/generator/prompt.d.ts +9 -0
- package/dist/generator/prompt.js +166 -0
- package/dist/generator/prompt.js.map +1 -0
- package/dist/generator/request.d.ts +17 -0
- package/dist/generator/request.js +15 -0
- package/dist/generator/request.js.map +1 -0
- package/dist/generators/prompts/stencil.md +45 -0
- package/dist/generators/prompts/vue.md +54 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +102 -0
- package/dist/index.js.map +1 -0
- package/dist/init.d.ts +1 -0
- package/dist/init.js +89 -0
- package/dist/init.js.map +1 -0
- package/dist/installers/context.d.ts +4 -0
- package/dist/installers/context.js +120 -0
- package/dist/installers/context.js.map +1 -0
- package/dist/installers/index.d.ts +7 -0
- package/dist/installers/index.js +22 -0
- package/dist/installers/index.js.map +1 -0
- package/dist/installers/installer.d.ts +12 -0
- package/dist/installers/installer.js +30 -0
- package/dist/installers/installer.js.map +1 -0
- package/dist/installers/stencil/django-template/installer.d.ts +10 -0
- package/dist/installers/stencil/django-template/installer.js +77 -0
- package/dist/installers/stencil/django-template/installer.js.map +1 -0
- package/dist/installers/stencil/react/installer.d.ts +9 -0
- package/dist/installers/stencil/react/installer.js +22 -0
- package/dist/installers/stencil/react/installer.js.map +1 -0
- package/dist/installers/stencil/react/manifest.json +17 -0
- package/dist/installers/types.d.ts +24 -0
- package/dist/installers/types.js +2 -0
- package/dist/installers/types.js.map +1 -0
- package/dist/lock.d.ts +25 -0
- package/dist/lock.js +86 -0
- package/dist/lock.js.map +1 -0
- package/dist/manifest.d.ts +1 -0
- package/dist/manifest.js +93 -0
- package/dist/manifest.js.map +1 -0
- package/dist/pm/audit.d.ts +36 -0
- package/dist/pm/audit.js +147 -0
- package/dist/pm/audit.js.map +1 -0
- package/dist/pm/backlog.d.ts +3 -0
- package/dist/pm/backlog.js +123 -0
- package/dist/pm/backlog.js.map +1 -0
- package/dist/pm/brief.d.ts +4 -0
- package/dist/pm/brief.js +18 -0
- package/dist/pm/brief.js.map +1 -0
- package/dist/pm/git.d.ts +3 -0
- package/dist/pm/git.js +43 -0
- package/dist/pm/git.js.map +1 -0
- package/dist/pm/grid.d.ts +8 -0
- package/dist/pm/grid.js +16 -0
- package/dist/pm/grid.js.map +1 -0
- package/dist/pm/index.d.ts +25 -0
- package/dist/pm/index.js +199 -0
- package/dist/pm/index.js.map +1 -0
- package/dist/pm/observe.d.ts +55 -0
- package/dist/pm/observe.js +177 -0
- package/dist/pm/observe.js.map +1 -0
- package/dist/pm/plan.d.ts +54 -0
- package/dist/pm/plan.js +151 -0
- package/dist/pm/plan.js.map +1 -0
- package/dist/pm/refinement-worktree.d.ts +31 -0
- package/dist/pm/refinement-worktree.js +160 -0
- package/dist/pm/refinement-worktree.js.map +1 -0
- package/dist/pm/refinement.d.ts +79 -0
- package/dist/pm/refinement.js +326 -0
- package/dist/pm/refinement.js.map +1 -0
- package/dist/pm/render.d.ts +2 -0
- package/dist/pm/render.js +39 -0
- package/dist/pm/render.js.map +1 -0
- package/dist/pm/roadmap-rings.d.ts +7 -0
- package/dist/pm/roadmap-rings.js +31 -0
- package/dist/pm/roadmap-rings.js.map +1 -0
- package/dist/pm/roadmap.d.ts +2 -0
- package/dist/pm/roadmap.js +118 -0
- package/dist/pm/roadmap.js.map +1 -0
- package/dist/pm/snapshot.d.ts +10 -0
- package/dist/pm/snapshot.js +129 -0
- package/dist/pm/snapshot.js.map +1 -0
- package/dist/pm/types.d.ts +99 -0
- package/dist/pm/types.js +29 -0
- package/dist/pm/types.js.map +1 -0
- package/dist/registry-layout.d.ts +18 -0
- package/dist/registry-layout.js +122 -0
- package/dist/registry-layout.js.map +1 -0
- package/dist/scaffold-registry.d.ts +10 -0
- package/dist/scaffold-registry.js +283 -0
- package/dist/scaffold-registry.js.map +1 -0
- package/dist/scaffold.d.ts +1 -0
- package/dist/scaffold.js +32 -0
- package/dist/scaffold.js.map +1 -0
- package/dist/spec-from-react.d.ts +11 -0
- package/dist/spec-from-react.js +522 -0
- package/dist/spec-from-react.js.map +1 -0
- package/dist/spec-from-stencil.d.ts +7 -0
- package/dist/spec-from-stencil.js +275 -0
- package/dist/spec-from-stencil.js.map +1 -0
- package/dist/spec.d.ts +1 -0
- package/dist/spec.js +60 -0
- package/dist/spec.js.map +1 -0
- package/dist/tokens-map.d.ts +11 -0
- package/dist/tokens-map.js +43 -0
- package/dist/tokens-map.js.map +1 -0
- package/dist/update.d.ts +39 -0
- package/dist/update.js +490 -0
- package/dist/update.js.map +1 -0
- package/dist/workspace-init.d.ts +9 -0
- package/dist/workspace-init.js +119 -0
- package/dist/workspace-init.js.map +1 -0
- package/package.json +53 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 xHadal
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# @chiralkit/cli
|
|
2
|
+
|
|
3
|
+
CLI for the Chiralkit registry.
|
|
4
|
+
|
|
5
|
+
## Commands
|
|
6
|
+
|
|
7
|
+
- `chiralkit init [--maintainer]` — write `ck/chiralkit.config.json`. Without `--maintainer`, detects a consumer framework and writes the consumer flavor. With `--maintainer`, writes (or merges into) a `maintainer` block with `design_system_path` + `registry_path`, enabling `scaffold registry` in this repo.
|
|
8
|
+
- `chiralkit add <module>` — copy a module's files into the current project.
|
|
9
|
+
- `chiralkit spec from-stencil <name>` — draft a `spec.json` from a Stencil component's source.
|
|
10
|
+
- `chiralkit scaffold registry <name> [--force]` — onboard a Stencil component from `<designSystemPath>/ds-<name>/` into the registry (envelope + spec + reversed symlinks + `generation.json`).
|
|
11
|
+
- `chiralkit generate <name> [--stack <s>] [--dry-run] [--debug-prompt] [--force]` — LLM-generate a stack implementation from `spec.json`.
|
|
12
|
+
- `chiralkit doctor` — lint the registry (envelopes, specs, implementations).
|
|
13
|
+
|
|
14
|
+
## `generate` — two modes
|
|
15
|
+
|
|
16
|
+
The generator reads `registry/generator.config.json`. It supports two modes; pick whichever fits.
|
|
17
|
+
|
|
18
|
+
### Agent mode (default; no API key required)
|
|
19
|
+
|
|
20
|
+
Uses whatever local LLM agent CLI you have installed. Only Claude Code is wired today (`claude -p`); Aider / Codex CLI / gemini-cli are extensions.
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"generator": {
|
|
25
|
+
"agent": "claude-code"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Prerequisite: `claude` binary on PATH (https://docs.claude.com/claude-code/quickstart).
|
|
31
|
+
|
|
32
|
+
### API mode
|
|
33
|
+
|
|
34
|
+
Direct call to the Vercel AI SDK. Requires the provider's env var (`ANTHROPIC_API_KEY` for the `anthropic` provider).
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"generator": {
|
|
39
|
+
"model": "anthropic/claude-opus-4-8"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Adding a provider = `pnpm --filter @chiralkit/cli add @ai-sdk/<provider>` + one case in `resolveModel()` at `src/generator/config.ts`.
|
|
45
|
+
|
|
46
|
+
### Flags
|
|
47
|
+
|
|
48
|
+
- `--stack <name>` — generate for a specific stack (defaults: every existing `implementations/<stack>/` folder).
|
|
49
|
+
- `--dry-run` — call the LLM but do not write files; print the response.
|
|
50
|
+
- `--debug-prompt` — print the prompt that WOULD be sent (AI SDK messages JSON in API mode; plaintext stdin in agent mode) and exit; do NOT invoke the LLM. Useful for debugging and for manually pasting into an agent that isn't wired yet.
|
|
51
|
+
- `--force` — overwrite even if `generation.json.manually_edited` is `true`.
|
|
52
|
+
|
|
53
|
+
## `scaffold registry` — onboarding a Stencil component
|
|
54
|
+
|
|
55
|
+
Reads a `maintainer` block from `ck/chiralkit.config.json`:
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"maintainer": {
|
|
60
|
+
"design_system_path": "packages/design-system/src/components",
|
|
61
|
+
"registry_path": "registry"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Given `<designSystemPath>/ds-<name>/ds-<name>.tsx` + `ds-<name>.css` (plus any companion files), `scaffold registry <name>` writes:
|
|
67
|
+
|
|
68
|
+
1. `<registryPath>/<name>/component.json` — envelope with parsed `tag` + flattened `tokens_used`. Human fields (`description`, `category`, `translations`) start as sensible placeholders (`description: "TODO: describe <name>"`, `category: "primitive"`, `translations: {}`) — edit them after.
|
|
69
|
+
2. `<registryPath>/<name>/spec.json` — via `spec from-stencil`.
|
|
70
|
+
3. `<registryPath>/<name>/implementations/stencil/*` — per-file reversed symlinks (git mode 120000) into the source dir. Files-only, hidden-file-skipping, sub-directory-skipping. `--force` first sweeps any pre-existing symlinks so orphans don't survive source-file renames.
|
|
71
|
+
4. `<registryPath>/<name>/implementations/stencil/generation.json` — baseline `{manually_edited: true, ...nulls}`.
|
|
72
|
+
|
|
73
|
+
Refuses if the target already exists; pass `--force` to overwrite. When `--force` regenerates over an existing `spec.json` that had hand-authored `slot`, `a11y`, or `state_machine` fields (which `runFromStencil` doesn't extract), scaffold prints a `[WARN]` naming the dropped fields — re-add them before running `chiralkit doctor`.
|
|
74
|
+
|
|
75
|
+
## PM roadmap dashboard
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
ck pm # deterministic local dashboard; no model required
|
|
79
|
+
ck pm --brief # same snapshot plus the read-only ck-pm interpretation
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The dashboard reads `ROADMAP.md` and `BACKLOG.md` independently, then adds active Git worktrees as operational context. Git inspection failures degrade only the Git section.
|
|
83
|
+
|
|
84
|
+
Backlog tasks use explicit metadata:
|
|
85
|
+
|
|
86
|
+
```md
|
|
87
|
+
- [ ] [fib:3] [priority:P1] [status:ready] Task text
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
- `fib`: `0 | 1 | 2 | 3 | 5 | 8 | 13`, expressing relative effort, difficulty, and time—not hours.
|
|
91
|
+
- `priority`: `P0 | P1 | P2 | P3`, expressing attraction toward doing the task now.
|
|
92
|
+
- `status`: `ready | active | blocked | done`.
|
|
93
|
+
- `[x]` requires `status:done`; unchecked tasks cannot be `done`.
|
|
94
|
+
|
|
95
|
+
Priority and Fibonacci are the planning pair `attraction ↔ resistance`; they remain separate and are never collapsed into one score. Missing or invalid metadata appears under `INVALID` and makes `ck pm` exit non-zero without hiding the rest of the dashboard. Tasks at `fib:8` or `fib:13` produce a decomposition warning, not an error.
|
|
96
|
+
|
|
97
|
+
`ck pm --brief` sends only the deterministic `ProjectSnapshot` to the L5 `ck-pm` persona. The agent cannot edit files, mutate Git, or infer missing planning data.
|
package/dist/add.d.ts
ADDED
package/dist/add.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { readFile, readdir, stat } from "node:fs/promises";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { parseModule, } from "@chiralkit/registry-schema";
|
|
4
|
+
import { resolveKitsRoot } from "@chiralkit/kits";
|
|
5
|
+
import { readConfig } from "./config.js";
|
|
6
|
+
import { createInstallContext, findInstaller } from "./installers/index.js";
|
|
7
|
+
import { hashFile, legacyLockExists, legacyLockMigrationHint, lockExists, lockKey, readLock, toRelativePosix, writeLock, } from "./lock.js";
|
|
8
|
+
import { MODULE_ENVELOPE_FILENAME, TYPE_TO_FAMILY, walkAllKitRegistries, } from "./registry-layout.js";
|
|
9
|
+
// Resolves a module name to its envelope path by walking every kit's
|
|
10
|
+
// registry/<family>/<name>/ layout, family- and kit-agnostically. `type`,
|
|
11
|
+
// when given, narrows the search to a single family up front — useful once
|
|
12
|
+
// a name collides across families (see the ambiguity error below).
|
|
13
|
+
async function resolveModuleRef(kitsRoot, moduleName, type) {
|
|
14
|
+
const modules = await walkAllKitRegistries(kitsRoot);
|
|
15
|
+
const matches = modules.filter((m) => m.name === moduleName && (type === undefined || m.family === TYPE_TO_FAMILY[type]));
|
|
16
|
+
if (matches.length === 0) {
|
|
17
|
+
throw new Error(type
|
|
18
|
+
? `Module '${moduleName}' (type '${type}') not found under ${kitsRoot}.`
|
|
19
|
+
: `Module '${moduleName}' not found under ${kitsRoot}.`);
|
|
20
|
+
}
|
|
21
|
+
if (matches.length > 1) {
|
|
22
|
+
const families = matches.map((m) => m.family).join(", ");
|
|
23
|
+
throw new Error(`Module '${moduleName}' exists in multiple families (${families}). Pass --type <t> to disambiguate.`);
|
|
24
|
+
}
|
|
25
|
+
return matches[0];
|
|
26
|
+
}
|
|
27
|
+
export async function runAdd(moduleName, cwd = process.cwd(), opts = {}) {
|
|
28
|
+
const config = await readConfig(cwd);
|
|
29
|
+
const registryRoot = resolve(cwd, config.registry_path);
|
|
30
|
+
const ref = await resolveModuleRef(resolveKitsRoot(), moduleName, opts.type);
|
|
31
|
+
let raw;
|
|
32
|
+
try {
|
|
33
|
+
raw = await readFile(ref.envelopePath, "utf8");
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
throw new Error(`Module '${moduleName}' not found at ${ref.envelopePath}.`);
|
|
37
|
+
}
|
|
38
|
+
const mod = parseModule(JSON.parse(raw));
|
|
39
|
+
if (mod.type !== "ui-component") {
|
|
40
|
+
throw new Error(`Only ui-component modules supported in v0. Got: ${mod.type}`);
|
|
41
|
+
}
|
|
42
|
+
const spec = mod.spec;
|
|
43
|
+
const installer = findInstaller(spec.tech, config.framework);
|
|
44
|
+
if (!installer.supports(mod)) {
|
|
45
|
+
throw new Error(`Installer for '${spec.tech}' × '${config.framework}' does not support module '${mod.name}'.`);
|
|
46
|
+
}
|
|
47
|
+
const ctx = createInstallContext(cwd, registryRoot, config);
|
|
48
|
+
await installer.install(mod, ctx);
|
|
49
|
+
await recordInstall(cwd, ref, mod, config.paths.components);
|
|
50
|
+
console.log(`Added: ${mod.name}@${mod.metadata.version} (${spec.tech} → ${config.framework})`);
|
|
51
|
+
}
|
|
52
|
+
// Appends (or replaces) the module's entry in chiralkit.lock.json. Runs
|
|
53
|
+
// after the installer, so writing succeeds only when the copy did. When
|
|
54
|
+
// the lock does not exist yet, it is created — 'add' is the natural
|
|
55
|
+
// bootstrap point so first-time projects do not need to run 'lock --init'
|
|
56
|
+
// before they have anything to lock.
|
|
57
|
+
async function recordInstall(cwd, ref, mod, componentsRel) {
|
|
58
|
+
if (!(await lockExists(cwd)) && (await legacyLockExists(cwd))) {
|
|
59
|
+
throw new Error(legacyLockMigrationHint(cwd));
|
|
60
|
+
}
|
|
61
|
+
const lock = (await lockExists(cwd))
|
|
62
|
+
? await readLock(cwd)
|
|
63
|
+
: { modules: {} };
|
|
64
|
+
const componentsAbs = resolve(cwd, componentsRel);
|
|
65
|
+
const registryBases = await collectRegistryFileBasenames(ref.moduleDir);
|
|
66
|
+
const files = {};
|
|
67
|
+
for (const base of registryBases) {
|
|
68
|
+
const abs = join(componentsAbs, base);
|
|
69
|
+
try {
|
|
70
|
+
const h = await hashFile(abs);
|
|
71
|
+
files[toRelativePosix(cwd, abs)] = h;
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
// File was in the registry but not written to the consumer; skip.
|
|
75
|
+
// This happens on stacks where component.assets covers only a
|
|
76
|
+
// subset of the registry source tree (e.g. Django ships from
|
|
77
|
+
// runtime.assets, not per-component).
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
lock.modules[lockKey(mod.name, mod.type)] = {
|
|
81
|
+
type: mod.type,
|
|
82
|
+
version: mod.metadata.version,
|
|
83
|
+
installed_at: new Date().toISOString(),
|
|
84
|
+
files,
|
|
85
|
+
};
|
|
86
|
+
await writeLock(cwd, lock);
|
|
87
|
+
}
|
|
88
|
+
async function collectRegistryFileBasenames(moduleDir) {
|
|
89
|
+
const out = [];
|
|
90
|
+
async function walk(dir) {
|
|
91
|
+
let entries;
|
|
92
|
+
try {
|
|
93
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
for (const e of entries) {
|
|
99
|
+
const p = join(dir, e.name);
|
|
100
|
+
if (e.isDirectory()) {
|
|
101
|
+
await walk(p);
|
|
102
|
+
}
|
|
103
|
+
else if (e.isFile() || e.isSymbolicLink()) {
|
|
104
|
+
try {
|
|
105
|
+
const s = await stat(p);
|
|
106
|
+
if (s.isFile())
|
|
107
|
+
out.push(e.name);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
/* dangling symlink; skip */
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
await walk(moduleDir);
|
|
116
|
+
return out.filter((b) => b !== MODULE_ENVELOPE_FILENAME && b !== "spec.json");
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=add.js.map
|
package/dist/add.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add.js","sourceRoot":"","sources":["../src/add.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface AgentInvocation {
|
|
2
|
+
bin: string;
|
|
3
|
+
args: string[];
|
|
4
|
+
label: string;
|
|
5
|
+
}
|
|
6
|
+
export interface LocalAgentOptions {
|
|
7
|
+
timeoutMs?: number;
|
|
8
|
+
onStderr?: (chunk: string) => void;
|
|
9
|
+
}
|
|
10
|
+
export declare function runLocalAgent(invocation: AgentInvocation, prompt: string, options?: LocalAgentOptions): Promise<string>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
export function runLocalAgent(invocation, prompt, options = {}) {
|
|
3
|
+
return new Promise((resolve, reject) => {
|
|
4
|
+
const child = spawn(invocation.bin, invocation.args, { stdio: ["pipe", "pipe", "pipe"] });
|
|
5
|
+
let stdout = "";
|
|
6
|
+
let stderr = "";
|
|
7
|
+
let settled = false;
|
|
8
|
+
const timer = setTimeout(() => {
|
|
9
|
+
if (settled)
|
|
10
|
+
return;
|
|
11
|
+
settled = true;
|
|
12
|
+
child.kill("SIGTERM");
|
|
13
|
+
reject(new Error(`${invocation.label} timed out after ${options.timeoutMs ?? 300_000}ms`));
|
|
14
|
+
}, options.timeoutMs ?? 300_000);
|
|
15
|
+
child.stdout.on("data", (chunk) => { stdout += chunk.toString("utf8"); });
|
|
16
|
+
child.stderr.on("data", (chunk) => {
|
|
17
|
+
const value = chunk.toString("utf8");
|
|
18
|
+
stderr = (stderr + value).slice(-8000);
|
|
19
|
+
options.onStderr?.(value);
|
|
20
|
+
});
|
|
21
|
+
child.on("error", (error) => {
|
|
22
|
+
if (settled)
|
|
23
|
+
return;
|
|
24
|
+
settled = true;
|
|
25
|
+
clearTimeout(timer);
|
|
26
|
+
reject(new Error(error.code === "ENOENT" ? `${invocation.label}: binary '${invocation.bin}' not found` : `${invocation.label}: ${error.message}`));
|
|
27
|
+
});
|
|
28
|
+
child.on("close", (code) => {
|
|
29
|
+
if (settled)
|
|
30
|
+
return;
|
|
31
|
+
settled = true;
|
|
32
|
+
clearTimeout(timer);
|
|
33
|
+
if (code !== 0)
|
|
34
|
+
return reject(new Error(`${invocation.label} exited with code ${code}.\n--- last stderr ---\n${stderr}`));
|
|
35
|
+
if (!stdout.trim())
|
|
36
|
+
return reject(new Error(`${invocation.label} produced empty stdout.\n--- last stderr ---\n${stderr}`));
|
|
37
|
+
resolve(stdout);
|
|
38
|
+
});
|
|
39
|
+
child.stdin.on("error", () => { });
|
|
40
|
+
child.stdin.end(prompt);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=subprocess.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subprocess.js","sourceRoot":"","sources":["../../src/agents/subprocess.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type RunRecord } from "./run.js";
|
|
2
|
+
import { type AutomationRow } from "./status.js";
|
|
3
|
+
export interface AutomationCommandDependencies {
|
|
4
|
+
stdout: (value: string) => void;
|
|
5
|
+
stderr: (value: string) => void;
|
|
6
|
+
cwd: () => string;
|
|
7
|
+
getStatus: (cwd: string) => Promise<AutomationRow[]>;
|
|
8
|
+
doRun: (name: string, cwd: string) => Promise<RunRecord>;
|
|
9
|
+
doInstall: (name: string, cwd: string) => Promise<void>;
|
|
10
|
+
doUninstall: (name: string, cwd: string) => Promise<void>;
|
|
11
|
+
readConfig: (name: string, cwd: string) => Promise<unknown>;
|
|
12
|
+
readTail: (name: string, cwd: string, count: number) => Promise<string[]>;
|
|
13
|
+
}
|
|
14
|
+
export declare function runAutomationCommand(argv: string[], overrides?: Partial<AutomationCommandDependencies>): Promise<number>;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { access, mkdir, readFile, readdir, rm, writeFile, appendFile } from "node:fs/promises";
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
3
|
+
import { promisify } from "node:util";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { runAutomation } from "./run.js";
|
|
7
|
+
import { installAutomation, uninstallAutomation } from "./install.js";
|
|
8
|
+
import { getAutomationStatus } from "./status.js";
|
|
9
|
+
import { parseAutomationConfig } from "./schema.js";
|
|
10
|
+
const execFileAsync = promisify(execFile);
|
|
11
|
+
async function fileExists(path) {
|
|
12
|
+
try {
|
|
13
|
+
await access(path);
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const defaults = {
|
|
21
|
+
stdout: (v) => process.stdout.write(v),
|
|
22
|
+
stderr: (v) => process.stderr.write(v),
|
|
23
|
+
cwd: () => process.cwd(),
|
|
24
|
+
getStatus: (cwd) => getAutomationStatus(cwd, {
|
|
25
|
+
listDir: (path) => readdir(path),
|
|
26
|
+
readText: (path) => readFile(path, "utf8"),
|
|
27
|
+
fileExists,
|
|
28
|
+
}),
|
|
29
|
+
doRun: (name, cwd) => runAutomation(name, cwd, {
|
|
30
|
+
now: () => new Date(),
|
|
31
|
+
readText: (p) => readFile(p, "utf8"),
|
|
32
|
+
appendLine: async (p, l) => { await appendFile(p, l + "\n"); },
|
|
33
|
+
writeText: (p, c) => writeFile(p, c),
|
|
34
|
+
readLines: async (p) => { const t = await readFile(p, "utf8").catch(() => ""); return t.split(/\r?\n/).filter(Boolean); },
|
|
35
|
+
}),
|
|
36
|
+
doInstall: (name, cwd) => installAutomation(name, cwd, {
|
|
37
|
+
home: homedir(),
|
|
38
|
+
launchctl: async (args) => { await execFileAsync("launchctl", args); },
|
|
39
|
+
writeText: async (p, c) => { await mkdir(join(homedir(), "Library", "LaunchAgents"), { recursive: true }); await writeFile(p, c); },
|
|
40
|
+
removeFile: (p) => rm(p, { force: true }),
|
|
41
|
+
fileExists,
|
|
42
|
+
nodePath: process.execPath,
|
|
43
|
+
repoRoot: cwd,
|
|
44
|
+
}),
|
|
45
|
+
doUninstall: (name, cwd) => uninstallAutomation(name, cwd, {
|
|
46
|
+
home: homedir(),
|
|
47
|
+
launchctl: async (args) => { await execFileAsync("launchctl", args); },
|
|
48
|
+
writeText: () => Promise.resolve(),
|
|
49
|
+
removeFile: (p) => rm(p, { force: true }),
|
|
50
|
+
fileExists,
|
|
51
|
+
nodePath: process.execPath,
|
|
52
|
+
repoRoot: cwd,
|
|
53
|
+
}),
|
|
54
|
+
readConfig: async (name, cwd) => JSON.parse(await readFile(join(cwd, "automations", name, "automation.json"), "utf8")),
|
|
55
|
+
readTail: async (name, cwd, count) => {
|
|
56
|
+
const path = join(cwd, "automations", name, "runs.jsonl");
|
|
57
|
+
const text = await readFile(path, "utf8").catch(() => "");
|
|
58
|
+
const lines = text.split(/\r?\n/).filter(Boolean);
|
|
59
|
+
return lines.slice(-count);
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
export async function runAutomationCommand(argv, overrides = {}) {
|
|
63
|
+
const deps = { ...defaults, ...overrides };
|
|
64
|
+
const [sub, ...rest] = argv;
|
|
65
|
+
switch (sub) {
|
|
66
|
+
case "list": {
|
|
67
|
+
const rows = await deps.getStatus(deps.cwd());
|
|
68
|
+
if (rows.length === 0) {
|
|
69
|
+
deps.stdout("no automations declared.\n");
|
|
70
|
+
return 0;
|
|
71
|
+
}
|
|
72
|
+
deps.stdout("STATUS NAME TRIGGER SUMMARY\n");
|
|
73
|
+
for (const row of rows) {
|
|
74
|
+
deps.stdout(`${row.status.padEnd(8)} ${row.name.padEnd(17)} ${row.triggerExpression.padEnd(16)} ${row.lastSummary ?? "-"}\n`);
|
|
75
|
+
}
|
|
76
|
+
return 0;
|
|
77
|
+
}
|
|
78
|
+
case "show": {
|
|
79
|
+
const name = rest[0];
|
|
80
|
+
if (!name) {
|
|
81
|
+
deps.stderr("automation show: missing name\n");
|
|
82
|
+
return 1;
|
|
83
|
+
}
|
|
84
|
+
const config = parseAutomationConfig(await deps.readConfig(name, deps.cwd()));
|
|
85
|
+
deps.stdout(JSON.stringify(config, null, 2) + "\n");
|
|
86
|
+
const tail = await deps.readTail(name, deps.cwd(), 3);
|
|
87
|
+
if (tail.length > 0) {
|
|
88
|
+
deps.stdout("\nLast runs:\n");
|
|
89
|
+
for (const line of tail)
|
|
90
|
+
deps.stdout(line + "\n");
|
|
91
|
+
}
|
|
92
|
+
return 0;
|
|
93
|
+
}
|
|
94
|
+
case "run": {
|
|
95
|
+
const name = rest[0];
|
|
96
|
+
if (!name) {
|
|
97
|
+
deps.stderr("automation run: missing name\n");
|
|
98
|
+
return 1;
|
|
99
|
+
}
|
|
100
|
+
const record = await deps.doRun(name, deps.cwd());
|
|
101
|
+
deps.stdout(`${record.ts} exit=${record.exit} drift=${record.drift} ${record.summary}\n`);
|
|
102
|
+
return record.exit === 0 ? 0 : 1;
|
|
103
|
+
}
|
|
104
|
+
case "install": {
|
|
105
|
+
const name = rest[0];
|
|
106
|
+
if (!name) {
|
|
107
|
+
deps.stderr("automation install: missing name\n");
|
|
108
|
+
return 1;
|
|
109
|
+
}
|
|
110
|
+
await deps.doInstall(name, deps.cwd());
|
|
111
|
+
deps.stdout(`installed dev.chiralkit.${name}\n`);
|
|
112
|
+
return 0;
|
|
113
|
+
}
|
|
114
|
+
case "uninstall": {
|
|
115
|
+
const name = rest[0];
|
|
116
|
+
if (!name) {
|
|
117
|
+
deps.stderr("automation uninstall: missing name\n");
|
|
118
|
+
return 1;
|
|
119
|
+
}
|
|
120
|
+
await deps.doUninstall(name, deps.cwd());
|
|
121
|
+
deps.stdout(`uninstalled dev.chiralkit.${name}\n`);
|
|
122
|
+
return 0;
|
|
123
|
+
}
|
|
124
|
+
default:
|
|
125
|
+
deps.stderr(`automation: unknown subcommand '${sub ?? ""}'. Use: list | show | run | install | uninstall\n`);
|
|
126
|
+
return 1;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/automation/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type AutomationConfig } from "./schema.js";
|
|
2
|
+
export interface InstallDependencies {
|
|
3
|
+
home: string;
|
|
4
|
+
launchctl: (args: string[]) => Promise<void>;
|
|
5
|
+
writeText: (path: string, content: string) => Promise<void>;
|
|
6
|
+
removeFile: (path: string) => Promise<void>;
|
|
7
|
+
fileExists: (path: string) => Promise<boolean>;
|
|
8
|
+
nodePath: string;
|
|
9
|
+
repoRoot: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function plistPath(home: string, name: string): string;
|
|
12
|
+
export declare function renderPlist(config: AutomationConfig, ctx: {
|
|
13
|
+
nodePath: string;
|
|
14
|
+
repoRoot: string;
|
|
15
|
+
logPath: string;
|
|
16
|
+
path: string;
|
|
17
|
+
}): string;
|
|
18
|
+
export declare function installAutomation(name: string, cwd: string, deps: InstallDependencies): Promise<void>;
|
|
19
|
+
export declare function uninstallAutomation(name: string, cwd: string, deps: InstallDependencies): Promise<void>;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { parseAutomationConfig } from "./schema.js";
|
|
4
|
+
export function plistPath(home, name) {
|
|
5
|
+
return join(home, "Library", "LaunchAgents", `dev.chiralkit.${name}.plist`);
|
|
6
|
+
}
|
|
7
|
+
function logPath(home, name) {
|
|
8
|
+
return join(home, "Library", "Logs", `chiralkit-${name}.log`);
|
|
9
|
+
}
|
|
10
|
+
function assertPlainInteger(field) {
|
|
11
|
+
if (field !== "*" && !/^\d+$/.test(field)) {
|
|
12
|
+
throw new Error(`cron field '${field}' is not a plain integer; step/list/range syntax not supported yet`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function cronToStartCalendarInterval(expression) {
|
|
16
|
+
const parts = expression.trim().split(/\s+/);
|
|
17
|
+
if (parts.length !== 5)
|
|
18
|
+
throw new Error(`unsupported cron expression: ${expression}`);
|
|
19
|
+
const [minute, hour] = parts;
|
|
20
|
+
assertPlainInteger(minute);
|
|
21
|
+
assertPlainInteger(hour);
|
|
22
|
+
const entries = [];
|
|
23
|
+
if (minute !== "*")
|
|
24
|
+
entries.push(`<key>Minute</key><integer>${Number(minute)}</integer>`);
|
|
25
|
+
if (hour !== "*")
|
|
26
|
+
entries.push(`<key>Hour</key><integer>${Number(hour)}</integer>`);
|
|
27
|
+
if (entries.length === 0)
|
|
28
|
+
throw new Error(`cron expression '${expression}' has no fixed minute or hour — StartInterval instead is a follow-up`);
|
|
29
|
+
return `<dict>\n ${entries.join("\n ")}\n </dict>`;
|
|
30
|
+
}
|
|
31
|
+
export function renderPlist(config, ctx) {
|
|
32
|
+
if (config.trigger.kind === "on-demand") {
|
|
33
|
+
throw new Error(`renderPlist: automation '${config.name}' has trigger.kind: "on-demand" — on-demand triggers are invocation-driven and have no cron expression to render into a launchd plist. Callers must guard before reaching renderPlist.`);
|
|
34
|
+
}
|
|
35
|
+
const args = [ctx.nodePath, join(ctx.repoRoot, "packages/cli/dist/index.js"), "automation", "run", config.name];
|
|
36
|
+
const programArgs = args.map((a) => ` <string>${a}</string>`).join("\n");
|
|
37
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
38
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
39
|
+
<plist version="1.0">
|
|
40
|
+
<dict>
|
|
41
|
+
<key>Label</key>
|
|
42
|
+
<string>dev.chiralkit.${config.name}</string>
|
|
43
|
+
|
|
44
|
+
<key>ProgramArguments</key>
|
|
45
|
+
<array>
|
|
46
|
+
${programArgs}
|
|
47
|
+
</array>
|
|
48
|
+
|
|
49
|
+
<key>WorkingDirectory</key>
|
|
50
|
+
<string>${ctx.repoRoot}</string>
|
|
51
|
+
|
|
52
|
+
<key>EnvironmentVariables</key>
|
|
53
|
+
<dict>
|
|
54
|
+
<key>PATH</key>
|
|
55
|
+
<string>${ctx.path}</string>
|
|
56
|
+
</dict>
|
|
57
|
+
|
|
58
|
+
<key>StartCalendarInterval</key>
|
|
59
|
+
${cronToStartCalendarInterval(config.trigger.expression)}
|
|
60
|
+
|
|
61
|
+
<key>StandardOutPath</key>
|
|
62
|
+
<string>${ctx.logPath}</string>
|
|
63
|
+
|
|
64
|
+
<key>StandardErrorPath</key>
|
|
65
|
+
<string>${ctx.logPath}</string>
|
|
66
|
+
|
|
67
|
+
<key>RunAtLoad</key>
|
|
68
|
+
<false/>
|
|
69
|
+
</dict>
|
|
70
|
+
</plist>
|
|
71
|
+
`;
|
|
72
|
+
}
|
|
73
|
+
export async function installAutomation(name, cwd, deps) {
|
|
74
|
+
const configRaw = JSON.parse(await readFile(join(cwd, "automations", name, "automation.json"), "utf8"));
|
|
75
|
+
const config = parseAutomationConfig(configRaw);
|
|
76
|
+
if (config.trigger.kind === "on-demand") {
|
|
77
|
+
// on-demand triggers are invocation-driven; there is nothing to register
|
|
78
|
+
// in launchd. No-op: do not write a plist, do not call launchctl.
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const path = plistPath(deps.home, name);
|
|
82
|
+
const xml = renderPlist(config, {
|
|
83
|
+
nodePath: deps.nodePath,
|
|
84
|
+
repoRoot: deps.repoRoot,
|
|
85
|
+
logPath: logPath(deps.home, name),
|
|
86
|
+
path: process.env.PATH ?? "/usr/local/bin:/usr/bin:/bin",
|
|
87
|
+
});
|
|
88
|
+
if (await deps.fileExists(path)) {
|
|
89
|
+
await deps.launchctl(["unload", path]);
|
|
90
|
+
}
|
|
91
|
+
await deps.writeText(path, xml);
|
|
92
|
+
await deps.launchctl(["load", path]);
|
|
93
|
+
}
|
|
94
|
+
export async function uninstallAutomation(name, cwd, deps) {
|
|
95
|
+
// Best-effort: on-demand triggers never get installed to launchd, so there
|
|
96
|
+
// is nothing to unload. Read the config to short-circuit explicitly when
|
|
97
|
+
// possible; if automation.json is missing or malformed, fall through to
|
|
98
|
+
// the existing plist-presence-based uninstall — that path is already safe
|
|
99
|
+
// regardless of config state (idempotent no-op when the plist is absent).
|
|
100
|
+
try {
|
|
101
|
+
const configRaw = JSON.parse(await readFile(join(cwd, "automations", name, "automation.json"), "utf8"));
|
|
102
|
+
const config = parseAutomationConfig(configRaw);
|
|
103
|
+
if (config.trigger.kind === "on-demand") {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// missing/malformed automation.json — fall through
|
|
109
|
+
}
|
|
110
|
+
const path = plistPath(deps.home, name);
|
|
111
|
+
if (await deps.fileExists(path)) {
|
|
112
|
+
await deps.launchctl(["unload", path]);
|
|
113
|
+
await deps.removeFile(path);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/automation/install.ts"],"names":[],"mappings":"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"}
|