@formigio/fazemos-cli 0.10.39 → 0.10.40

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
@@ -2383,8 +2383,20 @@ ws
2383
2383
  .argument('<id>', 'Worksheet ID')
2384
2384
  .action(async (id) => {
2385
2385
  try {
2386
- const data = await api('GET', `/api/worksheets/${id}`);
2386
+ // G4 (AC15): fetch enriched actions in parallel so we can display
2387
+ // linked_pipeline status chips next to bound actions.
2388
+ const [data, actionsResult] = await Promise.all([
2389
+ api('GET', `/api/worksheets/${id}`),
2390
+ api('GET', `/api/worksheets/${id}/actions`).catch(() => null),
2391
+ ]);
2387
2392
  const w = data.worksheet;
2393
+ // Build a lookup map from action id → linked_pipeline (from the enriched endpoint)
2394
+ const actionPipelineMap = new Map();
2395
+ if (actionsResult?.actions) {
2396
+ for (const a of actionsResult.actions) {
2397
+ actionPipelineMap.set(a.id, a.linked_pipeline ?? null);
2398
+ }
2399
+ }
2388
2400
  console.log(chalk.cyan(w.name));
2389
2401
  console.log(` ID: ${w.id}`);
2390
2402
  console.log(` Purpose: ${w.purpose || '(none)'}`);
@@ -2414,7 +2426,16 @@ ws
2414
2426
  console.log(chalk.cyan(`\n Actions (${data.actions.length}):`));
2415
2427
  for (const a of data.actions) {
2416
2428
  const progress = a.target_value ? ` ${a.current_value ?? 0}/${a.target_value}` : '';
2417
- console.log(` ${chalk.cyan(a.description)}${progress} ${a.member_name || 'unassigned'} ${a.id}`);
2429
+ // G4 (AC15): show pipeline status chip when action is bound to a pipeline
2430
+ const linkedPipeline = actionPipelineMap.get(a.id);
2431
+ let pipelineChip = '';
2432
+ if (linkedPipeline) {
2433
+ const chipColor = linkedPipeline.status === 'completed' ? chalk.green :
2434
+ linkedPipeline.status === 'failed' ? chalk.red :
2435
+ chalk.yellow;
2436
+ pipelineChip = ` ${chipColor(`[${linkedPipeline.status}]`)}`;
2437
+ }
2438
+ console.log(` ${chalk.cyan(a.description)}${progress}${pipelineChip} — ${a.member_name || 'unassigned'} — ${a.id}`);
2418
2439
  }
2419
2440
  }
2420
2441
  if (data.commitments?.length) {
@@ -4808,17 +4829,29 @@ pipelines
4808
4829
  .argument('<templateId>', 'Template ID')
4809
4830
  .requiredOption('-n, --name <name>', 'Instance name')
4810
4831
  .option('--params <json>', 'Parameters as JSON string')
4832
+ .option('--action <action-id>', 'Bind to a worksheet action at creation time (UUID)')
4811
4833
  .action(async (templateId, opts) => {
4812
4834
  try {
4813
4835
  const body = { templateId, name: opts.name };
4814
4836
  if (opts.params)
4815
4837
  body.parameters = parseJson(opts.params, '--params');
4838
+ // G4: optionally bind to a worksheet action at creation time (AC12)
4839
+ if (opts.action)
4840
+ body.worksheetActionId = opts.action;
4816
4841
  const data = await api('POST', '/api/pipeline-instances', body);
4817
4842
  const inst = data.instance;
4818
4843
  console.log(chalk.green(`Created: ${inst.name}`));
4819
4844
  console.log(` ID: ${inst.id}`);
4845
+ if (inst.worksheet_action_id) {
4846
+ console.log(` Bound Action: ${inst.worksheet_action_id}`);
4847
+ }
4820
4848
  }
4821
4849
  catch (err) {
4850
+ // G4: org-isolation guard fires when the action belongs to a different org (AC11)
4851
+ if (err instanceof ApiError && err.code === 'BINDING_ORG_ISOLATION_FAILED') {
4852
+ console.error(chalk.red('Binding failed: the action belongs to a different org than this pipeline.'));
4853
+ process.exit(1);
4854
+ }
4822
4855
  // F16 — Role-aware Connection-unavailable error (tech spec §5.14).
4823
4856
  // The pipeline-run path returns a structured payload when the
4824
4857
  // Project's Connection is missing/revoked/suspended/uninstalled.
@@ -4855,6 +4888,50 @@ pipelines
4855
4888
  process.exit(1);
4856
4889
  }
4857
4890
  });
4891
+ // G4 — Bind an existing pipeline instance to a worksheet action (AC13)
4892
+ pipelines
4893
+ .command('bind')
4894
+ .description('Bind an existing pipeline instance to a worksheet action')
4895
+ .argument('<instance-id>', 'Pipeline instance ID')
4896
+ .requiredOption('--action <action-id>', 'Worksheet action UUID to bind')
4897
+ .action(async (instanceId, opts) => {
4898
+ try {
4899
+ const data = await api('PATCH', `/api/pipeline-instances/${instanceId}`, {
4900
+ worksheetActionId: opts.action,
4901
+ });
4902
+ const inst = data.instance;
4903
+ console.log(chalk.green(`Bound: ${inst.name}`));
4904
+ console.log(` Pipeline: ${inst.id}`);
4905
+ console.log(` Action: ${inst.worksheet_action_id}`);
4906
+ }
4907
+ catch (err) {
4908
+ if (err instanceof ApiError && err.code === 'BINDING_ORG_ISOLATION_FAILED') {
4909
+ console.error(chalk.red('Binding failed: the action belongs to a different org than this pipeline.'));
4910
+ process.exit(1);
4911
+ }
4912
+ console.error(chalk.red(err.message));
4913
+ process.exit(1);
4914
+ }
4915
+ });
4916
+ // G4 — Remove binding between a pipeline instance and a worksheet action (AC14)
4917
+ pipelines
4918
+ .command('unbind')
4919
+ .description('Remove binding between a pipeline instance and a worksheet action')
4920
+ .argument('<instance-id>', 'Pipeline instance ID')
4921
+ .action(async (instanceId) => {
4922
+ try {
4923
+ const data = await api('PATCH', `/api/pipeline-instances/${instanceId}`, {
4924
+ worksheetActionId: null,
4925
+ });
4926
+ const inst = data.instance;
4927
+ console.log(chalk.green(`Unbound: ${inst.name}`));
4928
+ console.log(` Pipeline: ${inst.id}`);
4929
+ }
4930
+ catch (err) {
4931
+ console.error(chalk.red(err.message));
4932
+ process.exit(1);
4933
+ }
4934
+ });
4858
4935
  // I30 — `pl force-cancel` removed. Replaced by the generalised
4859
4936
  // `pl force-transition pipeline <id> --to cancelled` admin endpoint, which
4860
4937
  // covers the same emergency cancel path plus 12 more entity/state combos
@@ -5765,10 +5842,12 @@ program
5765
5842
  const executions = program.command('executions').alias('ex').description('Execution commands');
5766
5843
  executions
5767
5844
  .command('list')
5768
- .description('List executions')
5845
+ .description('List executions in the active project (or all projects with --all-projects)')
5769
5846
  .option('-s, --status <status>', 'Filter by status (pending, running, completed, failed)')
5770
5847
  .option('-a, --agent <name>', 'Filter by agent')
5771
5848
  .option('--source-type <type>', 'Filter by source type')
5849
+ .option('--project <slug>', 'Override active project for this call')
5850
+ .option('--all-projects', 'List executions across every project in the active org', false)
5772
5851
  .action(async (opts) => {
5773
5852
  try {
5774
5853
  const params = [];
@@ -5779,7 +5858,7 @@ executions
5779
5858
  if (opts.sourceType)
5780
5859
  params.push(`source_type=${opts.sourceType}`);
5781
5860
  const qs = params.length ? `?${params.join('&')}` : '';
5782
- const data = await api('GET', `/api/executions${qs}`);
5861
+ const data = await api('GET', `/api/executions${qs}`, undefined, projectOpts(opts));
5783
5862
  if (!data.executions?.length) {
5784
5863
  console.log(chalk.yellow('No executions'));
5785
5864
  return;
@@ -5790,12 +5869,20 @@ executions
5790
5869
  : e.status === 'failed' ? chalk.red('✗')
5791
5870
  : '○';
5792
5871
  const cost = e.cost_usd ? ` $${e.cost_usd}` : '';
5793
- console.log(` ${icon} ${e.agent_name}${e.source_type} (${e.status})${cost} ${e.id}`);
5872
+ // AUTON-PORTFOLIO-VIEWin the org-wide fleet view (--all-projects),
5873
+ // surface which project each execution belongs to so the list is
5874
+ // legible across projects. Degrades gracefully to project_id (the
5875
+ // executions list payload today includes project_id but not slug/name)
5876
+ // and is omitted entirely in the default single-project view where a
5877
+ // project column would be redundant.
5878
+ const projectCell = opts.allProjects
5879
+ ? chalk.gray(` [${e.project_slug || e.project_name || e.project_id || '—'}]`)
5880
+ : '';
5881
+ console.log(` ${icon} ${e.agent_name} — ${e.source_type} (${e.status})${cost}${projectCell} — ${e.id}`);
5794
5882
  }
5795
5883
  }
5796
5884
  catch (err) {
5797
- console.error(chalk.red(err.message));
5798
- process.exit(1);
5885
+ handleScopedError(err);
5799
5886
  }
5800
5887
  });
5801
5888
  executions