architectonic 0.0.1 → 0.0.3
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 +45 -15
- package/bin/architectonic.js +170 -21
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,41 +1,71 @@
|
|
|
1
1
|
# architectonic
|
|
2
2
|
|
|
3
|
-
`architectonic` is a command-line tool for
|
|
3
|
+
`architectonic` is a command-line tool for composing the core layers of an agentic system.
|
|
4
4
|
|
|
5
5
|
Those layers currently include:
|
|
6
6
|
|
|
7
7
|
```text
|
|
8
|
-
teleology -- purpose,
|
|
9
|
-
identity -- actors, roles, authority,
|
|
10
|
-
project --
|
|
11
|
-
skills -- reusable procedures
|
|
8
|
+
teleology -- purpose, principles, doctrine, governance
|
|
9
|
+
identity -- actors, roles, authority, boundaries
|
|
10
|
+
project -- operating context for a concrete initiative
|
|
11
|
+
skills -- reusable procedures and capabilities
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
The initial
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
The initial placeholder releases were intentionally minimal. Starting in
|
|
15
|
+
`0.0.3`, `architectonic add` becomes real: it clones the selected layer
|
|
16
|
+
repositories into a target directory and records them in `architectonic.json`.
|
|
17
17
|
|
|
18
|
-
##
|
|
18
|
+
## Command shape
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
The primary interaction model is:
|
|
21
21
|
|
|
22
22
|
```text
|
|
23
23
|
architectonic add teleology
|
|
24
24
|
architectonic add identity
|
|
25
25
|
architectonic add project
|
|
26
26
|
architectonic add skills
|
|
27
|
+
architectonic add teleology identity skills
|
|
27
28
|
architectonic doctor
|
|
29
|
+
architectonic list
|
|
28
30
|
architectonic update
|
|
29
31
|
```
|
|
30
32
|
|
|
33
|
+
`add` is explicit and leaves room for future verbs such as `doctor`, `list`,
|
|
34
|
+
`update`, and `remove`.
|
|
35
|
+
|
|
31
36
|
## Current behavior
|
|
32
37
|
|
|
33
|
-
|
|
38
|
+
The primary implemented command is:
|
|
39
|
+
|
|
40
|
+
```text
|
|
41
|
+
npx architectonic add teleology
|
|
42
|
+
npx architectonic add identity
|
|
43
|
+
npx architectonic add project
|
|
44
|
+
npx architectonic add skills
|
|
45
|
+
npx architectonic add teleology identity skills
|
|
46
|
+
npx architectonic add skills --dir ./vendor
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`add` clones from the Architectonic GitHub organization into the current
|
|
50
|
+
directory by default:
|
|
34
51
|
|
|
35
52
|
```text
|
|
36
|
-
|
|
37
|
-
|
|
53
|
+
./teleology
|
|
54
|
+
./identity
|
|
55
|
+
./project
|
|
56
|
+
./skills
|
|
57
|
+
./architectonic.json
|
|
38
58
|
```
|
|
39
59
|
|
|
40
|
-
|
|
41
|
-
|
|
60
|
+
`architectonic.json` records what was installed and where it landed.
|
|
61
|
+
|
|
62
|
+
If a target directory already exists, the command stops instead of silently
|
|
63
|
+
overwriting it.
|
|
64
|
+
|
|
65
|
+
## Run vs install
|
|
66
|
+
|
|
67
|
+
```text
|
|
68
|
+
npx architectonic ... # run immediately
|
|
69
|
+
npm install architectonic # install as a dependency
|
|
70
|
+
npm install -g architectonic # install globally, then run `architectonic ...`
|
|
71
|
+
```
|
package/bin/architectonic.js
CHANGED
|
@@ -1,42 +1,191 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { spawnSync } from "node:child_process";
|
|
6
|
+
|
|
7
|
+
const VERSION = "0.0.3";
|
|
3
8
|
const args = process.argv.slice(2);
|
|
4
|
-
const [command,
|
|
9
|
+
const [command, ...rest] = args;
|
|
10
|
+
const supported = ["teleology", "identity", "project", "skills"];
|
|
11
|
+
const supportedSet = new Set(supported);
|
|
12
|
+
const repoBase = process.env.ARCHITECTONIC_SOURCE_BASE || "https://github.com/architectonic";
|
|
5
13
|
|
|
6
14
|
function printHelp() {
|
|
7
|
-
console.log(`architectonic
|
|
15
|
+
console.log(`architectonic ${VERSION}
|
|
8
16
|
|
|
9
|
-
CLI for
|
|
17
|
+
CLI for composing the core layers of an agentic system.
|
|
10
18
|
|
|
11
19
|
Usage:
|
|
12
20
|
npx architectonic
|
|
13
21
|
npx architectonic help
|
|
14
22
|
npx architectonic add <teleology|identity|project|skills>
|
|
23
|
+
npx architectonic add teleology identity skills
|
|
24
|
+
npx architectonic add skills --dir ./vendor
|
|
25
|
+
|
|
26
|
+
Layers:
|
|
27
|
+
teleology purpose, principles, doctrine, governance
|
|
28
|
+
identity actors, roles, authority, boundaries
|
|
29
|
+
project operating context for a concrete initiative
|
|
30
|
+
skills reusable procedures and capabilities
|
|
31
|
+
|
|
32
|
+
Run vs install:
|
|
33
|
+
npx architectonic ... run immediately
|
|
34
|
+
npm install architectonic install in a project
|
|
35
|
+
npm install -g architectonic install globally
|
|
36
|
+
|
|
37
|
+
What add does:
|
|
38
|
+
Clones the selected layer repositories into the target directory
|
|
39
|
+
and records them in architectonic.json.`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function parseAddArgs(tokens) {
|
|
43
|
+
const targets = [];
|
|
44
|
+
let installDir = process.cwd();
|
|
45
|
+
|
|
46
|
+
for (let index = 0; index < tokens.length; index += 1) {
|
|
47
|
+
const token = tokens[index];
|
|
48
|
+
if (token === "--dir" || token === "--out") {
|
|
49
|
+
const next = tokens[index + 1];
|
|
50
|
+
if (!next) {
|
|
51
|
+
throw new Error(`Missing value for ${token}`);
|
|
52
|
+
}
|
|
53
|
+
installDir = path.resolve(next);
|
|
54
|
+
index += 1;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (token.startsWith("--dir=")) {
|
|
58
|
+
installDir = path.resolve(token.slice("--dir=".length));
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (token.startsWith("--out=")) {
|
|
62
|
+
installDir = path.resolve(token.slice("--out=".length));
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (token.startsWith("-")) {
|
|
66
|
+
throw new Error(`Unknown option: ${token}`);
|
|
67
|
+
}
|
|
68
|
+
targets.push(token);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return { targets, installDir };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function ensureGitAvailable() {
|
|
75
|
+
const result = spawnSync("git", ["--version"], { encoding: "utf8" });
|
|
76
|
+
if (result.status !== 0) {
|
|
77
|
+
throw new Error("git is required on PATH for `architectonic add`.");
|
|
78
|
+
}
|
|
79
|
+
}
|
|
15
80
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
81
|
+
function repoUrlFor(target) {
|
|
82
|
+
const normalizedBase = repoBase.replace(/\\/g, "/");
|
|
83
|
+
if (/^(?:[A-Za-z]:\/|\/|\.{1,2}\/)/.test(normalizedBase)) {
|
|
84
|
+
return path.resolve(normalizedBase, target);
|
|
85
|
+
}
|
|
86
|
+
return `${normalizedBase}/${target}.git`;
|
|
19
87
|
}
|
|
20
88
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
process.exit(0);
|
|
89
|
+
function targetPathFor(installDir, target) {
|
|
90
|
+
return path.join(installDir, target);
|
|
24
91
|
}
|
|
25
92
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
93
|
+
function readManifest(manifestPath) {
|
|
94
|
+
if (!fs.existsSync(manifestPath)) {
|
|
95
|
+
return {
|
|
96
|
+
schema_version: 1,
|
|
97
|
+
installed_at: new Date().toISOString(),
|
|
98
|
+
layers: {},
|
|
99
|
+
};
|
|
31
100
|
}
|
|
32
101
|
|
|
33
|
-
|
|
102
|
+
return JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function writeManifest(manifestPath, manifest) {
|
|
106
|
+
fs.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, "utf8");
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function cloneLayer(target, installDir) {
|
|
110
|
+
const repoUrl = repoUrlFor(target);
|
|
111
|
+
const targetPath = targetPathFor(installDir, target);
|
|
112
|
+
|
|
113
|
+
if (fs.existsSync(targetPath)) {
|
|
114
|
+
throw new Error(`Target already exists: ${targetPath}`);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const clone = spawnSync("git", ["clone", repoUrl, targetPath], {
|
|
118
|
+
cwd: installDir,
|
|
119
|
+
encoding: "utf8",
|
|
120
|
+
stdio: "pipe",
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
if (clone.status !== 0) {
|
|
124
|
+
const detail = (clone.stderr || clone.stdout || "").trim();
|
|
125
|
+
throw new Error(`Failed to clone ${repoUrl}${detail ? `\n${detail}` : ""}`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
name: target,
|
|
130
|
+
repo: repoUrl,
|
|
131
|
+
path: targetPath,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function addCommand(tokens) {
|
|
136
|
+
const { targets, installDir } = parseAddArgs(tokens);
|
|
137
|
+
|
|
138
|
+
if (!targets.length) {
|
|
139
|
+
throw new Error("Specify one or more layers: teleology, identity, project, skills");
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const invalid = targets.filter((target) => !supportedSet.has(target));
|
|
143
|
+
if (invalid.length) {
|
|
144
|
+
throw new Error(`Unknown layer(s): ${invalid.join(", ")}\nSupported layers: ${supported.join(", ")}`);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
ensureGitAvailable();
|
|
148
|
+
fs.mkdirSync(installDir, { recursive: true });
|
|
149
|
+
|
|
150
|
+
const installed = [];
|
|
151
|
+
for (const target of targets) {
|
|
152
|
+
console.log(`Adding ${target}...`);
|
|
153
|
+
installed.push(cloneLayer(target, installDir));
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const manifestPath = path.join(installDir, "architectonic.json");
|
|
157
|
+
const manifest = readManifest(manifestPath);
|
|
158
|
+
manifest.installed_at = new Date().toISOString();
|
|
159
|
+
manifest.source_base = repoBase;
|
|
160
|
+
|
|
161
|
+
for (const item of installed) {
|
|
162
|
+
manifest.layers[item.name] = {
|
|
163
|
+
repo: item.repo,
|
|
164
|
+
path: `./${path.relative(installDir, item.path).replace(/\\/g, "/")}`,
|
|
165
|
+
installed_at: manifest.installed_at,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
writeManifest(manifestPath, manifest);
|
|
170
|
+
|
|
34
171
|
console.log("");
|
|
35
|
-
console.log(
|
|
36
|
-
console.log(
|
|
37
|
-
process.exit(0);
|
|
172
|
+
console.log(`Installed ${installed.map((item) => item.name).join(", ")} into ${installDir}`);
|
|
173
|
+
console.log(`Wrote ${manifestPath}`);
|
|
38
174
|
}
|
|
39
175
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
176
|
+
try {
|
|
177
|
+
if (!command || command === "help" || command === "--help" || command === "-h") {
|
|
178
|
+
printHelp();
|
|
179
|
+
process.exit(0);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (command === "add") {
|
|
183
|
+
addCommand(rest);
|
|
184
|
+
process.exit(0);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
throw new Error(`Unknown command: ${command}\nRun \`architectonic help\` for usage.`);
|
|
188
|
+
} catch (error) {
|
|
189
|
+
console.error(error.message);
|
|
190
|
+
process.exit(1);
|
|
191
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "architectonic",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "CLI for
|
|
3
|
+
"version": "0.0.3",
|
|
4
|
+
"description": "CLI for composing agentic system layers such as teleology, identity, project, and skills.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|