lovarch-cli 0.2.1__py3-none-any.whl

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. lovarch_cli/__init__.py +16 -0
  2. lovarch_cli/__main__.py +10 -0
  3. lovarch_cli/ai/__init__.py +21 -0
  4. lovarch_cli/ai/gateway.py +240 -0
  5. lovarch_cli/api.py +111 -0
  6. lovarch_cli/auth/__init__.py +32 -0
  7. lovarch_cli/auth/keyring_store.py +214 -0
  8. lovarch_cli/auth/local_server.py +165 -0
  9. lovarch_cli/auth/pkce.py +57 -0
  10. lovarch_cli/auth/session.py +189 -0
  11. lovarch_cli/cli.py +262 -0
  12. lovarch_cli/clients/__init__.py +33 -0
  13. lovarch_cli/clients/factory.py +54 -0
  14. lovarch_cli/clients/local_client.py +432 -0
  15. lovarch_cli/clients/lovarch_storage.py +174 -0
  16. lovarch_cli/clients/lovarch_supabase.py +295 -0
  17. lovarch_cli/clients/persistence.py +166 -0
  18. lovarch_cli/clients/storage.py +66 -0
  19. lovarch_cli/commands/__init__.py +10 -0
  20. lovarch_cli/commands/account.py +172 -0
  21. lovarch_cli/commands/audit.py +394 -0
  22. lovarch_cli/commands/config_cmd.py +80 -0
  23. lovarch_cli/commands/consolidate.py +217 -0
  24. lovarch_cli/commands/context_cmd.py +73 -0
  25. lovarch_cli/commands/dev.py +287 -0
  26. lovarch_cli/commands/do_cmd.py +120 -0
  27. lovarch_cli/commands/init.py +218 -0
  28. lovarch_cli/commands/jobs_cmd.py +95 -0
  29. lovarch_cli/commands/login.py +202 -0
  30. lovarch_cli/commands/mcp_cmd.py +26 -0
  31. lovarch_cli/commands/run.py +375 -0
  32. lovarch_cli/commands/signup.py +185 -0
  33. lovarch_cli/commands/status.py +243 -0
  34. lovarch_cli/commands/upgrade.py +108 -0
  35. lovarch_cli/commands/verifica_cmd.py +174 -0
  36. lovarch_cli/config.py +101 -0
  37. lovarch_cli/config_store.py +111 -0
  38. lovarch_cli/credits/__init__.py +35 -0
  39. lovarch_cli/credits/base.py +84 -0
  40. lovarch_cli/credits/factory.py +36 -0
  41. lovarch_cli/credits/local.py +34 -0
  42. lovarch_cli/credits/lovarch.py +56 -0
  43. lovarch_cli/i18n/__init__.py +27 -0
  44. lovarch_cli/i18n/loader.py +121 -0
  45. lovarch_cli/i18n/translations/en.json +168 -0
  46. lovarch_cli/i18n/translations/es.json +168 -0
  47. lovarch_cli/i18n/translations/it.json +168 -0
  48. lovarch_cli/i18n/translations/pt.json +168 -0
  49. lovarch_cli/mcp/__init__.py +9 -0
  50. lovarch_cli/mcp/server.py +199 -0
  51. lovarch_cli/mcp/tools.py +372 -0
  52. lovarch_cli/sample_downloader.py +255 -0
  53. lovarch_cli/squad/README.md +206 -0
  54. lovarch_cli/squad/agents/auditor-input.md +353 -0
  55. lovarch_cli/squad/agents/bim-engineer.md +404 -0
  56. lovarch_cli/squad/agents/briefing-architect.md +249 -0
  57. lovarch_cli/squad/agents/cad-engineer.md +278 -0
  58. lovarch_cli/squad/agents/capitolato-writer.md +256 -0
  59. lovarch_cli/squad/agents/computo-engineer.md +258 -0
  60. lovarch_cli/squad/agents/concept-designer.md +399 -0
  61. lovarch_cli/squad/agents/contratto-architect.md +243 -0
  62. lovarch_cli/squad/agents/deliverable-builder.md +253 -0
  63. lovarch_cli/squad/agents/energy-prelim.md +388 -0
  64. lovarch_cli/squad/agents/pratiche-it.md +251 -0
  65. lovarch_cli/squad/agents/progetto-chief.md +768 -0
  66. lovarch_cli/squad/agents/quality-dati.md +409 -0
  67. lovarch_cli/squad/agents/quality-misure.md +418 -0
  68. lovarch_cli/squad/agents/quality-normativa.md +417 -0
  69. lovarch_cli/squad/agents/quality-output.md +436 -0
  70. lovarch_cli/squad/agents/regolatorio-it.md +278 -0
  71. lovarch_cli/squad/checklists/handoff-quality-gate.md +232 -0
  72. lovarch_cli/squad/checklists/quality-dati-checklist.md +134 -0
  73. lovarch_cli/squad/checklists/quality-misure-checklist.md +139 -0
  74. lovarch_cli/squad/checklists/quality-normativa-checklist.md +121 -0
  75. lovarch_cli/squad/checklists/quality-output-checklist.md +116 -0
  76. lovarch_cli/squad/config.yaml +408 -0
  77. lovarch_cli/squad/data/CHANGELOG.md +272 -0
  78. lovarch_cli/squad/data/agents-prd.md +428 -0
  79. lovarch_cli/squad/data/architettura-progetto-rules.md +328 -0
  80. lovarch_cli/squad/data/handoff-card-template.md +231 -0
  81. lovarch_cli/squad/data/mocks/catasto-visura.json +72 -0
  82. lovarch_cli/squad/data/mocks/firma-envelope.json +43 -0
  83. lovarch_cli/squad/data/prezzario-lombardia-sample.json +312 -0
  84. lovarch_cli/squad/scripts/api_clients.py +206 -0
  85. lovarch_cli/squad/scripts/architect_profile.py +276 -0
  86. lovarch_cli/squad/scripts/deliverable_generators.py +844 -0
  87. lovarch_cli/squad/scripts/generate_attico_brera_dwg.py +369 -0
  88. lovarch_cli/squad/scripts/generate_chianti_dxf.py +368 -0
  89. lovarch_cli/squad/scripts/generate_chianti_images.py +223 -0
  90. lovarch_cli/squad/scripts/generate_real_sample_images.py +189 -0
  91. lovarch_cli/squad/scripts/generate_sample_assets.py +382 -0
  92. lovarch_cli/squad/scripts/lovarch_client.py +1046 -0
  93. lovarch_cli/squad/scripts/pipeline_runner.py +2095 -0
  94. lovarch_cli/squad/scripts/render_dxf_to_png.py +57 -0
  95. lovarch_cli/squad/scripts/run_palestra_demo.sh +277 -0
  96. lovarch_cli/squad/scripts/simulate_squad_execution.py +515 -0
  97. lovarch_cli/squad/scripts/validate-squad.py +383 -0
  98. lovarch_cli/squad/tasks/audit-input.md +146 -0
  99. lovarch_cli/squad/tasks/compute-metric.md +105 -0
  100. lovarch_cli/squad/tasks/consolidate-dossier.md +187 -0
  101. lovarch_cli/squad/tasks/generate-cad-plan.md +120 -0
  102. lovarch_cli/squad/tasks/generate-ifc-model.md +108 -0
  103. lovarch_cli/squad/tasks/write-capitolato.md +100 -0
  104. lovarch_cli/squad/templates/asseverazione-tecnica.md +126 -0
  105. lovarch_cli/squad/templates/capitolato-uni-11337.md +235 -0
  106. lovarch_cli/squad/templates/cila-comune-milano.md +177 -0
  107. lovarch_cli/squad/templates/contratto-cnappc.md +220 -0
  108. lovarch_cli/squad/workflows/dal-brief-al-cantiere.yaml +218 -0
  109. lovarch_cli/squad_loader.py +114 -0
  110. lovarch_cli/verify/__init__.py +15 -0
  111. lovarch_cli/verify/contratto.py +110 -0
  112. lovarch_cli/verify/dossier.py +97 -0
  113. lovarch_cli/verify/misure.py +83 -0
  114. lovarch_cli/verify/normativa.py +178 -0
  115. lovarch_cli/version.py +13 -0
  116. lovarch_cli/workflows/__init__.py +9 -0
  117. lovarch_cli/workflows/platform.py +212 -0
  118. lovarch_cli-0.2.1.dist-info/METADATA +232 -0
  119. lovarch_cli-0.2.1.dist-info/RECORD +122 -0
  120. lovarch_cli-0.2.1.dist-info/WHEEL +4 -0
  121. lovarch_cli-0.2.1.dist-info/entry_points.txt +3 -0
  122. lovarch_cli-0.2.1.dist-info/licenses/LICENSE +38 -0
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env python3
2
+ """Render stato-attuale.dxf to PNG using ezdxf + matplotlib."""
3
+
4
+ from pathlib import Path
5
+ import ezdxf
6
+ from ezdxf.addons.drawing import RenderContext, Frontend
7
+ from ezdxf.addons.drawing.matplotlib import MatplotlibBackend
8
+ import matplotlib.pyplot as plt
9
+
10
+ ROOT = Path(__file__).resolve().parents[1]
11
+ DXF_PATH = ROOT / "data" / "sample-input" / "stato-attuale.dxf"
12
+ OUT_PATH = ROOT / "data" / "sample-input" / "stato-attuale.png"
13
+
14
+
15
+ def main():
16
+ print(f"Loading DXF: {DXF_PATH}")
17
+ doc = ezdxf.readfile(DXF_PATH)
18
+ msp = doc.modelspace()
19
+
20
+ fig, ax = plt.subplots(figsize=(16, 12), dpi=150)
21
+ ax.set_facecolor("#0A0A0A")
22
+ fig.patch.set_facecolor("#0A0A0A")
23
+
24
+ ctx = RenderContext(doc)
25
+ ctx.set_current_layout(msp)
26
+
27
+ # Customize layer colors for dark background
28
+ for layer in doc.layers:
29
+ name = layer.dxf.name.upper()
30
+ if "MURI" in name or "WALL" in name or "MURO" in name:
31
+ layer.color = 7 # white-ish
32
+ elif "PORTE" in name or "DOOR" in name:
33
+ layer.color = 3 # green
34
+ elif "FINESTRE" in name or "WINDOW" in name:
35
+ layer.color = 5 # blue
36
+ elif "QUOTE" in name or "DIM" in name:
37
+ layer.color = 2 # yellow
38
+ elif "TESTI" in name or "TEXT" in name:
39
+ layer.color = 6 # magenta
40
+ elif "ARRED" in name or "FURN" in name:
41
+ layer.color = 8 # grey
42
+ else:
43
+ layer.color = 7
44
+
45
+ out_backend = MatplotlibBackend(ax)
46
+ Frontend(ctx, out_backend).draw_layout(msp, finalize=True)
47
+
48
+ ax.set_aspect("equal")
49
+ ax.axis("off")
50
+ plt.tight_layout(pad=0)
51
+ plt.savefig(OUT_PATH, dpi=150, bbox_inches="tight", facecolor="#0A0A0A", pad_inches=0.2)
52
+ print(f"✓ saved: {OUT_PATH}")
53
+ print(f" size: {OUT_PATH.stat().st_size // 1024} KB")
54
+
55
+
56
+ if __name__ == "__main__":
57
+ main()
@@ -0,0 +1,277 @@
1
+ #!/usr/bin/env bash
2
+ # ================================================================================
3
+ # Run Palestra Demo · Squad Architettura-Progetto
4
+ #
5
+ # Orchestratore principale per la demo Salone del Mobile 2026.
6
+ # Modalità:
7
+ # --simulate Usa simulator (sicuro, fake-realistic, ~14 min)
8
+ # --simulate --fast Simulator velocizzato 5× (~3 min, per test)
9
+ # --real Esegue squad reale via Claude Code (futuro)
10
+ # --check Solo check prerequisites, no run
11
+ #
12
+ # Default: --simulate (più sicuro per la palestra)
13
+ #
14
+ # Usage:
15
+ # ./run_palestra_demo.sh # default safe demo (simulate)
16
+ # ./run_palestra_demo.sh --simulate --fast # quick test
17
+ # ./run_palestra_demo.sh --check # health check only
18
+ # ================================================================================
19
+
20
+ set -euo pipefail
21
+
22
+ # ------------------------------------------------------------------------------
23
+ # Config
24
+ # ------------------------------------------------------------------------------
25
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
26
+ SQUAD_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
27
+ LOVARCH_DIR="$(cd "${SQUAD_DIR}/../.." && pwd)"
28
+ SECRETS_FILE="${HOME}/.lovarch/secrets.env"
29
+
30
+ PROJECT_INPUT_DIR="${HOME}/projects/attico-brera"
31
+
32
+ # Colors
33
+ RED='\033[0;31m'
34
+ GREEN='\033[0;32m'
35
+ YELLOW='\033[1;33m'
36
+ GOLD='\033[1;33m'
37
+ BLUE='\033[0;34m'
38
+ NC='\033[0m' # No Color
39
+
40
+ # ------------------------------------------------------------------------------
41
+ # Helpers
42
+ # ------------------------------------------------------------------------------
43
+ log() { echo -e "${BLUE}[$(date +%H:%M:%S)]${NC} $*"; }
44
+ ok() { echo -e "${GREEN}✓${NC} $*"; }
45
+ warn() { echo -e "${YELLOW}⚠${NC} $*"; }
46
+ err() { echo -e "${RED}✗${NC} $*" >&2; }
47
+
48
+ banner() {
49
+ echo ""
50
+ echo -e "${GOLD}════════════════════════════════════════════════════════════════════${NC}"
51
+ echo -e "${GOLD} $1${NC}"
52
+ echo -e "${GOLD}════════════════════════════════════════════════════════════════════${NC}"
53
+ echo ""
54
+ }
55
+
56
+ # ------------------------------------------------------------------------------
57
+ # Args
58
+ # ------------------------------------------------------------------------------
59
+ MODE="simulate"
60
+ SPEED="1.0"
61
+ CHECK_ONLY=0
62
+ USER_ID=""
63
+
64
+ while [[ $# -gt 0 ]]; do
65
+ case "$1" in
66
+ --simulate) MODE="simulate"; shift ;;
67
+ --real) MODE="real"; shift ;;
68
+ --check) CHECK_ONLY=1; shift ;;
69
+ --fast) SPEED="5.0"; shift ;;
70
+ --speed) SPEED="$2"; shift 2 ;;
71
+ --user-id) USER_ID="$2"; shift 2 ;;
72
+ --help|-h)
73
+ head -22 "$0" | tail -19
74
+ exit 0 ;;
75
+ *)
76
+ err "Unknown arg: $1"
77
+ exit 1 ;;
78
+ esac
79
+ done
80
+
81
+ # ------------------------------------------------------------------------------
82
+ # Banner
83
+ # ------------------------------------------------------------------------------
84
+ banner "Squad Architettura-Progetto · Palestra Demo Runner"
85
+ log "Mode: $MODE"
86
+ log "Speed: ${SPEED}× $([ "$SPEED" = "1.0" ] && echo '(real time)' || echo '(accelerated)')"
87
+ log "Squad dir: $SQUAD_DIR"
88
+ log "Lovarch dir: $LOVARCH_DIR"
89
+ log "Project input: $PROJECT_INPUT_DIR"
90
+ echo ""
91
+
92
+ # ------------------------------------------------------------------------------
93
+ # Step 1 · Check prerequisites
94
+ # ------------------------------------------------------------------------------
95
+ banner "Step 1 · Pre-flight checks"
96
+
97
+ PASS=1
98
+ fail() { err "$1"; PASS=0; }
99
+
100
+ # Python 3
101
+ if command -v python3 >/dev/null 2>&1; then
102
+ ok "python3: $(python3 --version)"
103
+ else
104
+ fail "python3 missing · brew install python@3.11"
105
+ fi
106
+
107
+ # ezdxf
108
+ if python3 -c "import ezdxf" 2>/dev/null; then
109
+ ok "ezdxf: $(python3 -c 'import ezdxf; print(ezdxf.__version__)')"
110
+ else
111
+ warn "ezdxf missing · pip3 install --user ezdxf"
112
+ fi
113
+
114
+ # Secrets file
115
+ if [[ -f "$SECRETS_FILE" ]]; then
116
+ ok "secrets file: $SECRETS_FILE"
117
+ source "$SECRETS_FILE" 2>/dev/null || true
118
+ else
119
+ fail "secrets file missing: $SECRETS_FILE"
120
+ fi
121
+
122
+ # Mapbox token
123
+ if [[ -n "${MAPBOX_TOKEN:-}" ]]; then
124
+ ok "MAPBOX_TOKEN: configured (${MAPBOX_TOKEN:0:20}...)"
125
+ else
126
+ fail "MAPBOX_TOKEN missing in $SECRETS_FILE"
127
+ fi
128
+
129
+ # Supabase secrets (only required for real run, optional for dry-run)
130
+ if [[ -n "${SUPABASE_URL:-}" && -n "${SUPABASE_SERVICE_ROLE_KEY:-}" ]]; then
131
+ ok "Supabase: $SUPABASE_URL"
132
+ elif [[ "$MODE" = "simulate" && $CHECK_ONLY -eq 0 ]]; then
133
+ warn "Supabase secrets missing — simulator richiede SUPABASE_URL + SUPABASE_SERVICE_ROLE_KEY"
134
+ warn "Aggiungi in $SECRETS_FILE per inserire dati nel DB"
135
+ fi
136
+
137
+ # Sample input files
138
+ if [[ -f "$SQUAD_DIR/data/sample-input/briefing-cliente.md" ]]; then
139
+ ok "briefing-cliente.md: $(wc -l < "$SQUAD_DIR/data/sample-input/briefing-cliente.md") righe"
140
+ else
141
+ fail "briefing-cliente.md missing"
142
+ fi
143
+
144
+ # Templates
145
+ TEMPLATES_FOUND=$(find "$SQUAD_DIR/templates" -name '*.md' 2>/dev/null | wc -l | tr -d ' ')
146
+ if [[ "$TEMPLATES_FOUND" -ge 4 ]]; then
147
+ ok "templates: $TEMPLATES_FOUND files"
148
+ else
149
+ fail "templates incomplete (found $TEMPLATES_FOUND, expected ≥4)"
150
+ fi
151
+
152
+ # Prezzario
153
+ if [[ -f "$SQUAD_DIR/data/prezzario-lombardia-sample.json" ]]; then
154
+ PREZZI_COUNT=$(python3 -c "import json; print(len(json.load(open('$SQUAD_DIR/data/prezzario-lombardia-sample.json'))['voci']))" 2>/dev/null || echo "?")
155
+ ok "prezzario lombardia: $PREZZI_COUNT voci"
156
+ else
157
+ fail "prezzario sample missing"
158
+ fi
159
+
160
+ # Final check verdict
161
+ if [[ $PASS -eq 0 ]]; then
162
+ err ""
163
+ err "Pre-flight FAILED. Fix issues sopra e riprova."
164
+ exit 1
165
+ fi
166
+
167
+ ok ""
168
+ ok "All checks passed."
169
+
170
+ # Stop here if --check only
171
+ if [[ $CHECK_ONLY -eq 1 ]]; then
172
+ banner "Check-only mode · stopping"
173
+ exit 0
174
+ fi
175
+
176
+ # ------------------------------------------------------------------------------
177
+ # Step 2 · Prepare project input directory
178
+ # ------------------------------------------------------------------------------
179
+ banner "Step 2 · Preparing project input"
180
+
181
+ mkdir -p "$PROJECT_INPUT_DIR/01-input/foto"
182
+ log "Created $PROJECT_INPUT_DIR/"
183
+
184
+ # Copy briefing
185
+ cp "$SQUAD_DIR/data/sample-input/briefing-cliente.md" "$PROJECT_INPUT_DIR/01-input/briefing-cliente.md"
186
+ ok "briefing-cliente.md copied"
187
+
188
+ # Generate DWG
189
+ if [[ ! -f "$PROJECT_INPUT_DIR/01-input/stato-attuale.dxf" ]]; then
190
+ log "Generating stato-attuale.dxf..."
191
+ if python3 "$SQUAD_DIR/scripts/generate_attico_brera_dwg.py" \
192
+ "$PROJECT_INPUT_DIR/01-input/stato-attuale.dxf" >/dev/null 2>&1; then
193
+ ok "stato-attuale.dxf generated ($(du -h "$PROJECT_INPUT_DIR/01-input/stato-attuale.dxf" | cut -f1))"
194
+ else
195
+ warn "DWG generation failed (ezdxf not installed?)"
196
+ fi
197
+ else
198
+ ok "stato-attuale.dxf already exists"
199
+ fi
200
+
201
+ # Sync templates
202
+ mkdir -p "$PROJECT_INPUT_DIR/templates"
203
+ cp -n "$SQUAD_DIR/templates"/*.md "$PROJECT_INPUT_DIR/templates/" 2>/dev/null || true
204
+ ok "templates synced ($(ls "$PROJECT_INPUT_DIR/templates" | wc -l | tr -d ' ') files)"
205
+
206
+ # Sync prezzario
207
+ mkdir -p "$PROJECT_INPUT_DIR/data"
208
+ cp -n "$SQUAD_DIR/data/prezzario-lombardia-sample.json" "$PROJECT_INPUT_DIR/data/" 2>/dev/null || true
209
+ ok "prezzario synced"
210
+
211
+ log ""
212
+ log "Project input ready: $PROJECT_INPUT_DIR"
213
+ ls -la "$PROJECT_INPUT_DIR/01-input"
214
+
215
+ # ------------------------------------------------------------------------------
216
+ # Step 3 · Resolve user_id (admin Pablo)
217
+ # ------------------------------------------------------------------------------
218
+ banner "Step 3 · Resolving Supabase user_id"
219
+
220
+ if [[ -z "$USER_ID" && -n "${SUPABASE_URL:-}" && -n "${SUPABASE_SERVICE_ROLE_KEY:-}" ]]; then
221
+ USER_ID=$(curl -s "${SUPABASE_URL}/rest/v1/profiles?email=eq.pablo@archprime.io&select=id" \
222
+ -H "apikey: ${SUPABASE_SERVICE_ROLE_KEY}" \
223
+ -H "Authorization: Bearer ${SUPABASE_SERVICE_ROLE_KEY}" \
224
+ | python3 -c "import sys,json; d=json.load(sys.stdin); print(d[0]['id'] if d else '')" 2>/dev/null || echo "")
225
+ fi
226
+
227
+ if [[ -n "$USER_ID" ]]; then
228
+ ok "user_id: $USER_ID"
229
+ else
230
+ warn "user_id not resolved · usando placeholder UUID"
231
+ USER_ID="00000000-0000-0000-0000-000000000000"
232
+ fi
233
+
234
+ # ------------------------------------------------------------------------------
235
+ # Step 4 · Execute simulation OR real squad
236
+ # ------------------------------------------------------------------------------
237
+ banner "Step 4 · Execution"
238
+
239
+ if [[ "$MODE" = "simulate" ]]; then
240
+ log "Running simulator at speed ${SPEED}×..."
241
+ log ""
242
+ python3 "$SQUAD_DIR/scripts/simulate_squad_execution.py" \
243
+ --user-id "$USER_ID" \
244
+ --speed "$SPEED"
245
+ elif [[ "$MODE" = "real" ]]; then
246
+ warn "REAL mode: launching Claude Code with squad architettura-progetto"
247
+ warn "Questa modalità richiede Claude Code installato e configurato."
248
+ echo ""
249
+ log "Comando suggerito:"
250
+ echo ""
251
+ echo -e "${GOLD} cd $LOVARCH_DIR${NC}"
252
+ echo -e "${GOLD} claude \"Squad architettura-progetto: esegui workflow dal-brief-al-cantiere${NC}"
253
+ echo -e "${GOLD} con input $PROJECT_INPUT_DIR/01-input/\"${NC}"
254
+ echo ""
255
+ read -r -p "Lancio? (y/N) " yn
256
+ if [[ "$yn" = "y" || "$yn" = "Y" ]]; then
257
+ cd "$LOVARCH_DIR"
258
+ claude "Squad architettura-progetto: esegui workflow dal-brief-al-cantiere con input $PROJECT_INPUT_DIR/01-input/"
259
+ else
260
+ log "Skipped."
261
+ exit 0
262
+ fi
263
+ fi
264
+
265
+ # ------------------------------------------------------------------------------
266
+ # Step 5 · Final
267
+ # ------------------------------------------------------------------------------
268
+ banner "Demo complete"
269
+
270
+ ok "Esecuzione completata."
271
+ log ""
272
+ log "Per visualizzare la live page e il dossier:"
273
+ log " https://lovarch.com/admin · login admin"
274
+ log " Vai su: /admin/squad-execution/{execution_id}/live"
275
+ log " Poi: /admin/squad-execution/{execution_id}/dossier"
276
+ log ""
277
+ log "L'ID dell'esecuzione è stampato sopra. Buona presentazione!"