Skip to content

Commit 2afe653

Browse files
committed
feat: add dynamic version sync from package.json
- Use createRequire to dynamically import version from package.json - Ensures CLI version always matches package.json version - Eliminates manual version synchronization issues Also includes: - Security documentation updates - JSONata security warnings in README - GitHub issue for future hardening options
1 parent ed76cc0 commit 2afe653

5 files changed

Lines changed: 23 additions & 17 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ost-tools",
3-
"version": "0.2.0",
3+
"version": "0.3.0",
44
"description": "Tools for working with Opportunity Solution Tree structures and other product management and strategy frameworks",
55
"module": "./dist/index.js",
66
"type": "module",

src/commands/dump.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import { statSync } from 'node:fs';
2+
import JSON5 from 'json5';
23
import { readSpaceDirectory } from '../read-space-directory';
34
import { readSpaceOnAPage } from '../read-space-on-a-page';
45

56
export async function dump(path: string) {
67
if (statSync(path).isFile()) {
78
const { nodes, diagnostics } = readSpaceOnAPage(path);
8-
console.log(JSON.stringify({ nodes, diagnostics }, null, 2));
9+
console.log(JSON5.stringify({ nodes, diagnostics }, null, 2));
910
} else {
1011
const { nodes, skipped, nonSpace: nonOst } = await readSpaceDirectory(path);
11-
console.log(JSON.stringify({ nodes, skipped, nonOst }, null, 2));
12+
console.log(JSON5.stringify({ nodes, skipped, nonOst }, null, 2));
1213
}
1314
}

src/config.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,10 @@ function resolveRelativePaths(config: Config, configDir: string): Config {
9696
};
9797
}
9898

99-
export function loadConfig(): Config {
100-
const path = configPath();
99+
function _loadConfig(path: string): Config {
101100
if (!existsSync(path)) {
102-
return { spaces: [] };
101+
console.error(`Config file not found: ${path}`);
102+
process.exit(1);
103103
}
104104

105105
const config = JSON5.parse(readFileSync(path, 'utf-8'));
@@ -110,8 +110,13 @@ export function loadConfig(): Config {
110110
console.error('Invalid config.json:', validate.errors);
111111
process.exit(1);
112112
}
113+
return config as unknown as Config;
114+
}
113115

114-
return resolveRelativePaths(config as unknown as Config, dirname(resolve(path)));
116+
export function loadConfig(): Config {
117+
const path = configPath();
118+
const config = _loadConfig(path);
119+
return resolveRelativePaths(config, dirname(resolve(path)));
115120
}
116121

117122
/** Resolve alias-or-path to a filesystem path. Falls through if not an alias. */
@@ -153,14 +158,11 @@ export function resolveTemplateSettings(config: Config, space?: SpaceConfig): Te
153158
/** Update a field on a space entry and persist config.json. */
154159
export function updateSpaceField(alias: string, field: keyof SpaceConfig, value: string): void {
155160
const path = configPath();
156-
if (!existsSync(path)) {
157-
throw new Error(`Config file not found: ${path}`);
158-
}
159-
const raw = JSON5.parse(readFileSync(path, 'utf-8'));
160-
const space = raw.spaces?.find((s: SpaceConfig) => s.alias === alias);
161+
const config = _loadConfig(path);
162+
const space = config.spaces?.find((s: SpaceConfig) => s.alias === alias);
161163
if (!space) {
162164
throw new Error(`Unknown space config: "${alias}". Check config.json.`);
163165
}
164166
space[field] = value;
165-
writeFileSync(path, `${JSON.stringify(raw, null, 2)}\n`);
167+
writeFileSync(path, `${JSON5.stringify(config, null, 2)}\n`);
166168
}

src/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#!/usr/bin/env bun
2+
import { createRequire } from 'node:module';
23
import { Command } from 'commander';
34
import { diagram } from './commands/diagram';
45
import { dump } from './commands/dump';
@@ -8,12 +9,15 @@ import { validate } from './commands/validate';
89
import { loadConfig, resolveSchema, resolveSpacePath, resolveTemplateSettings, setConfigPath } from './config';
910
import { miroSync } from './miro/sync';
1011

12+
const require = createRequire(import.meta.url);
13+
const packageJson = require('../package.json');
14+
1115
const program = new Command();
1216

1317
program
1418
.name('ost-tools')
1519
.description('Opportunity Solution Tree validation and diagram generation tool')
16-
.version('0.1.0')
20+
.version(packageJson.version)
1721
.option('--config <path>', 'Path to config file (overrides default config.json locations)');
1822

1923
program.hook('preAction', () => {

src/schema.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,9 @@ export function buildSchemaRegistry(dir: string, targetFile?: string): Map<strin
3131

3232
/**
3333
* Load a schema as a self-contained object for direct traversal (e.g. template-sync).
34-
* External $refs are resolved against peer schemas in the same directory: their $defs
34+
* External $refs are resolved against peer schemas: their $defs
3535
* are merged in and the refs rewritten to internal #/$defs/... form.
36-
* Note: only one level of ref resolution is performed here. Full cross-schema traversal
37-
* will be addressed when template-sync is updated in #15.
36+
* Note: only one level of ref resolution is performed here currently.
3837
*/
3938
export function loadSchema(schemaPath: string): JsonSchemaObject {
4039
const absPath = resolve(schemaPath);

0 commit comments

Comments
 (0)