siesa-agents 2.1.80 → 2.1.81
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.
|
@@ -73,7 +73,7 @@ Parse the JSON object printed to stdout. The `status` field selects the next bra
|
|
|
73
73
|
|
|
74
74
|
Proceed straight to Step 2 with `proposed_slug` and `recommended_dir`. Do **not** ask the user to confirm — the user has already accepted the auto-detection policy by invoking this skill.
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
Single-repo projects also return `status: "ready"` (with `convention_match: false`). The proposed slug is the repo name lowercased and sanitized to kebab-case (e.g. `Siesa-Agents` → `siesa-agents`) and `recommended_dir` is the git root itself. Proceed to Step 2 the same way — no separate branch.
|
|
77
77
|
|
|
78
78
|
**`status: "already-configured"`** — A `.siesa-project` exists above the current git root. Stop and report `existing_siesa_project.path` and `existing_siesa_project.value` to the user. Do not overwrite implicitly. If the user replies that they want it changed, run `--write` with `--force`, the new slug, and the same directory.
|
|
79
79
|
|
|
@@ -95,7 +95,9 @@ Parse the JSON response:
|
|
|
95
95
|
- **`status: "exists"`** — A file is already there with a different value (the detect step missed it because the user pointed at a non-default dir, or a race). Show `current_value` vs `requested_slug` and ask the user whether to overwrite. If yes, re-run with `--force`.
|
|
96
96
|
- **`status: "error"`** — Surface the error message verbatim and stop.
|
|
97
97
|
|
|
98
|
-
For the `
|
|
98
|
+
For the `already-configured` and `no-remote` branches where the user explicitly opts into writing, gather slug + directory inline and run the same `--write` command.
|
|
99
|
+
|
|
100
|
+
The file body written by `--write` is always `project_id=<slug>\n` (key=value form). `sa-emit.js` accepts both this format and a legacy bare-slug line for backward compatibility, so existing `.siesa-project` files keep working.
|
|
99
101
|
|
|
100
102
|
### Step 3 — Verify (optional)
|
|
101
103
|
|
|
@@ -129,7 +131,7 @@ business-<module>-<role>-<rest>
|
|
|
129
131
|
|
|
130
132
|
The logical slug collapses `<role>` away: `business-pos-backend-pdv` → `pos-pdv`.
|
|
131
133
|
|
|
132
|
-
For repo names that do not contain `docs`/`backend`/`frontend`, the script returns `
|
|
134
|
+
For repo names that do not contain `docs`/`backend`/`frontend`, the script still returns `status: "ready"` but with `convention_match: false`. The slug is derived from the repo name (lowercased, sanitized to kebab-case) and the file is written at the git root of that single repo.
|
|
133
135
|
|
|
134
136
|
## Examples
|
|
135
137
|
|
|
@@ -157,11 +159,11 @@ Model: <runs sa-init-env.js — status "created">
|
|
|
157
159
|
|
|
158
160
|
```
|
|
159
161
|
User: Set up .siesa-project for Siesa-Agents.
|
|
160
|
-
Model: <runs
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
162
|
+
Model: <runs sa-init-env.js — silent>
|
|
163
|
+
<runs --detect from Siesa-Agents/>
|
|
164
|
+
<reads proposed_slug="siesa-agents", recommended_dir=C:\…\Siesa-Agents, convention_match=false>
|
|
165
|
+
<runs --write --slug siesa-agents --dir C:\…\Siesa-Agents>
|
|
166
|
+
Wrote C:\…\Siesa-Agents\.siesa-project (project_id=siesa-agents). sa-emit.js will now report project_id="siesa-agents" instead of "SiesaTeams/Siesa-Agents".
|
|
165
167
|
```
|
|
166
168
|
|
|
167
169
|
**Example 3 — Already configured**
|
package/package.json
CHANGED
|
@@ -134,17 +134,38 @@ const stateDir = path.join(os.homedir(), '.claude', 'observability')
|
|
|
134
134
|
const epicIdMatch = story.match(/^(\d+)-/)
|
|
135
135
|
const epicId = epicIdMatch ? epicIdMatch[1] : 'unknown'
|
|
136
136
|
|
|
137
|
+
function parseSiesaProject(content) {
|
|
138
|
+
// Preferred format: a single `project_id=<slug>` line. For backward compatibility a bare
|
|
139
|
+
// slug on its own line is also accepted. `#` introduces a comment. Returns the resolved
|
|
140
|
+
// slug, or null if nothing usable was found.
|
|
141
|
+
if (!content) return null
|
|
142
|
+
let firstBare = null
|
|
143
|
+
for (const raw of content.split(/\r?\n/)) {
|
|
144
|
+
const line = raw.trim()
|
|
145
|
+
if (!line || line.startsWith('#')) continue
|
|
146
|
+
const eq = line.indexOf('=')
|
|
147
|
+
if (eq !== -1) {
|
|
148
|
+
const key = line.slice(0, eq).trim()
|
|
149
|
+
const val = line.slice(eq + 1).trim()
|
|
150
|
+
if (key === 'project_id' && val) return val
|
|
151
|
+
continue
|
|
152
|
+
}
|
|
153
|
+
if (firstBare === null) firstBare = line
|
|
154
|
+
}
|
|
155
|
+
return firstBare
|
|
156
|
+
}
|
|
157
|
+
|
|
137
158
|
function findSiesaProject(startDir) {
|
|
138
|
-
// Walk up from startDir looking for a `.siesa-project` file. Returns
|
|
139
|
-
//
|
|
159
|
+
// Walk up from startDir looking for a `.siesa-project` file. Returns the project_id slug
|
|
160
|
+
// it declares, or null. Lets a parent dir override the git-remote-derived project_id —
|
|
140
161
|
// useful when several sub-repos (docs/backend/frontend) belong to the same logical project.
|
|
141
162
|
let cur = path.resolve(startDir)
|
|
142
163
|
for (let i = 0; i < 40; i++) {
|
|
143
164
|
const candidate = path.join(cur, '.siesa-project')
|
|
144
165
|
if (fs.existsSync(candidate)) {
|
|
145
166
|
try {
|
|
146
|
-
const
|
|
147
|
-
if (
|
|
167
|
+
const slug = parseSiesaProject(fs.readFileSync(candidate, 'utf8'))
|
|
168
|
+
if (slug) return slug
|
|
148
169
|
} catch (_) {}
|
|
149
170
|
}
|
|
150
171
|
const parent = path.dirname(cur)
|
|
@@ -63,6 +63,27 @@ function tryExec(cmd, opts) {
|
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
// Parse a `.siesa-project` file body. Preferred format is `project_id=<slug>` (one key=value
|
|
67
|
+
// line, optional `#` comments). For backward compatibility a bare slug on its own line is
|
|
68
|
+
// also accepted. Returns the resolved slug, or null if nothing usable was found.
|
|
69
|
+
function parseSiesaProject(content) {
|
|
70
|
+
if (!content) return null
|
|
71
|
+
let firstBare = null
|
|
72
|
+
for (const raw of content.split(/\r?\n/)) {
|
|
73
|
+
const line = raw.trim()
|
|
74
|
+
if (!line || line.startsWith('#')) continue
|
|
75
|
+
const eq = line.indexOf('=')
|
|
76
|
+
if (eq !== -1) {
|
|
77
|
+
const key = line.slice(0, eq).trim()
|
|
78
|
+
const val = line.slice(eq + 1).trim()
|
|
79
|
+
if (key === 'project_id' && val) return val
|
|
80
|
+
continue
|
|
81
|
+
}
|
|
82
|
+
if (firstBare === null) firstBare = line
|
|
83
|
+
}
|
|
84
|
+
return firstBare
|
|
85
|
+
}
|
|
86
|
+
|
|
66
87
|
// Walk up from `startDir` looking for an existing `.siesa-project`. Returns
|
|
67
88
|
// { path, value } of the first match found, or null.
|
|
68
89
|
function findExistingSiesaProject(startDir) {
|
|
@@ -71,8 +92,8 @@ function findExistingSiesaProject(startDir) {
|
|
|
71
92
|
const candidate = path.join(cur, '.siesa-project')
|
|
72
93
|
if (fs.existsSync(candidate)) {
|
|
73
94
|
try {
|
|
74
|
-
const
|
|
75
|
-
return { path: candidate, value
|
|
95
|
+
const value = parseSiesaProject(fs.readFileSync(candidate, 'utf8'))
|
|
96
|
+
return { path: candidate, value }
|
|
76
97
|
} catch (_) {
|
|
77
98
|
return { path: candidate, value: null }
|
|
78
99
|
}
|
|
@@ -186,15 +207,38 @@ function runDetect() {
|
|
|
186
207
|
const derived = deriveLogicalSlug(repoName)
|
|
187
208
|
|
|
188
209
|
if (!derived.matched) {
|
|
210
|
+
// Single-repo project: still write a `.siesa-project` so the project_id is explicit
|
|
211
|
+
// and self-documented. The slug is derived from the repo name, sanitized to kebab-case,
|
|
212
|
+
// and the file lands at the git root of the current project.
|
|
213
|
+
const singleRepoSlug = (repoName || '')
|
|
214
|
+
.toLowerCase()
|
|
215
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
216
|
+
.replace(/^-+|-+$/g, '')
|
|
217
|
+
if (!singleRepoSlug || !/^[a-z0-9][a-z0-9-]*[a-z0-9]$/.test(singleRepoSlug)) {
|
|
218
|
+
emit({
|
|
219
|
+
status: 'no-remote',
|
|
220
|
+
message: 'Could not derive a valid kebab-case slug from the repo name. Pass --slug explicitly to write a .siesa-project.',
|
|
221
|
+
git_root: gitRoot,
|
|
222
|
+
remote_url: remoteUrl,
|
|
223
|
+
remote_repo: repoName,
|
|
224
|
+
})
|
|
225
|
+
process.exit(2)
|
|
226
|
+
}
|
|
189
227
|
emit({
|
|
190
|
-
status: '
|
|
191
|
-
message: '
|
|
228
|
+
status: 'ready',
|
|
229
|
+
message: 'Single-repo project detected. The .siesa-project file will be written at the git root with a slug derived from the repo name.',
|
|
192
230
|
git_root: gitRoot,
|
|
193
231
|
remote_url: remoteUrl,
|
|
194
232
|
remote_repo: repoName,
|
|
233
|
+
convention_match: false,
|
|
234
|
+
proposed_slug: singleRepoSlug,
|
|
235
|
+
convention_breakdown: null,
|
|
236
|
+
parent_candidates: [{ path: gitRoot, label: 'git root', levelsUp: 0 }],
|
|
237
|
+
recommended_dir: gitRoot,
|
|
195
238
|
fallback_project_id: remoteParsed ? `${remoteParsed.org}/${remoteParsed.repo}` : null,
|
|
239
|
+
next_step_example: `node sa-init-project.js --write --slug "${singleRepoSlug}" --dir "${gitRoot}"`,
|
|
196
240
|
})
|
|
197
|
-
process.exit(
|
|
241
|
+
process.exit(0)
|
|
198
242
|
}
|
|
199
243
|
|
|
200
244
|
const candidates = listParentCandidates(gitRoot)
|
|
@@ -256,7 +300,7 @@ function runWrite(args) {
|
|
|
256
300
|
const target = path.join(resolvedDir, '.siesa-project')
|
|
257
301
|
if (fs.existsSync(target) && !force) {
|
|
258
302
|
let current = null
|
|
259
|
-
try { current = fs.readFileSync(target, 'utf8')
|
|
303
|
+
try { current = parseSiesaProject(fs.readFileSync(target, 'utf8')) } catch (_) {}
|
|
260
304
|
emit({
|
|
261
305
|
status: 'exists',
|
|
262
306
|
message: '.siesa-project already exists at this location. Pass --force to overwrite.',
|
|
@@ -268,7 +312,7 @@ function runWrite(args) {
|
|
|
268
312
|
}
|
|
269
313
|
|
|
270
314
|
try {
|
|
271
|
-
fs.writeFileSync(target, normalizedSlug
|
|
315
|
+
fs.writeFileSync(target, `project_id=${normalizedSlug}\n`, { encoding: 'utf8' })
|
|
272
316
|
} catch (err) {
|
|
273
317
|
emit({ status: 'error', message: `Failed to write ${target}: ${err.message}` })
|
|
274
318
|
process.exit(3)
|