agentic-team 6.1.0 → 6.2.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.
Files changed (45) hide show
  1. package/README.md +8 -3
  2. package/bin/build-template.js +2 -2
  3. package/bin/index.js +234 -39
  4. package/bin/platforms.js +510 -0
  5. package/package.json +4 -4
  6. package/template/.claude-plugin/plugin.json +2 -2
  7. package/template/.orchestra/README.md +41 -51
  8. package/template/.orchestra/config.yml +16 -0
  9. package/template/.orchestra/roles/product-manager.md +3 -2
  10. package/template/.orchestra/scripts/compact-diff.awk +1 -1
  11. package/template/.orchestra/scripts/context.mjs +373 -0
  12. package/template/.orchestra/stacks/_repo/setup.sh +7 -3
  13. package/template/.orchestra/stacks/mobile-expo/setup.sh +1 -1
  14. package/template/CLAUDE.md +1 -1
  15. package/template/agents/lead.md +171 -116
  16. package/template/agents/milestone-reviewer.md +5 -3
  17. package/template/agents/product-manager.md +3 -2
  18. package/template/agents/re-reviewer.md +25 -0
  19. package/template/agents/reviewer.md +7 -5
  20. package/template/agents/scaffolder.md +26 -0
  21. package/template/commands/help.md +1 -0
  22. package/template/commands/hotfix.md +3 -1
  23. package/template/commands/rewind.md +10 -8
  24. package/template/commands/setup.md +2 -1
  25. package/template/commands/start.md +2 -2
  26. package/template/commands/status.md +1 -1
  27. package/template/commands/sync.md +5 -2
  28. package/template/commands/verifier.md +2 -2
  29. package/template/hooks/audit-context.sh +15 -2
  30. package/template/hooks/enforce-role.sh +21 -3
  31. package/template/hooks/protect-system-files.sh +2 -2
  32. package/template/hooks/review-rounds.sh +1 -1
  33. package/template/rules/code-standards.orchestra.md +3 -2
  34. package/template/rules/design-parity.orchestra.md +12 -1
  35. package/template/rules/observability.orchestra.md +3 -0
  36. package/template/rules/performance.orchestra.md +5 -1
  37. package/template/rules/phase-limits.orchestra.md +1 -1
  38. package/template/rules/pull-request.orchestra.md +7 -2
  39. package/template/rules/role-boundaries.orchestra.md +24 -9
  40. package/template/rules/security.orchestra.md +1 -1
  41. package/template/rules/stuck-detection.orchestra.md +1 -1
  42. package/template/rules/testing-standards.orchestra.md +10 -5
  43. package/template/rules/tracker-authority.orchestra.md +9 -1
  44. package/template/skills/push-notifications/SKILL.md +1 -1
  45. package/template/skills/testing/SKILL.md +2 -1
@@ -0,0 +1,510 @@
1
+ // Which platforms a project builds for, and which installed files belong to
2
+ // which platform.
3
+ //
4
+ // An iOS project was getting Next.js, Expo, Hono and Android material: every
5
+ // stack, every skill, every platform's testing rules. The engineer read "never
6
+ // mock the database" and "component tests run in Chromium", and was offered
7
+ // web-testing as a skill. `project.platforms` in config.yml narrows the
8
+ // install to what the project actually is. An empty list installs everything,
9
+ // because /orchestra:setup has not chosen yet.
10
+
11
+ const fs = require("node:fs");
12
+ const path = require("node:path");
13
+
14
+ const read = (file) => {
15
+ try {
16
+ return fs.readFileSync(file, "utf8");
17
+ } catch {
18
+ // Optional: an unreadable or missing file is simply not a signal.
19
+ return "";
20
+ }
21
+ };
22
+
23
+ const PLATFORMS = ["web", "expo", "ios", "android", "backend"];
24
+
25
+ // Every shipped skill is listed. test/platforms.test.js fails on one that is
26
+ // not, so a new skill cannot silently install everywhere.
27
+ const SKILLS = {
28
+ architecture: "all",
29
+ "code-optimizer": "all",
30
+ debug: "all",
31
+ "error-handling": "all",
32
+ observability: "all",
33
+ "project-structure": "all",
34
+ realtime: "all",
35
+ review: "all",
36
+ testing: "all",
37
+ // Both speak ARIA and CSS today; native iOS and Android have no UI or
38
+ // accessibility skill yet, and these would teach them the web's answers.
39
+ accessibility: ["web", "expo"],
40
+ "frontend-design": ["web", "expo"],
41
+ "best-practices": ["web"],
42
+ "core-web-vitals": ["web"],
43
+ "react-best-practices": ["web"],
44
+ "web-quality-audit": ["web"],
45
+ "web-testing": ["web"],
46
+ // TypeScript and React conventions — every platform written in TypeScript.
47
+ "fullstack-infrastructure": ["web", "expo", "backend"],
48
+ "mobile-testing": ["expo"],
49
+ "ios-testing": ["ios"],
50
+ "android-testing": ["android"],
51
+ "push-notifications": ["expo", "ios", "android"],
52
+ "crud-api": ["backend"],
53
+ // Health and readiness endpoints, promotion, rollback, migrations: a
54
+ // service's deploy, and it implements the rule sections only a backend gets.
55
+ deployment: ["backend"],
56
+ // The decisions the backend stack scaffolded — sessions, hashing, where the
57
+ // code lives. On a client it would describe a server that is not there.
58
+ "auth-setup": ["backend"],
59
+ };
60
+
61
+ // Keyed by the directory under .orchestra/stacks/. Files directly under it
62
+ // (README.md) and the shared _lib and _repo serve every stack.
63
+ const STACKS = {
64
+ _lib: "all",
65
+ _repo: "all",
66
+ "web-vite-react": ["web"],
67
+ "web-nextjs": ["web"],
68
+ "mobile-expo": ["expo"],
69
+ "mobile-ios-native": ["ios"],
70
+ "mobile-android-native": ["android"],
71
+ "backend-hono": ["backend"],
72
+ };
73
+
74
+ /** "[ios, backend]", "ios,backend" or an array → a trimmed, de-duplicated list. */
75
+ function parsePlatforms(value) {
76
+ if (Array.isArray(value)) {
77
+ // Quotes and case are the user's spelling, not a different platform:
78
+ // `- "iOS"` dropped as unknown once narrowed a project and rewrote its list.
79
+ const clean = value.map((v) =>
80
+ String(v)
81
+ .trim()
82
+ .replace(/^["']|["']$/g, "")
83
+ .toLowerCase(),
84
+ );
85
+ return [...new Set(clean.filter(Boolean))];
86
+ }
87
+ const inner = String(value ?? "")
88
+ .trim()
89
+ .replace(/^\[|\]$/g, "");
90
+ return parsePlatforms(inner.split(",").map((v) => v.trim().replace(/^["']|["']$/g, "")));
91
+ }
92
+
93
+ /** The tags of one installed path (repo-relative, POSIX), or "all". */
94
+ function tagsFor(rel) {
95
+ const skill = /^\.claude\/skills\/([^/]+)\//.exec(rel);
96
+ if (skill) return SKILLS[skill[1]] ?? "all";
97
+ const stack = /^\.orchestra\/stacks\/([^/]+)\//.exec(rel);
98
+ if (stack) return STACKS[stack[1]] ?? "all";
99
+ return "all";
100
+ }
101
+
102
+ function wanted(tags, platforms) {
103
+ if (!platforms.length || tags === "all") return true;
104
+ return tags.some((t) => platforms.includes(t));
105
+ }
106
+
107
+ /**
108
+ * Whether an installed path belongs in a project with these platforms. A
109
+ * skill a milestone phase already names is kept whatever its tags: lead reads
110
+ * `.claude/skills/{name}/SKILL.md` for every name a phase lists, and a plan
111
+ * written before the list was narrowed must not lose a skill it relies on.
112
+ */
113
+ function selected(rel, platforms, keepSkills = new Set()) {
114
+ const skill = /^\.claude\/skills\/([^/]+)\//.exec(rel);
115
+ if (skill && keepSkills.has(skill[1])) return true;
116
+ return wanted(tagsFor(rel), platforms);
117
+ }
118
+
119
+ /** Every skill name a phase under `.orchestra/milestones/` lists in `skills:`. */
120
+ function phaseSkills(root) {
121
+ const names = new Set();
122
+ const milestones = path.join(root, ".orchestra", "milestones");
123
+ let dirs = [];
124
+ try {
125
+ dirs = fs.readdirSync(milestones);
126
+ } catch {
127
+ // No milestones yet: no phase names any skill.
128
+ return names;
129
+ }
130
+ for (const m of dirs) {
131
+ const phases = path.join(milestones, m, "phases");
132
+ let files = [];
133
+ try {
134
+ files = fs.readdirSync(phases).filter((f) => f.endsWith(".md"));
135
+ } catch {
136
+ // A milestone without phases yet.
137
+ continue;
138
+ }
139
+ for (const f of files) {
140
+ const text = read(path.join(phases, f));
141
+ const flow = /^skills:\s*\[([^\]]*)\]/m.exec(text);
142
+ if (flow) {
143
+ for (const n of parsePlatforms(flow[1])) names.add(n);
144
+ continue;
145
+ }
146
+ const block = /^skills:\s*\n((?:\s+-\s*.+\n?)+)/m.exec(text);
147
+ if (block) {
148
+ for (const line of block[1].split("\n")) {
149
+ const item = /^\s+-\s*([^#\s]+)/.exec(line);
150
+ if (item) names.add(item[1].replace(/^["']|["']$/g, ""));
151
+ }
152
+ }
153
+ }
154
+ }
155
+ return names;
156
+ }
157
+
158
+ /**
159
+ * The value of `--platforms` in an argument list, and the indexes it used.
160
+ * Names after the flag, space-separated or after `=`, are all taken until the
161
+ * next option: "--platforms ios backend" once kept ios and retired backend.
162
+ * Shared by the install and by `new`, which parsed it differently and took a
163
+ * platform for the repository name.
164
+ */
165
+ function takePlatformsArg(argv) {
166
+ const at = argv.findIndex((a) => a === "--platforms" || a.startsWith("--platforms="));
167
+ if (at === -1) return null;
168
+ const parts = argv[at] === "--platforms" ? [] : [argv[at].slice("--platforms=".length)];
169
+ let i = at + 1;
170
+ while (i < argv.length && !argv[i].startsWith("-")) parts.push(argv[i++]);
171
+ return { list: parsePlatforms(parts.join(",")), used: new Set(range(at, i)) };
172
+ }
173
+
174
+ const range = (from, to) => Array.from({ length: to - from }, (_, k) => from + k);
175
+
176
+ // A rule section that applies to some platforms only carries a marker on the
177
+ // line before its heading:
178
+ //
179
+ // <!-- platforms: backend -->
180
+ // ## Backend — the shape
181
+ //
182
+ // The section runs to the next heading of the same or a higher level. Markers
183
+ // rather than one file per platform, because a dozen files point at
184
+ // `testing-standards.orchestra.md` by name; split, every one of those pointers
185
+ // would have to learn which piece it meant.
186
+ const MARKER = /^<!--\s*platforms:\s*([^>]*?)\s*-->\s*$/;
187
+ const HEADING = /^(#{1,6})\s/;
188
+
189
+ /** A rule's text with other platforms' sections removed, and markers always removed. */
190
+ function filterSections(text, platforms) {
191
+ const out = [];
192
+ let pending = null;
193
+ let skipLevel = 0;
194
+ let fence = null;
195
+ for (const line of text.split("\n")) {
196
+ // A `#` line inside a code block is a shell comment, not a heading. A
197
+ // fence closes only on the same character, at least as long — a ````
198
+ // block may show a ``` one inside it.
199
+ const f = /^\s*(`{3,}|~{3,})/.exec(line);
200
+ if (f && (!fence || (f[1][0] === fence[0] && f[1].length >= fence.length))) {
201
+ fence = fence ? null : f[1];
202
+ if (!skipLevel) out.push(line);
203
+ continue;
204
+ }
205
+ if (fence) {
206
+ if (!skipLevel) out.push(line);
207
+ continue;
208
+ }
209
+ const marker = MARKER.exec(line);
210
+ if (marker) {
211
+ pending = parsePlatforms(marker[1]);
212
+ continue;
213
+ }
214
+ const heading = HEADING.exec(line);
215
+ if (heading) {
216
+ const level = heading[1].length;
217
+ if (skipLevel && level <= skipLevel) skipLevel = 0;
218
+ if (pending && !wanted(pending, platforms)) skipLevel = level;
219
+ pending = null;
220
+ }
221
+ if (!skipLevel) out.push(line);
222
+ }
223
+ return out.join("\n");
224
+ }
225
+
226
+ // ── Detection ──────────────────────────────────────────────────────────────
227
+ //
228
+ // Code, not an agent's guess: the same files every time give the same answer,
229
+ // and the installer prints it so a wrong answer is seen and overridden.
230
+
231
+ const SKIP_DIRS = new Set([
232
+ "node_modules",
233
+ "Pods",
234
+ "build",
235
+ "dist",
236
+ "DerivedData",
237
+ "vendor",
238
+ "target",
239
+ "out",
240
+ "export",
241
+ "exports",
242
+ "release",
243
+ "generated",
244
+ ]);
245
+
246
+ function dependencies(dir) {
247
+ const text = read(path.join(dir, "package.json"));
248
+ if (!text) return null;
249
+ try {
250
+ const pkg = JSON.parse(text);
251
+ return { ...pkg.dependencies, ...pkg.devDependencies, ...pkg.peerDependencies };
252
+ } catch {
253
+ // A package.json that does not parse says nothing about the platform.
254
+ return null;
255
+ }
256
+ }
257
+
258
+ const has = (deps, names) => names.some((n) => Object.hasOwn(deps, n));
259
+
260
+ // vite is not on either list: the scaffolded Hono backend carries it as
261
+ // vitest's peer, and a bundler is not a web app until a UI library sits on it.
262
+ const WEB_FRAMEWORKS = [
263
+ "next",
264
+ "nuxt",
265
+ "@sveltejs/kit",
266
+ "astro",
267
+ "@angular/core",
268
+ "@remix-run/react",
269
+ ];
270
+ const WEB_UI = ["react-dom", "vue", "svelte", "solid-js", "preact"];
271
+ // A desktop shell renders a UI with the same libraries. Desktop has no pack,
272
+ // so it detects as nothing rather than as web.
273
+ const DESKTOP = ["electron", "@tauri-apps/api", "@tauri-apps/cli"];
274
+ const SERVER = [
275
+ "hono",
276
+ "express",
277
+ "fastify",
278
+ "koa",
279
+ "@nestjs/core",
280
+ "@hapi/hapi",
281
+ "@trpc/server",
282
+ "elysia",
283
+ ];
284
+
285
+ const MOBILE_SDK = /SDKROOT = (iphoneos|watchos|xros)|IPHONEOS_DEPLOYMENT_TARGET/;
286
+ // A target's platform key, not any mention: a macOS app's comment may say iOS.
287
+ const XCODEGEN_IOS =
288
+ /^\s*(platform|supportedDestinations|deploymentTarget):[^\n]*\b(iOS|watchOS|visionOS)\b/m;
289
+ const PY_REQUIREMENT = /^\s*(fastapi|django|flask|starlette)\b/im;
290
+ const PY_PROJECT =
291
+ /(["'](fastapi|django|flask|starlette)\b|^\s*(fastapi|django|flask|starlette)\s*=)/im;
292
+
293
+ /** Platforms one directory shows on its own, plus children to leave unscanned. */
294
+ function signals(dir) {
295
+ const found = new Set();
296
+ const skip = new Set();
297
+ const names = (() => {
298
+ try {
299
+ return fs.readdirSync(dir);
300
+ } catch {
301
+ // Unreadable directory: nothing to detect in it.
302
+ return [];
303
+ }
304
+ })();
305
+
306
+ const deps = dependencies(dir);
307
+ if (deps) {
308
+ const native = has(deps, ["expo", "react-native"]);
309
+ if (native) {
310
+ found.add("expo");
311
+ // A React Native app carries generated ios/ and android/ projects.
312
+ // They are its build output, not a second and third app.
313
+ skip.add("ios");
314
+ skip.add("android");
315
+ }
316
+ // react-dom alone is Expo's web target in a React Native app.
317
+ const web =
318
+ native || has(deps, DESKTOP)
319
+ ? has(deps, WEB_FRAMEWORKS)
320
+ : has(deps, [...WEB_FRAMEWORKS, ...WEB_UI]);
321
+ if (web) found.add("web");
322
+ if (has(deps, SERVER)) found.add("backend");
323
+ }
324
+
325
+ // An Xcode project is iOS only when it builds for an Apple mobile SDK; a
326
+ // macOS-only app is desktop, which has no pack. watchOS and visionOS ride
327
+ // along with iOS, which is what the ios stack and skills cover.
328
+ if (
329
+ names.some(
330
+ (n) =>
331
+ n.endsWith(".xcodeproj") && MOBILE_SDK.test(read(path.join(dir, n, "project.pbxproj"))),
332
+ ) ||
333
+ XCODEGEN_IOS.test(read(path.join(dir, "project.yml"))) ||
334
+ /\.iOS\(/.test(read(path.join(dir, "Package.swift")))
335
+ ) {
336
+ found.add("ios");
337
+ }
338
+
339
+ const gradle = ["build.gradle", "build.gradle.kts", "settings.gradle", "settings.gradle.kts"]
340
+ .map((f) => read(path.join(dir, f)))
341
+ .join("\n");
342
+ if (/com\.android|plugins\.android|android\s*\{/.test(gradle)) found.add("android");
343
+
344
+ if (names.includes("go.mod")) found.add("backend");
345
+ // A requirement line starts with the package name; a pyproject names it in
346
+ // quotes or as a key. Prose that mentions Flask is not a server.
347
+ if (
348
+ PY_REQUIREMENT.test(read(path.join(dir, "requirements.txt"))) ||
349
+ PY_PROJECT.test(read(path.join(dir, "pyproject.toml")))
350
+ ) {
351
+ found.add("backend");
352
+ }
353
+ if (/\brails\b/.test(read(path.join(dir, "Gemfile")))) found.add("backend");
354
+ if (/\b(axum|actix-web|rocket)\b/.test(read(path.join(dir, "Cargo.toml")))) found.add("backend");
355
+
356
+ // A game engine exports native projects for every target it ships to.
357
+ // They are build output; game has no pack, so the engine project is nothing.
358
+ const engine =
359
+ names.includes("project.godot") ||
360
+ names.some((n) => n.endsWith(".uproject")) ||
361
+ (names.includes("Assets") && names.includes("ProjectSettings"));
362
+ if (engine) return { found: new Set(), skip: new Set(names), names };
363
+
364
+ return { found, skip, names };
365
+ }
366
+
367
+ // Directories that hold something other than the product: a docs site, an
368
+ // example, a fixture. Scanning them reports platforms nobody ships.
369
+ const NOT_APPS = new Set([
370
+ "docs",
371
+ "doc",
372
+ "website",
373
+ "examples",
374
+ "example",
375
+ "samples",
376
+ "sample",
377
+ "fixtures",
378
+ "test",
379
+ "tests",
380
+ "__tests__",
381
+ "e2e",
382
+ "scripts",
383
+ "tools",
384
+ "archive",
385
+ ]);
386
+
387
+ /**
388
+ * Platforms found in the repository at `root`: the root and two levels of
389
+ * directories under it (`apps/web`, `clients/ios`), skipping dependencies,
390
+ * build output and directories that are not the product. Deeper than that is
391
+ * a guess.
392
+ */
393
+ function detectPlatforms(root) {
394
+ const found = new Set();
395
+ const visit = (dir, depth) => {
396
+ const s = signals(dir);
397
+ for (const p of s.found) found.add(p);
398
+ if (depth === 0) return;
399
+ for (const name of s.names) {
400
+ if (name.startsWith(".") || s.skip.has(name)) continue;
401
+ if (SKIP_DIRS.has(name) || NOT_APPS.has(name.toLowerCase())) continue;
402
+ const child = path.join(dir, name);
403
+ let isDir = false;
404
+ try {
405
+ isDir = fs.statSync(child).isDirectory();
406
+ } catch {
407
+ // A dangling link or a permission error: not a directory to scan.
408
+ }
409
+ if (!isDir) continue;
410
+ visit(child, depth - 1);
411
+ }
412
+ };
413
+ visit(root, 2);
414
+ return PLATFORMS.filter((p) => found.has(p));
415
+ }
416
+
417
+ // ── config.yml ─────────────────────────────────────────────────────────────
418
+
419
+ /** The `project:` block's line range in config.yml text: [start, end). */
420
+ function projectBlock(lines) {
421
+ const start = lines.findIndex((l) => /^project:\s*(#.*)?$/.test(l));
422
+ if (start === -1) return null;
423
+ let end = start + 1;
424
+ while (end < lines.length && !/^[A-Za-z_]/.test(lines[end])) end++;
425
+ return [start, end];
426
+ }
427
+
428
+ /** `project.platforms` from config.yml text — flow or block form. */
429
+ function readConfigPlatforms(text) {
430
+ const lines = String(text).split("\n");
431
+ const block = projectBlock(lines);
432
+ if (!block) {
433
+ // `project: { platforms: [ios] }` — the merge rewrites it as a block, so
434
+ // it has to be read here or the user's list is lost to detection.
435
+ const inline = lines
436
+ .map((l) => /^project:\s*\{.*\bplatforms:\s*(\[[^\]]*\])/.exec(l))
437
+ .find(Boolean);
438
+ return inline ? parsePlatforms(inline[1]) : [];
439
+ }
440
+ for (let i = block[0] + 1; i < block[1]; i++) {
441
+ const m = /^\s+platforms:\s*([^#]*)/.exec(lines[i]);
442
+ if (!m) continue;
443
+ let flow = m[1].trim();
444
+ // A flow list may run over several lines: `[` here, `]` further down.
445
+ for (let j = i + 1; flow.startsWith("[") && !flow.includes("]") && j < block[1]; j++) {
446
+ flow += ` ${lines[j].replace(/#.*$/, "").trim()}`;
447
+ }
448
+ if (flow) return parsePlatforms(flow);
449
+ const items = [];
450
+ for (let j = i + 1; j < block[1]; j++) {
451
+ const item = /^\s+-\s*([^#\s]+)/.exec(lines[j]);
452
+ if (item) items.push(item[1]);
453
+ else if (lines[j].trim() && !lines[j].trim().startsWith("#")) break;
454
+ }
455
+ return parsePlatforms(items);
456
+ }
457
+ return [];
458
+ }
459
+
460
+ /**
461
+ * config.yml text with `project.platforms` set to `list`, in flow form, or
462
+ * null when `project:` is written in a shape this cannot edit safely (an
463
+ * inline map) — adding a second `project:` key would make the file invalid.
464
+ */
465
+ function writeConfigPlatforms(text, list) {
466
+ const lines = String(text).split("\n");
467
+ const value = ` platforms: [${list.join(", ")}]`;
468
+ const block = projectBlock(lines);
469
+ if (!block) {
470
+ if (lines.some((l) => /^project:/.test(l))) return null;
471
+ return [`project:`, value, "", ...lines].join("\n");
472
+ }
473
+ for (let i = block[0] + 1; i < block[1]; i++) {
474
+ if (!/^\s+platforms:/.test(lines[i])) continue;
475
+ const indent = /^\s*/.exec(lines[i])[0];
476
+ const comment = /\s+#.*$/.exec(lines[i].replace(/^[^[]*\[[^\]]*\]/, ""))?.[0] ?? "";
477
+ let end = i + 1;
478
+ if (/platforms:\s*\[[^\]]*$/.test(lines[i])) {
479
+ while (end < block[1] && !lines[end - 1].includes("]")) end++;
480
+ }
481
+ // A block list, comment lines between its items included.
482
+ if (/platforms:\s*(#.*)?$/.test(lines[i])) {
483
+ let last = end - 1;
484
+ for (let j = end; j < block[1]; j++) {
485
+ if (/^\s+-\s/.test(lines[j])) last = j;
486
+ else if (!/^\s*(#.*)?$/.test(lines[j])) break;
487
+ }
488
+ end = last + 1;
489
+ }
490
+ lines.splice(i, end - i, `${indent}platforms: [${list.join(", ")}]${comment}`);
491
+ return lines.join("\n");
492
+ }
493
+ lines.splice(block[0] + 1, 0, value);
494
+ return lines.join("\n");
495
+ }
496
+
497
+ module.exports = {
498
+ PLATFORMS,
499
+ SKILLS,
500
+ STACKS,
501
+ parsePlatforms,
502
+ tagsFor,
503
+ selected,
504
+ phaseSkills,
505
+ takePlatformsArg,
506
+ filterSections,
507
+ detectPlatforms,
508
+ readConfigPlatforms,
509
+ writeConfigPlatforms,
510
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentic-team",
3
- "version": "6.1.0",
3
+ "version": "6.2.0",
4
4
  "description": "AI Team Orchestration System — multi-role coordination for Claude Code",
5
5
  "engines": {
6
6
  "node": ">=22"
@@ -22,11 +22,11 @@
22
22
  ],
23
23
  "repository": {
24
24
  "type": "git",
25
- "url": "https://github.com/sulhadin/orchestrator.git"
25
+ "url": "https://github.com/sulhadin/agentic-team.git"
26
26
  },
27
- "homepage": "https://github.com/sulhadin/orchestrator/blob/main/docs/README.md",
27
+ "homepage": "https://github.com/sulhadin/agentic-team/blob/main/docs/README.md",
28
28
  "bugs": {
29
- "url": "https://github.com/sulhadin/orchestrator/issues"
29
+ "url": "https://github.com/sulhadin/agentic-team/issues"
30
30
  },
31
31
  "author": "Sulhadin Öney",
32
32
  "license": "MIT",
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "orchestra",
3
3
  "description": "AI Team Orchestration — multi-role coordination with milestones, phases, and quality gates for Claude Code",
4
- "version": "6.1.0",
4
+ "version": "6.2.0",
5
5
  "author": {
6
6
  "name": "Sulhadin Öney"
7
7
  },
8
- "repository": "https://github.com/sulhadin/orchestrator",
8
+ "repository": "https://github.com/sulhadin/agentic-team",
9
9
  "license": "MIT"
10
10
  }