dxcomplete 0.2.1 → 0.3.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 (89) hide show
  1. package/.env.example +0 -7
  2. package/README.md +68 -103
  3. package/dist/cli.js +2 -24
  4. package/dist/validate.js +10 -26
  5. package/docs/cost-model.md +2 -2
  6. package/docs/decision-basis.md +5 -11
  7. package/docs/diagrams.md +3 -3
  8. package/docs/index.md +25 -39
  9. package/docs/model.md +15 -23
  10. package/docs/open-questions.md +1 -1
  11. package/docs/taxonomy.md +7 -8
  12. package/docs/workflows.md +3 -3
  13. package/package.json +24 -24
  14. package/templates/process/README.md +11 -11
  15. package/templates/process/controls.yml +19 -19
  16. package/templates/process/cost-model.yml +3 -3
  17. package/templates/process/decision-basis.yml +4 -4
  18. package/templates/process/diagrams/00-decision-basis.mmd +1 -1
  19. package/templates/process/diagrams/00-overview.mmd +1 -1
  20. package/templates/process/diagrams/01-intake-triage.mmd +4 -4
  21. package/templates/process/diagrams/02-product-definition.mmd +3 -3
  22. package/templates/process/diagrams/03-engineering-execution.mmd +1 -1
  23. package/templates/process/diagrams/04-qa-verification.mmd +1 -1
  24. package/templates/process/diagrams/05-product-validation.mmd +1 -1
  25. package/templates/process/diagrams/06-change-release-control.mmd +1 -1
  26. package/templates/process/diagrams/07-deployment-operations.mmd +1 -1
  27. package/templates/process/diagrams/08-support-incident-management.mmd +1 -1
  28. package/templates/process/diagrams/09-problem-improvement.mmd +1 -1
  29. package/templates/process/diagrams/10-risk-control-management.mmd +1 -1
  30. package/templates/process/diagrams/11-audit-evidence-capture.mmd +1 -1
  31. package/templates/process/roles.yml +6 -6
  32. package/templates/process/taxonomy.yml +46 -46
  33. package/templates/process/workflows.yml +29 -29
  34. package/website/account.html +57 -0
  35. package/website/app.js +177 -0
  36. package/website/flow.html +4 -0
  37. package/website/glossary.html +4 -0
  38. package/website/index.html +4 -0
  39. package/website/objects.html +4 -0
  40. package/website/operating-guide.html +4 -0
  41. package/website/outcomes.html +4 -0
  42. package/website/phase-build.html +4 -0
  43. package/website/phase-elicit.html +4 -0
  44. package/website/phase-go-live.html +4 -0
  45. package/website/phase-measure.html +4 -0
  46. package/website/phase-operate.html +4 -0
  47. package/website/phase-orient.html +4 -0
  48. package/website/phase-weigh.html +4 -0
  49. package/website/roles.html +4 -0
  50. package/website/styles.css +217 -1
  51. package/dist/http/service.d.ts +0 -7
  52. package/dist/http/service.js +0 -725
  53. package/dist/mcp/docs.d.ts +0 -114
  54. package/dist/mcp/docs.js +0 -626
  55. package/dist/mcp/server.d.ts +0 -20
  56. package/dist/mcp/server.js +0 -3059
  57. package/dist/runtime/auth.d.ts +0 -162
  58. package/dist/runtime/auth.js +0 -394
  59. package/dist/runtime/check.d.ts +0 -7
  60. package/dist/runtime/check.js +0 -16
  61. package/dist/runtime/config.d.ts +0 -17
  62. package/dist/runtime/config.js +0 -93
  63. package/dist/runtime/mongo.d.ts +0 -9
  64. package/dist/runtime/mongo.js +0 -56
  65. package/dist/runtime/records.d.ts +0 -427
  66. package/dist/runtime/records.js +0 -2092
  67. package/scripts/check-env-surface.mjs +0 -136
  68. package/scripts/check-public-copy.mjs +0 -263
  69. package/scripts/check-service-boundary.mjs +0 -63
  70. package/scripts/runtime-work-order.mjs +0 -506
  71. package/scripts/smoke-mcp-http.mjs +0 -4026
  72. package/src/cli.ts +0 -268
  73. package/src/http/server.ts +0 -314
  74. package/src/http/service.ts +0 -934
  75. package/src/init.ts +0 -262
  76. package/src/install-manifest.ts +0 -144
  77. package/src/mcp/docs.ts +0 -777
  78. package/src/mcp/server.ts +0 -4580
  79. package/src/package-root.ts +0 -31
  80. package/src/runtime/actor.ts +0 -61
  81. package/src/runtime/auth.ts +0 -673
  82. package/src/runtime/check.ts +0 -18
  83. package/src/runtime/config.ts +0 -128
  84. package/src/runtime/mongo.ts +0 -89
  85. package/src/runtime/records.ts +0 -3205
  86. package/src/runtime/workspace.ts +0 -155
  87. package/src/upgrade.ts +0 -356
  88. package/src/validate.ts +0 -141
  89. package/src/version.ts +0 -16
package/src/init.ts DELETED
@@ -1,262 +0,0 @@
1
- import { copyFile, mkdir, readdir, writeFile } from "node:fs/promises";
2
- import path from "node:path";
3
- import { INSTALL_MANIFEST_PATH, writeInstallManifest } from "./install-manifest.js";
4
- import { fileExists, resolvePackageRoot } from "./package-root.js";
5
- import { getUpgradeManagedFiles } from "./upgrade.js";
6
-
7
- export type InitOptions = {
8
- targetDir: string;
9
- force?: boolean;
10
- dryRun?: boolean;
11
- includeGithubWorkflow?: boolean;
12
- };
13
-
14
- export type InitResult = {
15
- targetDir: string;
16
- written: string[];
17
- skipped: string[];
18
- planned: string[];
19
- };
20
-
21
- type CopyOptions = Required<Pick<InitOptions, "force" | "dryRun">>;
22
-
23
- export async function initProject(options: InitOptions): Promise<InitResult> {
24
- const targetDir = path.resolve(options.targetDir);
25
- const force = options.force ?? false;
26
- const dryRun = options.dryRun ?? false;
27
- const includeGithubWorkflow = options.includeGithubWorkflow ?? true;
28
- const packageRoot = await resolvePackageRoot();
29
-
30
- const result: InitResult = {
31
- targetDir,
32
- written: [],
33
- skipped: [],
34
- planned: []
35
- };
36
-
37
- await copyDirectory(
38
- path.join(packageRoot, "docs"),
39
- path.join(targetDir, "dxcomplete", "docs"),
40
- { force, dryRun },
41
- result
42
- );
43
-
44
- await copyDirectory(
45
- path.join(packageRoot, "templates", "process"),
46
- path.join(targetDir, "dxcomplete", "process"),
47
- { force, dryRun },
48
- result
49
- );
50
-
51
- await writeWorkspaceConfig(targetDir, { force, dryRun }, result);
52
-
53
- await copyFileIfAbsent(
54
- path.join(packageRoot, "templates", "AGENTS.md"),
55
- path.join(targetDir, "AGENTS.md"),
56
- { dryRun },
57
- result
58
- );
59
-
60
- await copyDirectory(
61
- path.join(packageRoot, "templates", "next", "pages"),
62
- path.join(targetDir, "pages"),
63
- { force, dryRun },
64
- result
65
- );
66
-
67
- await copyFileIfAvailable(
68
- path.join(packageRoot, "templates", "next", "vercel.json"),
69
- path.join(targetDir, "vercel.json"),
70
- { force, dryRun },
71
- result
72
- );
73
-
74
- if (includeGithubWorkflow) {
75
- await copyDirectory(
76
- path.join(packageRoot, "templates", "github", "workflows"),
77
- path.join(targetDir, ".github", "workflows"),
78
- { force, dryRun },
79
- result
80
- );
81
- }
82
-
83
- await writeScaffoldManifest(packageRoot, targetDir, { force, dryRun }, result);
84
-
85
- return result;
86
- }
87
-
88
- async function writeScaffoldManifest(
89
- packageRoot: string,
90
- targetDir: string,
91
- options: CopyOptions,
92
- result: InitResult
93
- ): Promise<void> {
94
- const managedFiles = getUpgradeManagedFiles(packageRoot, targetDir);
95
- const managedDestinations = new Set(managedFiles.map((file) => file.destinationRelative));
96
- const skippedManagedFile = result.skipped.some((file) => managedDestinations.has(file));
97
-
98
- if (skippedManagedFile && !options.force) {
99
- result.skipped.push(INSTALL_MANIFEST_PATH);
100
- return;
101
- }
102
-
103
- if (options.dryRun) {
104
- result.planned.push(INSTALL_MANIFEST_PATH);
105
- return;
106
- }
107
-
108
- await writeInstallManifest(targetDir, managedFiles);
109
- result.written.push(INSTALL_MANIFEST_PATH);
110
- }
111
-
112
- async function copyFileIfAvailable(
113
- sourcePath: string,
114
- destinationPath: string,
115
- options: CopyOptions,
116
- result: InitResult
117
- ): Promise<void> {
118
- if (!(await fileExists(sourcePath))) {
119
- return;
120
- }
121
-
122
- const relativeDestination = path.relative(result.targetDir, destinationPath);
123
- const exists = await fileExists(destinationPath);
124
-
125
- if (exists && !options.force) {
126
- result.skipped.push(relativeDestination);
127
- return;
128
- }
129
-
130
- if (options.dryRun) {
131
- result.planned.push(relativeDestination);
132
- return;
133
- }
134
-
135
- await mkdir(path.dirname(destinationPath), { recursive: true });
136
- await copyFile(sourcePath, destinationPath);
137
- result.written.push(relativeDestination);
138
- }
139
-
140
- async function copyFileIfAbsent(
141
- sourcePath: string,
142
- destinationPath: string,
143
- options: Pick<CopyOptions, "dryRun">,
144
- result: InitResult
145
- ): Promise<void> {
146
- if (!(await fileExists(sourcePath))) {
147
- return;
148
- }
149
-
150
- const relativeDestination = path.relative(result.targetDir, destinationPath);
151
- const exists = await fileExists(destinationPath);
152
-
153
- if (exists) {
154
- result.skipped.push(relativeDestination);
155
- return;
156
- }
157
-
158
- if (options.dryRun) {
159
- result.planned.push(relativeDestination);
160
- return;
161
- }
162
-
163
- await mkdir(path.dirname(destinationPath), { recursive: true });
164
- await copyFile(sourcePath, destinationPath);
165
- result.written.push(relativeDestination);
166
- }
167
-
168
- async function writeWorkspaceConfig(
169
- targetDir: string,
170
- options: CopyOptions,
171
- result: InitResult
172
- ): Promise<void> {
173
- const destinationPath = path.join(targetDir, "dxcomplete", "workspace.json");
174
- const relativeDestination = path.relative(result.targetDir, destinationPath);
175
- const exists = await fileExists(destinationPath);
176
-
177
- if (exists && !options.force) {
178
- result.skipped.push(relativeDestination);
179
- return;
180
- }
181
-
182
- if (options.dryRun) {
183
- result.planned.push(relativeDestination);
184
- return;
185
- }
186
-
187
- const workspaceId = slugifyWorkspaceId(path.basename(targetDir)) || "dxcomplete-workspace";
188
- const workspaceName = titleizeWorkspaceName(path.basename(targetDir)) || "DX Complete Workspace";
189
- const content = `${JSON.stringify(
190
- {
191
- workspaceId,
192
- name: workspaceName,
193
- bootstrapMembers: []
194
- },
195
- null,
196
- 2
197
- )}\n`;
198
-
199
- await mkdir(path.dirname(destinationPath), { recursive: true });
200
- await writeFile(destinationPath, content, "utf8");
201
- result.written.push(relativeDestination);
202
- }
203
-
204
- async function copyDirectory(
205
- sourceDir: string,
206
- destinationDir: string,
207
- options: CopyOptions,
208
- result: InitResult
209
- ): Promise<void> {
210
- const entries = await readdir(sourceDir, { withFileTypes: true });
211
-
212
- if (!options.dryRun) {
213
- await mkdir(destinationDir, { recursive: true });
214
- }
215
-
216
- for (const entry of entries) {
217
- const sourcePath = path.join(sourceDir, entry.name);
218
- const destinationPath = path.join(destinationDir, entry.name);
219
-
220
- if (entry.isDirectory()) {
221
- await copyDirectory(sourcePath, destinationPath, options, result);
222
- continue;
223
- }
224
-
225
- if (!entry.isFile()) {
226
- continue;
227
- }
228
-
229
- const relativeDestination = path.relative(result.targetDir, destinationPath);
230
- const exists = await fileExists(destinationPath);
231
-
232
- if (exists && !options.force) {
233
- result.skipped.push(relativeDestination);
234
- continue;
235
- }
236
-
237
- if (options.dryRun) {
238
- result.planned.push(relativeDestination);
239
- continue;
240
- }
241
-
242
- await mkdir(path.dirname(destinationPath), { recursive: true });
243
- await copyFile(sourcePath, destinationPath);
244
- result.written.push(relativeDestination);
245
- }
246
- }
247
-
248
- function slugifyWorkspaceId(value: string): string {
249
- return value
250
- .trim()
251
- .toLowerCase()
252
- .replace(/[^a-z0-9]+/g, "-")
253
- .replace(/^-+|-+$/g, "");
254
- }
255
-
256
- function titleizeWorkspaceName(value: string): string {
257
- return value
258
- .trim()
259
- .replace(/[-_]+/g, " ")
260
- .replace(/\s+/g, " ")
261
- .replace(/\b\w/g, (letter) => letter.toUpperCase());
262
- }
@@ -1,144 +0,0 @@
1
- import { createHash } from "node:crypto";
2
- import { mkdir, readFile, writeFile } from "node:fs/promises";
3
- import path from "node:path";
4
- import { fileExists } from "./package-root.js";
5
- import {
6
- DXCOMPLETE_PACKAGE_VERSION,
7
- WORKSPACE_COMPATIBILITY_VERSION
8
- } from "./version.js";
9
-
10
- export const INSTALL_MANIFEST_PATH = path.join("dxcomplete", ".install-manifest.json");
11
- export const INSTALL_MANIFEST_SCHEMA_VERSION = 1;
12
-
13
- export type UpgradeManagedFile = {
14
- destinationRelative: string;
15
- sourceRelative: string;
16
- sourcePath: string;
17
- destinationPath: string;
18
- strategy: "copy" | "merge-vercel";
19
- };
20
-
21
- export type InstallManifest = {
22
- schemaVersion: number;
23
- packageVersion: string;
24
- workspaceCompatibility: number;
25
- installedAt: string;
26
- managedFiles: Record<string, InstallManifestFile>;
27
- };
28
-
29
- export type InstallManifestFile = {
30
- sha256: string;
31
- source: string;
32
- strategy: UpgradeManagedFile["strategy"];
33
- };
34
-
35
- export async function readInstallManifest(targetDir: string): Promise<InstallManifest | undefined> {
36
- const manifestPath = path.join(targetDir, INSTALL_MANIFEST_PATH);
37
-
38
- if (!(await fileExists(manifestPath))) {
39
- return undefined;
40
- }
41
-
42
- const parsed = JSON.parse(await readFile(manifestPath, "utf8")) as unknown;
43
- return parseInstallManifest(parsed, manifestPath);
44
- }
45
-
46
- export async function writeInstallManifest(targetDir: string, files: UpgradeManagedFile[]): Promise<void> {
47
- const managedFiles: Record<string, InstallManifestFile> = {};
48
-
49
- for (const file of files) {
50
- if (!(await fileExists(file.destinationPath))) {
51
- continue;
52
- }
53
-
54
- managedFiles[file.destinationRelative] = {
55
- sha256: await hashFile(file.destinationPath),
56
- source: file.sourceRelative,
57
- strategy: file.strategy
58
- };
59
- }
60
-
61
- const manifest: InstallManifest = {
62
- schemaVersion: INSTALL_MANIFEST_SCHEMA_VERSION,
63
- packageVersion: DXCOMPLETE_PACKAGE_VERSION,
64
- workspaceCompatibility: WORKSPACE_COMPATIBILITY_VERSION,
65
- installedAt: new Date().toISOString(),
66
- managedFiles
67
- };
68
-
69
- const manifestPath = path.join(targetDir, INSTALL_MANIFEST_PATH);
70
- await mkdir(path.dirname(manifestPath), { recursive: true });
71
- await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, "utf8");
72
- }
73
-
74
- export async function hashFile(filePath: string): Promise<string> {
75
- return hashContent(await readFile(filePath));
76
- }
77
-
78
- export function hashContent(content: string | Buffer): string {
79
- return createHash("sha256").update(content).digest("hex");
80
- }
81
-
82
- function parseInstallManifest(value: unknown, source: string): InstallManifest {
83
- if (!value || typeof value !== "object") {
84
- throw new Error(`${source} must be a JSON object.`);
85
- }
86
-
87
- const input = value as Record<string, unknown>;
88
- const schemaVersion = readNumber(input.schemaVersion, "schemaVersion", source);
89
- const packageVersion = readString(input.packageVersion, "packageVersion", source);
90
- const workspaceCompatibility = readNumber(input.workspaceCompatibility, "workspaceCompatibility", source);
91
- const installedAt = readString(input.installedAt, "installedAt", source);
92
- const managedFiles = parseManagedFiles(input.managedFiles, source);
93
-
94
- return {
95
- schemaVersion,
96
- packageVersion,
97
- workspaceCompatibility,
98
- installedAt,
99
- managedFiles
100
- };
101
- }
102
-
103
- function parseManagedFiles(value: unknown, source: string): Record<string, InstallManifestFile> {
104
- if (!value || typeof value !== "object" || Array.isArray(value)) {
105
- throw new Error(`${source} managedFiles must be a JSON object.`);
106
- }
107
-
108
- const output: Record<string, InstallManifestFile> = {};
109
- for (const [filePath, fileValue] of Object.entries(value as Record<string, unknown>)) {
110
- if (!fileValue || typeof fileValue !== "object" || Array.isArray(fileValue)) {
111
- throw new Error(`${source} managedFiles.${filePath} must be a JSON object.`);
112
- }
113
-
114
- const file = fileValue as Record<string, unknown>;
115
- const strategy = readString(file.strategy, `managedFiles.${filePath}.strategy`, source);
116
- if (strategy !== "copy" && strategy !== "merge-vercel") {
117
- throw new Error(`${source} managedFiles.${filePath}.strategy must be copy or merge-vercel.`);
118
- }
119
-
120
- output[filePath] = {
121
- sha256: readString(file.sha256, `managedFiles.${filePath}.sha256`, source),
122
- source: readString(file.source, `managedFiles.${filePath}.source`, source),
123
- strategy
124
- };
125
- }
126
-
127
- return output;
128
- }
129
-
130
- function readString(value: unknown, key: string, source: string): string {
131
- if (typeof value !== "string" || !value.trim()) {
132
- throw new Error(`${source} ${key} must be a non-empty string.`);
133
- }
134
-
135
- return value;
136
- }
137
-
138
- function readNumber(value: unknown, key: string, source: string): number {
139
- if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
140
- throw new Error(`${source} ${key} must be a non-negative integer.`);
141
- }
142
-
143
- return value;
144
- }