dtSpark 1.0.5__tar.gz → 1.0.9__tar.gz

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 (122) hide show
  1. {dtspark-1.0.5 → dtspark-1.0.9}/PKG-INFO +1 -1
  2. dtspark-1.0.9/src/dtSpark/_version.txt +1 -0
  3. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/core/application.py +198 -56
  4. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/resources/config.yaml.template +21 -12
  5. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark.egg-info/PKG-INFO +1 -1
  6. dtspark-1.0.5/src/dtSpark/_version.txt +0 -1
  7. {dtspark-1.0.5 → dtspark-1.0.9}/LICENSE +0 -0
  8. {dtspark-1.0.5 → dtspark-1.0.9}/MANIFEST.in +0 -0
  9. {dtspark-1.0.5 → dtspark-1.0.9}/README.md +0 -0
  10. {dtspark-1.0.5 → dtspark-1.0.9}/pyproject.toml +0 -0
  11. {dtspark-1.0.5 → dtspark-1.0.9}/setup.cfg +0 -0
  12. {dtspark-1.0.5 → dtspark-1.0.9}/setup.py +0 -0
  13. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/__init__.py +0 -0
  14. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/_description.txt +0 -0
  15. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/_full_name.txt +0 -0
  16. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/_licence.txt +0 -0
  17. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/_metadata.yaml +0 -0
  18. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/_name.txt +0 -0
  19. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/aws/__init__.py +0 -0
  20. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/aws/authentication.py +0 -0
  21. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/aws/bedrock.py +0 -0
  22. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/aws/costs.py +0 -0
  23. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/aws/pricing.py +0 -0
  24. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/cli_interface.py +0 -0
  25. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/conversation_manager.py +0 -0
  26. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/core/__init__.py +0 -0
  27. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/core/context_compaction.py +0 -0
  28. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/daemon/__init__.py +0 -0
  29. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/daemon/__main__.py +0 -0
  30. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/daemon/action_monitor.py +0 -0
  31. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/daemon/daemon_app.py +0 -0
  32. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/daemon/daemon_manager.py +0 -0
  33. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/daemon/execution_coordinator.py +0 -0
  34. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/daemon/pid_file.py +0 -0
  35. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/database/__init__.py +0 -0
  36. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/database/autonomous_actions.py +0 -0
  37. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/database/backends.py +0 -0
  38. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/database/connection.py +0 -0
  39. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/database/conversations.py +0 -0
  40. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/database/credential_prompt.py +0 -0
  41. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/database/files.py +0 -0
  42. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/database/mcp_ops.py +0 -0
  43. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/database/messages.py +0 -0
  44. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/database/schema.py +0 -0
  45. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/database/tool_permissions.py +0 -0
  46. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/database/usage.py +0 -0
  47. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/files/__init__.py +0 -0
  48. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/files/manager.py +0 -0
  49. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/launch.py +0 -0
  50. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/limits/__init__.py +0 -0
  51. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/limits/costs.py +0 -0
  52. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/limits/tokens.py +0 -0
  53. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/llm/__init__.py +0 -0
  54. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/llm/anthropic_direct.py +0 -0
  55. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/llm/base.py +0 -0
  56. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/llm/context_limits.py +0 -0
  57. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/llm/manager.py +0 -0
  58. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/llm/ollama.py +0 -0
  59. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/mcp_integration/__init__.py +0 -0
  60. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/mcp_integration/manager.py +0 -0
  61. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/mcp_integration/tool_selector.py +0 -0
  62. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/safety/__init__.py +0 -0
  63. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/safety/llm_service.py +0 -0
  64. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/safety/patterns.py +0 -0
  65. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/safety/prompt_inspector.py +0 -0
  66. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/safety/violation_logger.py +0 -0
  67. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/scheduler/__init__.py +0 -0
  68. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/scheduler/creation_tools.py +0 -0
  69. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/scheduler/execution_queue.py +0 -0
  70. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/scheduler/executor.py +0 -0
  71. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/scheduler/manager.py +0 -0
  72. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/tools/__init__.py +0 -0
  73. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/tools/builtin.py +0 -0
  74. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/web/__init__.py +0 -0
  75. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/web/auth.py +0 -0
  76. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/web/dependencies.py +0 -0
  77. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/web/endpoints/__init__.py +0 -0
  78. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/web/endpoints/autonomous_actions.py +0 -0
  79. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/web/endpoints/chat.py +0 -0
  80. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/web/endpoints/conversations.py +0 -0
  81. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/web/endpoints/main_menu.py +0 -0
  82. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/web/endpoints/streaming.py +0 -0
  83. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/web/server.py +0 -0
  84. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/web/session.py +0 -0
  85. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/web/ssl_utils.py +0 -0
  86. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/web/static/css/dark-theme.css +0 -0
  87. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/web/static/js/actions.js +0 -0
  88. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/web/static/js/chat.js +0 -0
  89. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/web/static/js/main.js +0 -0
  90. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/web/static/js/sse-client.js +0 -0
  91. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/web/templates/actions.html +0 -0
  92. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/web/templates/base.html +0 -0
  93. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/web/templates/chat.html +0 -0
  94. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/web/templates/conversations.html +0 -0
  95. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/web/templates/goodbye.html +0 -0
  96. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/web/templates/login.html +0 -0
  97. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/web/templates/main_menu.html +0 -0
  98. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/web/templates/new_conversation.html +0 -0
  99. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark/web/web_interface.py +0 -0
  100. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark.egg-info/SOURCES.txt +0 -0
  101. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark.egg-info/dependency_links.txt +0 -0
  102. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark.egg-info/entry_points.txt +0 -0
  103. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark.egg-info/not-zip-safe +0 -0
  104. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark.egg-info/requires.txt +0 -0
  105. {dtspark-1.0.5 → dtspark-1.0.9}/src/dtSpark.egg-info/top_level.txt +0 -0
  106. {dtspark-1.0.5 → dtspark-1.0.9}/tests/README.md +0 -0
  107. {dtspark-1.0.5 → dtspark-1.0.9}/tests/debug_bulk_api.py +0 -0
  108. {dtspark-1.0.5 → dtspark-1.0.9}/tests/diagnose_aws_costs.py +0 -0
  109. {dtspark-1.0.5 → dtspark-1.0.9}/tests/test_builtin_tools.py +0 -0
  110. {dtspark-1.0.5 → dtspark-1.0.9}/tests/test_builtin_tools_integration.py +0 -0
  111. {dtspark-1.0.5 → dtspark-1.0.9}/tests/test_bulk_pricing.py +0 -0
  112. {dtspark-1.0.5 → dtspark-1.0.9}/tests/test_filesystem_tools.py +0 -0
  113. {dtspark-1.0.5 → dtspark-1.0.9}/tests/test_mcp_server.py +0 -0
  114. {dtspark-1.0.5 → dtspark-1.0.9}/tests/test_ollama_context.py +0 -0
  115. {dtspark-1.0.5 → dtspark-1.0.9}/tests/test_ollama_conversation.py +0 -0
  116. {dtspark-1.0.5 → dtspark-1.0.9}/tests/test_ollama_integration.py +0 -0
  117. {dtspark-1.0.5 → dtspark-1.0.9}/tests/test_pricing_integration.py +0 -0
  118. {dtspark-1.0.5 → dtspark-1.0.9}/tests/test_prompt_inspection.py +0 -0
  119. {dtspark-1.0.5 → dtspark-1.0.9}/tests/test_status_indicator.py +0 -0
  120. {dtspark-1.0.5 → dtspark-1.0.9}/tests/test_tool_selector.py +0 -0
  121. {dtspark-1.0.5 → dtspark-1.0.9}/tests/test_web_auth.py +0 -0
  122. {dtspark-1.0.5 → dtspark-1.0.9}/tests/test_web_session.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dtSpark
3
- Version: 1.0.5
3
+ Version: 1.0.9
4
4
  Summary: Secure Personal AI Research Kit - Multi-provider LLM CLI/Web interface with MCP tool integration
5
5
  Home-page: https://github.com/digital-thought/dtSpark
6
6
  Author: Matthew Westwood-Hill
@@ -0,0 +1 @@
1
+ 1.0.9
@@ -124,6 +124,7 @@ class AWSBedrockCLI(AbstractApp):
124
124
  if value is not None:
125
125
  return value
126
126
 
127
+
127
128
  # Fallback: Navigate the dict manually
128
129
  parts = key.split('.')
129
130
  if len(parts) > 1:
@@ -1258,10 +1259,6 @@ class AWSBedrockCLI(AbstractApp):
1258
1259
  from dtSpark.cli_interface import CLIInterface
1259
1260
  cli = CLIInterface()
1260
1261
 
1261
- # Initialize secrets manager for storing sensitive credentials
1262
- from dtPyAppFramework.settings import Settings
1263
- secret_manager = Settings().secret_manager
1264
-
1265
1262
  # Display SPARK splash screen
1266
1263
  cli.print_splash_screen(
1267
1264
  full_name=full_name(),
@@ -1283,10 +1280,23 @@ class AWSBedrockCLI(AbstractApp):
1283
1280
  ))
1284
1281
  cli.console.print()
1285
1282
 
1286
- # Destination: user data directory
1287
- user_data_path = ApplicationPaths().usr_data_root_path
1288
- dest_config_dir = os.path.join(user_data_path, 'config')
1283
+ # Destination: depends on CONTAINER_MODE environment variable
1284
+ container_mode = os.environ.get('CONTAINER_MODE', '').lower() == 'true'
1285
+ if container_mode:
1286
+ # Container mode: use working directory
1287
+ dest_config_dir = os.path.join(os.getcwd(), 'config')
1288
+ secrets_dir = os.getcwd()
1289
+ else:
1290
+ # Normal mode: use user data directory
1291
+ user_data_path = ApplicationPaths().usr_data_root_path
1292
+ dest_config_dir = os.path.join(user_data_path, 'config')
1293
+ secrets_dir = user_data_path
1294
+
1289
1295
  dest_config = os.path.join(dest_config_dir, 'config.yaml')
1296
+ secrets_file = os.path.join(secrets_dir, 'secrets.yaml')
1297
+
1298
+ # Collection for secrets to be written to secrets.yaml
1299
+ secrets_to_store = []
1290
1300
 
1291
1301
  cli.print_info(f"Configuration will be created at: {dest_config}")
1292
1302
  cli.console.print()
@@ -1327,8 +1337,14 @@ class AWSBedrockCLI(AbstractApp):
1327
1337
  # ═══════════════════════════════════════════════════════════════
1328
1338
  # AWS Bedrock Configuration
1329
1339
  # ═══════════════════════════════════════════════════════════════
1340
+ aws_auth_method = "sso"
1330
1341
  aws_profile = "default"
1331
1342
  aws_region = "us-east-1"
1343
+ aws_account_name = ""
1344
+ aws_account_id = ""
1345
+ aws_access_key_id = ""
1346
+ aws_secret_access_key = ""
1347
+ aws_session_token = ""
1332
1348
  enable_cost_tracking = False
1333
1349
 
1334
1350
  if use_aws_bedrock:
@@ -1338,16 +1354,94 @@ class AWSBedrockCLI(AbstractApp):
1338
1354
  cli.print_separator("═")
1339
1355
  cli.console.print()
1340
1356
 
1341
- aws_profile = Prompt.ask(
1342
- "AWS SSO profile name",
1343
- default="default"
1357
+ # Authentication method selection
1358
+ cli.console.print("[bold]Authentication Method[/bold]")
1359
+ cli.console.print()
1360
+ cli.console.print(" [1] SSO Profile - AWS Single Sign-On (recommended for interactive use)")
1361
+ cli.console.print(" [2] IAM Access Keys - Long-lived credentials (recommended for autonomous actions)")
1362
+ cli.console.print(" [3] Session Credentials - Temporary credentials with session token")
1363
+ cli.console.print()
1364
+ cli.console.print("[dim]Note: SSO and session credentials have timeouts which may interrupt[/dim]")
1365
+ cli.console.print("[dim]autonomous actions running on a schedule. IAM access keys are recommended[/dim]")
1366
+ cli.console.print("[dim]for unattended/scheduled operations as they do not expire.[/dim]")
1367
+ cli.console.print()
1368
+
1369
+ auth_method_choices = {
1370
+ "1": "sso",
1371
+ "2": "iam",
1372
+ "3": "session"
1373
+ }
1374
+ auth_method_choice = Prompt.ask(
1375
+ "Select authentication method",
1376
+ choices=["1", "2", "3"],
1377
+ default="1"
1344
1378
  )
1379
+ aws_auth_method = auth_method_choices[auth_method_choice]
1380
+
1381
+ cli.console.print()
1345
1382
 
1383
+ # Region (common to all methods)
1346
1384
  aws_region = Prompt.ask(
1347
1385
  "AWS region",
1348
1386
  default="us-east-1"
1349
1387
  )
1350
1388
 
1389
+ # SSO Profile authentication
1390
+ if aws_auth_method == "sso":
1391
+ cli.console.print()
1392
+ aws_profile = Prompt.ask(
1393
+ "AWS SSO profile name",
1394
+ default="default"
1395
+ )
1396
+
1397
+ # IAM or Session authentication
1398
+ if aws_auth_method in ["iam", "session"]:
1399
+ cli.console.print()
1400
+ cli.console.print("[dim]AWS Account Information (optional, for reference):[/dim]")
1401
+ aws_account_name = Prompt.ask(
1402
+ "AWS account name (friendly name)",
1403
+ default=""
1404
+ )
1405
+ aws_account_id = Prompt.ask(
1406
+ "AWS account ID (12-digit number)",
1407
+ default=""
1408
+ )
1409
+
1410
+ cli.console.print()
1411
+ cli.console.print("[dim]AWS Credentials (will be stored in secrets.yaml for secure ingestion):[/dim]")
1412
+
1413
+ # Access Key ID (not typically considered secret, but mask anyway for consistency)
1414
+ aws_access_key_id_input = Prompt.ask(
1415
+ "AWS access key ID",
1416
+ default=""
1417
+ )
1418
+ if aws_access_key_id_input:
1419
+ secrets_to_store.append({"name": "aws_access_key_id", "value": aws_access_key_id_input})
1420
+ aws_access_key_id = "SEC/aws_access_key_id"
1421
+
1422
+ # Secret Access Key (sensitive - mask input)
1423
+ aws_secret_access_key_input = Prompt.ask(
1424
+ "AWS secret access key",
1425
+ default="",
1426
+ password=True
1427
+ )
1428
+ if aws_secret_access_key_input:
1429
+ secrets_to_store.append({"name": "aws_secret_access_key", "value": aws_secret_access_key_input})
1430
+ aws_secret_access_key = "SEC/aws_secret_access_key"
1431
+
1432
+ # Session Token (only for session auth)
1433
+ if aws_auth_method == "session":
1434
+ cli.console.print()
1435
+ aws_session_token_input = Prompt.ask(
1436
+ "AWS session token",
1437
+ default="",
1438
+ password=True
1439
+ )
1440
+ if aws_session_token_input:
1441
+ secrets_to_store.append({"name": "aws_session_token", "value": aws_session_token_input})
1442
+ aws_session_token = "SEC/aws_session_token"
1443
+
1444
+ cli.console.print()
1351
1445
  enable_cost_tracking = Confirm.ask(
1352
1446
  "Enable AWS cost tracking?",
1353
1447
  default=False
@@ -1384,14 +1478,14 @@ class AWSBedrockCLI(AbstractApp):
1384
1478
 
1385
1479
  anthropic_api_key_input = Prompt.ask(
1386
1480
  "Anthropic API key (or press Enter to set via environment variable later)",
1387
- default=""
1481
+ default="",
1482
+ password=True
1388
1483
  )
1389
1484
 
1390
- # Store API key in secrets manager if provided
1485
+ # Store API key in secrets.yaml if provided
1391
1486
  if anthropic_api_key_input:
1392
- secret_manager.set_secret("anthropic_api_key", anthropic_api_key_input)
1487
+ secrets_to_store.append({"name": "anthropic_api_key", "value": anthropic_api_key_input})
1393
1488
  anthropic_api_key = "SEC/anthropic_api_key"
1394
- cli.print_success("✓ Anthropic API key securely stored in secrets manager")
1395
1489
  else:
1396
1490
  anthropic_api_key = ""
1397
1491
 
@@ -1450,23 +1544,21 @@ class AWSBedrockCLI(AbstractApp):
1450
1544
  cli.console.print("[dim]Leave username/password empty (null) to be prompted on startup (more secure)[/dim]")
1451
1545
  db_username_input = Prompt.ask("Database username (or press Enter for null)", default="")
1452
1546
 
1453
- # Store database username in secrets manager if provided
1547
+ # Store database username in secrets.yaml if provided
1454
1548
  if db_username_input:
1455
1549
  secret_key = f"db_{database_type}_username"
1456
- secret_manager.set_secret(secret_key, db_username_input)
1550
+ secrets_to_store.append({"name": secret_key, "value": db_username_input})
1457
1551
  db_username = f"SEC/{secret_key}"
1458
- cli.print_success(f"✓ Database username securely stored in secrets manager")
1459
1552
  else:
1460
1553
  db_username = "null"
1461
1554
 
1462
- db_password_input = Prompt.ask("Database password (or press Enter for null)", default="")
1555
+ db_password_input = Prompt.ask("Database password (or press Enter for null)", default="", password=True)
1463
1556
 
1464
- # Store database password in secrets manager if provided
1557
+ # Store database password in secrets.yaml if provided
1465
1558
  if db_password_input:
1466
1559
  secret_key = f"db_{database_type}_password"
1467
- secret_manager.set_secret(secret_key, db_password_input)
1560
+ secrets_to_store.append({"name": secret_key, "value": db_password_input})
1468
1561
  db_password = f"SEC/{secret_key}"
1469
- cli.print_success(f"✓ Database password securely stored in secrets manager")
1470
1562
  else:
1471
1563
  db_password = "null"
1472
1564
 
@@ -1811,21 +1903,66 @@ class AWSBedrockCLI(AbstractApp):
1811
1903
  )
1812
1904
 
1813
1905
  # AWS settings
1814
- config_content = re.sub(
1815
- r'(sso_profile:\s+)[^\s#]+',
1816
- f'\\g<1>{aws_profile}',
1817
- config_content
1818
- )
1819
- config_content = re.sub(
1820
- r'(region:\s+)[^\s#]+',
1821
- f'\\g<1>{aws_region}',
1822
- config_content
1823
- )
1824
- config_content = re.sub(
1825
- r'(cost_tracking:\s*\n\s+enabled:\s+)(true|false)',
1826
- f'\\g<1>{str(enable_cost_tracking).lower()}',
1827
- config_content
1828
- )
1906
+ if use_aws_bedrock:
1907
+ # Auth method
1908
+ config_content = re.sub(
1909
+ r'(auth_method:\s+)[^\s#]+',
1910
+ f'\\g<1>{aws_auth_method}',
1911
+ config_content
1912
+ )
1913
+ # Region
1914
+ config_content = re.sub(
1915
+ r'(aws_bedrock:\s*\n(?:.*\n)*?\s+region:\s+)[^\s#]+',
1916
+ f'\\g<1>{aws_region}',
1917
+ config_content
1918
+ )
1919
+ # Account name (only if provided)
1920
+ if aws_account_name:
1921
+ config_content = re.sub(
1922
+ r'(account_name:\s+)[^\s#]+',
1923
+ f'\\g<1>{aws_account_name}',
1924
+ config_content
1925
+ )
1926
+ # Account ID (only if provided)
1927
+ if aws_account_id:
1928
+ config_content = re.sub(
1929
+ r'(account_id:\s+)[^\s#]+',
1930
+ f'\\g<1>{aws_account_id}',
1931
+ config_content
1932
+ )
1933
+ # SSO profile
1934
+ config_content = re.sub(
1935
+ r'(sso_profile:\s+)[^\s#]+',
1936
+ f'\\g<1>{aws_profile}',
1937
+ config_content
1938
+ )
1939
+ # Access key ID (only if provided)
1940
+ if aws_access_key_id:
1941
+ config_content = re.sub(
1942
+ r'(access_key_id:\s+)[^\s#]+',
1943
+ f'\\g<1>{aws_access_key_id}',
1944
+ config_content
1945
+ )
1946
+ # Secret access key (only if provided)
1947
+ if aws_secret_access_key:
1948
+ config_content = re.sub(
1949
+ r'(secret_access_key:\s+)[^\s#]+',
1950
+ f'\\g<1>{aws_secret_access_key}',
1951
+ config_content
1952
+ )
1953
+ # Session token (only if provided)
1954
+ if aws_session_token:
1955
+ config_content = re.sub(
1956
+ r'(session_token:\s+)[^\s#]+',
1957
+ f'\\g<1>{aws_session_token}',
1958
+ config_content
1959
+ )
1960
+ # Cost tracking
1961
+ config_content = re.sub(
1962
+ r'(cost_tracking:\s*\n\s+enabled:\s+)(true|false)',
1963
+ f'\\g<1>{str(enable_cost_tracking).lower()}',
1964
+ config_content
1965
+ )
1829
1966
 
1830
1967
  # Ollama settings
1831
1968
  if use_ollama:
@@ -1835,11 +1972,11 @@ class AWSBedrockCLI(AbstractApp):
1835
1972
  config_content
1836
1973
  )
1837
1974
 
1838
- # Anthropic settings
1975
+ # Anthropic settings - update api_key under anthropic section
1839
1976
  if use_anthropic and anthropic_api_key:
1840
1977
  config_content = re.sub(
1841
- r'(api_key:\s+")[^"]*(")',
1842
- f'\\g<1>{anthropic_api_key}\\g<2>',
1978
+ r'(anthropic:\s*\n\s+enabled:\s+(?:true|false)\s*#[^\n]*\n\s+api_key:\s+)[^\s#]+',
1979
+ f'\\g<1>{anthropic_api_key}',
1843
1980
  config_content
1844
1981
  )
1845
1982
 
@@ -1965,30 +2102,34 @@ class AWSBedrockCLI(AbstractApp):
1965
2102
  f.write(config_content)
1966
2103
 
1967
2104
  cli.console.print()
1968
- cli.print_success(f"✓ Configuration file created successfully!")
2105
+ cli.print_success("✓ Configuration file created successfully!")
1969
2106
  cli.console.print()
1970
2107
  cli.print_info(f"Location: {dest_config}")
1971
2108
  cli.console.print()
1972
2109
 
1973
- # Display summary of secrets stored
1974
- secrets_stored = []
1975
- if use_anthropic and anthropic_api_key.startswith("SEC/"):
1976
- secrets_stored.append("• Anthropic API key")
1977
- if database_type != "sqlite":
1978
- if db_username.startswith("SEC/"):
1979
- secrets_stored.append(f"• {database_type.upper()} database username")
1980
- if db_password.startswith("SEC/"):
1981
- secrets_stored.append(f"• {database_type.upper()} database password")
1982
-
1983
- if secrets_stored:
2110
+ # Write secrets.yaml if there are secrets to store
2111
+ if secrets_to_store:
2112
+ import yaml
2113
+ secrets_yaml_content = {"secrets": secrets_to_store}
2114
+
2115
+ # Ensure secrets directory exists
2116
+ os.makedirs(secrets_dir, exist_ok=True)
2117
+
2118
+ with open(secrets_file, 'w', encoding='utf-8') as f:
2119
+ yaml.dump(secrets_yaml_content, f, default_flow_style=False, sort_keys=False)
2120
+
1984
2121
  cli.console.print()
1985
2122
  cli.print_separator("─")
1986
- cli.console.print("[bold green]Secrets Securely Stored:[/bold green]")
1987
- for secret in secrets_stored:
1988
- cli.console.print(f" {secret}")
2123
+ cli.console.print("[bold green]Secrets Written to secrets.yaml:[/bold green]")
2124
+ for secret in secrets_to_store:
2125
+ cli.console.print(f" {secret['name']}")
2126
+ cli.console.print()
2127
+ cli.print_info(f"Location: {secrets_file}")
1989
2128
  cli.console.print()
1990
- cli.console.print("[dim]These credentials are stored in the secrets manager and[/dim]")
1991
- cli.console.print("[dim]referenced in config.yaml as SEC/<key_name> for security.[/dim]")
2129
+ cli.console.print("[dim]On next application startup, secrets will be automatically[/dim]")
2130
+ cli.console.print("[dim]ingested into the secrets manager and secrets.yaml will be deleted.[/dim]")
2131
+ cli.console.print()
2132
+ cli.console.print("[dim]Secrets are referenced in config.yaml as SEC/<key_name>.[/dim]")
1992
2133
  cli.print_separator("─")
1993
2134
  cli.console.print()
1994
2135
 
@@ -3211,6 +3352,7 @@ class AWSBedrockCLI(AbstractApp):
3211
3352
  self.settings = Settings()
3212
3353
  self.settings.init_settings_readers()
3213
3354
 
3355
+
3214
3356
  # Check if model is locked via configuration
3215
3357
  # Priority 1: Check for mandatory_model (forces model for ALL conversations)
3216
3358
  # Priority 2: Check for bedrock.model_id (legacy configuration)
@@ -83,20 +83,29 @@ llm_providers:
83
83
  enabled: true # Set to false to disable AWS Bedrock
84
84
  region: us-east-1 # AWS region for Bedrock API
85
85
 
86
- # Authentication method: Choose one of the following:
87
- #
88
- # 1. SSO Profile (recommended for interactive use)
86
+ # Authentication method: sso, iam, or session
87
+ # - sso: AWS SSO profile (recommended for interactive use, has session timeout)
88
+ # - iam: IAM access keys (recommended for autonomous actions, no timeout)
89
+ # - session: Temporary session credentials (has session timeout)
90
+ auth_method: sso # Authentication method to use
91
+
92
+ # AWS Account Information (optional, for reference/logging)
93
+ account_name: null # Friendly name for the AWS account
94
+ account_id: null # AWS account ID (12-digit number)
95
+
96
+ # SSO Profile Authentication (used when auth_method: sso)
89
97
  sso_profile: default # AWS SSO profile name
90
- #
91
- # 2. API Keys (for programmatic access, CI/CD, or when SSO is not available)
92
- # Uncomment and set these to use API keys instead of SSO:
93
- # access_key_id: YOUR_ACCESS_KEY_ID
94
- # secret_access_key: YOUR_SECRET_ACCESS_KEY
95
- # session_token: YOUR_SESSION_TOKEN # Optional: for temporary credentials
96
- #
97
- # Note: API keys take precedence over SSO profile if both are configured
98
- #
98
+
99
+ # API Key Authentication (used when auth_method: iam or session)
100
+ # For IAM: Set access_key_id and secret_access_key
101
+ # For Session: Also set session_token
102
+ # Note: Use SEC/<key_name> to reference secrets stored in secrets manager
103
+ access_key_id: null # AWS access key ID
104
+ secret_access_key: null # AWS secret access key (use SEC/aws_secret_access_key)
105
+ session_token: null # Session token for temporary credentials (use SEC/aws_session_token)
106
+
99
107
  # Security Warning: Do NOT commit API keys to version control!
108
+ # Use the setup wizard (--setup) to securely store credentials in secrets manager
100
109
 
101
110
  cost_tracking:
102
111
  enabled: false # Set to true to enable AWS Bedrock cost gathering and display
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dtSpark
3
- Version: 1.0.5
3
+ Version: 1.0.9
4
4
  Summary: Secure Personal AI Research Kit - Multi-provider LLM CLI/Web interface with MCP tool integration
5
5
  Home-page: https://github.com/digital-thought/dtSpark
6
6
  Author: Matthew Westwood-Hill
@@ -1 +0,0 @@
1
- 1.0.5
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes