crewly 1.11.6 → 1.12.1
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/config/skills/agent/onboarding/synthesize-hierarchy/SKILL.md +65 -0
- package/config/skills/agent/onboarding/synthesize-hierarchy/execute.sh +61 -0
- package/config/skills/agent/web-search/SKILL.md +70 -0
- package/config/skills/agent/web-search/execute.sh +170 -0
- package/config/skills/agent/web-search/skill.json +23 -0
- package/dist/backend/backend/src/constants.d.ts +12 -0
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +12 -0
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/cloud/cloud.controller.d.ts +22 -0
- package/dist/backend/backend/src/controllers/cloud/cloud.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/cloud/cloud.controller.js +58 -0
- package/dist/backend/backend/src/controllers/cloud/cloud.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/cloud/cloud.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/cloud/cloud.routes.js +3 -1
- package/dist/backend/backend/src/controllers/cloud/cloud.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/orchestrator-onboarding/orchestrator-onboarding.controller.d.ts +27 -0
- package/dist/backend/backend/src/controllers/orchestrator-onboarding/orchestrator-onboarding.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/orchestrator-onboarding/orchestrator-onboarding.controller.js +108 -0
- package/dist/backend/backend/src/controllers/orchestrator-onboarding/orchestrator-onboarding.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/orchestrator-onboarding/orchestrator-onboarding.routes.d.ts +6 -2
- package/dist/backend/backend/src/controllers/orchestrator-onboarding/orchestrator-onboarding.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/orchestrator-onboarding/orchestrator-onboarding.routes.js +9 -3
- package/dist/backend/backend/src/controllers/orchestrator-onboarding/orchestrator-onboarding.routes.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +36 -2
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-external-runtime.service.d.ts +18 -0
- package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-external-runtime.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-external-runtime.service.js +24 -2
- package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-external-runtime.service.js.map +1 -1
- package/dist/backend/backend/src/services/cloud/mobile-api-relay.service.d.ts +102 -0
- package/dist/backend/backend/src/services/cloud/mobile-api-relay.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/cloud/mobile-api-relay.service.js +167 -0
- package/dist/backend/backend/src/services/cloud/mobile-api-relay.service.js.map +1 -0
- package/dist/backend/backend/src/services/fission/fission-guard.service.d.ts +21 -0
- package/dist/backend/backend/src/services/fission/fission-guard.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/fission/fission-guard.service.js +30 -0
- package/dist/backend/backend/src/services/fission/fission-guard.service.js.map +1 -1
- package/dist/backend/backend/src/services/intent-task/intent-classifier.rules.d.ts +4 -0
- package/dist/backend/backend/src/services/intent-task/intent-classifier.rules.d.ts.map +1 -1
- package/dist/backend/backend/src/services/intent-task/intent-classifier.rules.js +8 -0
- package/dist/backend/backend/src/services/intent-task/intent-classifier.rules.js.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/onboarding/materialize-team.d.ts +79 -58
- package/dist/backend/backend/src/services/orchestrator/onboarding/materialize-team.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/onboarding/materialize-team.js +140 -65
- package/dist/backend/backend/src/services/orchestrator/onboarding/materialize-team.js.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/onboarding/synthesize-hierarchy.d.ts +117 -0
- package/dist/backend/backend/src/services/orchestrator/onboarding/synthesize-hierarchy.d.ts.map +1 -0
- package/dist/backend/backend/src/services/orchestrator/onboarding/synthesize-hierarchy.js +189 -0
- package/dist/backend/backend/src/services/orchestrator/onboarding/synthesize-hierarchy.js.map +1 -0
- package/dist/backend/backend/src/services/orchestrator/onboarding-mode-loader.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/onboarding-mode-loader.js +1 -0
- package/dist/backend/backend/src/services/orchestrator/onboarding-mode-loader.js.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/onboarding-mode.skill-allowlist.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/onboarding-mode.skill-allowlist.js +2 -0
- package/dist/backend/backend/src/services/orchestrator/onboarding-mode.skill-allowlist.js.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/prompts/onboarding-mode.prompt.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/prompts/onboarding-mode.prompt.js +17 -1
- package/dist/backend/backend/src/services/orchestrator/prompts/onboarding-mode.prompt.js.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconcile-rules.d.ts +50 -0
- package/dist/backend/backend/src/services/reconciler/reconcile-rules.d.ts.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconcile-rules.js +71 -0
- package/dist/backend/backend/src/services/reconciler/reconcile-rules.js.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconciler.service.d.ts +18 -0
- package/dist/backend/backend/src/services/reconciler/reconciler.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconciler.service.js +75 -1
- package/dist/backend/backend/src/services/reconciler/reconciler.service.js.map +1 -1
- package/dist/backend/backend/src/services/session/pty/pty-session-backend.d.ts +115 -0
- package/dist/backend/backend/src/services/session/pty/pty-session-backend.d.ts.map +1 -1
- package/dist/backend/backend/src/services/session/pty/pty-session-backend.js +189 -3
- package/dist/backend/backend/src/services/session/pty/pty-session-backend.js.map +1 -1
- package/dist/backend/backend/src/services/session/pty/pty-session.d.ts +28 -0
- package/dist/backend/backend/src/services/session/pty/pty-session.d.ts.map +1 -1
- package/dist/backend/backend/src/services/session/pty/pty-session.js +61 -1
- package/dist/backend/backend/src/services/session/pty/pty-session.js.map +1 -1
- package/dist/backend/backend/src/services/template/template.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/template/template.service.js +67 -2
- package/dist/backend/backend/src/services/template/template.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/cascade-request-status.d.ts +19 -1
- package/dist/backend/backend/src/services/v3/cascade-request-status.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/cascade-request-status.js +39 -2
- package/dist/backend/backend/src/services/v3/cascade-request-status.js.map +1 -1
- package/dist/backend/backend/src/services/v3/escalation-router.service.d.ts +41 -0
- package/dist/backend/backend/src/services/v3/escalation-router.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/escalation-router.service.js +169 -0
- package/dist/backend/backend/src/services/v3/escalation-router.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/request-cascade.subscriber.d.ts +4 -1
- package/dist/backend/backend/src/services/v3/request-cascade.subscriber.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/request-cascade.subscriber.js +21 -0
- package/dist/backend/backend/src/services/v3/request-cascade.subscriber.js.map +1 -1
- package/dist/backend/backend/src/types/intent-task.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/intent-task.types.js +8 -0
- package/dist/backend/backend/src/types/intent-task.types.js.map +1 -1
- package/dist/backend/backend/src/types/v2/request.types.d.ts +1 -1
- package/dist/backend/backend/src/types/v2/request.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/v2/request.types.js +1 -0
- package/dist/backend/backend/src/types/v2/request.types.js.map +1 -1
- package/dist/cli/backend/src/constants.d.ts +12 -0
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +12 -0
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/package.json +9 -3
- package/packages/crewly-agent/README.md +27 -0
- package/packages/crewly-agent/bin/crewly-agent +33 -0
- package/packages/crewly-agent/package.json +39 -0
- package/packages/crewly-agent/src/cli.ts +168 -0
- package/packages/crewly-agent/src/runtime/agent-runner.service.test.ts +2355 -0
- package/packages/crewly-agent/src/runtime/agent-runner.service.ts +1827 -0
- package/packages/crewly-agent/src/runtime/agent-stream.service.test.ts +153 -0
- package/packages/crewly-agent/src/runtime/agent-stream.service.ts +225 -0
- package/packages/crewly-agent/src/runtime/agent-worker.test.ts +171 -0
- package/packages/crewly-agent/src/runtime/agent-worker.ts +193 -0
- package/packages/crewly-agent/src/runtime/api-client.ts +143 -0
- package/packages/crewly-agent/src/runtime/approval-queue.service.ts +307 -0
- package/packages/crewly-agent/src/runtime/audit-log.service.test.ts +208 -0
- package/packages/crewly-agent/src/runtime/audit-log.service.ts +332 -0
- package/packages/crewly-agent/src/runtime/audit-trail.service.test.ts +178 -0
- package/packages/crewly-agent/src/runtime/audit-trail.service.ts +151 -0
- package/packages/crewly-agent/src/runtime/auditor-tools.test.ts +274 -0
- package/packages/crewly-agent/src/runtime/auditor-tools.ts +311 -0
- package/packages/crewly-agent/src/runtime/cloud-config.ts +67 -0
- package/packages/crewly-agent/src/runtime/deepseek-sse-transform.test.ts +165 -0
- package/packages/crewly-agent/src/runtime/deepseek-sse-transform.ts +168 -0
- package/packages/crewly-agent/src/runtime/env-isolation.service.ts +246 -0
- package/packages/crewly-agent/src/runtime/in-process-log-buffer.test.ts +280 -0
- package/packages/crewly-agent/src/runtime/in-process-log-buffer.ts +317 -0
- package/packages/crewly-agent/src/runtime/index.ts +38 -0
- package/packages/crewly-agent/src/runtime/mcp-tool-bridge.test.ts +352 -0
- package/packages/crewly-agent/src/runtime/mcp-tool-bridge.ts +244 -0
- package/packages/crewly-agent/src/runtime/model-manager.test.ts +326 -0
- package/packages/crewly-agent/src/runtime/model-manager.ts +363 -0
- package/packages/crewly-agent/src/runtime/output-filter.service.ts +175 -0
- package/packages/crewly-agent/src/runtime/prompt-guard.service.ts +303 -0
- package/packages/crewly-agent/src/runtime/rate-limiter.test.ts +228 -0
- package/packages/crewly-agent/src/runtime/rate-limiter.ts +353 -0
- package/packages/crewly-agent/src/runtime/tool-registry.test.ts +2510 -0
- package/packages/crewly-agent/src/runtime/tool-registry.ts +2104 -0
- package/packages/crewly-agent/src/runtime/types.test.ts +519 -0
- package/packages/crewly-agent/src/runtime/types.ts +637 -0
- package/packages/crewly-agent/src/runtime/web-search.tool.test.ts +131 -0
- package/packages/crewly-agent/src/runtime/web-search.tool.ts +140 -0
|
@@ -1,108 +1,129 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Materialize-Team Logic (Onboarding v3
|
|
2
|
+
* Materialize-Team Logic (Onboarding v3)
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* (template-engine wiring, agent-soul generation, system-prompt
|
|
7
|
-
* personalisation) lands Wed–Fri — Sam's brief explicitly says a
|
|
8
|
-
* "logs + flips flag" stub is acceptable for the Mon 5/4 EOD demo.
|
|
4
|
+
* Turns a confirmed {@link TeamRecommendation} into a REAL, persisted team
|
|
5
|
+
* that the rest of the system can run hands-off:
|
|
9
6
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
7
|
+
* 1. Provision a live, template-backed team via the proven
|
|
8
|
+
* `TemplateService.createTeamFromTemplate` + `StorageService.saveTeam`
|
|
9
|
+
* path — the same path `onboarding-provision.service.ts` uses. The
|
|
10
|
+
* created members carry real system prompts, skill sets, hierarchy
|
|
11
|
+
* (`hierarchyLevel` / `parentMemberId`) and `canDelegate` flags from the
|
|
12
|
+
* template, so the orchestrator can immediately delegate into the team
|
|
13
|
+
* and the agents auto-activate on first claim.
|
|
14
|
+
* 2. Flip the project `onboardingComplete` flag.
|
|
14
15
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* `
|
|
18
|
-
*
|
|
19
|
-
*
|
|
16
|
+
* Fallback: if the recommendation's `templateId` is not a registered template
|
|
17
|
+
* (or provisioning throws — e.g. a tier-gated template on OSS), we write the
|
|
18
|
+
* legacy minimal `config.json` stub so the orc never dead-ends. That stub has
|
|
19
|
+
* inactive members with empty prompts and is clearly marked `provisioned:false`
|
|
20
|
+
* so callers can warn the user that a generic team was created.
|
|
21
|
+
*
|
|
22
|
+
* History: this was a "Mon EOD v0 stub" that only wrote a dead config and
|
|
23
|
+
* flipped a flag (members `agentStatus:'inactive'`, empty `systemPrompt`),
|
|
24
|
+
* which meant every new-team goal required a human to actually stand up
|
|
25
|
+
* agents. P0 of the autonomy roadmap wires it to real provisioning.
|
|
26
|
+
*
|
|
27
|
+
* The function stays injection-friendly: callers pass `teamsDir`,
|
|
28
|
+
* `projectFlagPath`, a UUID generator, a clock, and (for tests) a
|
|
29
|
+
* `provisionTeam` implementation — so unit tests run against tmp dirs with
|
|
30
|
+
* deterministic IDs and a fake provisioner, never touching the real
|
|
31
|
+
* `~/.crewly` tree or the singletons.
|
|
20
32
|
*
|
|
21
33
|
* @module services/orchestrator/onboarding/materialize-team
|
|
22
34
|
*/
|
|
23
35
|
import type { TeamRecommendation } from './recommend-team.js';
|
|
36
|
+
/** A live team produced by {@link MaterializeOptions.provisionTeam}. */
|
|
37
|
+
export interface ProvisionedTeam {
|
|
38
|
+
/** Persisted team id (from StorageService). */
|
|
39
|
+
readonly teamId: string;
|
|
40
|
+
/** Number of members created from the template. */
|
|
41
|
+
readonly memberCount: number;
|
|
42
|
+
}
|
|
24
43
|
/**
|
|
25
44
|
* Side-effects the materialize step needs. Injected so tests can run
|
|
26
|
-
* against a tmp dir without touching the real
|
|
45
|
+
* against a tmp dir + a fake provisioner without touching the real
|
|
46
|
+
* `~/.crewly` tree or the TemplateService/StorageService singletons.
|
|
27
47
|
*/
|
|
28
48
|
export interface MaterializeOptions {
|
|
29
|
-
/** Root teams directory (e.g. `~/.crewly/teams`). */
|
|
49
|
+
/** Root teams directory for the FALLBACK stub write (e.g. `~/.crewly/teams`). */
|
|
30
50
|
readonly teamsDir: string;
|
|
31
51
|
/** File path for the project onboarding-complete flag. */
|
|
32
52
|
readonly projectFlagPath: string;
|
|
33
|
-
/** UUID generator — defaults to {@link crypto.randomUUID}
|
|
53
|
+
/** UUID generator (fallback stub only) — defaults to {@link crypto.randomUUID}. */
|
|
34
54
|
readonly uuid?: () => string;
|
|
35
55
|
/** Clock — defaults to `() => new Date()` when omitted. */
|
|
36
56
|
readonly now?: () => Date;
|
|
57
|
+
/** Optional logger sink — receives the materialize log lines. */
|
|
58
|
+
readonly log?: (message: string) => void;
|
|
59
|
+
/** Owner principal to attribute the created team to (multi-tenant). */
|
|
60
|
+
readonly ownerUserId?: string;
|
|
37
61
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
62
|
+
* Parent team id, set when this team is a CHILD in a nested hierarchy (P3).
|
|
63
|
+
* Links the created team to its parent so the parent TL coordinates it.
|
|
64
|
+
* Undefined for a standalone or top-level team.
|
|
40
65
|
*/
|
|
41
|
-
readonly
|
|
66
|
+
readonly parentTeamId?: string;
|
|
67
|
+
/**
|
|
68
|
+
* Team provisioner. Defaults to {@link defaultProvisionTeam}, which creates
|
|
69
|
+
* a live, persisted, template-backed team. Returns `null` when the
|
|
70
|
+
* recommendation's `templateId` is not a registered template, signalling the
|
|
71
|
+
* caller to fall back to a minimal stub. Tests inject a fake.
|
|
72
|
+
*/
|
|
73
|
+
readonly provisionTeam?: (recommendation: TeamRecommendation, teamName: string, ownerUserId: string | undefined, parentTeamId: string | undefined) => Promise<ProvisionedTeam | null>;
|
|
42
74
|
}
|
|
43
75
|
/**
|
|
44
76
|
* Outcome of a successful materialize call.
|
|
45
77
|
*/
|
|
46
78
|
export interface MaterializeResult {
|
|
47
|
-
/**
|
|
79
|
+
/** Team ID — the persisted team id (live path) or the generated id (fallback). */
|
|
48
80
|
readonly teamId: string;
|
|
49
|
-
/** Absolute path to the team's `config.json`. */
|
|
50
|
-
readonly teamConfigPath: string;
|
|
51
81
|
/**
|
|
52
|
-
*
|
|
53
|
-
*
|
|
82
|
+
* Absolute path to the team's fallback `config.json`. Empty string on the
|
|
83
|
+
* live path (the team is persisted via StorageService, not a flat file).
|
|
54
84
|
*/
|
|
85
|
+
readonly teamConfigPath: string;
|
|
86
|
+
/** Always `true` for a successful call — mirrors "flips `onboardingComplete = true`". */
|
|
55
87
|
readonly onboardingComplete: true;
|
|
56
|
-
/** Echo of the recommendation that was materialized (for orc to summarise back
|
|
88
|
+
/** Echo of the recommendation that was materialized (for the orc to summarise back). */
|
|
57
89
|
readonly recommendation: TeamRecommendation;
|
|
90
|
+
/** Where the project flag was persisted. */
|
|
91
|
+
readonly projectFlagPath: string;
|
|
92
|
+
/** Number of members on the created team. */
|
|
93
|
+
readonly memberCount: number;
|
|
58
94
|
/**
|
|
59
|
-
*
|
|
60
|
-
*
|
|
95
|
+
* `true` when a live, template-backed team was provisioned (real agents,
|
|
96
|
+
* prompts, hierarchy). `false` when provisioning was unavailable and a
|
|
97
|
+
* minimal stub config was written instead — the orc should tell the user a
|
|
98
|
+
* generic team was created and offer to refine it.
|
|
61
99
|
*/
|
|
62
|
-
readonly
|
|
100
|
+
readonly provisioned: boolean;
|
|
63
101
|
}
|
|
64
102
|
/**
|
|
65
|
-
* Materialize a {@link TeamRecommendation} into a team
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* v0 (Mon 5/4 EOD) writes a minimal config:
|
|
69
|
-
* ```json
|
|
70
|
-
* {
|
|
71
|
-
* "id": "<uuid>",
|
|
72
|
-
* "name": "<recommendation.templateId> Team",
|
|
73
|
-
* "createdAt": "...",
|
|
74
|
-
* "createdBy": "onboarding-v3",
|
|
75
|
-
* "templateId": "...",
|
|
76
|
-
* "members": [ ... ]
|
|
77
|
-
* }
|
|
78
|
-
* ```
|
|
79
|
-
* No agent-soul personalisation, no project linkage, no goals.md
|
|
80
|
-
* generation — those land Wed–Fri when this calls into
|
|
81
|
-
* `onboarding-provision.service.ts`.
|
|
103
|
+
* Materialize a {@link TeamRecommendation} into a REAL team + project
|
|
104
|
+
* onboarding-complete flag.
|
|
82
105
|
*
|
|
83
106
|
* @param recommendation - Output of {@link recommendTeam} that the user confirmed.
|
|
84
|
-
* @param opts - Side-effect injection (teamsDir, projectFlagPath,
|
|
85
|
-
* @returns The team ID +
|
|
86
|
-
* @throws If the
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
* silently.
|
|
107
|
+
* @param opts - Side-effect injection (teamsDir, projectFlagPath, provisionTeam, …).
|
|
108
|
+
* @returns The team ID + member count + provisioned flag + flag-path on success.
|
|
109
|
+
* @throws If BOTH provisioning fails AND the fallback config write fails
|
|
110
|
+
* (filesystem error). Caller surfaces a brief honest error rather than
|
|
111
|
+
* retrying silently.
|
|
90
112
|
*
|
|
91
113
|
* @example
|
|
92
114
|
* ```ts
|
|
93
115
|
* import { getCrewlyHomePath } from '../../core/crewly-home.utils.js';
|
|
94
116
|
*
|
|
95
|
-
* const crewlyHome = getCrewlyHomePath();
|
|
117
|
+
* const crewlyHome = getCrewlyHomePath();
|
|
96
118
|
* const result = await materializeTeam(rec, {
|
|
97
119
|
* teamsDir: path.join(crewlyHome, 'teams'),
|
|
98
120
|
* projectFlagPath: path.join(crewlyHome, 'onboarding-complete.json'),
|
|
99
121
|
* });
|
|
100
|
-
*
|
|
122
|
+
* // result.provisioned === true → live team `result.teamId` with `result.memberCount` agents
|
|
101
123
|
* ```
|
|
102
124
|
*
|
|
103
|
-
* Do NOT inline `path.join(os.homedir(), '.crewly/teams')` — that
|
|
104
|
-
*
|
|
105
|
-
* (see crewly-home.utils.ts for context).
|
|
125
|
+
* Do NOT inline `path.join(os.homedir(), '.crewly/teams')` — that ignores
|
|
126
|
+
* CREWLY_HOME and breaks ESTestNode + dry-run-kit isolation.
|
|
106
127
|
*/
|
|
107
128
|
export declare function materializeTeam(recommendation: TeamRecommendation, opts: MaterializeOptions): Promise<MaterializeResult>;
|
|
108
129
|
//# sourceMappingURL=materialize-team.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"materialize-team.d.ts","sourceRoot":"","sources":["../../../../../../../backend/src/services/orchestrator/onboarding/materialize-team.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"materialize-team.d.ts","sourceRoot":"","sources":["../../../../../../../backend/src/services/orchestrator/onboarding/materialize-team.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAKH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAM9D,wEAAwE;AACxE,MAAM,WAAW,eAAe;IAC9B,+CAA+C;IAC/C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,mDAAmD;IACnD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,iFAAiF;IACjF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,0DAA0D;IAC1D,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,mFAAmF;IACnF,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,MAAM,CAAC;IAC7B,2DAA2D;IAC3D,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,iEAAiE;IACjE,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,uEAAuE;IACvE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,CACvB,cAAc,EAAE,kBAAkB,EAClC,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,YAAY,EAAE,MAAM,GAAG,SAAS,KAC7B,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;CACtC;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,kFAAkF;IAClF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,yFAAyF;IACzF,QAAQ,CAAC,kBAAkB,EAAE,IAAI,CAAC;IAClC,wFAAwF;IACxF,QAAQ,CAAC,cAAc,EAAE,kBAAkB,CAAC;IAC5C,4CAA4C;IAC5C,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,6CAA6C;IAC7C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;CAC/B;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,eAAe,CACnC,cAAc,EAAE,kBAAkB,EAClC,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,iBAAiB,CAAC,CAsE5B"}
|
|
@@ -1,22 +1,34 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Materialize-Team Logic (Onboarding v3
|
|
2
|
+
* Materialize-Team Logic (Onboarding v3)
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* (template-engine wiring, agent-soul generation, system-prompt
|
|
7
|
-
* personalisation) lands Wed–Fri — Sam's brief explicitly says a
|
|
8
|
-
* "logs + flips flag" stub is acceptable for the Mon 5/4 EOD demo.
|
|
4
|
+
* Turns a confirmed {@link TeamRecommendation} into a REAL, persisted team
|
|
5
|
+
* that the rest of the system can run hands-off:
|
|
9
6
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
7
|
+
* 1. Provision a live, template-backed team via the proven
|
|
8
|
+
* `TemplateService.createTeamFromTemplate` + `StorageService.saveTeam`
|
|
9
|
+
* path — the same path `onboarding-provision.service.ts` uses. The
|
|
10
|
+
* created members carry real system prompts, skill sets, hierarchy
|
|
11
|
+
* (`hierarchyLevel` / `parentMemberId`) and `canDelegate` flags from the
|
|
12
|
+
* template, so the orchestrator can immediately delegate into the team
|
|
13
|
+
* and the agents auto-activate on first claim.
|
|
14
|
+
* 2. Flip the project `onboardingComplete` flag.
|
|
14
15
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* `
|
|
18
|
-
*
|
|
19
|
-
*
|
|
16
|
+
* Fallback: if the recommendation's `templateId` is not a registered template
|
|
17
|
+
* (or provisioning throws — e.g. a tier-gated template on OSS), we write the
|
|
18
|
+
* legacy minimal `config.json` stub so the orc never dead-ends. That stub has
|
|
19
|
+
* inactive members with empty prompts and is clearly marked `provisioned:false`
|
|
20
|
+
* so callers can warn the user that a generic team was created.
|
|
21
|
+
*
|
|
22
|
+
* History: this was a "Mon EOD v0 stub" that only wrote a dead config and
|
|
23
|
+
* flipped a flag (members `agentStatus:'inactive'`, empty `systemPrompt`),
|
|
24
|
+
* which meant every new-team goal required a human to actually stand up
|
|
25
|
+
* agents. P0 of the autonomy roadmap wires it to real provisioning.
|
|
26
|
+
*
|
|
27
|
+
* The function stays injection-friendly: callers pass `teamsDir`,
|
|
28
|
+
* `projectFlagPath`, a UUID generator, a clock, and (for tests) a
|
|
29
|
+
* `provisionTeam` implementation — so unit tests run against tmp dirs with
|
|
30
|
+
* deterministic IDs and a fake provisioner, never touching the real
|
|
31
|
+
* `~/.crewly` tree or the singletons.
|
|
20
32
|
*
|
|
21
33
|
* @module services/orchestrator/onboarding/materialize-team
|
|
22
34
|
*/
|
|
@@ -26,63 +38,76 @@ import * as path from 'node:path';
|
|
|
26
38
|
// Public API
|
|
27
39
|
// =============================================================================
|
|
28
40
|
/**
|
|
29
|
-
* Materialize a {@link TeamRecommendation} into a team
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* v0 (Mon 5/4 EOD) writes a minimal config:
|
|
33
|
-
* ```json
|
|
34
|
-
* {
|
|
35
|
-
* "id": "<uuid>",
|
|
36
|
-
* "name": "<recommendation.templateId> Team",
|
|
37
|
-
* "createdAt": "...",
|
|
38
|
-
* "createdBy": "onboarding-v3",
|
|
39
|
-
* "templateId": "...",
|
|
40
|
-
* "members": [ ... ]
|
|
41
|
-
* }
|
|
42
|
-
* ```
|
|
43
|
-
* No agent-soul personalisation, no project linkage, no goals.md
|
|
44
|
-
* generation — those land Wed–Fri when this calls into
|
|
45
|
-
* `onboarding-provision.service.ts`.
|
|
41
|
+
* Materialize a {@link TeamRecommendation} into a REAL team + project
|
|
42
|
+
* onboarding-complete flag.
|
|
46
43
|
*
|
|
47
44
|
* @param recommendation - Output of {@link recommendTeam} that the user confirmed.
|
|
48
|
-
* @param opts - Side-effect injection (teamsDir, projectFlagPath,
|
|
49
|
-
* @returns The team ID +
|
|
50
|
-
* @throws If the
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
* silently.
|
|
45
|
+
* @param opts - Side-effect injection (teamsDir, projectFlagPath, provisionTeam, …).
|
|
46
|
+
* @returns The team ID + member count + provisioned flag + flag-path on success.
|
|
47
|
+
* @throws If BOTH provisioning fails AND the fallback config write fails
|
|
48
|
+
* (filesystem error). Caller surfaces a brief honest error rather than
|
|
49
|
+
* retrying silently.
|
|
54
50
|
*
|
|
55
51
|
* @example
|
|
56
52
|
* ```ts
|
|
57
53
|
* import { getCrewlyHomePath } from '../../core/crewly-home.utils.js';
|
|
58
54
|
*
|
|
59
|
-
* const crewlyHome = getCrewlyHomePath();
|
|
55
|
+
* const crewlyHome = getCrewlyHomePath();
|
|
60
56
|
* const result = await materializeTeam(rec, {
|
|
61
57
|
* teamsDir: path.join(crewlyHome, 'teams'),
|
|
62
58
|
* projectFlagPath: path.join(crewlyHome, 'onboarding-complete.json'),
|
|
63
59
|
* });
|
|
64
|
-
*
|
|
60
|
+
* // result.provisioned === true → live team `result.teamId` with `result.memberCount` agents
|
|
65
61
|
* ```
|
|
66
62
|
*
|
|
67
|
-
* Do NOT inline `path.join(os.homedir(), '.crewly/teams')` — that
|
|
68
|
-
*
|
|
69
|
-
* (see crewly-home.utils.ts for context).
|
|
63
|
+
* Do NOT inline `path.join(os.homedir(), '.crewly/teams')` — that ignores
|
|
64
|
+
* CREWLY_HOME and breaks ESTestNode + dry-run-kit isolation.
|
|
70
65
|
*/
|
|
71
66
|
export async function materializeTeam(recommendation, opts) {
|
|
72
|
-
const uuid = opts.uuid ?? defaultUuid;
|
|
73
67
|
const now = opts.now ?? defaultNow;
|
|
74
68
|
const log = opts.log ?? noopLog;
|
|
75
|
-
const
|
|
76
|
-
const teamDir = path.join(opts.teamsDir, teamId);
|
|
77
|
-
const teamConfigPath = path.join(teamDir, 'config.json');
|
|
69
|
+
const provisionTeam = opts.provisionTeam ?? defaultProvisionTeam;
|
|
78
70
|
const createdAt = now().toISOString();
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
71
|
+
const teamName = humanizeTemplateName(recommendation.templateId);
|
|
72
|
+
log(`[materialize-team] materializing template "${recommendation.templateId}" (${recommendation.agents.length} recommended agents)`);
|
|
73
|
+
// 1. Provision a live, persisted, template-backed team when possible.
|
|
74
|
+
let teamId;
|
|
75
|
+
let memberCount;
|
|
76
|
+
let teamConfigPath = '';
|
|
77
|
+
let provisioned;
|
|
78
|
+
let live = null;
|
|
79
|
+
try {
|
|
80
|
+
live = await provisionTeam(recommendation, teamName, opts.ownerUserId, opts.parentTeamId);
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
// Tier-gated template, missing registry, or storage error — don't dead-end
|
|
84
|
+
// the orc; drop to the minimal fallback with a warning.
|
|
85
|
+
log(`[materialize-team] WARN live provisioning failed for template "${recommendation.templateId}" ` +
|
|
86
|
+
`(${err instanceof Error ? err.message : String(err)}) — falling back to a minimal team`);
|
|
87
|
+
}
|
|
88
|
+
if (live) {
|
|
89
|
+
teamId = live.teamId;
|
|
90
|
+
memberCount = live.memberCount;
|
|
91
|
+
provisioned = true;
|
|
92
|
+
log(`[materialize-team] provisioned LIVE team id=${teamId} (${memberCount} members) from template "${recommendation.templateId}"`);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
// Fallback: template not registered / provisioning unavailable. Write a
|
|
96
|
+
// minimal stub config so the orc still has a team to talk about.
|
|
97
|
+
const uuid = opts.uuid ?? defaultUuid;
|
|
98
|
+
teamId = uuid();
|
|
99
|
+
const teamDir = path.join(opts.teamsDir, teamId);
|
|
100
|
+
teamConfigPath = path.join(teamDir, 'config.json');
|
|
101
|
+
const config = buildTeamConfig(recommendation, teamId, createdAt);
|
|
102
|
+
memberCount = recommendation.agents.length;
|
|
103
|
+
provisioned = false;
|
|
104
|
+
await fs.mkdir(teamDir, { recursive: true });
|
|
105
|
+
await fs.writeFile(teamConfigPath, JSON.stringify(config, null, 2) + '\n', 'utf8');
|
|
106
|
+
log(`[materialize-team] wrote MINIMAL fallback config id=${teamId} ` +
|
|
107
|
+
`(template "${recommendation.templateId}" not provisionable)`);
|
|
108
|
+
}
|
|
84
109
|
// 2. Flip the project onboarding-complete flag.
|
|
85
|
-
const flag = { onboardingComplete: true, completedAt: createdAt };
|
|
110
|
+
const flag = { onboardingComplete: true, completedAt: createdAt, teamId };
|
|
86
111
|
await fs.mkdir(path.dirname(opts.projectFlagPath), { recursive: true });
|
|
87
112
|
await fs.writeFile(opts.projectFlagPath, JSON.stringify(flag, null, 2) + '\n', 'utf8');
|
|
88
113
|
log(`[materialize-team] flipped onboardingComplete = true at ${opts.projectFlagPath}`);
|
|
@@ -92,14 +117,54 @@ export async function materializeTeam(recommendation, opts) {
|
|
|
92
117
|
onboardingComplete: true,
|
|
93
118
|
recommendation,
|
|
94
119
|
projectFlagPath: opts.projectFlagPath,
|
|
120
|
+
memberCount,
|
|
121
|
+
provisioned,
|
|
95
122
|
};
|
|
96
123
|
}
|
|
97
124
|
// =============================================================================
|
|
98
125
|
// Internals
|
|
99
126
|
// =============================================================================
|
|
100
127
|
/**
|
|
101
|
-
*
|
|
102
|
-
* recommendation's
|
|
128
|
+
* Default team provisioner: create a live, persisted team from the
|
|
129
|
+
* recommendation's template via the same path `onboarding-provision.service.ts`
|
|
130
|
+
* uses. Lazy-imports the singletons so this module stays dependency-light and
|
|
131
|
+
* unit-testable (callers inject a fake `provisionTeam` instead).
|
|
132
|
+
*
|
|
133
|
+
* @param recommendation - The confirmed recommendation (carries `templateId`).
|
|
134
|
+
* @param teamName - Human-readable team name to assign.
|
|
135
|
+
* @param ownerUserId - Owner principal, or undefined for OSS single-user mode.
|
|
136
|
+
* @returns The persisted team id + member count, or `null` when the template
|
|
137
|
+
* is not registered (caller falls back to a minimal stub).
|
|
138
|
+
* @throws Propagates a tier-gating error from `createTeamFromTemplate` (the
|
|
139
|
+
* caller catches it and falls back).
|
|
140
|
+
*/
|
|
141
|
+
async function defaultProvisionTeam(recommendation, teamName, ownerUserId, parentTeamId) {
|
|
142
|
+
const { TemplateService } = await import('../../template/template.service.js');
|
|
143
|
+
const { StorageService } = await import('../../core/storage.service.js');
|
|
144
|
+
const result = TemplateService.getInstance().createTeamFromTemplate(recommendation.templateId, teamName);
|
|
145
|
+
if (!result)
|
|
146
|
+
return null;
|
|
147
|
+
// Attribute to the authenticated principal (multi-tenant). Undefined in OSS
|
|
148
|
+
// single-user mode leaves the team unscoped (legacy behaviour).
|
|
149
|
+
if (ownerUserId !== undefined) {
|
|
150
|
+
result.team.ownerUserId = ownerUserId;
|
|
151
|
+
}
|
|
152
|
+
// Link to the parent team when this is a child in a nested hierarchy (P3).
|
|
153
|
+
if (parentTeamId !== undefined) {
|
|
154
|
+
result.team.parentTeamId = parentTeamId;
|
|
155
|
+
}
|
|
156
|
+
await StorageService.getInstance().saveTeam(result.team);
|
|
157
|
+
return { teamId: result.team.id, memberCount: result.memberCount };
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Build the minimal FALLBACK team config. Members are derived 1:1 from the
|
|
161
|
+
* recommendation's agents list, inactive with empty prompts. Only used when
|
|
162
|
+
* live provisioning is unavailable.
|
|
163
|
+
*
|
|
164
|
+
* @param rec - The recommendation to materialize.
|
|
165
|
+
* @param teamId - The generated team id.
|
|
166
|
+
* @param createdAt - ISO creation timestamp.
|
|
167
|
+
* @returns A plain config object ready to JSON-serialize.
|
|
103
168
|
*/
|
|
104
169
|
function buildTeamConfig(rec, teamId, createdAt) {
|
|
105
170
|
return {
|
|
@@ -124,10 +189,10 @@ function buildTeamConfig(rec, teamId, createdAt) {
|
|
|
124
189
|
}
|
|
125
190
|
/**
|
|
126
191
|
* Convert a kebab-case template id → human team name
|
|
127
|
-
* (`"dtc-viral-content-team"` → `"Dtc Viral Content Team"`).
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
192
|
+
* (`"dtc-viral-content-team"` → `"Dtc Viral Content Team"`).
|
|
193
|
+
*
|
|
194
|
+
* @param templateId - The kebab-case template id.
|
|
195
|
+
* @returns A title-cased, space-separated name.
|
|
131
196
|
*/
|
|
132
197
|
function humanizeTemplateName(templateId) {
|
|
133
198
|
return templateId
|
|
@@ -137,6 +202,9 @@ function humanizeTemplateName(templateId) {
|
|
|
137
202
|
}
|
|
138
203
|
/**
|
|
139
204
|
* Convert a kebab-case role → human display name.
|
|
205
|
+
*
|
|
206
|
+
* @param role - The kebab-case role id.
|
|
207
|
+
* @returns A title-cased, space-separated name.
|
|
140
208
|
*/
|
|
141
209
|
function humanizeRoleName(role) {
|
|
142
210
|
return role
|
|
@@ -145,20 +213,27 @@ function humanizeRoleName(role) {
|
|
|
145
213
|
.join(' ');
|
|
146
214
|
}
|
|
147
215
|
/**
|
|
148
|
-
* Default UUID generator
|
|
149
|
-
*
|
|
216
|
+
* Default UUID generator (fallback stub only).
|
|
217
|
+
*
|
|
218
|
+
* @returns A random UUID string.
|
|
150
219
|
*/
|
|
151
220
|
function defaultUuid() {
|
|
152
|
-
// Lazy require to keep the import surface minimal and avoid loading
|
|
153
|
-
// `node:crypto` at module load.
|
|
154
221
|
const { randomUUID } = require('node:crypto');
|
|
155
222
|
return randomUUID();
|
|
156
223
|
}
|
|
157
|
-
/**
|
|
224
|
+
/**
|
|
225
|
+
* Default clock — wall-clock time.
|
|
226
|
+
*
|
|
227
|
+
* @returns The current Date.
|
|
228
|
+
*/
|
|
158
229
|
function defaultNow() {
|
|
159
230
|
return new Date();
|
|
160
231
|
}
|
|
161
|
-
/**
|
|
232
|
+
/**
|
|
233
|
+
* Default log sink — drops the message on the floor.
|
|
234
|
+
*
|
|
235
|
+
* @param _message - Ignored.
|
|
236
|
+
*/
|
|
162
237
|
function noopLog(_message) {
|
|
163
238
|
/* intentional no-op */
|
|
164
239
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"materialize-team.js","sourceRoot":"","sources":["../../../../../../../backend/src/services/orchestrator/onboarding/materialize-team.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"materialize-team.js","sourceRoot":"","sources":["../../../../../../../backend/src/services/orchestrator/onboarding/materialize-team.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nested sub-team synthesis (Autonomy roadmap P3).
|
|
3
|
+
*
|
|
4
|
+
* When a goal needs PARALLEL work-streams (e.g. "build a SaaS with a frontend,
|
|
5
|
+
* a backend, and DevOps"), a single flat team is the wrong shape — you want a
|
|
6
|
+
* top coordination team whose lead (TL) delegates to per-stream CHILD teams,
|
|
7
|
+
* each with its own TL who decomposes + verifies its slice and reports up.
|
|
8
|
+
* The data model already supports this (`Team.parentTeamId`,
|
|
9
|
+
* `TeamMember.parentMemberId`/`hierarchyLevel`) but nothing DECIDED the shape
|
|
10
|
+
* or instantiated it — complex goals had to be wired by hand.
|
|
11
|
+
*
|
|
12
|
+
* This module adds that decision + instantiation:
|
|
13
|
+
* 1. {@link detectStreams} — heuristically find the parallel streams in a goal.
|
|
14
|
+
* 2. {@link synthesizeHierarchyPlan} — turn them into a parent + child-team
|
|
15
|
+
* plan (or a single flat team when <2 streams), capped by a branching
|
|
16
|
+
* limit aligned with fission-guard's `maxBranchingFactor`.
|
|
17
|
+
* 3. {@link materializeHierarchy} — instantiate the parent then each child via
|
|
18
|
+
* the P0 {@link materializeTeam} path, linking children to the parent.
|
|
19
|
+
*
|
|
20
|
+
* The stream detection is heuristic (v1) — same spirit as the hardcoded
|
|
21
|
+
* `recommendTeam` mappings; a semantic/LLM planner is a later upgrade. The
|
|
22
|
+
* STRUCTURE (parent + linked children, real provisioning) is the deliverable.
|
|
23
|
+
*
|
|
24
|
+
* @module services/orchestrator/onboarding/synthesize-hierarchy
|
|
25
|
+
*/
|
|
26
|
+
import { type BusinessContext, type TeamRecommendation } from './recommend-team.js';
|
|
27
|
+
import { type MaterializeOptions } from './materialize-team.js';
|
|
28
|
+
/**
|
|
29
|
+
* Default cap on child teams in a single hierarchy. Aligned with fission-guard's
|
|
30
|
+
* `maxBranchingFactor` so the synthesized shape never exceeds the runtime's
|
|
31
|
+
* fan-out guardrail.
|
|
32
|
+
*/
|
|
33
|
+
export declare const DEFAULT_MAX_SUBTEAMS = 5;
|
|
34
|
+
/**
|
|
35
|
+
* Detect the parallel work-streams named in a goal context.
|
|
36
|
+
*
|
|
37
|
+
* @param ctx - The business context (goal/industry + tasks).
|
|
38
|
+
* @returns Stream keys (e.g. `['frontend','backend','infra']`) in canonical order.
|
|
39
|
+
*/
|
|
40
|
+
export declare function detectStreams(ctx: BusinessContext): string[];
|
|
41
|
+
/** One child team in a synthesized hierarchy. */
|
|
42
|
+
export interface HierarchyNode {
|
|
43
|
+
/** The stream this child team owns (e.g. `frontend`). */
|
|
44
|
+
readonly stream: string;
|
|
45
|
+
/** The team recommendation for this child. */
|
|
46
|
+
readonly recommendation: TeamRecommendation;
|
|
47
|
+
}
|
|
48
|
+
/** A synthesized team hierarchy: a parent coordination team + child teams. */
|
|
49
|
+
export interface HierarchyPlan {
|
|
50
|
+
/** Top coordination team (its TL delegates to + accepts from the children). */
|
|
51
|
+
readonly parent: TeamRecommendation;
|
|
52
|
+
/** Per-stream child teams. Empty → a single flat team is sufficient. */
|
|
53
|
+
readonly children: readonly HierarchyNode[];
|
|
54
|
+
/** Human-readable rationale for the shape. */
|
|
55
|
+
readonly rationale: string;
|
|
56
|
+
}
|
|
57
|
+
/** Options for {@link synthesizeHierarchyPlan}. */
|
|
58
|
+
export interface SynthesizeOptions {
|
|
59
|
+
/** Max child teams (default {@link DEFAULT_MAX_SUBTEAMS}). */
|
|
60
|
+
readonly maxSubteams?: number;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Synthesize a (possibly nested) team plan for a goal.
|
|
64
|
+
*
|
|
65
|
+
* If fewer than 2 parallel streams are detected, returns a single flat team
|
|
66
|
+
* (no children) — nesting would be overhead. Otherwise returns a parent
|
|
67
|
+
* coordination team plus one child team per detected stream, capped at
|
|
68
|
+
* `maxSubteams`.
|
|
69
|
+
*
|
|
70
|
+
* @param ctx - The goal/business context.
|
|
71
|
+
* @param opts - Synthesis options (branching cap).
|
|
72
|
+
* @returns The hierarchy plan.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```ts
|
|
76
|
+
* const plan = synthesizeHierarchyPlan({
|
|
77
|
+
* industry: 'build a SaaS with a React frontend, a Node API backend, and DevOps',
|
|
78
|
+
* scale: 'small-team',
|
|
79
|
+
* tasks: [],
|
|
80
|
+
* });
|
|
81
|
+
* // plan.children → frontend / backend / infra child teams under a parent
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
export declare function synthesizeHierarchyPlan(ctx: BusinessContext, opts?: SynthesizeOptions): HierarchyPlan;
|
|
85
|
+
/** A child team that was instantiated as part of a hierarchy. */
|
|
86
|
+
export interface MaterializedChild {
|
|
87
|
+
readonly stream: string;
|
|
88
|
+
readonly teamId: string;
|
|
89
|
+
readonly memberCount: number;
|
|
90
|
+
readonly parentTeamId: string;
|
|
91
|
+
readonly provisioned: boolean;
|
|
92
|
+
}
|
|
93
|
+
/** Result of {@link materializeHierarchy}. */
|
|
94
|
+
export interface MaterializedHierarchy {
|
|
95
|
+
readonly parentTeamId: string;
|
|
96
|
+
readonly parentMemberCount: number;
|
|
97
|
+
readonly parentProvisioned: boolean;
|
|
98
|
+
readonly children: readonly MaterializedChild[];
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Instantiate a {@link HierarchyPlan}: materialize the parent team, then each
|
|
102
|
+
* child team linked to the parent via `parentTeamId`. Reuses the P0
|
|
103
|
+
* {@link materializeTeam} path (real, persisted, template-backed teams).
|
|
104
|
+
*
|
|
105
|
+
* The same `opts` (teamsDir, projectFlagPath, ownerUserId, provisionTeam, …)
|
|
106
|
+
* is used for every team; the per-child `parentTeamId` is injected by this
|
|
107
|
+
* function. When the plan has no children, only the parent is created (this is
|
|
108
|
+
* equivalent to a single {@link materializeTeam} call).
|
|
109
|
+
*
|
|
110
|
+
* @param plan - The hierarchy plan from {@link synthesizeHierarchyPlan}.
|
|
111
|
+
* @param opts - Materialize options shared across all teams.
|
|
112
|
+
* @returns The created parent + children team ids with parent links.
|
|
113
|
+
* @throws If the PARENT materialize fails (a child failure is surfaced via its
|
|
114
|
+
* `provisioned` flag, not thrown — partial hierarchies are usable).
|
|
115
|
+
*/
|
|
116
|
+
export declare function materializeHierarchy(plan: HierarchyPlan, opts: MaterializeOptions): Promise<MaterializedHierarchy>;
|
|
117
|
+
//# sourceMappingURL=synthesize-hierarchy.d.ts.map
|
package/dist/backend/backend/src/services/orchestrator/onboarding/synthesize-hierarchy.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"synthesize-hierarchy.d.ts","sourceRoot":"","sources":["../../../../../../../backend/src/services/orchestrator/onboarding/synthesize-hierarchy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,uBAAuB,CAAC;AAM/B;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,IAAI,CAAC;AA8BtC;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,eAAe,GAAG,MAAM,EAAE,CAK5D;AAqBD,iDAAiD;AACjD,MAAM,WAAW,aAAa;IAC5B,yDAAyD;IACzD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,8CAA8C;IAC9C,QAAQ,CAAC,cAAc,EAAE,kBAAkB,CAAC;CAC7C;AAED,8EAA8E;AAC9E,MAAM,WAAW,aAAa;IAC5B,+EAA+E;IAC/E,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;IACpC,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,EAAE,SAAS,aAAa,EAAE,CAAC;IAC5C,8CAA8C;IAC9C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,mDAAmD;AACnD,MAAM,WAAW,iBAAiB;IAChC,8DAA8D;IAC9D,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAeD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,eAAe,EACpB,IAAI,GAAE,iBAAsB,GAC3B,aAAa,CA2Bf;AAMD,iEAAiE;AACjE,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;CAC/B;AAED,8CAA8C;AAC9C,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,CAAC;CACjD;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,qBAAqB,CAAC,CA0BhC"}
|