aligndev 0.18.0 → 0.20.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 +34 -130
- package/dist/cli.js +10 -14
- package/dist/code/code-cli.d.ts +2 -2
- package/dist/code/code-cli.js +7 -5
- package/dist/code/coding-agent.d.ts +1 -0
- package/dist/code/coding-agent.js +10 -0
- package/dist/code/run-agent.js +1 -1
- package/dist/config.d.ts +10 -7
- package/dist/config.js +25 -20
- package/dist/guide/code-guide.js +2 -2
- package/dist/guide/guide-cli.d.ts +2 -2
- package/dist/guide/guide-cli.js +5 -5
- package/dist/project/project-cli.d.ts +2 -2
- package/dist/project/project-cli.js +1 -1
- package/package.json +2 -2
- package/templates/guide/code.md +34 -34
- package/templates/guide/playbook/consultation.md +4 -4
- package/templates/guide/playbook/playbook.md +17 -12
- package/templates/guide/playbook/project-lifecycle.md +8 -8
- package/templates/guide/playbook/project-workspace-setup.md +5 -5
- package/templates/guide/playbook/working-session.md +44 -44
- package/templates/guide/project.md +1 -1
package/README.md
CHANGED
|
@@ -1,168 +1,72 @@
|
|
|
1
1
|
# aligndev
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Autonomous software development. You say what you want; the assistant drives the coding agents and brings you the decisions.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
You talk to an **assistant**, the way you would to a developer on your team. It never touches the code itself. It isolates each task in its own workspace, then hands the investigation and the coding to an AI coding agent, **the agent**, which follows the [AlignFirst](https://alignfirst.paroi.tech/) protocols: specify, plan, implement, review. The assistant reads the agent's work, tests it, asks you what only you can decide, and opens the pull request.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
`aligndev` is the assistant's CLI. It gives the assistant its playbook, launches and tracks the agent, and keeps the inventory of your projects. You never run it yourself: the assistant does.
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## Two Ways to Run the Assistant
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
aligndev code <command> [<options>] # run a coding agent through AlignFirst protocols
|
|
13
|
-
aligndev project <command> [<options>] # list projects, check the inventory, claim port ranges
|
|
14
|
-
aligndev guide [<topic>] # print the playbook and the guides
|
|
15
|
-
aligndev --help
|
|
16
|
-
aligndev --version
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
Each command prints its own usage with `--help`.
|
|
11
|
+
**In your coding agent.** A Claude Code or Codex session becomes the assistant of the repository it starts in. You keep chatting in the same session; the agents it launches work in the background.
|
|
20
12
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
```sh
|
|
24
|
-
aligndev code new --protocol spec --ticket AB-123 --message "Feature description"
|
|
25
|
-
aligndev code resume <sessionId> --protocol plan
|
|
26
|
-
aligndev code new --message "Execute the plan: .plans/AB-123/A2-plan.md"
|
|
27
|
-
aligndev code new --protocol aad --no-ticket --message "Task description"
|
|
28
|
-
aligndev code new --ticket AB-123 --catchup --protocol aad --message-file message.md
|
|
29
|
-
aligndev code status .plans/AB-123/_aligndev/20260829-135529.md
|
|
30
|
-
aligndev code quota
|
|
31
|
-
```
|
|
13
|
+
**As an OpenClaw bot.** The [AlignFirst Dev Kit](https://alignfirst.paroi.tech/openclaw-dev-kit) deploys the assistant on a server, under its own name in Slack or Discord. It works on every project of the host, one thread per task.
|
|
32
14
|
|
|
33
|
-
|
|
15
|
+
Either way, the agent is Claude Code or Codex. A coding-agent assistant launches its own kind by default.
|
|
34
16
|
|
|
35
|
-
|
|
17
|
+
## Start in Claude Code or Codex
|
|
36
18
|
|
|
37
|
-
|
|
19
|
+
The project needs an AlignFirst `.plans` directory, in its repository or in a [companion directory](https://github.com/paleo/alignfirst/tree/main/packages/alignfirst#companion-directories). The [setup guide](https://github.com/paleo/alignfirst/blob/main/skills/alignfirst-setup-guide/references/coding-agent-assistant.md) prepares it.
|
|
38
20
|
|
|
39
|
-
|
|
21
|
+
The agent needs network access and writes outside the repository, so the assistant launches it outside its sandbox: approve that request when it comes.
|
|
40
22
|
|
|
41
|
-
|
|
23
|
+
### With the Skill
|
|
42
24
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
`aligndev code quota` shows the selected coding agent's account limits, consumed percentages, and reset times. It works outside a project.
|
|
46
|
-
|
|
47
|
-
### `aligndev project`
|
|
25
|
+
Install the `aligndev` skill:
|
|
48
26
|
|
|
49
27
|
```sh
|
|
50
|
-
|
|
51
|
-
aligndev project doctor [--root <path>]
|
|
52
|
-
aligndev project status <path> [--json] [--root <path>]
|
|
53
|
-
aligndev project init [--root <path>] [--description <text>] [--port-range [<code>=]<first>-<last>]...
|
|
54
|
-
aligndev project free-ports --size <n> [--range <code>] [--json] [--root <path>]
|
|
28
|
+
npx skills add https://github.com/paleo/alignfirst --global --skill aligndev
|
|
55
29
|
```
|
|
56
30
|
|
|
57
|
-
|
|
31
|
+
Then start a session in the project and invoke `/aligndev` in Claude Code, or `$aligndev` in Codex.
|
|
58
32
|
|
|
59
|
-
|
|
60
|
-
{
|
|
61
|
-
"description": "Every project is a direct child of ~/projects.",
|
|
62
|
-
"portRanges": [
|
|
63
|
-
{ "first": 28000, "last": 28599, "description": "Web projects, exposed through the gateway." },
|
|
64
|
-
{ "code": "local", "first": 29000, "last": 29199, "description": "Desktop apps, never exposed." }
|
|
65
|
-
]
|
|
66
|
-
}
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
`--root` defaults to `projectsRoot` in the config, then to the working directory. `doctor` is a read-only health gate: it succeeds only when discovery completes with no inventory issue.
|
|
33
|
+
### Without a Skill
|
|
70
34
|
|
|
71
|
-
|
|
35
|
+
Add this section to your global agent instructions (`~/.claude/CLAUDE.md`, `~/.codex/AGENTS.md`, or the equivalent):
|
|
72
36
|
|
|
73
|
-
|
|
37
|
+
```markdown
|
|
38
|
+
## Aligndev
|
|
74
39
|
|
|
75
|
-
|
|
76
|
-
aligndev guide [<topic>] [--root <path>]
|
|
40
|
+
When the user mentions **aligndev**, follow the `aligndev` playbook if it is already in context. Otherwise, run `npx -y aligndev guide` and follow it.
|
|
77
41
|
```
|
|
78
42
|
|
|
79
|
-
|
|
43
|
+
Then ask your session to work with aligndev.
|
|
80
44
|
|
|
81
|
-
|
|
82
|
-
|-------|--------|-----------|
|
|
83
|
-
| (none) | The playbook dispatcher. | both |
|
|
84
|
-
| `working-session` | The work procedure: a thread under OpenClaw, the conversation for a coding agent. | both |
|
|
85
|
-
| `project-workspace-setup`, `consultation` | Runbooks. | both |
|
|
86
|
-
| `code` | The delegation guide. | both |
|
|
87
|
-
| `channel-handling` | The channel and DM procedure. | `openclaw` |
|
|
88
|
-
| `project-lifecycle` | The runbook to create, onboard or remove a project. | `openclaw` |
|
|
89
|
-
| `slack-message-tool`, `discord-message-tool` | Extended `message` references. | `openclaw` |
|
|
90
|
-
| `project` | The projects guide, followed by the directory sections when the root carries a marker. `--root` overrides `projectsRoot`. | `openclaw` |
|
|
45
|
+
### Requirements
|
|
91
46
|
|
|
92
|
-
|
|
47
|
+
- Node.js 22.11 or later. The assistant runs `aligndev` through `npx`, so there is nothing to install.
|
|
48
|
+
- Claude Code or Codex installed and logged in: `claude` then `/login`, or `codex login`.
|
|
49
|
+
- Linux or macOS, or Windows through WSL.
|
|
93
50
|
|
|
94
51
|
## Configuration
|
|
95
52
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
```json
|
|
99
|
-
{
|
|
100
|
-
"platform": "openclaw",
|
|
101
|
-
"projectsRoot": "~/projects",
|
|
102
|
-
"code": {
|
|
103
|
-
"agent": "claude",
|
|
104
|
-
"models": ["opus", "sonnet"],
|
|
105
|
-
"skipPermissions": false,
|
|
106
|
-
"unset": ["ANTHROPIC_API_KEY"]
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
A coding agent acting as the assistant needs only the required keys:
|
|
53
|
+
`~/.alignfirst/aligndev.config.json` is optional. Without it, every key takes its default. For example, to launch Codex as the agent, whatever runs the assistant:
|
|
112
54
|
|
|
113
55
|
```json
|
|
114
56
|
{
|
|
115
|
-
"platform": "codingAgent",
|
|
116
57
|
"code": { "agent": "codex" }
|
|
117
58
|
}
|
|
118
59
|
```
|
|
119
60
|
|
|
120
|
-
- `platform` —
|
|
121
|
-
- `projectsRoot` — the
|
|
122
|
-
- `code.agent` —
|
|
123
|
-
- `code.models` —
|
|
124
|
-
- `code.skipPermissions` — `true`
|
|
125
|
-
- `code.unset` — environment variables
|
|
126
|
-
|
|
127
|
-
Unknown keys are rejected. An unreadable file, invalid JSON or an invalid value fails every command that loads the config, with an error naming the file.
|
|
128
|
-
|
|
129
|
-
Companion directories are declared in `~/.config/alignfirst/companions.json`, which the `alignfirst` CLI reads for both tools. See [its README](https://github.com/paleo/alignfirst/tree/main/packages/alignfirst#companion-directories).
|
|
130
|
-
|
|
131
|
-
## Execution model
|
|
132
|
-
|
|
133
|
-
`aligndev code` runs the coder as a direct **foreground** child of its own process. It streams a live transcript to stdout and to a per-run session file, whose frontmatter status goes from `running` to `succeeded` or `failed`, and blocks until the coder exits. It never backgrounds or detaches itself.
|
|
134
|
-
|
|
135
|
-
Coding runs can be very long, so the caller always runs `aligndev code` as a background task and owns the backgrounding, as `aligndev guide code` prescribes:
|
|
136
|
-
|
|
137
|
-
- Under OpenClaw, the assistant invokes it through the `exec` tool with `background: true` and `timeoutSeconds: 0`, and chains `openclaw system event --mode now --session-key <key>` onto the command.
|
|
138
|
-
- A coding-agent assistant starts it with its own background-execution facility, with no time limit, and outside its sandbox. When the agent wakes the session as the command exits, as Claude Code does, the assistant handles the completion on that wake. Otherwise, the assistant checks its pending runs at the start of the next user turn.
|
|
139
|
-
|
|
140
|
-
The completion turn locates the session file with `aligndev code status` and reads the result. The session file is the durable result handoff: frontmatter `sessionId` and status, and the `---- Result ----` block.
|
|
141
|
-
|
|
142
|
-
If `aligndev code` is terminated, its signal handlers seal the session file (`status: failed`, `exitReason: terminated`), then send `SIGTERM` to the coder. After a short grace period, a `SIGKILL` guarantees no orphan is left behind. Only a `SIGKILL` of `aligndev` itself can leave a stale `running` status, which the next `status` call seals.
|
|
143
|
-
|
|
144
|
-
When the coding agent's session on the host is missing or expired, `aligndev code` detects the authentication failure in its stream, seals the session file with `exitReason: auth_required`, and exits `2` with a one-line stderr message.
|
|
145
|
-
|
|
146
|
-
## Coding agents
|
|
147
|
-
|
|
148
|
-
Install the selected CLI and authenticate it on the host: run `claude`, then `/login`, for Claude Code; run `codex login` for Codex.
|
|
149
|
-
|
|
150
|
-
Normal runs use Claude's `--permission-mode auto` or Codex's `--sandbox workspace-write`.
|
|
151
|
-
|
|
152
|
-
Claude's default model list is `fable`, `opus`, `sonnet`, `haiku`. Codex's is `astra`, `sol`, `terra`, `luna`; `aligndev code` resolves a selected Codex alias against `codex debug models --bundled`. Set `code.models` to narrow the list or to advertise an explicit Codex slug such as `gpt-5.6-terra`.
|
|
153
|
-
|
|
154
|
-
Session files record `agent`. A session resumes only with the same selected agent. Agentless legacy sessions stay readable but require a new session.
|
|
155
|
-
|
|
156
|
-
## The `aligndev` skill
|
|
157
|
-
|
|
158
|
-
The `aligndev` agent skill makes a Claude Code or Codex session the assistant of the project it runs in. Invoked as `/aligndev` in Claude Code, or `$aligndev` in Codex, it loads the playbook through `npx -y aligndev guide`, which needs `platform: "codingAgent"` in the config. Install it:
|
|
159
|
-
|
|
160
|
-
```sh
|
|
161
|
-
npx skills add https://github.com/paleo/alignfirst --global --skill aligndev
|
|
162
|
-
```
|
|
61
|
+
- `platform` — `codingAgent` (default) for a coding-agent assistant, `openclaw` for an OpenClaw bot.
|
|
62
|
+
- `projectsRoot` — the projects directory of an OpenClaw host. Required by `openclaw`. `~/` expands to the home directory; a relative path resolves against `~/.alignfirst/`.
|
|
63
|
+
- `code.agent` — the agent: `claude` or `codex`. Default: the coding agent that runs the assistant, detected from its environment. Set it to launch the other one, or when both are detected, as with Codex in a VS Code terminal where the Claude Code extension is installed.
|
|
64
|
+
- `code.models` — the models the assistant may choose from. Default: Claude's `fable`, `opus`, `sonnet`, `haiku`, or Codex's `astra`, `sol`, `terra`, `luna`.
|
|
65
|
+
- `code.skipPermissions` — `true` runs Claude Code with `--dangerously-skip-permissions` instead of `--permission-mode auto`, and Codex with `--dangerously-bypass-approvals-and-sandbox` instead of `--sandbox workspace-write`. Default: `false`.
|
|
66
|
+
- `code.unset` — environment variables to hide from the agent, such as an API key meant for another tool on the host.
|
|
163
67
|
|
|
164
|
-
|
|
68
|
+
Unknown keys and invalid values are errors.
|
|
165
69
|
|
|
166
|
-
##
|
|
70
|
+
## Under the Hood
|
|
167
71
|
|
|
168
|
-
|
|
72
|
+
`aligndev` documents itself for the assistant: `aligndev --help`, then `aligndev guide`, print everything it needs. Maintainers: see [aligndev Architecture](https://github.com/paleo/alignfirst/blob/main/docs/aligndev-architecture.md).
|
package/dist/cli.js
CHANGED
|
@@ -5,7 +5,7 @@ import { CODING_AGENTS } from "./code/coding-agent.js";
|
|
|
5
5
|
import { resolveExecutableModel } from "./code/models.js";
|
|
6
6
|
import { readQuota } from "./code/quota.js";
|
|
7
7
|
import { resolveCommandForms } from "./command-form.js";
|
|
8
|
-
import { loadConfig,
|
|
8
|
+
import { loadConfig, PLATFORMS } from "./config.js";
|
|
9
9
|
import { errorMessage } from "./errors.js";
|
|
10
10
|
import { runGuide } from "./guide/guide-cli.js";
|
|
11
11
|
import { runProject } from "./project/project-cli.js";
|
|
@@ -25,23 +25,18 @@ export async function main(options) {
|
|
|
25
25
|
ctx.stderr.write(`${error}\n\n${renderHelp(ctx.forms.aligndev)}`);
|
|
26
26
|
return 1;
|
|
27
27
|
}
|
|
28
|
-
let config;
|
|
29
28
|
try {
|
|
30
|
-
config = loadConfig(ctx.home);
|
|
29
|
+
const config = loadConfig(ctx.home);
|
|
30
|
+
if (command === "project")
|
|
31
|
+
return runProject(tokens, config, ctx);
|
|
32
|
+
if (command === "code")
|
|
33
|
+
return await runCode(tokens, config, ctx);
|
|
34
|
+
return runGuide(tokens, config, ctx);
|
|
31
35
|
}
|
|
32
36
|
catch (error) {
|
|
33
37
|
ctx.stderr.write(`${errorMessage(error)}\n`);
|
|
34
38
|
return 1;
|
|
35
39
|
}
|
|
36
|
-
if (command === "project")
|
|
37
|
-
return runProject(tokens, config, ctx);
|
|
38
|
-
if (config === undefined) {
|
|
39
|
-
ctx.stderr.write(`${missingConfigMessage(ctx.home)}\n`);
|
|
40
|
-
return 1;
|
|
41
|
-
}
|
|
42
|
-
if (command === "code")
|
|
43
|
-
return runCode(tokens, config, ctx);
|
|
44
|
-
return runGuide(tokens, config, ctx);
|
|
45
40
|
}
|
|
46
41
|
function renderHelp(aligndev) {
|
|
47
42
|
const usage = renderUsageRows([
|
|
@@ -61,8 +56,9 @@ ${usage}
|
|
|
61
56
|
|
|
62
57
|
Run \`${aligndev} <command> --help\` for the usage of a command.
|
|
63
58
|
|
|
64
|
-
Config: ~/.
|
|
65
|
-
"code.agent" (${CODING_AGENTS.join(" or ")})
|
|
59
|
+
Config (optional): ~/.alignfirst/aligndev.config.json. "platform" (${PLATFORMS.join(" or ")})
|
|
60
|
+
defaults to codingAgent. "code.agent" (${CODING_AGENTS.join(" or ")}) defaults to the coding agent that
|
|
61
|
+
runs aligndev, detected from its environment.
|
|
66
62
|
`;
|
|
67
63
|
}
|
|
68
64
|
// Each row is a command, optionally followed by its description in an aligned column.
|
package/dist/code/code-cli.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CommandForms } from "../command-form.js";
|
|
2
|
-
import
|
|
2
|
+
import { type CodeConfig, type LoadedConfig } from "../config.js";
|
|
3
3
|
import type { Output } from "../output.js";
|
|
4
4
|
import { type ProjectReport } from "../project/layout.js";
|
|
5
5
|
import { type CodingAgent } from "./coding-agent.js";
|
|
@@ -51,7 +51,7 @@ export interface SessionArgs {
|
|
|
51
51
|
model?: string;
|
|
52
52
|
meta?: string;
|
|
53
53
|
}
|
|
54
|
-
export declare function runCode(tokens: string[], config:
|
|
54
|
+
export declare function runCode(tokens: string[], config: LoadedConfig, ctx: CodeContext): Promise<number>;
|
|
55
55
|
export declare function parseCodeArgs(tokens: string[], aligndev: string): CodeCommand;
|
|
56
56
|
export declare function validateSessionArgs(args: SessionArgs, models: readonly string[]): string | undefined;
|
|
57
57
|
export declare function checkLaunchGuards(args: SessionArgs, agent: CodingAgent, realCwd: string, records: SessionRecord[]): string | undefined;
|
package/dist/code/code-cli.js
CHANGED
|
@@ -2,6 +2,7 @@ import { existsSync, readFileSync, realpathSync } from "node:fs";
|
|
|
2
2
|
import { extname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
3
3
|
import { parseArgs } from "node:util";
|
|
4
4
|
import { loadCatchup, loadContext, openTicket, reserveSideTicket } from "../alignfirst-cli.js";
|
|
5
|
+
import { resolveCodeConfig } from "../config.js";
|
|
5
6
|
import { errorMessage } from "../errors.js";
|
|
6
7
|
import { companionInUse, readProjectReport, } from "../project/layout.js";
|
|
7
8
|
import { createAgentAdapter } from "./coding-agent.js";
|
|
@@ -22,7 +23,7 @@ const SESSION_OPTIONS = {
|
|
|
22
23
|
meta: { type: "string" },
|
|
23
24
|
help: { type: "boolean", short: "h", default: false },
|
|
24
25
|
};
|
|
25
|
-
// Items whose companion copy the
|
|
26
|
+
// Items whose companion copy the agent may edit: the companion becomes a writable directory.
|
|
26
27
|
const WRITABLE_COMPANION_ITEMS = [
|
|
27
28
|
".alignfirst.json",
|
|
28
29
|
".alignfirst.md",
|
|
@@ -30,7 +31,7 @@ const WRITABLE_COMPANION_ITEMS = [
|
|
|
30
31
|
"docs",
|
|
31
32
|
".plans",
|
|
32
33
|
];
|
|
33
|
-
// Items the
|
|
34
|
+
// Items the agent would not find in the repository: a new session gets `alignfirst context`.
|
|
34
35
|
const CONTEXT_COMPANION_ITEMS = [
|
|
35
36
|
".alignfirst.json",
|
|
36
37
|
".alignfirst.md",
|
|
@@ -44,7 +45,7 @@ export async function runCode(tokens, config, ctx) {
|
|
|
44
45
|
const command = parseCodeArgs(tokens, ctx.forms.aligndev);
|
|
45
46
|
if (command.kind === "status")
|
|
46
47
|
return showStatus(ctx, command.target);
|
|
47
|
-
const
|
|
48
|
+
const code = resolveCodeConfig(config, ctx.env);
|
|
48
49
|
if (command.kind === "quota")
|
|
49
50
|
return await showQuota(ctx, code);
|
|
50
51
|
const models = resolveModels(code.agent, code.models);
|
|
@@ -610,8 +611,9 @@ Options (new, resume):
|
|
|
610
611
|
|
|
611
612
|
${requires}
|
|
612
613
|
|
|
613
|
-
Config (~/.
|
|
614
|
-
code.agent
|
|
614
|
+
Config (~/.alignfirst/aligndev.config.json):
|
|
615
|
+
code.agent Coding agent: claude or codex (selected: ${agent}). Defaults to the coding
|
|
616
|
+
agent that runs aligndev.
|
|
615
617
|
code.models List replacing the models accepted by --model.
|
|
616
618
|
code.skipPermissions true to run the coding agent with permission prompts disabled.
|
|
617
619
|
code.unset Env vars to strip from the coding agent child.
|
|
@@ -2,3 +2,4 @@ import type { AgentAdapter } from "./run-agent.js";
|
|
|
2
2
|
export declare const CODING_AGENTS: readonly ["claude", "codex"];
|
|
3
3
|
export type CodingAgent = (typeof CODING_AGENTS)[number];
|
|
4
4
|
export declare function createAgentAdapter(agent: CodingAgent): AgentAdapter;
|
|
5
|
+
export declare function detectCodingAgents(env: NodeJS.ProcessEnv): CodingAgent[];
|
|
@@ -4,3 +4,13 @@ export const CODING_AGENTS = ["claude", "codex"];
|
|
|
4
4
|
export function createAgentAdapter(agent) {
|
|
5
5
|
return agent === "claude" ? createClaudeAdapter() : createCodexAdapter();
|
|
6
6
|
}
|
|
7
|
+
// Each coding agent marks the commands it runs: Claude Code sets `CLAUDECODE=1` (documented), and
|
|
8
|
+
// Codex sets `CODEX_THREAD_ID`.
|
|
9
|
+
export function detectCodingAgents(env) {
|
|
10
|
+
const detected = [];
|
|
11
|
+
if (env.CLAUDECODE === "1")
|
|
12
|
+
detected.push("claude");
|
|
13
|
+
if (env.CODEX_THREAD_ID !== undefined && env.CODEX_THREAD_ID !== "")
|
|
14
|
+
detected.push("codex");
|
|
15
|
+
return detected;
|
|
16
|
+
}
|
package/dist/code/run-agent.js
CHANGED
|
@@ -2,7 +2,7 @@ import { spawn } from "node:child_process";
|
|
|
2
2
|
import { appendTranscript, applyCompletion } from "./session-file.js";
|
|
3
3
|
const TERMINATION_GRACE_MS = 2000;
|
|
4
4
|
// A coding-agent session exports its own identity to every command it runs; when the assistant
|
|
5
|
-
// runs in one, the
|
|
5
|
+
// runs in one, the agent it launches must not inherit it.
|
|
6
6
|
const ASSISTANT_SESSION_VARIABLES = [
|
|
7
7
|
"CLAUDECODE",
|
|
8
8
|
"CLAUDE_CODE_SESSION_ID",
|
package/dist/config.d.ts
CHANGED
|
@@ -1,22 +1,25 @@
|
|
|
1
1
|
import { type CodingAgent } from "./code/coding-agent.js";
|
|
2
2
|
export declare const PLATFORMS: readonly ["openclaw", "codingAgent"];
|
|
3
3
|
export type Platform = (typeof PLATFORMS)[number];
|
|
4
|
-
export interface
|
|
4
|
+
export interface LoadedConfig {
|
|
5
5
|
path: string;
|
|
6
6
|
platform: Platform;
|
|
7
7
|
projectsRoot?: ProjectsRoot;
|
|
8
|
-
code:
|
|
8
|
+
code: LoadedCodeConfig;
|
|
9
9
|
}
|
|
10
10
|
export interface ProjectsRoot {
|
|
11
11
|
path: string;
|
|
12
12
|
written: string;
|
|
13
13
|
}
|
|
14
|
-
export interface
|
|
15
|
-
agent
|
|
14
|
+
export interface LoadedCodeConfig {
|
|
15
|
+
agent?: CodingAgent;
|
|
16
16
|
models?: string[];
|
|
17
17
|
skipPermissions: boolean;
|
|
18
18
|
unset: string[];
|
|
19
19
|
}
|
|
20
|
-
export
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
export interface CodeConfig extends LoadedCodeConfig {
|
|
21
|
+
agent: CodingAgent;
|
|
22
|
+
}
|
|
23
|
+
export declare function loadConfig(home: string): LoadedConfig;
|
|
24
|
+
export declare function resolveCodeConfig(config: LoadedConfig, env: NodeJS.ProcessEnv): CodeConfig;
|
|
25
|
+
export declare function requireProjectsRoot(config: LoadedConfig): ProjectsRoot;
|
package/dist/config.js
CHANGED
|
@@ -1,45 +1,41 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
3
3
|
import { type } from "arktype";
|
|
4
|
-
import { CODING_AGENTS } from "./code/coding-agent.js";
|
|
4
|
+
import { CODING_AGENTS, detectCodingAgents } from "./code/coding-agent.js";
|
|
5
5
|
import { errorMessage } from "./errors.js";
|
|
6
6
|
export const PLATFORMS = ["openclaw", "codingAgent"];
|
|
7
7
|
const codeSchema = type({
|
|
8
8
|
"+": "reject",
|
|
9
|
-
agent: type.enumerated(...CODING_AGENTS),
|
|
9
|
+
"agent?": type.enumerated(...CODING_AGENTS),
|
|
10
10
|
"models?": "string[]",
|
|
11
11
|
"skipPermissions?": "boolean",
|
|
12
12
|
"unset?": "string[]",
|
|
13
13
|
});
|
|
14
14
|
const configSchema = type({
|
|
15
15
|
"+": "reject",
|
|
16
|
-
platform: type.enumerated(...PLATFORMS),
|
|
16
|
+
"platform?": type.enumerated(...PLATFORMS),
|
|
17
17
|
"projectsRoot?": "string > 0",
|
|
18
|
-
code: codeSchema,
|
|
18
|
+
"code?": codeSchema,
|
|
19
19
|
});
|
|
20
|
-
// An absent file is a normal state:
|
|
20
|
+
// An absent file is a normal state: every key takes its default.
|
|
21
21
|
export function loadConfig(home) {
|
|
22
|
-
const path =
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const value = parseConfigFile(path);
|
|
22
|
+
const path = join(home, ".alignfirst", "aligndev.config.json");
|
|
23
|
+
const value = existsSync(path) ? parseConfigFile(path) : {};
|
|
24
|
+
const code = value.code ?? {};
|
|
26
25
|
return {
|
|
27
26
|
path,
|
|
28
|
-
platform: value.platform,
|
|
27
|
+
platform: value.platform ?? "codingAgent",
|
|
29
28
|
...(value.projectsRoot === undefined
|
|
30
29
|
? {}
|
|
31
30
|
: { projectsRoot: resolveProjectsRoot(value.projectsRoot, home, path) }),
|
|
32
31
|
code: {
|
|
33
|
-
agent:
|
|
34
|
-
...(
|
|
35
|
-
skipPermissions:
|
|
36
|
-
unset:
|
|
32
|
+
...(code.agent === undefined ? {} : { agent: code.agent }),
|
|
33
|
+
...(code.models === undefined ? {} : { models: code.models }),
|
|
34
|
+
skipPermissions: code.skipPermissions ?? false,
|
|
35
|
+
unset: code.unset ?? [],
|
|
37
36
|
},
|
|
38
37
|
};
|
|
39
38
|
}
|
|
40
|
-
function configPath(home) {
|
|
41
|
-
return join(home, ".config", "alignfirst", "aligndev.config.json");
|
|
42
|
-
}
|
|
43
39
|
function parseConfigFile(path) {
|
|
44
40
|
let value;
|
|
45
41
|
try {
|
|
@@ -61,9 +57,18 @@ function resolveProjectsRoot(written, home, path) {
|
|
|
61
57
|
return { path: join(home, written.slice(2)), written };
|
|
62
58
|
return { path: isAbsolute(written) ? written : resolve(dirname(path), written), written };
|
|
63
59
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
60
|
+
// The configured `code.agent` wins; otherwise, the coding agent that runs aligndev.
|
|
61
|
+
export function resolveCodeConfig(config, env) {
|
|
62
|
+
const { agent } = config.code;
|
|
63
|
+
if (agent !== undefined)
|
|
64
|
+
return { ...config.code, agent };
|
|
65
|
+
const detected = detectCodingAgents(env);
|
|
66
|
+
if (detected.length === 1)
|
|
67
|
+
return { ...config.code, agent: detected[0] };
|
|
68
|
+
const problem = detected.length === 0
|
|
69
|
+
? "no coding agent detected: run aligndev from Claude Code or Codex, or set"
|
|
70
|
+
: "both Claude Code and Codex detected: set";
|
|
71
|
+
throw new Error(`Error: ${problem} "code.agent" (${CODING_AGENTS.join(" or ")}) in ${config.path}.`);
|
|
67
72
|
}
|
|
68
73
|
export function requireProjectsRoot(config) {
|
|
69
74
|
if (config.projectsRoot !== undefined)
|
package/dist/guide/code-guide.js
CHANGED
|
@@ -11,7 +11,7 @@ export function renderCodeGuide(platform, agent, models, forms) {
|
|
|
11
11
|
? "The project must be prepared for AlignFirst. `npx -y aligndev` runs the `alignfirst` CLI through `npx`."
|
|
12
12
|
: "The project must be prepared for AlignFirst, with the `alignfirst` CLI installed (`npm install -g alignfirst`).",
|
|
13
13
|
ALIGNFIRST_USE: forms.viaNpx
|
|
14
|
-
? "`npx -y aligndev code` runs the `alignfirst` CLI through `npx`, and so does the
|
|
15
|
-
: "`aligndev code` requires the `alignfirst` CLI on `PATH`. The
|
|
14
|
+
? "`npx -y aligndev code` runs the `alignfirst` CLI through `npx`, and so does the agent: it runs `npx -y alignfirst guide <protocol>` in the project."
|
|
15
|
+
: "`aligndev code` requires the `alignfirst` CLI on `PATH`. The agent runs `alignfirst guide <protocol>` in the project, so the protocols come from the installed CLI.",
|
|
16
16
|
});
|
|
17
17
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type LoadedConfig } from "../config.js";
|
|
2
2
|
import { type ProjectsCallerContext } from "../project/project-cli.js";
|
|
3
|
-
export declare function runGuide(tokens: string[], config:
|
|
3
|
+
export declare function runGuide(tokens: string[], config: LoadedConfig, ctx: ProjectsCallerContext): number;
|
package/dist/guide/guide-cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { parseArgs } from "node:util";
|
|
2
2
|
import { resolveModels } from "../code/models.js";
|
|
3
|
-
import { PLATFORMS, requireProjectsRoot } from "../config.js";
|
|
3
|
+
import { PLATFORMS, requireProjectsRoot, resolveCodeConfig, } from "../config.js";
|
|
4
4
|
import { errorMessage } from "../errors.js";
|
|
5
5
|
import { renderProjectsGuideForRoot } from "../project/project-cli.js";
|
|
6
6
|
import { renderCodeGuide } from "./code-guide.js";
|
|
@@ -53,16 +53,16 @@ ${playbookTopics.join("\n")}
|
|
|
53
53
|
}
|
|
54
54
|
function renderTopic(args, config, ctx) {
|
|
55
55
|
if (args.topic === "code")
|
|
56
|
-
return renderCodeTopic(config, ctx
|
|
56
|
+
return renderCodeTopic(config, ctx);
|
|
57
57
|
if (args.topic === "project" && config.platform === "openclaw") {
|
|
58
58
|
return renderProjectsGuideForRoot({ ...ctx, projectsRoot: config.projectsRoot }, args.root);
|
|
59
59
|
}
|
|
60
60
|
return renderPlaybookTopic(args.topic, config, ctx.forms);
|
|
61
61
|
}
|
|
62
|
-
function renderCodeTopic(config,
|
|
63
|
-
const
|
|
62
|
+
function renderCodeTopic(config, ctx) {
|
|
63
|
+
const code = resolveCodeConfig(config, ctx.env);
|
|
64
64
|
const models = resolveModels(code.agent, code.models);
|
|
65
|
-
return renderCodeGuide(config.platform, code.agent, models, forms);
|
|
65
|
+
return renderCodeGuide(config.platform, code.agent, models, ctx.forms);
|
|
66
66
|
}
|
|
67
67
|
function renderPlaybookTopic(topic, config, forms) {
|
|
68
68
|
if (topic !== undefined)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CommandForms } from "../command-form.js";
|
|
2
|
-
import type {
|
|
2
|
+
import type { LoadedConfig, ProjectsRoot } from "../config.js";
|
|
3
3
|
import type { Output } from "../output.js";
|
|
4
4
|
export interface ProjectsCallerContext {
|
|
5
5
|
cwd: string;
|
|
@@ -13,5 +13,5 @@ export interface ProjectsCallerContext {
|
|
|
13
13
|
export interface ProjectsContext extends ProjectsCallerContext {
|
|
14
14
|
projectsRoot?: ProjectsRoot;
|
|
15
15
|
}
|
|
16
|
-
export declare function runProject(tokens: string[], config:
|
|
16
|
+
export declare function runProject(tokens: string[], config: LoadedConfig, caller: ProjectsCallerContext): number;
|
|
17
17
|
export declare function renderProjectsGuideForRoot(ctx: ProjectsContext, rootOption: string | undefined): string;
|
|
@@ -10,7 +10,7 @@ import { findFreeBlock } from "./ports.js";
|
|
|
10
10
|
import { renderPortRangeJson, renderProjectDoctor, renderProjectDoctorFailure, renderProjectList, renderProjectListJson, renderProjectStatus, renderProjectStatusJson, } from "./render.js";
|
|
11
11
|
import { getProjectStatus } from "./status.js";
|
|
12
12
|
export function runProject(tokens, config, caller) {
|
|
13
|
-
const ctx = { ...caller, projectsRoot: config
|
|
13
|
+
const ctx = { ...caller, projectsRoot: config.projectsRoot };
|
|
14
14
|
try {
|
|
15
15
|
return runProjectCommand(ctx, parseProjectsArgs(tokens));
|
|
16
16
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aligndev",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.0",
|
|
4
4
|
"license": "CC0-1.0",
|
|
5
5
|
"author": "Thomas MUR",
|
|
6
6
|
"description": "The AlignFirst Dev Kit CLI: the assistant's playbook, coding-agent delegation, and project inventory.",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"directory": "packages/aligndev"
|
|
23
23
|
},
|
|
24
24
|
"engines": {
|
|
25
|
-
"node": ">=
|
|
25
|
+
"node": ">=22.11.0"
|
|
26
26
|
},
|
|
27
27
|
"packageManager": "npm@11.19.0",
|
|
28
28
|
"type": "module",
|