@sdods/cli 0.2.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.
Files changed (124) hide show
  1. package/LICENSE +17 -0
  2. package/bin/sdods.js +19 -0
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/bin.d.ts +2 -0
  5. package/dist/bin.js +11 -0
  6. package/dist/commands/agent.d.ts +3 -0
  7. package/dist/commands/agent.js +219 -0
  8. package/dist/commands/analyze.d.ts +20 -0
  9. package/dist/commands/analyze.js +216 -0
  10. package/dist/commands/auth.d.ts +7 -0
  11. package/dist/commands/auth.js +97 -0
  12. package/dist/commands/browsers.d.ts +17 -0
  13. package/dist/commands/browsers.js +103 -0
  14. package/dist/commands/completion.d.ts +17 -0
  15. package/dist/commands/completion.js +143 -0
  16. package/dist/commands/config.d.ts +3 -0
  17. package/dist/commands/config.js +79 -0
  18. package/dist/commands/coverage.d.ts +3 -0
  19. package/dist/commands/coverage.js +65 -0
  20. package/dist/commands/data.d.ts +7 -0
  21. package/dist/commands/data.js +188 -0
  22. package/dist/commands/db.d.ts +3 -0
  23. package/dist/commands/db.js +241 -0
  24. package/dist/commands/doctor.d.ts +3 -0
  25. package/dist/commands/doctor.js +323 -0
  26. package/dist/commands/env.d.ts +3 -0
  27. package/dist/commands/env.js +65 -0
  28. package/dist/commands/features.d.ts +3 -0
  29. package/dist/commands/features.js +57 -0
  30. package/dist/commands/feedback.d.ts +7 -0
  31. package/dist/commands/feedback.js +96 -0
  32. package/dist/commands/har.d.ts +3 -0
  33. package/dist/commands/har.js +124 -0
  34. package/dist/commands/heal.d.ts +4 -0
  35. package/dist/commands/heal.js +63 -0
  36. package/dist/commands/init.d.ts +38 -0
  37. package/dist/commands/init.js +363 -0
  38. package/dist/commands/insights.d.ts +7 -0
  39. package/dist/commands/insights.js +127 -0
  40. package/dist/commands/integrations.d.ts +14 -0
  41. package/dist/commands/integrations.js +306 -0
  42. package/dist/commands/lint.d.ts +3 -0
  43. package/dist/commands/lint.js +74 -0
  44. package/dist/commands/mcp.d.ts +3 -0
  45. package/dist/commands/mcp.js +190 -0
  46. package/dist/commands/project.d.ts +3 -0
  47. package/dist/commands/project.js +133 -0
  48. package/dist/commands/proposals.d.ts +3 -0
  49. package/dist/commands/proposals.js +106 -0
  50. package/dist/commands/record.d.ts +3 -0
  51. package/dist/commands/record.js +174 -0
  52. package/dist/commands/report.d.ts +3 -0
  53. package/dist/commands/report.js +255 -0
  54. package/dist/commands/run.d.ts +41 -0
  55. package/dist/commands/run.js +369 -0
  56. package/dist/commands/schedule.d.ts +3 -0
  57. package/dist/commands/schedule.js +337 -0
  58. package/dist/commands/serve.d.ts +3 -0
  59. package/dist/commands/serve.js +38 -0
  60. package/dist/commands/steps.d.ts +8 -0
  61. package/dist/commands/steps.js +67 -0
  62. package/dist/commands/tokens.d.ts +3 -0
  63. package/dist/commands/tokens.js +110 -0
  64. package/dist/commands/trace.d.ts +10 -0
  65. package/dist/commands/trace.js +104 -0
  66. package/dist/commands/upgrade.d.ts +14 -0
  67. package/dist/commands/upgrade.js +115 -0
  68. package/dist/commands/users.d.ts +3 -0
  69. package/dist/commands/users.js +183 -0
  70. package/dist/commands/watch.d.ts +7 -0
  71. package/dist/commands/watch.js +116 -0
  72. package/dist/commands/workspace.d.ts +8 -0
  73. package/dist/commands/workspace.js +83 -0
  74. package/dist/context.d.ts +17 -0
  75. package/dist/context.js +22 -0
  76. package/dist/index.d.ts +3 -0
  77. package/dist/index.js +3 -0
  78. package/dist/program.d.ts +7 -0
  79. package/dist/program.js +90 -0
  80. package/dist/templates/project.d.ts +10 -0
  81. package/dist/templates/project.js +115 -0
  82. package/dist/ui.d.ts +16 -0
  83. package/dist/ui.js +67 -0
  84. package/package.json +61 -0
  85. package/templates/.claude/skills/sdods-record/SKILL.md +75 -0
  86. package/templates/.claude/skills/sdods-run/SKILL.md +54 -0
  87. package/templates/.env.example +62 -0
  88. package/templates/docker-compose.yml +40 -0
  89. package/templates/projects/demo-shop/.env.example +4 -0
  90. package/templates/projects/demo-shop/data/common/posts.yaml +11 -0
  91. package/templates/projects/demo-shop/data/common/products.json +8 -0
  92. package/templates/projects/demo-shop/data/common/users.csv +7 -0
  93. package/templates/projects/demo-shop/data/factories.ts +16 -0
  94. package/templates/projects/demo-shop/data/staging/users.csv +6 -0
  95. package/templates/projects/demo-shop/envs/local.yaml +17 -0
  96. package/templates/projects/demo-shop/envs/staging.yaml +23 -0
  97. package/templates/projects/demo-shop/features/__screenshots__/demo-shop--ui--chromium/darwin/inventory.png +0 -0
  98. package/templates/projects/demo-shop/features/api/posts.feature +90 -0
  99. package/templates/projects/demo-shop/features/auth/data-driven-login.feature +17 -0
  100. package/templates/projects/demo-shop/features/auth/login.feature +32 -0
  101. package/templates/projects/demo-shop/features/auth/user-pool.feature +20 -0
  102. package/templates/projects/demo-shop/features/cart/cart.feature +33 -0
  103. package/templates/projects/demo-shop/features/hybrid/seed-then-verify.feature +28 -0
  104. package/templates/projects/demo-shop/features/inventory/inventory.feature +38 -0
  105. package/templates/projects/demo-shop/features/inventory/network-intercept.feature +29 -0
  106. package/templates/projects/demo-shop/features/inventory/visual.feature +10 -0
  107. package/templates/projects/demo-shop/har/staging/cart.har +1 -0
  108. package/templates/projects/demo-shop/har/staging/cart.har.json +11 -0
  109. package/templates/projects/demo-shop/har/staging/login.har +1 -0
  110. package/templates/projects/demo-shop/har/staging/login.har.json +11 -0
  111. package/templates/projects/demo-shop/har/staging/posts.api.har +2061 -0
  112. package/templates/projects/demo-shop/har/staging/posts.har.json +8 -0
  113. package/templates/projects/demo-shop/har/staging/products.har +1 -0
  114. package/templates/projects/demo-shop/har/staging/products.har.json +11 -0
  115. package/templates/projects/demo-shop/har/staging/site.api.har +148 -0
  116. package/templates/projects/demo-shop/har/staging/site.har +1 -0
  117. package/templates/projects/demo-shop/har/staging/site.har.json +11 -0
  118. package/templates/projects/demo-shop/pages/CartPage.ts +20 -0
  119. package/templates/projects/demo-shop/pages/InventoryPage.ts +103 -0
  120. package/templates/projects/demo-shop/pages/LoginPage.ts +42 -0
  121. package/templates/projects/demo-shop/schemas/post.schema.json +13 -0
  122. package/templates/projects/demo-shop/sdods.project.yaml +185 -0
  123. package/templates/projects/demo-shop/steps/auth.ts +7 -0
  124. package/templates/projects/demo-shop/steps/fixtures.ts +39 -0
@@ -0,0 +1,57 @@
1
+ import { relative } from 'node:path';
2
+ import { listFeatureFiles, parseFeatureFile, scenariosOf } from '@sdods/core';
3
+ import { createContext } from '../context.js';
4
+ import { json, table } from '../ui.js';
5
+ export function register(program) {
6
+ const features = program.command('features').description('Inspect feature files and scenarios');
7
+ features
8
+ .command('list')
9
+ .description('List features with module, layer, suite, scenario count and tags')
10
+ .requiredOption('-p, --project <slug>', 'project slug')
11
+ .option('--tags <expr>', 'only scenarios carrying this tag (simple @tag filter)')
12
+ .option('--scenarios', 'one row per scenario instead of per feature')
13
+ .action((opts, cmd) => {
14
+ const ctx = createContext(cmd);
15
+ const cfg = ctx.registry.resolve(opts.project);
16
+ const rows = [];
17
+ for (const file of listFeatureFiles(cfg.project.root)) {
18
+ const rel = relative(cfg.project.root, file).replace(/\\/g, '/');
19
+ const parsed = parseFeatureFile(file);
20
+ const mod = ctx.registry.moduleOfFeature(opts.project, rel)?.name ?? '';
21
+ const scenarios = scenariosOf(parsed).filter((s) => !opts.tags || s.tags.includes(opts.tags));
22
+ if (!scenarios.length && opts.tags)
23
+ continue;
24
+ if (opts.scenarios) {
25
+ for (const s of scenarios) {
26
+ rows.push({
27
+ feature: rel,
28
+ module: mod,
29
+ line: s.line,
30
+ scenario: s.name,
31
+ layer: s.tags.find((t) => ['@ui', '@api', '@hybrid'].includes(t)) ?? '',
32
+ suite: s.tags.find((t) => cfg.project.tags.suites.map((x) => `@${x}`).includes(t)) ?? '',
33
+ tags: s.tags.join(' '),
34
+ });
35
+ }
36
+ }
37
+ else {
38
+ const tags = [...new Set(scenarios.flatMap((s) => s.tags))];
39
+ rows.push({
40
+ feature: rel,
41
+ module: mod,
42
+ name: parsed.document.feature?.name ?? '',
43
+ scenarios: scenarios.length,
44
+ layers: [
45
+ ...new Set(scenarios.map((s) => s.tags.find((t) => ['@ui', '@api', '@hybrid'].includes(t)) ?? '?')),
46
+ ].join(','),
47
+ tags: tags.join(' '),
48
+ errors: parsed.errors.length,
49
+ });
50
+ }
51
+ }
52
+ if (ctx.opts.json)
53
+ return json(rows);
54
+ table(rows);
55
+ });
56
+ }
57
+ //# sourceMappingURL=features.js.map
@@ -0,0 +1,7 @@
1
+ import type { Command } from 'commander';
2
+ /**
3
+ * `sdods feedback` — open a prefilled GitHub issue (feature request or bug report).
4
+ * No backend: the URL carries the fields; bug reports embed the doctor summary.
5
+ */
6
+ export declare function register(program: Command): void;
7
+ //# sourceMappingURL=feedback.d.ts.map
@@ -0,0 +1,96 @@
1
+ import { execa } from 'execa';
2
+ import pc from 'picocolors';
3
+ import { VERSION } from '@sdods/core';
4
+ import { json, out } from '../ui.js';
5
+ const REPO = 'https://github.com/siri1410/SDODS';
6
+ const DISCUSSIONS = `${REPO}/discussions/categories/ideas`;
7
+ /**
8
+ * `sdods feedback` — open a prefilled GitHub issue (feature request or bug report).
9
+ * No backend: the URL carries the fields; bug reports embed the doctor summary.
10
+ */
11
+ export function register(program) {
12
+ program
13
+ .command('feedback')
14
+ .description('Request a feature or report a bug (prefilled GitHub issue; opens in your browser)')
15
+ .option('--feature', 'feature request (default)')
16
+ .option('--bug', 'bug report with environment details from `sdods doctor`')
17
+ .option('--discuss', 'print the Discussions (ideas) URL instead')
18
+ .option('-t, --title <text>', 'issue title')
19
+ .option('-m, --message <text>', 'problem statement or observed behaviour')
20
+ .option('--open', 'open the URL in the default browser')
21
+ .action(async (opts, cmd) => {
22
+ const root = cmd.parent ?? cmd;
23
+ const asJson = Boolean(root.opts().json);
24
+ let url;
25
+ if (opts.discuss) {
26
+ url = DISCUSSIONS;
27
+ }
28
+ else if (opts.bug) {
29
+ const params = new URLSearchParams({
30
+ template: 'bug_report.yml',
31
+ title: opts.title ? `[Bug] ${opts.title}` : '[Bug] ',
32
+ labels: 'bug,triage',
33
+ 'sdods-version': VERSION,
34
+ os: osLabel(),
35
+ });
36
+ const doctor = await doctorSummary();
37
+ if (doctor)
38
+ params.set('doctor', doctor);
39
+ if (opts.message)
40
+ params.set('actual', opts.message);
41
+ url = `${REPO}/issues/new?${params.toString()}`;
42
+ }
43
+ else {
44
+ const params = new URLSearchParams({
45
+ template: 'feature_request.yml',
46
+ title: opts.title ? `[Feature] ${opts.title}` : '[Feature] ',
47
+ labels: 'enhancement,triage',
48
+ 'sdods-version': VERSION,
49
+ });
50
+ if (opts.message)
51
+ params.set('problem', opts.message);
52
+ url = `${REPO}/issues/new?${params.toString()}`;
53
+ }
54
+ if (asJson)
55
+ return json({ url });
56
+ out(url);
57
+ if (opts.open) {
58
+ const opener = process.platform === 'darwin'
59
+ ? 'open'
60
+ : process.platform === 'win32'
61
+ ? 'start'
62
+ : 'xdg-open';
63
+ await execa(opener, [url], { shell: process.platform === 'win32' }).catch(() => out(pc.dim('Could not open a browser; copy the URL above.')));
64
+ }
65
+ else {
66
+ out(pc.dim('Add --open to launch it in your browser.'));
67
+ }
68
+ });
69
+ }
70
+ function osLabel() {
71
+ return process.platform === 'darwin'
72
+ ? 'macOS'
73
+ : process.platform === 'linux'
74
+ ? 'Linux'
75
+ : process.platform === 'win32'
76
+ ? 'Windows'
77
+ : 'Other';
78
+ }
79
+ /** Compact doctor output for the bug form; never includes secret values. */
80
+ async function doctorSummary() {
81
+ try {
82
+ const { stdout } = await execa(process.execPath, ['--import', 'tsx', new URL('../bin.ts', import.meta.url).pathname, '--json', 'doctor'], {
83
+ timeout: 60_000,
84
+ reject: false,
85
+ });
86
+ const start = stdout.indexOf('[');
87
+ if (start < 0)
88
+ return undefined;
89
+ const rows = JSON.parse(stdout.slice(start));
90
+ return JSON.stringify(rows.map((r) => ({ name: r.name, ok: r.ok, detail: r.detail })), null, 0).slice(0, 3000);
91
+ }
92
+ catch {
93
+ return undefined;
94
+ }
95
+ }
96
+ //# sourceMappingURL=feedback.js.map
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare function register(program: Command): void;
3
+ //# sourceMappingURL=har.d.ts.map
@@ -0,0 +1,124 @@
1
+ import { relative } from 'node:path';
2
+ import pc from 'picocolors';
3
+ import { SdodsError } from '@sdods/core';
4
+ import { createContext } from '../context.js';
5
+ import { collect, json, ok, out, table } from '../ui.js';
6
+ import { runCommand } from './run.js';
7
+ function baseRunFlags(over) {
8
+ return { layer: [], browser: [], module: [], reporter: [], lint: true, trigger: 'cli', ...over };
9
+ }
10
+ export function register(program) {
11
+ const har = program
12
+ .command('har')
13
+ .description('Record or replay HAR files so runs work offline (browser and API layers)');
14
+ har
15
+ .command('record')
16
+ .description('Run @har scenarios in update mode (writes har/<env>/<name>.har), or record interactively with codegen')
17
+ .option('-p, --project <slug>', 'project slug')
18
+ .option('-e, --env <name>', 'environment')
19
+ .option('-t, --tags <expr>', 'tag expression, e.g. "@har:products" (default: every @har scenario)')
20
+ .option('-l, --layer <layer>', 'ui | api | hybrid (repeatable)', collect, [])
21
+ .option('-b, --browser <name>', 'browser (repeatable; default chromium)', collect, [])
22
+ .option('--interactive', 'open codegen with --save-har instead of running scenarios')
23
+ .option('--name <name>', 'HAR name for --interactive')
24
+ .option('--url <route|path|url>', 'start URL for --interactive', '/')
25
+ .option('--har-glob <glob>', 'URL glob to capture', '**/*')
26
+ .action(async (opts, cmd) => {
27
+ const ctx = createContext(cmd);
28
+ if (opts.interactive) {
29
+ if (!opts.name)
30
+ throw new SdodsError('CONFIG_INVALID', '--interactive needs --name <har-name>.', {
31
+ exitCode: 2,
32
+ });
33
+ const entry = ctx.registry.pick(opts.project);
34
+ const config = ctx.registry.resolve(entry.slug, opts.env);
35
+ const { runCodegen } = await import('@sdods/core/recorder');
36
+ const { writeSidecar } = await import('@sdods/core/har');
37
+ const res = await runCodegen({
38
+ config,
39
+ name: opts.name,
40
+ url: opts.url,
41
+ saveHar: true,
42
+ harUrlGlob: opts.harGlob,
43
+ outputFile: `${config.runtime.artifactsDir}/../codegen-scratch/${opts.name}.spec.ts`,
44
+ });
45
+ if (!res.harFile)
46
+ throw new SdodsError('RUN_FAILED', 'Codegen closed without writing a HAR.', {
47
+ exitCode: 1,
48
+ });
49
+ writeSidecar(config, {
50
+ name: opts.name,
51
+ project: entry.slug,
52
+ env: config.env.name,
53
+ urlGlob: opts.harGlob,
54
+ recordedAt: new Date().toISOString(),
55
+ source: 'codegen',
56
+ scenarios: [],
57
+ });
58
+ if (ctx.opts.json)
59
+ return json({ har: res.harFile });
60
+ return ok(`HAR written: ${relative(ctx.rootDir, res.harFile)} — tag scenarios with @har:${opts.name}`);
61
+ }
62
+ const tags = opts.tags ?? '@har:*';
63
+ if (tags === '@har:*') {
64
+ // Cucumber tag expressions have no wildcards: run every ui/hybrid/api scenario in update mode;
65
+ // the hook only records for scenarios that carry a @har:<name> tag.
66
+ out(pc.dim('no --tags given: running the project in HAR update mode (only @har-tagged scenarios record)'));
67
+ }
68
+ process.exitCode = await runCommand(baseRunFlags({
69
+ project: opts.project,
70
+ env: opts.env,
71
+ tags: tags === '@har:*' ? undefined : tags,
72
+ layer: opts.layer,
73
+ browser: opts.browser.length ? opts.browser : ['chromium'],
74
+ harUpdate: true,
75
+ }), cmd);
76
+ });
77
+ har
78
+ .command('replay')
79
+ .description('Run scenarios from their HAR files; --strict aborts any request that is not recorded (offline)')
80
+ .option('-p, --project <slug>', 'project slug')
81
+ .option('-e, --env <name>', 'environment')
82
+ .option('-t, --tags <expr>', 'tag expression (default: all)')
83
+ .option('-l, --layer <layer>', 'ui | api | hybrid (repeatable)', collect, [])
84
+ .option('-b, --browser <name>', 'browser (repeatable)', collect, [])
85
+ .option('--strict', 'abort requests missing from the HAR and block all other network')
86
+ .option('-w, --workers <n>', 'workers')
87
+ .action(async (opts, cmd) => {
88
+ process.exitCode = await runCommand(baseRunFlags({
89
+ project: opts.project,
90
+ env: opts.env,
91
+ tags: opts.tags,
92
+ layer: opts.layer,
93
+ browser: opts.browser,
94
+ harReplay: true,
95
+ strict: Boolean(opts.strict),
96
+ workers: opts.workers ? Number(opts.workers) : undefined,
97
+ }), cmd);
98
+ });
99
+ har
100
+ .command('list')
101
+ .description('List HAR files of a project')
102
+ .option('-p, --project <slug>', 'project slug')
103
+ .option('-e, --env <name>', 'only this environment')
104
+ .action(async (opts, cmd) => {
105
+ const ctx = createContext(cmd);
106
+ const entry = ctx.registry.pick(opts.project);
107
+ const { listHars } = await import('@sdods/core/har');
108
+ const rows = listHars(entry.root, opts.env).map((h) => ({
109
+ env: h.env,
110
+ name: h.name,
111
+ tag: `@har:${h.name}`,
112
+ size: `${Math.round(h.sizeBytes / 1024)} KB`,
113
+ api: h.apiFile ? 'yes' : '',
114
+ glob: h.sidecar?.urlGlob ?? '',
115
+ recorded: h.sidecar?.recordedAt?.slice(0, 19).replace('T', ' ') ?? '',
116
+ scenarios: h.sidecar?.scenarios?.length ?? 0,
117
+ file: relative(ctx.rootDir, h.file),
118
+ }));
119
+ if (ctx.opts.json)
120
+ return json(rows);
121
+ table(rows, ['env', 'name', 'tag', 'size', 'api', 'glob', 'recorded', 'scenarios']);
122
+ });
123
+ }
124
+ //# sourceMappingURL=har.js.map
@@ -0,0 +1,4 @@
1
+ import type { Command } from 'commander';
2
+ export declare function latestRunDir(artifactsDir: string): string | undefined;
3
+ export declare function register(program: Command): void;
4
+ //# sourceMappingURL=heal.d.ts.map
@@ -0,0 +1,63 @@
1
+ import { existsSync, readdirSync, statSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import pc from 'picocolors';
4
+ import { SdodsError, HealHistory, collectHealEvents, summarizeHealEvents } from '@sdods/core';
5
+ import { createContext } from '../context.js';
6
+ import { json, out, table } from '../ui.js';
7
+ export function latestRunDir(artifactsDir) {
8
+ if (!existsSync(artifactsDir))
9
+ return undefined;
10
+ const dirs = readdirSync(artifactsDir)
11
+ .map((d) => join(artifactsDir, d))
12
+ .filter((d) => statSync(d).isDirectory() && existsSync(join(d, 'run.json')))
13
+ .sort((a, b) => statSync(b).mtimeMs - statSync(a).mtimeMs);
14
+ return dirs[0];
15
+ }
16
+ export function register(program) {
17
+ const heal = program.command('heal').description('Self-healing locator reports');
18
+ heal
19
+ .command('report')
20
+ .description('Summarise heal events from a run (or every run) and suggest locator updates')
21
+ .option('--run <id>', 'run id')
22
+ .option('--last', 'the most recent run (default)')
23
+ .option('--all', 'aggregate every run under the artifacts dir')
24
+ .option('--write-history', 'persist a heal-history.json used to bias future heals')
25
+ .action((opts, cmd) => {
26
+ const ctx = createContext(cmd);
27
+ const artifacts = join(ctx.rootDir, process.env.SDODS_ARTIFACTS_DIR ?? '.sdods/runs');
28
+ const root = opts.all
29
+ ? artifacts
30
+ : opts.run
31
+ ? join(artifacts, opts.run)
32
+ : latestRunDir(artifacts);
33
+ if (!root || !existsSync(root))
34
+ throw new SdodsError('RUN_FAILED', 'No run found.', {
35
+ hint: 'Run `sdods run` first or pass --run <id>.',
36
+ exitCode: 2,
37
+ });
38
+ const events = collectHealEvents(root);
39
+ const rows = summarizeHealEvents(events);
40
+ if (opts.writeHistory) {
41
+ const history = new HealHistory(join(artifacts, '..', 'heal-history.json'));
42
+ for (const e of events)
43
+ history.record(e);
44
+ history.save();
45
+ }
46
+ if (ctx.opts.json)
47
+ return json({ root, events: events.length, rows });
48
+ if (!rows.length)
49
+ return out(pc.green(`No heal events under ${root}`));
50
+ table(rows.map((r) => ({
51
+ description: r.description,
52
+ original: r.originalSelector,
53
+ occurrences: r.occurrences,
54
+ succeeded: r.succeeded,
55
+ strategy: Object.entries(r.strategies)
56
+ .map(([k, v]) => `${k}×${v}`)
57
+ .join(' '),
58
+ suggested: r.suggestedSelector ?? '',
59
+ })));
60
+ out(pc.dim(`${events.length} event(s) from ${root}`));
61
+ });
62
+ }
63
+ //# sourceMappingURL=heal.js.map
@@ -0,0 +1,38 @@
1
+ import type { Command } from 'commander';
2
+ /** Root of the SDODS monorepo this CLI runs from (used by --link, which needs a real checkout). */
3
+ export declare function sourceRepoRoot(): string;
4
+ /**
5
+ * Where `init` reads the assets it copies into a new workspace. A real checkout wins, so working
6
+ * on SDODS scaffolds from the live `projects/demo-shop` rather than a staged copy. A published
7
+ * install has no checkout above it and falls back to `templates/`, put into the tarball at pack
8
+ * time by scripts/build-publish-assets.ts. The staged layout mirrors the repo root, so the callers
9
+ * below resolve the same relative paths either way.
10
+ */
11
+ export declare function templateRoot(): string;
12
+ export interface InitFlags {
13
+ db: 'sqlite' | 'postgres';
14
+ pm: 'bun' | 'pnpm';
15
+ demo: boolean;
16
+ claude?: boolean;
17
+ from?: string;
18
+ git?: boolean;
19
+ link?: boolean;
20
+ install: boolean;
21
+ browsers: boolean;
22
+ org: string;
23
+ orgName?: string;
24
+ workspace: string;
25
+ workspaceName?: string;
26
+ force?: boolean;
27
+ }
28
+ export declare function register(program: Command): void;
29
+ export interface InitResult {
30
+ dir: string;
31
+ files: string[];
32
+ installed: boolean;
33
+ browsers: boolean;
34
+ demo: boolean;
35
+ }
36
+ export declare function initWorkspace(target: string, flags: InitFlags): Promise<InitResult>;
37
+ export declare function isDir(p: string): boolean;
38
+ //# sourceMappingURL=init.d.ts.map