rootkid0-initializer 0.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/.opencode/README.md +38 -0
- package/.opencode/agents/README.md +12 -0
- package/.opencode/agents/architect.md +16 -0
- package/.opencode/agents/implementer.md +16 -0
- package/.opencode/agents/ops.md +15 -0
- package/.opencode/agents/reviewer.md +12 -0
- package/.opencode/context.md +36 -0
- package/.opencode/mcp/README.md +34 -0
- package/.opencode/mcp/servers.recommended.template.json +30 -0
- package/.opencode/mcp/servers.template.json +18 -0
- package/.opencode/skills/global/SKILL.md +20 -0
- package/.opencode/templates/subproject-agents.template.md +20 -0
- package/.opencode/templates/subproject-skill.template.md +9 -0
- package/01-business/01-business-understanding.md +22 -0
- package/01-business/02-problem-statement.md +15 -0
- package/01-business/03-as-is-flow.md +17 -0
- package/01-business/04-scope-definition.md +17 -0
- package/01-business/05-assumptions-risks.md +17 -0
- package/01-business/AGENTS.md +32 -0
- package/01-business/DISCOVERY-OPERATING-MODEL.md +74 -0
- package/01-business/skills/SKILL.md +12 -0
- package/02-proposal/01-proposal.md +27 -0
- package/02-proposal/AGENTS.md +28 -0
- package/02-proposal/PROPOSAL-OPERATING-MODEL.md +77 -0
- package/02-proposal/skills/SKILL.md +11 -0
- package/03-design/01-architecture-overview.md +17 -0
- package/03-design/02-to-be-flow.md +16 -0
- package/03-design/03-components.md +12 -0
- package/03-design/04-data-model.md +17 -0
- package/03-design/05-api-contracts.md +18 -0
- package/03-design/06-error-handling.md +19 -0
- package/03-design/AGENTS.md +33 -0
- package/03-design/DESIGN-OPERATING-MODEL.md +83 -0
- package/03-design/skills/SKILL.md +11 -0
- package/04-management/01-project-overview.md +17 -0
- package/04-management/02-roadmap.md +14 -0
- package/04-management/03-backlog.md +11 -0
- package/04-management/04-sprints.md +12 -0
- package/04-management/05-risks.md +12 -0
- package/04-management/06-change-log.md +11 -0
- package/04-management/AGENTS.md +33 -0
- package/04-management/MANAGEMENT-OPERATING-MODEL.md +83 -0
- package/04-management/skills/SKILL.md +11 -0
- package/05-development/01-setup.md +13 -0
- package/05-development/02-standards.md +12 -0
- package/05-development/03-testing.md +12 -0
- package/05-development/04-structure.md +11 -0
- package/05-development/AGENTS.md +31 -0
- package/05-development/DEVELOPMENT-OPERATING-MODEL.md +82 -0
- package/05-development/skills/SKILL.md +11 -0
- package/06-deployment/01-environments.md +11 -0
- package/06-deployment/02-ci-cd.md +13 -0
- package/06-deployment/03-config.md +11 -0
- package/06-deployment/04-monitoring.md +12 -0
- package/06-deployment/AGENTS.md +31 -0
- package/06-deployment/DEPLOYMENT-OPERATING-MODEL.md +82 -0
- package/06-deployment/skills/SKILL.md +11 -0
- package/07-production/01-operations-runbook.md +23 -0
- package/07-production/02-incident-management.md +25 -0
- package/07-production/03-performance-capacity.md +24 -0
- package/07-production/04-continuous-improvement.md +24 -0
- package/07-production/AGENTS.md +31 -0
- package/07-production/PRODUCTION-OPERATING-MODEL.md +81 -0
- package/07-production/skills/SKILL.md +11 -0
- package/99-common/01-readme-base.md +16 -0
- package/99-common/02-initial-checklist.md +7 -0
- package/99-common/03-glossary.md +7 -0
- package/99-common/04-release-closure-product-3-4.md +47 -0
- package/99-common/05-p1-notion-multi-db-plan.md +126 -0
- package/99-common/06-p1-notion-schema-spec.md +189 -0
- package/99-common/07-p1-notion-manual-setup-checklist.md +72 -0
- package/99-common/AGENTS.md +20 -0
- package/99-common/project.config.json +7 -0
- package/99-common/skills/SKILL.md +9 -0
- package/AGENTS.md +275 -0
- package/LICENSE +201 -0
- package/README.md +95 -0
- package/bin/rootkid0-initializer.js +89 -0
- package/package.json +38 -0
- package/rootkid0-bootstrap/AGENTS.md +20 -0
- package/rootkid0-bootstrap/helpers.sh +106 -0
- package/rootkid0-bootstrap/init-project.ps1 +114 -0
- package/rootkid0-bootstrap/init-project.sh +71 -0
- package/rootkid0-bootstrap/notion-bootstrap.ps1 +162 -0
- package/rootkid0-bootstrap/notion-bootstrap.sh +301 -0
- package/rootkid0-bootstrap/skills/SKILL.md +9 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
6
|
+
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
7
|
+
|
|
8
|
+
source "$SCRIPT_DIR/helpers.sh"
|
|
9
|
+
|
|
10
|
+
print_usage() {
|
|
11
|
+
echo "Uso: ./rootkid0-bootstrap/init-project.sh [--setup-mcp] <project-name>"
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
SETUP_MCP=false
|
|
15
|
+
PROJECT_NAME=""
|
|
16
|
+
|
|
17
|
+
for arg in "$@"; do
|
|
18
|
+
case "$arg" in
|
|
19
|
+
--setup-mcp)
|
|
20
|
+
SETUP_MCP=true
|
|
21
|
+
;;
|
|
22
|
+
-h|--help)
|
|
23
|
+
print_usage
|
|
24
|
+
exit 0
|
|
25
|
+
;;
|
|
26
|
+
*)
|
|
27
|
+
if [[ -z "$PROJECT_NAME" ]]; then
|
|
28
|
+
PROJECT_NAME="$arg"
|
|
29
|
+
else
|
|
30
|
+
echo "Error: argumento no reconocido '$arg'" >&2
|
|
31
|
+
print_usage
|
|
32
|
+
exit 1
|
|
33
|
+
fi
|
|
34
|
+
;;
|
|
35
|
+
esac
|
|
36
|
+
done
|
|
37
|
+
|
|
38
|
+
if [[ -z "$PROJECT_NAME" ]]; then
|
|
39
|
+
read -r -p "Nombre del proyecto: " PROJECT_NAME
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
validate_project_name "$PROJECT_NAME"
|
|
43
|
+
|
|
44
|
+
DESTINATION="$PWD/$PROJECT_NAME"
|
|
45
|
+
|
|
46
|
+
if [[ -e "$DESTINATION" ]]; then
|
|
47
|
+
echo "Error: Ya existe la carpeta $DESTINATION" >&2
|
|
48
|
+
exit 1
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
echo "Creando proyecto: $PROJECT_NAME"
|
|
52
|
+
mkdir -p "$DESTINATION"
|
|
53
|
+
|
|
54
|
+
copy_baseline "$REPO_ROOT" "$DESTINATION"
|
|
55
|
+
replace_project_placeholders "$DESTINATION" "$PROJECT_NAME"
|
|
56
|
+
generate_project_readme "$DESTINATION" "$PROJECT_NAME"
|
|
57
|
+
|
|
58
|
+
if [[ "$SETUP_MCP" == "true" ]]; then
|
|
59
|
+
setup_global_mcp_config "$REPO_ROOT"
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
bash "$SCRIPT_DIR/notion-bootstrap.sh" --project-name "$PROJECT_NAME" --project-dir "$DESTINATION"
|
|
63
|
+
|
|
64
|
+
echo
|
|
65
|
+
echo "Proyecto creado en: $DESTINATION"
|
|
66
|
+
echo "Siguientes pasos:"
|
|
67
|
+
echo " 1) cd \"$PROJECT_NAME\""
|
|
68
|
+
echo " 2) Completar 01-business/ a 07-production/"
|
|
69
|
+
echo " 3) Ajustar 99-common/project.config.json"
|
|
70
|
+
echo " 4) Revisar AGENTS.md y .opencode/README.md"
|
|
71
|
+
echo " 5) Revisar 99-common/notion-bootstrap.output.json"
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
param(
|
|
2
|
+
[Parameter(Mandatory = $true)]
|
|
3
|
+
[string]$ProjectName,
|
|
4
|
+
|
|
5
|
+
[Parameter(Mandatory = $true)]
|
|
6
|
+
[string]$ProjectDir
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
Set-StrictMode -Version Latest
|
|
10
|
+
$ErrorActionPreference = "Stop"
|
|
11
|
+
|
|
12
|
+
function Fail([string]$Message) {
|
|
13
|
+
throw $Message
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function Require-Env([string]$Name) {
|
|
17
|
+
$value = [Environment]::GetEnvironmentVariable($Name)
|
|
18
|
+
if ([string]::IsNullOrWhiteSpace($value)) {
|
|
19
|
+
Fail "Variable requerida no definida: $Name. Definila y vuelve a ejecutar init-project."
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function Get-NotionPagePayload([string]$ParentPageId, [string]$Title) {
|
|
24
|
+
return @{
|
|
25
|
+
parent = @{ page_id = $ParentPageId }
|
|
26
|
+
properties = @{
|
|
27
|
+
title = @{
|
|
28
|
+
title = @(
|
|
29
|
+
@{
|
|
30
|
+
type = "text"
|
|
31
|
+
text = @{ content = $Title }
|
|
32
|
+
}
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
} | ConvertTo-Json -Depth 10
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function New-NotionPage([string]$ParentPageId, [string]$Title) {
|
|
40
|
+
$headers = @{
|
|
41
|
+
Authorization = "Bearer $env:NOTION_TOKEN"
|
|
42
|
+
"Notion-Version" = "2022-06-28"
|
|
43
|
+
"Content-Type" = "application/json"
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
$body = Get-NotionPagePayload -ParentPageId $ParentPageId -Title $Title
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
$response = Invoke-RestMethod -Method Post -Uri "https://api.notion.com/v1/pages" -Headers $headers -Body $body
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
$apiMessage = $_.ErrorDetails.Message
|
|
53
|
+
if ([string]::IsNullOrWhiteSpace($apiMessage)) {
|
|
54
|
+
$apiMessage = $_.Exception.Message
|
|
55
|
+
}
|
|
56
|
+
Fail "No se pudo crear pagina en Notion ($Title). Detalle: $apiMessage"
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if ([string]::IsNullOrWhiteSpace($response.id)) {
|
|
60
|
+
Fail "Notion no devolvio un id valido al crear '$Title'."
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return $response.id
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (-not (Test-Path -LiteralPath $ProjectDir)) {
|
|
67
|
+
Fail "No existe el directorio de proyecto: $ProjectDir"
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
$mcpFile = Join-Path $HOME ".config/opencode/mcp-servers.json"
|
|
71
|
+
|
|
72
|
+
if (-not (Test-Path -LiteralPath $mcpFile)) {
|
|
73
|
+
Fail "No existe $mcpFile. Configura MCP global con servidor notion y vuelve a ejecutar init-project."
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
$mcpConfig = Get-Content -Path $mcpFile -Raw | ConvertFrom-Json
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
Fail "El archivo $mcpFile no tiene JSON valido. Corrigelo y vuelve a ejecutar init-project."
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if ($null -eq $mcpConfig.servers -or $null -eq $mcpConfig.servers.notion) {
|
|
84
|
+
Fail "Falta entrada servers.notion en $mcpFile. Agregala y vuelve a ejecutar init-project."
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
Require-Env "NOTION_TOKEN"
|
|
88
|
+
Require-Env "NOTION_PARENT_PAGE_ID"
|
|
89
|
+
|
|
90
|
+
$workspaceName = [Environment]::GetEnvironmentVariable("NOTION_WORKSPACE_NAME")
|
|
91
|
+
|
|
92
|
+
Write-Host "Iniciando bootstrap automatico de Notion..."
|
|
93
|
+
|
|
94
|
+
$rootTitle = $ProjectName
|
|
95
|
+
if (-not [string]::IsNullOrWhiteSpace($workspaceName)) {
|
|
96
|
+
$rootTitle = "$workspaceName - $ProjectName"
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
$projectRootPageId = New-NotionPage -ParentPageId $env:NOTION_PARENT_PAGE_ID -Title $rootTitle
|
|
100
|
+
Write-Host "Pagina raiz creada: $projectRootPageId"
|
|
101
|
+
|
|
102
|
+
$phaseNames = @(
|
|
103
|
+
"01-business",
|
|
104
|
+
"02-proposal",
|
|
105
|
+
"03-design",
|
|
106
|
+
"04-management",
|
|
107
|
+
"05-development",
|
|
108
|
+
"06-deployment",
|
|
109
|
+
"07-production",
|
|
110
|
+
"99-common"
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
$phaseMap = [ordered]@{}
|
|
114
|
+
$commonPageId = ""
|
|
115
|
+
|
|
116
|
+
foreach ($phase in $phaseNames) {
|
|
117
|
+
$phaseId = New-NotionPage -ParentPageId $projectRootPageId -Title $phase
|
|
118
|
+
$phaseMap[$phase] = $phaseId
|
|
119
|
+
Write-Host "Pagina creada ($phase): $phaseId"
|
|
120
|
+
if ($phase -eq "99-common") {
|
|
121
|
+
$commonPageId = $phaseId
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if ([string]::IsNullOrWhiteSpace($commonPageId)) {
|
|
126
|
+
Fail "No se pudo crear la pagina 99-common en Notion."
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
$sectionNames = @(
|
|
130
|
+
"Projects",
|
|
131
|
+
"Phases",
|
|
132
|
+
"Deliverables",
|
|
133
|
+
"Backlog",
|
|
134
|
+
"Risks",
|
|
135
|
+
"Decisions",
|
|
136
|
+
"Incidents"
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
$sectionMap = [ordered]@{}
|
|
140
|
+
|
|
141
|
+
foreach ($section in $sectionNames) {
|
|
142
|
+
$sectionId = New-NotionPage -ParentPageId $commonPageId -Title $section
|
|
143
|
+
$sectionMap[$section] = $sectionId
|
|
144
|
+
Write-Host "Seccion modelo MVP creada ($section): $sectionId"
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
$outputPath = Join-Path $ProjectDir "99-common/notion-bootstrap.output.json"
|
|
148
|
+
|
|
149
|
+
$result = [ordered]@{
|
|
150
|
+
project_name = $ProjectName
|
|
151
|
+
workspace_name = $workspaceName
|
|
152
|
+
created_at_utc = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
|
|
153
|
+
notion_parent_page_id = $env:NOTION_PARENT_PAGE_ID
|
|
154
|
+
project_root_page_id = $projectRootPageId
|
|
155
|
+
phase_pages = $phaseMap
|
|
156
|
+
model_sections = $sectionMap
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
$result | ConvertTo-Json -Depth 10 | Set-Content -Path $outputPath
|
|
160
|
+
|
|
161
|
+
Write-Host "Bootstrap Notion completado."
|
|
162
|
+
Write-Host "Salida guardada en: $outputPath"
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
print_usage() {
|
|
6
|
+
echo "Uso: ./rootkid0-bootstrap/notion-bootstrap.sh --project-name <name> --project-dir <path>"
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
fail() {
|
|
10
|
+
echo "Error: $1" >&2
|
|
11
|
+
exit 1
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
json_escape() {
|
|
15
|
+
local value="${1:-}"
|
|
16
|
+
value="${value//\\/\\\\}"
|
|
17
|
+
value="${value//\"/\\\"}"
|
|
18
|
+
value="${value//$'\n'/ }"
|
|
19
|
+
value="${value//$'\r'/ }"
|
|
20
|
+
printf '%s' "$value"
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
pick_python() {
|
|
24
|
+
if command -v python3 >/dev/null 2>&1; then
|
|
25
|
+
echo "python3"
|
|
26
|
+
return 0
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
if command -v python >/dev/null 2>&1; then
|
|
30
|
+
echo "python"
|
|
31
|
+
return 0
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
return 1
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
validate_mcp_config() {
|
|
38
|
+
local mcp_file="$HOME/.config/opencode/mcp-servers.json"
|
|
39
|
+
local py_bin
|
|
40
|
+
local py_status
|
|
41
|
+
|
|
42
|
+
if [[ ! -f "$mcp_file" ]]; then
|
|
43
|
+
fail "No existe $mcp_file. Configura el MCP global con entrada 'notion' y vuelve a ejecutar init-project."
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
py_bin="$(pick_python || true)"
|
|
47
|
+
|
|
48
|
+
if [[ -n "$py_bin" ]]; then
|
|
49
|
+
if "$py_bin" - "$mcp_file" <<'PY'; then
|
|
50
|
+
import json
|
|
51
|
+
import sys
|
|
52
|
+
|
|
53
|
+
path = sys.argv[1]
|
|
54
|
+
try:
|
|
55
|
+
with open(path, "r", encoding="utf-8") as f:
|
|
56
|
+
data = json.load(f)
|
|
57
|
+
except Exception:
|
|
58
|
+
sys.exit(2)
|
|
59
|
+
|
|
60
|
+
servers = data.get("servers")
|
|
61
|
+
if isinstance(servers, dict) and "notion" in servers:
|
|
62
|
+
sys.exit(0)
|
|
63
|
+
|
|
64
|
+
sys.exit(1)
|
|
65
|
+
PY
|
|
66
|
+
py_status=0
|
|
67
|
+
else
|
|
68
|
+
py_status=$?
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
if [[ "$py_status" -ne 0 ]]; then
|
|
72
|
+
case "$py_status" in
|
|
73
|
+
1)
|
|
74
|
+
fail "Falta el servidor 'notion' en $mcp_file. Agrega la entrada en servers.notion y vuelve a ejecutar init-project."
|
|
75
|
+
;;
|
|
76
|
+
2)
|
|
77
|
+
fail "El archivo $mcp_file no tiene JSON valido. Corrigelo y vuelve a ejecutar init-project."
|
|
78
|
+
;;
|
|
79
|
+
*)
|
|
80
|
+
fail "No se pudo validar $mcp_file. Verifica permisos y formato del archivo."
|
|
81
|
+
;;
|
|
82
|
+
esac
|
|
83
|
+
fi
|
|
84
|
+
return 0
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
if ! grep -q '"notion"' "$mcp_file"; then
|
|
88
|
+
fail "No se detecto la entrada 'notion' en $mcp_file. Agrega el servidor notion y vuelve a ejecutar init-project."
|
|
89
|
+
fi
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
require_env() {
|
|
93
|
+
local var_name="$1"
|
|
94
|
+
local var_value="${!var_name:-}"
|
|
95
|
+
|
|
96
|
+
if [[ -z "$var_value" ]]; then
|
|
97
|
+
fail "Variable requerida no definida: $var_name. Exporta $var_name y vuelve a ejecutar init-project."
|
|
98
|
+
fi
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
require_command() {
|
|
102
|
+
local command_name="$1"
|
|
103
|
+
if ! command -v "$command_name" >/dev/null 2>&1; then
|
|
104
|
+
fail "Dependencia requerida no encontrada: $command_name. Instalala y vuelve a ejecutar init-project."
|
|
105
|
+
fi
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
build_page_payload() {
|
|
109
|
+
local parent_id="$1"
|
|
110
|
+
local title="$2"
|
|
111
|
+
|
|
112
|
+
printf '{"parent":{"page_id":"%s"},"properties":{"title":{"title":[{"type":"text","text":{"content":"%s"}}]}}}' \
|
|
113
|
+
"$parent_id" \
|
|
114
|
+
"$(json_escape "$title")"
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
create_notion_page() {
|
|
118
|
+
local parent_id="$1"
|
|
119
|
+
local title="$2"
|
|
120
|
+
local payload
|
|
121
|
+
local response_file
|
|
122
|
+
local status
|
|
123
|
+
local py_bin
|
|
124
|
+
local page_id
|
|
125
|
+
|
|
126
|
+
payload="$(build_page_payload "$parent_id" "$title")"
|
|
127
|
+
response_file="$(mktemp)"
|
|
128
|
+
|
|
129
|
+
status="$(curl -sS -o "$response_file" -w "%{http_code}" \
|
|
130
|
+
-X POST "https://api.notion.com/v1/pages" \
|
|
131
|
+
-H "Authorization: Bearer $NOTION_TOKEN" \
|
|
132
|
+
-H "Notion-Version: 2022-06-28" \
|
|
133
|
+
-H "Content-Type: application/json" \
|
|
134
|
+
--data "$payload")"
|
|
135
|
+
|
|
136
|
+
if [[ "$status" -lt 200 || "$status" -ge 300 ]]; then
|
|
137
|
+
local error_body
|
|
138
|
+
error_body="$(tr -d '\n' < "$response_file")"
|
|
139
|
+
rm -f "$response_file"
|
|
140
|
+
fail "Notion API devolvio HTTP $status al crear '$title'. Respuesta: $error_body"
|
|
141
|
+
fi
|
|
142
|
+
|
|
143
|
+
py_bin="$(pick_python || true)"
|
|
144
|
+
if [[ -n "$py_bin" ]]; then
|
|
145
|
+
page_id="$("$py_bin" - "$response_file" <<'PY'
|
|
146
|
+
import json
|
|
147
|
+
import sys
|
|
148
|
+
|
|
149
|
+
with open(sys.argv[1], "r", encoding="utf-8") as f:
|
|
150
|
+
data = json.load(f)
|
|
151
|
+
|
|
152
|
+
print(data.get("id", ""))
|
|
153
|
+
PY
|
|
154
|
+
)"
|
|
155
|
+
else
|
|
156
|
+
page_id="$(grep -o '"id":"[^"]*"' "$response_file" | head -n 1 | cut -d '"' -f 4)"
|
|
157
|
+
fi
|
|
158
|
+
|
|
159
|
+
rm -f "$response_file"
|
|
160
|
+
|
|
161
|
+
if [[ -z "$page_id" ]]; then
|
|
162
|
+
fail "No se pudo extraer el id de la pagina creada para '$title'."
|
|
163
|
+
fi
|
|
164
|
+
|
|
165
|
+
printf '%s' "$page_id"
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
PROJECT_NAME=""
|
|
169
|
+
PROJECT_DIR=""
|
|
170
|
+
|
|
171
|
+
while [[ $# -gt 0 ]]; do
|
|
172
|
+
case "$1" in
|
|
173
|
+
--project-name)
|
|
174
|
+
PROJECT_NAME="${2:-}"
|
|
175
|
+
shift 2
|
|
176
|
+
;;
|
|
177
|
+
--project-dir)
|
|
178
|
+
PROJECT_DIR="${2:-}"
|
|
179
|
+
shift 2
|
|
180
|
+
;;
|
|
181
|
+
-h|--help)
|
|
182
|
+
print_usage
|
|
183
|
+
exit 0
|
|
184
|
+
;;
|
|
185
|
+
*)
|
|
186
|
+
fail "Argumento no reconocido: $1"
|
|
187
|
+
;;
|
|
188
|
+
esac
|
|
189
|
+
done
|
|
190
|
+
|
|
191
|
+
if [[ -z "$PROJECT_NAME" || -z "$PROJECT_DIR" ]]; then
|
|
192
|
+
print_usage
|
|
193
|
+
fail "Debes indicar --project-name y --project-dir."
|
|
194
|
+
fi
|
|
195
|
+
|
|
196
|
+
if [[ ! -d "$PROJECT_DIR" ]]; then
|
|
197
|
+
fail "No existe el directorio de proyecto: $PROJECT_DIR"
|
|
198
|
+
fi
|
|
199
|
+
|
|
200
|
+
validate_mcp_config
|
|
201
|
+
require_command "curl"
|
|
202
|
+
require_env "NOTION_TOKEN"
|
|
203
|
+
require_env "NOTION_PARENT_PAGE_ID"
|
|
204
|
+
|
|
205
|
+
NOTION_WORKSPACE_NAME="${NOTION_WORKSPACE_NAME:-}"
|
|
206
|
+
|
|
207
|
+
echo "Iniciando bootstrap automatico de Notion..."
|
|
208
|
+
|
|
209
|
+
root_title="$PROJECT_NAME"
|
|
210
|
+
if [[ -n "$NOTION_WORKSPACE_NAME" ]]; then
|
|
211
|
+
root_title="$NOTION_WORKSPACE_NAME - $PROJECT_NAME"
|
|
212
|
+
fi
|
|
213
|
+
|
|
214
|
+
project_root_page_id="$(create_notion_page "$NOTION_PARENT_PAGE_ID" "$root_title")"
|
|
215
|
+
echo "Pagina raiz creada: $project_root_page_id"
|
|
216
|
+
|
|
217
|
+
phase_names=(
|
|
218
|
+
"01-business"
|
|
219
|
+
"02-proposal"
|
|
220
|
+
"03-design"
|
|
221
|
+
"04-management"
|
|
222
|
+
"05-development"
|
|
223
|
+
"06-deployment"
|
|
224
|
+
"07-production"
|
|
225
|
+
"99-common"
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
phase_ids=()
|
|
229
|
+
common_page_id=""
|
|
230
|
+
|
|
231
|
+
for phase in "${phase_names[@]}"; do
|
|
232
|
+
phase_id="$(create_notion_page "$project_root_page_id" "$phase")"
|
|
233
|
+
phase_ids+=("$phase_id")
|
|
234
|
+
echo "Pagina creada ($phase): $phase_id"
|
|
235
|
+
if [[ "$phase" == "99-common" ]]; then
|
|
236
|
+
common_page_id="$phase_id"
|
|
237
|
+
fi
|
|
238
|
+
done
|
|
239
|
+
|
|
240
|
+
if [[ -z "$common_page_id" ]]; then
|
|
241
|
+
fail "No se pudo crear la pagina 99-common en Notion."
|
|
242
|
+
fi
|
|
243
|
+
|
|
244
|
+
section_names=(
|
|
245
|
+
"Projects"
|
|
246
|
+
"Phases"
|
|
247
|
+
"Deliverables"
|
|
248
|
+
"Backlog"
|
|
249
|
+
"Risks"
|
|
250
|
+
"Decisions"
|
|
251
|
+
"Incidents"
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
section_ids=()
|
|
255
|
+
for section in "${section_names[@]}"; do
|
|
256
|
+
section_id="$(create_notion_page "$common_page_id" "$section")"
|
|
257
|
+
section_ids+=("$section_id")
|
|
258
|
+
echo "Seccion modelo MVP creada ($section): $section_id"
|
|
259
|
+
done
|
|
260
|
+
|
|
261
|
+
output_file="$PROJECT_DIR/99-common/notion-bootstrap.output.json"
|
|
262
|
+
timestamp_utc="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
|
263
|
+
|
|
264
|
+
{
|
|
265
|
+
echo "{"
|
|
266
|
+
echo " \"project_name\": \"$(json_escape "$PROJECT_NAME")\","
|
|
267
|
+
echo " \"workspace_name\": \"$(json_escape "$NOTION_WORKSPACE_NAME")\","
|
|
268
|
+
echo " \"created_at_utc\": \"$timestamp_utc\","
|
|
269
|
+
echo " \"notion_parent_page_id\": \"$(json_escape "$NOTION_PARENT_PAGE_ID")\","
|
|
270
|
+
echo " \"project_root_page_id\": \"$project_root_page_id\","
|
|
271
|
+
echo " \"phase_pages\": {"
|
|
272
|
+
|
|
273
|
+
for i in "${!phase_names[@]}"; do
|
|
274
|
+
key="${phase_names[$i]}"
|
|
275
|
+
value="${phase_ids[$i]}"
|
|
276
|
+
suffix=","
|
|
277
|
+
if [[ "$i" -eq $((${#phase_names[@]} - 1)) ]]; then
|
|
278
|
+
suffix=""
|
|
279
|
+
fi
|
|
280
|
+
echo " \"$(json_escape "$key")\": \"$value\"$suffix"
|
|
281
|
+
done
|
|
282
|
+
|
|
283
|
+
echo " },"
|
|
284
|
+
echo " \"model_sections\": {"
|
|
285
|
+
|
|
286
|
+
for i in "${!section_names[@]}"; do
|
|
287
|
+
key="${section_names[$i]}"
|
|
288
|
+
value="${section_ids[$i]}"
|
|
289
|
+
suffix=","
|
|
290
|
+
if [[ "$i" -eq $((${#section_names[@]} - 1)) ]]; then
|
|
291
|
+
suffix=""
|
|
292
|
+
fi
|
|
293
|
+
echo " \"$(json_escape "$key")\": \"$value\"$suffix"
|
|
294
|
+
done
|
|
295
|
+
|
|
296
|
+
echo " }"
|
|
297
|
+
echo "}"
|
|
298
|
+
} > "$output_file"
|
|
299
|
+
|
|
300
|
+
echo "Bootstrap Notion completado."
|
|
301
|
+
echo "Salida guardada en: $output_file"
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: local-bootstrap-conventions
|
|
3
|
+
description: Convenciones para scripts de bootstrap. Trigger: cambios en rootkid0-bootstrap.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Skill local rootkid0-bootstrap
|
|
7
|
+
|
|
8
|
+
- Cuidar validaciones de nombre y rutas.
|
|
9
|
+
- No introducir dependencias innecesarias.
|