optimal-cli 1.0.1 → 1.1.0
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/.claude-plugin/marketplace.json +18 -0
- package/.claude-plugin/plugin.json +10 -0
- package/.env.example +17 -0
- package/CLAUDE.md +67 -0
- package/COMMANDS.md +264 -0
- package/PUBLISH.md +70 -0
- package/agents/content-ops.md +2 -2
- package/agents/financial-ops.md +2 -2
- package/agents/infra-ops.md +2 -2
- package/apps/.gitkeep +0 -0
- package/bin/optimal.ts +1418 -0
- package/docs/MIGRATION_NEEDED.md +37 -0
- package/docs/plans/.gitkeep +0 -0
- package/docs/plans/optimal-cli-config-registry-v1.md +71 -0
- package/hooks/.gitkeep +0 -0
- package/lib/budget/projections.ts +561 -0
- package/lib/budget/scenarios.ts +312 -0
- package/lib/cms/publish-blog.ts +129 -0
- package/lib/cms/strapi-client.ts +302 -0
- package/lib/config/registry.ts +229 -0
- package/lib/config/schema.ts +58 -0
- package/lib/config.ts +247 -0
- package/lib/infra/.gitkeep +0 -0
- package/lib/infra/deploy.ts +70 -0
- package/lib/infra/migrate.ts +141 -0
- package/lib/kanban-obsidian.ts +232 -0
- package/lib/kanban-sync.ts +258 -0
- package/lib/kanban.ts +239 -0
- package/lib/newsletter/.gitkeep +0 -0
- package/lib/newsletter/distribute.ts +256 -0
- package/{dist/lib/newsletter/generate-insurance.d.ts → lib/newsletter/generate-insurance.ts} +24 -7
- package/lib/newsletter/generate.ts +735 -0
- package/lib/obsidian-tasks.ts +231 -0
- package/lib/returnpro/.gitkeep +0 -0
- package/lib/returnpro/anomalies.ts +258 -0
- package/lib/returnpro/audit.ts +194 -0
- package/lib/returnpro/diagnose.ts +400 -0
- package/lib/returnpro/kpis.ts +255 -0
- package/lib/returnpro/templates.ts +323 -0
- package/lib/returnpro/upload-income.ts +311 -0
- package/lib/returnpro/upload-netsuite.ts +696 -0
- package/lib/returnpro/upload-r1.ts +563 -0
- package/lib/social/post-generator.ts +468 -0
- package/lib/social/publish.ts +301 -0
- package/lib/social/scraper.ts +503 -0
- package/lib/supabase.ts +25 -0
- package/lib/transactions/delete-batch.ts +258 -0
- package/lib/transactions/ingest.ts +659 -0
- package/lib/transactions/stamp.ts +654 -0
- package/package.json +5 -18
- package/pnpm-workspace.yaml +3 -0
- package/scripts/check-table.ts +24 -0
- package/scripts/create-tables.ts +94 -0
- package/scripts/migrate-kanban.sh +28 -0
- package/scripts/migrate-v2.ts +78 -0
- package/scripts/migrate.ts +79 -0
- package/scripts/run-migration.ts +59 -0
- package/scripts/seed-board.ts +203 -0
- package/scripts/test-kanban.ts +21 -0
- package/skills/audit-financials/SKILL.md +33 -0
- package/skills/board-create/SKILL.md +28 -0
- package/skills/board-update/SKILL.md +27 -0
- package/skills/board-view/SKILL.md +27 -0
- package/skills/delete-batch/SKILL.md +77 -0
- package/skills/deploy/SKILL.md +40 -0
- package/skills/diagnose-months/SKILL.md +68 -0
- package/skills/distribute-newsletter/SKILL.md +58 -0
- package/skills/export-budget/SKILL.md +44 -0
- package/skills/export-kpis/SKILL.md +52 -0
- package/skills/generate-netsuite-template/SKILL.md +51 -0
- package/skills/generate-newsletter/SKILL.md +53 -0
- package/skills/generate-newsletter-insurance/SKILL.md +59 -0
- package/skills/generate-social-posts/SKILL.md +67 -0
- package/skills/health-check/SKILL.md +42 -0
- package/skills/ingest-transactions/SKILL.md +51 -0
- package/skills/manage-cms/SKILL.md +50 -0
- package/skills/manage-scenarios/SKILL.md +83 -0
- package/skills/migrate-db/SKILL.md +79 -0
- package/skills/preview-newsletter/SKILL.md +50 -0
- package/skills/project-budget/SKILL.md +60 -0
- package/skills/publish-blog/SKILL.md +70 -0
- package/skills/publish-social-posts/SKILL.md +70 -0
- package/skills/rate-anomalies/SKILL.md +62 -0
- package/skills/scrape-ads/SKILL.md +49 -0
- package/skills/stamp-transactions/SKILL.md +62 -0
- package/skills/upload-income-statements/SKILL.md +54 -0
- package/skills/upload-netsuite/SKILL.md +56 -0
- package/skills/upload-r1/SKILL.md +45 -0
- package/supabase/.temp/cli-latest +1 -0
- package/supabase/migrations/.gitkeep +0 -0
- package/supabase/migrations/20250305000001_create_agent_configs.sql +36 -0
- package/supabase/migrations/20260305111300_create_cli_config_registry.sql +22 -0
- package/supabase/migrations/20260306195000_create_kanban_tables.sql +97 -0
- package/tests/config-command-smoke.test.ts +395 -0
- package/tests/config-registry.test.ts +173 -0
- package/tsconfig.json +19 -0
- package/agents/profiles.json +0 -5
- package/dist/bin/optimal.d.ts +0 -2
- package/dist/bin/optimal.js +0 -1590
- package/dist/lib/assets/index.d.ts +0 -79
- package/dist/lib/assets/index.js +0 -153
- package/dist/lib/assets.d.ts +0 -20
- package/dist/lib/assets.js +0 -112
- package/dist/lib/auth/index.d.ts +0 -83
- package/dist/lib/auth/index.js +0 -146
- package/dist/lib/board/index.d.ts +0 -39
- package/dist/lib/board/index.js +0 -285
- package/dist/lib/board/types.d.ts +0 -111
- package/dist/lib/board/types.js +0 -1
- package/dist/lib/bot/claim.d.ts +0 -3
- package/dist/lib/bot/claim.js +0 -20
- package/dist/lib/bot/coordinator.d.ts +0 -27
- package/dist/lib/bot/coordinator.js +0 -178
- package/dist/lib/bot/heartbeat.d.ts +0 -6
- package/dist/lib/bot/heartbeat.js +0 -30
- package/dist/lib/bot/index.d.ts +0 -9
- package/dist/lib/bot/index.js +0 -6
- package/dist/lib/bot/protocol.d.ts +0 -12
- package/dist/lib/bot/protocol.js +0 -74
- package/dist/lib/bot/reporter.d.ts +0 -3
- package/dist/lib/bot/reporter.js +0 -27
- package/dist/lib/bot/skills.d.ts +0 -26
- package/dist/lib/bot/skills.js +0 -69
- package/dist/lib/budget/projections.d.ts +0 -115
- package/dist/lib/budget/projections.js +0 -384
- package/dist/lib/budget/scenarios.d.ts +0 -93
- package/dist/lib/budget/scenarios.js +0 -214
- package/dist/lib/cms/publish-blog.d.ts +0 -62
- package/dist/lib/cms/publish-blog.js +0 -74
- package/dist/lib/cms/strapi-client.d.ts +0 -123
- package/dist/lib/cms/strapi-client.js +0 -213
- package/dist/lib/config/registry.d.ts +0 -17
- package/dist/lib/config/registry.js +0 -182
- package/dist/lib/config/schema.d.ts +0 -31
- package/dist/lib/config/schema.js +0 -25
- package/dist/lib/config.d.ts +0 -55
- package/dist/lib/config.js +0 -206
- package/dist/lib/errors.d.ts +0 -25
- package/dist/lib/errors.js +0 -91
- package/dist/lib/format.d.ts +0 -28
- package/dist/lib/format.js +0 -98
- package/dist/lib/infra/deploy.d.ts +0 -29
- package/dist/lib/infra/deploy.js +0 -58
- package/dist/lib/infra/migrate.d.ts +0 -34
- package/dist/lib/infra/migrate.js +0 -103
- package/dist/lib/newsletter/distribute.d.ts +0 -52
- package/dist/lib/newsletter/distribute.js +0 -193
- package/dist/lib/newsletter/generate-insurance.js +0 -36
- package/dist/lib/newsletter/generate.d.ts +0 -104
- package/dist/lib/newsletter/generate.js +0 -571
- package/dist/lib/returnpro/anomalies.d.ts +0 -64
- package/dist/lib/returnpro/anomalies.js +0 -166
- package/dist/lib/returnpro/audit.d.ts +0 -32
- package/dist/lib/returnpro/audit.js +0 -147
- package/dist/lib/returnpro/diagnose.d.ts +0 -52
- package/dist/lib/returnpro/diagnose.js +0 -281
- package/dist/lib/returnpro/kpis.d.ts +0 -32
- package/dist/lib/returnpro/kpis.js +0 -192
- package/dist/lib/returnpro/templates.d.ts +0 -48
- package/dist/lib/returnpro/templates.js +0 -229
- package/dist/lib/returnpro/upload-income.d.ts +0 -25
- package/dist/lib/returnpro/upload-income.js +0 -235
- package/dist/lib/returnpro/upload-netsuite.d.ts +0 -37
- package/dist/lib/returnpro/upload-netsuite.js +0 -566
- package/dist/lib/returnpro/upload-r1.d.ts +0 -48
- package/dist/lib/returnpro/upload-r1.js +0 -398
- package/dist/lib/returnpro/validate.d.ts +0 -37
- package/dist/lib/returnpro/validate.js +0 -124
- package/dist/lib/social/meta.d.ts +0 -90
- package/dist/lib/social/meta.js +0 -160
- package/dist/lib/social/post-generator.d.ts +0 -83
- package/dist/lib/social/post-generator.js +0 -333
- package/dist/lib/social/publish.d.ts +0 -66
- package/dist/lib/social/publish.js +0 -226
- package/dist/lib/social/scraper.d.ts +0 -67
- package/dist/lib/social/scraper.js +0 -361
- package/dist/lib/supabase.d.ts +0 -4
- package/dist/lib/supabase.js +0 -20
- package/dist/lib/transactions/delete-batch.d.ts +0 -60
- package/dist/lib/transactions/delete-batch.js +0 -203
- package/dist/lib/transactions/ingest.d.ts +0 -43
- package/dist/lib/transactions/ingest.js +0 -555
- package/dist/lib/transactions/stamp.d.ts +0 -51
- package/dist/lib/transactions/stamp.js +0 -524
- package/docs/CLI-REFERENCE.md +0 -361
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { createClient } from '@supabase/supabase-js'
|
|
2
|
+
|
|
3
|
+
const url = 'https://hbfalrpswysryltysonm.supabase.co'
|
|
4
|
+
const key = process.env.OPTIMAL_SUPABASE_SERVICE_KEY || 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImhiZmFscnBzd3lzcnlsdHlzb25tIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTczODI0NTY0NywiZXhwIjoyMDUzODIxNjQ3fQ.placeholder'
|
|
5
|
+
|
|
6
|
+
const supabase = createClient(url, key)
|
|
7
|
+
|
|
8
|
+
async function checkTable() {
|
|
9
|
+
// Try to query the table
|
|
10
|
+
const { data, error } = await supabase
|
|
11
|
+
.from('agent_configs')
|
|
12
|
+
.select('*')
|
|
13
|
+
.limit(1)
|
|
14
|
+
|
|
15
|
+
if (error) {
|
|
16
|
+
console.log('Table status:', error.code === '42P01' ? 'DOES NOT EXIST' : 'ERROR')
|
|
17
|
+
console.log('Error:', error.message)
|
|
18
|
+
} else {
|
|
19
|
+
console.log('Table status: EXISTS')
|
|
20
|
+
console.log('Rows:', data.length)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
checkTable()
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run kanban migration - creates tables in supabase
|
|
3
|
+
*/
|
|
4
|
+
import { createClient } from '@supabase/supabase-js'
|
|
5
|
+
|
|
6
|
+
const SUPABASE_URL = 'https://vvutttwunexshxkmygik.supabase.co'
|
|
7
|
+
const SUPABASE_SERVICE_KEY = 'sb_secret_zokm_eFGX9ENuRV8hKA05Q_JQDOEOOl'
|
|
8
|
+
|
|
9
|
+
const supabase = createClient(SUPABASE_URL, SUPABASE_SERVICE_KEY, {
|
|
10
|
+
db: { schema: 'public' }
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
const sql = `
|
|
14
|
+
-- Projects table
|
|
15
|
+
CREATE TABLE IF NOT EXISTS cli_projects (
|
|
16
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
17
|
+
slug TEXT UNIQUE NOT NULL,
|
|
18
|
+
name TEXT NOT NULL,
|
|
19
|
+
description TEXT,
|
|
20
|
+
status TEXT DEFAULT 'active' CHECK (status IN ('active', 'archived', 'on_hold')),
|
|
21
|
+
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
22
|
+
updated_at TIMESTAMPTZ DEFAULT NOW()
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
-- Tasks table
|
|
26
|
+
CREATE TABLE IF NOT EXISTS cli_tasks (
|
|
27
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
28
|
+
project_id UUID REFERENCES cli_projects(id) ON DELETE CASCADE,
|
|
29
|
+
task_id TEXT NOT NULL,
|
|
30
|
+
title TEXT NOT NULL,
|
|
31
|
+
description TEXT,
|
|
32
|
+
status TEXT DEFAULT 'pending' CHECK (status IN ('pending', 'in_progress', 'done', 'cancelled')),
|
|
33
|
+
priority INTEGER DEFAULT 3 CHECK (priority BETWEEN 1 AND 4),
|
|
34
|
+
owner TEXT,
|
|
35
|
+
assignee TEXT,
|
|
36
|
+
tags JSONB DEFAULT '[]',
|
|
37
|
+
source TEXT,
|
|
38
|
+
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
39
|
+
updated_at TIMESTAMPTZ DEFAULT NOW(),
|
|
40
|
+
completed_at TIMESTAMPTZ,
|
|
41
|
+
completed_by TEXT,
|
|
42
|
+
metadata JSONB DEFAULT '{}',
|
|
43
|
+
UNIQUE(project_id, task_id)
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
-- Sync log
|
|
47
|
+
CREATE TABLE IF NOT EXISTS cli_sync_log (
|
|
48
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
49
|
+
entity_type TEXT NOT NULL,
|
|
50
|
+
entity_id UUID NOT NULL,
|
|
51
|
+
action TEXT NOT NULL,
|
|
52
|
+
source TEXT NOT NULL,
|
|
53
|
+
synced_at TIMESTAMPTZ DEFAULT NOW(),
|
|
54
|
+
payload JSONB
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
-- Indexes
|
|
58
|
+
CREATE INDEX IF NOT EXISTS idx_tasks_project ON cli_tasks(project_id);
|
|
59
|
+
CREATE INDEX IF NOT EXISTS idx_tasks_status ON cli_tasks(status);
|
|
60
|
+
CREATE INDEX IF NOT EXISTS idx_tasks_owner ON cli_tasks(owner);
|
|
61
|
+
CREATE INDEX IF NOT EXISTS idx_tasks_assignee ON cli_tasks(assignee);
|
|
62
|
+
`
|
|
63
|
+
|
|
64
|
+
async function main() {
|
|
65
|
+
console.log('Running migration...')
|
|
66
|
+
|
|
67
|
+
// Run raw SQL via postgrest
|
|
68
|
+
const { data, error } = await supabase.rpc('pg_catalog.exec', {
|
|
69
|
+
query: sql
|
|
70
|
+
}).catch(() => {
|
|
71
|
+
// Fallback: try via REST directly
|
|
72
|
+
return supabase.from('_temp').select('*').limit(0)
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
// Actually, rpc won't work - let's just create tables one by one via insert
|
|
76
|
+
// Since we can't run raw SQL easily, let's try a different approach
|
|
77
|
+
console.log('Trying alternative...')
|
|
78
|
+
|
|
79
|
+
// Check if tables exist
|
|
80
|
+
const { data: tables } = await supabase
|
|
81
|
+
.from('information_schema.tables')
|
|
82
|
+
.select('table_name')
|
|
83
|
+
.eq('table_schema', 'public')
|
|
84
|
+
.in('table_name', ['cli_projects', 'cli_tasks'])
|
|
85
|
+
|
|
86
|
+
console.log('Existing tables:', tables)
|
|
87
|
+
|
|
88
|
+
if (!tables?.length) {
|
|
89
|
+
console.log('Tables do not exist. Trying to create via console...')
|
|
90
|
+
console.log('Please run manually or use supabase studio.')
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
main().catch(console.error)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Migrate kanban tables to supabase
|
|
3
|
+
|
|
4
|
+
SQL_FILE="supabase/migrations/20260306195000_create_kanban_tables.sql"
|
|
5
|
+
|
|
6
|
+
# Load env from workspace secrets
|
|
7
|
+
if [ -f ".secrets/dashboard-returnpro.vercel.env" ]; then
|
|
8
|
+
export "$(cat .secrets/dashboard-returnpro.vercel.env | grep -v '^#' | xargs)"
|
|
9
|
+
fi
|
|
10
|
+
|
|
11
|
+
# Check for supabase URL and key
|
|
12
|
+
if [ -z "$SUPABASE_URL" ] || [ -z "$SUPABASE_SERVICE_ROLE_KEY" ]; then
|
|
13
|
+
echo "Error: SUPABASE_URL or SUPABASE_SERVICE_ROLE_KEY not found"
|
|
14
|
+
exit 1
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
echo "Applying migration..."
|
|
18
|
+
echo "SUPABASE_URL: $SUPABASE_URL"
|
|
19
|
+
|
|
20
|
+
# Use psql if available, otherwise try with supabase cli
|
|
21
|
+
if command -v psql &> /dev/null; then
|
|
22
|
+
# Extract password from the key (it's after the = sign)
|
|
23
|
+
DB_PASS="${SUPABASE_SERVICE_ROLE_KEY##*=}"
|
|
24
|
+
psql "host=vvutttwunexshxkmygik.supabase.co port=5432 dbname=postgres user=postgres password=$DB_PASS" -f "$SQL_FILE" 2>&1
|
|
25
|
+
else
|
|
26
|
+
echo "psql not available, trying supabase cli..."
|
|
27
|
+
npx supabase db push 2>&1
|
|
28
|
+
fi
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { createClient } from '@supabase/supabase-js'
|
|
2
|
+
|
|
3
|
+
const url = 'https://hbfalrpswysryltysonm.supabase.co'
|
|
4
|
+
const key = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImhiZmFscnBzd3lzcnlsdHlzb25tIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTc0MjIzMTEyMiwiZXhwIjoyMDU3ODA3MTIyfQ.oyzf_We-WCOsJ8xYs2_Q9wi8QSBr_1Ym_F_75o67kR0'
|
|
5
|
+
|
|
6
|
+
const supabase = createClient(url, key)
|
|
7
|
+
|
|
8
|
+
async function runMigration() {
|
|
9
|
+
console.log('🔧 Running migration: agent_configs table')
|
|
10
|
+
console.log(` URL: ${url}`)
|
|
11
|
+
console.log('')
|
|
12
|
+
|
|
13
|
+
// Test connection first
|
|
14
|
+
const { data: testData, error: testError } = await supabase
|
|
15
|
+
.from('agent_configs')
|
|
16
|
+
.select('count')
|
|
17
|
+
.limit(1)
|
|
18
|
+
|
|
19
|
+
if (testError?.code === '42P01') {
|
|
20
|
+
console.log(' Table does not exist. Creating...')
|
|
21
|
+
} else if (testError) {
|
|
22
|
+
console.log(' Error checking table:', testError.message)
|
|
23
|
+
} else {
|
|
24
|
+
console.log(' ✓ Table already exists')
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Create table using raw SQL
|
|
29
|
+
const sql = `
|
|
30
|
+
CREATE TABLE IF NOT EXISTS agent_configs (
|
|
31
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
32
|
+
agent_name TEXT NOT NULL UNIQUE,
|
|
33
|
+
config_json JSONB NOT NULL DEFAULT '{}',
|
|
34
|
+
version TEXT NOT NULL DEFAULT '0.0.0',
|
|
35
|
+
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
36
|
+
updated_at TIMESTAMPTZ DEFAULT NOW()
|
|
37
|
+
);
|
|
38
|
+
`
|
|
39
|
+
|
|
40
|
+
// Try using the SQL API directly
|
|
41
|
+
const response = await fetch(`${url}/rest/v1/`, {
|
|
42
|
+
method: 'POST',
|
|
43
|
+
headers: {
|
|
44
|
+
'Content-Type': 'application/json',
|
|
45
|
+
'Authorization': `Bearer ${key}`,
|
|
46
|
+
'apikey': key,
|
|
47
|
+
'Prefer': 'tx=rollback'
|
|
48
|
+
},
|
|
49
|
+
body: JSON.stringify({ query: sql })
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
console.log(' Response status:', response.status)
|
|
53
|
+
|
|
54
|
+
if (response.status === 404 || response.status === 400) {
|
|
55
|
+
console.log('')
|
|
56
|
+
console.log('⚠️ Cannot run migration via REST API.')
|
|
57
|
+
console.log('')
|
|
58
|
+
console.log('Please run this SQL in Supabase SQL Editor:')
|
|
59
|
+
console.log('')
|
|
60
|
+
console.log('━'.repeat(60))
|
|
61
|
+
console.log(sql)
|
|
62
|
+
console.log('━'.repeat(60))
|
|
63
|
+
console.log('')
|
|
64
|
+
console.log('Then run:')
|
|
65
|
+
console.log(' CREATE INDEX idx_agent_configs_name ON agent_configs(agent_name);')
|
|
66
|
+
console.log(' ALTER TABLE agent_configs ENABLE ROW LEVEL SECURITY;')
|
|
67
|
+
console.log(' CREATE POLICY "Service role full access" ON agent_configs FOR ALL TO service_role USING (true) WITH CHECK (true);')
|
|
68
|
+
process.exit(1)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const text = await response.text()
|
|
72
|
+
console.log(' Response:', text.slice(0, 200))
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
runMigration().catch(err => {
|
|
76
|
+
console.error('❌ Migration failed:', err)
|
|
77
|
+
process.exit(1)
|
|
78
|
+
})
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { createClient } from '@supabase/supabase-js'
|
|
2
|
+
|
|
3
|
+
const url = 'https://hbfalrpswysryltysonm.supabase.co'
|
|
4
|
+
const key = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImhiZmFscnBzd3lzcnlsdHlzb25tIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTc0MjIzMTEyMiwiZXhwIjoyMDU3ODA3MTIyfQ.oyzf_We-WCOsJ8xYs2_Q9wi8QSBr_1Ym_F_75o67kR0'
|
|
5
|
+
|
|
6
|
+
const supabase = createClient(url, key)
|
|
7
|
+
|
|
8
|
+
async function createTable() {
|
|
9
|
+
console.log('🔧 Creating agent_configs table...')
|
|
10
|
+
|
|
11
|
+
// Create table using raw SQL via RPC or direct query
|
|
12
|
+
const createTableSQL = `
|
|
13
|
+
CREATE TABLE IF NOT EXISTS agent_configs (
|
|
14
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
15
|
+
agent_name TEXT NOT NULL UNIQUE,
|
|
16
|
+
config_json JSONB NOT NULL DEFAULT '{}',
|
|
17
|
+
version TEXT NOT NULL DEFAULT '0.0.0',
|
|
18
|
+
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
19
|
+
updated_at TIMESTAMPTZ DEFAULT NOW()
|
|
20
|
+
);
|
|
21
|
+
`
|
|
22
|
+
|
|
23
|
+
// Try to create the table by inserting and letting it fail if exists
|
|
24
|
+
const { error: insertError } = await supabase
|
|
25
|
+
.from('agent_configs')
|
|
26
|
+
.insert({
|
|
27
|
+
agent_name: '__test__',
|
|
28
|
+
config_json: {},
|
|
29
|
+
version: '0.0.0'
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
if (insertError?.code === '42P01') {
|
|
33
|
+
console.log(' Table does not exist. Creating via SQL...')
|
|
34
|
+
|
|
35
|
+
// Use the SQL API
|
|
36
|
+
const response = await fetch(`${url}/rest/v1/rpc/exec_sql`, {
|
|
37
|
+
method: 'POST',
|
|
38
|
+
headers: {
|
|
39
|
+
'Content-Type': 'application/json',
|
|
40
|
+
'Authorization': `Bearer ${key}`,
|
|
41
|
+
'apikey': key
|
|
42
|
+
},
|
|
43
|
+
body: JSON.stringify({ sql: createTableSQL })
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
if (!response.ok) {
|
|
47
|
+
const text = await response.text()
|
|
48
|
+
console.log(' RPC failed, trying alternative...')
|
|
49
|
+
console.log(' Error:', text.slice(0, 200))
|
|
50
|
+
|
|
51
|
+
// Alternative: create via pg_graphql or direct postgrest
|
|
52
|
+
console.log(' Please run this SQL in Supabase SQL Editor:')
|
|
53
|
+
console.log('')
|
|
54
|
+
console.log(createTableSQL)
|
|
55
|
+
console.log('')
|
|
56
|
+
console.log(' Then run:')
|
|
57
|
+
console.log(' CREATE INDEX idx_agent_configs_name ON agent_configs(agent_name);')
|
|
58
|
+
console.log(' ALTER TABLE agent_configs ENABLE ROW LEVEL SECURITY;')
|
|
59
|
+
process.exit(1)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
console.log(' ✓ Table created')
|
|
63
|
+
} else if (insertError?.code === '23505') {
|
|
64
|
+
console.log(' ✓ Table already exists (unique constraint violation on test insert)')
|
|
65
|
+
// Clean up test row
|
|
66
|
+
await supabase.from('agent_configs').delete().eq('agent_name', '__test__')
|
|
67
|
+
} else if (insertError) {
|
|
68
|
+
console.log(' Error:', insertError.message)
|
|
69
|
+
} else {
|
|
70
|
+
console.log(' ✓ Table exists and is writable')
|
|
71
|
+
// Clean up test row
|
|
72
|
+
await supabase.from('agent_configs').delete().eq('agent_name', '__test__')
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
console.log('')
|
|
76
|
+
console.log('✅ Migration complete!')
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
createTable().catch(console.error)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { createClient } from '@supabase/supabase-js'
|
|
2
|
+
|
|
3
|
+
const url = process.env.OPTIMAL_SUPABASE_URL!
|
|
4
|
+
const key = process.env.OPTIMAL_SUPABASE_SERVICE_KEY!
|
|
5
|
+
|
|
6
|
+
const supabase = createClient(url, key)
|
|
7
|
+
|
|
8
|
+
// Create the table via SQL query
|
|
9
|
+
const sql = `
|
|
10
|
+
create table if not exists public.cli_config_registry (
|
|
11
|
+
id uuid primary key default gen_random_uuid(),
|
|
12
|
+
owner text not null,
|
|
13
|
+
profile text not null default 'default',
|
|
14
|
+
config_version text not null,
|
|
15
|
+
payload jsonb not null,
|
|
16
|
+
payload_hash text not null,
|
|
17
|
+
source text not null default 'optimal-cli',
|
|
18
|
+
updated_by text,
|
|
19
|
+
updated_at timestamptz not null default now(),
|
|
20
|
+
created_at timestamptz not null default now(),
|
|
21
|
+
unique (owner, profile)
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
create index if not exists idx_cli_config_registry_owner_profile
|
|
25
|
+
on public.cli_config_registry (owner, profile);
|
|
26
|
+
|
|
27
|
+
create index if not exists idx_cli_config_registry_updated_at
|
|
28
|
+
on public.cli_config_registry (updated_at desc);
|
|
29
|
+
`
|
|
30
|
+
|
|
31
|
+
const { data, error } = await supabase.rpc('pg_execute', { sql_text: sql })
|
|
32
|
+
|
|
33
|
+
if (error) {
|
|
34
|
+
console.error('Migration failed:', error)
|
|
35
|
+
// Try alternative approach
|
|
36
|
+
console.log('Attempting alternative table creation...')
|
|
37
|
+
|
|
38
|
+
// Just verify table exists by querying
|
|
39
|
+
const { data: test, error: testErr } = await supabase
|
|
40
|
+
.from('cli_config_registry')
|
|
41
|
+
.select('count')
|
|
42
|
+
.limit(1)
|
|
43
|
+
|
|
44
|
+
if (testErr && testErr.code !== '42P01') {
|
|
45
|
+
console.error('Table verification failed:', testErr)
|
|
46
|
+
process.exit(1)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (testErr?.code === '42P01') {
|
|
50
|
+
console.error('Table cli_config_registry does not exist and could not be created.')
|
|
51
|
+
console.error('Please run this SQL manually in Supabase SQL Editor:')
|
|
52
|
+
console.log(sql)
|
|
53
|
+
process.exit(1)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
console.log('Table exists!')
|
|
57
|
+
} else {
|
|
58
|
+
console.log('Migration applied successfully')
|
|
59
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* Seed the kanban board with the full implementation backlog.
|
|
4
|
+
* Idempotent — checks existing tasks by title before creating.
|
|
5
|
+
*
|
|
6
|
+
* Usage: npx tsx scripts/seed-board.ts
|
|
7
|
+
*/
|
|
8
|
+
import 'dotenv/config'
|
|
9
|
+
import { createTask, getBoard } from '../lib/kanban.js'
|
|
10
|
+
|
|
11
|
+
const PROJECT_SLUG = 'optimal-cli-refactor'
|
|
12
|
+
|
|
13
|
+
interface SeedTask {
|
|
14
|
+
title: string
|
|
15
|
+
skill_ref?: string
|
|
16
|
+
priority: 1 | 2 | 3 | 4
|
|
17
|
+
labels: string[]
|
|
18
|
+
description?: string
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const tasks: SeedTask[] = [
|
|
22
|
+
// --- Phase 2 follow-ups (ready — no blockers) ---
|
|
23
|
+
{
|
|
24
|
+
title: 'Implement upload-r1 lib function',
|
|
25
|
+
skill_ref: '/upload-r1',
|
|
26
|
+
priority: 2,
|
|
27
|
+
labels: ['returnpro', 'phase-2'],
|
|
28
|
+
description: 'Extract R1 marketplace data upload from dashboard-returnpro into lib/returnpro/upload-r1.ts',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
title: 'Implement upload-netsuite lib function',
|
|
32
|
+
skill_ref: '/upload-netsuite',
|
|
33
|
+
priority: 2,
|
|
34
|
+
labels: ['returnpro', 'phase-2'],
|
|
35
|
+
description: 'Extract NetSuite XLSM upload pipeline into lib/returnpro/upload-netsuite.ts',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
title: 'Implement upload-income-statements lib function',
|
|
39
|
+
skill_ref: '/upload-income-statements',
|
|
40
|
+
priority: 2,
|
|
41
|
+
labels: ['returnpro', 'phase-2'],
|
|
42
|
+
description: 'Extract confirmed income statement CSV upload into lib/returnpro/upload-income-statements.ts',
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
title: 'Implement rate-anomalies lib function',
|
|
46
|
+
skill_ref: '/rate-anomalies',
|
|
47
|
+
priority: 3,
|
|
48
|
+
labels: ['returnpro', 'phase-2'],
|
|
49
|
+
description: 'Extract rate anomaly detection logic from dashboard-returnpro into lib/returnpro/rate-anomalies.ts',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
title: 'Implement diagnose-months lib function',
|
|
53
|
+
skill_ref: '/diagnose-months',
|
|
54
|
+
priority: 3,
|
|
55
|
+
labels: ['returnpro', 'phase-2'],
|
|
56
|
+
description: 'Extract month-level diagnostic comparison into lib/returnpro/diagnose-months.ts',
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
title: 'Implement generate-netsuite-template lib function',
|
|
60
|
+
skill_ref: '/generate-netsuite-template',
|
|
61
|
+
priority: 3,
|
|
62
|
+
labels: ['returnpro', 'phase-2'],
|
|
63
|
+
description: 'Generate blank NetSuite XLSM templates for data entry into lib/returnpro/generate-netsuite-template.ts',
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
// --- Content follow-ups (ready) ---
|
|
67
|
+
{
|
|
68
|
+
title: 'Implement generate-newsletter-insurance',
|
|
69
|
+
skill_ref: '/generate-newsletter-insurance',
|
|
70
|
+
priority: 2,
|
|
71
|
+
labels: ['content', 'phase-3'],
|
|
72
|
+
description: 'Insurance-specific newsletter generation (LIFEINSUR brand) with Groq AI content',
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
title: 'Implement distribute-newsletter (n8n webhook)',
|
|
76
|
+
skill_ref: '/distribute-newsletter',
|
|
77
|
+
priority: 2,
|
|
78
|
+
labels: ['content', 'phase-3'],
|
|
79
|
+
description: 'Trigger n8n webhook to distribute published newsletter via GoHighLevel email',
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
title: 'Implement generate-social-posts pipeline',
|
|
83
|
+
skill_ref: '/generate-social-posts',
|
|
84
|
+
priority: 2,
|
|
85
|
+
labels: ['content', 'phase-3'],
|
|
86
|
+
description: 'Full pipeline: scrape competitors, analyze patterns, generate 9 social posts, push to Strapi',
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
title: 'Implement publish-social-posts',
|
|
90
|
+
skill_ref: '/publish-social-posts',
|
|
91
|
+
priority: 3,
|
|
92
|
+
labels: ['content', 'phase-3'],
|
|
93
|
+
description: 'Publish scheduled social posts to Meta (IG/FB) via Marketing API',
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
title: 'Implement publish-blog',
|
|
97
|
+
skill_ref: '/publish-blog',
|
|
98
|
+
priority: 3,
|
|
99
|
+
labels: ['content', 'phase-3'],
|
|
100
|
+
description: 'Publish blog post to Strapi CMS and deploy preview site via Vercel',
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
// --- Infrastructure follow-ups (ready) ---
|
|
104
|
+
{
|
|
105
|
+
title: 'Implement migrate-db skill',
|
|
106
|
+
skill_ref: '/migrate-db',
|
|
107
|
+
priority: 3,
|
|
108
|
+
labels: ['infra', 'phase-3'],
|
|
109
|
+
description: 'Run Supabase migrations via CLI (supabase db push --linked) with pre-flight checks',
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
title: 'Implement manage-scenarios for budget',
|
|
113
|
+
skill_ref: '/manage-scenarios',
|
|
114
|
+
priority: 3,
|
|
115
|
+
labels: ['budget', 'phase-3'],
|
|
116
|
+
description: 'CRUD for budget projection scenarios (save/load/compare named adjustment sets)',
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
title: 'Implement delete-batch for transactions',
|
|
120
|
+
skill_ref: '/delete-batch',
|
|
121
|
+
priority: 3,
|
|
122
|
+
labels: ['transactions', 'phase-3'],
|
|
123
|
+
description: 'Bulk delete transactions by date range or import batch ID with confirmation safeguard',
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
// --- Frontend migration (backlog — future phase) ---
|
|
127
|
+
{
|
|
128
|
+
title: 'Migrate dashboard-returnpro to apps/ as read-only',
|
|
129
|
+
priority: 4,
|
|
130
|
+
labels: ['frontend', 'phase-4'],
|
|
131
|
+
description: 'Move dashboard-returnpro Next.js app into apps/dashboard-returnpro as a read-only frontend consuming CLI skills',
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
title: 'Migrate optimalos to apps/ as read-only',
|
|
135
|
+
priority: 4,
|
|
136
|
+
labels: ['frontend', 'phase-4'],
|
|
137
|
+
description: 'Move optimalos Next.js app into apps/optimalos as a read-only frontend consuming CLI skills',
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
title: 'Migrate portfolio-2026 to apps/ as read-only',
|
|
141
|
+
priority: 4,
|
|
142
|
+
labels: ['frontend', 'phase-4'],
|
|
143
|
+
description: 'Move portfolio-2026 Next.js app into apps/portfolio-2026 as a read-only frontend consuming CLI skills',
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
title: 'Migrate wes-dashboard to apps/ as read-only',
|
|
147
|
+
priority: 4,
|
|
148
|
+
labels: ['frontend', 'phase-4'],
|
|
149
|
+
description: 'Move wes-dashboard Next.js app into apps/wes-dashboard as a read-only frontend consuming CLI skills',
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
title: 'Migrate newsletter-preview to apps/ as read-only',
|
|
153
|
+
priority: 4,
|
|
154
|
+
labels: ['frontend', 'phase-4'],
|
|
155
|
+
description: 'Move newsletter-preview Next.js app into apps/newsletter-preview as a read-only frontend consuming CLI skills',
|
|
156
|
+
},
|
|
157
|
+
]
|
|
158
|
+
|
|
159
|
+
async function main() {
|
|
160
|
+
console.log(`Seeding kanban board for project: ${PROJECT_SLUG}`)
|
|
161
|
+
console.log(`Tasks to seed: ${tasks.length}\n`)
|
|
162
|
+
|
|
163
|
+
// Fetch existing tasks for idempotency check
|
|
164
|
+
const existing = await getBoard(PROJECT_SLUG)
|
|
165
|
+
const existingTitles = new Set(existing.map(t => t.title))
|
|
166
|
+
|
|
167
|
+
console.log(`Existing tasks on board: ${existing.length}`)
|
|
168
|
+
|
|
169
|
+
let created = 0
|
|
170
|
+
let skipped = 0
|
|
171
|
+
|
|
172
|
+
for (const task of tasks) {
|
|
173
|
+
if (existingTitles.has(task.title)) {
|
|
174
|
+
console.log(` SKIP: "${task.title}" (already exists)`)
|
|
175
|
+
skipped++
|
|
176
|
+
continue
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
try {
|
|
180
|
+
const result = await createTask({
|
|
181
|
+
project_slug: PROJECT_SLUG,
|
|
182
|
+
title: task.title,
|
|
183
|
+
description: task.description,
|
|
184
|
+
priority: task.priority,
|
|
185
|
+
skill_ref: task.skill_ref,
|
|
186
|
+
labels: task.labels,
|
|
187
|
+
})
|
|
188
|
+
console.log(` CREATE: "${result.title}" [P${result.priority}] (${result.id})`)
|
|
189
|
+
created++
|
|
190
|
+
} catch (err) {
|
|
191
|
+
const msg = err instanceof Error ? err.message : String(err)
|
|
192
|
+
console.error(` ERROR: "${task.title}" — ${msg}`)
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
console.log(`\nDone. Created: ${created}, Skipped: ${skipped}`)
|
|
197
|
+
console.log(`Total tasks on board: ${existing.length + created}`)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
main().catch((err) => {
|
|
201
|
+
console.error('Seed failed:', err)
|
|
202
|
+
process.exit(1)
|
|
203
|
+
})
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { getBoardByStatus, listProjects } from '../lib/kanban.js'
|
|
2
|
+
|
|
3
|
+
async function main() {
|
|
4
|
+
console.log('Testing kanban lib...')
|
|
5
|
+
|
|
6
|
+
const projects = await listProjects()
|
|
7
|
+
console.log('Projects:', projects.map(p => p.slug).join(', '))
|
|
8
|
+
|
|
9
|
+
const board = await getBoardByStatus('optimal-cli')
|
|
10
|
+
console.log('Board:')
|
|
11
|
+
for (const [status, tasks] of Object.entries(board)) {
|
|
12
|
+
if (tasks.length > 0) {
|
|
13
|
+
console.log(` ${status}: ${tasks.length}`)
|
|
14
|
+
for (const t of tasks) {
|
|
15
|
+
console.log(` - ${t.title} (claimed: ${t.claimed_by || 'none'})`)
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
main().catch(console.error)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: audit-financials
|
|
3
|
+
description: Compare staged financials against confirmed income statements and report accuracy per month
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
Verifies data accuracy between `stg_financials_raw` (staged from NetSuite XLSM/CSV) and `confirmed_income_statements` (from NetSuite income statement CSVs). This is the most critical financial health check — every data session should start by running this.
|
|
8
|
+
|
|
9
|
+
## Inputs
|
|
10
|
+
- **months** (optional): Comma-separated YYYY-MM strings to filter (e.g., `2026-01,2025-12`). Omit for all months.
|
|
11
|
+
- **tolerance** (optional): Dollar tolerance for match detection. Default `1.00`.
|
|
12
|
+
|
|
13
|
+
## Steps
|
|
14
|
+
1. Call `lib/returnpro/audit.ts::runAuditComparison(months?, tolerance?)` to fetch and compare data
|
|
15
|
+
2. Paginate all `stg_financials_raw` rows (amount is TEXT — parseFloat)
|
|
16
|
+
3. Paginate all `confirmed_income_statements` rows
|
|
17
|
+
4. Aggregate staging by `account_code|YYYY-MM` key
|
|
18
|
+
5. Compare each overlapping account: exact match, sign-flip match, or mismatch (within tolerance)
|
|
19
|
+
6. Compute accuracy = (exactMatch + signFlipMatch) / overlap * 100
|
|
20
|
+
|
|
21
|
+
## Output
|
|
22
|
+
Per-month table:
|
|
23
|
+
|
|
24
|
+
| Month | Confirmed | Staged | Match | Mismatch | Accuracy |
|
|
25
|
+
|-------|-----------|--------|-------|----------|----------|
|
|
26
|
+
| 2026-01 | 189 | 91 | 83 | 8 | 91.2% |
|
|
27
|
+
|
|
28
|
+
Plus total staging rows and confirmed rows counts.
|
|
29
|
+
|
|
30
|
+
Flag any month below 100% accuracy — investigate mismatches and identify root causes.
|
|
31
|
+
|
|
32
|
+
## Environment
|
|
33
|
+
Requires: `RETURNPRO_SUPABASE_URL`, `RETURNPRO_SUPABASE_SERVICE_KEY`
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: board-create
|
|
3
|
+
description: Create a new task on the kanban board
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
Adds a new task to the project board. Agents use this to break work into trackable subtasks.
|
|
8
|
+
|
|
9
|
+
## Inputs
|
|
10
|
+
- **project** (optional): Project slug. Default: `optimal-cli-refactor`
|
|
11
|
+
- **title** (required): Task title
|
|
12
|
+
- **description** (optional): Detailed task description
|
|
13
|
+
- **priority** (optional): 1=urgent, 2=high, 3=normal, 4=low. Default: 3
|
|
14
|
+
- **skill** (optional): Skill that should handle this task (e.g. `/audit-financials`)
|
|
15
|
+
- **labels** (optional): Comma-separated labels
|
|
16
|
+
- **blocked_by** (optional): Comma-separated task IDs that must complete first
|
|
17
|
+
|
|
18
|
+
## Steps
|
|
19
|
+
1. Call `lib/kanban.ts::createTask(input)` with provided params
|
|
20
|
+
2. Return the created task ID and title
|
|
21
|
+
|
|
22
|
+
## Output
|
|
23
|
+
```
|
|
24
|
+
Created task: {id} — "{title}" (priority {priority}, status backlog)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Environment
|
|
28
|
+
Requires: `OPTIMAL_SUPABASE_URL`, `OPTIMAL_SUPABASE_SERVICE_KEY`
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: board-update
|
|
3
|
+
description: Update a task's status, assignment, or metadata on the kanban board
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
Moves tasks through the kanban lifecycle. Agents call this to claim work, mark completion, or flag blockers.
|
|
8
|
+
|
|
9
|
+
## Inputs
|
|
10
|
+
- **task_id** (required): UUID of the task to update
|
|
11
|
+
- **status** (optional): New status (backlog, ready, in_progress, blocked, review, done, canceled)
|
|
12
|
+
- **agent** (optional): Agent name to assign (e.g. `claude-code`, `carlos`)
|
|
13
|
+
- **priority** (optional): New priority (1-4)
|
|
14
|
+
- **message** (optional): Log message describing the update
|
|
15
|
+
|
|
16
|
+
## Steps
|
|
17
|
+
1. Call `lib/kanban.ts::updateTask(taskId, updates)`
|
|
18
|
+
2. Call `lib/kanban.ts::logActivity(taskId, { agent, action: 'status_change', message })`
|
|
19
|
+
3. Return updated task summary
|
|
20
|
+
|
|
21
|
+
## Output
|
|
22
|
+
```
|
|
23
|
+
Updated task {id}: status → {status}, agent → {agent}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Environment
|
|
27
|
+
Requires: `OPTIMAL_SUPABASE_URL`, `OPTIMAL_SUPABASE_SERVICE_KEY`
|