@distributionos/cli 0.1.15 → 0.1.17
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/README.md +7 -7
- package/package.json +1 -1
- package/src/api.js +125 -125
- package/src/bootstrap.js +27 -25
- package/src/cli.js +387 -220
- package/src/constants.js +8 -8
- package/src/initialization.js +63 -63
- package/src/mcp-config.js +319 -187
- package/src/mutate.js +46 -43
- package/src/oauth.js +30 -30
- package/src/plan.js +175 -169
- package/src/setup-report.js +253 -222
- package/src/validation.js +108 -0
package/src/constants.js
CHANGED
|
@@ -6,9 +6,9 @@ export const CLI_PACKAGE_NAME = '@distributionos/cli';
|
|
|
6
6
|
export const CLI_LOCAL_VERSION = typeof cliPackageJson.version === 'string' ? cliPackageJson.version : '0.0.0-local';
|
|
7
7
|
export const DEFAULT_API_BASE = 'https://distributionos.dev';
|
|
8
8
|
export const MCP_SERVER_URL = 'https://distributionos.dev/api/mcp';
|
|
9
|
-
export const CURRENT_BOOTSTRAP_VERSION = '2026.06.
|
|
10
|
-
export const CURRENT_ANALYTICS_CONTRACT_VERSION = '2026.06.
|
|
11
|
-
export const CURRENT_SETUP_CONTRACT_VERSION = '2026.
|
|
9
|
+
export const CURRENT_BOOTSTRAP_VERSION = '2026.06.27';
|
|
10
|
+
export const CURRENT_ANALYTICS_CONTRACT_VERSION = '2026.06.20';
|
|
11
|
+
export const CURRENT_SETUP_CONTRACT_VERSION = '2026.07.01';
|
|
12
12
|
|
|
13
13
|
export const TOKEN_ENV_NAMES = [
|
|
14
14
|
'DISTRIBUTIONOS_API_KEY',
|
|
@@ -49,11 +49,11 @@ export const PRIVATE_ROUTE_PATTERNS = [
|
|
|
49
49
|
'/products/**',
|
|
50
50
|
'/project/**',
|
|
51
51
|
'/projects/**',
|
|
52
|
-
'/workspace/**',
|
|
53
|
-
'/workspaces/**',
|
|
54
|
-
'/workflow/**',
|
|
55
|
-
'/workflows/**',
|
|
56
|
-
'/customer/**',
|
|
52
|
+
'/workspace/**',
|
|
53
|
+
'/workspaces/**',
|
|
54
|
+
'/workflow/**',
|
|
55
|
+
'/workflows/**',
|
|
56
|
+
'/customer/**',
|
|
57
57
|
'/customers/**',
|
|
58
58
|
'/client/**',
|
|
59
59
|
'/clients/**',
|
package/src/initialization.js
CHANGED
|
@@ -1,42 +1,42 @@
|
|
|
1
1
|
import { promises as fs } from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
|
|
4
|
-
export async function buildInitializationPayload(plan, options = {}) {
|
|
5
|
-
const appName = titleFromPackageName(plan.repo.packageJson?.name ?? plan.appId);
|
|
6
|
-
const docs = await readProjectDocs(plan.cwd);
|
|
7
|
-
const routes = plan.repo.routes ?? [];
|
|
8
|
-
const publicBlogRoute = routes.find(route => route === '/blog' || route.startsWith('/blog/'));
|
|
9
|
-
const routePrivacy = plan.repo.routePrivacy ?? { allowed: [], blocked: [], review: [] };
|
|
10
|
-
const appIdentity = {
|
|
11
|
-
name: appName,
|
|
12
|
-
};
|
|
13
|
-
if (options.domain) {
|
|
14
|
-
appIdentity.domain = options.domain;
|
|
15
|
-
}
|
|
16
|
-
if (docs.overview?.claim) {
|
|
17
|
-
appIdentity.description = docs.overview.claim;
|
|
18
|
-
}
|
|
19
|
-
const repo = {
|
|
20
|
-
root: path.basename(plan.cwd),
|
|
21
|
-
frameworks: [plan.repo.framework].filter(value => value && value !== 'unknown'),
|
|
22
|
-
languages: ['TypeScript', 'JavaScript'],
|
|
23
|
-
packageManagers: [plan.repo.packageManager].filter(value => value && value !== 'unknown'),
|
|
24
|
-
routes: routes.slice(0, 80),
|
|
25
|
-
routePrivacy: {
|
|
26
|
-
allowed: (routePrivacy.allowed ?? []).slice(0, 40),
|
|
27
|
-
blocked: (routePrivacy.blocked ?? []).slice(0, 40),
|
|
28
|
-
review: (routePrivacy.review ?? []).slice(0, 40),
|
|
29
|
-
},
|
|
30
|
-
notableFiles: [
|
|
31
|
-
'package.json',
|
|
32
|
-
...plan.repo.layoutCandidates,
|
|
33
|
-
...plan.repo.contentFiles.slice(0, 12),
|
|
34
|
-
],
|
|
35
|
-
};
|
|
36
|
-
if (plan.repo.git.branch) {
|
|
37
|
-
repo.defaultBranch = plan.repo.git.branch;
|
|
38
|
-
}
|
|
39
|
-
const claims = [
|
|
4
|
+
export async function buildInitializationPayload(plan, options = {}) {
|
|
5
|
+
const appName = titleFromPackageName(plan.repo.packageJson?.name ?? plan.appId);
|
|
6
|
+
const docs = await readProjectDocs(plan.cwd);
|
|
7
|
+
const routes = plan.repo.routes ?? [];
|
|
8
|
+
const publicBlogRoute = routes.find(route => route === '/blog' || route.startsWith('/blog/'));
|
|
9
|
+
const routePrivacy = plan.repo.routePrivacy ?? { allowed: [], blocked: [], review: [] };
|
|
10
|
+
const appIdentity = {
|
|
11
|
+
name: appName,
|
|
12
|
+
};
|
|
13
|
+
if (options.domain) {
|
|
14
|
+
appIdentity.domain = options.domain;
|
|
15
|
+
}
|
|
16
|
+
if (docs.overview?.claim) {
|
|
17
|
+
appIdentity.description = docs.overview.claim;
|
|
18
|
+
}
|
|
19
|
+
const repo = {
|
|
20
|
+
root: path.basename(plan.cwd),
|
|
21
|
+
frameworks: [plan.repo.framework].filter(value => value && value !== 'unknown'),
|
|
22
|
+
languages: ['TypeScript', 'JavaScript'],
|
|
23
|
+
packageManagers: [plan.repo.packageManager].filter(value => value && value !== 'unknown'),
|
|
24
|
+
routes: routes.slice(0, 80),
|
|
25
|
+
routePrivacy: {
|
|
26
|
+
allowed: (routePrivacy.allowed ?? []).slice(0, 40),
|
|
27
|
+
blocked: (routePrivacy.blocked ?? []).slice(0, 40),
|
|
28
|
+
review: (routePrivacy.review ?? []).slice(0, 40),
|
|
29
|
+
},
|
|
30
|
+
notableFiles: [
|
|
31
|
+
'package.json',
|
|
32
|
+
...plan.repo.layoutCandidates,
|
|
33
|
+
...plan.repo.contentFiles.slice(0, 12),
|
|
34
|
+
],
|
|
35
|
+
};
|
|
36
|
+
if (plan.repo.git.branch) {
|
|
37
|
+
repo.defaultBranch = plan.repo.git.branch;
|
|
38
|
+
}
|
|
39
|
+
const claims = [
|
|
40
40
|
{
|
|
41
41
|
category: 'repo',
|
|
42
42
|
claim: `The repo package name is ${plan.repo.packageJson?.name ?? appName}.`,
|
|
@@ -78,8 +78,8 @@ export async function buildInitializationPayload(plan, options = {}) {
|
|
|
78
78
|
client: 'distributionos-cli',
|
|
79
79
|
instructionPackVersion: plan.instructionPackVersion,
|
|
80
80
|
sourceSummary: 'DistributionOS CLI inspected package metadata, routes, content files, deploy hints, and agent instruction files. It did not read .env files or secrets.',
|
|
81
|
-
appIdentity,
|
|
82
|
-
repo,
|
|
81
|
+
appIdentity,
|
|
82
|
+
repo,
|
|
83
83
|
distribution: {
|
|
84
84
|
blogRoute: publicBlogRoute ?? undefined,
|
|
85
85
|
analytics: plan.analytics.status === 'enabled'
|
|
@@ -137,31 +137,31 @@ async function readProjectDocs(cwd) {
|
|
|
137
137
|
return {};
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
-
function extractOverviewExcerpt(text) {
|
|
141
|
-
const normalized = text.replace(/\r\n/g, '\n');
|
|
142
|
-
if (isScaffoldReadme(normalized)) {
|
|
143
|
-
return null;
|
|
144
|
-
}
|
|
145
|
-
const overviewIndex = normalized.search(/(^|\n)#{1,3}\s+(Project Overview|Overview|Solution|What it does)\s*\n/i);
|
|
146
|
-
const source = overviewIndex >= 0 ? normalized.slice(overviewIndex) : normalized;
|
|
147
|
-
return source
|
|
148
|
-
.split(/\n{2,}/)
|
|
149
|
-
.map(block => block.replace(/^#{1,6}\s+[^\n]+\n?/, '').trim())
|
|
150
|
-
.find(block => block.length >= 80 && !/secret|api key|environment variables/i.test(block) && !isScaffoldReadme(block))
|
|
151
|
-
?.slice(0, 700) ?? null;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
function isScaffoldReadme(value) {
|
|
155
|
-
const text = value.toLowerCase();
|
|
156
|
-
return [
|
|
157
|
-
'this is a [next.js]',
|
|
158
|
-
'bootstrapped with [`create-next-app`]',
|
|
159
|
-
'next.js documentation',
|
|
160
|
-
'learn next.js',
|
|
161
|
-
'deploy on vercel',
|
|
162
|
-
'you can start editing the page by modifying',
|
|
163
|
-
].filter(needle => text.includes(needle)).length >= 2;
|
|
164
|
-
}
|
|
140
|
+
function extractOverviewExcerpt(text) {
|
|
141
|
+
const normalized = text.replace(/\r\n/g, '\n');
|
|
142
|
+
if (isScaffoldReadme(normalized)) {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
const overviewIndex = normalized.search(/(^|\n)#{1,3}\s+(Project Overview|Overview|Solution|What it does)\s*\n/i);
|
|
146
|
+
const source = overviewIndex >= 0 ? normalized.slice(overviewIndex) : normalized;
|
|
147
|
+
return source
|
|
148
|
+
.split(/\n{2,}/)
|
|
149
|
+
.map(block => block.replace(/^#{1,6}\s+[^\n]+\n?/, '').trim())
|
|
150
|
+
.find(block => block.length >= 80 && !/secret|api key|environment variables/i.test(block) && !isScaffoldReadme(block))
|
|
151
|
+
?.slice(0, 700) ?? null;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function isScaffoldReadme(value) {
|
|
155
|
+
const text = value.toLowerCase();
|
|
156
|
+
return [
|
|
157
|
+
'this is a [next.js]',
|
|
158
|
+
'bootstrapped with [`create-next-app`]',
|
|
159
|
+
'next.js documentation',
|
|
160
|
+
'learn next.js',
|
|
161
|
+
'deploy on vercel',
|
|
162
|
+
'you can start editing the page by modifying',
|
|
163
|
+
].filter(needle => text.includes(needle)).length >= 2;
|
|
164
|
+
}
|
|
165
165
|
|
|
166
166
|
function routeReference(route, files) {
|
|
167
167
|
if (route === '/blog' && files.includes('src/app/blog/page.tsx')) return 'src/app/blog/page.tsx';
|