@zq-silk/yui 0.2.0 → 0.4.2

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 (208) hide show
  1. package/ARCHITECTURE.md +603 -133
  2. package/README.md +806 -31
  3. package/dist/agent/agent.js +2 -1
  4. package/dist/agent/argumentPolicy.js +3 -1
  5. package/dist/agent/launchEnvironment.js +106 -0
  6. package/dist/agent/managedRuntimeEnvironment.js +34 -0
  7. package/dist/brief/taskBrief.js +11 -1
  8. package/dist/cli/agentConfigurationPicker.js +287 -0
  9. package/dist/cli/commandCatalog.js +488 -60
  10. package/dist/cli/completion.js +146 -22
  11. package/dist/cli/helpRenderer.js +3 -1
  12. package/dist/cli/interactionCandidates.js +53 -15
  13. package/dist/cli/interactionPolicy.js +267 -30
  14. package/dist/cli/interactiveSelection.js +6 -2
  15. package/dist/cli/invocationRouter.js +5 -1
  16. package/dist/cli/operatorWizard.js +87 -0
  17. package/dist/cli/roleOptionCatalog.js +1 -0
  18. package/dist/cli/roleWizard.js +185 -21
  19. package/dist/cli/updateCommand.js +62 -19
  20. package/dist/cli/updateOrchestrator.js +539 -0
  21. package/dist/cli/updatePorts.js +1119 -0
  22. package/dist/cli/upgradeCommand.js +112 -0
  23. package/dist/cli.js +1420 -86
  24. package/dist/commands/agentCommands.js +146 -3
  25. package/dist/commands/configCommands.js +126 -0
  26. package/dist/commands/controllerCommands.js +365 -0
  27. package/dist/commands/globalRoleCommands.js +168 -126
  28. package/dist/commands/jobCommands.js +18 -8
  29. package/dist/commands/operatorCommands.js +159 -9
  30. package/dist/commands/profileCommands.js +203 -0
  31. package/dist/commands/projectCommands.js +650 -0
  32. package/dist/commands/roleConfiguration.js +85 -24
  33. package/dist/commands/roleRuntimeGuard.js +12 -0
  34. package/dist/commands/roleSkillValidation.js +47 -0
  35. package/dist/commands/taskActor.js +127 -0
  36. package/dist/commands/taskCommands.js +4201 -313
  37. package/dist/commands/taskCompletionGate.js +131 -0
  38. package/dist/commands/taskContextCommand.js +244 -30
  39. package/dist/commands/taskInputCommands.js +177 -59
  40. package/dist/commands/taskIntegrationCommands.js +303 -0
  41. package/dist/commands/taskOverviewCommand.js +363 -0
  42. package/dist/commands/taskRoleRuntimeStatus.js +125 -19
  43. package/dist/commands/textInput.js +15 -0
  44. package/dist/completion/completionInstaller.js +26 -22
  45. package/dist/config/yuiConfig.js +4 -3
  46. package/dist/context/dispatchContext.js +90 -38
  47. package/dist/context/roleSessionContext.js +119 -0
  48. package/dist/controller/claudeLifecycleHook.js +203 -0
  49. package/dist/controller/clientRuntime.js +408 -56
  50. package/dist/controller/codexLifecycleHook.js +108 -0
  51. package/dist/controller/controller.js +1089 -32
  52. package/dist/controller/domainIdentity.js +505 -0
  53. package/dist/controller/ephemeralResourceReaper.js +131 -0
  54. package/dist/controller/fileSchedulerStoreAdapter.js +2153 -103
  55. package/dist/controller/providerHookRunFence.js +127 -0
  56. package/dist/controller/resourceCleanupLinux.js +286 -0
  57. package/dist/controller/resourceInventory.js +531 -0
  58. package/dist/controller/resourceInventoryLinux.js +610 -0
  59. package/dist/controller/runtime.js +629 -10
  60. package/dist/controller/runtimeEventInbox.js +564 -0
  61. package/dist/controller/runtimeEventProcessor.js +248 -0
  62. package/dist/controller/runtimeLaunchCoordinator.js +477 -0
  63. package/dist/controller/sessionNotify.js +121 -78
  64. package/dist/coordination/deadlineScheduler.js +15 -0
  65. package/dist/coordination/mailboxScheduler.js +108 -0
  66. package/dist/coordination/workMailbox.js +329 -0
  67. package/dist/coordination/workMailboxQueue.js +86 -0
  68. package/dist/core/controllerClient.js +19 -5
  69. package/dist/core/controllerEndpoint.js +37 -0
  70. package/dist/core/controllerServer.js +218 -10
  71. package/dist/core/protocol.js +6 -2
  72. package/dist/decision/decision.js +2 -1
  73. package/dist/doctor/doctor.js +681 -32
  74. package/dist/domain/validation.js +53 -0
  75. package/dist/errors/cliError.js +5 -3
  76. package/dist/event/taskEvent.js +7 -3
  77. package/dist/execution/codexThreadNaming.js +160 -0
  78. package/dist/execution/executionGroup.js +579 -0
  79. package/dist/executor/agentAdapter.js +255 -40
  80. package/dist/executor/agentConfigurationCatalog.js +326 -0
  81. package/dist/executor/agentConfigurationProbe.js +506 -0
  82. package/dist/executor/agentExecutor.js +625 -10
  83. package/dist/executor/codexConfigConflict.js +290 -0
  84. package/dist/executor/effectiveLaunch.js +340 -0
  85. package/dist/executor/executorRegistry.js +238 -36
  86. package/dist/executor/fileRoleLaunchPlanner.js +550 -40
  87. package/dist/executor/turnCompletion.js +126 -0
  88. package/dist/input/inputRequest.js +30 -9
  89. package/dist/integration/changeSet.js +36 -0
  90. package/dist/integration/checkResult.js +24 -0
  91. package/dist/integration/gitIntegrationService.js +695 -0
  92. package/dist/integration/integrationAttempt.js +142 -0
  93. package/dist/interaction/operatorPresentation.js +96 -0
  94. package/dist/lifecycle/canonicalLifecycleEvent.js +342 -0
  95. package/dist/lifecycle/exactRunTerminalization.js +572 -0
  96. package/dist/lifecycle/providerLifecycleMapping.js +190 -0
  97. package/dist/lifecycle/taskRoleSessionReset.js +124 -0
  98. package/dist/message/message.js +23 -7
  99. package/dist/milestone/milestone.js +2 -1
  100. package/dist/operator/operatorSessionHistory.js +124 -0
  101. package/dist/output/agentConfigurationPresentation.js +43 -0
  102. package/dist/output/rolePresentation.js +34 -10
  103. package/dist/output/terminal.js +8 -0
  104. package/dist/output/timePresentation.js +55 -0
  105. package/dist/profile/agentProfile.js +128 -0
  106. package/dist/repository/gitWorkspace.js +578 -24
  107. package/dist/repository/project.js +213 -0
  108. package/dist/repository/taskWorkspaceCoordinator.js +392 -0
  109. package/dist/repository/taskWorkspacePreparer.js +1688 -191
  110. package/dist/review/reviewConfig.js +11 -0
  111. package/dist/review/reviewRound.js +399 -0
  112. package/dist/review/taskFinalReviewContract.js +90 -0
  113. package/dist/role/role.js +124 -23
  114. package/dist/run/agentRun.js +155 -12
  115. package/dist/run/runIdentity.js +82 -0
  116. package/dist/runtime/exactControlPlane.js +472 -0
  117. package/dist/runtime/index.js +8 -0
  118. package/dist/runtime/lifecycleReservation.js +38 -0
  119. package/dist/runtime/ports.js +11 -0
  120. package/dist/runtime/preallocatedNativeSession.js +13 -0
  121. package/dist/runtime/promptEnvelope.js +30 -0
  122. package/dist/runtime/runtimeBinding.js +31 -0
  123. package/dist/runtime/runtimeOwner.js +14 -0
  124. package/dist/runtime/sessionLaunchRequest.js +62 -0
  125. package/dist/runtime/sessionTitle.js +54 -0
  126. package/dist/runtime/taskRuntimeIsolation.js +643 -0
  127. package/dist/runtime/tmuxAdapters.js +315 -0
  128. package/dist/runtime/turnCompletion.js +3 -0
  129. package/dist/runtime/validation.js +23 -0
  130. package/dist/scheduler/activeRoleRunDelivery.js +342 -32
  131. package/dist/scheduler/activeTaskProgress.js +63 -0
  132. package/dist/scheduler/leaderFailure.js +2 -1
  133. package/dist/scheduler/leaderWakeupProcessor.js +307 -66
  134. package/dist/scheduler/operatorInputNotificationProcessor.js +109 -46
  135. package/dist/scheduler/operatorNotification.js +44 -2
  136. package/dist/scheduler/ports.js +28 -1
  137. package/dist/scheduler/roleRunLiveness.js +131 -25
  138. package/dist/scheduler/roleRunStall.js +951 -0
  139. package/dist/scheduler/taskExecutionProjection.js +544 -0
  140. package/dist/scheduler/wakeupQueue.js +3 -0
  141. package/dist/setup/setupCommand.js +302 -52
  142. package/dist/storage/compatibleTaskStore.js +102 -0
  143. package/dist/storage/migration/baseline.js +78 -0
  144. package/dist/storage/migration/classifier.js +51 -0
  145. package/dist/storage/migration/compatibleCodec.js +53 -0
  146. package/dist/storage/migration/engine.js +147 -0
  147. package/dist/storage/migration/index.js +33 -0
  148. package/dist/storage/migration/planner.js +154 -0
  149. package/dist/storage/migration/productionRegistry.js +486 -0
  150. package/dist/storage/migration/registry.js +169 -0
  151. package/dist/storage/migration/report.js +54 -0
  152. package/dist/storage/migration/types.js +31 -0
  153. package/dist/storage/storageSchema.js +147 -123
  154. package/dist/storage/storageVersions.js +11 -0
  155. package/dist/storage/taskStore.js +1793 -197
  156. package/dist/storage/upgrade/homeClassification.js +156 -0
  157. package/dist/storage/upgrade/homeMigrationTarget.js +595 -0
  158. package/dist/storage/upgrade/offlineUpgradeInventory.js +315 -0
  159. package/dist/storage/upgrade/productionMigrationRegistry.js +6 -0
  160. package/dist/storage/upgrade/recordVersionScan.js +176 -0
  161. package/dist/storage/upgrade/recordVersions.js +159 -0
  162. package/dist/storage/upgrade/switchProgress.js +80 -0
  163. package/dist/storage/upgrade/upgradeOrchestrator.js +948 -0
  164. package/dist/storage/upgrade/upgradeReceipt.js +161 -0
  165. package/dist/storage/upgradeCoordination.js +186 -0
  166. package/dist/storage/upgradeFence.js +366 -0
  167. package/dist/task/task.js +132 -26
  168. package/dist/task/taskRecordReference.js +66 -0
  169. package/dist/tmux/commandExecutor.js +75 -2
  170. package/dist/tmux/tmuxManager.js +747 -49
  171. package/dist/version.js +23 -0
  172. package/dist/web/assets/assetManifest.js +62 -0
  173. package/dist/web/assets/client/app.js +631 -0
  174. package/dist/web/assets/client/components.js +605 -0
  175. package/dist/web/assets/client/dom.js +14 -0
  176. package/dist/web/assets/client/format.js +28 -0
  177. package/dist/web/assets/client/i18n.js +494 -0
  178. package/dist/web/assets/client/markdown.js +114 -0
  179. package/dist/web/assets/client/theme.js +32 -0
  180. package/dist/web/assets/client/view.js +458 -0
  181. package/dist/web/assets/fontData.js +12 -0
  182. package/dist/web/assets/fonts.js +12 -0
  183. package/dist/web/assets/shell.js +114 -0
  184. package/dist/web/assets/styles/cards.js +135 -0
  185. package/dist/web/assets/styles/layout.js +47 -0
  186. package/dist/web/assets/styles/markdown.js +29 -0
  187. package/dist/web/assets/styles/responsive.js +39 -0
  188. package/dist/web/assets/styles/tokens.js +101 -0
  189. package/dist/web/assets/styles/widgets.js +147 -0
  190. package/dist/web/tmuxWebTerminal.js +158 -0
  191. package/dist/web/webServer.js +463 -0
  192. package/dist/web/webSnapshot.js +148 -0
  193. package/dist/workItem/workItem.js +642 -23
  194. package/dist/workspace/gitChangeSetCapture.js +86 -0
  195. package/dist/workspace/workItemChangeSetManager.js +445 -0
  196. package/dist/worktree/managedWorkspace.js +202 -0
  197. package/docs/task-local-identity.md +62 -0
  198. package/i18n/README.zh-CN.md +406 -31
  199. package/package.json +10 -2
  200. package/skills/yui-leader/SKILL.md +601 -39
  201. package/skills/yui-operator/SKILL.md +255 -34
  202. package/skills/yui-reviewer/SKILL.md +57 -0
  203. package/skills/yui-worker/SKILL.md +214 -17
  204. package/dist/commands/repositoryCommands.js +0 -86
  205. package/dist/operator/operatorContext.js +0 -66
  206. package/dist/repository/repository.js +0 -55
  207. package/dist/scheduler/archivedTaskRuntime.js +0 -12
  208. package/dist/worktree/roleWorkspace.js +0 -62
@@ -1,86 +0,0 @@
1
- import { usageError } from "../errors/cliError.js";
2
- import { defaultTableWidth, renderTable } from "../output/table.js";
3
- import { NodeGitWorkspace } from "../repository/gitWorkspace.js";
4
- import { createRepository } from "../repository/repository.js";
5
- export async function runRepositoryCommand(args, store, options = {}) {
6
- const [command, ...rest] = args;
7
- if (command === "add")
8
- return addRepository(rest, store, options);
9
- if (command === "list")
10
- return listRepositories(rest, store);
11
- throw usageError(command === undefined
12
- ? "Repository command is required."
13
- : `Unknown command: repository ${command}`);
14
- }
15
- async function addRepository(args, store, options) {
16
- const usage = "Repository add usage: yui repository add <name> <path> [--base <ref>].";
17
- const parsed = parseAddArguments(args, usage);
18
- const git = options.git ?? new NodeGitWorkspace();
19
- const inspected = await git.inspect(parsed.path, parsed.baseRef ?? "HEAD");
20
- const repository = createRepository(store.nextRepositoryId(), parsed.name, inspected.root, parsed.baseRef ?? inspected.baseRef, (options.now ?? (() => new Date()))());
21
- if (store.listRepositories().some((entry) => entry.path === repository.path)) {
22
- throw usageError(`Repository path is already registered: ${repository.path}.`);
23
- }
24
- const created = store.createRepositoryIfAbsent(repository);
25
- if (created === null)
26
- throw usageError(`Repository already exists: ${repository.name}.`);
27
- return [
28
- `Added repository ${created.id}`,
29
- `Name: ${created.name}`,
30
- `Path: ${created.path}`,
31
- `Base: ${created.defaultBranch}`
32
- ].join("\n").concat("\n");
33
- }
34
- function listRepositories(args, store) {
35
- if (args.length !== 0) {
36
- throw usageError("Repository list usage: yui repository list.");
37
- }
38
- const repositories = store.listRepositories();
39
- if (repositories.length === 0)
40
- return "No repositories found.\n";
41
- return `${renderTable("Repositories", [
42
- { header: "Repository", minWidth: 10, maxWidth: 24 },
43
- { header: "Name", minWidth: 4, maxWidth: 28 },
44
- { header: "Path", minWidth: 8, maxWidth: 64 },
45
- { header: "Base", minWidth: 4, maxWidth: 24 }
46
- ], repositories.map((repository) => [
47
- repository.id,
48
- repository.name,
49
- repository.path,
50
- repository.defaultBranch
51
- ]), defaultTableWidth())}\n`;
52
- }
53
- function parseAddArguments(args, usage) {
54
- const positionals = [];
55
- let baseRef;
56
- for (let index = 0; index < args.length; index += 1) {
57
- const value = args[index];
58
- if (value === "--base") {
59
- if (baseRef !== undefined)
60
- throw usageError(`--base may only be provided once. ${usage}`);
61
- const next = args[index + 1];
62
- if (next === undefined || next.startsWith("--"))
63
- throw usageError(`--base is required. ${usage}`);
64
- baseRef = requireText(next, "--base");
65
- index += 1;
66
- continue;
67
- }
68
- if (value.startsWith("--"))
69
- throw usageError(`Unknown option: ${value}. ${usage}`);
70
- positionals.push(value);
71
- }
72
- if (positionals.length !== 2)
73
- throw usageError(usage);
74
- return {
75
- name: requireText(positionals[0], "Repository name"),
76
- path: requireText(positionals[1], "Repository path"),
77
- ...(baseRef === undefined ? {} : { baseRef })
78
- };
79
- }
80
- function requireText(value, label) {
81
- const normalized = value.trim();
82
- if (normalized.length === 0 || normalized.includes("\0")) {
83
- throw usageError(`${label} is required.`);
84
- }
85
- return normalized;
86
- }
@@ -1,66 +0,0 @@
1
- import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
- import { join } from "node:path";
3
- import { SYSTEM_OPERATOR_ROLE } from "../role/systemRoles.js";
4
- /**
5
- * Prepares durable Operator instructions without turning them into Codex's
6
- * positional first prompt. Interactive Operator entry must open at the native
7
- * Agent composer; launch code can pass systemPrompt through an adapter-native
8
- * instruction channel when one is available.
9
- */
10
- export function prepareGlobalRoleLaunch(role, options = {}) {
11
- const args = [...(role.args ?? [])];
12
- const base = mergeEnv(options.baseEnv, role.env ?? {});
13
- if (role.name !== SYSTEM_OPERATOR_ROLE || options.yuiHome === undefined) {
14
- return { args, env: base };
15
- }
16
- const contextPath = writeOperatorContext(options.yuiHome, role.workspace);
17
- return {
18
- args,
19
- env: mergeEnv(base, {
20
- YUI_HOME: options.yuiHome,
21
- YUI_ROLE: role.name,
22
- YUI_WORKSPACE: role.workspace,
23
- YUI_OPERATOR_CONTEXT: contextPath
24
- }),
25
- systemPrompt: renderOperatorLaunchInstruction(contextPath),
26
- contextPath
27
- };
28
- }
29
- export function writeOperatorContext(yuiHome, workspace) {
30
- const operatorDir = join(yuiHome, "operator");
31
- const contextPath = join(operatorDir, "YUI_OPERATOR.md");
32
- mkdirSync(operatorDir, { recursive: true });
33
- writeFileSync(contextPath, `${renderOperatorContext(yuiHome, workspace)}\n`, { mode: 0o600 });
34
- return contextPath;
35
- }
36
- export function renderOperatorLaunchInstruction(contextPath) {
37
- return [
38
- `Read and follow the Yui Operator instructions in ${contextPath}.`,
39
- "Manage Yui through its CLI; do not perform Task work."
40
- ].join(" ");
41
- }
42
- function renderOperatorContext(yuiHome, workspace) {
43
- return `${readOperatorSkill()}
44
-
45
- # Yui Operator runtime
46
-
47
- You are the Yui Operator. Act as the user's CLI proxy and manage Yui without performing Task work.
48
-
49
- Rules:
50
-
51
- - Use Yui commands to create and inspect Tasks, manage global and Task Roles, choose Agents, and submit user input.
52
- - Do not edit files under YUI_HOME directly.
53
- - Every Task has a protected leader Role; Operator is global and never acts as a Task Leader or Worker.
54
- - Keep native Agent session interaction intact. Do not emulate Agent slash commands or terminal input.
55
-
56
- Environment:
57
-
58
- - YUI_HOME=${yuiHome}
59
- - YUI_WORKSPACE=${workspace}`;
60
- }
61
- function readOperatorSkill() {
62
- return readFileSync(new URL("../../skills/yui-operator/SKILL.md", import.meta.url), "utf8").trim();
63
- }
64
- function mergeEnv(baseEnv = process.env, roleEnv) {
65
- return { ...baseEnv, ...roleEnv };
66
- }
@@ -1,55 +0,0 @@
1
- import { resolve } from "node:path";
2
- export function createRepository(id, name, path, defaultBranch, now) {
3
- const timestamp = now.toISOString();
4
- return validateRepository({
5
- schemaVersion: 1,
6
- id: requireIdentity(id, "Repository id"),
7
- name: requireText(name, "Repository name"),
8
- path: resolve(requireText(path, "Repository path")),
9
- defaultBranch: requireGitRef(defaultBranch),
10
- createdAt: timestamp,
11
- updatedAt: timestamp
12
- });
13
- }
14
- export function validateRepository(repository) {
15
- if (repository.schemaVersion !== 1) {
16
- throw new Error("Repository must use schemaVersion 1.");
17
- }
18
- requireIdentity(repository.id, "Repository id");
19
- requireText(repository.name, "Repository name");
20
- if (resolve(requireText(repository.path, "Repository path")) !== repository.path) {
21
- throw new Error("Repository path must be absolute and normalized.");
22
- }
23
- requireGitRef(repository.defaultBranch);
24
- requireTimestamp(repository.createdAt, "Repository createdAt");
25
- requireTimestamp(repository.updatedAt, "Repository updatedAt");
26
- return repository;
27
- }
28
- function requireIdentity(value, label) {
29
- const normalized = requireText(value, label);
30
- if (["__proto__", "prototype", "constructor", ".", ".."].includes(normalized)
31
- || /[\/\\\0]/.test(normalized)) {
32
- throw new Error(`${label} is invalid.`);
33
- }
34
- return normalized;
35
- }
36
- function requireGitRef(value) {
37
- const ref = requireText(value, "Repository base ref");
38
- if (ref.startsWith("-") || /[\r\n]/.test(ref)) {
39
- throw new Error("Repository base ref is invalid.");
40
- }
41
- return ref;
42
- }
43
- function requireText(value, label) {
44
- if (typeof value !== "string" || value.includes("\0"))
45
- throw new Error(`${label} is invalid.`);
46
- const normalized = value.trim();
47
- if (normalized.length === 0)
48
- throw new Error(`${label} is required.`);
49
- return normalized;
50
- }
51
- function requireTimestamp(value, label) {
52
- if (typeof value !== "string" || !Number.isFinite(Date.parse(value))) {
53
- throw new Error(`${label} is invalid.`);
54
- }
55
- }
@@ -1,12 +0,0 @@
1
- /** Stops archived Task processes at the tmux boundary and closes their sessions. */
2
- export async function stopArchivedTaskRuntimes(store, delivery, now) {
3
- const stopped = [];
4
- for (const task of store.listTasks()) {
5
- if (task.status !== "archived")
6
- continue;
7
- if (await delivery.stopTask(task.id))
8
- stopped.push(task.id);
9
- store.saveArchivedTaskStopped(task.id, now);
10
- }
11
- return stopped;
12
- }
@@ -1,62 +0,0 @@
1
- import { resolve } from "node:path";
2
- export function createRoleWorkspace(input, now) {
3
- const timestamp = now.toISOString();
4
- return validateRoleWorkspace({
5
- schemaVersion: 1,
6
- taskId: requireIdentity(input.taskId, "Task id"),
7
- roleName: requireIdentity(input.roleName, "Role name"),
8
- repositoryId: requireIdentity(input.repositoryId, "Repository id"),
9
- path: resolve(requireText(input.path, "Role workspace path")),
10
- branch: requireText(input.branch, "Role workspace branch"),
11
- baseRef: requireText(input.baseRef, "Role workspace base ref"),
12
- baseCommit: requireCommit(input.baseCommit),
13
- createdAt: timestamp,
14
- updatedAt: timestamp
15
- });
16
- }
17
- export function validateRoleWorkspace(workspace) {
18
- if (workspace.schemaVersion !== 1) {
19
- throw new Error("RoleWorkspace must use schemaVersion 1.");
20
- }
21
- requireIdentity(workspace.taskId, "Task id");
22
- requireIdentity(workspace.roleName, "Role name");
23
- requireIdentity(workspace.repositoryId, "Repository id");
24
- if (resolve(requireText(workspace.path, "Role workspace path")) !== workspace.path) {
25
- throw new Error("Role workspace path must be absolute and normalized.");
26
- }
27
- requireText(workspace.branch, "Role workspace branch");
28
- requireText(workspace.baseRef, "Role workspace base ref");
29
- requireCommit(workspace.baseCommit);
30
- requireTimestamp(workspace.createdAt, "RoleWorkspace createdAt");
31
- requireTimestamp(workspace.updatedAt, "RoleWorkspace updatedAt");
32
- return workspace;
33
- }
34
- function requireIdentity(value, label) {
35
- const identity = requireText(value, label);
36
- if ([".", "..", "__proto__", "prototype", "constructor"].includes(identity)
37
- || /[\/\\\0]/.test(identity)) {
38
- throw new Error(`${label} is invalid.`);
39
- }
40
- return identity;
41
- }
42
- function requireCommit(value) {
43
- const commit = requireText(value, "Role workspace base commit").toLowerCase();
44
- if (!/^[a-f0-9]{40}(?:[a-f0-9]{24})?$/.test(commit)) {
45
- throw new Error("Role workspace base commit is invalid.");
46
- }
47
- return commit;
48
- }
49
- function requireText(value, label) {
50
- if (typeof value !== "string" || value.includes("\0")) {
51
- throw new Error(`${label} is invalid.`);
52
- }
53
- const normalized = value.trim();
54
- if (normalized.length === 0)
55
- throw new Error(`${label} is required.`);
56
- return normalized;
57
- }
58
- function requireTimestamp(value, label) {
59
- if (typeof value !== "string" || !Number.isFinite(Date.parse(value))) {
60
- throw new Error(`${label} is invalid.`);
61
- }
62
- }