@opengsd/gsd-core 1.4.4 → 1.4.5

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "gsd-core",
3
3
  "displayName": "GSD Core",
4
- "version": "1.4.4",
4
+ "version": "1.4.5",
5
5
  "description": "GSD Core is a meta-prompting, context engineering, and spec-driven development system for AI coding agents.",
6
6
  "author": {
7
7
  "name": "open-gsd",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gsd-core",
3
- "version": "1.4.4",
3
+ "version": "1.4.5",
4
4
  "description": "GSD Core — a meta-prompting, context engineering, and spec-driven development system for AI coding agents. Loads gsd's operating context into every Gemini CLI session.",
5
5
  "contextFileName": "GEMINI.md"
6
6
  }
@@ -1283,6 +1283,7 @@ function _warnUnknownProfileOverrides(parsed, configLabel) {
1283
1283
  // between cases that intentionally exercise the warning path repeatedly.
1284
1284
  function _resetRuntimeWarningCacheForTests() {
1285
1285
  _warnedConfigKeys.clear();
1286
+ _modelPolicyUnmappableWarned.clear();
1286
1287
  }
1287
1288
  /**
1288
1289
  * #2517 — Resolve the runtime-aware tier entry for (runtime, tier).
@@ -1312,6 +1313,26 @@ function _resolveRuntimeTier(config, tier) {
1312
1313
  overrides: config['model_profile_overrides'],
1313
1314
  });
1314
1315
  }
1316
+ // Reverse of the Claude tier-default IDs, plus the Fable alias which Claude
1317
+ // Code's Agent tool accepts but which is not a GSD model-profile tier (#1133).
1318
+ const CLAUDE_POLICY_ID_TO_ALIAS = {
1319
+ ...Object.fromEntries(Object.entries(model_catalog_cjs_1.MODEL_ALIAS_MAP)
1320
+ .filter((e) => typeof e[1] === 'string')
1321
+ .map(([aliasName, id]) => [id, aliasName])),
1322
+ 'claude-fable-5': 'fable',
1323
+ };
1324
+ const CLAUDE_AGENT_ALIASES = new Set(['opus', 'sonnet', 'haiku', 'fable']);
1325
+ // Dedupe stderr warnings so repeated agent resolutions don't spam (#1133).
1326
+ const _modelPolicyUnmappableWarned = new Set();
1327
+ function warnModelPolicyUnmappable(agentType, policyModel, tier) {
1328
+ const key = `${agentType}::${policyModel}::${tier}`;
1329
+ if (_modelPolicyUnmappableWarned.has(key))
1330
+ return;
1331
+ _modelPolicyUnmappableWarned.add(key);
1332
+ // MUST go to stderr — resolve-model's JSON result is parsed from stdout.
1333
+ process.stderr.write(`gsd: warning — model_policy resolved "${policyModel}" for ${agentType}, ` +
1334
+ `but it has no Claude agent alias; using "${tier}" instead.\n`);
1335
+ }
1315
1336
  /**
1316
1337
  * #49 — Provider-neutral model policy preset resolution.
1317
1338
  */
@@ -1389,15 +1410,32 @@ function resolveModelInternal(cwd, agentType) {
1389
1410
  : (profile === 'inherit'
1390
1411
  ? 'inherit'
1391
1412
  : (agentModels ? (agentModels[profile] || agentModels['balanced']) : null));
1392
- // 2.5. model_policy preset (#49)
1413
+ // 2.5. model_policy preset (#49, #1133)
1393
1414
  const configRuntime = config['runtime'];
1394
- if (configRuntime && configRuntime !== 'claude' && tier && tier !== 'inherit') {
1415
+ if (tier && tier !== 'inherit') {
1416
+ const onClaude = !configRuntime || configRuntime === 'claude';
1417
+ const effectiveRuntime = configRuntime || 'claude';
1395
1418
  const mergedPolicy = config['model_policy']
1396
- ? { ...config['model_policy'], runtime: configRuntime }
1419
+ ? { ...config['model_policy'], runtime: effectiveRuntime }
1397
1420
  : null;
1398
1421
  const policyModel = resolveModelPolicy(mergedPolicy, tier);
1399
- if (policyModel)
1400
- return policyModel;
1422
+ if (policyModel) {
1423
+ // Non-Claude runtimes take full model IDs verbatim (unchanged behavior).
1424
+ if (!onClaude)
1425
+ return policyModel;
1426
+ // Claude Code's Agent tool takes tier aliases (opus/sonnet/haiku/fable),
1427
+ // not full model IDs — map the policy-resolved ID back to an alias (#1133).
1428
+ const aliasForId = CLAUDE_POLICY_ID_TO_ALIAS[policyModel];
1429
+ if (aliasForId)
1430
+ return aliasForId;
1431
+ // The policy value may already be a bare Claude agent alias (e.g. "fable").
1432
+ if (CLAUDE_AGENT_ALIASES.has(policyModel))
1433
+ return policyModel;
1434
+ // No Claude alias for this ID (e.g. a pinned minor version like
1435
+ // claude-opus-4-5). Warn once and fall through to the tier alias rather
1436
+ // than returning an ID Claude Code cannot spawn.
1437
+ warnModelPolicyUnmappable(agentType, policyModel, tier);
1438
+ }
1401
1439
  }
1402
1440
  // 3. Runtime-aware resolution (#2517)
1403
1441
  if (configRuntime && configRuntime !== 'claude' && tier && tier !== 'inherit') {
@@ -672,6 +672,8 @@ Canonical tier mappings by provider and budget:
672
672
 
673
673
  Look up the selected (provider, budget) row and proceed to Step E to write those values.
674
674
 
675
+ > **claude runtime note:** On the default `claude` runtime, policy-resolved model IDs (e.g. `claude-fable-5`) are mapped to Claude Code agent aliases (`fable`, `opus`, `sonnet`, `haiku`); an ID with no corresponding alias emits a stderr warning and falls back to the configured tier alias.
676
+
675
677
  **Step D — Generic-provider path:**
676
678
 
677
679
  Prompt the user to enter each model ID as a free-text input. An empty input means "keep
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengsd/gsd-core",
3
- "version": "1.4.4",
3
+ "version": "1.4.5",
4
4
  "description": "GSD Core is a meta-prompting, context engineering, and spec-driven development system for AI coding agents.",
5
5
  "bin": {
6
6
  "gsd-core": "bin/install.js",