@firatcand/roster 0.4.0 → 1.0.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/README.md +77 -220
- package/agents/lesson-drafter.md +3 -8
- package/agents/pattern-detector.md +0 -1
- package/bin/roster.js +168 -57
- package/package.json +2 -3
- package/skills/chief-of-staff/SKILL.md +62 -78
- package/skills/dreamer/SKILL.md +8 -7
- package/skills/roster-orchestrator/SKILL.md +53 -25
- package/templates/CLAUDE.project.template.md +1 -1
- package/templates/CONTEXT.template.md +2 -2
- package/templates/gitignore-defaults.txt +2 -0
- package/templates/scaffold/chief-of-staff/README.md +16 -24
- package/templates/scaffold/chief-of-staff/agent.md +22 -32
- package/templates/scaffold/chief-of-staff/plans/audit-agent.yaml +4 -4
- package/templates/scaffold/chief-of-staff/plans/audit-repo.yaml +5 -4
- package/templates/scaffold/chief-of-staff/plans/create-agent.yaml +5 -34
- package/templates/scaffold/config/project.yaml.template +10 -0
- package/templates/scaffold/conventions.md +159 -171
- package/templates/scaffold/dreamer/README.md +2 -2
- package/templates/scaffold/dreamer/agent.md +0 -1
- package/templates/scaffold/dreamer/plans/nightly-reflection.yaml +23 -37
- package/templates/scaffold/dreamer/subagents/lesson-drafter.md +2 -7
- package/templates/scaffold/{projects/_demo/guidelines → guidelines}/asset-links.md +4 -0
- package/templates/scaffold/{projects/_demo/guidelines → guidelines}/brand-book.md +4 -0
- package/templates/scaffold/{projects/_demo/guidelines → guidelines}/messaging.md +4 -0
- package/templates/scaffold/{projects/_demo/guidelines → guidelines}/voice.md +4 -0
- package/templates/scaffold/scripts/audit-agent.sh +74 -47
- package/templates/scaffold/scripts/audit-repo.sh +27 -49
- package/templates/scaffold/scripts/create-function.sh +1 -1
- package/templates/scaffold/scripts/lib/README.md +1 -1
- package/templates/scaffold/scripts/lib/bindings-prompt.sh +41 -124
- package/templates/scaffold/scripts/new-agent.sh +97 -91
- package/templates/scaffold/scripts/rename-agent.sh +91 -0
- package/templates/scaffold/scripts/save-state.sh +32 -0
- package/agents/critic.md +0 -74
- package/agents/enricher.md +0 -56
- package/agents/promotion-arbiter.md +0 -71
- package/agents/prospector.md +0 -51
- package/agents/writer.md +0 -58
- package/skills/sdr/SKILL.md +0 -147
- package/templates/scaffold/chief-of-staff/plans/add-agent-to-project.yaml +0 -45
- package/templates/scaffold/chief-of-staff/plans/archive-project.yaml +0 -51
- package/templates/scaffold/chief-of-staff/plans/audit-project.yaml +0 -34
- package/templates/scaffold/chief-of-staff/plans/create-project.yaml +0 -65
- package/templates/scaffold/chief-of-staff/plans/remove-agent-from-project.yaml +0 -50
- package/templates/scaffold/chief-of-staff/plans/rename-project.yaml +0 -62
- package/templates/scaffold/chief-of-staff/plans/unarchive-project.yaml +0 -41
- package/templates/scaffold/dreamer/subagents/promotion-arbiter.md +0 -64
- package/templates/scaffold/gtm/sdr/.claude/settings.json +0 -3
- package/templates/scaffold/gtm/sdr/.mcp.json +0 -21
- package/templates/scaffold/gtm/sdr/README.md +0 -41
- package/templates/scaffold/gtm/sdr/agent.md +0 -136
- package/templates/scaffold/gtm/sdr/plans/cold-outreach.yaml +0 -92
- package/templates/scaffold/gtm/sdr/projects/_demo/asset-references.md +0 -7
- package/templates/scaffold/gtm/sdr/projects/_demo/config/default.yaml +0 -69
- package/templates/scaffold/gtm/sdr/projects/_demo/log/feedback/.gitkeep +0 -0
- package/templates/scaffold/gtm/sdr/projects/_demo/log/runs/.gitkeep +0 -0
- package/templates/scaffold/gtm/sdr/projects/_demo/playbook/.gitkeep +0 -0
- package/templates/scaffold/gtm/sdr/subagents/critic.md +0 -67
- package/templates/scaffold/gtm/sdr/subagents/enricher.md +0 -49
- package/templates/scaffold/gtm/sdr/subagents/prospector.md +0 -44
- package/templates/scaffold/gtm/sdr/subagents/writer.md +0 -51
- package/templates/scaffold/projects/_demo/CLAUDE.md +0 -35
- package/templates/scaffold/projects/_demo/README.md +0 -16
- package/templates/scaffold/projects/_demo/assets/.gitkeep +0 -0
- package/templates/scaffold/projects/_demo/config/default.yaml +0 -28
- package/templates/scaffold/projects/_demo/state.md +0 -11
- package/templates/scaffold/scripts/archive-project.sh +0 -98
- package/templates/scaffold/scripts/audit-project.sh +0 -361
- package/templates/scaffold/scripts/new-agent-instance.sh +0 -114
- package/templates/scaffold/scripts/new-project.sh +0 -125
- package/templates/scaffold/scripts/remove-agent-from-project.sh +0 -67
- package/templates/scaffold/scripts/rename-project.sh +0 -118
- package/templates/scaffold/scripts/unarchive-project.sh +0 -115
- /package/templates/scaffold/gtm/{sdr/playbook/.gitkeep → .gitkeep} +0 -0
- /package/templates/scaffold/{projects/_demo/guidelines → guidelines}/icps/_persona-template.md +0 -0
package/bin/roster.js
CHANGED
|
@@ -141,6 +141,19 @@ function missingScaffoldError(scaffoldPath) {
|
|
|
141
141
|
exitCode: 1
|
|
142
142
|
});
|
|
143
143
|
}
|
|
144
|
+
function v04WorkspaceDetectedError(paths) {
|
|
145
|
+
const list = paths.map((p) => ` - ${p}`).join("\n");
|
|
146
|
+
return new RosterError({
|
|
147
|
+
header: `${chalk.red.bold("roster:")} detected v0.4 workspace`,
|
|
148
|
+
body: [
|
|
149
|
+
" v1.0 is a breaking change with no automatic migration.",
|
|
150
|
+
" Found:",
|
|
151
|
+
list
|
|
152
|
+
].join("\n"),
|
|
153
|
+
remedy: " Re-scaffold in a fresh directory; see docs/CHANGELOG.md#v1.0.0.",
|
|
154
|
+
exitCode: 2
|
|
155
|
+
});
|
|
156
|
+
}
|
|
144
157
|
function userCancelledInit() {
|
|
145
158
|
return new RosterError({
|
|
146
159
|
header: `${chalk.dim("roster:")} cancelled`,
|
|
@@ -747,8 +760,6 @@ function isValidIanaTimezone(tz) {
|
|
|
747
760
|
}
|
|
748
761
|
}
|
|
749
762
|
const kebabString = (label) => z.string().min(1, { message: `${label}: required` }).refine((s) => KEBAB_RE$1.test(s), { message: `${label}: must be kebab-case (lowercase letters, digits, hyphens)` });
|
|
750
|
-
const PROJECT_SLUG_RE = /^_?[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
751
|
-
const projectString = (label) => z.string().min(1, { message: `${label}: required` }).refine((s) => PROJECT_SLUG_RE.test(s), { message: `${label}: must be kebab-case (optionally prefixed with '_' for scaffold templates)` });
|
|
752
763
|
const cronString = z.string().min(1, { message: "cron: required" }).transform((s) => s.trim()).superRefine((expr, ctx) => {
|
|
753
764
|
const result = validateCronExpression(expr);
|
|
754
765
|
if (!result.ok) ctx.addIssue({
|
|
@@ -769,11 +780,10 @@ const subscriptionAttestationSchema = z.object({
|
|
|
769
780
|
env_policy: z.literal("cleared"),
|
|
770
781
|
codex_home: z.string().min(1, { message: "subscription_attestation.codex_home: required" })
|
|
771
782
|
}).strict();
|
|
772
|
-
const
|
|
783
|
+
const scheduleEntryShape = z.object({
|
|
773
784
|
name: kebabString("name"),
|
|
774
785
|
agent: kebabString("agent"),
|
|
775
786
|
plan: kebabString("plan"),
|
|
776
|
-
project: projectString("project"),
|
|
777
787
|
cron: cronString,
|
|
778
788
|
tool: z.enum(TOOL_VALUES, { error: (issue) => {
|
|
779
789
|
const base = `tool: must be one of ${TOOL_VALUES.map((v) => `'${v}'`).join(" | ")}`;
|
|
@@ -815,6 +825,17 @@ const scheduleEntrySchema = z.object({
|
|
|
815
825
|
message: "capture_events: requires install_mode=via-cron (ui-handoff routes through the Codex app; no wrapper to redirect stdout)"
|
|
816
826
|
});
|
|
817
827
|
});
|
|
828
|
+
const scheduleEntrySchema = z.preprocess((raw, ctx) => {
|
|
829
|
+
if (raw !== null && typeof raw === "object" && "project" in raw) {
|
|
830
|
+
ctx.addIssue({
|
|
831
|
+
code: "custom",
|
|
832
|
+
path: ["project"],
|
|
833
|
+
message: "v0.4 schedule entry detected — see CHANGELOG#breaking-v1"
|
|
834
|
+
});
|
|
835
|
+
return z.NEVER;
|
|
836
|
+
}
|
|
837
|
+
return raw;
|
|
838
|
+
}, scheduleEntryShape);
|
|
818
839
|
const scheduleFileSchema = z.object({
|
|
819
840
|
version: z.number().int({ message: "version: must be an integer" }).refine((n) => n === 1, { message: `version: unsupported schema version (expected 1)` }),
|
|
820
841
|
schedules: z.array(scheduleEntrySchema)
|
|
@@ -1010,7 +1031,6 @@ function parseInstall(rest) {
|
|
|
1010
1031
|
let toolRaw;
|
|
1011
1032
|
let viaRaw;
|
|
1012
1033
|
let name;
|
|
1013
|
-
let project;
|
|
1014
1034
|
let dryRun = false;
|
|
1015
1035
|
let cloudRoutine = false;
|
|
1016
1036
|
let json = false;
|
|
@@ -1088,21 +1108,11 @@ function parseInstall(rest) {
|
|
|
1088
1108
|
message: "flag --name specified more than once"
|
|
1089
1109
|
};
|
|
1090
1110
|
name = arg.slice(7);
|
|
1091
|
-
} else if (arg === "--project") {
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
};
|
|
1097
|
-
project = r.value;
|
|
1098
|
-
i++;
|
|
1099
|
-
} else if (arg.startsWith("--project=")) {
|
|
1100
|
-
if (project !== void 0) return {
|
|
1101
|
-
kind: "err",
|
|
1102
|
-
message: "flag --project specified more than once"
|
|
1103
|
-
};
|
|
1104
|
-
project = arg.slice(10);
|
|
1105
|
-
} else if (arg === "--cwd") {
|
|
1111
|
+
} else if (arg === "--project" || arg.startsWith("--project=")) return {
|
|
1112
|
+
kind: "err",
|
|
1113
|
+
message: "--project removed in v1.0 — see CHANGELOG"
|
|
1114
|
+
};
|
|
1115
|
+
else if (arg === "--cwd") {
|
|
1106
1116
|
const r = consumeValue("--cwd", cwd, rest[i + 1]);
|
|
1107
1117
|
if (!r.ok) return {
|
|
1108
1118
|
kind: "err",
|
|
@@ -1168,7 +1178,6 @@ function parseInstall(rest) {
|
|
|
1168
1178
|
functionName,
|
|
1169
1179
|
agent,
|
|
1170
1180
|
plan,
|
|
1171
|
-
project: project ?? "_demo",
|
|
1172
1181
|
cron,
|
|
1173
1182
|
tool: toolRaw,
|
|
1174
1183
|
via,
|
|
@@ -1950,7 +1959,6 @@ function renderFailedExitItem(args) {
|
|
|
1950
1959
|
`function: ${schedule.functionName}`,
|
|
1951
1960
|
`agent: ${schedule.entry.agent}`,
|
|
1952
1961
|
`plan: ${schedule.entry.plan}`,
|
|
1953
|
-
`project: ${schedule.entry.project}`,
|
|
1954
1962
|
`cron: '${schedule.entry.cron}'`,
|
|
1955
1963
|
`exit_code: ${code}`,
|
|
1956
1964
|
`exit_path: ${exit.exitPath}`,
|
|
@@ -1988,7 +1996,6 @@ function renderStaleItem(args) {
|
|
|
1988
1996
|
`function: ${schedule.functionName}`,
|
|
1989
1997
|
`agent: ${schedule.entry.agent}`,
|
|
1990
1998
|
`plan: ${schedule.entry.plan}`,
|
|
1991
|
-
`project: ${schedule.entry.project}`,
|
|
1992
1999
|
`cron: '${schedule.entry.cron}'`,
|
|
1993
2000
|
`expected_before: '${expectedBeforeUtc}'`,
|
|
1994
2001
|
`last_run: '${lastRun?.timestamp ?? ""}'`,
|
|
@@ -2471,6 +2478,14 @@ const FORGE_MARKERS = [
|
|
|
2471
2478
|
"spec/PRD.md",
|
|
2472
2479
|
"plans/phases.yaml"
|
|
2473
2480
|
];
|
|
2481
|
+
const V04_SCAN_SKIP = new Set([
|
|
2482
|
+
"node_modules",
|
|
2483
|
+
"dist",
|
|
2484
|
+
"build",
|
|
2485
|
+
"coverage",
|
|
2486
|
+
"lib",
|
|
2487
|
+
"bin"
|
|
2488
|
+
]);
|
|
2474
2489
|
const TEMPLATE_SUFFIX_RE = /\.template(\.[^.]+)?$/;
|
|
2475
2490
|
function readTemplate(name) {
|
|
2476
2491
|
return readFileSync(join(ROSTER_ROOT, "templates", name), "utf8");
|
|
@@ -2481,6 +2496,35 @@ function substitute(template, vars) {
|
|
|
2481
2496
|
function detectForgeMarkers(cwd) {
|
|
2482
2497
|
return FORGE_MARKERS.filter((m) => existsSync(join(cwd, m)));
|
|
2483
2498
|
}
|
|
2499
|
+
function detectV04Workspace(cwd) {
|
|
2500
|
+
const hits = [];
|
|
2501
|
+
if (existsSync(join(cwd, "projects"))) hits.push("projects/");
|
|
2502
|
+
let topEntries;
|
|
2503
|
+
try {
|
|
2504
|
+
topEntries = readdirSync(cwd, { withFileTypes: true });
|
|
2505
|
+
} catch {
|
|
2506
|
+
return hits;
|
|
2507
|
+
}
|
|
2508
|
+
for (const top of topEntries) {
|
|
2509
|
+
if (!top.isDirectory()) continue;
|
|
2510
|
+
if (top.name.startsWith(".")) continue;
|
|
2511
|
+
if (V04_SCAN_SKIP.has(top.name)) continue;
|
|
2512
|
+
const topPath = join(cwd, top.name);
|
|
2513
|
+
if (existsSync(join(topPath, "projects"))) hits.push(`${top.name}/projects/`);
|
|
2514
|
+
let subEntries;
|
|
2515
|
+
try {
|
|
2516
|
+
subEntries = readdirSync(topPath, { withFileTypes: true });
|
|
2517
|
+
} catch {
|
|
2518
|
+
continue;
|
|
2519
|
+
}
|
|
2520
|
+
for (const sub of subEntries) {
|
|
2521
|
+
if (!sub.isDirectory()) continue;
|
|
2522
|
+
if (sub.name.startsWith(".")) continue;
|
|
2523
|
+
if (existsSync(join(topPath, sub.name, "projects"))) hits.push(`${top.name}/${sub.name}/projects/`);
|
|
2524
|
+
}
|
|
2525
|
+
}
|
|
2526
|
+
return hits;
|
|
2527
|
+
}
|
|
2484
2528
|
function entryAtPath(path) {
|
|
2485
2529
|
try {
|
|
2486
2530
|
return {
|
|
@@ -2576,6 +2620,8 @@ async function executeInit(opts) {
|
|
|
2576
2620
|
const info = (msg) => {
|
|
2577
2621
|
if (!silent) logger.log(msg);
|
|
2578
2622
|
};
|
|
2623
|
+
const v04Hits = detectV04Workspace(opts.cwd);
|
|
2624
|
+
if (v04Hits.length > 0) throw v04WorkspaceDetectedError(v04Hits);
|
|
2579
2625
|
const forgeMarkers = detectForgeMarkers(opts.cwd);
|
|
2580
2626
|
const contextMdPath = join(opts.cwd, "CONTEXT.md");
|
|
2581
2627
|
const claudeMdPath = join(opts.cwd, "CLAUDE.md");
|
|
@@ -2621,7 +2667,10 @@ async function executeInit(opts) {
|
|
|
2621
2667
|
const warnings = [];
|
|
2622
2668
|
const scaffoldSrc = join(ROSTER_ROOT, "templates", "scaffold");
|
|
2623
2669
|
if (!existsSync(scaffoldSrc)) throw missingScaffoldError(scaffoldSrc);
|
|
2624
|
-
const scaffoldFiles = walkScaffold(scaffoldSrc, opts.cwd, {
|
|
2670
|
+
const scaffoldFiles = walkScaffold(scaffoldSrc, opts.cwd, {
|
|
2671
|
+
PROJECT_NAME: projectName,
|
|
2672
|
+
DISPLAY_NAME: projectName
|
|
2673
|
+
});
|
|
2625
2674
|
filesWritten.push(...scaffoldFiles);
|
|
2626
2675
|
if (isMigration && migrate) {
|
|
2627
2676
|
const existingClaudeMd = readFileSync(claudeMdPath, "utf8");
|
|
@@ -3101,6 +3150,90 @@ function validateSchedulesInCwd(cwd) {
|
|
|
3101
3150
|
};
|
|
3102
3151
|
}
|
|
3103
3152
|
//#endregion
|
|
3153
|
+
//#region src/lib/dotenv-parse.ts
|
|
3154
|
+
const KEY_RE = /^([A-Za-z_][A-Za-z0-9_]*)\s*=\s*/;
|
|
3155
|
+
function parseEnvFile(content) {
|
|
3156
|
+
const out = /* @__PURE__ */ new Map();
|
|
3157
|
+
if (content.charCodeAt(0) === 65279) content = content.slice(1);
|
|
3158
|
+
for (const rawLine of content.split(/\r?\n/)) {
|
|
3159
|
+
const trimmed = rawLine.replace(/^\s+/, "");
|
|
3160
|
+
if (trimmed.length === 0 || trimmed.startsWith("#")) continue;
|
|
3161
|
+
const candidate = trimmed.startsWith("export ") ? trimmed.slice(7).replace(/^\s+/, "") : trimmed;
|
|
3162
|
+
const m = candidate.match(KEY_RE);
|
|
3163
|
+
if (m === null) continue;
|
|
3164
|
+
const key = m[1];
|
|
3165
|
+
const parsed = parseValue(candidate.slice(m[0].length));
|
|
3166
|
+
if (parsed === null) continue;
|
|
3167
|
+
out.set(key, parsed);
|
|
3168
|
+
}
|
|
3169
|
+
return out;
|
|
3170
|
+
}
|
|
3171
|
+
function parseEnvKeys(content) {
|
|
3172
|
+
return Array.from(parseEnvFile(content).keys());
|
|
3173
|
+
}
|
|
3174
|
+
function parseValue(src) {
|
|
3175
|
+
if (src.length === 0) return "";
|
|
3176
|
+
const first = src.charAt(0);
|
|
3177
|
+
if (first === "\"") return parseDoubleQuoted(src);
|
|
3178
|
+
if (first === "'") return parseSingleQuoted(src);
|
|
3179
|
+
return parseUnquoted(src);
|
|
3180
|
+
}
|
|
3181
|
+
function parseDoubleQuoted(src) {
|
|
3182
|
+
let i = 1;
|
|
3183
|
+
let out = "";
|
|
3184
|
+
while (i < src.length) {
|
|
3185
|
+
const c = src.charAt(i);
|
|
3186
|
+
if (c === "\\" && i + 1 < src.length) {
|
|
3187
|
+
const next = src.charAt(i + 1);
|
|
3188
|
+
switch (next) {
|
|
3189
|
+
case "n":
|
|
3190
|
+
out += "\n";
|
|
3191
|
+
break;
|
|
3192
|
+
case "r":
|
|
3193
|
+
out += "\r";
|
|
3194
|
+
break;
|
|
3195
|
+
case "t":
|
|
3196
|
+
out += " ";
|
|
3197
|
+
break;
|
|
3198
|
+
case "\"":
|
|
3199
|
+
out += "\"";
|
|
3200
|
+
break;
|
|
3201
|
+
case "\\":
|
|
3202
|
+
out += "\\";
|
|
3203
|
+
break;
|
|
3204
|
+
default:
|
|
3205
|
+
out += "\\" + next;
|
|
3206
|
+
break;
|
|
3207
|
+
}
|
|
3208
|
+
i += 2;
|
|
3209
|
+
continue;
|
|
3210
|
+
}
|
|
3211
|
+
if (c === "\"") {
|
|
3212
|
+
const after = src.slice(i + 1).replace(/^\s+/, "");
|
|
3213
|
+
if (after.length === 0 || after.startsWith("#")) return out;
|
|
3214
|
+
return null;
|
|
3215
|
+
}
|
|
3216
|
+
out += c;
|
|
3217
|
+
i++;
|
|
3218
|
+
}
|
|
3219
|
+
return null;
|
|
3220
|
+
}
|
|
3221
|
+
function parseSingleQuoted(src) {
|
|
3222
|
+
const close = src.indexOf("'", 1);
|
|
3223
|
+
if (close === -1) return null;
|
|
3224
|
+
const after = src.slice(close + 1).replace(/^\s+/, "");
|
|
3225
|
+
if (after.length === 0 || after.startsWith("#")) return src.slice(1, close);
|
|
3226
|
+
return null;
|
|
3227
|
+
}
|
|
3228
|
+
function parseUnquoted(src) {
|
|
3229
|
+
let end = src.length;
|
|
3230
|
+
for (let i = 0; i < src.length; i++) if (src.charAt(i) === "#" && i > 0 && /\s/.test(src.charAt(i - 1))) {
|
|
3231
|
+
end = i;
|
|
3232
|
+
break;
|
|
3233
|
+
}
|
|
3234
|
+
return src.slice(0, end).replace(/\s+$/, "");
|
|
3235
|
+
}
|
|
3236
|
+
//#endregion
|
|
3104
3237
|
//#region src/lib/platform.ts
|
|
3105
3238
|
function getPlatform() {
|
|
3106
3239
|
const override = process.env["ROSTER_PLATFORM"];
|
|
@@ -3142,21 +3275,6 @@ function auditEnvPermissions(cwd) {
|
|
|
3142
3275
|
autoFixable: true
|
|
3143
3276
|
};
|
|
3144
3277
|
}
|
|
3145
|
-
const ENV_KEY_RE = /^([A-Za-z_][A-Za-z0-9_]*)\s*=/;
|
|
3146
|
-
function parseEnvKeys(content) {
|
|
3147
|
-
const out = [];
|
|
3148
|
-
const seen = /* @__PURE__ */ new Set();
|
|
3149
|
-
for (const rawLine of content.split(/\r?\n/)) {
|
|
3150
|
-
const line = rawLine.trim();
|
|
3151
|
-
if (line.length === 0 || line.startsWith("#")) continue;
|
|
3152
|
-
const m = (line.startsWith("export ") ? line.slice(7).trim() : line).match(ENV_KEY_RE);
|
|
3153
|
-
if (m && !seen.has(m[1])) {
|
|
3154
|
-
seen.add(m[1]);
|
|
3155
|
-
out.push(m[1]);
|
|
3156
|
-
}
|
|
3157
|
-
}
|
|
3158
|
-
return out;
|
|
3159
|
-
}
|
|
3160
3278
|
const VAR_REF_RE = /\$(?:\{([A-Za-z_][A-Za-z0-9_]*)\}|([A-Za-z_][A-Za-z0-9_]*))/g;
|
|
3161
3279
|
function extractVarRefs(content) {
|
|
3162
3280
|
const out = /* @__PURE__ */ new Map();
|
|
@@ -3257,7 +3375,8 @@ function auditEnvKeyReferences(cwd) {
|
|
|
3257
3375
|
const envPath = join(cwd, ".env");
|
|
3258
3376
|
let envKeys = [];
|
|
3259
3377
|
try {
|
|
3260
|
-
|
|
3378
|
+
const raw = readFileSync(envPath, "utf8");
|
|
3379
|
+
envKeys = Array.from(parseEnvFile(raw).entries()).filter(([, v]) => v.length > 0).map(([k]) => k);
|
|
3261
3380
|
} catch {}
|
|
3262
3381
|
const envKeySet = new Set(envKeys);
|
|
3263
3382
|
const yamls = collectConfigYamls(cwd);
|
|
@@ -3895,11 +4014,11 @@ function deriveScheduleName(agent, plan, override) {
|
|
|
3895
4014
|
if (override !== void 0 && override !== "") return override;
|
|
3896
4015
|
return `${agent}-${plan}`;
|
|
3897
4016
|
}
|
|
3898
|
-
function buildOrchestratorPrompt(agent, plan
|
|
3899
|
-
return `Use the roster-orchestrator skill to run plan ${plan} for agent ${agent}
|
|
4017
|
+
function buildOrchestratorPrompt(agent, plan) {
|
|
4018
|
+
return `Use the roster-orchestrator skill to run plan ${plan} for agent ${agent}`;
|
|
3900
4019
|
}
|
|
3901
4020
|
function renderFieldsDoc(args) {
|
|
3902
|
-
const prompt = buildOrchestratorPrompt(args.agent, args.plan
|
|
4021
|
+
const prompt = buildOrchestratorPrompt(args.agent, args.plan);
|
|
3903
4022
|
const allowedTools = DEFAULT_ALLOWED_TOOLS.join(", ");
|
|
3904
4023
|
return [
|
|
3905
4024
|
`# Claude Desktop Scheduled Task — ${args.name}`,
|
|
@@ -3963,7 +4082,6 @@ function installClaudeSchedule(opts) {
|
|
|
3963
4082
|
name: resolvedName,
|
|
3964
4083
|
agent: opts.agent,
|
|
3965
4084
|
plan: opts.plan,
|
|
3966
|
-
project: opts.project,
|
|
3967
4085
|
cron: opts.cron,
|
|
3968
4086
|
tool: "claude",
|
|
3969
4087
|
install_mode: "ui-handoff",
|
|
@@ -3994,8 +4112,7 @@ function installClaudeSchedule(opts) {
|
|
|
3994
4112
|
cron: validatedEntry.cron,
|
|
3995
4113
|
workspacePath,
|
|
3996
4114
|
agent: validatedEntry.agent,
|
|
3997
|
-
plan: validatedEntry.plan
|
|
3998
|
-
project: validatedEntry.project
|
|
4115
|
+
plan: validatedEntry.plan
|
|
3999
4116
|
});
|
|
4000
4117
|
if (opts.dryRun) return {
|
|
4001
4118
|
resolvedName,
|
|
@@ -4145,7 +4262,7 @@ function auditCronDrift(opts) {
|
|
|
4145
4262
|
cron: entry.cron,
|
|
4146
4263
|
workspacePath,
|
|
4147
4264
|
codexBinaryPath,
|
|
4148
|
-
prompt: buildOrchestratorPrompt(entry.agent, entry.plan
|
|
4265
|
+
prompt: buildOrchestratorPrompt(entry.agent, entry.plan),
|
|
4149
4266
|
logPath: logPathFor(workspacePath, entry.name),
|
|
4150
4267
|
exitPath: exitPathFor(workspacePath, entry.name),
|
|
4151
4268
|
...entry.capture_events === true ? { eventsPath: eventsPathFor(workspacePath, entry.name) } : {}
|
|
@@ -4777,7 +4894,7 @@ function executeDoctor(opts) {
|
|
|
4777
4894
|
//#region src/lib/codex-install.ts
|
|
4778
4895
|
const KEBAB_RE = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
4779
4896
|
function renderCodexHandoffDoc(args) {
|
|
4780
|
-
const prompt = buildOrchestratorPrompt(args.agent, args.plan
|
|
4897
|
+
const prompt = buildOrchestratorPrompt(args.agent, args.plan);
|
|
4781
4898
|
return [
|
|
4782
4899
|
`# Codex App Automation — ${args.name}`,
|
|
4783
4900
|
"",
|
|
@@ -4865,7 +4982,6 @@ function installCodexSchedule(opts) {
|
|
|
4865
4982
|
name: resolvedName,
|
|
4866
4983
|
agent: opts.agent,
|
|
4867
4984
|
plan: opts.plan,
|
|
4868
|
-
project: opts.project,
|
|
4869
4985
|
cron: opts.cron,
|
|
4870
4986
|
tool: "codex",
|
|
4871
4987
|
install_mode: opts.installMode,
|
|
@@ -4893,8 +5009,7 @@ function installCodexSchedule(opts) {
|
|
|
4893
5009
|
cron: validatedEntry.cron,
|
|
4894
5010
|
workspacePath,
|
|
4895
5011
|
agent: validatedEntry.agent,
|
|
4896
|
-
plan: validatedEntry.plan
|
|
4897
|
-
project: validatedEntry.project
|
|
5012
|
+
plan: validatedEntry.plan
|
|
4898
5013
|
}) : null;
|
|
4899
5014
|
let cronLine = null;
|
|
4900
5015
|
if (opts.installMode === "via-cron") {
|
|
@@ -4903,7 +5018,7 @@ function installCodexSchedule(opts) {
|
|
|
4903
5018
|
cron: validatedEntry.cron,
|
|
4904
5019
|
workspacePath,
|
|
4905
5020
|
codexBinaryPath,
|
|
4906
|
-
prompt: buildOrchestratorPrompt(validatedEntry.agent, validatedEntry.plan
|
|
5021
|
+
prompt: buildOrchestratorPrompt(validatedEntry.agent, validatedEntry.plan),
|
|
4907
5022
|
logPath,
|
|
4908
5023
|
exitPath,
|
|
4909
5024
|
...validatedEntry.capture_events === true ? { eventsPath: eventsPathFor(workspacePath, resolvedName) } : {}
|
|
@@ -5716,7 +5831,7 @@ async function executeRun(opts) {
|
|
|
5716
5831
|
name: opts.name,
|
|
5717
5832
|
functionName: opts.functionName
|
|
5718
5833
|
});
|
|
5719
|
-
const prompt = buildOrchestratorPrompt(resolved.entry.agent, resolved.entry.plan
|
|
5834
|
+
const prompt = buildOrchestratorPrompt(resolved.entry.agent, resolved.entry.plan);
|
|
5720
5835
|
if (resolved.entry.tool === "claude") {
|
|
5721
5836
|
for (const line of renderClaudeHandoff(resolved.workspacePath, prompt, resolved.entry.name, opts.silent, opts.dryRun)) console.log(line);
|
|
5722
5837
|
return {
|
|
@@ -5893,7 +6008,6 @@ function executeScheduleInstall(opts) {
|
|
|
5893
6008
|
functionName: opts.functionName,
|
|
5894
6009
|
agent: opts.agent,
|
|
5895
6010
|
plan: opts.plan,
|
|
5896
|
-
project: opts.project,
|
|
5897
6011
|
cron: opts.cron,
|
|
5898
6012
|
name: opts.name,
|
|
5899
6013
|
dryRun: opts.dryRun
|
|
@@ -5917,7 +6031,6 @@ function executeScheduleInstall(opts) {
|
|
|
5917
6031
|
functionName: opts.functionName,
|
|
5918
6032
|
agent: opts.agent,
|
|
5919
6033
|
plan: opts.plan,
|
|
5920
|
-
project: opts.project,
|
|
5921
6034
|
cron: opts.cron,
|
|
5922
6035
|
name: opts.name,
|
|
5923
6036
|
installMode,
|
|
@@ -7693,7 +7806,6 @@ function printHelp(version) {
|
|
|
7693
7806
|
` --fix ${chalk.dim("Auto-fix broken symlinks + .env permissions (doctor)")}`,
|
|
7694
7807
|
` --cwd <dir> ${chalk.dim("Run schedule validate against a different cwd")}`,
|
|
7695
7808
|
` --dest <dir> ${chalk.dim("Destination workspace for migrate (default: cwd)")}`,
|
|
7696
|
-
` --project <name> ${chalk.dim("Project slug for schedule install (default: _demo)")}`,
|
|
7697
7809
|
` --dry-run ${chalk.dim("Print plan without writes (schedule *, doctor, migrate)")}`,
|
|
7698
7810
|
` --force-resync ${chalk.dim("Re-copy source files that changed since last migration (migrate)")}`,
|
|
7699
7811
|
` --debug ${chalk.dim("Print full stack trace on error (global)")}`,
|
|
@@ -7839,7 +7951,6 @@ async function runSchedule(args) {
|
|
|
7839
7951
|
functionName: parsed.functionName,
|
|
7840
7952
|
agent: parsed.agent,
|
|
7841
7953
|
plan: parsed.plan,
|
|
7842
|
-
project: parsed.project,
|
|
7843
7954
|
cron: parsed.cron,
|
|
7844
7955
|
tool: parsed.tool,
|
|
7845
7956
|
via: parsed.via,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@firatcand/roster",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "A CLI that scaffolds a structured multi-agent workspace on top of AI coding tools (Claude Code, Codex CLI, Gemini)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -27,10 +27,9 @@
|
|
|
27
27
|
"test:update-golden": "node --experimental-strip-types scripts/update-golden.ts",
|
|
28
28
|
"test:update-golden:stub": "node --experimental-strip-types scripts/update-golden-stub.ts",
|
|
29
29
|
"smoke": "bash test/smoke.sh",
|
|
30
|
-
"e2e": "bash test/e2e-sdr.sh",
|
|
31
30
|
"e2e:schedule": "bash test/e2e-schedule.sh",
|
|
32
31
|
"perf": "bash test/perf.sh",
|
|
33
|
-
"test:
|
|
32
|
+
"test:scaffold-scripts": "bash test/new-agent-slash-only.sh",
|
|
34
33
|
"probe:claude-url": "bash scripts/probe-claude-url-scheme.sh"
|
|
35
34
|
},
|
|
36
35
|
"keywords": [
|