@biznetgio/neo-app 0.4.20 → 0.4.22

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.
Files changed (2) hide show
  1. package/package.json +2 -1
  2. package/src/mcp/tools.js +54 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@biznetgio/neo-app",
3
- "version": "0.4.20",
3
+ "version": "0.4.22",
4
4
  "description": "NEO App CLI — one-command agent onboarding, MCP server, and project ops for coding agents (Codex, Claude Code).",
5
5
  "type": "module",
6
6
  "bin": {
@@ -16,6 +16,7 @@
16
16
  },
17
17
  "scripts": {
18
18
  "test": "node --test",
19
+ "e2e": "node e2e/mcp-regression.mjs",
19
20
  "prepublishOnly": "node --test"
20
21
  },
21
22
  "dependencies": {
package/src/mcp/tools.js CHANGED
@@ -94,10 +94,10 @@ export const TOOLS = [
94
94
  { type: 'template', create: true, deploy: true, scale: false, logs: true, variables: true, delete: true },
95
95
  { type: 'static_site', create: 'via_folder', deploy: true, scale: false, logs: true, variables: true, delete: true, note: 'neo_deploy_folder serviceType=static_site (auto-detected for static-only folders); auto-detection from a repo/monorepo is still TODO (handoff 6)' },
96
96
  { type: 'worker', create: 'via_folder', deploy: true, scale: true, logs: true, variables: true, delete: true, note: 'neo_deploy_folder serviceType=worker — no public ingress; repo auto-detection still TODO (handoff 6)' },
97
- { type: 'database', create: true, get: true, list: true, delete: true, note: 'neo_create/list/get/delete_database (0.4.15); update/plan still TODO (handoff 4.4)' },
97
+ { type: 'database', create: true, get: true, list: true, update: true, delete: true, note: 'neo_create/list/get/update(resize)/delete_database (0.4.15-0.4.21); backup/restore still TODO (handoff 4.4)' },
98
98
  { type: 'queue', create: true, get: true, list: true, delete: true, note: 'neo_create/list/get/delete_queue (0.4.15); update/plan still TODO (handoff 4.5)' },
99
- { type: 'cron', create: true, get: true, list: true, run: true, delete: true, note: 'neo_create/list/get/run/delete_cron (0.4.15-0.4.17); run-history still TODO (handoff 4.6)' },
100
- { type: 'object_storage', create: true, get: true, list: true, delete: true, note: 'neo_create/list/get/delete_bucket (0.4.15); object put/get still TODO (handoff 4.7)' },
99
+ { type: 'cron', create: true, get: true, list: true, run: true, runs: true, delete: true, note: 'neo_create/list/get/run/list_runs/delete_cron (0.4.15-0.4.21) (handoff 4.6)' },
100
+ { type: 'object_storage', create: true, get: true, list: true, objects: true, delete: true, note: 'neo_create/list/get/delete_bucket + list/delete objects (0.4.15-0.4.21); object upload still TODO (handoff 4.7)' },
101
101
  ];
102
102
 
103
103
  return {
@@ -473,6 +473,27 @@ export const TOOLS = [
473
473
  return redactSecrets((await api.get(`/api/v1/databases/${args.databaseId}`)).data);
474
474
  },
475
475
  },
476
+ {
477
+ name: 'neo_update_database',
478
+ description: 'Resize a managed database (handoff 4.4): grow storage (volumeSize) and/or set replicas for HA. Storage is GROW-ONLY — the server rejects a smaller volumeSize. Redeploy the database for a change to take effect.',
479
+ mutating: true,
480
+ schema: {
481
+ type: 'object',
482
+ properties: {
483
+ databaseId: str('Database id'),
484
+ volumeSize: str('New storage size, e.g. "20Gi" — must be >= current (grow-only)'),
485
+ replicas: int('Read/failover replicas (CNPG/postgres); total instances = 1 + replicas'),
486
+ },
487
+ required: ['databaseId'],
488
+ },
489
+ async call(api, args) {
490
+ const body = {};
491
+ if (args.volumeSize) body.volumeSize = args.volumeSize;
492
+ if (args.replicas !== undefined) body.replicas = args.replicas;
493
+ const { status, data } = await api.put(`/api/v1/databases/${args.databaseId}`, body);
494
+ return redactSecrets(result(status, data));
495
+ },
496
+ },
476
497
  {
477
498
  name: 'neo_create_queue',
478
499
  description: 'Create a managed queue in a project (handoff 4.5). Credentials redacted. May return pending_approval.',
@@ -572,6 +593,15 @@ export const TOOLS = [
572
593
  return redactSecrets(result(status, data));
573
594
  },
574
595
  },
596
+ {
597
+ name: 'neo_list_cron_runs',
598
+ description: 'List the recent runs of a scheduled job (cron) with their status/timing — run history + output verification (handoff 4.6).',
599
+ mutating: false,
600
+ schema: { type: 'object', properties: { cronId: str('Cron/scheduled-job id') }, required: ['cronId'] },
601
+ async call(api, args) {
602
+ return redactSecrets((await api.get(`/api/v1/crons/${args.cronId}/runs`)).data);
603
+ },
604
+ },
575
605
  {
576
606
  name: 'neo_create_bucket',
577
607
  description: 'Create an S3-compatible object-storage bucket in a project (handoff 4.7). Access keys are provisioned server-side and are NOT returned (write-only). May return pending_approval.',
@@ -611,6 +641,26 @@ export const TOOLS = [
611
641
  return redactSecrets((await api.get(`/api/v1/buckets/${args.bucketId}`)).data);
612
642
  },
613
643
  },
644
+ {
645
+ name: 'neo_list_bucket_objects',
646
+ description: 'List the objects in an object-storage bucket (handoff 4.7).',
647
+ mutating: false,
648
+ schema: { type: 'object', properties: { bucketId: str('Bucket id') }, required: ['bucketId'] },
649
+ async call(api, args) {
650
+ return (await api.get(`/api/v1/buckets/${args.bucketId}/objects`)).data;
651
+ },
652
+ },
653
+ {
654
+ name: 'neo_delete_bucket_object',
655
+ description: 'Delete one object from an object-storage bucket by its key. Destructive and irreversible (handoff 4.7).',
656
+ mutating: true,
657
+ destructive: true,
658
+ schema: { type: 'object', properties: { bucketId: str('Bucket id'), object: str('Object key/path to delete') }, required: ['bucketId', 'object'] },
659
+ async call(api, args) {
660
+ const { status, data } = await api.del(`/api/v1/buckets/${args.bucketId}/objects`, { query: { object: args.object } });
661
+ return result(status, data);
662
+ },
663
+ },
614
664
  // --- Typed bindings (handoff 5): attach a DB/queue to a consumer service. The
615
665
  // connection string is injected as an env var SERVER-SIDE at the consumer's next
616
666
  // deploy (marked a secret) — it is never returned to the agent (write-only). ---
@@ -735,7 +785,7 @@ export const TOOLS = [
735
785
  },
736
786
  {
737
787
  name: 'neo_get_operation',
738
- description: 'Get the status of a stack apply (the operationId/planId from neo_apply_stack): overall status (applying | applied | failed) plus per-resource status (creating | created | deployed | failed). Poll until terminal.',
788
+ description: 'Get the status of a stack apply (the operationId/planId from neo_apply_stack): overall status (applying | applied | failed) plus per-resource status (creating | deploying | deployed | failed). Apply waits for each deploy — "applied" means every resource reached a successful deploy (databases/queues rollout-ready), not merely that the manifest was submitted. Poll until terminal.',
739
789
  mutating: false,
740
790
  schema: { type: 'object', properties: { operationId: str('Operation id (= plan id from neo_apply_stack)') }, required: ['operationId'] },
741
791
  async call(api, args) {