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.
Files changed (118) hide show
  1. package/BETA.md +91 -0
  2. package/LICENSE +21 -0
  3. package/README.md +525 -2
  4. package/assets/gradle-wrapper/README.txt +2 -0
  5. package/assets/gradle-wrapper/gradle-wrapper.jar +0 -0
  6. package/assets/gradle-wrapper/gradlew +251 -0
  7. package/assets/gradle-wrapper/gradlew.bat +94 -0
  8. package/bin/codz.js +33 -0
  9. package/dist/adapters/android.js +321 -0
  10. package/dist/adapters/androidSetup.js +277 -0
  11. package/dist/adapters/common.js +114 -0
  12. package/dist/adapters/dartGen.js +83 -0
  13. package/dist/adapters/flutter.js +291 -0
  14. package/dist/adapters/flutterGen.js +204 -0
  15. package/dist/adapters/flutterScan.js +312 -0
  16. package/dist/adapters/flutterSetup.js +252 -0
  17. package/dist/adapters/flutterStyles.js +130 -0
  18. package/dist/adapters/generic.js +20 -0
  19. package/dist/adapters/getx.js +423 -0
  20. package/dist/adapters/index.js +28 -0
  21. package/dist/adapters/ios.js +440 -0
  22. package/dist/adapters/kotlinGen.js +110 -0
  23. package/dist/adapters/models.js +116 -0
  24. package/dist/adapters/nextjs.js +243 -0
  25. package/dist/adapters/nextjsGen.js +285 -0
  26. package/dist/adapters/nextjsScan.js +364 -0
  27. package/dist/adapters/nextjsSetup.js +119 -0
  28. package/dist/adapters/react.js +89 -0
  29. package/dist/adapters/reactNative.js +109 -0
  30. package/dist/adapters/reactNativeSetup.js +236 -0
  31. package/dist/adapters/reactQuery.js +89 -0
  32. package/dist/adapters/reactSetup.js +150 -0
  33. package/dist/adapters/source.js +165 -0
  34. package/dist/cli.js +1175 -0
  35. package/dist/core/cache.js +76 -0
  36. package/dist/core/changeset.js +404 -0
  37. package/dist/core/commands.js +239 -0
  38. package/dist/core/config.js +45 -0
  39. package/dist/core/diff.js +143 -0
  40. package/dist/core/events.js +41 -0
  41. package/dist/core/fsutil.js +122 -0
  42. package/dist/core/git.js +36 -0
  43. package/dist/core/jsonEdit.js +113 -0
  44. package/dist/core/merge.js +159 -0
  45. package/dist/core/proc.js +23 -0
  46. package/dist/core/safe.js +75 -0
  47. package/dist/core/templates.js +100 -0
  48. package/dist/core/tsAst.js +112 -0
  49. package/dist/core/types.js +12 -0
  50. package/dist/core/validateConfig.js +172 -0
  51. package/dist/core/workflow.js +72 -0
  52. package/dist/core/workspace.js +80 -0
  53. package/dist/core/yaml.js +126 -0
  54. package/dist/core/yamlDoc.js +367 -0
  55. package/dist/detector.js +95 -0
  56. package/dist/input/apiSpec.js +395 -0
  57. package/dist/input/curl.js +259 -0
  58. package/dist/input/endpoint.js +220 -0
  59. package/dist/input/har.js +120 -0
  60. package/dist/input/infer.js +174 -0
  61. package/dist/input/naming.js +145 -0
  62. package/dist/input/paste.js +130 -0
  63. package/dist/skills/androidSkeleton.js +292 -0
  64. package/dist/skills/androidTests.js +221 -0
  65. package/dist/skills/androidUi.js +561 -0
  66. package/dist/skills/androidViews.js +536 -0
  67. package/dist/skills/apiAdd.js +99 -0
  68. package/dist/skills/apiDiff.js +271 -0
  69. package/dist/skills/apiEdit.js +547 -0
  70. package/dist/skills/apiImport.js +127 -0
  71. package/dist/skills/apiList.js +35 -0
  72. package/dist/skills/apiSync.js +221 -0
  73. package/dist/skills/auth.js +1304 -0
  74. package/dist/skills/completion.js +142 -0
  75. package/dist/skills/config.js +93 -0
  76. package/dist/skills/create.js +638 -0
  77. package/dist/skills/createDemo.js +1026 -0
  78. package/dist/skills/doctor.js +304 -0
  79. package/dist/skills/doctorFix.js +214 -0
  80. package/dist/skills/explain.js +61 -0
  81. package/dist/skills/feature.js +418 -0
  82. package/dist/skills/featureEdit.js +225 -0
  83. package/dist/skills/featureLinks.js +179 -0
  84. package/dist/skills/init.js +66 -0
  85. package/dist/skills/iosUi.js +468 -0
  86. package/dist/skills/locale.js +335 -0
  87. package/dist/skills/mcp.js +175 -0
  88. package/dist/skills/mock.js +482 -0
  89. package/dist/skills/module.js +23 -0
  90. package/dist/skills/plans.js +66 -0
  91. package/dist/skills/prefill.js +84 -0
  92. package/dist/skills/reactNativeUi.js +388 -0
  93. package/dist/skills/reactUi.js +352 -0
  94. package/dist/skills/report.js +75 -0
  95. package/dist/skills/route.js +230 -0
  96. package/dist/skills/screen.js +597 -0
  97. package/dist/skills/screenForm.js +410 -0
  98. package/dist/skills/setup.js +28 -0
  99. package/dist/skills/setupDoctor.js +226 -0
  100. package/dist/skills/templatesCmd.js +32 -0
  101. package/dist/skills/testgen.js +331 -0
  102. package/dist/skills/theme.js +388 -0
  103. package/dist/starters/auth.js +144 -0
  104. package/dist/starters/commands.js +283 -0
  105. package/dist/starters/engine.js +315 -0
  106. package/dist/starters/home.js +42 -0
  107. package/dist/starters/http.js +93 -0
  108. package/dist/starters/manifest.js +285 -0
  109. package/dist/starters/paths.js +70 -0
  110. package/dist/starters/publish.js +150 -0
  111. package/dist/starters/registry.js +258 -0
  112. package/dist/starters/sign.js +72 -0
  113. package/dist/starters/source.js +98 -0
  114. package/dist/starters/strictJson.js +148 -0
  115. package/dist/starters/tar.js +180 -0
  116. package/docs/COMMANDS.md +527 -0
  117. package/examples/openapi.yaml +319 -0
  118. 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
+ }