aw-spec-cli 0.1.3 ā 0.1.4
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 +291 -0
- package/assets/docs/UI.Visualization/PACKAGING.md +191 -0
- package/assets/docs/UI.Visualization/UI.Visualization.Reference.pack.txt +11768 -0
- package/assets/docs/UI.Visualization/UI.Visualization.pack.txt +11214 -0
- package/assets/docs/UI.Visualization/pack-foundation.ps1 +165 -0
- package/assets/docs/UI.Visualization/pack-foundation.sh +206 -0
- package/assets/docs/UI.Visualization/pack-reference-foundation.ps1 +159 -0
- package/assets/docs/UI.Visualization/pack-reference-foundation.sh +205 -0
- package/assets/docs/UI.Visualization/unpack-foundation.ps1 +126 -0
- package/assets/docs/UI.Visualization/unpack-foundation.sh +217 -0
- package/assets/docs/UI.Visualization/unpack-reference-foundation.ps1 +129 -0
- package/assets/docs/UI.Visualization/unpack-reference-foundation.sh +218 -0
- package/assets/docs/domainspecs/UIVisualization/chart-bubble.md +70 -0
- package/assets/docs/domainspecs/UIVisualization/chart-dimred.md +58 -0
- package/assets/docs/domainspecs/UIVisualization/chart-heatmap.md +62 -0
- package/assets/docs/domainspecs/UIVisualization/chart-network.md +69 -0
- package/assets/docs/domainspecs/UIVisualization/chart-parallel.md +75 -0
- package/assets/docs/domainspecs/UIVisualization/chart-scurve.md +66 -0
- package/assets/docs/domainspecs/UIVisualization/chart-survival.md +69 -0
- package/assets/docs/domainspecs/UIVisualization/chart-trellis.md +68 -0
- package/assets/docs/domainspecs/UIVisualization/chart-violin.md +61 -0
- package/assets/docs/domainspecs/UIVisualization/chart-volcano.md +63 -0
- package/assets/docs/domainspecs/UIVisualization/charting-standards.domain.md +80 -0
- package/assets/docs/domainspecs/UIVisualization/clean-architecture.domain.md +87 -0
- package/assets/docs/domainspecs/UIVisualization/coding-standards.domain.md +47 -0
- package/assets/docs/domainspecs/UIVisualization/comandrulemap.md +130 -0
- package/assets/docs/domainspecs/UIVisualization/component-contracts.domain.md +67 -0
- package/assets/docs/domainspecs/UIVisualization/data-source.domain.md +68 -0
- package/assets/docs/domainspecs/UIVisualization/domain-requirements.md +110 -0
- package/assets/docs/domainspecs/UIVisualization/folder-structure.domain.md +55 -0
- package/assets/docs/domainspecs/UIVisualization/state-management.domain.md +67 -0
- package/assets/docs/domainspecs/UIVisualization/testing.domain.md +52 -0
- package/assets/docs/domainspecs/UIVisualization/ui-viz-terms.md +39 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +54 -7
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/update.d.ts +3 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +142 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/manifest.d.ts +31 -0
- package/dist/utils/manifest.d.ts.map +1 -0
- package/dist/utils/manifest.js +91 -0
- package/dist/utils/manifest.js.map +1 -0
- package/dist/utils/update-engine.d.ts +52 -0
- package/dist/utils/update-engine.d.ts.map +1 -0
- package/dist/utils/update-engine.js +203 -0
- package/dist/utils/update-engine.js.map +1 -0
- package/package.json +1 -1
- package/assets/docs/requirement-spec.txt +0 -15
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import inquirer from 'inquirer';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import fs from 'fs-extra';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
import { resolveAssetsPath } from '../utils/paths.js';
|
|
8
|
+
import { readManifest, updateManifest } from '../utils/manifest.js';
|
|
9
|
+
import { buildUpdatePlan, applyUpdatePlan } from '../utils/update-engine.js';
|
|
10
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const AGENT_FOLDER_MAP = {
|
|
12
|
+
claude: '.claude',
|
|
13
|
+
antigravity: '.agents',
|
|
14
|
+
kilocode: '.kilocode',
|
|
15
|
+
};
|
|
16
|
+
const ALWAYS_COPY = ['.aw-spec', 'docs'];
|
|
17
|
+
export const updateCommand = new Command('update')
|
|
18
|
+
.description('Update an existing AppWeaver Spec project with latest assets from registry')
|
|
19
|
+
.argument('[directory]', 'Target directory (default: current directory)', '.')
|
|
20
|
+
.option('-a, --agent <agent>', 'Agent to use: claude, antigravity, kilocode (detected from manifest if not specified)')
|
|
21
|
+
.option('-y, --yes', 'Skip prompts and apply non-conflicting updates automatically')
|
|
22
|
+
.option('--dry-run', 'Show what would be updated without making changes')
|
|
23
|
+
.action(async (directory, options) => {
|
|
24
|
+
const targetDir = directory === '.' ? process.cwd() : directory;
|
|
25
|
+
const manifestPath = path.join(targetDir, '.aw-spec', 'manifest.json');
|
|
26
|
+
console.log(`\nš Checking for updates in: ${targetDir}\n`);
|
|
27
|
+
// Load existing manifest
|
|
28
|
+
const manifest = await readManifest(manifestPath);
|
|
29
|
+
if (!manifest) {
|
|
30
|
+
console.log(chalk.red('ā No manifest found. This project was not initialized with aw-spec or is from an older version.'));
|
|
31
|
+
console.log(chalk.yellow(' Run `aw-spec init` to initialize a new project.'));
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
console.log(chalk.gray(` Current version: ${manifest.version}`));
|
|
35
|
+
console.log(chalk.gray(` Last updated: ${manifest.updatedAt}`));
|
|
36
|
+
console.log(chalk.gray(` Tracked files: ${Object.keys(manifest.files).length}`));
|
|
37
|
+
// Determine agent from manifest or options
|
|
38
|
+
let agent = options.agent;
|
|
39
|
+
if (agent === 'prompt') {
|
|
40
|
+
// Try to detect from init-options.json
|
|
41
|
+
const initOptionsPath = path.join(targetDir, '.aw-spec', 'init-options.json');
|
|
42
|
+
if (await fs.pathExists(initOptionsPath)) {
|
|
43
|
+
try {
|
|
44
|
+
const initOptions = await fs.readJSON(initOptionsPath);
|
|
45
|
+
if (initOptions.ai && ['claude', 'antigravity', 'kilocode'].includes(initOptions.ai)) {
|
|
46
|
+
agent = initOptions.ai;
|
|
47
|
+
console.log(chalk.gray(` Detected agent from init-options: ${agent}`));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// Ignore parse errors
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// If still not determined, prompt
|
|
56
|
+
if (agent === 'prompt') {
|
|
57
|
+
if (options.yes) {
|
|
58
|
+
agent = 'claude';
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
const { selectedAgent } = await inquirer.prompt([
|
|
62
|
+
{
|
|
63
|
+
type: 'list',
|
|
64
|
+
name: 'selectedAgent',
|
|
65
|
+
message: 'Which agent skills should be updated?',
|
|
66
|
+
choices: [
|
|
67
|
+
{ name: 'Claude Code (.claude/skills)', value: 'claude' },
|
|
68
|
+
{ name: 'Antigravity (.agents/skills)', value: 'antigravity' },
|
|
69
|
+
{ name: 'KiloCode (.kilocode/skills)', value: 'kilocode' },
|
|
70
|
+
],
|
|
71
|
+
default: 'claude',
|
|
72
|
+
},
|
|
73
|
+
]);
|
|
74
|
+
agent = selectedAgent;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const agentFolder = AGENT_FOLDER_MAP[agent];
|
|
78
|
+
// Resolve new assets from registry
|
|
79
|
+
const assetsPath = await resolveAssetsPath();
|
|
80
|
+
console.log(chalk.gray(` Source assets: ${assetsPath}`));
|
|
81
|
+
if (options.dryRun) {
|
|
82
|
+
console.log('\nš Dry run - checking for updates...\n');
|
|
83
|
+
}
|
|
84
|
+
// Build update plan
|
|
85
|
+
console.log(chalk.bold('\nš Analyzing changes...\n'));
|
|
86
|
+
const plan = await buildUpdatePlan(manifest.files, targetDir, assetsPath);
|
|
87
|
+
// Print summary
|
|
88
|
+
console.log(chalk.bold('\nš Update Plan:'));
|
|
89
|
+
console.log(chalk.green(` Update: ${plan.summary.update}`));
|
|
90
|
+
console.log(chalk.blue(` Add: ${plan.summary.add}`));
|
|
91
|
+
console.log(chalk.yellow(` Preserve: ${plan.summary.preserve}`));
|
|
92
|
+
console.log(chalk.red(` Skip (conflicts): ${plan.summary.skip}`));
|
|
93
|
+
console.log(chalk.gray(` Remove: ${plan.summary.remove}`));
|
|
94
|
+
if (plan.summary.skip > 0) {
|
|
95
|
+
console.log(chalk.yellow('\nā ļø Conflicts detected - these files have both user and upstream changes:'));
|
|
96
|
+
for (const file of plan.files.filter(f => f.disposition === 'skip')) {
|
|
97
|
+
console.log(chalk.yellow(` ā ${file.relPath} - ${file.reason}`));
|
|
98
|
+
}
|
|
99
|
+
console.log(chalk.yellow('\n These files will be skipped. Resolve manually after update.'));
|
|
100
|
+
}
|
|
101
|
+
if (plan.summary.preserve > 0) {
|
|
102
|
+
console.log(chalk.blue('\nā¹ļø User-modified files preserved:'));
|
|
103
|
+
for (const file of plan.files.filter(f => f.disposition === 'preserve')) {
|
|
104
|
+
console.log(chalk.blue(` ā ${file.relPath} - ${file.reason}`));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (options.dryRun) {
|
|
108
|
+
console.log(chalk.bold('\nš Dry run complete - no changes made.'));
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
// Confirm before applying if not --yes
|
|
112
|
+
if (!options.yes && (plan.summary.update > 0 || plan.summary.add > 0 || plan.summary.remove > 0)) {
|
|
113
|
+
const { confirm } = await inquirer.prompt([
|
|
114
|
+
{
|
|
115
|
+
type: 'confirm',
|
|
116
|
+
name: 'confirm',
|
|
117
|
+
message: 'Apply these updates?',
|
|
118
|
+
default: true,
|
|
119
|
+
},
|
|
120
|
+
]);
|
|
121
|
+
if (!confirm) {
|
|
122
|
+
console.log(chalk.gray('\nUpdate cancelled.'));
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// Apply update plan
|
|
127
|
+
console.log(chalk.bold('\nš¦ Applying updates...\n'));
|
|
128
|
+
await applyUpdatePlan(plan, targetDir, assetsPath, {
|
|
129
|
+
onProgress: (msg) => console.log(msg),
|
|
130
|
+
});
|
|
131
|
+
// Update manifest with new state
|
|
132
|
+
console.log(chalk.bold('\nš Updating manifest...'));
|
|
133
|
+
const newManifest = await updateManifest(manifestPath, targetDir, manifest.version);
|
|
134
|
+
console.log(chalk.green(` ā Manifest updated (${Object.keys(newManifest.files).length} files tracked)`));
|
|
135
|
+
console.log(chalk.bold('\nā
Update complete!'));
|
|
136
|
+
console.log('\nNext steps:');
|
|
137
|
+
console.log(' aw-spec doctor # Verify the installation');
|
|
138
|
+
if (plan.summary.skip > 0) {
|
|
139
|
+
console.log(chalk.yellow(' Review skipped files and resolve conflicts manually'));
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
//# sourceMappingURL=update.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { program } from 'commander';
|
|
3
3
|
import { initCommand } from './commands/init.js';
|
|
4
4
|
import { doctorCommand } from './commands/doctor.js';
|
|
5
|
+
import { updateCommand } from './commands/update.js';
|
|
5
6
|
import fs from 'fs-extra';
|
|
6
7
|
import path from 'path';
|
|
7
8
|
import { fileURLToPath } from 'url';
|
|
@@ -12,6 +13,7 @@ program
|
|
|
12
13
|
.description('AppWeaver Spec-Driven Development CLI')
|
|
13
14
|
.version(packageJson.version)
|
|
14
15
|
.addCommand(initCommand)
|
|
16
|
+
.addCommand(updateCommand)
|
|
15
17
|
.addCommand(doctorCommand);
|
|
16
18
|
program.parse();
|
|
17
19
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC/D,MAAM,WAAW,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC,CAAC;AAElF,OAAO;KACJ,IAAI,CAAC,SAAS,CAAC;KACf,WAAW,CAAC,uCAAuC,CAAC;KACpD,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC;KAC5B,UAAU,CAAC,WAAW,CAAC;KACvB,UAAU,CAAC,aAAa,CAAC,CAAC;AAE7B,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC/D,MAAM,WAAW,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC,CAAC;AAElF,OAAO;KACJ,IAAI,CAAC,SAAS,CAAC;KACf,WAAW,CAAC,uCAAuC,CAAC;KACpD,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC;KAC5B,UAAU,CAAC,WAAW,CAAC;KACvB,UAAU,CAAC,aAAa,CAAC;KACzB,UAAU,CAAC,aAAa,CAAC,CAAC;AAE7B,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface Manifest {
|
|
2
|
+
version: string;
|
|
3
|
+
files: Record<string, string>;
|
|
4
|
+
updatedAt: string;
|
|
5
|
+
}
|
|
6
|
+
export interface ManifestOptions {
|
|
7
|
+
manifestPath: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Compute SHA256 hash of a file
|
|
11
|
+
*/
|
|
12
|
+
export declare function computeFileHash(filePath: string): Promise<string>;
|
|
13
|
+
/**
|
|
14
|
+
* Read manifest from disk, returns null if not found
|
|
15
|
+
*/
|
|
16
|
+
export declare function readManifest(manifestPath: string): Promise<Manifest | null>;
|
|
17
|
+
/**
|
|
18
|
+
* Write manifest to disk
|
|
19
|
+
*/
|
|
20
|
+
export declare function writeManifest(manifestPath: string, manifest: Manifest): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Create a new manifest from a source directory
|
|
23
|
+
* Walks the directory and computes hashes for all files
|
|
24
|
+
*/
|
|
25
|
+
export declare function createManifest(sourceRoot: string, targetRoot: string, version: string): Promise<Manifest>;
|
|
26
|
+
/**
|
|
27
|
+
* Update manifest with new hashes from target directory
|
|
28
|
+
* Used after successful update to record new state
|
|
29
|
+
*/
|
|
30
|
+
export declare function updateManifest(manifestPath: string, targetRoot: string, version: string): Promise<Manifest>;
|
|
31
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/utils/manifest.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAKvE;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAUjF;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAG3F;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,QAAQ,CAAC,CAyBnB;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,QAAQ,CAAC,CA4BnB"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { createHash } from 'crypto';
|
|
4
|
+
/**
|
|
5
|
+
* Compute SHA256 hash of a file
|
|
6
|
+
*/
|
|
7
|
+
export async function computeFileHash(filePath) {
|
|
8
|
+
const content = await fs.readFile(filePath);
|
|
9
|
+
const hash = createHash('sha256');
|
|
10
|
+
hash.update(content);
|
|
11
|
+
return hash.digest('hex');
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Read manifest from disk, returns null if not found
|
|
15
|
+
*/
|
|
16
|
+
export async function readManifest(manifestPath) {
|
|
17
|
+
if (!(await fs.pathExists(manifestPath))) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
const manifest = await fs.readJSON(manifestPath);
|
|
22
|
+
return manifest;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Write manifest to disk
|
|
30
|
+
*/
|
|
31
|
+
export async function writeManifest(manifestPath, manifest) {
|
|
32
|
+
await fs.ensureDir(path.dirname(manifestPath));
|
|
33
|
+
await fs.writeJSON(manifestPath, manifest, { spaces: 2 });
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Create a new manifest from a source directory
|
|
37
|
+
* Walks the directory and computes hashes for all files
|
|
38
|
+
*/
|
|
39
|
+
export async function createManifest(sourceRoot, targetRoot, version) {
|
|
40
|
+
const files = {};
|
|
41
|
+
async function walk(dir, baseSource) {
|
|
42
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
43
|
+
for (const entry of entries) {
|
|
44
|
+
const fullPath = path.join(dir, entry.name);
|
|
45
|
+
const relPath = path.relative(baseSource, fullPath);
|
|
46
|
+
if (entry.isDirectory()) {
|
|
47
|
+
await walk(fullPath, baseSource);
|
|
48
|
+
}
|
|
49
|
+
else if (entry.isFile()) {
|
|
50
|
+
const hash = await computeFileHash(fullPath);
|
|
51
|
+
files[relPath] = hash;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
await walk(sourceRoot, sourceRoot);
|
|
56
|
+
return {
|
|
57
|
+
version,
|
|
58
|
+
files,
|
|
59
|
+
updatedAt: new Date().toISOString(),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Update manifest with new hashes from target directory
|
|
64
|
+
* Used after successful update to record new state
|
|
65
|
+
*/
|
|
66
|
+
export async function updateManifest(manifestPath, targetRoot, version) {
|
|
67
|
+
const files = {};
|
|
68
|
+
async function walk(dir, baseTarget) {
|
|
69
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
70
|
+
for (const entry of entries) {
|
|
71
|
+
const fullPath = path.join(dir, entry.name);
|
|
72
|
+
const relPath = path.relative(baseTarget, fullPath);
|
|
73
|
+
if (entry.isDirectory()) {
|
|
74
|
+
await walk(fullPath, baseTarget);
|
|
75
|
+
}
|
|
76
|
+
else if (entry.isFile()) {
|
|
77
|
+
const hash = await computeFileHash(fullPath);
|
|
78
|
+
files[relPath] = hash;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
await walk(targetRoot, targetRoot);
|
|
83
|
+
const manifest = {
|
|
84
|
+
version,
|
|
85
|
+
files,
|
|
86
|
+
updatedAt: new Date().toISOString(),
|
|
87
|
+
};
|
|
88
|
+
await writeManifest(manifestPath, manifest);
|
|
89
|
+
return manifest;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/utils/manifest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export type Disposition = 'update' | 'preserve' | 'skip' | 'remove' | 'add';
|
|
2
|
+
export interface FileDisposition {
|
|
3
|
+
relPath: string;
|
|
4
|
+
disposition: Disposition;
|
|
5
|
+
reason: string;
|
|
6
|
+
manifestHash?: string;
|
|
7
|
+
currentHash?: string;
|
|
8
|
+
sourceHash?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface UpdatePlan {
|
|
11
|
+
files: FileDisposition[];
|
|
12
|
+
summary: {
|
|
13
|
+
update: number;
|
|
14
|
+
preserve: number;
|
|
15
|
+
skip: number;
|
|
16
|
+
remove: number;
|
|
17
|
+
add: number;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Compare three states and determine disposition for a single file
|
|
22
|
+
*
|
|
23
|
+
* Three-way comparison logic:
|
|
24
|
+
* - manifestHash: hash from original manifest (what we installed)
|
|
25
|
+
* - currentHash: hash of file currently on disk (user's version)
|
|
26
|
+
* - sourceHash: hash of file in new source (registry version)
|
|
27
|
+
*
|
|
28
|
+
* Cases:
|
|
29
|
+
* 1. All three same ā no-op (not in plan)
|
|
30
|
+
* 2. manifest === current !== source ā UPDATE (upstream changed, user didn't touch)
|
|
31
|
+
* 3. manifest !== current === source ā PRESERVE (user changed, upstream same - but this is weird)
|
|
32
|
+
* 4. manifest === source !== current ā PRESERVE (user changed, upstream didn't)
|
|
33
|
+
* 5. All three different ā SKIP (conflict - both changed)
|
|
34
|
+
* 6. manifest exists, current missing, source exists ā UPDATE (user deleted, restore from source)
|
|
35
|
+
* 7. manifest exists, current exists, source missing ā REMOVE (upstream deleted)
|
|
36
|
+
* 8. manifest missing, current exists, source exists ā SKIP (file added by user, also in new source - conflict)
|
|
37
|
+
* 9. manifest missing, current exists, source missing ā PRESERVE (user added, not in upstream)
|
|
38
|
+
* 10. manifest missing, current missing, source exists ā ADD (new file in upstream)
|
|
39
|
+
*/
|
|
40
|
+
export declare function computeDisposition(relPath: string, manifestHash: string | undefined, currentHash: string | undefined, sourceHash: string | undefined): FileDisposition;
|
|
41
|
+
/**
|
|
42
|
+
* Build update plan by comparing manifest, current target, and new source
|
|
43
|
+
*/
|
|
44
|
+
export declare function buildUpdatePlan(manifest: Record<string, string>, targetRoot: string, sourceRoot: string): Promise<UpdatePlan>;
|
|
45
|
+
/**
|
|
46
|
+
* Apply update plan to target directory
|
|
47
|
+
*/
|
|
48
|
+
export declare function applyUpdatePlan(plan: UpdatePlan, targetRoot: string, sourceRoot: string, options?: {
|
|
49
|
+
dryRun?: boolean;
|
|
50
|
+
onProgress?: (msg: string) => void;
|
|
51
|
+
}): Promise<void>;
|
|
52
|
+
//# sourceMappingURL=update-engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-engine.d.ts","sourceRoot":"","sources":["../../src/utils/update-engine.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AAE5E,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,WAAW,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,OAAO,EAAE;QACP,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;CACH;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,eAAe,CAqEjB;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAChC,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,UAAU,CAAC,CAyFrB;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,UAAU,EAChB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAAO,GACrE,OAAO,CAAC,IAAI,CAAC,CAkCf"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { computeFileHash } from './manifest.js';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
/**
|
|
5
|
+
* Compare three states and determine disposition for a single file
|
|
6
|
+
*
|
|
7
|
+
* Three-way comparison logic:
|
|
8
|
+
* - manifestHash: hash from original manifest (what we installed)
|
|
9
|
+
* - currentHash: hash of file currently on disk (user's version)
|
|
10
|
+
* - sourceHash: hash of file in new source (registry version)
|
|
11
|
+
*
|
|
12
|
+
* Cases:
|
|
13
|
+
* 1. All three same ā no-op (not in plan)
|
|
14
|
+
* 2. manifest === current !== source ā UPDATE (upstream changed, user didn't touch)
|
|
15
|
+
* 3. manifest !== current === source ā PRESERVE (user changed, upstream same - but this is weird)
|
|
16
|
+
* 4. manifest === source !== current ā PRESERVE (user changed, upstream didn't)
|
|
17
|
+
* 5. All three different ā SKIP (conflict - both changed)
|
|
18
|
+
* 6. manifest exists, current missing, source exists ā UPDATE (user deleted, restore from source)
|
|
19
|
+
* 7. manifest exists, current exists, source missing ā REMOVE (upstream deleted)
|
|
20
|
+
* 8. manifest missing, current exists, source exists ā SKIP (file added by user, also in new source - conflict)
|
|
21
|
+
* 9. manifest missing, current exists, source missing ā PRESERVE (user added, not in upstream)
|
|
22
|
+
* 10. manifest missing, current missing, source exists ā ADD (new file in upstream)
|
|
23
|
+
*/
|
|
24
|
+
export function computeDisposition(relPath, manifestHash, currentHash, sourceHash) {
|
|
25
|
+
// Case: file exists in all three
|
|
26
|
+
if (manifestHash && currentHash && sourceHash) {
|
|
27
|
+
if (manifestHash === currentHash && currentHash === sourceHash) {
|
|
28
|
+
// All same - no change needed (caller should filter these out)
|
|
29
|
+
return { relPath, disposition: 'update', reason: 'No changes (all identical)', manifestHash, currentHash, sourceHash };
|
|
30
|
+
}
|
|
31
|
+
if (manifestHash === currentHash && manifestHash !== sourceHash) {
|
|
32
|
+
// User didn't touch, upstream changed
|
|
33
|
+
return { relPath, disposition: 'update', reason: 'Upstream changed, user unmodified', manifestHash, currentHash, sourceHash };
|
|
34
|
+
}
|
|
35
|
+
if (manifestHash !== currentHash && manifestHash === sourceHash) {
|
|
36
|
+
// User changed, upstream didn't
|
|
37
|
+
return { relPath, disposition: 'preserve', reason: 'User modified, upstream unchanged', manifestHash, currentHash, sourceHash };
|
|
38
|
+
}
|
|
39
|
+
if (manifestHash === sourceHash && currentHash !== sourceHash) {
|
|
40
|
+
// Same as above - user changed, upstream same
|
|
41
|
+
return { relPath, disposition: 'preserve', reason: 'User modified, upstream unchanged', manifestHash, currentHash, sourceHash };
|
|
42
|
+
}
|
|
43
|
+
if (manifestHash !== currentHash && currentHash === sourceHash) {
|
|
44
|
+
// User changed to match upstream (e.g. user anticipated change)
|
|
45
|
+
return { relPath, disposition: 'preserve', reason: 'User version matches upstream', manifestHash, currentHash, sourceHash };
|
|
46
|
+
}
|
|
47
|
+
// All three different
|
|
48
|
+
return { relPath, disposition: 'skip', reason: 'Conflict: both user and upstream modified', manifestHash, currentHash, sourceHash };
|
|
49
|
+
}
|
|
50
|
+
// Case: manifest exists, current missing (user deleted)
|
|
51
|
+
if (manifestHash && !currentHash && sourceHash) {
|
|
52
|
+
return { relPath, disposition: 'update', reason: 'User deleted, restoring from upstream', manifestHash, currentHash, sourceHash };
|
|
53
|
+
}
|
|
54
|
+
// Case: manifest exists, current exists, source missing (upstream deleted)
|
|
55
|
+
if (manifestHash && currentHash && !sourceHash) {
|
|
56
|
+
return { relPath, disposition: 'remove', reason: 'Upstream removed file', manifestHash, currentHash, sourceHash };
|
|
57
|
+
}
|
|
58
|
+
// Case: manifest missing, current exists, source exists (user added, also in new upstream)
|
|
59
|
+
if (!manifestHash && currentHash && sourceHash) {
|
|
60
|
+
if (currentHash === sourceHash) {
|
|
61
|
+
// User added same content as upstream - treat as add
|
|
62
|
+
return { relPath, disposition: 'add', reason: 'New file in upstream (matches user)', manifestHash, currentHash, sourceHash };
|
|
63
|
+
}
|
|
64
|
+
// Different content - conflict
|
|
65
|
+
return { relPath, disposition: 'skip', reason: 'Conflict: user added file, upstream also added different version', manifestHash, currentHash, sourceHash };
|
|
66
|
+
}
|
|
67
|
+
// Case: manifest missing, current exists, source missing (user added, not in upstream)
|
|
68
|
+
if (!manifestHash && currentHash && !sourceHash) {
|
|
69
|
+
return { relPath, disposition: 'preserve', reason: 'User added file, not in upstream', manifestHash, currentHash, sourceHash };
|
|
70
|
+
}
|
|
71
|
+
// Case: manifest missing, current missing, source exists (new file in upstream)
|
|
72
|
+
if (!manifestHash && !currentHash && sourceHash) {
|
|
73
|
+
return { relPath, disposition: 'add', reason: 'New file in upstream', manifestHash, currentHash, sourceHash };
|
|
74
|
+
}
|
|
75
|
+
// Case: manifest exists, current missing, source missing (file was in manifest but deleted everywhere)
|
|
76
|
+
if (manifestHash && !currentHash && !sourceHash) {
|
|
77
|
+
return { relPath, disposition: 'remove', reason: 'File removed from upstream', manifestHash, currentHash, sourceHash };
|
|
78
|
+
}
|
|
79
|
+
// Should not reach here
|
|
80
|
+
return { relPath, disposition: 'skip', reason: 'Unknown state', manifestHash, currentHash, sourceHash };
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Build update plan by comparing manifest, current target, and new source
|
|
84
|
+
*/
|
|
85
|
+
export async function buildUpdatePlan(manifest, targetRoot, sourceRoot) {
|
|
86
|
+
const files = [];
|
|
87
|
+
// Collect all unique relative paths from all three sources
|
|
88
|
+
const allPaths = new Set();
|
|
89
|
+
// From manifest
|
|
90
|
+
for (const relPath of Object.keys(manifest)) {
|
|
91
|
+
allPaths.add(relPath);
|
|
92
|
+
}
|
|
93
|
+
// From target (current)
|
|
94
|
+
async function walkTarget(dir, base) {
|
|
95
|
+
try {
|
|
96
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
97
|
+
for (const entry of entries) {
|
|
98
|
+
const fullPath = path.join(dir, entry.name);
|
|
99
|
+
const relPath = path.relative(base, fullPath);
|
|
100
|
+
if (entry.isDirectory()) {
|
|
101
|
+
await walkTarget(fullPath, base);
|
|
102
|
+
}
|
|
103
|
+
else if (entry.isFile()) {
|
|
104
|
+
allPaths.add(relPath);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// Directory might not exist
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
await walkTarget(targetRoot, targetRoot);
|
|
113
|
+
// From source (new)
|
|
114
|
+
async function walkSource(dir, base) {
|
|
115
|
+
try {
|
|
116
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
117
|
+
for (const entry of entries) {
|
|
118
|
+
const fullPath = path.join(dir, entry.name);
|
|
119
|
+
const relPath = path.relative(base, fullPath);
|
|
120
|
+
if (entry.isDirectory()) {
|
|
121
|
+
await walkSource(fullPath, base);
|
|
122
|
+
}
|
|
123
|
+
else if (entry.isFile()) {
|
|
124
|
+
allPaths.add(relPath);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
// Directory might not exist
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
await walkSource(sourceRoot, sourceRoot);
|
|
133
|
+
// Compute disposition for each path
|
|
134
|
+
for (const relPath of allPaths) {
|
|
135
|
+
const manifestHash = manifest[relPath];
|
|
136
|
+
// Get current hash
|
|
137
|
+
let currentHash;
|
|
138
|
+
const currentPath = path.join(targetRoot, relPath);
|
|
139
|
+
if (await fs.pathExists(currentPath)) {
|
|
140
|
+
currentHash = await computeFileHash(currentPath);
|
|
141
|
+
}
|
|
142
|
+
// Get source hash
|
|
143
|
+
let sourceHash;
|
|
144
|
+
const sourcePath = path.join(sourceRoot, relPath);
|
|
145
|
+
if (await fs.pathExists(sourcePath)) {
|
|
146
|
+
sourceHash = await computeFileHash(sourcePath);
|
|
147
|
+
}
|
|
148
|
+
const disposition = computeDisposition(relPath, manifestHash, currentHash, sourceHash);
|
|
149
|
+
// Only include files that need action (not 'no-op')
|
|
150
|
+
if (disposition.disposition !== 'update' || disposition.reason !== 'No changes (all identical)') {
|
|
151
|
+
files.push(disposition);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// Sort for consistent output: update, add, preserve, skip, remove
|
|
155
|
+
const order = { update: 0, add: 1, preserve: 2, skip: 3, remove: 4 };
|
|
156
|
+
files.sort((a, b) => order[a.disposition] - order[b.disposition]);
|
|
157
|
+
// Build summary
|
|
158
|
+
const summary = {
|
|
159
|
+
update: files.filter(f => f.disposition === 'update').length,
|
|
160
|
+
preserve: files.filter(f => f.disposition === 'preserve').length,
|
|
161
|
+
skip: files.filter(f => f.disposition === 'skip').length,
|
|
162
|
+
remove: files.filter(f => f.disposition === 'remove').length,
|
|
163
|
+
add: files.filter(f => f.disposition === 'add').length,
|
|
164
|
+
};
|
|
165
|
+
return { files, summary };
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Apply update plan to target directory
|
|
169
|
+
*/
|
|
170
|
+
export async function applyUpdatePlan(plan, targetRoot, sourceRoot, options = {}) {
|
|
171
|
+
const { dryRun = false, onProgress = () => { } } = options;
|
|
172
|
+
for (const file of plan.files) {
|
|
173
|
+
const targetPath = path.join(targetRoot, file.relPath);
|
|
174
|
+
const sourcePath = path.join(sourceRoot, file.relPath);
|
|
175
|
+
switch (file.disposition) {
|
|
176
|
+
case 'update':
|
|
177
|
+
case 'add': {
|
|
178
|
+
onProgress(` ā ${file.relPath} (${file.disposition})`);
|
|
179
|
+
if (!dryRun) {
|
|
180
|
+
await fs.ensureDir(path.dirname(targetPath));
|
|
181
|
+
await fs.copy(sourcePath, targetPath, { overwrite: true });
|
|
182
|
+
}
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
case 'remove': {
|
|
186
|
+
onProgress(` ā ${file.relPath} (remove)`);
|
|
187
|
+
if (!dryRun) {
|
|
188
|
+
await fs.remove(targetPath);
|
|
189
|
+
}
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
case 'preserve': {
|
|
193
|
+
onProgress(` ā ${file.relPath} (preserved - user modified)`);
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
case 'skip': {
|
|
197
|
+
onProgress(` ā ${file.relPath} (skipped - conflict: ${file.reason})`);
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=update-engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-engine.js","sourceRoot":"","sources":["../../src/utils/update-engine.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/aw-spec-specify MedicinalProduct/RegisterMedicinalProduct
|
|
2
|
-
|
|
3
|
-
Allow an authorized user to register a new medicinal product in the registry.
|
|
4
|
-
|
|
5
|
-
On registration the user provides: product name, generic name, NDC, dosage form, strength, route of administration, manufacturer, one or more active ingredients with details, one or more packaging configurations and one or more ATC classification codes.
|
|
6
|
-
|
|
7
|
-
The system validates the submission (required attributes, duplicate NDC, valid dosage form and route of administration) and creates the product in the Draft state. A successful registration is auditable and emits a registration event.
|
|
8
|
-
|
|
9
|
-
Acceptance:
|
|
10
|
-
- A valid submission creates a Draft MedicinalProduct and returns its identifier.
|
|
11
|
-
- A malformed or duplicate NDC is rejected with a clear validation error.
|
|
12
|
-
- A product missing a required attribute, an active ingredient, or a packaging configuration is rejected.
|
|
13
|
-
- The creation is recorded in the audit trail.
|
|
14
|
-
|
|
15
|
-
==============================================================================================
|