spaps 0.7.3 → 0.7.5
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/AI_TOOLS.json +10 -11
- package/README.md +216 -36
- package/assets/local-runtime/Dockerfile +28 -0
- package/assets/local-runtime/alembic/env.py +101 -0
- package/assets/local-runtime/alembic/path_bootstrap.py +71 -0
- package/assets/local-runtime/alembic/versions/000000000001_baseline_consolidated_schema.py +1076 -0
- package/assets/local-runtime/alembic/versions/000000000002_fix_column_types_to_match_prod.py +83 -0
- package/assets/local-runtime/alembic/versions/000000000003_fix_email_template_key_uniqueness.py +49 -0
- package/assets/local-runtime/alembic/versions/000000000004_add_hold_duration_minutes_to_dayrate_config.py +30 -0
- package/assets/local-runtime/alembic/versions/000000000005_resource_scoped_entitlements.py +77 -0
- package/assets/local-runtime/alembic/versions/000000000006_cfo_rbac_add_is_admin.py +37 -0
- package/assets/local-runtime/alembic/versions/000000000007_agent_approvals.py +158 -0
- package/assets/local-runtime/alembic/versions/000000000008_add_company_id_to_cfo_connections.py +35 -0
- package/assets/local-runtime/alembic/versions/000000000009_tx_signing.py +62 -0
- package/assets/local-runtime/alembic/versions/000000000010_affiliate_referrals.py +235 -0
- package/assets/local-runtime/alembic/versions/000000000011_checkin_call_booking.py +137 -0
- package/assets/local-runtime/alembic/versions/000000000012_subscription_application_scoping.py +55 -0
- package/assets/local-runtime/alembic/versions/000000000013_refresh_token_anomaly_context.py +61 -0
- package/assets/local-runtime/alembic/versions/000000000014_buildooor_dayrate_hire_schedule.py +39 -0
- package/assets/local-runtime/alembic/versions/000000000015_support_telemetry_platform.py +112 -0
- package/assets/local-runtime/alembic/versions/000000000016_issue_reporting_platform.py +54 -0
- package/assets/local-runtime/alembic/versions/000000000017_issue_reporting_platform_import_tracking.py +44 -0
- package/assets/local-runtime/alembic/versions/000000000018_authorization_policy_engine.py +76 -0
- package/assets/local-runtime/alembic.ini +47 -0
- package/assets/local-runtime/docker-compose.yml +61 -0
- package/assets/local-runtime/manifest.json +8 -0
- package/assets/local-runtime/scripts/container-entrypoint.sh +13 -0
- package/assets/local-runtime/scripts/fetch-prod-db.sh +112 -0
- package/assets/local-runtime/scripts/run-migrations.sh +96 -0
- package/package.json +2 -1
- package/src/ai-helper.js +176 -234
- package/src/ai-tool-spec.js +52 -20
- package/src/auth/api-key.js +119 -0
- package/src/auth/client-id.js +136 -0
- package/src/auth/client.js +169 -0
- package/src/auth/credentials.js +110 -0
- package/src/auth/device-flow.js +159 -0
- package/src/auth/env.js +57 -0
- package/src/auth/handlers.js +462 -0
- package/src/auth/http.js +74 -0
- package/src/cli-dispatcher.js +134 -21
- package/src/docs-system.js +7 -7
- package/src/fixture-kernel.js +1143 -0
- package/src/handlers.js +202 -11
- package/src/help-system.js +2 -0
- package/src/local-runtime.js +258 -0
- package/src/local-server.js +597 -199
- package/src/project-scaffolder.js +185 -45
package/src/cli-dispatcher.js
CHANGED
|
@@ -28,10 +28,11 @@ function defineProgram({ handlers = {}, dryRun = false, version = '0.0.0', logo
|
|
|
28
28
|
// For commands with args, it passes (arg1, arg2, ..., options, command)
|
|
29
29
|
const cmd = args[args.length - 1];
|
|
30
30
|
const options = args[args.length - 2] || {};
|
|
31
|
+
const positionals = args.slice(0, -2);
|
|
31
32
|
const parentJson = program.opts().json;
|
|
32
33
|
const isJson = Boolean(options.json || parentJson);
|
|
33
34
|
|
|
34
|
-
const intent = { name, options: { ...shape(options, cmd, isJson) } };
|
|
35
|
+
const intent = { name, options: { ...shape(options, cmd, isJson, positionals) } };
|
|
35
36
|
intents.push(intent);
|
|
36
37
|
|
|
37
38
|
if (dryRun) return intent;
|
|
@@ -48,34 +49,26 @@ function defineProgram({ handlers = {}, dryRun = false, version = '0.0.0', logo
|
|
|
48
49
|
.command('local [subcommand]')
|
|
49
50
|
.description('Start local SPAPS server via Docker Compose (subcommand: stop)')
|
|
50
51
|
.option('-p, --port <port>', 'Port to check (default: 3301)', String(DEFAULT_PORT))
|
|
52
|
+
.option('--runtime-dir <path>', 'Portable runtime directory (defaults to ~/.cache/spaps/local-<port>)')
|
|
53
|
+
.option('--runtime-source <source>', 'Runtime source: auto|repo|bundle', 'auto')
|
|
54
|
+
.option(
|
|
55
|
+
'--data-source <source>',
|
|
56
|
+
'Base data source: empty|prod-cache|prod-fresh (use --from-backup for an explicit dump file)',
|
|
57
|
+
'empty'
|
|
58
|
+
)
|
|
51
59
|
.option('-d, --detach', 'Run in background (don\'t tail logs)', false)
|
|
52
60
|
.option('--fresh', 'Fresh start: tear down and rebuild from scratch', false)
|
|
53
61
|
.option('--from-backup <path>', 'Load from Supabase backup file', null)
|
|
54
62
|
.option('-o, --open', 'Open browser automatically', false)
|
|
55
63
|
.option('--json', 'Output in JSON format')
|
|
56
64
|
.action(
|
|
57
|
-
makeAction('local', (
|
|
58
|
-
|
|
59
|
-
let subcommand = null;
|
|
60
|
-
let opts = null;
|
|
61
|
-
let cmd = null;
|
|
62
|
-
let isJson = false;
|
|
63
|
-
|
|
64
|
-
if (typeof subcommandOrOpts === 'string') {
|
|
65
|
-
// 'local stop' case
|
|
66
|
-
subcommand = subcommandOrOpts;
|
|
67
|
-
opts = cmdOrOpts;
|
|
68
|
-
cmd = isJsonOrCmd;
|
|
69
|
-
isJson = Boolean(opts.json || (cmd && cmd.parent && cmd.parent.opts().json));
|
|
70
|
-
} else {
|
|
71
|
-
// 'local' case (no subcommand)
|
|
72
|
-
opts = subcommandOrOpts;
|
|
73
|
-
cmd = cmdOrOpts;
|
|
74
|
-
isJson = Boolean(opts.json || (cmd && cmd.parent && cmd.parent.opts().json));
|
|
75
|
-
}
|
|
76
|
-
|
|
65
|
+
makeAction('local', (opts, _cmd, isJson, positionals) => {
|
|
66
|
+
const subcommand = typeof positionals[0] === 'string' ? positionals[0] : null;
|
|
77
67
|
const out = {
|
|
78
68
|
port: Number(opts.port) || 3301,
|
|
69
|
+
runtimeDir: opts.runtimeDir || null,
|
|
70
|
+
runtimeSource: String(opts.runtimeSource || 'auto'),
|
|
71
|
+
dataSource: String(opts.dataSource || 'empty'),
|
|
79
72
|
open: Boolean(opts.open),
|
|
80
73
|
detach: Boolean(opts.detach),
|
|
81
74
|
fresh: Boolean(opts.fresh),
|
|
@@ -141,6 +134,7 @@ function defineProgram({ handlers = {}, dryRun = false, version = '0.0.0', logo
|
|
|
141
134
|
.description('Create a starter project directory wired for SPAPS')
|
|
142
135
|
.option('-t, --template <template>', 'Starter template: nextjs|react|node|vanilla')
|
|
143
136
|
.option('--dir <dir>', 'Target directory (defaults to ./<name>)')
|
|
137
|
+
.option('-p, --port <port>', 'Local SPAPS port to provision against', String(DEFAULT_PORT))
|
|
144
138
|
.option('-f, --force', 'Allow writing into a non-empty directory', false)
|
|
145
139
|
.option('--json', 'Output in JSON format')
|
|
146
140
|
.action(
|
|
@@ -148,6 +142,7 @@ function defineProgram({ handlers = {}, dryRun = false, version = '0.0.0', logo
|
|
|
148
142
|
name: cmd.args[0],
|
|
149
143
|
template: opts.template || null,
|
|
150
144
|
dir: opts.dir || null,
|
|
145
|
+
port: Number(opts.port) || DEFAULT_PORT,
|
|
151
146
|
force: Boolean(opts.force),
|
|
152
147
|
json: isJson,
|
|
153
148
|
}))
|
|
@@ -221,6 +216,38 @@ function defineProgram({ handlers = {}, dryRun = false, version = '0.0.0', logo
|
|
|
221
216
|
}
|
|
222
217
|
}
|
|
223
218
|
|
|
219
|
+
// spaps fixtures
|
|
220
|
+
const cmdFixtures = program
|
|
221
|
+
.command('fixtures <subcommand>')
|
|
222
|
+
.description('Manage repo-local .spaps auth fixtures (init|apply|reset|storage-state)')
|
|
223
|
+
.option('--dir <dir>', 'Target repo directory (defaults to current working directory)')
|
|
224
|
+
.option('-p, --port <port>', 'Port to inspect for SPAPS runtime hints', String(DEFAULT_PORT))
|
|
225
|
+
.option('--base-url <url>', 'Browser app base URL for generated storage-state files')
|
|
226
|
+
.option('--persona <persona>', 'Persona code to target for storage-state export')
|
|
227
|
+
.option('-f, --format <format>', 'Artifact format (playwright)', 'playwright')
|
|
228
|
+
.option('--force', 'Overwrite fixture files during init', false)
|
|
229
|
+
.option('--json', 'Output in JSON format')
|
|
230
|
+
.action(
|
|
231
|
+
makeAction('fixtures', (opts, cmd, isJson) => {
|
|
232
|
+
return {
|
|
233
|
+
subcommand: cmd.args[0],
|
|
234
|
+
dir: opts.dir || null,
|
|
235
|
+
port: Number(opts.port) || DEFAULT_PORT,
|
|
236
|
+
baseUrl: opts.baseUrl || null,
|
|
237
|
+
persona: opts.persona || null,
|
|
238
|
+
format: String(opts.format || 'playwright'),
|
|
239
|
+
force: Boolean(opts.force),
|
|
240
|
+
json: isJson,
|
|
241
|
+
};
|
|
242
|
+
})
|
|
243
|
+
);
|
|
244
|
+
if (dryRun) {
|
|
245
|
+
cmdFixtures.allowUnknownOption(true);
|
|
246
|
+
if (typeof cmdFixtures.allowExcessArguments === 'function') {
|
|
247
|
+
cmdFixtures.allowExcessArguments(true);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
224
251
|
// spaps doctor
|
|
225
252
|
const cmdDoctor = program
|
|
226
253
|
.command('doctor')
|
|
@@ -238,6 +265,92 @@ function defineProgram({ handlers = {}, dryRun = false, version = '0.0.0', logo
|
|
|
238
265
|
}
|
|
239
266
|
}
|
|
240
267
|
|
|
268
|
+
// spaps login
|
|
269
|
+
const cmdLogin = program
|
|
270
|
+
.command('login')
|
|
271
|
+
.description('Authenticate with a SPAPS server (RFC 8628 device flow)')
|
|
272
|
+
.option('-p, --port <port>', 'Port (default: 3301)', String(DEFAULT_PORT))
|
|
273
|
+
.option('--server-url <url>', 'Full server URL (overrides --port and SPAPS_API_URL)')
|
|
274
|
+
.option('--client-id <id>', 'Application slug to authorize as')
|
|
275
|
+
.option('--json', 'Output in JSON format')
|
|
276
|
+
.action(
|
|
277
|
+
makeAction('login', (opts, _cmd, isJson) => ({
|
|
278
|
+
port: Number(opts.port) || DEFAULT_PORT,
|
|
279
|
+
serverUrl: opts.serverUrl || null,
|
|
280
|
+
clientId: opts.clientId || null,
|
|
281
|
+
json: isJson,
|
|
282
|
+
}))
|
|
283
|
+
);
|
|
284
|
+
if (dryRun) {
|
|
285
|
+
cmdLogin.allowUnknownOption(true);
|
|
286
|
+
if (typeof cmdLogin.allowExcessArguments === 'function') {
|
|
287
|
+
cmdLogin.allowExcessArguments(true);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// spaps logout
|
|
292
|
+
const cmdLogout = program
|
|
293
|
+
.command('logout')
|
|
294
|
+
.description('Revoke and clear stored SPAPS credentials')
|
|
295
|
+
.option('-p, --port <port>', 'Port (default: 3301)', String(DEFAULT_PORT))
|
|
296
|
+
.option('--server-url <url>', 'Full server URL (overrides --port and SPAPS_API_URL)')
|
|
297
|
+
.option('--json', 'Output in JSON format')
|
|
298
|
+
.action(
|
|
299
|
+
makeAction('logout', (opts, _cmd, isJson) => ({
|
|
300
|
+
port: Number(opts.port) || DEFAULT_PORT,
|
|
301
|
+
serverUrl: opts.serverUrl || null,
|
|
302
|
+
json: isJson,
|
|
303
|
+
}))
|
|
304
|
+
);
|
|
305
|
+
if (dryRun) {
|
|
306
|
+
cmdLogout.allowUnknownOption(true);
|
|
307
|
+
if (typeof cmdLogout.allowExcessArguments === 'function') {
|
|
308
|
+
cmdLogout.allowExcessArguments(true);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// spaps whoami
|
|
313
|
+
const cmdWhoami = program
|
|
314
|
+
.command('whoami')
|
|
315
|
+
.description('Show the currently authenticated user')
|
|
316
|
+
.option('-p, --port <port>', 'Port (default: 3301)', String(DEFAULT_PORT))
|
|
317
|
+
.option('--server-url <url>', 'Full server URL (overrides --port and SPAPS_API_URL)')
|
|
318
|
+
.option('--json', 'Output in JSON format')
|
|
319
|
+
.action(
|
|
320
|
+
makeAction('whoami', (opts, _cmd, isJson) => ({
|
|
321
|
+
port: Number(opts.port) || DEFAULT_PORT,
|
|
322
|
+
serverUrl: opts.serverUrl || null,
|
|
323
|
+
json: isJson,
|
|
324
|
+
}))
|
|
325
|
+
);
|
|
326
|
+
if (dryRun) {
|
|
327
|
+
cmdWhoami.allowUnknownOption(true);
|
|
328
|
+
if (typeof cmdWhoami.allowExcessArguments === 'function') {
|
|
329
|
+
cmdWhoami.allowExcessArguments(true);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// spaps token (print access token for piping to curl or env vars)
|
|
334
|
+
const cmdToken = program
|
|
335
|
+
.command('token')
|
|
336
|
+
.description('Print the current access token (for piping to tools like curl)')
|
|
337
|
+
.option('-p, --port <port>', 'Port (default: 3301)', String(DEFAULT_PORT))
|
|
338
|
+
.option('--server-url <url>', 'Full server URL (overrides --port and SPAPS_API_URL)')
|
|
339
|
+
.option('--json', 'Output JSON with metadata instead of bare token')
|
|
340
|
+
.action(
|
|
341
|
+
makeAction('token', (opts, _cmd, isJson) => ({
|
|
342
|
+
port: Number(opts.port) || DEFAULT_PORT,
|
|
343
|
+
serverUrl: opts.serverUrl || null,
|
|
344
|
+
json: isJson,
|
|
345
|
+
}))
|
|
346
|
+
);
|
|
347
|
+
if (dryRun) {
|
|
348
|
+
cmdToken.allowUnknownOption(true);
|
|
349
|
+
if (typeof cmdToken.allowExcessArguments === 'function') {
|
|
350
|
+
cmdToken.allowExcessArguments(true);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
241
354
|
return { program, getIntents: () => intents };
|
|
242
355
|
}
|
|
243
356
|
|
package/src/docs-system.js
CHANGED
|
@@ -22,13 +22,13 @@ ${chalk.green('Basic Usage:')}
|
|
|
22
22
|
${chalk.gray('// CommonJS')}
|
|
23
23
|
const { SweetPotatoSDK } = require('spaps-sdk')
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
${chalk.gray('// Create client for local or provisioned SPAPS')}
|
|
26
26
|
const sdk = new SweetPotatoSDK({
|
|
27
27
|
apiUrl: process.env.SPAPS_API_URL || 'http://localhost:3301',
|
|
28
|
-
apiKey: process.env.SPAPS_API_KEY, ${chalk.gray('//
|
|
28
|
+
apiKey: process.env.SPAPS_API_KEY, ${chalk.gray('// Required unless /health/local-mode says otherwise')}
|
|
29
29
|
})
|
|
30
30
|
|
|
31
|
-
${chalk.gray('// Sign in with email/password
|
|
31
|
+
${chalk.gray('// Sign in with email/password')}
|
|
32
32
|
const auth = await sdk.auth.signInWithPassword({ email: 'user@example.com', password: 'password' })
|
|
33
33
|
console.log('User:', auth.user)
|
|
34
34
|
`
|
|
@@ -108,18 +108,18 @@ ${chalk.green('Environment Variables:')}
|
|
|
108
108
|
${chalk.green('Configuration Options:')}
|
|
109
109
|
const sdk = new SweetPotatoSDK({
|
|
110
110
|
apiUrl: process.env.SPAPS_API_URL || 'http://localhost:3301',
|
|
111
|
-
apiKey: process.env.SPAPS_API_KEY, ${chalk.gray('// Omit
|
|
111
|
+
apiKey: process.env.SPAPS_API_KEY, ${chalk.gray('// Omit only when /health/local-mode reports local_mode_active: true')}
|
|
112
112
|
})
|
|
113
113
|
|
|
114
114
|
${chalk.green('Local Mode Detection:')}
|
|
115
|
-
${chalk.gray('//
|
|
115
|
+
${chalk.gray('// Localhost URLs still need the running server to advertise local mode:')}
|
|
116
116
|
- URL contains 'localhost'
|
|
117
117
|
- URL contains '127.0.0.1'
|
|
118
118
|
- No API URL is provided
|
|
119
119
|
|
|
120
|
-
${chalk.gray('//
|
|
120
|
+
${chalk.gray('// Verify against the server before assuming no key is required')}
|
|
121
121
|
if (sdk.isLocalMode) {
|
|
122
|
-
console.log('
|
|
122
|
+
console.log('Check /health/local-mode before skipping API keys.')
|
|
123
123
|
}
|
|
124
124
|
`
|
|
125
125
|
},
|