architectonic 0.0.2 → 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 +25 -9
- package/bin/architectonic.js +150 -21
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,9 +11,9 @@ project -- operating context for a concrete initiative
|
|
|
11
11
|
skills -- reusable procedures and capabilities
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
The initial placeholder releases
|
|
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
|
|
|
@@ -35,16 +35,32 @@ architectonic update
|
|
|
35
35
|
|
|
36
36
|
## Current behavior
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
The primary implemented command is:
|
|
39
39
|
|
|
40
40
|
```text
|
|
41
|
-
npx architectonic
|
|
42
|
-
npx architectonic
|
|
43
|
-
npx architectonic add
|
|
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
|
|
44
47
|
```
|
|
45
48
|
|
|
46
|
-
|
|
47
|
-
|
|
49
|
+
`add` clones from the Architectonic GitHub organization into the current
|
|
50
|
+
directory by default:
|
|
51
|
+
|
|
52
|
+
```text
|
|
53
|
+
./teleology
|
|
54
|
+
./identity
|
|
55
|
+
./project
|
|
56
|
+
./skills
|
|
57
|
+
./architectonic.json
|
|
58
|
+
```
|
|
59
|
+
|
|
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.
|
|
48
64
|
|
|
49
65
|
## Run vs install
|
|
50
66
|
|
package/bin/architectonic.js
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
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;
|
|
5
10
|
const supported = ["teleology", "identity", "project", "skills"];
|
|
6
11
|
const supportedSet = new Set(supported);
|
|
12
|
+
const repoBase = process.env.ARCHITECTONIC_SOURCE_BASE || "https://github.com/architectonic";
|
|
7
13
|
|
|
8
14
|
function printHelp() {
|
|
9
|
-
console.log(`architectonic
|
|
15
|
+
console.log(`architectonic ${VERSION}
|
|
10
16
|
|
|
11
17
|
CLI for composing the core layers of an agentic system.
|
|
12
18
|
|
|
@@ -15,6 +21,7 @@ Usage:
|
|
|
15
21
|
npx architectonic help
|
|
16
22
|
npx architectonic add <teleology|identity|project|skills>
|
|
17
23
|
npx architectonic add teleology identity skills
|
|
24
|
+
npx architectonic add skills --dir ./vendor
|
|
18
25
|
|
|
19
26
|
Layers:
|
|
20
27
|
teleology purpose, principles, doctrine, governance
|
|
@@ -27,36 +34,158 @@ Run vs install:
|
|
|
27
34
|
npm install architectonic install in a project
|
|
28
35
|
npm install -g architectonic install globally
|
|
29
36
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
+
}
|
|
80
|
+
|
|
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`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function targetPathFor(installDir, target) {
|
|
90
|
+
return path.join(installDir, target);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function readManifest(manifestPath) {
|
|
94
|
+
if (!fs.existsSync(manifestPath)) {
|
|
95
|
+
return {
|
|
96
|
+
schema_version: 1,
|
|
97
|
+
installed_at: new Date().toISOString(),
|
|
98
|
+
layers: {},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
|
33
103
|
}
|
|
34
104
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
process.exit(0);
|
|
105
|
+
function writeManifest(manifestPath, manifest) {
|
|
106
|
+
fs.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, "utf8");
|
|
38
107
|
}
|
|
39
108
|
|
|
40
|
-
|
|
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
|
+
|
|
41
138
|
if (!targets.length) {
|
|
42
|
-
|
|
43
|
-
process.exit(1);
|
|
139
|
+
throw new Error("Specify one or more layers: teleology, identity, project, skills");
|
|
44
140
|
}
|
|
45
141
|
|
|
46
142
|
const invalid = targets.filter((target) => !supportedSet.has(target));
|
|
47
143
|
if (invalid.length) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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));
|
|
51
154
|
}
|
|
52
155
|
|
|
53
|
-
|
|
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
|
+
|
|
54
171
|
console.log("");
|
|
55
|
-
console.log(
|
|
56
|
-
console.log(
|
|
57
|
-
process.exit(0);
|
|
172
|
+
console.log(`Installed ${installed.map((item) => item.name).join(", ")} into ${installDir}`);
|
|
173
|
+
console.log(`Wrote ${manifestPath}`);
|
|
58
174
|
}
|
|
59
175
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
+
}
|