kiro-spec-engine 1.27.0 → 1.29.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/CHANGELOG.md +33 -0
- package/lib/commands/scene.js +401 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,39 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.29.0] - 2026-02-10
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **Scene Registry Query**: List and search scene packages in local registry
|
|
14
|
+
- `kse scene list` list all packages in registry
|
|
15
|
+
- `--registry <dir>` custom registry directory
|
|
16
|
+
- `--json` structured JSON output
|
|
17
|
+
- `kse scene search --query <term>` search packages by keyword
|
|
18
|
+
- Case-insensitive substring matching on name, description, and group
|
|
19
|
+
- `--registry <dir>` custom registry directory
|
|
20
|
+
- `--json` structured JSON output
|
|
21
|
+
- Shared helpers: `buildRegistryPackageList`, `filterRegistryPackages`
|
|
22
|
+
- Follows normalize → validate → run → print pattern
|
|
23
|
+
- Implements Spec 79-00-scene-registry-query
|
|
24
|
+
|
|
25
|
+
## [1.28.0] - 2026-02-10
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
- **Scene Package Install**: Install published scene packages from local registry
|
|
29
|
+
- `kse scene install --name <packageName>` install scene package from registry
|
|
30
|
+
- `--version <version>` exact version or omit for latest
|
|
31
|
+
- `--out <dir>` custom target directory (default: `./{packageName}`)
|
|
32
|
+
- `--registry <dir>` custom registry directory
|
|
33
|
+
- `--force` overwrite existing installation
|
|
34
|
+
- `--dry-run` preview without writing files
|
|
35
|
+
- `--json` structured JSON output
|
|
36
|
+
- SHA-256 integrity verification before extraction
|
|
37
|
+
- Tarball decompression and file extraction preserving relative paths
|
|
38
|
+
- Install manifest (`scene-install-manifest.json`) with package metadata, timestamp, file list
|
|
39
|
+
- Automatic latest version resolution from registry index
|
|
40
|
+
- Completes publish → install lifecycle for scene packages
|
|
41
|
+
- Implements Spec 78-00-scene-package-install
|
|
42
|
+
|
|
10
43
|
## [1.27.0] - 2026-02-10
|
|
11
44
|
|
|
12
45
|
### Added
|
package/lib/commands/scene.js
CHANGED
|
@@ -503,6 +503,39 @@ function registerSceneCommands(program) {
|
|
|
503
503
|
.action(async (options) => {
|
|
504
504
|
await runSceneUnpublishCommand(options);
|
|
505
505
|
});
|
|
506
|
+
|
|
507
|
+
sceneCmd
|
|
508
|
+
.command('install')
|
|
509
|
+
.description('Install scene package from local registry')
|
|
510
|
+
.requiredOption('-n, --name <name>', 'Package name to install')
|
|
511
|
+
.option('-v, --version <version>', 'Package version (default: latest)')
|
|
512
|
+
.option('-o, --out <dir>', 'Target output directory')
|
|
513
|
+
.option('-r, --registry <path>', 'Registry root directory', '.kiro/registry')
|
|
514
|
+
.option('--force', 'Overwrite existing installation')
|
|
515
|
+
.option('--dry-run', 'Preview install without writing files')
|
|
516
|
+
.option('--json', 'Print install payload as JSON')
|
|
517
|
+
.action(async (options) => {
|
|
518
|
+
await runSceneInstallCommand(options);
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
sceneCmd
|
|
522
|
+
.command('list')
|
|
523
|
+
.description('List all packages in the local scene registry')
|
|
524
|
+
.option('-r, --registry <path>', 'Registry root directory', '.kiro/registry')
|
|
525
|
+
.option('--json', 'Print result as JSON')
|
|
526
|
+
.action(async (options) => {
|
|
527
|
+
await runSceneListCommand(options);
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
sceneCmd
|
|
531
|
+
.command('search')
|
|
532
|
+
.description('Search packages in the local scene registry')
|
|
533
|
+
.requiredOption('-q, --query <term>', 'Search term (substring match on name, description, group)')
|
|
534
|
+
.option('-r, --registry <path>', 'Registry root directory', '.kiro/registry')
|
|
535
|
+
.option('--json', 'Print result as JSON')
|
|
536
|
+
.action(async (options) => {
|
|
537
|
+
await runSceneSearchCommand(options);
|
|
538
|
+
});
|
|
506
539
|
}
|
|
507
540
|
|
|
508
541
|
function normalizeSourceOptions(options = {}) {
|
|
@@ -9847,6 +9880,358 @@ function validateSceneUnpublishOptions(options) {
|
|
|
9847
9880
|
return null;
|
|
9848
9881
|
}
|
|
9849
9882
|
|
|
9883
|
+
function normalizeSceneInstallOptions(options = {}) {
|
|
9884
|
+
return {
|
|
9885
|
+
name: options.name ? String(options.name).trim() : undefined,
|
|
9886
|
+
version: options.version ? String(options.version).trim() : undefined,
|
|
9887
|
+
out: options.out ? String(options.out).trim() : undefined,
|
|
9888
|
+
registry: options.registry ? String(options.registry).trim() : '.kiro/registry',
|
|
9889
|
+
force: options.force === true,
|
|
9890
|
+
dryRun: options.dryRun === true,
|
|
9891
|
+
json: options.json === true
|
|
9892
|
+
};
|
|
9893
|
+
}
|
|
9894
|
+
|
|
9895
|
+
function validateSceneInstallOptions(options) {
|
|
9896
|
+
if (!options.name || typeof options.name !== 'string') {
|
|
9897
|
+
return '--name is required';
|
|
9898
|
+
}
|
|
9899
|
+
if (options.version && options.version !== 'latest' && !semver.valid(options.version)) {
|
|
9900
|
+
return `--version "${options.version}" is not valid semver`;
|
|
9901
|
+
}
|
|
9902
|
+
return null;
|
|
9903
|
+
}
|
|
9904
|
+
|
|
9905
|
+
function buildInstallManifest(packageName, version, registryDir, integrity, files) {
|
|
9906
|
+
return {
|
|
9907
|
+
packageName,
|
|
9908
|
+
version,
|
|
9909
|
+
installedAt: new Date().toISOString(),
|
|
9910
|
+
registryDir,
|
|
9911
|
+
integrity,
|
|
9912
|
+
files
|
|
9913
|
+
};
|
|
9914
|
+
}
|
|
9915
|
+
|
|
9916
|
+
function printSceneInstallSummary(options, payload, projectRoot = process.cwd()) {
|
|
9917
|
+
if (options.json) {
|
|
9918
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
9919
|
+
return;
|
|
9920
|
+
}
|
|
9921
|
+
|
|
9922
|
+
const dryRunLabel = payload.dry_run ? chalk.yellow(' [dry-run]') : '';
|
|
9923
|
+
console.log(chalk.blue('Scene Package Install') + dryRunLabel);
|
|
9924
|
+
console.log(` Package: ${payload.coordinate}`);
|
|
9925
|
+
console.log(` Target: ${chalk.gray(payload.target_dir)}`);
|
|
9926
|
+
console.log(` Files: ${payload.file_count}`);
|
|
9927
|
+
console.log(` Integrity: ${payload.integrity}`);
|
|
9928
|
+
if (payload.overwritten) {
|
|
9929
|
+
console.log(` Overwritten: ${chalk.yellow('yes')}`);
|
|
9930
|
+
}
|
|
9931
|
+
}
|
|
9932
|
+
|
|
9933
|
+
async function runSceneInstallCommand(rawOptions = {}, dependencies = {}) {
|
|
9934
|
+
const projectRoot = dependencies.projectRoot || process.cwd();
|
|
9935
|
+
const fileSystem = dependencies.fileSystem || fs;
|
|
9936
|
+
|
|
9937
|
+
const options = normalizeSceneInstallOptions(rawOptions);
|
|
9938
|
+
const validationError = validateSceneInstallOptions(options);
|
|
9939
|
+
|
|
9940
|
+
if (validationError) {
|
|
9941
|
+
console.error(chalk.red(`Scene package install failed: ${validationError}`));
|
|
9942
|
+
process.exitCode = 1;
|
|
9943
|
+
return null;
|
|
9944
|
+
}
|
|
9945
|
+
|
|
9946
|
+
const readFile = typeof fileSystem.readFile === 'function'
|
|
9947
|
+
? fileSystem.readFile.bind(fileSystem)
|
|
9948
|
+
: fs.readFile.bind(fs);
|
|
9949
|
+
|
|
9950
|
+
try {
|
|
9951
|
+
// 1. Resolve registry root
|
|
9952
|
+
const registryRoot = path.isAbsolute(options.registry)
|
|
9953
|
+
? options.registry
|
|
9954
|
+
: path.join(projectRoot, options.registry);
|
|
9955
|
+
|
|
9956
|
+
// 2. Load registry index
|
|
9957
|
+
const index = await loadRegistryIndex(registryRoot, fileSystem);
|
|
9958
|
+
|
|
9959
|
+
// 3. Resolve package in index
|
|
9960
|
+
if (!index.packages || !index.packages[options.name]) {
|
|
9961
|
+
throw new Error(`package "${options.name}" not found in registry`);
|
|
9962
|
+
}
|
|
9963
|
+
const pkg = index.packages[options.name];
|
|
9964
|
+
|
|
9965
|
+
// 4. Resolve version (default to latest)
|
|
9966
|
+
const version = (!options.version || options.version === 'latest')
|
|
9967
|
+
? pkg.latest
|
|
9968
|
+
: options.version;
|
|
9969
|
+
|
|
9970
|
+
if (!version) {
|
|
9971
|
+
throw new Error(`no latest version found for package "${options.name}"`);
|
|
9972
|
+
}
|
|
9973
|
+
|
|
9974
|
+
if (!pkg.versions || !pkg.versions[version]) {
|
|
9975
|
+
throw new Error(`version "${version}" not found for package "${options.name}"`);
|
|
9976
|
+
}
|
|
9977
|
+
const versionEntry = pkg.versions[version];
|
|
9978
|
+
|
|
9979
|
+
// 5. Read tarball from disk
|
|
9980
|
+
const tarballRelativePath = buildRegistryTarballPath(options.name, version);
|
|
9981
|
+
const tarballAbsolutePath = path.join(registryRoot, tarballRelativePath);
|
|
9982
|
+
const tarballBuffer = await readFile(tarballAbsolutePath);
|
|
9983
|
+
|
|
9984
|
+
// 6. Verify integrity
|
|
9985
|
+
const computedHash = 'sha256-' + crypto.createHash('sha256').update(tarballBuffer).digest('hex');
|
|
9986
|
+
if (computedHash !== versionEntry.integrity) {
|
|
9987
|
+
throw new Error(`integrity verification failed: expected ${versionEntry.integrity}, got ${computedHash}`);
|
|
9988
|
+
}
|
|
9989
|
+
|
|
9990
|
+
// 7. Resolve target directory
|
|
9991
|
+
const targetDir = options.out
|
|
9992
|
+
? (path.isAbsolute(options.out) ? options.out : path.join(projectRoot, options.out))
|
|
9993
|
+
: path.join(projectRoot, options.name);
|
|
9994
|
+
|
|
9995
|
+
// 8. Decompress and extract tarball
|
|
9996
|
+
const decompressed = zlib.gunzipSync(tarballBuffer);
|
|
9997
|
+
const files = extractTarBuffer(decompressed);
|
|
9998
|
+
const fileNames = files.map(f => f.relativePath);
|
|
9999
|
+
|
|
10000
|
+
// 9. Build coordinate
|
|
10001
|
+
const coordinate = `kse.scene/${options.name}@${version}`;
|
|
10002
|
+
|
|
10003
|
+
// 10. Dry-run: build payload without writing, print, return
|
|
10004
|
+
if (options.dryRun) {
|
|
10005
|
+
const payload = {
|
|
10006
|
+
installed: false,
|
|
10007
|
+
dry_run: true,
|
|
10008
|
+
overwritten: false,
|
|
10009
|
+
coordinate,
|
|
10010
|
+
package: {
|
|
10011
|
+
name: options.name,
|
|
10012
|
+
version
|
|
10013
|
+
},
|
|
10014
|
+
target_dir: formatScenePackagePath(projectRoot, targetDir),
|
|
10015
|
+
file_count: fileNames.length,
|
|
10016
|
+
files: fileNames,
|
|
10017
|
+
integrity: computedHash,
|
|
10018
|
+
registry: {
|
|
10019
|
+
index_path: formatScenePackagePath(projectRoot, path.join(registryRoot, 'registry-index.json'))
|
|
10020
|
+
}
|
|
10021
|
+
};
|
|
10022
|
+
|
|
10023
|
+
printSceneInstallSummary(options, payload, projectRoot);
|
|
10024
|
+
return payload;
|
|
10025
|
+
}
|
|
10026
|
+
|
|
10027
|
+
// 11. Check target dir conflict (unless --force)
|
|
10028
|
+
const ensureDirSync = typeof fileSystem.ensureDirSync === 'function'
|
|
10029
|
+
? fileSystem.ensureDirSync.bind(fileSystem)
|
|
10030
|
+
: fs.ensureDirSync.bind(fs);
|
|
10031
|
+
const writeFileSync = typeof fileSystem.writeFileSync === 'function'
|
|
10032
|
+
? fileSystem.writeFileSync.bind(fileSystem)
|
|
10033
|
+
: fs.writeFileSync.bind(fs);
|
|
10034
|
+
const pathExistsSync = typeof fileSystem.pathExistsSync === 'function'
|
|
10035
|
+
? fileSystem.pathExistsSync.bind(fileSystem)
|
|
10036
|
+
: fs.pathExistsSync.bind(fs);
|
|
10037
|
+
|
|
10038
|
+
const targetExists = pathExistsSync(targetDir);
|
|
10039
|
+
if (targetExists && !options.force) {
|
|
10040
|
+
throw new Error(`target directory already exists: ${formatScenePackagePath(projectRoot, targetDir)} (use --force to overwrite)`);
|
|
10041
|
+
}
|
|
10042
|
+
|
|
10043
|
+
// 12. Write extracted files preserving relative paths
|
|
10044
|
+
ensureDirSync(targetDir);
|
|
10045
|
+
for (const file of files) {
|
|
10046
|
+
const filePath = path.join(targetDir, file.relativePath);
|
|
10047
|
+
ensureDirSync(path.dirname(filePath));
|
|
10048
|
+
writeFileSync(filePath, file.content);
|
|
10049
|
+
}
|
|
10050
|
+
|
|
10051
|
+
// 13. Write install manifest
|
|
10052
|
+
const manifest = buildInstallManifest(options.name, version, options.registry, computedHash, fileNames);
|
|
10053
|
+
const manifestPath = path.join(targetDir, 'scene-install-manifest.json');
|
|
10054
|
+
writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
|
|
10055
|
+
|
|
10056
|
+
// 14. Build payload
|
|
10057
|
+
const payload = {
|
|
10058
|
+
installed: true,
|
|
10059
|
+
dry_run: false,
|
|
10060
|
+
overwritten: targetExists && options.force,
|
|
10061
|
+
coordinate,
|
|
10062
|
+
package: {
|
|
10063
|
+
name: options.name,
|
|
10064
|
+
version
|
|
10065
|
+
},
|
|
10066
|
+
target_dir: formatScenePackagePath(projectRoot, targetDir),
|
|
10067
|
+
file_count: fileNames.length,
|
|
10068
|
+
files: fileNames,
|
|
10069
|
+
integrity: computedHash,
|
|
10070
|
+
registry: {
|
|
10071
|
+
index_path: formatScenePackagePath(projectRoot, path.join(registryRoot, 'registry-index.json'))
|
|
10072
|
+
}
|
|
10073
|
+
};
|
|
10074
|
+
|
|
10075
|
+
printSceneInstallSummary(options, payload, projectRoot);
|
|
10076
|
+
return payload;
|
|
10077
|
+
} catch (error) {
|
|
10078
|
+
console.error(chalk.red('Scene package install failed:'), error.message);
|
|
10079
|
+
process.exitCode = 1;
|
|
10080
|
+
return null;
|
|
10081
|
+
}
|
|
10082
|
+
}
|
|
10083
|
+
|
|
10084
|
+
// --- Scene Registry Query Helpers ---
|
|
10085
|
+
|
|
10086
|
+
function buildRegistryPackageList(registryPackages) {
|
|
10087
|
+
return Object.values(registryPackages || {})
|
|
10088
|
+
.map(pkg => ({
|
|
10089
|
+
name: pkg.name || '',
|
|
10090
|
+
group: pkg.group || '',
|
|
10091
|
+
description: pkg.description || '',
|
|
10092
|
+
latest: pkg.latest || '',
|
|
10093
|
+
version_count: Object.keys(pkg.versions || {}).length
|
|
10094
|
+
}))
|
|
10095
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
10096
|
+
}
|
|
10097
|
+
|
|
10098
|
+
function filterRegistryPackages(packageList, query) {
|
|
10099
|
+
if (!query) return packageList;
|
|
10100
|
+
const lowerQuery = query.toLowerCase();
|
|
10101
|
+
return packageList.filter(pkg =>
|
|
10102
|
+
pkg.name.toLowerCase().includes(lowerQuery) ||
|
|
10103
|
+
pkg.description.toLowerCase().includes(lowerQuery) ||
|
|
10104
|
+
pkg.group.toLowerCase().includes(lowerQuery)
|
|
10105
|
+
);
|
|
10106
|
+
}
|
|
10107
|
+
|
|
10108
|
+
// --- Scene List Command ---
|
|
10109
|
+
|
|
10110
|
+
function normalizeSceneListOptions(options = {}) {
|
|
10111
|
+
return {
|
|
10112
|
+
registry: options.registry ? String(options.registry).trim() : '.kiro/registry',
|
|
10113
|
+
json: options.json === true
|
|
10114
|
+
};
|
|
10115
|
+
}
|
|
10116
|
+
|
|
10117
|
+
function validateSceneListOptions(options) {
|
|
10118
|
+
return null;
|
|
10119
|
+
}
|
|
10120
|
+
|
|
10121
|
+
async function runSceneListCommand(rawOptions = {}, dependencies = {}) {
|
|
10122
|
+
const projectRoot = dependencies.projectRoot || process.cwd();
|
|
10123
|
+
const fileSystem = dependencies.fileSystem || fs;
|
|
10124
|
+
|
|
10125
|
+
const options = normalizeSceneListOptions(rawOptions);
|
|
10126
|
+
const validationError = validateSceneListOptions(options);
|
|
10127
|
+
|
|
10128
|
+
if (validationError) {
|
|
10129
|
+
console.error(chalk.red(`Scene list failed: ${validationError}`));
|
|
10130
|
+
process.exitCode = 1;
|
|
10131
|
+
return null;
|
|
10132
|
+
}
|
|
10133
|
+
|
|
10134
|
+
try {
|
|
10135
|
+
const registryRoot = path.isAbsolute(options.registry)
|
|
10136
|
+
? options.registry
|
|
10137
|
+
: path.join(projectRoot, options.registry);
|
|
10138
|
+
|
|
10139
|
+
const index = await loadRegistryIndex(registryRoot, fileSystem);
|
|
10140
|
+
const packages = buildRegistryPackageList(index.packages);
|
|
10141
|
+
const payload = { packages, total: packages.length };
|
|
10142
|
+
|
|
10143
|
+
printSceneListSummary(options, payload, projectRoot);
|
|
10144
|
+
return payload;
|
|
10145
|
+
} catch (error) {
|
|
10146
|
+
console.error(chalk.red('Scene list failed:'), error.message);
|
|
10147
|
+
process.exitCode = 1;
|
|
10148
|
+
return null;
|
|
10149
|
+
}
|
|
10150
|
+
}
|
|
10151
|
+
|
|
10152
|
+
function printSceneListSummary(options, payload, projectRoot = process.cwd()) {
|
|
10153
|
+
if (options.json) {
|
|
10154
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
10155
|
+
return;
|
|
10156
|
+
}
|
|
10157
|
+
|
|
10158
|
+
if (payload.total === 0) {
|
|
10159
|
+
console.log('No packages found');
|
|
10160
|
+
return;
|
|
10161
|
+
}
|
|
10162
|
+
|
|
10163
|
+
console.log(chalk.blue(`Scene Registry (${payload.total} package${payload.total !== 1 ? 's' : ''})`));
|
|
10164
|
+
for (const pkg of payload.packages) {
|
|
10165
|
+
console.log(` ${pkg.name.padEnd(20)} ${pkg.latest.padEnd(10)} ${String(pkg.version_count).padEnd(10)} ${pkg.description}`);
|
|
10166
|
+
}
|
|
10167
|
+
}
|
|
10168
|
+
|
|
10169
|
+
function normalizeSceneSearchOptions(options = {}) {
|
|
10170
|
+
return {
|
|
10171
|
+
query: options.query ? String(options.query).trim() : '',
|
|
10172
|
+
registry: options.registry ? String(options.registry).trim() : '.kiro/registry',
|
|
10173
|
+
json: options.json === true
|
|
10174
|
+
};
|
|
10175
|
+
}
|
|
10176
|
+
|
|
10177
|
+
function validateSceneSearchOptions(options) {
|
|
10178
|
+
return null; // Empty query is valid (returns all)
|
|
10179
|
+
}
|
|
10180
|
+
|
|
10181
|
+
async function runSceneSearchCommand(rawOptions = {}, dependencies = {}) {
|
|
10182
|
+
const projectRoot = dependencies.projectRoot || process.cwd();
|
|
10183
|
+
const fileSystem = dependencies.fileSystem || fs;
|
|
10184
|
+
|
|
10185
|
+
const options = normalizeSceneSearchOptions(rawOptions);
|
|
10186
|
+
const validationError = validateSceneSearchOptions(options);
|
|
10187
|
+
|
|
10188
|
+
if (validationError) {
|
|
10189
|
+
console.error(chalk.red(`Scene search failed: ${validationError}`));
|
|
10190
|
+
process.exitCode = 1;
|
|
10191
|
+
return null;
|
|
10192
|
+
}
|
|
10193
|
+
|
|
10194
|
+
try {
|
|
10195
|
+
const registryRoot = path.isAbsolute(options.registry)
|
|
10196
|
+
? options.registry
|
|
10197
|
+
: path.join(projectRoot, options.registry);
|
|
10198
|
+
|
|
10199
|
+
const index = await loadRegistryIndex(registryRoot, fileSystem);
|
|
10200
|
+
const allPackages = buildRegistryPackageList(index.packages);
|
|
10201
|
+
const packages = filterRegistryPackages(allPackages, options.query);
|
|
10202
|
+
const payload = { query: options.query, packages, total: packages.length };
|
|
10203
|
+
|
|
10204
|
+
printSceneSearchSummary(options, payload, projectRoot);
|
|
10205
|
+
return payload;
|
|
10206
|
+
} catch (error) {
|
|
10207
|
+
console.error(chalk.red('Scene search failed:'), error.message);
|
|
10208
|
+
process.exitCode = 1;
|
|
10209
|
+
return null;
|
|
10210
|
+
}
|
|
10211
|
+
}
|
|
10212
|
+
|
|
10213
|
+
function printSceneSearchSummary(options, payload, projectRoot = process.cwd()) {
|
|
10214
|
+
if (options.json) {
|
|
10215
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
10216
|
+
return;
|
|
10217
|
+
}
|
|
10218
|
+
|
|
10219
|
+
if (payload.total === 0) {
|
|
10220
|
+
if (payload.query) {
|
|
10221
|
+
console.log(`No packages matching '${payload.query}'`);
|
|
10222
|
+
} else {
|
|
10223
|
+
console.log('No packages found');
|
|
10224
|
+
}
|
|
10225
|
+
return;
|
|
10226
|
+
}
|
|
10227
|
+
|
|
10228
|
+
const matchLabel = payload.total === 1 ? 'match' : 'matches';
|
|
10229
|
+
console.log(chalk.blue(`Scene Search: "${payload.query}" (${payload.total} ${matchLabel})`));
|
|
10230
|
+
for (const pkg of payload.packages) {
|
|
10231
|
+
console.log(` ${pkg.name.padEnd(20)} ${pkg.latest.padEnd(10)} ${String(pkg.version_count).padEnd(10)} ${pkg.description}`);
|
|
10232
|
+
}
|
|
10233
|
+
}
|
|
10234
|
+
|
|
9850
10235
|
function printSceneUnpublishSummary(options, payload, projectRoot = process.cwd()) {
|
|
9851
10236
|
if (options.json) {
|
|
9852
10237
|
console.log(JSON.stringify(payload, null, 2));
|
|
@@ -10070,5 +10455,20 @@ module.exports = {
|
|
|
10070
10455
|
normalizeSceneUnpublishOptions,
|
|
10071
10456
|
validateSceneUnpublishOptions,
|
|
10072
10457
|
printSceneUnpublishSummary,
|
|
10073
|
-
runSceneUnpublishCommand
|
|
10458
|
+
runSceneUnpublishCommand,
|
|
10459
|
+
buildInstallManifest,
|
|
10460
|
+
normalizeSceneInstallOptions,
|
|
10461
|
+
printSceneInstallSummary,
|
|
10462
|
+
runSceneInstallCommand,
|
|
10463
|
+
validateSceneInstallOptions,
|
|
10464
|
+
buildRegistryPackageList,
|
|
10465
|
+
filterRegistryPackages,
|
|
10466
|
+
normalizeSceneListOptions,
|
|
10467
|
+
validateSceneListOptions,
|
|
10468
|
+
runSceneListCommand,
|
|
10469
|
+
printSceneListSummary,
|
|
10470
|
+
normalizeSceneSearchOptions,
|
|
10471
|
+
validateSceneSearchOptions,
|
|
10472
|
+
runSceneSearchCommand,
|
|
10473
|
+
printSceneSearchSummary
|
|
10074
10474
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kiro-spec-engine",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.29.0",
|
|
4
4
|
"description": "kiro-spec-engine (kse) - A CLI tool and npm package for spec-driven development with AI coding assistants. NOT the Kiro IDE desktop application.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|