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,180 @@
1
+ // A small, strict reader (and a deterministic writer) for starter archives:
2
+ // gzip-compressed ustar holding regular files and folders only. Anything else
3
+ // (links, devices, FIFOs, GNU long names, global or unknown pax records,
4
+ // duplicate or unsafe paths) stops the read before a single byte is written.
5
+ import { gunzipSync, gzipSync } from 'node:zlib';
6
+ import { ToolError } from "../core/types.js";
7
+ import { checkCollisions, checkRelPath, LIMITS } from "./paths.js";
8
+ const tooLarge = (what) => new ToolError('archive_too_large', `The archive exceeds a safety limit (${what}).`, 'Report it; nothing was written.');
9
+ const unsafe = (what) => new ToolError('archive_unsafe', `The archive has an unsafe entry: ${what}. Nothing was written.`, 'Do not use this template; report it.');
10
+ const broken = (what) => new ToolError('bad_template', `The archive is damaged: ${what}.`, 'Clear the cache with codz starters cache --clear and retry; report it if it persists.');
11
+ function field(b, off, len) {
12
+ const raw = b.subarray(off, off + len);
13
+ const nul = raw.indexOf(0);
14
+ return raw.subarray(0, nul === -1 ? len : nul).toString('utf8');
15
+ }
16
+ function octal(b, off, len, what) {
17
+ if (b[off] & 0x80)
18
+ throw unsafe(`a binary-encoded ${what}`);
19
+ const s = field(b, off, len).trim();
20
+ if (!s)
21
+ return 0;
22
+ if (!/^[0-7]+$/.test(s))
23
+ throw broken(`a bad ${what} field`);
24
+ return parseInt(s, 8);
25
+ }
26
+ export function readTarGz(gz) {
27
+ if (gz.length > LIMITS.compressedBytes)
28
+ throw tooLarge(`${LIMITS.compressedBytes / 1024 / 1024} MB compressed`);
29
+ let tar;
30
+ try {
31
+ // The cap stops a decompression bomb while it inflates, not after.
32
+ tar = gunzipSync(gz, { maxOutputLength: LIMITS.expandedBytes + LIMITS.entries * 1024 + 1024 });
33
+ }
34
+ catch (e) {
35
+ const msg = e.message;
36
+ if (/maxOutputLength|buffer|too large/i.test(msg) || e.code === 'ERR_BUFFER_TOO_LARGE')
37
+ throw tooLarge(`${LIMITS.expandedBytes / 1024 / 1024} MB expanded`);
38
+ throw broken('it is not a valid gzip file');
39
+ }
40
+ const files = new Map();
41
+ const dirs = new Set();
42
+ let total = 0;
43
+ let entries = 0;
44
+ let paxPath = null;
45
+ let off = 0;
46
+ for (;;) {
47
+ if (off + 512 > tar.length)
48
+ throw broken('it ends in the middle of an entry');
49
+ const h = tar.subarray(off, off + 512);
50
+ if (h.every((x) => x === 0))
51
+ break;
52
+ let sum = 0;
53
+ for (let i = 0; i < 512; i++)
54
+ sum += i >= 148 && i < 156 ? 32 : h[i];
55
+ if (sum !== octal(h, 148, 8, 'checksum'))
56
+ throw broken('a header checksum does not match');
57
+ const magic = field(h, 257, 6);
58
+ if (magic !== 'ustar' && magic !== 'ustar ')
59
+ throw broken('it is not a ustar archive');
60
+ const type = String.fromCharCode(h[156] || 48);
61
+ const size = octal(h, 124, 12, 'size');
62
+ if (size > LIMITS.fileBytes)
63
+ throw tooLarge(`one file over ${LIMITS.fileBytes / 1024 / 1024} MB`);
64
+ const dataStart = off + 512;
65
+ const dataEnd = dataStart + size;
66
+ if (dataEnd > tar.length)
67
+ throw broken('a file is cut short');
68
+ const data = tar.subarray(dataStart, dataEnd);
69
+ off = dataStart + Math.ceil(size / 512) * 512;
70
+ if (++entries > LIMITS.entries)
71
+ throw tooLarge(`more than ${LIMITS.entries} entries`);
72
+ if (type === 'x') {
73
+ // Per-entry pax record: only a long path is accepted, plus harmless times and owners.
74
+ paxPath = null;
75
+ for (const [k, v] of parsePax(data)) {
76
+ if (k === 'path')
77
+ paxPath = v;
78
+ else if (!['mtime', 'atime', 'ctime', 'uid', 'gid', 'uname', 'gname'].includes(k))
79
+ throw unsafe(`an unsupported pax field "${k.slice(0, 40)}"`);
80
+ }
81
+ continue;
82
+ }
83
+ if (type === 'g')
84
+ throw unsafe('a global pax header');
85
+ if (type === 'L' || type === 'K')
86
+ throw unsafe('a GNU long name record');
87
+ if (type === '1' || type === '2')
88
+ throw unsafe(`a ${type === '1' ? 'hard' : 'symbolic'} link`);
89
+ if (type === '3' || type === '4' || type === '6')
90
+ throw unsafe('a device file or FIFO');
91
+ if (type !== '0' && type !== '5' && type !== '7')
92
+ throw unsafe(`an entry of type "${type}"`);
93
+ const prefix = field(h, 345, 155);
94
+ let path = paxPath ?? (prefix ? `${prefix}/${field(h, 0, 100)}` : field(h, 0, 100));
95
+ paxPath = null;
96
+ path = path.replace(/^(\.\/)+/, '');
97
+ if (type === '5') {
98
+ path = path.replace(/\/+$/, '');
99
+ if (!path)
100
+ continue;
101
+ dirs.add(checkRelPath(path, 'archive'));
102
+ continue;
103
+ }
104
+ checkRelPath(path, 'archive');
105
+ if (files.has(path))
106
+ throw unsafe(`"${path}" appears twice`);
107
+ total += size;
108
+ if (total > LIMITS.expandedBytes)
109
+ throw tooLarge(`${LIMITS.expandedBytes / 1024 / 1024} MB expanded`);
110
+ files.set(path, Buffer.from(data));
111
+ }
112
+ checkCollisions([...files.keys()], 'archive');
113
+ return { files, dirs };
114
+ }
115
+ function parsePax(data) {
116
+ const out = [];
117
+ let i = 0;
118
+ while (i < data.length) {
119
+ const sp = data.indexOf(0x20, i);
120
+ if (sp === -1)
121
+ throw broken('a bad pax record');
122
+ const len = Number(data.subarray(i, sp).toString('ascii'));
123
+ if (!Number.isInteger(len) || len <= 0 || i + len > data.length)
124
+ throw broken('a bad pax record length');
125
+ const rec = data.subarray(sp + 1, i + len - 1).toString('utf8');
126
+ const eq = rec.indexOf('=');
127
+ if (eq === -1)
128
+ throw broken('a bad pax record');
129
+ out.push([rec.slice(0, eq), rec.slice(eq + 1)]);
130
+ i += len;
131
+ }
132
+ return out;
133
+ }
134
+ /**
135
+ * Writes files (path → bytes) as a deterministic .tar.gz: sorted entries, no
136
+ * folders, owner 0, time 0, mode 644 (755 for `executable`). The same input
137
+ * gives the same bytes on every machine.
138
+ */
139
+ export function writeTarGz(files, executable = new Set()) {
140
+ const blocks = [];
141
+ for (const path of [...files.keys()].sort()) {
142
+ const data = files.get(path);
143
+ const h = Buffer.alloc(512);
144
+ let name = path;
145
+ let prefix = '';
146
+ if (Buffer.byteLength(name) > 100) {
147
+ const cut = path.lastIndexOf('/', path.length - 1);
148
+ const at = (() => {
149
+ for (let i = cut; i > 0; i = path.lastIndexOf('/', i - 1))
150
+ if (Buffer.byteLength(path.slice(0, i)) <= 155 && Buffer.byteLength(path.slice(i + 1)) <= 100)
151
+ return i;
152
+ return -1;
153
+ })();
154
+ if (at === -1)
155
+ throw new ToolError('bad_template', `${path} is too long for the archive format.`);
156
+ prefix = path.slice(0, at);
157
+ name = path.slice(at + 1);
158
+ }
159
+ h.write(name, 0, 100, 'utf8');
160
+ h.write(executable.has(path) ? '0000755' : '0000644', 100, 8, 'ascii');
161
+ h.write('0000000', 108, 8, 'ascii');
162
+ h.write('0000000', 116, 8, 'ascii');
163
+ h.write(data.length.toString(8).padStart(11, '0'), 124, 12, 'ascii');
164
+ h.write('00000000000', 136, 12, 'ascii');
165
+ h.write(' ', 148, 8, 'ascii');
166
+ h[156] = 48; // '0'
167
+ h.write('ustar\u0000', 257, 6, 'binary');
168
+ h.write('00', 263, 2, 'ascii');
169
+ h.write(prefix, 345, 155, 'utf8');
170
+ let sum = 0;
171
+ for (const x of h)
172
+ sum += x;
173
+ h.write(sum.toString(8).padStart(6, '0') + '\u0000 ', 148, 8, 'binary');
174
+ blocks.push(h, data, Buffer.alloc((512 - (data.length % 512)) % 512));
175
+ }
176
+ blocks.push(Buffer.alloc(1024));
177
+ const gz = gzipSync(Buffer.concat(blocks), { level: 9 });
178
+ gz[9] = 0xff; // gzip "OS" byte: unknown, so the bytes do not depend on where it was packed
179
+ return gz;
180
+ }