@arjunkhera/atlas 0.3.4 → 0.3.5
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/.claude-plugin/plugin.json +1 -1
- package/door/cli.mjs +54 -16
- package/door/lib/install.mjs +1 -1
- package/door/lib/privacy.mjs +7 -2
- package/package.json +1 -1
package/door/cli.mjs
CHANGED
|
@@ -54,18 +54,53 @@ Atlas ${ATLAS_VERSION}. Check version ${CHECK_VERSION}; it reads spec ${Object.k
|
|
|
54
54
|
A person merges every file the tooling writer writes.
|
|
55
55
|
`;
|
|
56
56
|
|
|
57
|
-
//
|
|
58
|
-
//
|
|
59
|
-
|
|
57
|
+
// Each flag of each command, declared once. A test holds this table equal to
|
|
58
|
+
// the flags the handlers read. Three kinds:
|
|
59
|
+
// - switch: never takes a value, so it may come before a path
|
|
60
|
+
// (`atlas ste --share page.md`, a miss on 6 October);
|
|
61
|
+
// - value: takes the next word, and a flag with no value stops the command;
|
|
62
|
+
// - optional: takes the next word unless it is a flag; alone it means the
|
|
63
|
+
// default (`--root` alone is this folder, `upgrade --version` alone is the
|
|
64
|
+
// newest release).
|
|
65
|
+
// Any other flag stops the command with exit 2. A misspelt `--shared` once
|
|
66
|
+
// skipped the privacy filter and printed GREEN (review of PR #107).
|
|
67
|
+
export const FLAGS = Object.freeze({
|
|
68
|
+
tooling: { root: 'optional', branch: 'optional', 'replace-unknown': 'switch', workflow: 'switch', 'dry-run': 'switch' },
|
|
69
|
+
status: { root: 'optional' },
|
|
70
|
+
'kind-drift': { root: 'optional', 'record-kind': 'value', registry: 'value', repo: 'value' },
|
|
71
|
+
check: { root: 'optional', repo: 'value', 'fail-on': 'value' },
|
|
72
|
+
ste: { share: 'switch', terms: 'value' },
|
|
73
|
+
design: {},
|
|
74
|
+
install: { local: 'switch', from: 'value', 'skip-global': 'switch', yes: 'switch' },
|
|
75
|
+
upgrade: { version: 'optional', yes: 'switch' },
|
|
76
|
+
doctor: {},
|
|
77
|
+
});
|
|
60
78
|
|
|
61
|
-
|
|
79
|
+
// Every command takes --help.
|
|
80
|
+
export function options(argv, declared = {}) {
|
|
81
|
+
const kinds = { help: 'switch', ...declared };
|
|
62
82
|
const out = { _: [] };
|
|
63
83
|
for (let index = 0; index < argv.length; index += 1) {
|
|
64
|
-
const
|
|
65
|
-
if (!
|
|
66
|
-
const
|
|
84
|
+
const word = argv[index];
|
|
85
|
+
if (!word.startsWith('--')) { out._.push(word); continue; }
|
|
86
|
+
const equals = word.indexOf('=');
|
|
87
|
+
const key = word.slice(2, equals === -1 ? undefined : equals);
|
|
88
|
+
const kind = Object.hasOwn(kinds, key) ? kinds[key] : null;
|
|
89
|
+
if (!kind) throw new Error(`there is no flag "--${key}" for "atlas ${argv[0]}". Run "atlas help".`);
|
|
90
|
+
if (equals !== -1) {
|
|
91
|
+
if (kind === 'switch') throw new Error(`the flag "--${key}" takes no value.`);
|
|
92
|
+
if (equals === word.length - 1) throw new Error(`the flag "--${key}" needs a value.`);
|
|
93
|
+
out[key] = word.slice(equals + 1);
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (kind === 'switch') { out[key] = true; continue; }
|
|
67
97
|
const value = argv[index + 1];
|
|
68
|
-
if (
|
|
98
|
+
if (value === undefined || value.startsWith('--')) {
|
|
99
|
+
if (kind === 'value') throw new Error(`the flag "--${key}" needs a value.`);
|
|
100
|
+
out[key] = true;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (value === '') throw new Error(`the flag "--${key}" needs a value.`);
|
|
69
104
|
out[key] = value;
|
|
70
105
|
index += 1;
|
|
71
106
|
}
|
|
@@ -123,10 +158,10 @@ function statusCommand(chosen) {
|
|
|
123
158
|
|
|
124
159
|
function kindDriftCommand(chosen) {
|
|
125
160
|
const root = rootOf(chosen);
|
|
126
|
-
let recordKind = chosen['record-kind']
|
|
127
|
-
if (!recordKind && chosen.registry
|
|
161
|
+
let recordKind = chosen['record-kind'] ?? null;
|
|
162
|
+
if (!recordKind && chosen.registry) {
|
|
128
163
|
const kinds = kindsFromRegistry(JSON.parse(readFileSync(resolve(chosen.registry), 'utf8')));
|
|
129
|
-
const repo = chosen.repo
|
|
164
|
+
const repo = chosen.repo ?? null;
|
|
130
165
|
recordKind = repo ? kinds[repo] ?? null : null;
|
|
131
166
|
if (!repo) {
|
|
132
167
|
// One checkout, so only the registry row that names THIS repo can be
|
|
@@ -159,7 +194,8 @@ function steCommand(chosen) {
|
|
|
159
194
|
const paths = chosen._.slice(1);
|
|
160
195
|
if (!paths.length) throw new Error('give a file or a folder: atlas ste <path> [--share]');
|
|
161
196
|
const share = Boolean(chosen.share);
|
|
162
|
-
|
|
197
|
+
if (chosen.terms !== undefined && !share) throw new Error('--terms works only with --share.');
|
|
198
|
+
const terms = share ? loadPrivateTerms({ path: chosen.terms !== undefined ? resolve(chosen.terms) : null }) : [];
|
|
163
199
|
const results = checkPaths(paths.map((one) => resolve(one)), { share, terms });
|
|
164
200
|
let count = 0;
|
|
165
201
|
for (const { file, findings } of results) {
|
|
@@ -186,8 +222,8 @@ function designCommand(chosen) {
|
|
|
186
222
|
|
|
187
223
|
function checkCommand(chosen) {
|
|
188
224
|
const root = rootOf(chosen);
|
|
189
|
-
const report = scan({ root, repoId: chosen.repo
|
|
190
|
-
const decision = verdict(report, chosen['fail-on']
|
|
225
|
+
const report = scan({ root, repoId: chosen.repo ?? null });
|
|
226
|
+
const decision = verdict(report, chosen['fail-on'] ?? 'error');
|
|
191
227
|
process.stdout.write(toText(report));
|
|
192
228
|
line(`${decision.green ? 'GREEN' : 'RED'}: ${decision.why}`);
|
|
193
229
|
return decision.green ? 0 : 1;
|
|
@@ -200,8 +236,10 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
200
236
|
const result = spawnSync(process.execPath, [join(PACKAGE_ROOT, 'work', 'code-read.mjs'), ...argv.slice(1)], { stdio: 'inherit' });
|
|
201
237
|
return result.status ?? 1;
|
|
202
238
|
}
|
|
203
|
-
|
|
204
|
-
if (!command
|
|
239
|
+
if (!command || command === 'help' || command === '--help') { process.stdout.write(HELP); return 0; }
|
|
240
|
+
if (!Object.hasOwn(FLAGS, command)) throw new Error(`there is no verb "${command}". Run "atlas help".`);
|
|
241
|
+
const chosen = options(argv, FLAGS[command]);
|
|
242
|
+
if (chosen.help) { process.stdout.write(HELP); return 0; }
|
|
205
243
|
switch (command) {
|
|
206
244
|
case 'install': return install({ packageRoot: PACKAGE_ROOT, options: chosen, line });
|
|
207
245
|
case 'upgrade': return upgrade({ packageRoot: PACKAGE_ROOT, options: chosen, line });
|
package/door/lib/install.mjs
CHANGED
|
@@ -67,7 +67,7 @@ const findPlugin = (listed, id) => pluginRows(listed).find((row) => row.id === i
|
|
|
67
67
|
export async function install({ packageRoot, options = {}, line = console.log, env = process.env, exec = defaultExec, ask = defaultAsk }) {
|
|
68
68
|
const { name, version } = packageJson(packageRoot);
|
|
69
69
|
const local = Boolean(options.local);
|
|
70
|
-
const from = options.from
|
|
70
|
+
const from = options.from ? String(options.from) : null;
|
|
71
71
|
const catalog = catalogFor({ name, version, local });
|
|
72
72
|
const file = catalogFile(env);
|
|
73
73
|
const before = existsSync(file) ? readFileSync(file, 'utf8') : null;
|
package/door/lib/privacy.mjs
CHANGED
|
@@ -27,10 +27,15 @@ export const PRIVACY_PATTERNS = Object.freeze([
|
|
|
27
27
|
|
|
28
28
|
const escape = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
29
29
|
|
|
30
|
-
// The owner's private terms
|
|
30
|
+
// The owner's private terms. The default file is optional: no file there
|
|
31
|
+
// means no terms. A file the caller names must exist, because a mistyped
|
|
32
|
+
// name once loaded no terms and passed the page (review of PR #107).
|
|
31
33
|
export function loadPrivateTerms({ path = null, home = homedir() } = {}) {
|
|
32
34
|
const file = path ?? join(home, PRIVATE_TERMS_PATH);
|
|
33
|
-
if (!existsSync(file))
|
|
35
|
+
if (!existsSync(file)) {
|
|
36
|
+
if (path) throw new Error(`the private terms file ${path} does not exist.`);
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
34
39
|
return readFileSync(file, 'utf8').split('\n').map((line) => line.trim()).filter((line) => line && !line.startsWith('#'));
|
|
35
40
|
}
|
|
36
41
|
|
package/package.json
CHANGED