sofia-cli 0.1.2 → 0.1.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.
- package/README.md +42 -20
- package/dist/infra/deploy.sh +193 -0
- package/dist/infra/gather-env.sh +211 -0
- package/dist/infra/infra/deploy.sh +193 -0
- package/dist/infra/infra/gather-env.sh +211 -0
- package/dist/infra/infra/main.bicep +90 -0
- package/dist/infra/infra/main.bicepparam +18 -0
- package/dist/infra/infra/resources.bicep +134 -0
- package/dist/infra/infra/teardown.sh +114 -0
- package/dist/infra/main.bicep +90 -0
- package/dist/infra/main.bicepparam +18 -0
- package/dist/infra/resources.bicep +134 -0
- package/dist/infra/teardown.sh +114 -0
- package/dist/src/cli/developCommand.js +0 -2
- package/dist/src/cli/index.js +8 -1
- package/dist/src/cli/workshopCommand.js +1 -1
- package/dist/src/develop/index.js +1 -1
- package/dist/src/develop/pocUtils.js +228 -0
- package/dist/src/develop/ralphLoop.js +8 -27
- package/dist/src/shared/data/cards.json +655 -670
- package/docs/architecture.md +2 -1
- package/package.json +5 -3
- package/src/cli/developCommand.ts +1 -3
- package/src/cli/index.ts +11 -1
- package/src/cli/workshopCommand.ts +21 -17
- package/src/develop/dynamicScaffolder.ts +36 -30
- package/src/develop/index.ts +13 -2
- package/src/develop/pocUtils.ts +296 -0
- package/src/develop/ralphLoop.ts +8 -28
- package/src/develop/templateRegistry.ts +19 -18
- package/src/shared/data/cards.json +655 -670
- package/tests/e2e/developE2e.spec.ts +3 -61
- package/tests/e2e/developFailureE2e.spec.ts +34 -38
- package/tests/integration/pocGithubMcp.spec.ts +29 -39
- package/tests/integration/pocLocalFallback.spec.ts +29 -39
- package/tests/integration/ralphLoopFlow.spec.ts +46 -66
- package/tests/integration/ralphLoopPartial.spec.ts +30 -37
- package/tests/unit/develop/githubMcpAdapter.spec.ts +0 -134
- package/tests/unit/develop/outputValidator.spec.ts +45 -21
- package/tests/unit/develop/ralphLoop.spec.ts +58 -94
- package/tsconfig.json +2 -1
- package/vitest.workspace.ts +5 -0
- package/dist/src/develop/pocScaffolder.js +0 -542
- package/dist/tests/e2e/developE2e.spec.js +0 -126
- package/dist/tests/e2e/developFailureE2e.spec.js +0 -247
- package/dist/tests/e2e/developPty.spec.js +0 -75
- package/dist/tests/e2e/discoveryWebSearchRelevance.spec.js +0 -84
- package/dist/tests/e2e/harness.spec.js +0 -83
- package/dist/tests/e2e/mcpLive.spec.js +0 -120
- package/dist/tests/e2e/newSession.e2e.spec.js +0 -177
- package/dist/tests/e2e/ralphLoopEnrichmentComparison.spec.js +0 -62
- package/dist/tests/e2e/workiqEnrichment.spec.js +0 -56
- package/dist/tests/e2e/zavaSimulation.spec.js +0 -452
- package/dist/tests/fixtures/test-fixture-project/src/add.js +0 -3
- package/dist/tests/fixtures/test-fixture-project/tests/failing.test.js +0 -6
- package/dist/tests/fixtures/test-fixture-project/tests/hanging.test.js +0 -8
- package/dist/tests/fixtures/test-fixture-project/tests/passing.test.js +0 -10
- package/dist/tests/fixtures/test-fixture-project/vitest.config.js +0 -6
- package/dist/tests/integration/autoStartConversation.spec.js +0 -138
- package/dist/tests/integration/defaultCommand.spec.js +0 -147
- package/dist/tests/integration/directCommandNonTty.spec.js +0 -224
- package/dist/tests/integration/directCommandTty.spec.js +0 -151
- package/dist/tests/integration/discoveryEnrichmentFlow.spec.js +0 -175
- package/dist/tests/integration/exportArtifacts.spec.js +0 -202
- package/dist/tests/integration/exportFallbackFlow.spec.js +0 -99
- package/dist/tests/integration/mcpDegradationFlow.spec.js +0 -190
- package/dist/tests/integration/mcpTransportFlow.spec.js +0 -139
- package/dist/tests/integration/newSessionFlow.spec.js +0 -343
- package/dist/tests/integration/pocGithubMcp.spec.js +0 -186
- package/dist/tests/integration/pocLocalFallback.spec.js +0 -171
- package/dist/tests/integration/pocScaffold.spec.js +0 -163
- package/dist/tests/integration/ralphLoopFlow.spec.js +0 -359
- package/dist/tests/integration/ralphLoopPartial.spec.js +0 -368
- package/dist/tests/integration/resumeAndBacktrack.spec.js +0 -247
- package/dist/tests/integration/spinnerLifecycle.spec.js +0 -220
- package/dist/tests/integration/summarizationFlow.spec.js +0 -115
- package/dist/tests/integration/testRunnerReal.spec.js +0 -52
- package/dist/tests/integration/webSearchAgent.spec.js +0 -128
- package/dist/tests/live/copilotSdkLive.spec.js +0 -107
- package/dist/tests/live/zavaFullWorkshop.spec.js +0 -392
- package/dist/tests/setup/loadEnv.js +0 -3
- package/dist/tests/unit/cli/developCommand.spec.js +0 -567
- package/dist/tests/unit/cli/directCommands.spec.js +0 -279
- package/dist/tests/unit/cli/envLoader.spec.js +0 -58
- package/dist/tests/unit/cli/ioContext.spec.js +0 -119
- package/dist/tests/unit/cli/preflight.spec.js +0 -108
- package/dist/tests/unit/cli/statusCommand.spec.js +0 -111
- package/dist/tests/unit/cli/workshopClientFallback.spec.js +0 -80
- package/dist/tests/unit/cli/workshopCommand.spec.js +0 -328
- package/dist/tests/unit/config/vitestEnvSetup.spec.js +0 -13
- package/dist/tests/unit/develop/checkpointState.spec.js +0 -315
- package/dist/tests/unit/develop/codeGenerator.spec.js +0 -355
- package/dist/tests/unit/develop/githubMcpAdapter.spec.js +0 -231
- package/dist/tests/unit/develop/mcpContextEnricher.spec.js +0 -433
- package/dist/tests/unit/develop/outputValidator.spec.js +0 -119
- package/dist/tests/unit/develop/pocScaffolder.spec.js +0 -353
- package/dist/tests/unit/develop/ralphLoop.spec.js +0 -1248
- package/dist/tests/unit/develop/templateRegistry.spec.js +0 -85
- package/dist/tests/unit/develop/testRunner.spec.js +0 -249
- package/dist/tests/unit/infraBicep.spec.js +0 -92
- package/dist/tests/unit/infraDeploy.spec.js +0 -82
- package/dist/tests/unit/infraTeardown.spec.js +0 -63
- package/dist/tests/unit/logging/logger.spec.js +0 -43
- package/dist/tests/unit/loop/conversationLoop.spec.js +0 -592
- package/dist/tests/unit/loop/phaseSummarizer.spec.js +0 -141
- package/dist/tests/unit/loop/streamingMarkdown.spec.js +0 -147
- package/dist/tests/unit/mcp/mcpManager.spec.js +0 -279
- package/dist/tests/unit/mcp/mcpTransport.spec.js +0 -529
- package/dist/tests/unit/mcp/retryPolicy.spec.js +0 -218
- package/dist/tests/unit/mcp/timeoutValidation.spec.js +0 -46
- package/dist/tests/unit/mcp/webSearch.spec.js +0 -567
- package/dist/tests/unit/phases/contextSummarizer.spec.js +0 -140
- package/dist/tests/unit/phases/discoveryEnricher.repeatCalls.spec.js +0 -93
- package/dist/tests/unit/phases/discoveryEnricher.spec.js +0 -411
- package/dist/tests/unit/phases/phaseExtractors.spec.js +0 -352
- package/dist/tests/unit/phases/phaseHandlers.spec.js +0 -425
- package/dist/tests/unit/prompts/promptLoader.spec.js +0 -118
- package/dist/tests/unit/schemas/pocSchemas.spec.js +0 -412
- package/dist/tests/unit/schemas/session.spec.js +0 -257
- package/dist/tests/unit/sessions/exportPaths.spec.js +0 -31
- package/dist/tests/unit/sessions/exportWriter.spec.js +0 -655
- package/dist/tests/unit/sessions/sessionManager.spec.js +0 -151
- package/dist/tests/unit/sessions/sessionStore.spec.js +0 -116
- package/dist/tests/unit/shared/activitySpinner.spec.js +0 -175
- package/dist/tests/unit/shared/cardsLoader.spec.js +0 -76
- package/dist/tests/unit/shared/copilotClient.spec.js +0 -155
- package/dist/tests/unit/shared/errorClassifier.spec.js +0 -131
- package/dist/tests/unit/shared/events.spec.js +0 -55
- package/dist/tests/unit/shared/markdownRenderer.spec.js +0 -35
- package/dist/tests/unit/shared/markdownRendererChunks.spec.js +0 -70
- package/dist/tests/unit/shared/tableRenderer.spec.js +0 -34
- package/dist/vitest.config.js +0 -14
- package/dist/vitest.live.config.js +0 -18
- package/src/develop/pocScaffolder.ts +0 -646
- package/tests/integration/pocScaffold.spec.ts +0 -220
- package/tests/unit/develop/pocScaffolder.spec.ts +0 -451
package/README.md
CHANGED
|
@@ -69,22 +69,34 @@ sofIA uses [Model Context Protocol](https://modelcontextprotocol.io/) servers to
|
|
|
69
69
|
```bash
|
|
70
70
|
# Prerequisites: Node.js >= 20, a GitHub Copilot subscription
|
|
71
71
|
|
|
72
|
-
#
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
72
|
+
# Install globally from npm
|
|
73
|
+
npm install -g sofia-cli
|
|
74
|
+
|
|
75
|
+
# Or run directly with npx (no install required)
|
|
76
|
+
npx sofia-cli workshop
|
|
76
77
|
|
|
77
78
|
# Start an interactive workshop
|
|
78
|
-
|
|
79
|
+
sofia workshop
|
|
79
80
|
|
|
80
81
|
# Check session status
|
|
81
|
-
|
|
82
|
+
sofia status
|
|
82
83
|
|
|
83
84
|
# Generate a PoC from a completed session
|
|
84
|
-
|
|
85
|
+
sofia dev --session <id>
|
|
85
86
|
|
|
86
87
|
# Export workshop artifacts
|
|
87
|
-
|
|
88
|
+
sofia export --session <id>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Development Setup
|
|
92
|
+
|
|
93
|
+
If you want to contribute or run from source:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
git clone https://github.com/jmservera/sofia-cli.git
|
|
97
|
+
cd sofia-cli
|
|
98
|
+
npm install
|
|
99
|
+
npm run start -- workshop
|
|
88
100
|
```
|
|
89
101
|
|
|
90
102
|
## CLI Commands
|
|
@@ -111,24 +123,28 @@ infra/ # Azure AI Foundry IaC (Bicep + deployment scripts)
|
|
|
111
123
|
src/
|
|
112
124
|
├── cli/ # Command handlers (workshop, dev, status, export)
|
|
113
125
|
├── develop/ # PoC generation & Ralph loop
|
|
114
|
-
│ ├── ralphLoop.ts
|
|
115
|
-
│ ├──
|
|
116
|
-
│ ├── codeGenerator.ts
|
|
117
|
-
│ ├── testRunner.ts
|
|
126
|
+
│ ├── ralphLoop.ts # Autonomous iteration orchestrator
|
|
127
|
+
│ ├── dynamicScaffolder.ts # LLM-based project scaffolding
|
|
128
|
+
│ ├── codeGenerator.ts # LLM-driven code generation
|
|
129
|
+
│ ├── testRunner.ts # Test execution & result parsing
|
|
130
|
+
│ ├── checkpointState.ts # Resume/checkpoint detection
|
|
118
131
|
│ └── ...
|
|
119
132
|
├── loop/ # Multi-turn conversation orchestrator
|
|
120
133
|
├── phases/ # Phase handlers & JSON extractors
|
|
121
134
|
├── prompts/ # Versioned prompt templates
|
|
122
135
|
├── sessions/ # Session persistence & export
|
|
123
|
-
├── mcp/ # MCP server connection manager
|
|
136
|
+
├── mcp/ # MCP server connection manager & transports
|
|
124
137
|
├── shared/ # Schemas, events, error classification
|
|
125
138
|
│ └── schemas/ # Zod schemas for session state
|
|
126
139
|
└── vendor/ # Re-exports of external packages
|
|
127
140
|
|
|
128
141
|
specs/
|
|
129
|
-
├── 001-cli-workshop-rebuild/
|
|
130
|
-
├── 002-poc-generation/
|
|
131
|
-
|
|
142
|
+
├── 001-cli-workshop-rebuild/ # Workshop phases orchestration
|
|
143
|
+
├── 002-poc-generation/ # Develop phase & Ralph loop
|
|
144
|
+
├── 003-mcp-transport-integration/ # Real MCP server connections
|
|
145
|
+
├── 004-dev-resume-hardening/ # Checkpoint, resume, --force
|
|
146
|
+
├── 005-ai-search-deploy/ # Azure AI Foundry infrastructure
|
|
147
|
+
└── 006-workshop-extraction-fixes/ # Extraction, wiring, context mgmt
|
|
132
148
|
|
|
133
149
|
docs/ # User-facing documentation
|
|
134
150
|
tests/
|
|
@@ -183,10 +199,16 @@ See [.github/copilot-instructions.md](.github/copilot-instructions.md) for detai
|
|
|
183
199
|
|
|
184
200
|
## Current Status
|
|
185
201
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
202
|
+
All six features have been implemented and tested:
|
|
203
|
+
|
|
204
|
+
| Feature | Title | Description | Status |
|
|
205
|
+
| ------- | --------------------------------------------------------------- | ---------------------------------------------------------------------- | --------------- |
|
|
206
|
+
| 001 | [Workshop Rebuild](specs/001-cli-workshop-rebuild/spec.md) | 5-phase orchestration (Discover → Plan), session persistence, export | **Implemented** |
|
|
207
|
+
| 002 | [PoC Generation](specs/002-poc-generation/spec.md) | Develop phase with Ralph loop, LLM-based dynamic scaffolding | **Implemented** |
|
|
208
|
+
| 003 | [MCP Transport](specs/003-mcp-transport-integration/spec.md) | Real MCP tool invocation (GitHub, Context7, Azure, web search, WorkIQ) | **Implemented** |
|
|
209
|
+
| 004 | [Dev Hardening](specs/004-dev-resume-hardening/spec.md) | Checkpoint/resume, `--force` flag, template registry, test coverage | **Implemented** |
|
|
210
|
+
| 005 | [Search Deployment](specs/005-ai-search-deploy/spec.md) | Azure AI Foundry Bicep infrastructure with one-command deploy/teardown | **Implemented** |
|
|
211
|
+
| 006 | [Extraction Fixes](specs/006-workshop-extraction-fixes/spec.md) | Fallback extraction, MCP wiring per phase, context window management | **Implemented** |
|
|
190
212
|
|
|
191
213
|
## Web Search Setup
|
|
192
214
|
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ──────────────────────────────────────────────────────────────────────────────
|
|
3
|
+
# deploy.sh — One-command Azure AI Foundry deployment for sofIA
|
|
4
|
+
#
|
|
5
|
+
# Provisions:
|
|
6
|
+
# - Resource group (auto-created)
|
|
7
|
+
# - AI Services account with Foundry project
|
|
8
|
+
# - Model deployment (gpt-4.1-mini by default)
|
|
9
|
+
# - Agent Service capability hosts
|
|
10
|
+
#
|
|
11
|
+
# Usage:
|
|
12
|
+
# ./infra/deploy.sh --resource-group <name> [options]
|
|
13
|
+
#
|
|
14
|
+
# Exit codes:
|
|
15
|
+
# 0 — Deployment succeeded
|
|
16
|
+
# 1 — Prerequisite check failed
|
|
17
|
+
# 2 — Deployment failed
|
|
18
|
+
# ──────────────────────────────────────────────────────────────────────────────
|
|
19
|
+
set -euo pipefail
|
|
20
|
+
|
|
21
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
22
|
+
|
|
23
|
+
# ── Defaults ──────────────────────────────────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
SUBSCRIPTION=""
|
|
26
|
+
RESOURCE_GROUP=""
|
|
27
|
+
LOCATION="swedencentral"
|
|
28
|
+
ACCOUNT_NAME="sofia-foundry"
|
|
29
|
+
MODEL="gpt-4.1-mini"
|
|
30
|
+
|
|
31
|
+
# ── Parameter parsing ─────────────────────────────────────────────────────────
|
|
32
|
+
|
|
33
|
+
usage() {
|
|
34
|
+
cat <<EOF
|
|
35
|
+
Usage: $(basename "$0") [options]
|
|
36
|
+
|
|
37
|
+
Required:
|
|
38
|
+
-g, --resource-group <name> Resource group name (created if missing)
|
|
39
|
+
|
|
40
|
+
Optional:
|
|
41
|
+
-s, --subscription <id> Azure subscription ID (default: current az CLI subscription)
|
|
42
|
+
-l, --location <region> Azure region (default: swedencentral)
|
|
43
|
+
-n, --account-name <name> Foundry account name (default: sofia-foundry)
|
|
44
|
+
-m, --model <name> Model deployment name (default: gpt-4.1-mini)
|
|
45
|
+
-h, --help Show this help message
|
|
46
|
+
EOF
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
while [[ $# -gt 0 ]]; do
|
|
50
|
+
case "$1" in
|
|
51
|
+
-s|--subscription)
|
|
52
|
+
SUBSCRIPTION="$2"; shift 2 ;;
|
|
53
|
+
-g|--resource-group)
|
|
54
|
+
RESOURCE_GROUP="$2"; shift 2 ;;
|
|
55
|
+
-l|--location)
|
|
56
|
+
LOCATION="$2"; shift 2 ;;
|
|
57
|
+
-n|--account-name)
|
|
58
|
+
ACCOUNT_NAME="$2"; shift 2 ;;
|
|
59
|
+
-m|--model)
|
|
60
|
+
MODEL="$2"; shift 2 ;;
|
|
61
|
+
-h|--help)
|
|
62
|
+
usage; exit 0 ;;
|
|
63
|
+
*)
|
|
64
|
+
echo "❌ Unknown option: $1" >&2
|
|
65
|
+
usage >&2
|
|
66
|
+
exit 1 ;;
|
|
67
|
+
esac
|
|
68
|
+
done
|
|
69
|
+
|
|
70
|
+
# ── Validate required parameters ─────────────────────────────────────────────
|
|
71
|
+
|
|
72
|
+
if [[ -z "$RESOURCE_GROUP" ]]; then
|
|
73
|
+
echo "❌ Missing required parameter: --resource-group (-g)" >&2
|
|
74
|
+
usage >&2
|
|
75
|
+
exit 1
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
# ── Prerequisite checks ──────────────────────────────────────────────────────
|
|
79
|
+
|
|
80
|
+
echo "🔍 Checking prerequisites..."
|
|
81
|
+
|
|
82
|
+
# Check az CLI is installed
|
|
83
|
+
if ! command -v az &>/dev/null; then
|
|
84
|
+
echo "❌ Azure CLI (az) is not installed." >&2
|
|
85
|
+
echo " Install: https://learn.microsoft.com/en-us/cli/azure/install-azure-cli" >&2
|
|
86
|
+
exit 1
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
# Check user is logged in
|
|
90
|
+
if ! az account show &>/dev/null; then
|
|
91
|
+
echo "❌ Not logged in to Azure. Run 'az login' first." >&2
|
|
92
|
+
exit 1
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
# Optionally set subscription
|
|
96
|
+
if [[ -n "$SUBSCRIPTION" ]]; then
|
|
97
|
+
echo "📋 Setting subscription to: $SUBSCRIPTION"
|
|
98
|
+
if ! az account set --subscription "$SUBSCRIPTION" 2>/dev/null; then
|
|
99
|
+
echo "❌ Could not set subscription '$SUBSCRIPTION'." >&2
|
|
100
|
+
echo " Check the subscription ID and your permissions." >&2
|
|
101
|
+
exit 1
|
|
102
|
+
fi
|
|
103
|
+
fi
|
|
104
|
+
|
|
105
|
+
echo "✅ Prerequisites passed"
|
|
106
|
+
|
|
107
|
+
# ── Resolve current user's principal (object) ID for RBAC ─────────────────────
|
|
108
|
+
|
|
109
|
+
echo "🔑 Resolving current user's principal ID..."
|
|
110
|
+
USER_PRINCIPAL_ID=$(az ad signed-in-user show --query id -o tsv 2>/dev/null || true)
|
|
111
|
+
if [[ -z "$USER_PRINCIPAL_ID" ]]; then
|
|
112
|
+
echo "⚠️ Could not resolve user principal ID. Role assignment will be skipped." >&2
|
|
113
|
+
echo " You may need to manually assign the 'Azure AI Developer' role." >&2
|
|
114
|
+
else
|
|
115
|
+
echo " Principal ID: $USER_PRINCIPAL_ID"
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
# ── Deploy ────────────────────────────────────────────────────────────────────
|
|
119
|
+
|
|
120
|
+
echo ""
|
|
121
|
+
echo "🚀 Deploying Azure AI Foundry infrastructure..."
|
|
122
|
+
echo " Resource Group: $RESOURCE_GROUP"
|
|
123
|
+
echo " Location: $LOCATION"
|
|
124
|
+
echo " Account: $ACCOUNT_NAME"
|
|
125
|
+
echo " Model: $MODEL"
|
|
126
|
+
echo ""
|
|
127
|
+
|
|
128
|
+
DEPLOYMENT_NAME="sofia-foundry-$(date +%Y%m%d%H%M%S)"
|
|
129
|
+
|
|
130
|
+
if ! az deployment sub create \
|
|
131
|
+
--location "$LOCATION" \
|
|
132
|
+
--name "$DEPLOYMENT_NAME" \
|
|
133
|
+
--template-file "$SCRIPT_DIR/main.bicep" \
|
|
134
|
+
--parameters "$SCRIPT_DIR/main.bicepparam" \
|
|
135
|
+
--parameters \
|
|
136
|
+
resourceGroupName="$RESOURCE_GROUP" \
|
|
137
|
+
location="$LOCATION" \
|
|
138
|
+
accountName="$ACCOUNT_NAME" \
|
|
139
|
+
modelDeploymentName="$MODEL" \
|
|
140
|
+
modelName="$MODEL" \
|
|
141
|
+
userPrincipalId="$USER_PRINCIPAL_ID" \
|
|
142
|
+
--output json; then
|
|
143
|
+
echo "" >&2
|
|
144
|
+
echo "❌ Deployment failed." >&2
|
|
145
|
+
echo " Check the error above for details." >&2
|
|
146
|
+
echo " Common issues:" >&2
|
|
147
|
+
echo " - Insufficient permissions (need Owner or Contributor)" >&2
|
|
148
|
+
echo " - Region doesn't support AI Foundry Agent Service" >&2
|
|
149
|
+
echo " - Resource name conflict (try a different --account-name)" >&2
|
|
150
|
+
exit 2
|
|
151
|
+
fi
|
|
152
|
+
|
|
153
|
+
# ── Query outputs ─────────────────────────────────────────────────────────────
|
|
154
|
+
|
|
155
|
+
PROJECT_ENDPOINT=$(az deployment sub show \
|
|
156
|
+
--name "$DEPLOYMENT_NAME" \
|
|
157
|
+
--query "properties.outputs.projectEndpoint.value" \
|
|
158
|
+
--output tsv 2>/dev/null || echo "")
|
|
159
|
+
|
|
160
|
+
MODEL_DEPLOYMENT_NAME=$(az deployment sub show \
|
|
161
|
+
--name "$DEPLOYMENT_NAME" \
|
|
162
|
+
--query "properties.outputs.modelDeploymentName.value" \
|
|
163
|
+
--output tsv 2>/dev/null || echo "$MODEL")
|
|
164
|
+
|
|
165
|
+
# ── Write .env file ───────────────────────────────────────────────────────────
|
|
166
|
+
|
|
167
|
+
ENV_FILE="$SCRIPT_DIR/../.env"
|
|
168
|
+
|
|
169
|
+
# Helper: set or update a KEY=VALUE in the .env file
|
|
170
|
+
set_env_var() {
|
|
171
|
+
local key="$1" value="$2"
|
|
172
|
+
if [[ -f "$ENV_FILE" ]] && grep -q "^${key}=" "$ENV_FILE"; then
|
|
173
|
+
# Update existing entry (portable sed -i)
|
|
174
|
+
sed -i "s|^${key}=.*|${key}=\"${value}\"|" "$ENV_FILE"
|
|
175
|
+
else
|
|
176
|
+
echo "${key}=\"${value}\"" >> "$ENV_FILE"
|
|
177
|
+
fi
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
set_env_var "FOUNDRY_PROJECT_ENDPOINT" "$PROJECT_ENDPOINT"
|
|
181
|
+
set_env_var "FOUNDRY_MODEL_DEPLOYMENT_NAME" "$MODEL_DEPLOYMENT_NAME"
|
|
182
|
+
|
|
183
|
+
# ── Output ────────────────────────────────────────────────────────────────────
|
|
184
|
+
|
|
185
|
+
echo ""
|
|
186
|
+
echo "✅ Deployment complete!"
|
|
187
|
+
echo ""
|
|
188
|
+
echo "Environment variables written to $(realpath "$ENV_FILE"):"
|
|
189
|
+
echo ""
|
|
190
|
+
echo " FOUNDRY_PROJECT_ENDPOINT=\"$PROJECT_ENDPOINT\""
|
|
191
|
+
echo " FOUNDRY_MODEL_DEPLOYMENT_NAME=\"$MODEL_DEPLOYMENT_NAME\""
|
|
192
|
+
echo ""
|
|
193
|
+
echo "To tear down: ./infra/teardown.sh --resource-group $RESOURCE_GROUP"
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ──────────────────────────────────────────────────────────────────────────────
|
|
3
|
+
# gather-env.sh — Fetch environment values from an existing Azure AI Foundry
|
|
4
|
+
# resource group without redeploying.
|
|
5
|
+
#
|
|
6
|
+
# Queries the AI Services account and project already provisioned by deploy.sh,
|
|
7
|
+
# then writes (or updates) the .env file with the same variables.
|
|
8
|
+
#
|
|
9
|
+
# Usage:
|
|
10
|
+
# ./infra/gather-env.sh --resource-group <name> [options]
|
|
11
|
+
#
|
|
12
|
+
# Exit codes:
|
|
13
|
+
# 0 — Values gathered and written successfully
|
|
14
|
+
# 1 — Prerequisite / parameter check failed
|
|
15
|
+
# 2 — Resource query failed
|
|
16
|
+
# ──────────────────────────────────────────────────────────────────────────────
|
|
17
|
+
set -euo pipefail
|
|
18
|
+
|
|
19
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
20
|
+
|
|
21
|
+
# ── Defaults ──────────────────────────────────────────────────────────────────
|
|
22
|
+
|
|
23
|
+
SUBSCRIPTION=""
|
|
24
|
+
RESOURCE_GROUP=""
|
|
25
|
+
ACCOUNT_NAME="sofia-foundry"
|
|
26
|
+
MODEL=""
|
|
27
|
+
|
|
28
|
+
# ── Parameter parsing ─────────────────────────────────────────────────────────
|
|
29
|
+
|
|
30
|
+
usage() {
|
|
31
|
+
cat <<EOF
|
|
32
|
+
Usage: $(basename "$0") [options]
|
|
33
|
+
|
|
34
|
+
Required:
|
|
35
|
+
-g, --resource-group <name> Resource group containing the Foundry resources
|
|
36
|
+
|
|
37
|
+
Optional:
|
|
38
|
+
-s, --subscription <id> Azure subscription ID (default: current az CLI subscription)
|
|
39
|
+
-n, --account-name <name> AI Services account name (default: sofia-foundry)
|
|
40
|
+
-m, --model <name> Override model deployment name (default: auto-detected)
|
|
41
|
+
-h, --help Show this help message
|
|
42
|
+
EOF
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
while [[ $# -gt 0 ]]; do
|
|
46
|
+
case "$1" in
|
|
47
|
+
-s|--subscription)
|
|
48
|
+
SUBSCRIPTION="$2"; shift 2 ;;
|
|
49
|
+
-g|--resource-group)
|
|
50
|
+
RESOURCE_GROUP="$2"; shift 2 ;;
|
|
51
|
+
-n|--account-name)
|
|
52
|
+
ACCOUNT_NAME="$2"; shift 2 ;;
|
|
53
|
+
-m|--model)
|
|
54
|
+
MODEL="$2"; shift 2 ;;
|
|
55
|
+
-h|--help)
|
|
56
|
+
usage; exit 0 ;;
|
|
57
|
+
*)
|
|
58
|
+
echo "❌ Unknown option: $1" >&2
|
|
59
|
+
usage >&2
|
|
60
|
+
exit 1 ;;
|
|
61
|
+
esac
|
|
62
|
+
done
|
|
63
|
+
|
|
64
|
+
# ── Validate required parameters ─────────────────────────────────────────────
|
|
65
|
+
|
|
66
|
+
if [[ -z "$RESOURCE_GROUP" ]]; then
|
|
67
|
+
echo "❌ Missing required parameter: --resource-group (-g)" >&2
|
|
68
|
+
usage >&2
|
|
69
|
+
exit 1
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
# ── Prerequisite checks ──────────────────────────────────────────────────────
|
|
73
|
+
|
|
74
|
+
echo "🔍 Checking prerequisites..."
|
|
75
|
+
|
|
76
|
+
if ! command -v az &>/dev/null; then
|
|
77
|
+
echo "❌ Azure CLI (az) is not installed." >&2
|
|
78
|
+
echo " Install: https://learn.microsoft.com/en-us/cli/azure/install-azure-cli" >&2
|
|
79
|
+
exit 1
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
if ! az account show &>/dev/null; then
|
|
83
|
+
echo "❌ Not logged in to Azure. Run 'az login' first." >&2
|
|
84
|
+
exit 1
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
if [[ -n "$SUBSCRIPTION" ]]; then
|
|
88
|
+
echo "📋 Setting subscription to: $SUBSCRIPTION"
|
|
89
|
+
if ! az account set --subscription "$SUBSCRIPTION" 2>/dev/null; then
|
|
90
|
+
echo "❌ Could not set subscription '$SUBSCRIPTION'." >&2
|
|
91
|
+
exit 1
|
|
92
|
+
fi
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
echo "✅ Prerequisites passed"
|
|
96
|
+
|
|
97
|
+
# ── Verify resource group exists ──────────────────────────────────────────────
|
|
98
|
+
|
|
99
|
+
echo ""
|
|
100
|
+
echo "🔍 Verifying resource group: $RESOURCE_GROUP"
|
|
101
|
+
|
|
102
|
+
if ! az group show --name "$RESOURCE_GROUP" &>/dev/null; then
|
|
103
|
+
echo "❌ Resource group '$RESOURCE_GROUP' not found." >&2
|
|
104
|
+
echo " Run deploy.sh first to create the infrastructure." >&2
|
|
105
|
+
exit 2
|
|
106
|
+
fi
|
|
107
|
+
|
|
108
|
+
# ── Find the AI Services account ─────────────────────────────────────────────
|
|
109
|
+
|
|
110
|
+
echo "🔍 Looking up AI Services account: $ACCOUNT_NAME"
|
|
111
|
+
|
|
112
|
+
if ! az cognitiveservices account show \
|
|
113
|
+
--resource-group "$RESOURCE_GROUP" \
|
|
114
|
+
--name "$ACCOUNT_NAME" &>/dev/null; then
|
|
115
|
+
echo "⚠️ Account '$ACCOUNT_NAME' not found. Searching for AI Services accounts in the resource group..."
|
|
116
|
+
ACCOUNT_NAME=$(az cognitiveservices account list \
|
|
117
|
+
--resource-group "$RESOURCE_GROUP" \
|
|
118
|
+
--query "[?kind=='AIServices'].name | [0]" \
|
|
119
|
+
--output tsv 2>/dev/null || true)
|
|
120
|
+
|
|
121
|
+
if [[ -z "$ACCOUNT_NAME" ]]; then
|
|
122
|
+
echo "❌ No AI Services account found in resource group '$RESOURCE_GROUP'." >&2
|
|
123
|
+
exit 2
|
|
124
|
+
fi
|
|
125
|
+
echo " Found account: $ACCOUNT_NAME"
|
|
126
|
+
fi
|
|
127
|
+
|
|
128
|
+
# ── Find the project and its endpoint ────────────────────────────────────────
|
|
129
|
+
|
|
130
|
+
echo "🔍 Looking up Foundry project..."
|
|
131
|
+
|
|
132
|
+
PROJECT_ENDPOINT=$(az cognitiveservices account show \
|
|
133
|
+
--resource-group "$RESOURCE_GROUP" \
|
|
134
|
+
--name "$ACCOUNT_NAME" \
|
|
135
|
+
--query "properties.endpoints.\"AI Foundry API\"" \
|
|
136
|
+
--output tsv 2>/dev/null || true)
|
|
137
|
+
|
|
138
|
+
# If the account-level endpoint isn't what we need, try querying the project
|
|
139
|
+
if [[ -z "$PROJECT_ENDPOINT" ]]; then
|
|
140
|
+
# List projects under the account
|
|
141
|
+
PROJECT_NAME=$(az resource list \
|
|
142
|
+
--resource-group "$RESOURCE_GROUP" \
|
|
143
|
+
--resource-type "Microsoft.CognitiveServices/accounts/projects" \
|
|
144
|
+
--query "[0].name" \
|
|
145
|
+
--output tsv 2>/dev/null || true)
|
|
146
|
+
|
|
147
|
+
if [[ -n "$PROJECT_NAME" ]]; then
|
|
148
|
+
# The resource name is "account/project", extract just the project part
|
|
149
|
+
LOCAL_PROJECT="${PROJECT_NAME##*/}"
|
|
150
|
+
echo " Found project: $LOCAL_PROJECT"
|
|
151
|
+
|
|
152
|
+
PROJECT_ENDPOINT=$(az rest \
|
|
153
|
+
--method GET \
|
|
154
|
+
--uri "https://management.azure.com/subscriptions/$(az account show --query id -o tsv)/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.CognitiveServices/accounts/$ACCOUNT_NAME/projects/$LOCAL_PROJECT?api-version=2025-06-01" \
|
|
155
|
+
--query "properties.endpoints.\"AI Foundry API\"" \
|
|
156
|
+
--output tsv 2>/dev/null || true)
|
|
157
|
+
fi
|
|
158
|
+
fi
|
|
159
|
+
|
|
160
|
+
if [[ -z "$PROJECT_ENDPOINT" ]]; then
|
|
161
|
+
echo "❌ Could not determine the Foundry project endpoint." >&2
|
|
162
|
+
echo " Ensure a project exists under account '$ACCOUNT_NAME'." >&2
|
|
163
|
+
exit 2
|
|
164
|
+
fi
|
|
165
|
+
|
|
166
|
+
echo " Endpoint: $PROJECT_ENDPOINT"
|
|
167
|
+
|
|
168
|
+
# ── Find the model deployment name ───────────────────────────────────────────
|
|
169
|
+
|
|
170
|
+
if [[ -z "$MODEL" ]]; then
|
|
171
|
+
echo "🔍 Looking up model deployment..."
|
|
172
|
+
MODEL=$(az cognitiveservices account deployment list \
|
|
173
|
+
--resource-group "$RESOURCE_GROUP" \
|
|
174
|
+
--name "$ACCOUNT_NAME" \
|
|
175
|
+
--query "[0].name" \
|
|
176
|
+
--output tsv 2>/dev/null || true)
|
|
177
|
+
|
|
178
|
+
if [[ -z "$MODEL" ]]; then
|
|
179
|
+
echo "⚠️ No model deployment found. Using default: gpt-4.1-mini"
|
|
180
|
+
MODEL="gpt-4.1-mini"
|
|
181
|
+
fi
|
|
182
|
+
fi
|
|
183
|
+
|
|
184
|
+
echo " Model deployment: $MODEL"
|
|
185
|
+
|
|
186
|
+
# ── Write .env file ───────────────────────────────────────────────────────────
|
|
187
|
+
|
|
188
|
+
ENV_FILE="$SCRIPT_DIR/../.env"
|
|
189
|
+
|
|
190
|
+
set_env_var() {
|
|
191
|
+
local key="$1" value="$2"
|
|
192
|
+
if [[ -f "$ENV_FILE" ]] && grep -q "^${key}=" "$ENV_FILE"; then
|
|
193
|
+
sed -i "s|^${key}=.*|${key}=\"${value}\"|" "$ENV_FILE"
|
|
194
|
+
else
|
|
195
|
+
echo "${key}=\"${value}\"" >> "$ENV_FILE"
|
|
196
|
+
fi
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
set_env_var "FOUNDRY_PROJECT_ENDPOINT" "$PROJECT_ENDPOINT"
|
|
200
|
+
set_env_var "FOUNDRY_MODEL_DEPLOYMENT_NAME" "$MODEL"
|
|
201
|
+
|
|
202
|
+
# ── Output ────────────────────────────────────────────────────────────────────
|
|
203
|
+
|
|
204
|
+
echo ""
|
|
205
|
+
echo "✅ Environment values gathered successfully!"
|
|
206
|
+
echo ""
|
|
207
|
+
echo "Written to $(realpath "$ENV_FILE"):"
|
|
208
|
+
echo ""
|
|
209
|
+
echo " FOUNDRY_PROJECT_ENDPOINT=\"$PROJECT_ENDPOINT\""
|
|
210
|
+
echo " FOUNDRY_MODEL_DEPLOYMENT_NAME=\"$MODEL\""
|
|
211
|
+
echo ""
|