codz-cli 0.0.0-stage → 0.1.2
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/BETA.md +91 -0
- package/LICENSE +21 -0
- package/README.md +525 -2
- package/assets/gradle-wrapper/README.txt +2 -0
- package/assets/gradle-wrapper/gradle-wrapper.jar +0 -0
- package/assets/gradle-wrapper/gradlew +251 -0
- package/assets/gradle-wrapper/gradlew.bat +94 -0
- package/bin/codz.js +33 -0
- package/dist/adapters/android.js +321 -0
- package/dist/adapters/androidSetup.js +277 -0
- package/dist/adapters/common.js +114 -0
- package/dist/adapters/dartGen.js +83 -0
- package/dist/adapters/flutter.js +291 -0
- package/dist/adapters/flutterGen.js +204 -0
- package/dist/adapters/flutterScan.js +312 -0
- package/dist/adapters/flutterSetup.js +252 -0
- package/dist/adapters/flutterStyles.js +130 -0
- package/dist/adapters/generic.js +20 -0
- package/dist/adapters/getx.js +423 -0
- package/dist/adapters/index.js +28 -0
- package/dist/adapters/ios.js +440 -0
- package/dist/adapters/kotlinGen.js +110 -0
- package/dist/adapters/models.js +116 -0
- package/dist/adapters/nextjs.js +243 -0
- package/dist/adapters/nextjsGen.js +285 -0
- package/dist/adapters/nextjsScan.js +364 -0
- package/dist/adapters/nextjsSetup.js +119 -0
- package/dist/adapters/react.js +89 -0
- package/dist/adapters/reactNative.js +109 -0
- package/dist/adapters/reactNativeSetup.js +236 -0
- package/dist/adapters/reactQuery.js +89 -0
- package/dist/adapters/reactSetup.js +150 -0
- package/dist/adapters/source.js +165 -0
- package/dist/cli.js +1175 -0
- package/dist/core/cache.js +76 -0
- package/dist/core/changeset.js +404 -0
- package/dist/core/commands.js +239 -0
- package/dist/core/config.js +45 -0
- package/dist/core/diff.js +143 -0
- package/dist/core/events.js +41 -0
- package/dist/core/fsutil.js +122 -0
- package/dist/core/git.js +36 -0
- package/dist/core/jsonEdit.js +113 -0
- package/dist/core/merge.js +159 -0
- package/dist/core/proc.js +23 -0
- package/dist/core/safe.js +75 -0
- package/dist/core/templates.js +100 -0
- package/dist/core/tsAst.js +112 -0
- package/dist/core/types.js +12 -0
- package/dist/core/validateConfig.js +172 -0
- package/dist/core/workflow.js +72 -0
- package/dist/core/workspace.js +80 -0
- package/dist/core/yaml.js +126 -0
- package/dist/core/yamlDoc.js +367 -0
- package/dist/detector.js +95 -0
- package/dist/input/apiSpec.js +395 -0
- package/dist/input/curl.js +259 -0
- package/dist/input/endpoint.js +220 -0
- package/dist/input/har.js +120 -0
- package/dist/input/infer.js +174 -0
- package/dist/input/naming.js +145 -0
- package/dist/input/paste.js +130 -0
- package/dist/skills/androidSkeleton.js +292 -0
- package/dist/skills/androidTests.js +221 -0
- package/dist/skills/androidUi.js +561 -0
- package/dist/skills/androidViews.js +536 -0
- package/dist/skills/apiAdd.js +99 -0
- package/dist/skills/apiDiff.js +271 -0
- package/dist/skills/apiEdit.js +547 -0
- package/dist/skills/apiImport.js +127 -0
- package/dist/skills/apiList.js +35 -0
- package/dist/skills/apiSync.js +221 -0
- package/dist/skills/auth.js +1304 -0
- package/dist/skills/completion.js +142 -0
- package/dist/skills/config.js +93 -0
- package/dist/skills/create.js +638 -0
- package/dist/skills/createDemo.js +1026 -0
- package/dist/skills/doctor.js +304 -0
- package/dist/skills/doctorFix.js +214 -0
- package/dist/skills/explain.js +61 -0
- package/dist/skills/feature.js +418 -0
- package/dist/skills/featureEdit.js +225 -0
- package/dist/skills/featureLinks.js +179 -0
- package/dist/skills/init.js +66 -0
- package/dist/skills/iosUi.js +468 -0
- package/dist/skills/locale.js +335 -0
- package/dist/skills/mcp.js +175 -0
- package/dist/skills/mock.js +482 -0
- package/dist/skills/module.js +23 -0
- package/dist/skills/plans.js +66 -0
- package/dist/skills/prefill.js +84 -0
- package/dist/skills/reactNativeUi.js +388 -0
- package/dist/skills/reactUi.js +352 -0
- package/dist/skills/report.js +75 -0
- package/dist/skills/route.js +230 -0
- package/dist/skills/screen.js +597 -0
- package/dist/skills/screenForm.js +410 -0
- package/dist/skills/setup.js +28 -0
- package/dist/skills/setupDoctor.js +226 -0
- package/dist/skills/templatesCmd.js +32 -0
- package/dist/skills/testgen.js +331 -0
- package/dist/skills/theme.js +388 -0
- package/dist/starters/auth.js +144 -0
- package/dist/starters/commands.js +283 -0
- package/dist/starters/engine.js +315 -0
- package/dist/starters/home.js +42 -0
- package/dist/starters/http.js +93 -0
- package/dist/starters/manifest.js +285 -0
- package/dist/starters/paths.js +70 -0
- package/dist/starters/publish.js +150 -0
- package/dist/starters/registry.js +258 -0
- package/dist/starters/sign.js +72 -0
- package/dist/starters/source.js +98 -0
- package/dist/starters/strictJson.js +148 -0
- package/dist/starters/tar.js +180 -0
- package/docs/COMMANDS.md +527 -0
- package/examples/openapi.yaml +319 -0
- package/package.json +57 -4
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
// Shell completion. `codz completion bash|zsh|fish` prints a script that calls
|
|
2
|
+
// the hidden `codz __complete <words...>` command, so all three shells share
|
|
3
|
+
// one implementation, including endpoint names, plan ids and config keys.
|
|
4
|
+
import { readdirSync } from 'node:fs';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { loadMap, setCacheWrites, TOOL_DIR } from "../core/cache.js";
|
|
7
|
+
import { CONFIG_FILE, loadConfig } from "../core/config.js";
|
|
8
|
+
import { exists } from "../core/fsutil.js";
|
|
9
|
+
import { ALLOWED, knownKeys } from "../core/validateConfig.js";
|
|
10
|
+
import { CHANGE_FLAGS, COMMAND_LIST, FLAGS, GLOBAL_FLAGS } from "../core/commands.js";
|
|
11
|
+
import { TEMPLATES } from "../core/templates.js";
|
|
12
|
+
export const SHELLS = ['bash', 'zsh', 'fish'];
|
|
13
|
+
/** Commands, their subcommands and the flags each takes, from the command table. */
|
|
14
|
+
export const COMMANDS = {};
|
|
15
|
+
for (const c of COMMAND_LIST) {
|
|
16
|
+
const flags = [...c.flags, ...(c.change ? CHANGE_FLAGS : [])].filter((f) => f.length > 1).map((f) => `--${f}`);
|
|
17
|
+
const entry = (COMMANDS[c.cmd] ??= {});
|
|
18
|
+
if (c.sub)
|
|
19
|
+
(entry.subs ??= {})[c.sub] = flags;
|
|
20
|
+
else
|
|
21
|
+
entry.flags = flags;
|
|
22
|
+
}
|
|
23
|
+
const GLOBAL = GLOBAL_FLAGS.filter((f) => f.length > 1).map((f) => `--${f}`);
|
|
24
|
+
/** Flags whose value is a file or folder (the shell completes paths). */
|
|
25
|
+
const PATH_FLAGS = new Set(Object.entries(FLAGS).filter(([, f]) => f.path).map(([n]) => `--${n}`));
|
|
26
|
+
const VALUE_FLAGS = new Set(Object.entries(FLAGS).filter(([, f]) => f.value).map(([n]) => `--${n}`));
|
|
27
|
+
export const FILES = '__files__';
|
|
28
|
+
function endpointNames(root, adapter) {
|
|
29
|
+
return loadMap(root, adapter, loadConfig(root).conventions)
|
|
30
|
+
.then(({ map }) => map.endpoints.map((e) => e.name))
|
|
31
|
+
.catch(() => []);
|
|
32
|
+
}
|
|
33
|
+
function planIds(root) {
|
|
34
|
+
try {
|
|
35
|
+
return readdirSync(join(root, TOOL_DIR, 'plans')).filter((n) => n.endsWith('.json')).map((n) => n.slice(0, -5)).sort().reverse();
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Candidates for the last word. `words` are the words after "codz", the last
|
|
43
|
+
* one being the word under the cursor (possibly empty).
|
|
44
|
+
*/
|
|
45
|
+
export async function complete(words, root, adapter) {
|
|
46
|
+
setCacheWrites(false);
|
|
47
|
+
const cur = words[words.length - 1] ?? '';
|
|
48
|
+
const prev = words[words.length - 2];
|
|
49
|
+
const positional = words.slice(0, -1).filter((w, i, a) => !w.startsWith('-') && !(i > 0 && VALUE_FLAGS.has(a[i - 1])));
|
|
50
|
+
const [cmd, sub] = positional;
|
|
51
|
+
const spec = cmd ? COMMANDS[cmd] : undefined;
|
|
52
|
+
const hasProject = exists(join(root, CONFIG_FILE));
|
|
53
|
+
if (prev && VALUE_FLAGS.has(prev)) {
|
|
54
|
+
if (PATH_FLAGS.has(prev))
|
|
55
|
+
return [FILES];
|
|
56
|
+
const choices = FLAGS[prev.slice(2)]?.choices;
|
|
57
|
+
if (choices)
|
|
58
|
+
return choices;
|
|
59
|
+
if (prev === '--architecture')
|
|
60
|
+
return adapter.id === 'flutter' ? ['getx', 'riverpod', 'get_it'] : ['fetch-helper', 'plain-fetch'];
|
|
61
|
+
if (prev === '--only' && cmd === 'doctor')
|
|
62
|
+
return ['locales', 'api', 'urls', 'models'];
|
|
63
|
+
if (prev === '--api' && hasProject)
|
|
64
|
+
return endpointNames(root, adapter);
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
if (cur.startsWith('-')) {
|
|
68
|
+
const own = spec?.subs ? (sub ? spec.subs[sub] ?? [] : []) : spec?.flags ?? [];
|
|
69
|
+
return [...new Set([...own, ...GLOBAL])];
|
|
70
|
+
}
|
|
71
|
+
if (!cmd)
|
|
72
|
+
return Object.keys(COMMANDS);
|
|
73
|
+
if (spec?.subs && !sub)
|
|
74
|
+
return Object.keys(spec.subs);
|
|
75
|
+
const argIndex = positional.length - (spec?.subs ? 2 : 1); // 0 = first argument after the (sub)command
|
|
76
|
+
const kind = COMMAND_LIST.find((c) => c.cmd === cmd && c.sub === (spec?.subs ? sub : undefined))?.args;
|
|
77
|
+
if (kind === 'template')
|
|
78
|
+
return TEMPLATES.map((t) => t.id);
|
|
79
|
+
if (kind === 'shell')
|
|
80
|
+
return argIndex === 0 ? ['bash', 'zsh', 'fish'] : [];
|
|
81
|
+
if (kind === 'endpoints' && hasProject)
|
|
82
|
+
return endpointNames(root, adapter);
|
|
83
|
+
if (cmd === 'api' && ['show', 'remove', 'rename', 'update', 'wire'].includes(sub) && argIndex === 0 && hasProject)
|
|
84
|
+
return endpointNames(root, adapter);
|
|
85
|
+
if (cmd === 'api' && (sub === 'import' || sub === 'sync') && argIndex === 0)
|
|
86
|
+
return [FILES];
|
|
87
|
+
if (cmd === 'mock' && sub === 'add' && hasProject)
|
|
88
|
+
return endpointNames(root, adapter);
|
|
89
|
+
if ((cmd === 'plans' && sub === 'show') || cmd === 'apply')
|
|
90
|
+
return argIndex === 0 ? planIds(root) : [];
|
|
91
|
+
if (cmd === 'config' && (sub === 'get' || sub === 'set') && argIndex === 0)
|
|
92
|
+
return Object.keys(knownKeys(adapter.id));
|
|
93
|
+
if (cmd === 'config' && sub === 'set' && argIndex === 1)
|
|
94
|
+
return ALLOWED[adapter.id]?.[positional[2]] ?? [];
|
|
95
|
+
if (cmd === 'theme' && sub === 'set' && argIndex % 2 === 0)
|
|
96
|
+
return ['primary', 'secondary', 'accent', 'background', 'surface', 'error', 'radius', 'spacing', 'font'];
|
|
97
|
+
return [];
|
|
98
|
+
}
|
|
99
|
+
export function completionScript(shell) {
|
|
100
|
+
if (shell === 'bash') {
|
|
101
|
+
return `# codz completion for bash. Add to ~/.bashrc: eval "$(codz completion bash)"
|
|
102
|
+
_codz() {
|
|
103
|
+
local cur="\${COMP_WORDS[COMP_CWORD]}" out
|
|
104
|
+
out=$(codz __complete "\${COMP_WORDS[@]:1:COMP_CWORD}" 2>/dev/null)
|
|
105
|
+
if [ "$out" = "${FILES}" ]; then
|
|
106
|
+
COMPREPLY=($(compgen -f -- "$cur"))
|
|
107
|
+
else
|
|
108
|
+
local IFS=$'\\n'
|
|
109
|
+
COMPREPLY=($(compgen -W "$out" -- "$cur"))
|
|
110
|
+
fi
|
|
111
|
+
}
|
|
112
|
+
complete -o default -F _codz codz
|
|
113
|
+
`;
|
|
114
|
+
}
|
|
115
|
+
if (shell === 'zsh') {
|
|
116
|
+
return `#compdef codz
|
|
117
|
+
# codz completion for zsh. Add to ~/.zshrc (after compinit): source <(codz completion zsh)
|
|
118
|
+
_codz() {
|
|
119
|
+
local -a out
|
|
120
|
+
out=("\${(@f)$(codz __complete "\${words[@]:1:$((CURRENT-1))}" 2>/dev/null)}")
|
|
121
|
+
if [[ "\${out[1]}" == "${FILES}" ]]; then
|
|
122
|
+
_files
|
|
123
|
+
else
|
|
124
|
+
compadd -a out
|
|
125
|
+
fi
|
|
126
|
+
}
|
|
127
|
+
compdef _codz codz
|
|
128
|
+
`;
|
|
129
|
+
}
|
|
130
|
+
return `# codz completion for fish. Save as ~/.config/fish/completions/codz.fish:
|
|
131
|
+
# codz completion fish > ~/.config/fish/completions/codz.fish
|
|
132
|
+
function __codz_complete
|
|
133
|
+
set -l out (codz __complete (commandline -opc)[2..-1] (commandline -ct) 2>/dev/null)
|
|
134
|
+
if test "$out" = "${FILES}"
|
|
135
|
+
__fish_complete_path (commandline -ct)
|
|
136
|
+
else
|
|
137
|
+
printf '%s\\n' $out
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
complete -c codz -f -a '(__codz_complete)'
|
|
141
|
+
`;
|
|
142
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// codz config: view, get and set conventions, and check the config file.
|
|
2
|
+
// `config set` edits codz.config.yaml in place (comments and order stay) and
|
|
3
|
+
// goes through the usual preview → apply → undo pipeline.
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { loadMap } from "../core/cache.js";
|
|
6
|
+
import { buildChangeSet } from "../core/changeset.js";
|
|
7
|
+
import { CONFIG_FILE, loadConfig } from "../core/config.js";
|
|
8
|
+
import { readText } from "../core/fsutil.js";
|
|
9
|
+
import { ToolError } from "../core/types.js";
|
|
10
|
+
import { ALLOWED, checkValue, closest, knownKeys, validateConfig } from "../core/validateConfig.js";
|
|
11
|
+
import { scalar } from "../core/yaml.js";
|
|
12
|
+
export async function configView(root, adapter) {
|
|
13
|
+
const cfg = loadConfig(root);
|
|
14
|
+
const { map } = await loadMap(root, adapter, cfg.conventions);
|
|
15
|
+
const docs = knownKeys(adapter.id);
|
|
16
|
+
const keys = [...new Set([...Object.keys(docs), ...Object.keys(map.conventions)])];
|
|
17
|
+
const rows = keys
|
|
18
|
+
.filter((k) => k in docs || map.conventions[k] !== undefined)
|
|
19
|
+
.map((key) => ({
|
|
20
|
+
key,
|
|
21
|
+
value: cfg.conventions[key] ?? map.conventions[key] ?? '',
|
|
22
|
+
source: (key in cfg.conventions ? 'config' : 'detected'),
|
|
23
|
+
description: docs[key] ?? '',
|
|
24
|
+
allowed: ALLOWED[adapter.id]?.[key],
|
|
25
|
+
}));
|
|
26
|
+
return { framework: adapter.id, file: cfg.exists ? CONFIG_FILE : null, rows };
|
|
27
|
+
}
|
|
28
|
+
export function configCheck(root) {
|
|
29
|
+
const text = readText(join(root, CONFIG_FILE));
|
|
30
|
+
if (text === null)
|
|
31
|
+
throw new ToolError('no_config', `There is no ${CONFIG_FILE} here.`, 'Create one with: codz init');
|
|
32
|
+
return { issues: validateConfig(text, root), file: CONFIG_FILE };
|
|
33
|
+
}
|
|
34
|
+
export function planConfigSet(root, adapter, key, value, opts = {}) {
|
|
35
|
+
const text = readText(join(root, CONFIG_FILE));
|
|
36
|
+
if (text === null)
|
|
37
|
+
throw new ToolError('no_config', `There is no ${CONFIG_FILE} here.`, 'Create one with: codz init');
|
|
38
|
+
const docs = knownKeys(adapter.id);
|
|
39
|
+
if (!(key in docs) && !opts.force) {
|
|
40
|
+
const close = closest(key, Object.keys(docs));
|
|
41
|
+
throw new ToolError('unknown_key', `"${key}" is not a ${adapter.id} convention.`, close ? `Did you mean ${close}?` : `Known keys: ${Object.keys(docs).join(', ')}. Pass --force to set it anyway.`);
|
|
42
|
+
}
|
|
43
|
+
const issue = checkValue(adapter.id, key, value, root);
|
|
44
|
+
if (issue?.level === 'error')
|
|
45
|
+
throw new ToolError('bad_value', issue.message, issue.hint);
|
|
46
|
+
const eol = text.includes('\r\n') ? '\r\n' : '\n';
|
|
47
|
+
const lines = text.split(/\r?\n/);
|
|
48
|
+
let convAt = lines.findIndex((l) => /^conventions:\s*(#.*)?$/.test(l) || /^conventions:\s*\{\}\s*$/.test(l));
|
|
49
|
+
if (convAt === -1) {
|
|
50
|
+
// No conventions block yet: add one at the end.
|
|
51
|
+
if (lines[lines.length - 1] === '')
|
|
52
|
+
lines.pop();
|
|
53
|
+
lines.push('conventions:');
|
|
54
|
+
convAt = lines.length - 1;
|
|
55
|
+
lines.push('');
|
|
56
|
+
}
|
|
57
|
+
else if (/\{\}/.test(lines[convAt]))
|
|
58
|
+
lines[convAt] = 'conventions:';
|
|
59
|
+
// The block runs while lines are indented (or blank/comment lines inside it).
|
|
60
|
+
let end = convAt + 1;
|
|
61
|
+
let found = -1;
|
|
62
|
+
let indent = ' ';
|
|
63
|
+
while (end < lines.length && (/^\s+\S/.test(lines[end]) || lines[end].trim() === '')) {
|
|
64
|
+
const m = /^(\s+)([^#\s][^:]*):/.exec(lines[end]);
|
|
65
|
+
if (m) {
|
|
66
|
+
indent = m[1];
|
|
67
|
+
if (m[2].trim() === key)
|
|
68
|
+
found = end;
|
|
69
|
+
}
|
|
70
|
+
end++;
|
|
71
|
+
}
|
|
72
|
+
// Do not swallow blank lines that follow the block.
|
|
73
|
+
while (end > convAt + 1 && lines[end - 1].trim() === '')
|
|
74
|
+
end--;
|
|
75
|
+
const rendered = `${indent}${key}: ${scalar(value)}`;
|
|
76
|
+
let before = null;
|
|
77
|
+
if (found !== -1) {
|
|
78
|
+
const old = /:\s*(.*)$/.exec(lines[found])?.[1] ?? '';
|
|
79
|
+
before = old.replace(/^'(.*)'$/, '$1');
|
|
80
|
+
const trailing = /\s+#.*$/.exec(lines[found].slice(lines[found].indexOf(':') + 1));
|
|
81
|
+
lines[found] = rendered + (trailing && !/['"]/.test(trailing[0]) ? trailing[0] : '');
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
const insert = docs[key] ? [`${indent}# ${docs[key]}`, rendered] : [rendered];
|
|
85
|
+
lines.splice(end, 0, ...insert);
|
|
86
|
+
}
|
|
87
|
+
const next = lines.join(eol);
|
|
88
|
+
const summary = [found !== -1 ? `Set ${key}: ${before || "''"} → ${value || "'' (detect)"} in ${CONFIG_FILE}` : `Add ${key}: ${value || "''"} to ${CONFIG_FILE}`];
|
|
89
|
+
const warnings = issue ? [issue.message + (issue.hint ? ` ${issue.hint}` : '')] : [];
|
|
90
|
+
if (value === '')
|
|
91
|
+
warnings.push(`An empty ${key} means codz detects it from the code again.`);
|
|
92
|
+
return buildChangeSet(root, 'config set', { files: new Map([[CONFIG_FILE, next]]), summary, warnings, generated: [] });
|
|
93
|
+
}
|