@karmaniverous/jeeves 0.1.0 → 0.1.2

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.
@@ -2,10 +2,11 @@
2
2
  #!/usr/bin/env node
3
3
  import require$$0 from 'commander';
4
4
  import { createRequire } from 'node:module';
5
- import { existsSync, readFileSync, mkdirSync, writeFileSync, renameSync, cpSync, rmSync } from 'node:fs';
6
5
  import { join, dirname } from 'node:path';
7
- import { z } from 'zod';
8
6
  import { fileURLToPath } from 'node:url';
7
+ import { packageDirectorySync } from 'package-directory';
8
+ import { existsSync, readFileSync, mkdirSync, writeFileSync, renameSync, cpSync, rmSync } from 'node:fs';
9
+ import { z } from 'zod';
9
10
  import Handlebars from 'handlebars';
10
11
  import { execSync } from 'node:child_process';
11
12
  import { lock } from 'proper-lockfile';
@@ -203,9 +204,16 @@ const SECTION_ORDER = [
203
204
  * Used for version-stamp convergence (Decision 21). The version stamp
204
205
  * on managed content reflects the actual published library version,
205
206
  * enabling higher-version writers to take precedence.
207
+ *
208
+ * Uses `package-directory` to locate the package root regardless of
209
+ * whether this code runs from `src/constants/` (dev) or `dist/` (bundled).
206
210
  */
211
+ const pkgDir = packageDirectorySync({ cwd: fileURLToPath(import.meta.url) });
212
+ if (!pkgDir) {
213
+ throw new Error('Could not find package root from ' + fileURLToPath(import.meta.url));
214
+ }
207
215
  const require$1 = createRequire(import.meta.url);
208
- const pkg = require$1('../../package.json');
216
+ const pkg = require$1(join(pkgDir, 'package.json'));
209
217
  /** The core library version from package.json. */
210
218
  const CORE_VERSION = pkg.version;
211
219
 
@@ -912,13 +920,22 @@ async function updateManagedSection(filePath, content, options = {}) {
912
920
  /**
913
921
  * Resolve the package's content directory.
914
922
  *
923
+ * @remarks
924
+ * Uses `package-directory` to locate the package root regardless of
925
+ * whether this code runs from `src/platform/` (dev) or `dist/` (bundled).
926
+ * Rollup flattens all source into `dist/index.js`, so static relative
927
+ * paths like `../../content/` break when consumed as a dependency.
928
+ *
915
929
  * @returns Absolute path to the content/ directory.
916
930
  */
917
931
  function getContentDir() {
918
- const thisFile = fileURLToPath(import.meta.url);
919
- // From src/platform/refreshPlatformContent.ts → ../../content/
920
- // From dist/platform/refreshPlatformContent.js → ../../content/
921
- return join(dirname(thisFile), '..', '..', 'content');
932
+ const pkgDir = packageDirectorySync({
933
+ cwd: fileURLToPath(import.meta.url),
934
+ });
935
+ if (!pkgDir) {
936
+ throw new Error('Could not find package root from ' + fileURLToPath(import.meta.url));
937
+ }
938
+ return join(pkgDir, 'content');
922
939
  }
923
940
  /**
924
941
  * Read a content file from the package's content/ directory.
package/dist/index.d.ts CHANGED
@@ -100,6 +100,63 @@ declare class ComponentWriter {
100
100
  cycle(): Promise<void>;
101
101
  }
102
102
 
103
+ /**
104
+ * Creates a synchronous content accessor backed by an async data source.
105
+ *
106
+ * @remarks
107
+ * Solves the sync/async gap in `JeevesComponent.generateToolsContent()`:
108
+ * the interface is synchronous, but most components fetch live data from
109
+ * their HTTP service. This utility returns a sync `() => string` that
110
+ * serves the last successfully fetched value while kicking off a background
111
+ * refresh on each call.
112
+ *
113
+ * First call returns `placeholder`. Subsequent calls return the last
114
+ * successfully fetched content. If a refresh fails, the previous good
115
+ * value is retained.
116
+ *
117
+ * @example
118
+ * ```typescript
119
+ * const getContent = createAsyncContentCache({
120
+ * fetch: async () => {
121
+ * const res = await fetch('http://127.0.0.1:1936/status');
122
+ * return formatWatcherStatus(await res.json());
123
+ * },
124
+ * placeholder: '> Initializing watcher status...',
125
+ * });
126
+ *
127
+ * const writer = createComponentWriter({
128
+ * // ...
129
+ * generateToolsContent: getContent,
130
+ * });
131
+ * ```
132
+ */
133
+ /** Options for {@link createAsyncContentCache}. */
134
+ interface AsyncContentCacheOptions {
135
+ /**
136
+ * Async function that fetches fresh content.
137
+ * Errors are caught and logged; the previous value is retained.
138
+ */
139
+ fetch: () => Promise<string>;
140
+ /**
141
+ * Content returned before the first successful fetch.
142
+ *
143
+ * @defaultValue `'> Initializing...'`
144
+ */
145
+ placeholder?: string;
146
+ /**
147
+ * Optional error handler. Called when `fetch` throws.
148
+ * Defaults to `console.warn`.
149
+ */
150
+ onError?: (error: unknown) => void;
151
+ }
152
+ /**
153
+ * Creates a synchronous content accessor backed by an async data source.
154
+ *
155
+ * @param options - Cache configuration.
156
+ * @returns A sync `() => string` suitable for `generateToolsContent`.
157
+ */
158
+ declare function createAsyncContentCache(options: AsyncContentCacheOptions): () => string;
159
+
103
160
  /**
104
161
  * Factory function for creating a ComponentWriter.
105
162
  *
@@ -250,6 +307,9 @@ declare const SECTION_ORDER: readonly string[];
250
307
  * Used for version-stamp convergence (Decision 21). The version stamp
251
308
  * on managed content reflects the actual published library version,
252
309
  * enabling higher-version writers to take precedence.
310
+ *
311
+ * Uses `package-directory` to locate the package root regardless of
312
+ * whether this code runs from `src/constants/` (dev) or `dist/` (bundled).
253
313
  */
254
314
  /** The core library version from package.json. */
255
315
  declare const CORE_VERSION: string;
@@ -666,5 +726,5 @@ interface SeedContentOptions {
666
726
  */
667
727
  declare function seedContent(options: SeedContentOptions): Promise<void>;
668
728
 
669
- export { AGENTS_MARKERS, CLEANUP_FLAG, COMPONENT_CONFIG_PREFIX, CONFIG_FILE, CORE_CONFIG_DIR, CORE_VERSION, ComponentWriter, DEFAULT_PORTS, META_PORT, REGISTRY_CACHE_FILE, RUNNER_PORT, SECTION_IDS, SECTION_ORDER, SERVER_PORT, SOUL_MARKERS, STALENESS_THRESHOLD_MS, TEMPLATES_DIR, TOOLS_MARKERS, VERSION_STAMP_PATTERN, WATCHER_PORT, WORKSPACE_FILES, checkRegistryVersion, coreConfigSchema, createComponentWriter, formatBeginMarker, formatEndMarker, generateJsonSchema, getComponentConfigDir, getConfigRoot, getCoreConfigDir, getCoreConfigFile, getServiceUrl, getWorkspacePath, init, jaccard, needsCleanup, parseManaged, probeAllServices, probeService, refreshPlatformContent, resetInit, seedContent, shingles, shouldWrite, updateManagedSection };
670
- export type { CoreConfig, CreateComponentWriterOptions, InitOptions, JeevesComponent, ManagedSection, ParseManagedResult, PluginCommands, ProbeResult, RefreshPlatformContentOptions, SectionId, SeedContentOptions, ServiceCommands, ServiceStatus, UpdateManagedSectionOptions, VersionStamp };
729
+ export { AGENTS_MARKERS, CLEANUP_FLAG, COMPONENT_CONFIG_PREFIX, CONFIG_FILE, CORE_CONFIG_DIR, CORE_VERSION, ComponentWriter, DEFAULT_PORTS, META_PORT, REGISTRY_CACHE_FILE, RUNNER_PORT, SECTION_IDS, SECTION_ORDER, SERVER_PORT, SOUL_MARKERS, STALENESS_THRESHOLD_MS, TEMPLATES_DIR, TOOLS_MARKERS, VERSION_STAMP_PATTERN, WATCHER_PORT, WORKSPACE_FILES, checkRegistryVersion, coreConfigSchema, createAsyncContentCache, createComponentWriter, formatBeginMarker, formatEndMarker, generateJsonSchema, getComponentConfigDir, getConfigRoot, getCoreConfigDir, getCoreConfigFile, getServiceUrl, getWorkspacePath, init, jaccard, needsCleanup, parseManaged, probeAllServices, probeService, refreshPlatformContent, resetInit, seedContent, shingles, shouldWrite, updateManagedSection };
730
+ export type { AsyncContentCacheOptions, CoreConfig, CreateComponentWriterOptions, InitOptions, JeevesComponent, ManagedSection, ParseManagedResult, PluginCommands, ProbeResult, RefreshPlatformContentOptions, SectionId, SeedContentOptions, ServiceCommands, ServiceStatus, UpdateManagedSectionOptions, VersionStamp };
package/dist/index.js CHANGED
@@ -1,9 +1,10 @@
1
1
  import { join, dirname } from 'node:path';
2
2
  import { createRequire } from 'node:module';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { packageDirectorySync } from 'package-directory';
3
5
  import { existsSync, mkdirSync, writeFileSync, readFileSync, renameSync, cpSync } from 'node:fs';
4
6
  import { lock } from 'proper-lockfile';
5
7
  import { gte } from 'semver';
6
- import { fileURLToPath } from 'node:url';
7
8
  import Handlebars from 'handlebars';
8
9
  import { z } from 'zod';
9
10
  import { execSync } from 'node:child_process';
@@ -141,9 +142,16 @@ const SECTION_ORDER = [
141
142
  * Used for version-stamp convergence (Decision 21). The version stamp
142
143
  * on managed content reflects the actual published library version,
143
144
  * enabling higher-version writers to take precedence.
145
+ *
146
+ * Uses `package-directory` to locate the package root regardless of
147
+ * whether this code runs from `src/constants/` (dev) or `dist/` (bundled).
144
148
  */
149
+ const pkgDir = packageDirectorySync({ cwd: fileURLToPath(import.meta.url) });
150
+ if (!pkgDir) {
151
+ throw new Error('Could not find package root from ' + fileURLToPath(import.meta.url));
152
+ }
145
153
  const require$1 = createRequire(import.meta.url);
146
- const pkg = require$1('../../package.json');
154
+ const pkg = require$1(join(pkgDir, 'package.json'));
147
155
  /** The core library version from package.json. */
148
156
  const CORE_VERSION = pkg.version;
149
157
 
@@ -884,13 +892,22 @@ function checkRegistryVersion(packageName, cacheDir, ttlSeconds = 3600) {
884
892
  /**
885
893
  * Resolve the package's content directory.
886
894
  *
895
+ * @remarks
896
+ * Uses `package-directory` to locate the package root regardless of
897
+ * whether this code runs from `src/platform/` (dev) or `dist/` (bundled).
898
+ * Rollup flattens all source into `dist/index.js`, so static relative
899
+ * paths like `../../content/` break when consumed as a dependency.
900
+ *
887
901
  * @returns Absolute path to the content/ directory.
888
902
  */
889
903
  function getContentDir() {
890
- const thisFile = fileURLToPath(import.meta.url);
891
- // From src/platform/refreshPlatformContent.ts → ../../content/
892
- // From dist/platform/refreshPlatformContent.js → ../../content/
893
- return join(dirname(thisFile), '..', '..', 'content');
904
+ const pkgDir = packageDirectorySync({
905
+ cwd: fileURLToPath(import.meta.url),
906
+ });
907
+ if (!pkgDir) {
908
+ throw new Error('Could not find package root from ' + fileURLToPath(import.meta.url));
909
+ }
910
+ return join(pkgDir, 'content');
894
911
  }
895
912
  /**
896
913
  * Read a content file from the package's content/ directory.
@@ -1098,6 +1115,64 @@ class ComponentWriter {
1098
1115
  }
1099
1116
  }
1100
1117
 
1118
+ /**
1119
+ * Creates a synchronous content accessor backed by an async data source.
1120
+ *
1121
+ * @remarks
1122
+ * Solves the sync/async gap in `JeevesComponent.generateToolsContent()`:
1123
+ * the interface is synchronous, but most components fetch live data from
1124
+ * their HTTP service. This utility returns a sync `() => string` that
1125
+ * serves the last successfully fetched value while kicking off a background
1126
+ * refresh on each call.
1127
+ *
1128
+ * First call returns `placeholder`. Subsequent calls return the last
1129
+ * successfully fetched content. If a refresh fails, the previous good
1130
+ * value is retained.
1131
+ *
1132
+ * @example
1133
+ * ```typescript
1134
+ * const getContent = createAsyncContentCache({
1135
+ * fetch: async () => {
1136
+ * const res = await fetch('http://127.0.0.1:1936/status');
1137
+ * return formatWatcherStatus(await res.json());
1138
+ * },
1139
+ * placeholder: '> Initializing watcher status...',
1140
+ * });
1141
+ *
1142
+ * const writer = createComponentWriter({
1143
+ * // ...
1144
+ * generateToolsContent: getContent,
1145
+ * });
1146
+ * ```
1147
+ */
1148
+ /**
1149
+ * Creates a synchronous content accessor backed by an async data source.
1150
+ *
1151
+ * @param options - Cache configuration.
1152
+ * @returns A sync `() => string` suitable for `generateToolsContent`.
1153
+ */
1154
+ function createAsyncContentCache(options) {
1155
+ const { fetch: fetchContent, placeholder = '> Initializing...', onError = (err) => {
1156
+ console.warn('[jeeves] async content cache refresh failed:', err);
1157
+ }, } = options;
1158
+ let cached = placeholder;
1159
+ let refreshing = false;
1160
+ return () => {
1161
+ if (!refreshing) {
1162
+ refreshing = true;
1163
+ fetchContent()
1164
+ .then((content) => {
1165
+ cached = content;
1166
+ })
1167
+ .catch(onError)
1168
+ .finally(() => {
1169
+ refreshing = false;
1170
+ });
1171
+ }
1172
+ return cached;
1173
+ };
1174
+ }
1175
+
1101
1176
  /**
1102
1177
  * Factory function for creating a ComponentWriter.
1103
1178
  *
@@ -1229,4 +1304,4 @@ async function seedContent(options) {
1229
1304
  });
1230
1305
  }
1231
1306
 
1232
- export { AGENTS_MARKERS, CLEANUP_FLAG, COMPONENT_CONFIG_PREFIX, CONFIG_FILE, CORE_CONFIG_DIR, CORE_VERSION, ComponentWriter, DEFAULT_PORTS, META_PORT, REGISTRY_CACHE_FILE, RUNNER_PORT, SECTION_IDS, SECTION_ORDER, SERVER_PORT, SOUL_MARKERS, STALENESS_THRESHOLD_MS, TEMPLATES_DIR, TOOLS_MARKERS, VERSION_STAMP_PATTERN, WATCHER_PORT, WORKSPACE_FILES, checkRegistryVersion, coreConfigSchema, createComponentWriter, formatBeginMarker, formatEndMarker, generateJsonSchema, getComponentConfigDir, getConfigRoot, getCoreConfigDir, getCoreConfigFile, getServiceUrl, getWorkspacePath, init, jaccard, needsCleanup, parseManaged, probeAllServices, probeService, refreshPlatformContent, resetInit, seedContent, shingles, shouldWrite, updateManagedSection };
1307
+ export { AGENTS_MARKERS, CLEANUP_FLAG, COMPONENT_CONFIG_PREFIX, CONFIG_FILE, CORE_CONFIG_DIR, CORE_VERSION, ComponentWriter, DEFAULT_PORTS, META_PORT, REGISTRY_CACHE_FILE, RUNNER_PORT, SECTION_IDS, SECTION_ORDER, SERVER_PORT, SOUL_MARKERS, STALENESS_THRESHOLD_MS, TEMPLATES_DIR, TOOLS_MARKERS, VERSION_STAMP_PATTERN, WATCHER_PORT, WORKSPACE_FILES, checkRegistryVersion, coreConfigSchema, createAsyncContentCache, createComponentWriter, formatBeginMarker, formatEndMarker, generateJsonSchema, getComponentConfigDir, getConfigRoot, getCoreConfigDir, getCoreConfigFile, getServiceUrl, getWorkspacePath, init, jaccard, needsCleanup, parseManaged, probeAllServices, probeService, refreshPlatformContent, resetInit, seedContent, shingles, shouldWrite, updateManagedSection };
package/package.json CHANGED
@@ -15,6 +15,7 @@
15
15
  "dependencies": {
16
16
  "commander": "^14.0.2",
17
17
  "handlebars": "^4.7.8",
18
+ "package-directory": "^8.2.0",
18
19
  "proper-lockfile": "^4.1.2",
19
20
  "semver": "^7.7.2",
20
21
  "zod": "^3.25.67"
@@ -137,5 +138,5 @@
137
138
  },
138
139
  "type": "module",
139
140
  "types": "dist/index.d.ts",
140
- "version": "0.1.0"
141
+ "version": "0.1.2"
141
142
  }