aos-harness 0.3.0 → 0.3.2
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/adapters/pi/src/index.ts +117 -67
- package/package.json +2 -2
package/adapters/pi/src/index.ts
CHANGED
|
@@ -211,6 +211,16 @@ export default function (pi: ExtensionAPI) {
|
|
|
211
211
|
`AOS Harness initialized\nProject: ${projectRoot}\nProfiles: ${profiles.length} | Agents: ${agentMap.size}\n\nRun /aos-run to start a deliberation.`,
|
|
212
212
|
"info",
|
|
213
213
|
);
|
|
214
|
+
|
|
215
|
+
// Auto-start session if CLI passed environment variables
|
|
216
|
+
const autoProfile = process.env.AOS_PROFILE;
|
|
217
|
+
const autoBrief = process.env.AOS_BRIEF;
|
|
218
|
+
if (autoProfile && autoBrief && projectRoot) {
|
|
219
|
+
// Defer to let Pi finish initialization, then send the command as user message
|
|
220
|
+
setTimeout(() => {
|
|
221
|
+
pi.sendUserMessage("/aos-run");
|
|
222
|
+
}, 500);
|
|
223
|
+
}
|
|
214
224
|
});
|
|
215
225
|
|
|
216
226
|
// ── 2. /aos-run command — main entry point ────────────────
|
|
@@ -228,74 +238,110 @@ export default function (pi: ExtensionAPI) {
|
|
|
228
238
|
return;
|
|
229
239
|
}
|
|
230
240
|
|
|
231
|
-
// ──
|
|
232
|
-
const
|
|
233
|
-
const
|
|
241
|
+
// ── Check for CLI-provided env vars (auto-start mode) ──
|
|
242
|
+
const envProfile = process.env.AOS_PROFILE;
|
|
243
|
+
const envBrief = process.env.AOS_BRIEF;
|
|
244
|
+
const envDomain = process.env.AOS_DOMAIN;
|
|
245
|
+
const envSessionId = process.env.AOS_SESSION_ID;
|
|
246
|
+
const autoMode = !!(envProfile && envBrief);
|
|
234
247
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
"warning",
|
|
239
|
-
);
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
const profileNames = profiles.map((p) => p.name);
|
|
244
|
-
let profileIdx: number;
|
|
245
|
-
if (profiles.length === 1) {
|
|
246
|
-
profileIdx = 0;
|
|
247
|
-
} else {
|
|
248
|
-
const selected = await ctx.ui.select("Select a profile:", profileNames);
|
|
249
|
-
profileIdx = typeof selected === "number" ? selected : Number(selected);
|
|
250
|
-
}
|
|
251
|
-
if (profileIdx === undefined || profileIdx === null || profileIdx < 0) {
|
|
252
|
-
ctx.ui.notify("No profile selected. Cancelled.", "info");
|
|
253
|
-
return;
|
|
254
|
-
}
|
|
255
|
-
const selectedProfile = profiles[profileIdx];
|
|
256
|
-
const profileDir = selectedProfile.dir;
|
|
257
|
-
|
|
258
|
-
// ── Select brief ──────────────────────────────────────
|
|
259
|
-
const briefsDir = join(projectRoot, "core", "briefs");
|
|
260
|
-
const briefs = listDirsWithFile(briefsDir, "brief.md");
|
|
261
|
-
|
|
262
|
-
if (briefs.length === 0) {
|
|
263
|
-
ctx.ui.notify(
|
|
264
|
-
"No briefs found in core/briefs/.\nCreate a directory containing a brief.md file.",
|
|
265
|
-
"warning",
|
|
266
|
-
);
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
248
|
+
let profileDir: string;
|
|
249
|
+
let selectedDomain: string | undefined;
|
|
250
|
+
let domainDir: string | undefined;
|
|
269
251
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
252
|
+
if (autoMode) {
|
|
253
|
+
// CLI provided profile and brief via env vars — skip interactive selection
|
|
254
|
+
profileDir = join(projectRoot, "core", "profiles", envProfile);
|
|
255
|
+
if (!existsSync(join(profileDir, "profile.yaml"))) {
|
|
256
|
+
ctx.ui.notify(`Profile not found: ${envProfile}`, "error");
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
briefPath = envBrief;
|
|
260
|
+
if (!existsSync(briefPath)) {
|
|
261
|
+
ctx.ui.notify(`Brief not found: ${briefPath}`, "error");
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
if (envDomain) {
|
|
265
|
+
selectedDomain = envDomain;
|
|
266
|
+
domainDir = join(projectRoot, "core", "domains", envDomain);
|
|
267
|
+
if (!existsSync(join(domainDir, "domain.yaml"))) {
|
|
268
|
+
ctx.ui.notify(`Domain not found: ${envDomain}`, "warning");
|
|
269
|
+
selectedDomain = undefined;
|
|
270
|
+
domainDir = undefined;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
if (envSessionId) {
|
|
274
|
+
sessionId = envSessionId;
|
|
275
|
+
}
|
|
274
276
|
} else {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
277
|
+
// Interactive mode — select profile, brief, domain via UI
|
|
278
|
+
// ── Select profile ────────────────────────────────────
|
|
279
|
+
const profilesDir = join(projectRoot, "core", "profiles");
|
|
280
|
+
const profiles = listDirsWithFile(profilesDir, "profile.yaml");
|
|
281
|
+
|
|
282
|
+
if (profiles.length === 0) {
|
|
283
|
+
ctx.ui.notify(
|
|
284
|
+
"No profiles found in core/profiles/.\nCreate a directory with a profile.yaml file.",
|
|
285
|
+
"warning",
|
|
286
|
+
);
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
284
289
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
290
|
+
const profileNames = profiles.map((p) => p.name);
|
|
291
|
+
let profileIdx: number;
|
|
292
|
+
if (profiles.length === 1) {
|
|
293
|
+
profileIdx = 0;
|
|
294
|
+
} else {
|
|
295
|
+
const selected = await ctx.ui.select("Select a profile:", profileNames);
|
|
296
|
+
profileIdx = typeof selected === "number" ? selected : Number(selected);
|
|
297
|
+
}
|
|
298
|
+
if (profileIdx === undefined || profileIdx === null || profileIdx < 0) {
|
|
299
|
+
ctx.ui.notify("No profile selected. Cancelled.", "info");
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
const selectedProfile = profiles[profileIdx];
|
|
303
|
+
profileDir = selectedProfile.dir;
|
|
304
|
+
|
|
305
|
+
// ── Select brief ──────────────────────────────────────
|
|
306
|
+
const briefsDir = join(projectRoot, "core", "briefs");
|
|
307
|
+
const briefs = listDirsWithFile(briefsDir, "brief.md");
|
|
308
|
+
|
|
309
|
+
if (briefs.length === 0) {
|
|
310
|
+
ctx.ui.notify(
|
|
311
|
+
"No briefs found in core/briefs/.\nCreate a directory containing a brief.md file.",
|
|
312
|
+
"warning",
|
|
313
|
+
);
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
289
316
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
if (
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
317
|
+
const briefNames = briefs.map((b) => b.name);
|
|
318
|
+
let briefIdx: number;
|
|
319
|
+
if (briefs.length === 1) {
|
|
320
|
+
briefIdx = 0;
|
|
321
|
+
} else {
|
|
322
|
+
const selected = await ctx.ui.select("Select a brief:", briefNames);
|
|
323
|
+
briefIdx = typeof selected === "number" ? selected : Number(selected);
|
|
324
|
+
}
|
|
325
|
+
if (briefIdx === undefined || briefIdx === null || briefIdx < 0) {
|
|
326
|
+
ctx.ui.notify("No brief selected. Cancelled.", "info");
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
const selectedBrief = briefs[briefIdx];
|
|
330
|
+
briefPath = join(selectedBrief.dir, "brief.md");
|
|
331
|
+
|
|
332
|
+
// ── Optionally select domain ──────────────────────────
|
|
333
|
+
const domainsDir = join(projectRoot, "core", "domains");
|
|
334
|
+
|
|
335
|
+
if (existsSync(domainsDir)) {
|
|
336
|
+
const domains = listDirsWithFile(domainsDir, "domain.yaml");
|
|
337
|
+
if (domains.length > 0) {
|
|
338
|
+
const domainNames = ["(none)", ...domains.map((d) => d.name)];
|
|
339
|
+
const rawDomainIdx = await ctx.ui.select("Select a domain (optional):", domainNames);
|
|
340
|
+
const domainIdx = typeof rawDomainIdx === "number" ? rawDomainIdx : Number(rawDomainIdx);
|
|
341
|
+
if (domainIdx > 0) {
|
|
342
|
+
selectedDomain = domains[domainIdx - 1].name;
|
|
343
|
+
domainDir = domains[domainIdx - 1].dir;
|
|
344
|
+
}
|
|
299
345
|
}
|
|
300
346
|
}
|
|
301
347
|
}
|
|
@@ -362,7 +408,9 @@ export default function (pi: ExtensionAPI) {
|
|
|
362
408
|
}
|
|
363
409
|
|
|
364
410
|
// Determine memo output path
|
|
365
|
-
const briefSlug =
|
|
411
|
+
const briefSlug = autoMode
|
|
412
|
+
? basename(briefPath, ".md").replace(/\s+/g, "-").toLowerCase()
|
|
413
|
+
: basename(briefPath, ".md").replace(/\s+/g, "-").toLowerCase();
|
|
366
414
|
const dateStr = new Date().toISOString().split("T")[0];
|
|
367
415
|
const memoDir = join(projectRoot, "output", "memos", `${dateStr}-${briefSlug}-${sessionId}`);
|
|
368
416
|
mkdirSync(memoDir, { recursive: true });
|
|
@@ -378,7 +426,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
378
426
|
|
|
379
427
|
// Resolve template variables using spec-compliant underscore names (Section 6.13)
|
|
380
428
|
// Also include hyphenated aliases for backward compatibility
|
|
381
|
-
const briefSlugValue =
|
|
429
|
+
const briefSlugValue = briefSlug;
|
|
382
430
|
const constraintsStr = `${profileRaw.match(/min_minutes:\s*(\d+)/)?.[1] ?? "?"}-${profileRaw.match(/max_minutes:\s*(\d+)/)?.[1] ?? "?"} min`;
|
|
383
431
|
const deliberationDirPath = join(projectRoot, ".aos", "sessions", sessionId);
|
|
384
432
|
const transcriptFilePath = join(deliberationDirPath, "transcript.jsonl");
|
|
@@ -416,9 +464,11 @@ export default function (pi: ExtensionAPI) {
|
|
|
416
464
|
// ── Block input (allow only halt and wrap) ────────────
|
|
417
465
|
ui.blockInput(["halt", "wrap"]);
|
|
418
466
|
|
|
419
|
-
|
|
467
|
+
const profileDisplayName = autoMode ? envProfile : basename(profileDir);
|
|
468
|
+
const briefDisplayName = autoMode ? basename(briefPath) : basename(briefPath);
|
|
469
|
+
ctx.ui.setStatus("aos", `AOS: ${profileDisplayName} | ${briefDisplayName}`);
|
|
420
470
|
ctx.ui.notify(
|
|
421
|
-
`Deliberation started!\nProfile: ${
|
|
471
|
+
`Deliberation started!\nProfile: ${profileDisplayName}\nBrief: ${briefDisplayName}\nMemo: ${memoPath}\n\nType 'halt' to stop or 'wrap' to end early.`,
|
|
422
472
|
"info",
|
|
423
473
|
);
|
|
424
474
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aos-harness",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "Agentic Orchestration System — assemble AI agents into deliberation and execution teams",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"test": "bun run src/index.ts validate"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@aos-harness/runtime": "0.3.
|
|
39
|
+
"@aos-harness/runtime": "0.3.2",
|
|
40
40
|
"js-yaml": "^4.1.0"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|