@harness-lab/cli 0.2.9 → 0.3.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 (50) hide show
  1. package/README.md +5 -0
  2. package/assets/workshop-bundle/SKILL.md +8 -0
  3. package/assets/workshop-bundle/bundle-manifest.json +44 -52
  4. package/assets/workshop-bundle/content/challenge-cards/deck.md +19 -17
  5. package/assets/workshop-bundle/content/challenge-cards/locales/en/deck.md +7 -5
  6. package/assets/workshop-bundle/content/codex-craft.md +190 -0
  7. package/assets/workshop-bundle/content/facilitation/codex-setup-verification.md +5 -5
  8. package/assets/workshop-bundle/content/facilitation/master-guide.md +132 -65
  9. package/assets/workshop-bundle/content/project-briefs/code-review-helper.md +9 -9
  10. package/assets/workshop-bundle/content/project-briefs/devtoolbox-cli.md +11 -9
  11. package/assets/workshop-bundle/content/project-briefs/doc-generator.md +10 -8
  12. package/assets/workshop-bundle/content/project-briefs/locales/en/devtoolbox-cli.md +4 -2
  13. package/assets/workshop-bundle/content/project-briefs/locales/en/doc-generator.md +5 -3
  14. package/assets/workshop-bundle/content/project-briefs/locales/en/metrics-dashboard.md +4 -2
  15. package/assets/workshop-bundle/content/project-briefs/locales/en/standup-bot.md +4 -2
  16. package/assets/workshop-bundle/content/project-briefs/metrics-dashboard.md +14 -12
  17. package/assets/workshop-bundle/content/project-briefs/standup-bot.md +11 -9
  18. package/assets/workshop-bundle/content/talks/codex-demo-script.md +12 -10
  19. package/assets/workshop-bundle/content/talks/context-is-king.md +24 -24
  20. package/assets/workshop-bundle/docs/harness-cli-foundation.md +2 -0
  21. package/assets/workshop-bundle/docs/learner-resource-kit.md +37 -37
  22. package/assets/workshop-bundle/materials/coaching-codex.md +76 -0
  23. package/assets/workshop-bundle/materials/locales/en/participant-resource-kit.md +14 -2
  24. package/assets/workshop-bundle/materials/participant-resource-kit.md +23 -11
  25. package/assets/workshop-bundle/workshop-blueprint/README.md +2 -5
  26. package/assets/workshop-bundle/workshop-blueprint/day-structure.md +14 -0
  27. package/assets/workshop-bundle/workshop-skill/analyze-checklist.md +3 -3
  28. package/assets/workshop-bundle/workshop-skill/closing-skill.md +5 -5
  29. package/assets/workshop-bundle/workshop-skill/commands.md +13 -13
  30. package/assets/workshop-bundle/workshop-skill/facilitator.md +33 -0
  31. package/assets/workshop-bundle/workshop-skill/follow-up-package.md +13 -8
  32. package/assets/workshop-bundle/workshop-skill/install.md +8 -8
  33. package/assets/workshop-bundle/workshop-skill/locales/en/follow-up-package.md +8 -3
  34. package/assets/workshop-bundle/workshop-skill/locales/en/recap.md +8 -1
  35. package/assets/workshop-bundle/workshop-skill/locales/en/reference.md +19 -3
  36. package/assets/workshop-bundle/workshop-skill/locales/en/setup.md +1 -1
  37. package/assets/workshop-bundle/workshop-skill/recap.md +12 -5
  38. package/assets/workshop-bundle/workshop-skill/reference.md +45 -29
  39. package/assets/workshop-bundle/workshop-skill/setup.md +11 -11
  40. package/assets/workshop-bundle/workshop-skill/template-agents.md +4 -4
  41. package/package.json +1 -1
  42. package/src/client.js +9 -0
  43. package/src/io.js +1 -0
  44. package/src/run-cli.js +95 -0
  45. package/src/skill-install.js +108 -7
  46. package/src/workshop-bundle.js +30 -2
  47. package/assets/workshop-bundle/content/czech-editorial-review-checklist.md +0 -88
  48. package/assets/workshop-bundle/content/style-examples.md +0 -127
  49. package/assets/workshop-bundle/content/style-guide.md +0 -108
  50. package/assets/workshop-bundle/workshop-blueprint/edit-boundaries.md +0 -64
package/src/run-cli.js CHANGED
@@ -166,6 +166,19 @@ function summarizeWorkshopInstance(instance) {
166
166
  };
167
167
  }
168
168
 
169
+ function summarizeParticipantAccess(participantAccess) {
170
+ return {
171
+ instanceId: participantAccess?.instanceId ?? null,
172
+ active: participantAccess?.active ?? false,
173
+ version: participantAccess?.version ?? null,
174
+ codeId: participantAccess?.codeId ?? null,
175
+ expiresAt: participantAccess?.expiresAt ?? null,
176
+ canRevealCurrent: participantAccess?.canRevealCurrent ?? false,
177
+ source: participantAccess?.source ?? "missing",
178
+ currentCode: participantAccess?.currentCode ?? null,
179
+ };
180
+ }
181
+
169
182
  function resolveCurrentInstanceTarget(session, env) {
170
183
  if (typeof session?.selectedInstanceId === "string" && session.selectedInstanceId.trim().length > 0) {
171
184
  return {
@@ -210,6 +223,7 @@ function printUsage(io, ui) {
210
223
  "harness workshop status",
211
224
  "harness workshop list-instances",
212
225
  "harness workshop show-instance <instance-id>",
226
+ "harness workshop participant-access [<instance-id>] [--rotate] [--code VALUE]",
213
227
  "harness workshop archive [--notes TEXT]",
214
228
  "harness workshop create-instance [<instance-id>] [--template-id ID] [--content-lang cs|en] [--event-title TEXT] [--city CITY]",
215
229
  "harness workshop update-instance <instance-id> [--content-lang cs|en] [--event-title TEXT] [--city CITY]",
@@ -592,6 +606,22 @@ async function handleAuthLogout(io, ui, env, deps) {
592
606
  return 0;
593
607
  }
594
608
 
609
+ function renderSelectedInstanceBanner(ui, target) {
610
+ if (ui.jsonMode) {
611
+ return;
612
+ }
613
+ const instanceId = target.instanceId ?? "none";
614
+ const label = target.source === "session"
615
+ ? "Selected instance (locally selected)"
616
+ : target.instanceId
617
+ ? `Selected instance (from ${target.source})`
618
+ : "Selected instance";
619
+ ui.keyValue(label, instanceId);
620
+ if (!target.instanceId) {
621
+ ui.keyValue("", "no instance is currently selected — run `harness workshop select-instance <id>` to pin one");
622
+ }
623
+ }
624
+
595
625
  async function handleWorkshopStatus(io, ui, env, deps) {
596
626
  const session = await requireSession(io, ui, env);
597
627
  if (!session) {
@@ -602,6 +632,8 @@ async function handleWorkshopStatus(io, ui, env, deps) {
602
632
  const client = createHarnessClient({ fetchFn: deps.fetchFn, session });
603
633
  const target = resolveCurrentInstanceTarget(session, env);
604
634
 
635
+ renderSelectedInstanceBanner(ui, target);
636
+
605
637
  if (target.source === "session" && target.instanceId) {
606
638
  const [instanceResult, agenda] = await Promise.all([
607
639
  client.getWorkshopInstance(target.instanceId),
@@ -609,6 +641,11 @@ async function handleWorkshopStatus(io, ui, env, deps) {
609
641
  ]);
610
642
  ui.json("Workshop Status", {
611
643
  ok: true,
644
+ selectedInstance: {
645
+ instanceId: target.instanceId,
646
+ source: target.source,
647
+ selected: true,
648
+ },
612
649
  targetInstanceId: target.instanceId,
613
650
  targetSource: target.source,
614
651
  ...summarizeWorkshopInstance(instanceResult.instance),
@@ -622,6 +659,11 @@ async function handleWorkshopStatus(io, ui, env, deps) {
622
659
  const [workshop, agenda] = await Promise.all([client.getWorkshopStatus(), client.getAgenda()]);
623
660
  ui.json("Workshop Status", {
624
661
  ok: true,
662
+ selectedInstance: {
663
+ instanceId: target.instanceId ?? null,
664
+ source: target.source,
665
+ selected: Boolean(target.instanceId),
666
+ },
625
667
  targetInstanceId: target.instanceId,
626
668
  targetSource: target.source,
627
669
  workshopId: workshop.workshopId,
@@ -801,6 +843,55 @@ async function handleWorkshopShowInstance(io, ui, env, positionals, flags, deps)
801
843
  }
802
844
  }
803
845
 
846
+ async function handleWorkshopParticipantAccess(io, ui, env, positionals, flags, deps) {
847
+ const session = await requireSession(io, ui, env);
848
+ if (!session) {
849
+ return 1;
850
+ }
851
+
852
+ const instanceId = await readRequiredCommandValue(
853
+ io,
854
+ flags,
855
+ ["id", "instance-id"],
856
+ "Instance id: ",
857
+ readOptionalPositional(positionals, 2) ?? session.selectedInstanceId,
858
+ );
859
+ if (!instanceId) {
860
+ ui.status("error", "Instance id is required.", { stream: "stderr" });
861
+ return 1;
862
+ }
863
+
864
+ try {
865
+ const client = createHarnessClient({ fetchFn: deps.fetchFn, session });
866
+ if (flags.rotate === true) {
867
+ const result = await client.issueWorkshopParticipantAccess(instanceId, {
868
+ ...(typeof flags.code === "string" ? { code: flags.code } : {}),
869
+ });
870
+ ui.json("Workshop Participant Access", {
871
+ ok: true,
872
+ issuedCode: result.issuedCode ?? null,
873
+ ...summarizeParticipantAccess(result.participantAccess),
874
+ participantAccess: result.participantAccess,
875
+ });
876
+ return 0;
877
+ }
878
+
879
+ const result = await client.getWorkshopParticipantAccess(instanceId);
880
+ ui.json("Workshop Participant Access", {
881
+ ok: true,
882
+ ...summarizeParticipantAccess(result.participantAccess),
883
+ participantAccess: result.participantAccess,
884
+ });
885
+ return 0;
886
+ } catch (error) {
887
+ if (error instanceof HarnessApiError) {
888
+ ui.status("error", `Participant access failed: ${error.message}`, { stream: "stderr" });
889
+ return 1;
890
+ }
891
+ throw error;
892
+ }
893
+ }
894
+
804
895
  async function handleWorkshopArchive(io, ui, env, flags, deps) {
805
896
  const session = await requireSession(io, ui, env);
806
897
  if (!session) {
@@ -1118,6 +1209,10 @@ export async function runCli(argv, io, deps = {}) {
1118
1209
  return handleWorkshopShowInstance(io, ui, io.env, positionals, flags, mergedDeps);
1119
1210
  }
1120
1211
 
1212
+ if (scope === "workshop" && action === "participant-access") {
1213
+ return handleWorkshopParticipantAccess(io, ui, io.env, positionals, flags, mergedDeps);
1214
+ }
1215
+
1121
1216
  if (scope === "workshop" && action === "archive") {
1122
1217
  return handleWorkshopArchive(io, ui, io.env, flags, mergedDeps);
1123
1218
  }
@@ -1,5 +1,6 @@
1
1
  import fs from "node:fs/promises";
2
2
  import path from "node:path";
3
+ import process from "node:process";
3
4
  import {
4
5
  createWorkshopBundleManifestFromDirectory,
5
6
  createWorkshopBundleManifestFromSource,
@@ -12,6 +13,8 @@ import {
12
13
  WORKSHOP_SKILL_NAME,
13
14
  } from "./workshop-bundle.js";
14
15
 
16
+ const MIN_NODE_MAJOR = 22;
17
+
15
18
  export class SkillInstallError extends Error {
16
19
  constructor(message, options = {}) {
17
20
  super(message);
@@ -20,6 +23,81 @@ export class SkillInstallError extends Error {
20
23
  }
21
24
  }
22
25
 
26
+ function assertSupportedNodeVersion() {
27
+ const raw = process.versions?.node;
28
+ if (!raw) {
29
+ return;
30
+ }
31
+ const major = Number.parseInt(raw.split(".")[0], 10);
32
+ if (Number.isFinite(major) && major < MIN_NODE_MAJOR) {
33
+ throw new SkillInstallError(
34
+ `Harness CLI requires Node.js ${MIN_NODE_MAJOR} or newer. This process is running Node.js ${raw}. Upgrade with your version manager (for example \`nvm install --lts\`) and re-run \`harness skill install\`.`,
35
+ { code: "unsupported_node_version" },
36
+ );
37
+ }
38
+ }
39
+
40
+ function translateFileSystemError(error, context) {
41
+ if (!error || typeof error !== "object" || !("code" in error)) {
42
+ return null;
43
+ }
44
+
45
+ const targetPath = error.path ? ` (${error.path})` : "";
46
+
47
+ if (error.code === "EACCES" || error.code === "EPERM") {
48
+ return new SkillInstallError(
49
+ `Harness CLI could not ${context}${targetPath} because the current user does not have write permission. Try running from a directory you own, or adjust the directory permissions. On macOS and Linux, that usually means avoiding system paths like /usr. On Windows, avoid running from a protected location such as C:\\Program Files.`,
50
+ { code: "install_permission_denied" },
51
+ );
52
+ }
53
+
54
+ if (error.code === "ENOSPC") {
55
+ return new SkillInstallError(
56
+ `Harness CLI could not ${context}${targetPath} because the disk is full. Free some space and re-run \`harness skill install\`.`,
57
+ { code: "install_no_space" },
58
+ );
59
+ }
60
+
61
+ if (error.code === "ENAMETOOLONG" || error.code === "ENOTDIR") {
62
+ return new SkillInstallError(
63
+ `Harness CLI could not ${context}${targetPath}. The target path is too long or part of it is not a directory. On Windows, this often happens when the repository lives in a deeply nested folder — move the repo closer to the drive root (for example C:\\repos\\your-project) and try again.`,
64
+ { code: "install_path_invalid" },
65
+ );
66
+ }
67
+
68
+ if (error.code === "EROFS") {
69
+ return new SkillInstallError(
70
+ `Harness CLI could not ${context}${targetPath} because the file system is read-only. Re-run \`harness skill install\` from a writable directory.`,
71
+ { code: "install_read_only" },
72
+ );
73
+ }
74
+
75
+ if (error.code === "EBUSY") {
76
+ return new SkillInstallError(
77
+ `Harness CLI could not ${context}${targetPath} because the target is busy (another process may hold it open). Close editors or agents pointing at \`.agents/skills/\` and re-run \`harness skill install\`.`,
78
+ { code: "install_target_busy" },
79
+ );
80
+ }
81
+
82
+ return null;
83
+ }
84
+
85
+ async function fsWithActionableError(operation, context) {
86
+ try {
87
+ return await operation();
88
+ } catch (error) {
89
+ if (error instanceof SkillInstallError) {
90
+ throw error;
91
+ }
92
+ const translated = translateFileSystemError(error, context);
93
+ if (translated) {
94
+ translated.cause = error;
95
+ throw translated;
96
+ }
97
+ throw error;
98
+ }
99
+ }
100
+
23
101
  async function resolveBundleSource() {
24
102
  const packagedBundlePath = getPackagedWorkshopBundlePath();
25
103
  if (await pathExists(path.join(packagedBundlePath, "SKILL.md"))) {
@@ -43,8 +121,14 @@ async function resolveBundleSource() {
43
121
  }
44
122
 
45
123
  async function ensureDirectory(targetPath) {
46
- await fs.mkdir(targetPath, { recursive: true });
47
- const stat = await fs.stat(targetPath);
124
+ await fsWithActionableError(
125
+ () => fs.mkdir(targetPath, { recursive: true }),
126
+ `create the install target directory`,
127
+ );
128
+ const stat = await fsWithActionableError(
129
+ () => fs.stat(targetPath),
130
+ `inspect the install target directory`,
131
+ );
48
132
  if (!stat.isDirectory()) {
49
133
  throw new SkillInstallError(`Install target is not a directory: ${targetPath}`, {
50
134
  code: "invalid_target",
@@ -71,14 +155,22 @@ async function getSourceBundleManifest(resolvedBundle) {
71
155
 
72
156
  async function installFromResolvedBundle(resolvedBundle, installPath) {
73
157
  if (resolvedBundle.mode === "packaged_bundle") {
74
- await fs.cp(resolvedBundle.sourcePath, installPath, { recursive: true });
158
+ await fsWithActionableError(
159
+ () => fs.cp(resolvedBundle.sourcePath, installPath, { recursive: true }),
160
+ `copy the workshop bundle into the install target`,
161
+ );
75
162
  return;
76
163
  }
77
164
 
78
- await createWorkshopBundleFromSource(resolvedBundle.sourceRoot, installPath);
165
+ await fsWithActionableError(
166
+ () => createWorkshopBundleFromSource(resolvedBundle.sourceRoot, installPath),
167
+ `build the workshop bundle from source into the install target`,
168
+ );
79
169
  }
80
170
 
81
171
  export async function installWorkshopSkill(startDir, options = {}) {
172
+ assertSupportedNodeVersion();
173
+
82
174
  const resolvedBundle = await resolveBundleSource();
83
175
  if (!resolvedBundle) {
84
176
  throw new SkillInstallError(
@@ -106,7 +198,10 @@ export async function installWorkshopSkill(startDir, options = {}) {
106
198
  };
107
199
  }
108
200
 
109
- await fs.rm(installPath, { recursive: true, force: true });
201
+ await fsWithActionableError(
202
+ () => fs.rm(installPath, { recursive: true, force: true }),
203
+ `remove the previous workshop bundle before refreshing it`,
204
+ );
110
205
 
111
206
  return {
112
207
  ...(await installFreshBundle(resolvedBundle, installPath, targetRoot)),
@@ -115,7 +210,10 @@ export async function installWorkshopSkill(startDir, options = {}) {
115
210
  }
116
211
 
117
212
  if (existingInstall && options.force === true) {
118
- await fs.rm(installPath, { recursive: true, force: true });
213
+ await fsWithActionableError(
214
+ () => fs.rm(installPath, { recursive: true, force: true }),
215
+ `remove the previous workshop bundle before reinstalling`,
216
+ );
119
217
  }
120
218
 
121
219
  const result = await installFreshBundle(resolvedBundle, installPath, targetRoot);
@@ -130,7 +228,10 @@ export async function installWorkshopSkill(startDir, options = {}) {
130
228
  }
131
229
 
132
230
  async function installFreshBundle(resolvedBundle, installPath, targetRoot) {
133
- await fs.mkdir(path.dirname(installPath), { recursive: true });
231
+ await fsWithActionableError(
232
+ () => fs.mkdir(path.dirname(installPath), { recursive: true }),
233
+ `create the parent directory for the installed skill`,
234
+ );
134
235
  await installFromResolvedBundle(resolvedBundle, installPath);
135
236
 
136
237
  return {
@@ -26,8 +26,26 @@ const FILE_COPIES = [
26
26
  ["docs/locales/en/learner-reference-gallery.md", "docs/locales/en/learner-reference-gallery.md"],
27
27
  ["materials/participant-resource-kit.md", "materials/participant-resource-kit.md"],
28
28
  ["materials/locales/en/participant-resource-kit.md", "materials/locales/en/participant-resource-kit.md"],
29
+ ["materials/coaching-codex.md", "materials/coaching-codex.md"],
29
30
  ];
30
31
 
32
+ // Files that live inside DIRECTORY_COPIES source trees but must not ship to
33
+ // participants. These are author/maintainer/copy-editor artifacts that have no
34
+ // runtime purpose inside the installed workshop skill. Keep the set minimal —
35
+ // every entry should be a file that (a) has no workshop-skill reference and
36
+ // (b) is clearly authoring/governance content rather than participant-facing.
37
+ const EXCLUDED_BUNDLE_PATHS = new Set([
38
+ "content/style-guide.md",
39
+ "content/style-examples.md",
40
+ "content/czech-reject-list.md",
41
+ "content/czech-editorial-review-checklist.md",
42
+ "workshop-blueprint/edit-boundaries.md",
43
+ ]);
44
+
45
+ function isExcludedBundlePath(bundleRelativePath) {
46
+ return EXCLUDED_BUNDLE_PATHS.has(normalizePathForManifest(bundleRelativePath));
47
+ }
48
+
31
49
  export function getPackageRoot() {
32
50
  return packageRoot;
33
51
  }
@@ -66,24 +84,31 @@ async function copyDirectoryTree(sourceRoot, targetRoot) {
66
84
  await copyDirectoryRecursive(
67
85
  path.join(sourceRoot, sourceRelativePath),
68
86
  path.join(targetRoot, targetRelativePath),
87
+ targetRelativePath,
69
88
  );
70
89
  }
71
90
  }
72
91
 
73
- async function copyDirectoryRecursive(sourcePath, targetPath) {
92
+ async function copyDirectoryRecursive(sourcePath, targetPath, bundleRelativePrefix) {
74
93
  const entries = await fs.readdir(sourcePath, { withFileTypes: true });
75
94
  await fs.mkdir(targetPath, { recursive: true });
76
95
 
77
96
  for (const entry of entries) {
78
97
  const sourceEntryPath = path.join(sourcePath, entry.name);
79
98
  const targetEntryPath = path.join(targetPath, entry.name);
99
+ const entryBundleRelativePath = bundleRelativePrefix
100
+ ? path.join(bundleRelativePrefix, entry.name)
101
+ : entry.name;
80
102
 
81
103
  if (entry.isDirectory()) {
82
- await copyDirectoryRecursive(sourceEntryPath, targetEntryPath);
104
+ await copyDirectoryRecursive(sourceEntryPath, targetEntryPath, entryBundleRelativePath);
83
105
  continue;
84
106
  }
85
107
 
86
108
  if (entry.isFile()) {
109
+ if (isExcludedBundlePath(entryBundleRelativePath)) {
110
+ continue;
111
+ }
87
112
  await fs.copyFile(sourceEntryPath, targetEntryPath);
88
113
  }
89
114
  }
@@ -187,6 +212,9 @@ export async function createWorkshopBundleManifestFromSource(sourceRoot) {
187
212
  if (targetRelative === "workshop-skill/SKILL.md") {
188
213
  continue;
189
214
  }
215
+ if (isExcludedBundlePath(targetRelative)) {
216
+ continue;
217
+ }
190
218
 
191
219
  entries.push({
192
220
  absolutePath: file.absolutePath,
@@ -1,88 +0,0 @@
1
- # Czech Editorial Review Checklist
2
-
3
- Použijte tento checklist při revizi českého obsahu pro účastníky, hlavně pro:
4
-
5
- - workshop agenda a presenter scenes
6
- - pokyny pro participant room
7
- - project briefs
8
- - challenge cards
9
- - setup, reference, recap, follow-up a learner-kit materiály
10
-
11
- Tento checklist doplňuje [`content/style-guide.md`](./style-guide.md) a [`content/style-examples.md`](./style-examples.md). Není to náhrada. Je to poslední quality gate před tím, než se text bere jako workshop-ready.
12
-
13
- ## 1. Přirozenost češtiny
14
-
15
- - Zní text jako přirozená čeština, ne jako překlad?
16
- - Přečetl by to český developer bez škobrtnutí?
17
- - Nejsou ve větách doslovné anglické kalky?
18
- - Nejsou věty zbytečně dlouhé nebo toporné?
19
-
20
- ## 2. Kvalita míchání češtiny a angličtiny
21
-
22
- - Zůstává česká věta česká?
23
- - Jsou anglické termíny použité jen tam, kde jsou v developerské praxi opravdu přirozené?
24
- - Není v textu náhodně promíchaná angličtina jen proto, že původní zdroj byl anglický?
25
- - Když se méně známý anglický termín objevuje poprvé, je stručně ukotvený česky?
26
-
27
- ## 3. Jasnost instrukce
28
-
29
- - Je z textu jasné, co má člověk udělat právě teď?
30
- - Mají věty konkrétní slovesa jako `spusťte`, `zkontrolujte`, `doplňte`, `ověřte`?
31
- - Neschovává se akce za abstraktní formulace typu „je vhodné realizovat“?
32
- - Nejsou odstavce přeplněné více cíli najednou?
33
-
34
- ## 4. Workshop voice
35
-
36
- - Zní text jako zkušený peer, ne jako marketér nebo korporát?
37
- - Drží se text klidného, věcného a praktického tónu?
38
- - Nezní text jako slide, slogan nebo generický AI obsah?
39
- - Je z textu cítit disciplína workshopu: kontext zapsaný v repu, ověření, handoff?
40
-
41
- ## 5. Terminologická disciplína
42
-
43
- - Jsou opakované workshop terms použité konzistentně?
44
- - Neobjevují se slabé nebo matoucí fráze jen proto, že znějí „AI-ish“?
45
- - Jsou výrazy jako `safe move`, `handoff`, `checkpoint`, `workflow`, `review`, `skill`, `runbook` použité záměrně, ne náhodně?
46
- - Není stejná věc jednou česky a podruhé napůl anglicky bez důvodu?
47
-
48
- ## 6. Vyhněte se těmto signálům
49
-
50
- Pokud se v textu objeví něco z toho, vraťte ho do editace:
51
-
52
- - doslovný překlad anglické vazby
53
- - česká věta s náhodně vloženými anglickými slovy mimo technické termíny
54
- - korporátní nebo školometský tón
55
- - fráze, které nic nekotví k akci
56
- - generické AI obraty bez konkrétního významu
57
-
58
- ## 7. Spoken check
59
-
60
- Přečtěte text nahlas nebo aspoň polohlasem.
61
-
62
- Text vrátit do editace, pokud:
63
-
64
- - se nedá říct plynule
65
- - obsahuje nepřirozený slovosled
66
- - zní tvrdě přeloženě
67
- - potřebuje v hlavě „opravovat“, co tím autor asi myslel
68
-
69
- ## 8. Cross-locale check
70
-
71
- Pokud text vznikal z anglického source:
72
-
73
- - není to doslovný překlad?
74
- - drží česká verze stejný význam, ale přirozenější formulací?
75
- - není česká verze výrazně slabší, plošší nebo méně konkrétní než anglická?
76
- - není anglický source sám o sobě slabý a nehodí se nejdřív přepsat?
77
-
78
- ## 9. Before publish
79
-
80
- Před schválením českého textu pro účastníky musí být možné říct `ano` na všechno:
81
-
82
- 1. Je to přirozená čeština?
83
- 2. Rozumí tomu český developer napoprvé?
84
- 3. Je jasné, co má člověk udělat nebo pochopit?
85
- 4. Drží text workshop voice bez hype a bez korporátu?
86
- 5. Je míchání češtiny a angličtiny disciplinované?
87
- 6. Neobsahuje text slabé fráze nebo „AI slop“?
88
- 7. Obstojí text při čtení nahlas?
@@ -1,127 +0,0 @@
1
- # Czech Style Examples
2
-
3
- ## Do / Don't
4
-
5
- ### 1. Instrukce
6
-
7
- Do:
8
-
9
- - „Otevřete repozitář a nejdřív doplňte `AGENTS.md`.“
10
-
11
- Don't:
12
-
13
- - „V prvním kroku je vhodné provést vytvoření souboru `AGENTS.md`.“
14
-
15
- ### 2. Setup
16
-
17
- Do:
18
-
19
- - „Když se setup sekne, přejděte na Codex App nebo web fallback.“
20
-
21
- Don't:
22
-
23
- - „V případě komplikací v procesu instalace je možné využít alternativní variantu přístupu.“
24
-
25
- ### 3. Facilitation
26
-
27
- Do:
28
-
29
- - „Prvních 10 minut po rotaci jen čtěte a mapujte repo.“
30
-
31
- Don't:
32
-
33
- - „Po realizaci rotace doporučujeme zahájit aktivitu detailní analýzou repozitáře.“
34
-
35
- ### 4. Workshop framing
36
-
37
- Do:
38
-
39
- - „Dnes nejde o to být nejrychlejší. Jde o to předat práci tak, aby ji cizí tým dokázal převzít.“
40
-
41
- Don't:
42
-
43
- - „Hlavním cílem dnešního dne je maximalizace schopnosti efektivního předávání výstupů mezi týmy.“
44
-
45
- ### 5. Czech + English
46
-
47
- Do:
48
-
49
- - „Nejdřív spusťte `/plan`, potom implementujte malý krok a nakonec udělejte `/review`.“
50
-
51
- Don't:
52
-
53
- - „Nejdříve vytvořte plán, pak proveďte implementaci a následně zrevidujte změnu.“
54
-
55
- Poznámka:
56
-
57
- Tady je angličtina přirozenější, protože jde o konkrétní commands a workflow terms.
58
-
59
- ### 6. Technical explanation
60
-
61
- Do:
62
-
63
- - „Monitoring teď běží jako manuální MVP. Ondřej spustí scan repozitářů a z výsledku připraví intermezzo brief.“
64
-
65
- Don't:
66
-
67
- - „Monitoring je aktuálně realizován prostřednictvím minimální životaschopné verze manuálního typu.“
68
-
69
- ### 7. Briefs
70
-
71
- Do:
72
-
73
- - „Mock data jsou v pořádku, pokud workflow působí realisticky.“
74
-
75
- Don't:
76
-
77
- - „Použití simulovaných dat je akceptovatelné za předpokladu, že výsledný proces bude působit realisticky.“
78
-
79
- ### 8. Error / fallback messaging
80
-
81
- Do:
82
-
83
- - „Pokud vám nefunguje CLI, pokračujte přes App a neztrácejte dalších 20 minut.“
84
-
85
- Don't:
86
-
87
- - „V případě nefunkčnosti rozhraní příkazové řádky doporučujeme zvážit alternativní postup.“
88
-
89
- ## Approved English Terms
90
-
91
- Tyto výrazy se v textech pro účastníky běžně nechávají v angličtině:
92
-
93
- - `prompt`
94
- - `review`
95
- - `workflow`
96
- - `skill`
97
- - `runbook`
98
- - `build`
99
- - `deploy`
100
- - `checkpoint`
101
- - `fallback`
102
- - `handoff`
103
- - `CLI`
104
- - `App`
105
- - `repo`
106
- - `README`
107
- - `AGENTS.md`
108
- - `Done When`
109
-
110
- ## Usually Better In Czech
111
-
112
- Tyto části bývají lepší česky:
113
-
114
- - cíle a instrukce
115
- - facilitační věty
116
- - reflexe a uzavírání
117
- - vysvětlení, proč něco děláme
118
- - očekávání a pravidla workshopu
119
-
120
- ## Rewrite Heuristic
121
-
122
- Když text zní moc tvrdě přeloženě, uprav ho takto:
123
-
124
- 1. zkrať větu
125
- 2. vrať české sloveso do aktivního rodu
126
- 3. nech technický termín v angličtině
127
- 4. zkontroluj, že věta vede k akci