@motujs/cli 0.0.0-stage → 0.1.0
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/LICENSE +21 -0
- package/bundled/github/agents/archipelago-build.agent.md +298 -0
- package/bundled/github/agents/island-create.agent.md +261 -0
- package/bundled/github/agents/island-extract.agent.md +360 -0
- package/bundled/github/agents/island-locate.agent.md +208 -0
- package/bundled/github/agents/motu-checks.agent.md +158 -0
- package/bundled/github/agents/motu-evidence.agent.md +267 -0
- package/bundled/github/agents/motu-regions.agent.md +304 -0
- package/bundled/github/host-rules.md +43 -0
- package/bundled/github/prompts/archipelago-build.prompt.md +19 -0
- package/bundled/github/prompts/island-create.prompt.md +37 -0
- package/bundled/github/prompts/island-extract.prompt.md +59 -0
- package/bundled/github/prompts/island-locate.prompt.md +43 -0
- package/bundled/packages/adapters/angularjs/vite.mjs +43 -0
- package/bundled/packages/adapters/next/lagoon/next-stubs.tsx +108 -0
- package/bundled/packages/adapters/next/vite.mjs +121 -0
- package/bundled/packages/adapters/vite/vite.mjs +179 -0
- package/package.json +64 -3
- package/src/alias-loader.mjs +63 -0
- package/src/alias-register.mjs +28 -0
- package/src/asset-stub.cjs +3 -0
- package/src/asset-stub.mjs +5 -0
- package/src/cli.mjs +78 -0
- package/src/commands/adopt-root.mjs +194 -0
- package/src/commands/archipelago-init.mjs +314 -0
- package/src/commands/archipelago.mjs +138 -0
- package/src/commands/assurance.mjs +40 -0
- package/src/commands/check.mjs +346 -0
- package/src/commands/codegen.mjs +29 -0
- package/src/commands/coverage.mjs +358 -0
- package/src/commands/create.mjs +277 -0
- package/src/commands/defaults.mjs +129 -0
- package/src/commands/diff.mjs +595 -0
- package/src/commands/fixtures.mjs +153 -0
- package/src/commands/init.mjs +473 -0
- package/src/commands/integrate.mjs +208 -0
- package/src/commands/integration.mjs +1349 -0
- package/src/commands/lagoon-try.mjs +272 -0
- package/src/commands/lagoon.mjs +1419 -0
- package/src/commands/link.mjs +110 -0
- package/src/commands/region-coverage.mjs +604 -0
- package/src/commands/removal-check.mjs +878 -0
- package/src/commands/skills.mjs +156 -0
- package/src/commands/snapshot.mjs +456 -0
- package/src/commands/sync.mjs +38 -0
- package/src/commands/verify/island-runtime.mjs +581 -0
- package/src/commands/verify/island-static.mjs +586 -0
- package/src/commands/verify/island.mjs +135 -0
- package/src/commands/verify/reach.mjs +426 -0
- package/src/commands/verify/region-composition.mjs +391 -0
- package/src/commands/verify/region-config.mjs +330 -0
- package/src/commands/verify/region-flows.mjs +760 -0
- package/src/commands/verify/region-sources.mjs +516 -0
- package/src/commands/verify/region.mjs +271 -0
- package/src/commands/verify/report.mjs +338 -0
- package/src/commands/verify/screens-runtime.mjs +123 -0
- package/src/commands/verify.mjs +18 -0
- package/src/lagoon-build.mjs +25 -0
- package/src/lagoon-dev.mjs +32 -0
- package/src/lib/alias-core.mjs +49 -0
- package/src/lib/archipelagos.mjs +111 -0
- package/src/lib/assurance.mjs +144 -0
- package/src/lib/baselines.mjs +107 -0
- package/src/lib/bundlability.mjs +123 -0
- package/src/lib/changed.mjs +157 -0
- package/src/lib/component-props.mjs +145 -0
- package/src/lib/config.mjs +451 -0
- package/src/lib/contracts.mjs +244 -0
- package/src/lib/data-flow.mjs +47 -0
- package/src/lib/declared-sources.mjs +101 -0
- package/src/lib/dock-inject.mjs +47 -0
- package/src/lib/effects.mjs +97 -0
- package/src/lib/eject.mjs +715 -0
- package/src/lib/evidence-json.mjs +74 -0
- package/src/lib/expect-calls.mjs +53 -0
- package/src/lib/finding-memory.mjs +0 -0
- package/src/lib/flow-calls.mjs +53 -0
- package/src/lib/framework.mjs +98 -0
- package/src/lib/host-rules.mjs +55 -0
- package/src/lib/host-sources.mjs +121 -0
- package/src/lib/island-placement.mjs +64 -0
- package/src/lib/island-render.mjs +105 -0
- package/src/lib/islands.mjs +112 -0
- package/src/lib/lagoon-bundle.mjs +138 -0
- package/src/lib/lagoon-declares.mjs +553 -0
- package/src/lib/lagoon-materialize.mjs +217 -0
- package/src/lib/lagoon-vite.mjs +788 -0
- package/src/lib/live-url.mjs +53 -0
- package/src/lib/node-aliases.mjs +73 -0
- package/src/lib/operations.mjs +145 -0
- package/src/lib/provenance-plugin.mjs +74 -0
- package/src/lib/region-refs.mjs +40 -0
- package/src/lib/remote.mjs +171 -0
- package/src/lib/scaffold.mjs +606 -0
- package/src/lib/screens.mjs +266 -0
- package/src/lib/snapshots.mjs +85 -0
- package/src/lib/stubs.mjs +114 -0
- package/src/lib/ts-project.mjs +42 -0
- package/src/lib/util.mjs +626 -0
- package/src/lib/worlds.mjs +236 -0
- package/src/lib/write-if-changed.mjs +35 -0
- package/src/lib/writes-coverage.mjs +32 -0
- package/src/playwright-lagoon.mjs +2305 -0
- package/src/run.mjs +385 -0
- package/src/runtime-harness.mjs +225 -0
- package/README.md +0 -3
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// `motu island defaults [name]` — classify every default an island declares, and say where it belongs.
|
|
2
|
+
//
|
|
3
|
+
// An island's `contract.input` defaults exist so the lagoon's "renders from default props alone" gate
|
|
4
|
+
// can hold. But most of them are not motu's business at all: measured across acme's eight islands,
|
|
5
|
+
// THIRTEEN of fourteen declared defaults are honest component defaults (`isLoading: false`,
|
|
6
|
+
// `missions: []`, `overallProgress: 0`) — values the app's own component should carry, where they are
|
|
7
|
+
// an improvement rather than a motu artifact. Exactly one is a lagoon fiction: a real-looking phone
|
|
8
|
+
// number, in a component a production page renders.
|
|
9
|
+
//
|
|
10
|
+
// That one is the tell, and it is the rule this command applies:
|
|
11
|
+
//
|
|
12
|
+
// If a default cannot be honest in production, it is not a default — it is missing evidence.
|
|
13
|
+
//
|
|
14
|
+
// It reports and proposes; it does not rewrite. Whether `kind: 'no-social'` is a sound empty state or
|
|
15
|
+
// a stand-in for data is a domain judgement, and the tool's job is to put it in front of the person
|
|
16
|
+
// who can make it — not to guess and quietly edit an app component.
|
|
17
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
18
|
+
import { Project, SyntaxKind } from 'ts-morph';
|
|
19
|
+
import { paths, color, names } from '../lib/util.mjs';
|
|
20
|
+
import { listIslands } from '../lib/islands.mjs';
|
|
21
|
+
|
|
22
|
+
/** Values that are neutral for their type: an empty state, not a piece of data. */
|
|
23
|
+
function classifyLiteral(node) {
|
|
24
|
+
const kind = node.getKind();
|
|
25
|
+
if (kind === SyntaxKind.NullKeyword) return 'empty';
|
|
26
|
+
if (node.getText() === 'undefined') return 'empty';
|
|
27
|
+
if (kind === SyntaxKind.FalseKeyword) return 'empty';
|
|
28
|
+
if (kind === SyntaxKind.TrueKeyword) return 'judge'; // `true` asserts something; `false` asserts nothing
|
|
29
|
+
if (kind === SyntaxKind.StringLiteral) return node.getLiteralValue() === '' ? 'empty' : 'judge';
|
|
30
|
+
if (kind === SyntaxKind.NumericLiteral) return node.getLiteralValue() === 0 ? 'empty' : 'judge';
|
|
31
|
+
if (kind === SyntaxKind.ArrayLiteralExpression) return node.getElements().length === 0 ? 'empty' : 'judge';
|
|
32
|
+
if (kind === SyntaxKind.ObjectLiteralExpression) {
|
|
33
|
+
// An object is empty when every leaf is. `{ profilsWaiting: 0, recap: [] }` is a zeroed shape —
|
|
34
|
+
// the component's own empty state, written out.
|
|
35
|
+
const props = node.getProperties();
|
|
36
|
+
if (!props.length) return 'empty';
|
|
37
|
+
return props.every((p) => {
|
|
38
|
+
const init = p.getInitializer?.();
|
|
39
|
+
return init && classifyLiteral(init) === 'empty';
|
|
40
|
+
})
|
|
41
|
+
? 'empty'
|
|
42
|
+
: 'judge';
|
|
43
|
+
}
|
|
44
|
+
return 'judge';
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Every `{ name, default }` entry in the island's declared input. */
|
|
48
|
+
function declaredDefaults(elementPath) {
|
|
49
|
+
const project = new Project({
|
|
50
|
+
skipAddingFilesFromTsConfig: true,
|
|
51
|
+
skipFileDependencyResolution: true,
|
|
52
|
+
compilerOptions: { allowJs: true },
|
|
53
|
+
});
|
|
54
|
+
const sf = project.addSourceFileAtPath(elementPath);
|
|
55
|
+
const out = [];
|
|
56
|
+
for (const obj of sf.getDescendantsOfKind(SyntaxKind.ObjectLiteralExpression)) {
|
|
57
|
+
const contract = obj.getProperty('contract')?.getInitializerIfKind(SyntaxKind.ObjectLiteralExpression);
|
|
58
|
+
const input = contract?.getProperty('input')?.getInitializerIfKind(SyntaxKind.ArrayLiteralExpression);
|
|
59
|
+
if (!input) continue;
|
|
60
|
+
for (const entry of input.getElements()) {
|
|
61
|
+
if (entry.getKind() !== SyntaxKind.ObjectLiteralExpression) continue;
|
|
62
|
+
const nameInit = entry.getProperty('name')?.getInitializer();
|
|
63
|
+
const defProp = entry.getProperty('default');
|
|
64
|
+
if (!nameInit || !defProp) continue;
|
|
65
|
+
const init = defProp.getInitializer();
|
|
66
|
+
out.push({
|
|
67
|
+
prop: nameInit.getText().replace(/['"]/g, ''),
|
|
68
|
+
text: init.getText().replace(/\s+/g, ' '),
|
|
69
|
+
verdict: classifyLiteral(init),
|
|
70
|
+
line: entry.getStartLineNumber(),
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return out;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** The component an island's element.ts mounts, and where it comes from. */
|
|
78
|
+
function componentImport(elementPath) {
|
|
79
|
+
const src = readFileSync(elementPath, 'utf8');
|
|
80
|
+
const comp = src.match(/component:\s*([A-Za-z0-9_]+)/)?.[1];
|
|
81
|
+
if (!comp) return {};
|
|
82
|
+
const imp = src.match(new RegExp(`import\\s*\\{[^}]*\\b${comp}\\b[^}]*\\}\\s*from\\s*['"]([^'"]+)['"]`));
|
|
83
|
+
return { component: comp, from: imp?.[1] };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function islandDefaultsCommand(argv) {
|
|
87
|
+
const only = argv._?.[0];
|
|
88
|
+
const kebabs = only ? [names.kebab(only)] : listIslands(paths.islandsDir).map((i) => i.kebab);
|
|
89
|
+
|
|
90
|
+
const rows = [];
|
|
91
|
+
for (const kebab of kebabs) {
|
|
92
|
+
const el = paths.elementFile(kebab);
|
|
93
|
+
if (!existsSync(el)) continue;
|
|
94
|
+
const { component, from } = componentImport(el);
|
|
95
|
+
for (const d of declaredDefaults(el)) rows.push({ kebab, component, from, ...d });
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (argv.json) {
|
|
99
|
+
console.log(JSON.stringify({ defaults: rows }, null, 2));
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
console.log(color.bold('\nmotu island defaults — where each declared default belongs\n'));
|
|
104
|
+
if (!rows.length) {
|
|
105
|
+
console.log(color.dim(' no declared defaults'));
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
let judge = 0;
|
|
109
|
+
for (const r of rows) {
|
|
110
|
+
const mark = r.verdict === 'empty' ? color.green('→') : color.yellow('?');
|
|
111
|
+
const note =
|
|
112
|
+
r.verdict === 'empty'
|
|
113
|
+
? color.dim('empty state — belongs in the component')
|
|
114
|
+
: color.yellow('needs judgement — honest default, or missing evidence?');
|
|
115
|
+
if (r.verdict !== 'empty') judge++;
|
|
116
|
+
console.log(` ${mark} ${color.dim(r.kebab.padEnd(18))} ${(r.prop + ' = ' + r.text).padEnd(46)} ${note}`);
|
|
117
|
+
}
|
|
118
|
+
console.log('');
|
|
119
|
+
console.log(color.dim(` ${rows.length - judge} can move into the component as-is.`));
|
|
120
|
+
if (judge) {
|
|
121
|
+
console.log(color.yellow(` ${judge} carry a value, so you decide:`));
|
|
122
|
+
console.log(color.dim(' • a sound empty state for the domain → move it into the component'));
|
|
123
|
+
console.log(color.dim(' • a stand-in for real data → it is EVIDENCE, not a default:'));
|
|
124
|
+
console.log(color.dim(' drop it and add a scenario seed, or the component ships a fiction'));
|
|
125
|
+
}
|
|
126
|
+
console.log('');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
|