@codemieai/cdk 0.1.450 → 0.1.452

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/dist/cli/index.js CHANGED
@@ -938,7 +938,7 @@ var init_backupTransformers = __esm({
938
938
 
939
939
  // package.json
940
940
  var package_default = {
941
- version: "0.1.450"};
941
+ version: "0.1.452"};
942
942
  var appConfigSchema = z.object({
943
943
  rootDir: z.string(),
944
944
  codemieConfig: z.string(),
@@ -2886,6 +2886,54 @@ function sortAssistantsByDependencies(assistants) {
2886
2886
  }
2887
2887
  return sorted;
2888
2888
  }
2889
+ async function syncAssistantSkills(client, assistantId, desiredSkillIds) {
2890
+ let currentSkills = [];
2891
+ try {
2892
+ currentSkills = await client.skills.getAssistantSkills(assistantId);
2893
+ } catch (fetchError) {
2894
+ logger.warn(` \u26A0\uFE0F Could not fetch current skills for assistant ${assistantId}, treating as empty`);
2895
+ logger.debug(` ${fetchError instanceof Error ? fetchError.message : String(fetchError)}`);
2896
+ }
2897
+ const currentIds = new Set(currentSkills.map((s) => s.id));
2898
+ const desiredIds = new Set(desiredSkillIds);
2899
+ const toAttach = desiredSkillIds.filter((id) => !currentIds.has(id));
2900
+ const toDetach = currentSkills.filter((s) => !desiredIds.has(s.id)).map((s) => s.id);
2901
+ if (toAttach.length === 0 && toDetach.length === 0) {
2902
+ return;
2903
+ }
2904
+ if (toAttach.length > 0) {
2905
+ logger.info(` Attaching ${toAttach.length} skill(s)...`);
2906
+ for (const skillId of toAttach) {
2907
+ try {
2908
+ await client.skills.attachToAssistant(assistantId, skillId);
2909
+ logger.info(` \u2713 Attached skill ${skillId}`);
2910
+ } catch (attachError) {
2911
+ const msg = attachError instanceof Error ? attachError.message : String(attachError);
2912
+ if (msg.includes("already attached") || msg.includes("already exists")) {
2913
+ logger.info(` \u2713 Skill ${skillId} already attached`);
2914
+ } else {
2915
+ throw attachError;
2916
+ }
2917
+ }
2918
+ }
2919
+ }
2920
+ if (toDetach.length > 0) {
2921
+ logger.info(` Detaching ${toDetach.length} skill(s)...`);
2922
+ for (const skillId of toDetach) {
2923
+ try {
2924
+ await client.skills.detachFromAssistant(assistantId, skillId);
2925
+ logger.info(` \u2713 Detached skill ${skillId}`);
2926
+ } catch (detachError) {
2927
+ const msg = detachError instanceof Error ? detachError.message : String(detachError);
2928
+ if (msg.includes("not found") || msg.includes("not attached")) {
2929
+ logger.info(` \u2713 Skill ${skillId} already detached`);
2930
+ } else {
2931
+ throw detachError;
2932
+ }
2933
+ }
2934
+ }
2935
+ }
2936
+ }
2889
2937
  async function deployAssistants(config, client, loader, stateManager) {
2890
2938
  const stats = { created: 0, updated: 0, unchanged: 0, failed: 0 };
2891
2939
  if (!config.resources.assistants) {
@@ -2956,11 +3004,11 @@ async function deployAssistants(config, client, loader, stateManager) {
2956
3004
  const assistantWithResolved = {
2957
3005
  ...assistant,
2958
3006
  assistant_ids: resolvedAssistantIds,
2959
- context: resolvedContext,
2960
- skill_ids: resolvedSkillIds
3007
+ context: resolvedContext
2961
3008
  };
2962
3009
  const apiParams = assistantResourceToCreateParams(assistantWithResolved, config.project.name, promptContent);
2963
3010
  const existingState = stateManager.getAssistantState(assistant.name);
3011
+ let deployedAssistantId = null;
2964
3012
  if (existingState) {
2965
3013
  const existsOnPlatform = await checkAssistantExists(client, assistant.name, stateManager);
2966
3014
  if (existsOnPlatform) {
@@ -2975,9 +3023,11 @@ async function deployAssistants(config, client, loader, stateManager) {
2975
3023
  await client.assistants.update(existingState.id, apiParams);
2976
3024
  logger.info(`\u2713 Updated assistant: ${assistant.name} (${existingState.id})`);
2977
3025
  stateManager.updateAssistantState(assistant.name, existingState.id, promptContent, assistant, buildConfig);
3026
+ deployedAssistantId = existingState.id;
2978
3027
  stats.updated++;
2979
3028
  } else {
2980
3029
  logger.info(` \u2713 No changes detected (ID: ${existingState.id})`);
3030
+ deployedAssistantId = existingState.id;
2981
3031
  stats.unchanged++;
2982
3032
  }
2983
3033
  } else {
@@ -3018,6 +3068,7 @@ async function deployAssistants(config, client, loader, stateManager) {
3018
3068
  stats.updated++;
3019
3069
  }
3020
3070
  stateManager.updateAssistantState(assistant.name, assistantId, promptContent, assistant, buildConfig);
3071
+ deployedAssistantId = assistantId;
3021
3072
  }
3022
3073
  } else {
3023
3074
  logger.info(` Creating new assistant...`);
@@ -3056,6 +3107,10 @@ async function deployAssistants(config, client, loader, stateManager) {
3056
3107
  stats.updated++;
3057
3108
  }
3058
3109
  stateManager.updateAssistantState(assistant.name, assistantId, promptContent, assistant, buildConfig);
3110
+ deployedAssistantId = assistantId;
3111
+ }
3112
+ if (deployedAssistantId && assistant.skills !== void 0) {
3113
+ await syncAssistantSkills(client, deployedAssistantId, resolvedSkillIds);
3059
3114
  }
3060
3115
  logger.info("");
3061
3116
  } catch (error) {
@@ -3517,19 +3572,7 @@ async function deployResources(options) {
3517
3572
  if (process.env.SAMPLE_DEPLOY === "1") {
3518
3573
  logger.info("\n\u{1F50E} SAMPLE_DEPLOY=1 -> Skipping orphan deletion (simulation / partial deploy mode)\n");
3519
3574
  } else if (prune) {
3520
- logger.info("\n\u{1F5D1}\uFE0F Deleting orphaned resources (removed from config)...\n");
3521
- const cleanupResult = await cleanupManager.deleteOrphanedResources(orphaned);
3522
- deleted = cleanupResult.deleted.assistants.length + cleanupResult.deleted.datasources.length + cleanupResult.deleted.workflows.length + cleanupResult.deleted.skills.length;
3523
- if (deleted > 0) {
3524
- logger.info(`
3525
- \u2713 Deleted ${deleted} orphaned resource(s)
3526
- `);
3527
- }
3528
- if (cleanupResult.errors.length > 0) {
3529
- logger.info(`
3530
- \u26A0\uFE0F ${cleanupResult.errors.length} error(s) during cleanup
3531
- `);
3532
- }
3575
+ logger.info("\n\u23F3 Orphaned resources will be deleted after deployment (to allow skill detachment first)\n");
3533
3576
  } else {
3534
3577
  logger.info("\n\u26A0\uFE0F Orphaned resources found but not deleted.");
3535
3578
  logger.info(" Use --prune flag to delete them.\n");
@@ -3561,6 +3604,21 @@ async function deployResources(options) {
3561
3604
  updated += workflowStats.updated;
3562
3605
  unchanged += workflowStats.unchanged;
3563
3606
  failed += workflowStats.failed;
3607
+ if (totalOrphaned > 0 && prune && process.env.SAMPLE_DEPLOY !== "1") {
3608
+ logger.info("\u{1F5D1}\uFE0F Deleting orphaned resources (removed from config)...\n");
3609
+ const cleanupResult = await cleanupManager.deleteOrphanedResources(orphaned);
3610
+ deleted = cleanupResult.deleted.assistants.length + cleanupResult.deleted.datasources.length + cleanupResult.deleted.workflows.length + cleanupResult.deleted.skills.length;
3611
+ if (deleted > 0) {
3612
+ logger.info(`
3613
+ \u2713 Deleted ${deleted} orphaned resource(s)
3614
+ `);
3615
+ }
3616
+ if (cleanupResult.errors.length > 0) {
3617
+ logger.info(`
3618
+ \u26A0\uFE0F ${cleanupResult.errors.length} error(s) during cleanup
3619
+ `);
3620
+ }
3621
+ }
3564
3622
  logger.info("=".repeat(50));
3565
3623
  logger.info("\u{1F4CA} Deployment Summary:\n");
3566
3624
  logger.info(` \u2705 Created: ${created}`);
@@ -4374,13 +4432,30 @@ async function previewAssistants(assistants, loader, stateManager, client) {
4374
4432
  "assistant",
4375
4433
  (name) => stateManager.getAssistantState(name),
4376
4434
  () => checkAssistantExists(client, assistant.name, stateManager),
4377
- () => {
4435
+ async () => {
4378
4436
  const existingState = stateManager.getAssistantState(assistant.name);
4379
- const hasChanged = existingState ? existingState.promptChecksum !== calculateChecksum(promptContent) || existingState.configChecksum !== configChecksum : false;
4437
+ const configChanged = existingState ? existingState.promptChecksum !== calculateChecksum(promptContent) || existingState.configChecksum !== configChecksum : false;
4438
+ if (configChanged) {
4439
+ return {
4440
+ hasChanged: true,
4441
+ createDetails: `Model: ${assistant.model}`,
4442
+ updateDetails: "Prompt or configuration changed"
4443
+ };
4444
+ }
4445
+ if (existingState?.id && assistant.skills !== void 0) {
4446
+ const desiredSkillIds = resolveDesiredSkillIds(assistant.skills, stateManager);
4447
+ const drifted = await checkSkillAttachmentDrift(client, existingState.id, desiredSkillIds);
4448
+ if (drifted) {
4449
+ return {
4450
+ hasChanged: true,
4451
+ createDetails: `Model: ${assistant.model}`,
4452
+ updateDetails: "Skill attachments out of sync with platform"
4453
+ };
4454
+ }
4455
+ }
4380
4456
  return {
4381
- hasChanged,
4382
- createDetails: `Model: ${assistant.model}`,
4383
- updateDetails: "Prompt or configuration changed"
4457
+ hasChanged: false,
4458
+ createDetails: `Model: ${assistant.model}`
4384
4459
  };
4385
4460
  }
4386
4461
  );
@@ -4388,6 +4463,34 @@ async function previewAssistants(assistants, loader, stateManager, client) {
4388
4463
  }
4389
4464
  return changes;
4390
4465
  }
4466
+ function resolveDesiredSkillIds(skillNames, stateManager) {
4467
+ const ids = [];
4468
+ for (const name of skillNames) {
4469
+ const skillState = stateManager.getSkillState(name);
4470
+ if (skillState) {
4471
+ ids.push(skillState.id);
4472
+ }
4473
+ }
4474
+ return ids;
4475
+ }
4476
+ async function checkSkillAttachmentDrift(client, assistantId, desiredSkillIds) {
4477
+ try {
4478
+ const currentSkills = await client.skills.getAssistantSkills(assistantId);
4479
+ const currentIds = new Set(currentSkills.map((s) => s.id));
4480
+ const desiredIds = new Set(desiredSkillIds);
4481
+ if (currentIds.size !== desiredIds.size) {
4482
+ return true;
4483
+ }
4484
+ for (const id of desiredIds) {
4485
+ if (!currentIds.has(id)) {
4486
+ return true;
4487
+ }
4488
+ }
4489
+ return false;
4490
+ } catch {
4491
+ return false;
4492
+ }
4493
+ }
4391
4494
  async function previewDatasources(datasources, stateManager, client) {
4392
4495
  const changes = [];
4393
4496
  for (const datasource of datasources) {
package/dist/index.js CHANGED
@@ -1925,6 +1925,54 @@ function sortAssistantsByDependencies(assistants) {
1925
1925
  }
1926
1926
  return sorted;
1927
1927
  }
1928
+ async function syncAssistantSkills(client, assistantId, desiredSkillIds) {
1929
+ let currentSkills = [];
1930
+ try {
1931
+ currentSkills = await client.skills.getAssistantSkills(assistantId);
1932
+ } catch (fetchError) {
1933
+ logger.warn(` \u26A0\uFE0F Could not fetch current skills for assistant ${assistantId}, treating as empty`);
1934
+ logger.debug(` ${fetchError instanceof Error ? fetchError.message : String(fetchError)}`);
1935
+ }
1936
+ const currentIds = new Set(currentSkills.map((s) => s.id));
1937
+ const desiredIds = new Set(desiredSkillIds);
1938
+ const toAttach = desiredSkillIds.filter((id) => !currentIds.has(id));
1939
+ const toDetach = currentSkills.filter((s) => !desiredIds.has(s.id)).map((s) => s.id);
1940
+ if (toAttach.length === 0 && toDetach.length === 0) {
1941
+ return;
1942
+ }
1943
+ if (toAttach.length > 0) {
1944
+ logger.info(` Attaching ${toAttach.length} skill(s)...`);
1945
+ for (const skillId of toAttach) {
1946
+ try {
1947
+ await client.skills.attachToAssistant(assistantId, skillId);
1948
+ logger.info(` \u2713 Attached skill ${skillId}`);
1949
+ } catch (attachError) {
1950
+ const msg = attachError instanceof Error ? attachError.message : String(attachError);
1951
+ if (msg.includes("already attached") || msg.includes("already exists")) {
1952
+ logger.info(` \u2713 Skill ${skillId} already attached`);
1953
+ } else {
1954
+ throw attachError;
1955
+ }
1956
+ }
1957
+ }
1958
+ }
1959
+ if (toDetach.length > 0) {
1960
+ logger.info(` Detaching ${toDetach.length} skill(s)...`);
1961
+ for (const skillId of toDetach) {
1962
+ try {
1963
+ await client.skills.detachFromAssistant(assistantId, skillId);
1964
+ logger.info(` \u2713 Detached skill ${skillId}`);
1965
+ } catch (detachError) {
1966
+ const msg = detachError instanceof Error ? detachError.message : String(detachError);
1967
+ if (msg.includes("not found") || msg.includes("not attached")) {
1968
+ logger.info(` \u2713 Skill ${skillId} already detached`);
1969
+ } else {
1970
+ throw detachError;
1971
+ }
1972
+ }
1973
+ }
1974
+ }
1975
+ }
1928
1976
  async function deployAssistants(config, client, loader, stateManager) {
1929
1977
  const stats = { created: 0, updated: 0, unchanged: 0, failed: 0 };
1930
1978
  if (!config.resources.assistants) {
@@ -1995,11 +2043,11 @@ async function deployAssistants(config, client, loader, stateManager) {
1995
2043
  const assistantWithResolved = {
1996
2044
  ...assistant,
1997
2045
  assistant_ids: resolvedAssistantIds,
1998
- context: resolvedContext,
1999
- skill_ids: resolvedSkillIds
2046
+ context: resolvedContext
2000
2047
  };
2001
2048
  const apiParams = assistantResourceToCreateParams(assistantWithResolved, config.project.name, promptContent);
2002
2049
  const existingState = stateManager.getAssistantState(assistant.name);
2050
+ let deployedAssistantId = null;
2003
2051
  if (existingState) {
2004
2052
  const existsOnPlatform = await checkAssistantExists(client, assistant.name, stateManager);
2005
2053
  if (existsOnPlatform) {
@@ -2014,9 +2062,11 @@ async function deployAssistants(config, client, loader, stateManager) {
2014
2062
  await client.assistants.update(existingState.id, apiParams);
2015
2063
  logger.info(`\u2713 Updated assistant: ${assistant.name} (${existingState.id})`);
2016
2064
  stateManager.updateAssistantState(assistant.name, existingState.id, promptContent, assistant, buildConfig);
2065
+ deployedAssistantId = existingState.id;
2017
2066
  stats.updated++;
2018
2067
  } else {
2019
2068
  logger.info(` \u2713 No changes detected (ID: ${existingState.id})`);
2069
+ deployedAssistantId = existingState.id;
2020
2070
  stats.unchanged++;
2021
2071
  }
2022
2072
  } else {
@@ -2057,6 +2107,7 @@ async function deployAssistants(config, client, loader, stateManager) {
2057
2107
  stats.updated++;
2058
2108
  }
2059
2109
  stateManager.updateAssistantState(assistant.name, assistantId, promptContent, assistant, buildConfig);
2110
+ deployedAssistantId = assistantId;
2060
2111
  }
2061
2112
  } else {
2062
2113
  logger.info(` Creating new assistant...`);
@@ -2095,6 +2146,10 @@ async function deployAssistants(config, client, loader, stateManager) {
2095
2146
  stats.updated++;
2096
2147
  }
2097
2148
  stateManager.updateAssistantState(assistant.name, assistantId, promptContent, assistant, buildConfig);
2149
+ deployedAssistantId = assistantId;
2150
+ }
2151
+ if (deployedAssistantId && assistant.skills !== void 0) {
2152
+ await syncAssistantSkills(client, deployedAssistantId, resolvedSkillIds);
2098
2153
  }
2099
2154
  logger.info("");
2100
2155
  } catch (error) {
@@ -2556,19 +2611,7 @@ async function deployResources(options) {
2556
2611
  if (process.env.SAMPLE_DEPLOY === "1") {
2557
2612
  logger.info("\n\u{1F50E} SAMPLE_DEPLOY=1 -> Skipping orphan deletion (simulation / partial deploy mode)\n");
2558
2613
  } else if (prune) {
2559
- logger.info("\n\u{1F5D1}\uFE0F Deleting orphaned resources (removed from config)...\n");
2560
- const cleanupResult = await cleanupManager.deleteOrphanedResources(orphaned);
2561
- deleted = cleanupResult.deleted.assistants.length + cleanupResult.deleted.datasources.length + cleanupResult.deleted.workflows.length + cleanupResult.deleted.skills.length;
2562
- if (deleted > 0) {
2563
- logger.info(`
2564
- \u2713 Deleted ${deleted} orphaned resource(s)
2565
- `);
2566
- }
2567
- if (cleanupResult.errors.length > 0) {
2568
- logger.info(`
2569
- \u26A0\uFE0F ${cleanupResult.errors.length} error(s) during cleanup
2570
- `);
2571
- }
2614
+ logger.info("\n\u23F3 Orphaned resources will be deleted after deployment (to allow skill detachment first)\n");
2572
2615
  } else {
2573
2616
  logger.info("\n\u26A0\uFE0F Orphaned resources found but not deleted.");
2574
2617
  logger.info(" Use --prune flag to delete them.\n");
@@ -2600,6 +2643,21 @@ async function deployResources(options) {
2600
2643
  updated += workflowStats.updated;
2601
2644
  unchanged += workflowStats.unchanged;
2602
2645
  failed += workflowStats.failed;
2646
+ if (totalOrphaned > 0 && prune && process.env.SAMPLE_DEPLOY !== "1") {
2647
+ logger.info("\u{1F5D1}\uFE0F Deleting orphaned resources (removed from config)...\n");
2648
+ const cleanupResult = await cleanupManager.deleteOrphanedResources(orphaned);
2649
+ deleted = cleanupResult.deleted.assistants.length + cleanupResult.deleted.datasources.length + cleanupResult.deleted.workflows.length + cleanupResult.deleted.skills.length;
2650
+ if (deleted > 0) {
2651
+ logger.info(`
2652
+ \u2713 Deleted ${deleted} orphaned resource(s)
2653
+ `);
2654
+ }
2655
+ if (cleanupResult.errors.length > 0) {
2656
+ logger.info(`
2657
+ \u26A0\uFE0F ${cleanupResult.errors.length} error(s) during cleanup
2658
+ `);
2659
+ }
2660
+ }
2603
2661
  logger.info("=".repeat(50));
2604
2662
  logger.info("\u{1F4CA} Deployment Summary:\n");
2605
2663
  logger.info(` \u2705 Created: ${created}`);
@@ -2977,13 +3035,30 @@ async function previewAssistants(assistants, loader, stateManager, client) {
2977
3035
  "assistant",
2978
3036
  (name) => stateManager.getAssistantState(name),
2979
3037
  () => checkAssistantExists(client, assistant.name, stateManager),
2980
- () => {
3038
+ async () => {
2981
3039
  const existingState = stateManager.getAssistantState(assistant.name);
2982
- const hasChanged = existingState ? existingState.promptChecksum !== calculateChecksum(promptContent) || existingState.configChecksum !== configChecksum : false;
3040
+ const configChanged = existingState ? existingState.promptChecksum !== calculateChecksum(promptContent) || existingState.configChecksum !== configChecksum : false;
3041
+ if (configChanged) {
3042
+ return {
3043
+ hasChanged: true,
3044
+ createDetails: `Model: ${assistant.model}`,
3045
+ updateDetails: "Prompt or configuration changed"
3046
+ };
3047
+ }
3048
+ if (existingState?.id && assistant.skills !== void 0) {
3049
+ const desiredSkillIds = resolveDesiredSkillIds(assistant.skills, stateManager);
3050
+ const drifted = await checkSkillAttachmentDrift(client, existingState.id, desiredSkillIds);
3051
+ if (drifted) {
3052
+ return {
3053
+ hasChanged: true,
3054
+ createDetails: `Model: ${assistant.model}`,
3055
+ updateDetails: "Skill attachments out of sync with platform"
3056
+ };
3057
+ }
3058
+ }
2983
3059
  return {
2984
- hasChanged,
2985
- createDetails: `Model: ${assistant.model}`,
2986
- updateDetails: "Prompt or configuration changed"
3060
+ hasChanged: false,
3061
+ createDetails: `Model: ${assistant.model}`
2987
3062
  };
2988
3063
  }
2989
3064
  );
@@ -2991,6 +3066,34 @@ async function previewAssistants(assistants, loader, stateManager, client) {
2991
3066
  }
2992
3067
  return changes;
2993
3068
  }
3069
+ function resolveDesiredSkillIds(skillNames, stateManager) {
3070
+ const ids = [];
3071
+ for (const name of skillNames) {
3072
+ const skillState = stateManager.getSkillState(name);
3073
+ if (skillState) {
3074
+ ids.push(skillState.id);
3075
+ }
3076
+ }
3077
+ return ids;
3078
+ }
3079
+ async function checkSkillAttachmentDrift(client, assistantId, desiredSkillIds) {
3080
+ try {
3081
+ const currentSkills = await client.skills.getAssistantSkills(assistantId);
3082
+ const currentIds = new Set(currentSkills.map((s) => s.id));
3083
+ const desiredIds = new Set(desiredSkillIds);
3084
+ if (currentIds.size !== desiredIds.size) {
3085
+ return true;
3086
+ }
3087
+ for (const id of desiredIds) {
3088
+ if (!currentIds.has(id)) {
3089
+ return true;
3090
+ }
3091
+ }
3092
+ return false;
3093
+ } catch {
3094
+ return false;
3095
+ }
3096
+ }
2994
3097
  async function previewDatasources(datasources, stateManager, client) {
2995
3098
  const changes = [];
2996
3099
  for (const datasource of datasources) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemieai/cdk",
3
- "version": "0.1.450",
3
+ "version": "0.1.452",
4
4
  "type": "module",
5
5
  "description": "Infrastructure as Code solution for managing Codemie AI assistants, datasources, and workflows through declarative YAML configuration",
6
6
  "main": "./dist/index.js",