spaps 0.7.2 → 0.7.4

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 (49) hide show
  1. package/AI_TOOLS.json +10 -11
  2. package/README.md +267 -110
  3. package/assets/local-runtime/Dockerfile +28 -0
  4. package/assets/local-runtime/alembic/env.py +101 -0
  5. package/assets/local-runtime/alembic/path_bootstrap.py +71 -0
  6. package/assets/local-runtime/alembic/versions/000000000001_baseline_consolidated_schema.py +1076 -0
  7. package/assets/local-runtime/alembic/versions/000000000002_fix_column_types_to_match_prod.py +83 -0
  8. package/assets/local-runtime/alembic/versions/000000000003_fix_email_template_key_uniqueness.py +49 -0
  9. package/assets/local-runtime/alembic/versions/000000000004_add_hold_duration_minutes_to_dayrate_config.py +30 -0
  10. package/assets/local-runtime/alembic/versions/000000000005_resource_scoped_entitlements.py +77 -0
  11. package/assets/local-runtime/alembic/versions/000000000006_cfo_rbac_add_is_admin.py +37 -0
  12. package/assets/local-runtime/alembic/versions/000000000007_agent_approvals.py +158 -0
  13. package/assets/local-runtime/alembic/versions/000000000008_add_company_id_to_cfo_connections.py +35 -0
  14. package/assets/local-runtime/alembic/versions/000000000009_tx_signing.py +62 -0
  15. package/assets/local-runtime/alembic/versions/000000000010_affiliate_referrals.py +235 -0
  16. package/assets/local-runtime/alembic/versions/000000000011_checkin_call_booking.py +137 -0
  17. package/assets/local-runtime/alembic/versions/000000000012_subscription_application_scoping.py +55 -0
  18. package/assets/local-runtime/alembic/versions/000000000013_refresh_token_anomaly_context.py +61 -0
  19. package/assets/local-runtime/alembic/versions/000000000014_buildooor_dayrate_hire_schedule.py +39 -0
  20. package/assets/local-runtime/alembic/versions/000000000015_support_telemetry_platform.py +112 -0
  21. package/assets/local-runtime/alembic/versions/000000000016_issue_reporting_platform.py +54 -0
  22. package/assets/local-runtime/alembic/versions/000000000017_issue_reporting_platform_import_tracking.py +44 -0
  23. package/assets/local-runtime/alembic/versions/000000000018_authorization_policy_engine.py +76 -0
  24. package/assets/local-runtime/alembic.ini +47 -0
  25. package/assets/local-runtime/docker-compose.yml +61 -0
  26. package/assets/local-runtime/manifest.json +8 -0
  27. package/assets/local-runtime/scripts/container-entrypoint.sh +13 -0
  28. package/assets/local-runtime/scripts/fetch-prod-db.sh +112 -0
  29. package/assets/local-runtime/scripts/run-migrations.sh +96 -0
  30. package/package.json +5 -4
  31. package/src/ai-helper.js +176 -234
  32. package/src/ai-tool-spec.js +52 -20
  33. package/src/auth/api-key.js +119 -0
  34. package/src/auth/client-id.js +136 -0
  35. package/src/auth/client.js +169 -0
  36. package/src/auth/credentials.js +110 -0
  37. package/src/auth/device-flow.js +159 -0
  38. package/src/auth/env.js +57 -0
  39. package/src/auth/handlers.js +462 -0
  40. package/src/auth/http.js +74 -0
  41. package/src/cli-dispatcher.js +155 -24
  42. package/src/docs-system.js +7 -7
  43. package/src/error-handler.js +42 -0
  44. package/src/fixture-kernel.js +1143 -0
  45. package/src/handlers.js +252 -15
  46. package/src/help-system.js +3 -1
  47. package/src/local-runtime.js +258 -0
  48. package/src/local-server.js +597 -199
  49. package/src/project-scaffolder.js +441 -0
@@ -0,0 +1,83 @@
1
+ """fix column types to match production
2
+
3
+ Revision ID: 000000000002
4
+ Revises: 000000000001
5
+ Create Date: 2026-02-09
6
+
7
+ Fix column types that diverged from the production Supabase schema:
8
+ - dayrate_config.slots: JSONB → TEXT[] (was always a text array in prod)
9
+ - endpoint_documentation.authentication: JSONB → TEXT (was always plain text in prod)
10
+ - endpoint_documentation.error_codes: JSONB → JSONB[] (was always a jsonb array in prod)
11
+
12
+ Idempotent: skips columns that already have the correct type (e.g. fresh installs
13
+ where the baseline was fixed).
14
+ """
15
+
16
+ from alembic import op
17
+
18
+ revision = "000000000002"
19
+ down_revision = "000000000001"
20
+ branch_labels = None
21
+ depends_on = None
22
+
23
+
24
+ def upgrade() -> None:
25
+ # Each block checks current type and only alters if wrong.
26
+ # On fresh installs the baseline already has the correct types.
27
+
28
+ op.execute("""
29
+ DO $$ BEGIN
30
+ IF (SELECT udt_name FROM information_schema.columns
31
+ WHERE table_schema = 'public'
32
+ AND table_name = 'dayrate_config'
33
+ AND column_name = 'slots') = 'jsonb' THEN
34
+ ALTER TABLE dayrate_config
35
+ ALTER COLUMN slots TYPE TEXT[] USING '{}';
36
+ END IF;
37
+ END $$
38
+ """)
39
+
40
+ op.execute("""
41
+ DO $$ BEGIN
42
+ IF (SELECT udt_name FROM information_schema.columns
43
+ WHERE table_schema = 'public'
44
+ AND table_name = 'endpoint_documentation'
45
+ AND column_name = 'authentication') = 'jsonb' THEN
46
+ ALTER TABLE endpoint_documentation
47
+ ALTER COLUMN authentication TYPE TEXT
48
+ USING authentication::TEXT;
49
+ END IF;
50
+ END $$
51
+ """)
52
+
53
+ op.execute("""
54
+ DO $$ BEGIN
55
+ IF (SELECT udt_name FROM information_schema.columns
56
+ WHERE table_schema = 'public'
57
+ AND table_name = 'endpoint_documentation'
58
+ AND column_name = 'error_codes') = 'jsonb' THEN
59
+ ALTER TABLE endpoint_documentation
60
+ ALTER COLUMN error_codes TYPE JSONB[]
61
+ USING ARRAY[]::JSONB[];
62
+ END IF;
63
+ END $$
64
+ """)
65
+
66
+
67
+ def downgrade() -> None:
68
+ op.execute("""
69
+ ALTER TABLE dayrate_config
70
+ ALTER COLUMN slots TYPE JSONB USING to_jsonb(slots)
71
+ """)
72
+
73
+ op.execute("""
74
+ ALTER TABLE endpoint_documentation
75
+ ALTER COLUMN authentication TYPE JSONB
76
+ USING to_jsonb(authentication)
77
+ """)
78
+
79
+ op.execute("""
80
+ ALTER TABLE endpoint_documentation
81
+ ALTER COLUMN error_codes TYPE JSONB
82
+ USING to_jsonb(error_codes)
83
+ """)
@@ -0,0 +1,49 @@
1
+ """fix email template_key uniqueness to composite (application_id, template_key)
2
+
3
+ Revision ID: 000000000003
4
+ Revises: 000000000002
5
+ Create Date: 2026-02-09
6
+
7
+ The template_key column had a global unique constraint, preventing
8
+ multi-tenant use (e.g. two different applications both creating
9
+ "auth_magic_link"). This migration replaces the single-column unique
10
+ constraint with a composite unique index on (application_id, template_key).
11
+ """
12
+
13
+ from alembic import op
14
+
15
+ revision = "000000000003"
16
+ down_revision = "000000000002"
17
+ branch_labels = None
18
+ depends_on = None
19
+
20
+
21
+ def upgrade() -> None:
22
+ # Drop the single-column unique constraint if it exists
23
+ op.execute("""
24
+ ALTER TABLE email_templates
25
+ DROP CONSTRAINT IF EXISTS email_templates_template_key_key;
26
+ """)
27
+
28
+ # Also drop the index-based form if present
29
+ op.execute("""
30
+ DROP INDEX IF EXISTS ix_email_templates_template_key;
31
+ """)
32
+
33
+ # Create composite unique index
34
+ op.execute("""
35
+ CREATE UNIQUE INDEX IF NOT EXISTS uq_email_templates_app_key
36
+ ON email_templates (application_id, template_key);
37
+ """)
38
+
39
+
40
+ def downgrade() -> None:
41
+ op.execute("""
42
+ DROP INDEX IF EXISTS uq_email_templates_app_key;
43
+ """)
44
+
45
+ # Restore original single-column unique constraint
46
+ op.execute("""
47
+ ALTER TABLE email_templates
48
+ ADD CONSTRAINT email_templates_template_key_key UNIQUE (template_key);
49
+ """)
@@ -0,0 +1,30 @@
1
+ """add hold_duration_minutes to dayrate_config
2
+
3
+ Revision ID: 000000000004
4
+ Revises: 000000000003
5
+ Create Date: 2026-02-11
6
+
7
+ Adds a configurable hold duration (in minutes) for pending dayrate bookings.
8
+ Previously hardcoded to 30 minutes. Defaults to 30 for backwards compatibility.
9
+ """
10
+
11
+ from alembic import op
12
+
13
+ revision = "000000000004"
14
+ down_revision = "000000000003"
15
+ branch_labels = None
16
+ depends_on = None
17
+
18
+
19
+ def upgrade() -> None:
20
+ op.execute("""
21
+ ALTER TABLE dayrate_config
22
+ ADD COLUMN IF NOT EXISTS hold_duration_minutes INTEGER NOT NULL DEFAULT 30;
23
+ """)
24
+
25
+
26
+ def downgrade() -> None:
27
+ op.execute("""
28
+ ALTER TABLE dayrate_config
29
+ DROP COLUMN IF EXISTS hold_duration_minutes;
30
+ """)
@@ -0,0 +1,77 @@
1
+ """resource scoped entitlements
2
+
3
+ Revision ID: 000000000005
4
+ Revises: 000000000004
5
+ Create Date: 2026-02-11
6
+
7
+ Adds resource_type and resource_id columns to the entitlements table
8
+ to support company, org, and system-scoped entitlements in addition
9
+ to user-scoped ones.
10
+ """
11
+
12
+ from alembic import op
13
+
14
+ revision = "000000000005"
15
+ down_revision = "000000000004"
16
+ branch_labels = None
17
+ depends_on = None
18
+
19
+
20
+ def upgrade() -> None:
21
+ # Add resource_type column with default 'user'
22
+ op.execute("""
23
+ ALTER TABLE entitlements
24
+ ADD COLUMN IF NOT EXISTS resource_type VARCHAR NOT NULL DEFAULT 'user';
25
+ """)
26
+
27
+ # Add CHECK constraint for allowed resource_type values
28
+ op.execute("""
29
+ ALTER TABLE entitlements
30
+ ADD CONSTRAINT ck_entitlements_resource_type
31
+ CHECK (resource_type IN ('user', 'company', 'system', 'org'));
32
+ """)
33
+
34
+ # Add resource_id column (nullable UUID)
35
+ op.execute("""
36
+ ALTER TABLE entitlements
37
+ ADD COLUMN IF NOT EXISTS resource_id UUID;
38
+ """)
39
+
40
+ # Add CHECK constraint: resource_id required for company and org types
41
+ op.execute("""
42
+ ALTER TABLE entitlements
43
+ ADD CONSTRAINT ck_entitlements_resource_id_required
44
+ CHECK (
45
+ resource_type NOT IN ('company', 'org')
46
+ OR resource_id IS NOT NULL
47
+ );
48
+ """)
49
+
50
+ # Add partial index for resource lookups
51
+ op.execute("""
52
+ CREATE INDEX IF NOT EXISTS idx_entitlements_resource
53
+ ON entitlements (resource_type, resource_id)
54
+ WHERE resource_id IS NOT NULL;
55
+ """)
56
+
57
+ # Add partial unique index for non-user resource scoping
58
+ op.execute("""
59
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_entitlements_resource_unique
60
+ ON entitlements (application_id, entitlement_key, resource_type, resource_id, source)
61
+ WHERE resource_type != 'user';
62
+ """)
63
+
64
+
65
+ def downgrade() -> None:
66
+ op.execute("DROP INDEX IF EXISTS idx_entitlements_resource_unique;")
67
+ op.execute("DROP INDEX IF EXISTS idx_entitlements_resource;")
68
+ op.execute("""
69
+ ALTER TABLE entitlements
70
+ DROP CONSTRAINT IF EXISTS ck_entitlements_resource_id_required;
71
+ """)
72
+ op.execute("""
73
+ ALTER TABLE entitlements
74
+ DROP CONSTRAINT IF EXISTS ck_entitlements_resource_type;
75
+ """)
76
+ op.execute("ALTER TABLE entitlements DROP COLUMN IF EXISTS resource_id;")
77
+ op.execute("ALTER TABLE entitlements DROP COLUMN IF EXISTS resource_type;")
@@ -0,0 +1,37 @@
1
+ """CFO RBAC: add is_admin to users table
2
+
3
+ Revision ID: 000000000006
4
+ Revises: 000000000005
5
+ Create Date: 2026-02-11
6
+
7
+ Adds is_admin column to users table (formerly user_profiles in the legacy
8
+ Node.js stack, merged into users in the Python rewrite). This provides
9
+ a fast-path admin check for CFO-specific routes without joining
10
+ user_applications.
11
+ """
12
+
13
+ from alembic import op
14
+
15
+ revision = "000000000006"
16
+ down_revision = "000000000005"
17
+ branch_labels = None
18
+ depends_on = None
19
+
20
+
21
+ def upgrade() -> None:
22
+ op.execute("""
23
+ ALTER TABLE users
24
+ ADD COLUMN IF NOT EXISTS is_admin BOOLEAN NOT NULL DEFAULT false;
25
+ """)
26
+
27
+ # Index for quick admin lookups
28
+ op.execute("""
29
+ CREATE INDEX IF NOT EXISTS idx_users_is_admin
30
+ ON users (is_admin)
31
+ WHERE is_admin = true;
32
+ """)
33
+
34
+
35
+ def downgrade() -> None:
36
+ op.execute("DROP INDEX IF EXISTS idx_users_is_admin;")
37
+ op.execute("ALTER TABLE users DROP COLUMN IF EXISTS is_admin;")
@@ -0,0 +1,158 @@
1
+ """agent approvals
2
+
3
+ Revision ID: 000000000007
4
+ Revises: 000000000006
5
+ Create Date: 2026-02-11
6
+
7
+ Creates agents, agent_approvers, and agent_approvals tables for the
8
+ agent consent gateway feature.
9
+ """
10
+
11
+ from alembic import op
12
+
13
+ revision = "000000000007"
14
+ down_revision = "000000000006"
15
+ branch_labels = None
16
+ depends_on = None
17
+
18
+
19
+ def upgrade() -> None:
20
+ # -----------------------------------------------------------------------
21
+ # agents table
22
+ # -----------------------------------------------------------------------
23
+ op.execute("""
24
+ CREATE TABLE IF NOT EXISTS agents (
25
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
26
+ application_id UUID NOT NULL REFERENCES applications(id) ON DELETE CASCADE,
27
+ owner_user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
28
+ name VARCHAR(100) NOT NULL,
29
+ description VARCHAR(500),
30
+ agent_secret_hash VARCHAR(128) NOT NULL,
31
+ agent_secret_prefix VARCHAR(8) NOT NULL,
32
+ scopes JSONB DEFAULT '[]'::jsonb,
33
+ metadata JSONB DEFAULT '{}'::jsonb,
34
+ is_active BOOLEAN NOT NULL DEFAULT true,
35
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
36
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
37
+ );
38
+ """)
39
+
40
+ # Unique name per application (active agents only)
41
+ op.execute("""
42
+ CREATE UNIQUE INDEX IF NOT EXISTS uq_agents_app_name_active
43
+ ON agents (application_id, name)
44
+ WHERE is_active = true;
45
+ """)
46
+
47
+ # Lookup indexes
48
+ op.execute("""
49
+ CREATE INDEX IF NOT EXISTS ix_agents_app_owner
50
+ ON agents (application_id, owner_user_id);
51
+ """)
52
+ op.execute("""
53
+ CREATE INDEX IF NOT EXISTS ix_agents_owner
54
+ ON agents (owner_user_id);
55
+ """)
56
+
57
+ # -----------------------------------------------------------------------
58
+ # agent_approvers table
59
+ # -----------------------------------------------------------------------
60
+ op.execute("""
61
+ CREATE TABLE IF NOT EXISTS agent_approvers (
62
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
63
+ agent_id UUID NOT NULL REFERENCES agents(id) ON DELETE CASCADE,
64
+ approver_user_id UUID REFERENCES users(id) ON DELETE CASCADE,
65
+ approver_agent_id UUID REFERENCES agents(id) ON DELETE CASCADE,
66
+ approver_type VARCHAR(10) NOT NULL,
67
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
68
+
69
+ CONSTRAINT ck_agent_approvers_type
70
+ CHECK (approver_type IN ('user', 'agent')),
71
+
72
+ CONSTRAINT ck_agent_approvers_exactly_one_fk
73
+ CHECK (
74
+ (approver_type = 'user' AND approver_user_id IS NOT NULL AND approver_agent_id IS NULL)
75
+ OR (approver_type = 'agent' AND approver_agent_id IS NOT NULL AND approver_user_id IS NULL)
76
+ )
77
+ );
78
+ """)
79
+
80
+ # Unique approver per agent (user)
81
+ op.execute("""
82
+ CREATE UNIQUE INDEX IF NOT EXISTS uq_agent_approvers_user
83
+ ON agent_approvers (agent_id, approver_user_id)
84
+ WHERE approver_type = 'user';
85
+ """)
86
+
87
+ # Unique approver per agent (agent)
88
+ op.execute("""
89
+ CREATE UNIQUE INDEX IF NOT EXISTS uq_agent_approvers_agent
90
+ ON agent_approvers (agent_id, approver_agent_id)
91
+ WHERE approver_type = 'agent';
92
+ """)
93
+
94
+ # Lookup indexes
95
+ op.execute("""
96
+ CREATE INDEX IF NOT EXISTS ix_agent_approvers_agent
97
+ ON agent_approvers (agent_id);
98
+ """)
99
+ op.execute("""
100
+ CREATE INDEX IF NOT EXISTS ix_agent_approvers_user
101
+ ON agent_approvers (approver_user_id)
102
+ WHERE approver_user_id IS NOT NULL;
103
+ """)
104
+ op.execute("""
105
+ CREATE INDEX IF NOT EXISTS ix_agent_approvers_agent_id
106
+ ON agent_approvers (approver_agent_id)
107
+ WHERE approver_agent_id IS NOT NULL;
108
+ """)
109
+
110
+ # -----------------------------------------------------------------------
111
+ # agent_approvals table
112
+ # -----------------------------------------------------------------------
113
+ op.execute("""
114
+ CREATE TABLE IF NOT EXISTS agent_approvals (
115
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
116
+ application_id UUID NOT NULL REFERENCES applications(id) ON DELETE CASCADE,
117
+ agent_id UUID NOT NULL REFERENCES agents(id) ON DELETE CASCADE,
118
+ code VARCHAR(9) NOT NULL UNIQUE,
119
+ action VARCHAR(200) NOT NULL,
120
+ resource_type VARCHAR(100),
121
+ resource_id VARCHAR(500),
122
+ reason VARCHAR(1000),
123
+ metadata JSONB DEFAULT '{}'::jsonb,
124
+ status VARCHAR(20) NOT NULL DEFAULT 'pending',
125
+ callback_url VARCHAR(2048),
126
+ note VARCHAR(500),
127
+ responded_by_user_id UUID REFERENCES users(id) ON DELETE SET NULL,
128
+ responded_by_agent_id UUID REFERENCES agents(id) ON DELETE SET NULL,
129
+ responder_type VARCHAR(10),
130
+ responded_at TIMESTAMPTZ,
131
+ approval_token TEXT,
132
+ token_expires_at TIMESTAMPTZ,
133
+ expires_at TIMESTAMPTZ NOT NULL,
134
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
135
+
136
+ CONSTRAINT ck_agent_approvals_status
137
+ CHECK (status IN ('pending', 'approved', 'denied', 'expired'))
138
+ );
139
+ """)
140
+
141
+ # Composite index for agent polling
142
+ op.execute("""
143
+ CREATE INDEX IF NOT EXISTS ix_agent_approvals_app_agent_status
144
+ ON agent_approvals (application_id, agent_id, status);
145
+ """)
146
+
147
+ # Partial index for expiration cleanup
148
+ op.execute("""
149
+ CREATE INDEX IF NOT EXISTS ix_agent_approvals_pending_expiry
150
+ ON agent_approvals (status, expires_at)
151
+ WHERE status = 'pending';
152
+ """)
153
+
154
+
155
+ def downgrade() -> None:
156
+ op.execute("DROP TABLE IF EXISTS agent_approvals CASCADE;")
157
+ op.execute("DROP TABLE IF EXISTS agent_approvers CASCADE;")
158
+ op.execute("DROP TABLE IF EXISTS agents CASCADE;")
@@ -0,0 +1,35 @@
1
+ """add company_id to cfo_connections
2
+
3
+ Revision ID: 000000000008
4
+ Revises: 000000000007
5
+ Create Date: 2026-02-12
6
+
7
+ Adds a nullable company_id UUID column to the cfo_connections table.
8
+ This is a soft reference to cfo_companies.id in the CFO database.
9
+ No foreign key constraint — the reference is cross-database.
10
+ """
11
+
12
+ from alembic import op
13
+
14
+ revision = "000000000008"
15
+ down_revision = "000000000007"
16
+ branch_labels = None
17
+ depends_on = None
18
+
19
+
20
+ def upgrade() -> None:
21
+ op.execute("""
22
+ ALTER TABLE cfo_connections
23
+ ADD COLUMN IF NOT EXISTS company_id UUID NULL;
24
+ """)
25
+ op.execute("""
26
+ COMMENT ON COLUMN cfo_connections.company_id
27
+ IS 'Soft reference to cfo_companies.id in CFO DB (no FK constraint)';
28
+ """)
29
+
30
+
31
+ def downgrade() -> None:
32
+ op.execute("""
33
+ ALTER TABLE cfo_connections
34
+ DROP COLUMN IF EXISTS company_id;
35
+ """)
@@ -0,0 +1,62 @@
1
+ """Add transaction signing fields to agent_approvals
2
+
3
+ Revision ID: 000000000009
4
+ Revises: 000000000008
5
+ Create Date: 2026-02-13
6
+
7
+ Add 4 nullable columns to agent_approvals to support transaction intent
8
+ and wallet signing (tx_signing):
9
+ - transaction_intent: JSONB storing EVM/Solana transaction intent
10
+ - signed_transaction: TEXT storing hex/base64 signed transaction bytes
11
+ - signer_address: TEXT storing wallet address that signed
12
+ - edited_intent: JSONB storing modified intent if approver edited
13
+
14
+ All columns are nullable for backward compatibility.
15
+ """
16
+
17
+ from alembic import op
18
+
19
+ revision = "000000000009"
20
+ down_revision = "000000000008"
21
+ branch_labels = None
22
+ depends_on = None
23
+
24
+
25
+ def upgrade() -> None:
26
+ """Add transaction signing fields to agent_approvals."""
27
+ op.execute("""
28
+ ALTER TABLE agent_approvals
29
+ ADD COLUMN transaction_intent JSONB;
30
+ """)
31
+ op.execute("""
32
+ ALTER TABLE agent_approvals
33
+ ADD COLUMN signed_transaction TEXT;
34
+ """)
35
+ op.execute("""
36
+ ALTER TABLE agent_approvals
37
+ ADD COLUMN signer_address VARCHAR(500);
38
+ """)
39
+ op.execute("""
40
+ ALTER TABLE agent_approvals
41
+ ADD COLUMN edited_intent JSONB;
42
+ """)
43
+
44
+
45
+ def downgrade() -> None:
46
+ """Remove transaction signing fields from agent_approvals."""
47
+ op.execute("""
48
+ ALTER TABLE agent_approvals
49
+ DROP COLUMN IF EXISTS transaction_intent;
50
+ """)
51
+ op.execute("""
52
+ ALTER TABLE agent_approvals
53
+ DROP COLUMN IF EXISTS signed_transaction;
54
+ """)
55
+ op.execute("""
56
+ ALTER TABLE agent_approvals
57
+ DROP COLUMN IF EXISTS signer_address;
58
+ """)
59
+ op.execute("""
60
+ ALTER TABLE agent_approvals
61
+ DROP COLUMN IF EXISTS edited_intent;
62
+ """)