trackops 1.1.0 → 2.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.
Files changed (51) hide show
  1. package/README.md +194 -230
  2. package/bin/trackops.js +54 -28
  3. package/lib/config.js +14 -10
  4. package/lib/control.js +44 -32
  5. package/lib/env.js +18 -1
  6. package/lib/init.js +40 -6
  7. package/lib/opera-bootstrap.js +825 -273
  8. package/lib/opera.js +360 -110
  9. package/lib/preferences.js +74 -0
  10. package/lib/runtime-state.js +144 -0
  11. package/lib/server.js +155 -25
  12. package/locales/en.json +136 -42
  13. package/locales/es.json +136 -42
  14. package/package.json +2 -1
  15. package/scripts/postinstall-locale.js +21 -0
  16. package/scripts/smoke-tests.js +130 -5
  17. package/scripts/validate-skill.js +2 -1
  18. package/skills/trackops/SKILL.md +57 -32
  19. package/skills/trackops/agents/openai.yaml +1 -1
  20. package/skills/trackops/references/activation.md +50 -16
  21. package/skills/trackops/references/troubleshooting.md +35 -20
  22. package/skills/trackops/references/workflow.md +18 -12
  23. package/skills/trackops/scripts/bootstrap-trackops.js +9 -7
  24. package/skills/trackops/skill.json +4 -4
  25. package/templates/opera/agent.md +10 -9
  26. package/templates/opera/architecture/dependency-graph.md +24 -0
  27. package/templates/opera/architecture/runtime-automation.md +24 -0
  28. package/templates/opera/architecture/runtime-operations.md +34 -0
  29. package/templates/opera/en/agent.md +21 -20
  30. package/templates/opera/en/architecture/dependency-graph.md +24 -0
  31. package/templates/opera/en/architecture/runtime-automation.md +24 -0
  32. package/templates/opera/en/architecture/runtime-operations.md +34 -0
  33. package/templates/opera/en/reviews/delivery-audit.md +18 -0
  34. package/templates/opera/en/reviews/integration-audit.md +18 -0
  35. package/templates/opera/en/router.md +19 -9
  36. package/templates/opera/reviews/delivery-audit.md +18 -0
  37. package/templates/opera/reviews/integration-audit.md +18 -0
  38. package/templates/opera/router.md +15 -5
  39. package/templates/skills/opera-contract-auditor/SKILL.md +38 -0
  40. package/templates/skills/opera-contract-auditor/locales/en/SKILL.md +38 -0
  41. package/templates/skills/opera-policy-guard/SKILL.md +26 -0
  42. package/templates/skills/opera-policy-guard/locales/en/SKILL.md +26 -0
  43. package/templates/skills/project-starter-skill/SKILL.md +89 -164
  44. package/templates/skills/project-starter-skill/locales/en/SKILL.md +104 -24
  45. package/ui/js/views/overview.js +16 -12
  46. package/templates/etapa/agent.md +0 -26
  47. package/templates/etapa/genesis.md +0 -94
  48. package/templates/etapa/references/autonomy-and-recovery.md +0 -117
  49. package/templates/etapa/references/etapa-cycle.md +0 -193
  50. package/templates/etapa/registry.md +0 -28
  51. package/templates/etapa/router.md +0 -39
package/bin/trackops.js CHANGED
@@ -2,22 +2,39 @@
2
2
 
3
3
  const path = require("path");
4
4
  const config = require("../lib/config");
5
+ const runtimeState = require("../lib/runtime-state");
6
+ const { setLocale, t } = require("../lib/i18n");
5
7
  const pkg = require("../package.json");
6
-
7
- const command = process.argv[2];
8
- const args = process.argv.slice(3);
9
-
8
+
9
+ const command = process.argv[2];
10
+ const args = process.argv.slice(3);
11
+
12
+ function initCliLocale() {
13
+ let projectLocale = null;
14
+ try {
15
+ const context = config.resolveWorkspaceContext();
16
+ if (context) {
17
+ projectLocale = config.getLocale(config.loadControl(context));
18
+ }
19
+ } catch (_error) {
20
+ projectLocale = null;
21
+ }
22
+ const doctor = runtimeState.doctorLocale(projectLocale);
23
+ setLocale(doctor.effectiveLocale);
24
+ }
25
+
10
26
  function resolveRoot() {
11
27
  const context = config.resolveWorkspaceContext();
12
28
  if (!context) {
13
- console.error("No TrackOps workspace found in this directory or any parent.");
29
+ console.error(t("cli.error.noWorkspace"));
14
30
  process.exit(1);
15
31
  }
16
32
  return context.workspaceRoot;
17
33
  }
18
-
19
- async function run() {
20
- try {
34
+
35
+ async function run() {
36
+ initCliLocale();
37
+ try {
21
38
  switch (command) {
22
39
  case "init":
23
40
  await require("../lib/init").cmdInit(args);
@@ -65,7 +82,7 @@ async function run() {
65
82
  const root = config.resolveProjectRoot() || process.cwd();
66
83
  if (sub === "status") workspace.cmdStatus(root);
67
84
  else if (sub === "migrate") workspace.cmdMigrate(root, args.slice(1));
68
- else console.log("Usage: trackops workspace <status|migrate>");
85
+ else console.log(t("cli.usage.workspace"));
69
86
  break;
70
87
  }
71
88
 
@@ -75,7 +92,7 @@ async function run() {
75
92
  const root = config.resolveProjectRoot() || process.cwd();
76
93
  if (sub === "status") env.cmdStatus(root);
77
94
  else if (sub === "sync") env.cmdSync(root);
78
- else console.log("Usage: trackops env <status|sync>");
95
+ else console.log(t("cli.usage.env"));
79
96
  break;
80
97
  }
81
98
 
@@ -83,18 +100,27 @@ async function run() {
83
100
  require("../lib/release").cmdRelease(config.resolveProjectRoot() || process.cwd(), args);
84
101
  break;
85
102
 
103
+ case "locale":
104
+ require("../lib/preferences").cmdLocale(args, config.resolveProjectRoot() || process.cwd());
105
+ break;
106
+
107
+ case "doctor":
108
+ require("../lib/preferences").cmdDoctor(args, config.resolveProjectRoot() || process.cwd());
109
+ break;
110
+
86
111
  case "opera": {
87
112
  const opera = require("../lib/opera");
88
113
  const sub = args[0];
89
- const root = config.resolveProjectRoot() || process.cwd();
90
- if (sub === "install") await opera.cmdInstall(root, args.slice(1));
91
- else if (sub === "bootstrap") await opera.cmdBootstrap(root, args.slice(1));
92
- else if (sub === "status") opera.cmdStatus(root);
93
- else if (sub === "configure") opera.cmdConfigure(root, args.slice(1));
94
- else if (sub === "upgrade") opera.cmdUpgrade(root);
95
- else { console.log("Usage: trackops opera <install|bootstrap|status|configure|upgrade>"); }
96
- break;
97
- }
114
+ const root = config.resolveProjectRoot() || process.cwd();
115
+ if (sub === "install") await opera.cmdInstall(root, args.slice(1));
116
+ else if (sub === "bootstrap") await opera.cmdBootstrap(root, args.slice(1));
117
+ else if (sub === "handoff") opera.cmdHandoff(root, args.slice(1));
118
+ else if (sub === "status") opera.cmdStatus(root);
119
+ else if (sub === "configure") opera.cmdConfigure(root, args.slice(1));
120
+ else if (sub === "upgrade") opera.cmdUpgrade(root, args.slice(1));
121
+ else { console.log(t("cli.usage.opera")); }
122
+ break;
123
+ }
98
124
 
99
125
  case "skill": {
100
126
  const skills = require("../lib/skills");
@@ -104,7 +130,7 @@ async function run() {
104
130
  else if (sub === "list") skills.cmdList(root);
105
131
  else if (sub === "remove") skills.cmdRemove(root, args[1]);
106
132
  else if (sub === "catalog") skills.cmdCatalog();
107
- else { console.log("Usage: trackops skill <install|list|remove|catalog> [name]"); }
133
+ else { console.log(t("cli.usage.skill")); }
108
134
  break;
109
135
  }
110
136
 
@@ -118,14 +144,14 @@ async function run() {
118
144
  case "--help":
119
145
  case "-h":
120
146
  case undefined:
121
- require("../lib/control").cmdHelp();
122
- break;
123
-
124
- default:
125
- console.error(`Unknown command: ${command}`);
126
- console.error("Run 'trackops help' for usage.");
127
- process.exit(1);
128
- }
147
+ require("../lib/control").cmdHelp();
148
+ break;
149
+
150
+ default:
151
+ console.error(t("cli.error.unknownCommand", { command }));
152
+ console.error(t("cli.error.runHelp"));
153
+ process.exit(1);
154
+ }
129
155
  } catch (error) {
130
156
  console.error(error.message);
131
157
  process.exit(1);
package/lib/config.js CHANGED
@@ -86,8 +86,15 @@ function createSplitContext(workspaceRoot, manifest = {}) {
86
86
  taskPlan: path.join(opsRoot, "task_plan.md"),
87
87
  progress: path.join(opsRoot, "progress.md"),
88
88
  findings: path.join(opsRoot, "findings.md"),
89
+ architectureDir: path.join(opsRoot, "architecture"),
89
90
  hooksDir: path.join(opsRoot, ".githooks"),
90
91
  tmpDir: path.join(opsRoot, ".tmp"),
92
+ bootstrapDir: path.join(opsRoot, "bootstrap"),
93
+ contractDir: path.join(opsRoot, "contract"),
94
+ contractFile: path.join(opsRoot, "contract", "operating-contract.json"),
95
+ policyDir: path.join(opsRoot, "policy"),
96
+ autonomyPolicyFile: path.join(opsRoot, "policy", "autonomy.json"),
97
+ reviewsDir: path.join(opsRoot, "reviews"),
91
98
  skillsDir: path.join(opsRoot, ".agents", "skills"),
92
99
  registryPath: path.join(opsRoot, ".agents", "skills", "_registry.md"),
93
100
  agentHubDir: path.join(opsRoot, ".agent", "hub"),
@@ -137,8 +144,15 @@ function createLegacyContext(rootDir) {
137
144
  taskPlan: path.join(root, "task_plan.md"),
138
145
  progress: path.join(root, "progress.md"),
139
146
  findings: path.join(root, "findings.md"),
147
+ architectureDir: path.join(root, "architecture"),
140
148
  hooksDir: path.join(root, ".githooks"),
141
149
  tmpDir: path.join(root, ".tmp"),
150
+ bootstrapDir: path.join(root, "bootstrap"),
151
+ contractDir: path.join(root, "contract"),
152
+ contractFile: path.join(root, "contract", "operating-contract.json"),
153
+ policyDir: path.join(root, "policy"),
154
+ autonomyPolicyFile: path.join(root, "policy", "autonomy.json"),
155
+ reviewsDir: path.join(root, "reviews"),
142
156
  skillsDir: path.join(root, ".agents", "skills"),
143
157
  registryPath: path.join(root, ".agents", "skills", "_registry.md"),
144
158
  agentHubDir: path.join(root, ".agent", "hub"),
@@ -255,14 +269,6 @@ function getOperaVersion(control) {
255
269
  return control.meta?.opera?.version || null;
256
270
  }
257
271
 
258
- function isEtapaInstalled(control) {
259
- return isOperaInstalled(control);
260
- }
261
-
262
- function getEtapaVersion(control) {
263
- return getOperaVersion(control);
264
- }
265
-
266
272
  function loadControl(contextOrRoot) {
267
273
  const filePath = controlFilePath(contextOrRoot);
268
274
  return JSON.parse(fs.readFileSync(filePath, "utf8"));
@@ -315,8 +321,6 @@ module.exports = {
315
321
  getLocale,
316
322
  isOperaInstalled,
317
323
  getOperaVersion,
318
- isEtapaInstalled,
319
- getEtapaVersion,
320
324
  loadControl,
321
325
  saveControl,
322
326
  };
package/lib/control.js CHANGED
@@ -442,6 +442,12 @@ function cmdStatus(root) {
442
442
  }
443
443
  if (control.meta?.opera?.bootstrap?.status) {
444
444
  console.log(t("cli.status.bootstrap", { status: control.meta.opera.bootstrap.status, locale: config.getLocale(control) }));
445
+ if (control.meta.opera.bootstrap.mode) {
446
+ console.log(`Bootstrap mode: ${control.meta.opera.bootstrap.mode}`);
447
+ }
448
+ if (control.meta.opera.bootstrap.routeReason) {
449
+ console.log(`Bootstrap route: ${control.meta.opera.bootstrap.routeReason}`);
450
+ }
445
451
  }
446
452
  console.log(t("cli.status.tasks", {
447
453
  completed: state.totals.completed, inProgress: state.totals.inProgress,
@@ -541,51 +547,57 @@ function cmdInstallHooks(root) {
541
547
  }
542
548
 
543
549
  function cmdHelp() {
544
- console.log("trackops — Operational project control");
550
+ console.log(`trackops — ${t("cli.help.title")}`);
545
551
  console.log("");
546
- console.log("Usage: trackops <command> [args]");
552
+ console.log(`${t("cli.help.usage")} trackops <command> [args]`);
547
553
  console.log("");
548
- console.log("Commands:");
554
+ console.log(t("cli.help.commands"));
549
555
  console.log(" init [--with-opera] [--legacy-layout] [--locale es|en] [--name \"...\"] [--no-bootstrap]");
550
- console.log(" Legacy alias available: --with-etapa");
551
- console.log(" Initialize trackops in the current directory.");
556
+ console.log(" [--bootstrap-mode auto|direct|handoff] [--technical-level low|medium|high|senior]");
557
+ console.log(" [--project-state idea|draft|existing_repo|advanced] [--docs-state none|notes|sos|spec_dossier|repo_docs]");
558
+ console.log(" [--decision-ownership user|shared|agent]");
559
+ console.log(` ${t("cli.help.init.desc")}`);
552
560
  console.log(" workspace status|migrate");
553
- console.log(" Show or migrate the current workspace layout.");
561
+ console.log(` ${t("cli.help.workspace.desc")}`);
554
562
  console.log(" env status|sync");
555
- console.log(" Audit or sync the workspace .env contract.");
563
+ console.log(` ${t("cli.help.env.desc")}`);
556
564
  console.log(" release [--push]");
557
- console.log(" Publish the configured app/ branch snapshot.");
565
+ console.log(` ${t("cli.help.release.desc")}`);
558
566
  console.log(" version");
559
- console.log(" Print the installed trackops version.");
567
+ console.log(` ${t("cli.help.version.desc")}`);
560
568
  console.log(" status");
561
- console.log(" Show project state: focus, active phase, ready tasks, blockers, repo.");
562
- console.log(" next");
563
- console.log(" Prioritized queue of next executable tasks.");
564
- console.log(" sync");
565
- console.log(" Regenerate task_plan.md, progress.md, findings.md from project_control.json.");
566
- console.log(" dashboard [--port N] [--host HOST] [--public] [--strict-port]");
567
- console.log(" Launch local web dashboard on a free port and print local/network URLs.");
569
+ console.log(` ${t("cli.help.status.desc")}`);
570
+ console.log(" next");
571
+ console.log(` ${t("cli.help.next.desc")}`);
572
+ console.log(" sync");
573
+ console.log(` ${t("cli.help.sync.desc")}`);
574
+ console.log(" dashboard [--port N] [--host HOST] [--public] [--strict-port]");
575
+ console.log(` ${t("cli.help.dashboard.desc")}`);
568
576
  console.log(" refresh-repo [--quiet]");
569
- console.log(" Update the repo runtime snapshot with git state.");
577
+ console.log(` ${t("cli.help.refreshRepo.desc")}`);
570
578
  console.log(" install-hooks");
571
- console.log(" Configure git core.hooksPath to use the TrackOps hooks dir.");
572
- console.log(" register");
573
- console.log(" Register current project in the multi-project portfolio.");
574
- console.log(" projects");
575
- console.log(" List registered projects.");
576
- console.log(" task <action> <id> [note]");
577
- console.log(" Actions: start, review, complete, block, pending, cancel, note.");
578
- console.log(" opera install|bootstrap|status|configure|upgrade");
579
- console.log(" Manage OPERA methodology.");
579
+ console.log(` ${t("cli.help.installHooks.desc")}`);
580
+ console.log(" register");
581
+ console.log(` ${t("cli.help.register.desc")}`);
582
+ console.log(" projects");
583
+ console.log(` ${t("cli.help.projects.desc")}`);
584
+ console.log(" task <action> <id> [note]");
585
+ console.log(` ${t("cli.help.task.desc")}`);
586
+ console.log(" opera install|bootstrap|handoff|status|configure|upgrade");
587
+ console.log(` ${t("cli.help.opera.desc")}`);
588
+ console.log(` ${t("cli.help.opera.upgradeHint")}`);
589
+ console.log(" locale get|set [es|en]");
590
+ console.log(` ${t("cli.help.locale.desc")}`);
591
+ console.log(" doctor locale");
592
+ console.log(` ${t("cli.help.doctor.desc")}`);
580
593
  console.log(" skill install|list|remove|catalog <name>");
581
- console.log(" Manage skills.");
594
+ console.log(` ${t("cli.help.skill.desc")}`);
582
595
  console.log(" help");
583
- console.log(" Show this help.");
596
+ console.log(` ${t("cli.help.help.desc")}`);
584
597
  console.log("");
585
- console.log("Global agent workflow:");
586
- console.log(" Install with 'npx skills add Baxahaun/trackops --skill trackops --full-depth'");
587
- console.log(" and the agent/global flags you need, then use 'trackops init' and");
588
- console.log(" 'trackops opera install' explicitly inside each project you want to manage.");
598
+ console.log(t("cli.help.globalWorkflow"));
599
+ console.log(` ${t("cli.help.globalWorkflow.line1")}`);
600
+ console.log(` ${t("cli.help.globalWorkflow.line2")}`);
589
601
  }
590
602
 
591
603
  /* ── project-scoped API (used by server) ── */
package/lib/env.js CHANGED
@@ -59,8 +59,13 @@ function normalizeEnvironmentMeta(control, context) {
59
59
  function inferRequiredKeys(control, contextOrRoot) {
60
60
  const envMeta = control.meta?.environment || {};
61
61
  const fromMeta = unique([...(envMeta.requiredKeys || []), ...(envMeta.optionalKeys || [])]);
62
+ const contractServices = readContractServices(contextOrRoot, control);
63
+ const bootstrapServices = unique([
64
+ ...(control.meta?.opera?.bootstrap?.discovery?.externalServices || []),
65
+ ...(control.meta?.opera?.bootstrap?.externalServices || []),
66
+ ]);
62
67
  const fromServices = unique(
63
- (control.meta?.opera?.bootstrap?.discovery?.externalServices || [])
68
+ (contractServices.length ? contractServices : bootstrapServices)
64
69
  .flatMap((service) => SERVICE_ENV_KEYS[service] || []),
65
70
  );
66
71
  const context = config.ensureContext(contextOrRoot || process.cwd());
@@ -68,6 +73,18 @@ function inferRequiredKeys(control, contextOrRoot) {
68
73
  return unique([...fromMeta, ...fromServices, ...fromExample]);
69
74
  }
70
75
 
76
+ function readContractServices(contextOrRoot, control) {
77
+ const context = config.ensureContext(contextOrRoot || process.cwd());
78
+ const contractFile = context.paths.contractFile;
79
+ if (!fs.existsSync(contractFile)) return [];
80
+ try {
81
+ const contract = JSON.parse(fs.readFileSync(contractFile, "utf8"));
82
+ return Array.isArray(contract?.system?.externalServices) ? contract.system.externalServices : [];
83
+ } catch (_error) {
84
+ return [];
85
+ }
86
+ }
87
+
71
88
  function ensureFileWithHeader(filePath, lines) {
72
89
  if (fs.existsSync(filePath)) return;
73
90
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
package/lib/init.js CHANGED
@@ -10,6 +10,7 @@ const env = require("./env");
10
10
  const workspace = require("./workspace");
11
11
  const { t, setLocale } = require("./i18n");
12
12
  const { detectSystemLocale, promptForLocale, resolveLocale } = require("./locale");
13
+ const runtimeState = require("./runtime-state");
13
14
 
14
15
  const GENERATED_SCRIPT_COMMANDS = {
15
16
  ops: "npx --yes trackops",
@@ -33,13 +34,23 @@ function parseArgs(args) {
33
34
  phases: null,
34
35
  noBootstrap: false,
35
36
  legacyLayout: false,
37
+ bootstrapMode: "auto",
38
+ technicalLevel: null,
39
+ projectState: null,
40
+ docsState: null,
41
+ decisionOwnership: null,
36
42
  };
37
43
  for (let i = 0; i < args.length; i += 1) {
38
44
  if (args[i] === "--locale" && args[i + 1]) { options.locale = args[i + 1]; i += 1; }
39
45
  else if (args[i] === "--name" && args[i + 1]) { options.name = args[i + 1]; i += 1; }
40
- else if (args[i] === "--with-opera" || args[i] === "--with-etapa") { options.withOpera = true; }
46
+ else if (args[i] === "--with-opera") { options.withOpera = true; }
41
47
  else if (args[i] === "--no-bootstrap") { options.noBootstrap = true; }
42
48
  else if (args[i] === "--legacy-layout") { options.legacyLayout = true; }
49
+ else if (args[i] === "--bootstrap-mode" && args[i + 1]) { options.bootstrapMode = args[i + 1]; i += 1; }
50
+ else if (args[i] === "--technical-level" && args[i + 1]) { options.technicalLevel = args[i + 1]; i += 1; }
51
+ else if (args[i] === "--project-state" && args[i + 1]) { options.projectState = args[i + 1]; i += 1; }
52
+ else if (args[i] === "--docs-state" && args[i + 1]) { options.docsState = args[i + 1]; i += 1; }
53
+ else if (args[i] === "--decision-ownership" && args[i + 1]) { options.decisionOwnership = args[i + 1]; i += 1; }
43
54
  else if (args[i] === "--phases" && args[i + 1]) {
44
55
  try { options.phases = JSON.parse(args[i + 1]); } catch (_e) { /* ignore */ }
45
56
  i += 1;
@@ -62,7 +73,7 @@ function detectProjectName(root) {
62
73
  }
63
74
 
64
75
  function buildDefaultControl(context, options) {
65
- const locale = resolveLocale(options.locale, config.DEFAULT_LOCALE);
76
+ const locale = resolveLocale(options.locale, runtimeState.getGlobalLocale() || config.DEFAULT_LOCALE);
66
77
  const phases = options.phases || config.buildDefaultPhases(locale);
67
78
  const isSplit = context.layout === "split";
68
79
  setLocale(locale);
@@ -96,6 +107,16 @@ function buildDefaultControl(context, options) {
96
107
  optionalKeys: [],
97
108
  lastAuditAt: null,
98
109
  },
110
+ userProfile: {
111
+ technicalLevel: null,
112
+ explanationMode: null,
113
+ capturedAt: null,
114
+ },
115
+ discovery: {
116
+ projectState: null,
117
+ documentationState: null,
118
+ availableArtifacts: [],
119
+ },
99
120
  },
100
121
  checks: {
101
122
  lastBuild: { status: "pending", date: null, note: "" },
@@ -188,7 +209,7 @@ function initSplitProject(root, options) {
188
209
  workspace.ensureRootGitignore(targetRoot);
189
210
 
190
211
  const control = buildDefaultControl(context, options);
191
- control.meta.projectName = options.name || detectProjectName(context.appRoot);
212
+ control.meta.projectName = options.name || detectProjectName(context.workspaceRoot);
192
213
  config.saveControl(context, control);
193
214
 
194
215
  installHooks(context);
@@ -261,7 +282,7 @@ function initLegacyProject(root, options) {
261
282
 
262
283
  function initProject(root, options) {
263
284
  const normalized = { ...(options || {}) };
264
- normalized.locale = resolveLocale(normalized.locale, config.DEFAULT_LOCALE);
285
+ normalized.locale = resolveLocale(normalized.locale, runtimeState.getGlobalLocale() || config.DEFAULT_LOCALE);
265
286
  setLocale(normalized.locale);
266
287
  if (normalized.legacyLayout) {
267
288
  return initLegacyProject(root, normalized);
@@ -271,9 +292,17 @@ function initProject(root, options) {
271
292
 
272
293
  async function cmdInit(args) {
273
294
  const options = parseArgs(args || []);
274
- options.locale = resolveLocale(options.locale, null);
275
- if (!options.locale) {
295
+ const explicitLocale = resolveLocale(options.locale, null);
296
+ const globalLocale = runtimeState.getGlobalLocale();
297
+ if (explicitLocale) {
298
+ options.locale = explicitLocale;
299
+ } else if (!globalLocale) {
276
300
  options.locale = await promptForLocale(detectSystemLocale());
301
+ } else {
302
+ options.locale = globalLocale;
303
+ }
304
+ if (!globalLocale) {
305
+ await runtimeState.ensureGlobalLocale({ preferredLocale: options.locale, interactive: false });
277
306
  }
278
307
  setLocale(options.locale || config.DEFAULT_LOCALE);
279
308
 
@@ -284,6 +313,11 @@ async function cmdInit(args) {
284
313
  await opera.install(result.root, {
285
314
  locale: options.locale,
286
315
  bootstrap: !options.noBootstrap,
316
+ bootstrapMode: options.bootstrapMode,
317
+ technicalLevel: options.technicalLevel,
318
+ projectState: options.projectState,
319
+ docsState: options.docsState,
320
+ decisionOwnership: options.decisionOwnership,
287
321
  });
288
322
  }
289
323
  }