@formigio/fazemos-cli 0.10.66 → 0.10.67

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/index.js CHANGED
@@ -7514,6 +7514,10 @@ function exitNoActiveProjectForAgentsList() {
7514
7514
  function formatAgentSource(source) {
7515
7515
  if (source === 'project_override')
7516
7516
  return 'project-override';
7517
+ if (source === 'org_file')
7518
+ return 'org-file';
7519
+ if (source === 'project_file')
7520
+ return 'project-file';
7517
7521
  return source;
7518
7522
  }
7519
7523
  /**
@@ -7781,11 +7785,26 @@ agentsCmd
7781
7785
  const { orgId, projectId } = await requireProjectForAgents(opts.project);
7782
7786
  const data = await api('GET', `/api/organizations/${orgId}/projects/${projectId}/agents/${encodeURIComponent(name)}`, undefined, { noProjectHeader: true });
7783
7787
  const a = data.agent;
7788
+ const resolution = data.resolution;
7784
7789
  const proj = findProjectById(orgId, projectId);
7785
7790
  const projSlug = proj?.slug ?? projectId;
7786
- const sourceLabel = formatAgentSource(a.source);
7791
+ // Use resolution.agent_source (F18-aware) when available; fall back to
7792
+ // a.source (F17-only) for older API versions (degrade per §6).
7793
+ const effectiveSource = resolution?.agent_source ?? a.source;
7794
+ const sourceLabel = formatAgentSource(effectiveSource);
7787
7795
  console.log(chalk.cyan(`Agent: ${a.name} (${a.display_name})`));
7788
7796
  console.log(`Project: ${projSlug} · Source: ${sourceLabel}`);
7797
+ // Role doc line — show immediately after source when a role doc is active.
7798
+ // Uses agent.role_doc_path populated by the API's F18 layer. When the API
7799
+ // is newer (resolution block present), also shows the resolved prompt length
7800
+ // so an empty role-doc stub is visible without a CloudWatch query (R10).
7801
+ if (a.role_doc_path) {
7802
+ const level = a.role_doc_level ? ` (level: ${a.role_doc_level})` : '';
7803
+ console.log(chalk.gray(` Role doc: ${a.role_doc_path}${level}`));
7804
+ if (resolution?.resolved_system_prompt_length !== undefined) {
7805
+ console.log(chalk.gray(` Resolved prompt: ${resolution.resolved_system_prompt_length.toLocaleString()} chars`));
7806
+ }
7807
+ }
7789
7808
  console.log('');
7790
7809
  // EFFECTIVE CONFIG
7791
7810
  console.log(chalk.cyan('EFFECTIVE CONFIG'));
@@ -7837,12 +7856,6 @@ agentsCmd
7837
7856
  const label = a.source === 'project_override' ? 'Override created' : 'Project-only created';
7838
7857
  console.log(chalk.gray(`${label}: ${new Date(a.override_updated_at).toISOString().slice(0, 10)}`));
7839
7858
  }
7840
- // F18 forward-compat: role doc line only when populated.
7841
- if (a.role_doc_path) {
7842
- const level = a.role_doc_level ? ` (${a.role_doc_level})` : '';
7843
- console.log('');
7844
- console.log(chalk.gray(`Role doc: ${a.role_doc_path}${level}`));
7845
- }
7846
7859
  }
7847
7860
  catch (err) {
7848
7861
  if (err instanceof ApiError && err.code === 'AGENT_NOT_FOUND') {
@@ -8545,9 +8558,11 @@ agentsCmd
8545
8558
  .description('Upload an agent definition file to Fazemos')
8546
8559
  .argument('<name>', 'Agent name')
8547
8560
  .argument('<file>', 'Path to agent definition .md file')
8548
- .action(async (name, file) => {
8561
+ .option('--project <slug>', 'Project context for role-doc check (uses active project if not set)')
8562
+ .option('--force', 'Proceed even when a role doc overrides the DB systemPrompt at runtime', false)
8563
+ .action(async (name, file, opts) => {
8549
8564
  try {
8550
- // Resolve agent name to member ID
8565
+ // Resolve agent name to member ID (org-level members list)
8551
8566
  const orgId = getActiveOrgId();
8552
8567
  if (!orgId) {
8553
8568
  console.error(chalk.red('No active org'));
@@ -8560,11 +8575,68 @@ agentsCmd
8560
8575
  console.error(chalk.red(`Agent "${name}" not found`));
8561
8576
  process.exit(1);
8562
8577
  }
8563
- // Read file and strip YAML frontmatter
8564
- const raw = readFileSync(resolve(file), 'utf-8');
8565
- const body = raw.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, '').trim();
8566
- await api('PATCH', `/api/members/${agent.id}/agent-config`, { systemPrompt: body });
8567
- console.log(chalk.green(`Uploaded definition for ${agent.display_name} (${body.length} chars)`));
8578
+ // BUG-PERSONA-RESOLUTION-PATHS-DISAGREE fix (R9, AC-9):
8579
+ // Before PATCHing the DB, check whether a role doc overrides the
8580
+ // systemPrompt at runtime. If so, the upload is silently inert — warn
8581
+ // and refuse unless --force is passed.
8582
+ //
8583
+ // Predicate is derived from the API's resolution.has_role_doc field
8584
+ // (predicate-based, NOT a name-list allowlist — rul_respaths_predicate_not_allowlist).
8585
+ // Requires a project context to call the F17 detail endpoint that carries
8586
+ // the resolution block. When no project context is available, skip the
8587
+ // check and proceed (defensive degrade per §6 — same behavior as today).
8588
+ //
8589
+ // proceedWithUpload is set to false BEFORE process.exit(1) so that test
8590
+ // environments where process.exit is mocked still gate the PATCH correctly.
8591
+ let proceedWithUpload = true;
8592
+ if (!opts.force) {
8593
+ // Resolve project context: --project flag → active project → none.
8594
+ let projectId = null;
8595
+ if (opts.project) {
8596
+ const proj = findProjectBySlug(orgId, opts.project);
8597
+ projectId = proj?.id ?? null;
8598
+ if (!projectId) {
8599
+ proceedWithUpload = false;
8600
+ console.error(chalk.red(`Project "${opts.project}" not found`));
8601
+ process.exit(1);
8602
+ }
8603
+ }
8604
+ else {
8605
+ projectId = getActiveProjectId();
8606
+ }
8607
+ if (proceedWithUpload && projectId) {
8608
+ // Fetch the F17 detail endpoint (now F18-aware) to get the resolution block.
8609
+ // Use agent.name (lowercase slug) as the URL param.
8610
+ const agentName = agent.name ?? norm(name).replace(/\s+/g, '-');
8611
+ try {
8612
+ const detailData = await api('GET', `/api/organizations/${orgId}/projects/${projectId}/agents/${encodeURIComponent(agentName)}`, undefined, { noProjectHeader: true });
8613
+ // Defensive degrade: if resolution block is absent (older API), treat as
8614
+ // has_role_doc=false and proceed — behavior identical to today (§6 / EC-7).
8615
+ if (detailData.resolution?.has_role_doc === true) {
8616
+ const roleDocPath = detailData.resolution.role_doc_path ?? '(unknown path)';
8617
+ proceedWithUpload = false; // Gate PATCH before calling exit (for test environments).
8618
+ console.error(chalk.yellow(`⚠ a role doc at ${roleDocPath} overrides the DB systemPrompt at runtime —`));
8619
+ console.error(chalk.yellow(` this upload will not take effect. Edit the file instead, or re-run with --force`));
8620
+ console.error(chalk.yellow(` if you deliberately want to write the DB value.`));
8621
+ process.exit(1);
8622
+ }
8623
+ }
8624
+ catch (detailErr) {
8625
+ // Detail-fetch failure should not block the upload — fall through.
8626
+ // The PATCH may still be inert if a role doc exists, but we cannot
8627
+ // determine that without the API's resolution block.
8628
+ console.error(chalk.gray(`(role-doc check skipped: ${detailErr.message})`));
8629
+ }
8630
+ }
8631
+ // No project context → skip check, proceed as before.
8632
+ }
8633
+ if (proceedWithUpload) {
8634
+ // Read file and strip YAML frontmatter
8635
+ const raw = readFileSync(resolve(file), 'utf-8');
8636
+ const body = raw.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, '').trim();
8637
+ await api('PATCH', `/api/members/${agent.id}/agent-config`, { systemPrompt: body });
8638
+ console.log(chalk.green(`Uploaded definition for ${agent.display_name} (${body.length} chars)`));
8639
+ }
8568
8640
  }
8569
8641
  catch (err) {
8570
8642
  console.error(chalk.red(err.message));