huddle60 0.1.0 → 0.1.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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/entry/action.ts", "../src/adapters/git-evidence.ts", "../src/core/canonical.ts", "../src/core/errors.ts", "../src/adapters/github.ts", "../src/adapters/memory.ts", "../src/core/policy.ts", "../src/ports.ts", "../src/core/issue-form.ts", "../src/core/vocabulary.ts", "../src/core/baseline.ts", "../src/core/command.ts", "../src/core/decision.ts", "../src/core/pr-block.ts", "../src/core/plan.ts", "../src/core/render.ts", "../src/workflow/service.ts"],
4
- "sourcesContent": ["import { appendFile, readFile } from \"node:fs/promises\";\nimport { GitBranchEvidenceStore } from \"../adapters/git-evidence.js\";\nimport { connectRepository, octokitFromToken } from \"../adapters/github.js\";\nimport { createJsonLogger } from \"../adapters/memory.js\";\nimport { POLICY_PATH, parsePolicy } from \"../core/policy.js\";\nimport { systemClock } from \"../ports.js\";\nimport { WorkflowService } from \"../workflow/service.js\";\n\n/** Runs inside GitHub Actions. Never checks out or executes pull request code. */\nasync function main(): Promise<void> {\n const eventName = requireEnv(\"GITHUB_EVENT_NAME\");\n const payload = JSON.parse(await readFile(requireEnv(\"GITHUB_EVENT_PATH\"), \"utf8\")) as {\n action?: string;\n issue?: { number: number; pull_request?: unknown };\n comment?: { id: number };\n pull_request?: { number: number };\n sender?: { type?: string };\n };\n const [owner, repo] = requireEnv(\"GITHUB_REPOSITORY\").split(\"/\") as [string, string];\n const logger = createJsonLogger({ component: \"ai-dlc-action\", event: eventName });\n const octokit = octokitFromToken(requireEnv(\"AI_DLC_TOKEN\"));\n const github = await connectRepository(octokit, owner, repo);\n const policySource = await github.readFile(POLICY_PATH, await github.getDefaultBranch());\n const branch = policySource ? parsePolicy(policySource).evidence.branch : \"ai-dlc-evidence\";\n const workflow = new WorkflowService({\n github,\n evidence: new GitBranchEvidenceStore(octokit, owner, repo, branch),\n clock: systemClock,\n logger,\n enabled: process.env.AI_DLC_ENABLED !== \"false\",\n });\n\n if (eventName === \"issue_comment\") {\n if (\n !payload.issue ||\n payload.issue.pull_request ||\n !payload.comment ||\n payload.sender?.type === \"Bot\"\n )\n return;\n const action = payload.action as \"created\" | \"edited\" | \"deleted\";\n await workflow.handleComment(payload.issue.number, payload.comment.id, action);\n return;\n }\n if (eventName === \"pull_request_target\" && payload.pull_request) {\n const result = await workflow.checkPullRequest(payload.pull_request.number);\n await summary([\n `### ai-dlc/baseline: ${result.state}`,\n \"\",\n result.description,\n ...result.details.map((line) => `> ${line}`),\n ]);\n return;\n }\n logger.info(\"event ignored\");\n}\n\nfunction requireEnv(name: string): string {\n const value = process.env[name];\n if (!value) throw new Error(`Missing environment variable ${name}`);\n return value;\n}\n\nasync function summary(lines: string[]): Promise<void> {\n const file = process.env.GITHUB_STEP_SUMMARY;\n if (file) await appendFile(file, `${lines.join(\"\\n\")}\\n`);\n}\n\nmain().catch((error: unknown) => {\n process.stderr.write(\n `ai-dlc action failed: ${error instanceof Error ? error.stack : String(error)}\\n`,\n );\n process.exitCode = 1;\n});\n", "import { setTimeout as delay } from \"node:timers/promises\";\nimport { canonicalJson } from \"../core/canonical.js\";\nimport { AiDlcError } from \"../core/errors.js\";\nimport type { EvidenceStore } from \"../ports.js\";\nimport { isStatus, type GitHubClient } from \"./github.js\";\n\nconst MAX_ATTEMPTS = 5;\n\n/**\n * Append-only JSON files on a dedicated branch, written through the Git Data API.\n * Every file has a unique path, so concurrent writers only race on the branch ref\n * and simply retry on a non-fast-forward update.\n */\nexport class GitBranchEvidenceStore implements EvidenceStore {\n constructor(\n private readonly octokit: GitHubClient,\n private readonly owner: string,\n private readonly repo: string,\n private readonly branch: string,\n ) {}\n\n private get base() {\n return { owner: this.owner, repo: this.repo };\n }\n\n private async readAt<T>(path: string, ref: string): Promise<T | null> {\n try {\n const { data } = await this.octokit.rest.repos.getContent({ ...this.base, path, ref });\n if (Array.isArray(data) || data.type !== \"file\" || !(\"content\" in data)) return null;\n return JSON.parse(Buffer.from(data.content, \"base64\").toString(\"utf8\")) as T;\n } catch (error) {\n if (isStatus(error, 404)) return null;\n throw error;\n }\n }\n\n async read<T>(path: string): Promise<T | null> {\n return this.readAt<T>(path, this.branch);\n }\n\n async list(prefix: string): Promise<string[]> {\n const directory = prefix.replace(/\\/+$/u, \"\");\n try {\n const { data } = await this.octokit.rest.repos.getContent({\n ...this.base,\n path: directory,\n ref: this.branch,\n });\n if (!Array.isArray(data)) return [];\n return data\n .filter((entry) => entry.type === \"file\")\n .map((entry) => entry.path)\n .sort();\n } catch (error) {\n if (isStatus(error, 404)) return [];\n throw error;\n }\n }\n\n async write(path: string, value: unknown): Promise<\"created\" | \"unchanged\"> {\n const canonical = canonicalJson(value);\n const content = `${JSON.stringify(JSON.parse(canonical), null, 2)}\\n`;\n for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt += 1) {\n const head = await this.headCommit();\n const existing = await this.readAt<unknown>(path, head.sha);\n if (existing !== null) {\n if (canonicalJson(existing) === canonical) return \"unchanged\";\n throw new AiDlcError(\n \"E_CONFLICT\",\n `Evidence already exists with different content at ${path}.`,\n );\n }\n const blob = await this.octokit.rest.git.createBlob({\n ...this.base,\n content,\n encoding: \"utf-8\",\n });\n const tree = await this.octokit.rest.git.createTree({\n ...this.base,\n base_tree: head.treeSha,\n tree: [{ path, mode: \"100644\", type: \"blob\", sha: blob.data.sha }],\n });\n const commit = await this.octokit.rest.git.createCommit({\n ...this.base,\n message: `ai-dlc: add ${path}`,\n tree: tree.data.sha,\n parents: [head.sha],\n });\n try {\n await this.octokit.rest.git.updateRef({\n ...this.base,\n ref: `heads/${this.branch}`,\n sha: commit.data.sha,\n force: false,\n });\n return \"created\";\n } catch (error) {\n if (!isStatus(error, 409, 422) || attempt === MAX_ATTEMPTS) throw error;\n await delay(250 * 2 ** attempt);\n }\n }\n throw new AiDlcError(\"E_GITHUB_API\", `Could not write ${path} after ${MAX_ATTEMPTS} attempts.`);\n }\n\n private async headCommit(): Promise<{ sha: string; treeSha: string }> {\n try {\n const ref = await this.octokit.rest.git.getRef({ ...this.base, ref: `heads/${this.branch}` });\n const commit = await this.octokit.rest.git.getCommit({\n ...this.base,\n commit_sha: ref.data.object.sha,\n });\n return { sha: commit.data.sha, treeSha: commit.data.tree.sha };\n } catch (error) {\n if (isStatus(error, 404)) {\n throw new AiDlcError(\n \"E_GITHUB_API\",\n `Evidence branch \\`${this.branch}\\` does not exist. Run \\`huddle60 init\\`.`,\n );\n }\n throw error;\n }\n }\n\n /** Creates the evidence branch as an orphan commit. Safe to call when it already exists. */\n async initialize(): Promise<\"created\" | \"exists\"> {\n try {\n await this.octokit.rest.git.getRef({ ...this.base, ref: `heads/${this.branch}` });\n return \"exists\";\n } catch (error) {\n if (!isStatus(error, 404)) throw error;\n }\n const readme = [\n \"# AI-DLC evidence\",\n \"\",\n \"Append-only baselines, decision receipts and revocations written by the AI-DLC GitHub App.\",\n \"Do not edit or force-push this branch; protect it with a ruleset.\",\n \"\",\n ].join(\"\\n\");\n const blob = await this.octokit.rest.git.createBlob({\n ...this.base,\n content: readme,\n encoding: \"utf-8\",\n });\n const tree = await this.octokit.rest.git.createTree({\n ...this.base,\n tree: [{ path: \"README.md\", mode: \"100644\", type: \"blob\", sha: blob.data.sha }],\n });\n const commit = await this.octokit.rest.git.createCommit({\n ...this.base,\n message: \"ai-dlc: initialize evidence branch\",\n tree: tree.data.sha,\n parents: [],\n });\n await this.octokit.rest.git.createRef({\n ...this.base,\n ref: `refs/heads/${this.branch}`,\n sha: commit.data.sha,\n });\n return \"created\";\n }\n}\n", "import { createHash } from \"node:crypto\";\n\nexport const CANONICAL_VERSION = 1;\n\nexport type JsonValue =\n null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue };\n\n/**\n * Normalizes free text so that cosmetic edits do not change a hash:\n * Unicode NFC, LF line endings, no trailing whitespace, no leading/trailing blank lines.\n */\nexport function normalizeText(value: string): string {\n return value\n .normalize(\"NFC\")\n .replace(/\\r\\n?/g, \"\\n\")\n .split(\"\\n\")\n .map((line) => line.replace(/[ \\t]+$/u, \"\"))\n .join(\"\\n\")\n .replace(/^\\n+/u, \"\")\n .replace(/\\n+$/u, \"\");\n}\n\nfunction normalizeDeep(value: unknown, path: string): JsonValue {\n if (value === null) return null;\n if (typeof value === \"string\") return normalizeText(value);\n if (typeof value === \"boolean\") return value;\n if (typeof value === \"number\") {\n if (!Number.isFinite(value)) throw new TypeError(`Non-finite number at ${path}`);\n return value;\n }\n if (Array.isArray(value))\n return value.map((item, index) => normalizeDeep(item, `${path}[${index}]`));\n if (typeof value === \"object\") {\n const result: { [key: string]: JsonValue } = {};\n for (const [key, item] of Object.entries(value as Record<string, unknown>)) {\n if (item === undefined) continue;\n result[key] = normalizeDeep(item, `${path}.${key}`);\n }\n return result;\n }\n throw new TypeError(`Unsupported value of type ${typeof value} at ${path}`);\n}\n\n/**\n * RFC 8785 (JCS) serialization. Object keys are sorted by UTF-16 code units and\n * primitives use ECMAScript JSON serialization, which is what JCS specifies.\n */\nexport function canonicalJson(value: unknown): string {\n return serialize(normalizeDeep(value, \"$\"));\n}\n\nfunction serialize(value: JsonValue): string {\n if (value === null || typeof value !== \"object\") return JSON.stringify(value);\n if (Array.isArray(value)) return `[${value.map(serialize).join(\",\")}]`;\n const keys = Object.keys(value).sort();\n return `{${keys.map((key) => `${JSON.stringify(key)}:${serialize(value[key] as JsonValue)}`).join(\",\")}}`;\n}\n\nexport function sha256(text: string): string {\n return `sha256:${createHash(\"sha256\").update(text, \"utf8\").digest(\"hex\")}`;\n}\n\n/** Hash of a payload, ignoring its own `contentHash` field. */\nexport function contentHash(payload: Record<string, unknown>): string {\n const { contentHash: _ignored, ...rest } = payload;\n return sha256(canonicalJson(rest));\n}\n\nexport function shortHash(hash: string, length = 12): string {\n return hash.replace(/^sha256:/u, \"\").slice(0, length);\n}\n", "export const ErrorCodes = [\n \"E_POLICY_INVALID\",\n \"E_SYNTAX\",\n \"E_ROLE\",\n \"E_FORM\",\n \"E_HASH_MISMATCH\",\n \"E_BASELINE_NOT_FOUND\",\n \"E_NOT_APPROVED\",\n \"E_NOT_READY\",\n \"E_DEPENDENCY_OPEN\",\n \"E_BUILD_INVALID\",\n \"E_CONFLICT\",\n \"E_DECISION_NOT_FOUND\",\n \"E_GITHUB_API\",\n \"E_GEMINI\",\n \"E_PLAN_SCHEMA\",\n \"E_PLAN_NOT_FOUND\",\n \"E_PLAN_STALE\",\n \"E_PLAN_LIMIT\",\n \"E_PLAN_BLOCKED\",\n \"E_PLAN_PARTIAL\",\n \"E_PLANNER_DISABLED\",\n \"E_NOT_REQUEST\",\n \"E_PR_BLOCK\",\n \"E_STALE\",\n \"E_SENSITIVE_PATH\",\n \"E_CLOSING_KEYWORD\",\n \"E_WRONG_KIND\",\n \"E_CONFIG\",\n] as const;\n\nexport type ErrorCode = (typeof ErrorCodes)[number];\n\n/** An expected, user-facing failure. The message must be safe to post on GitHub. */\nexport class AiDlcError extends Error {\n readonly code: ErrorCode;\n\n constructor(code: ErrorCode, message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = \"AiDlcError\";\n this.code = code;\n }\n}\n\nexport function isAiDlcError(error: unknown): error is AiDlcError {\n return error instanceof AiDlcError;\n}\n", "import { createAppAuth } from \"@octokit/auth-app\";\nimport { retry } from \"@octokit/plugin-retry\";\nimport { Octokit } from \"@octokit/rest\";\nimport { AiDlcError } from \"../core/errors.js\";\nimport type {\n Actor,\n CommentData,\n CommitState,\n IssueData,\n LocalGitHubPort,\n PullRequestData,\n RepoRef,\n WorkflowRunData,\n} from \"../ports.js\";\n\nconst RetryingOctokit = Octokit.plugin(retry);\nexport type GitHubClient = InstanceType<typeof RetryingOctokit>;\n\nconst USER_AGENT = \"huddle60/0.1.0\";\n\nexport function octokitFromToken(token: string): GitHubClient {\n return new RetryingOctokit({ auth: token, userAgent: USER_AGENT });\n}\n\nexport function octokitForInstallation(\n appId: string,\n privateKey: string,\n installationId: number,\n): GitHubClient {\n return new RetryingOctokit({\n authStrategy: createAppAuth,\n auth: { appId, privateKey, installationId },\n userAgent: USER_AGENT,\n });\n}\n\nexport function isStatus(error: unknown, ...statuses: number[]): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n statuses.includes((error as { status?: number }).status ?? -1)\n );\n}\n\ninterface RawUser {\n id: number;\n login: string;\n type: string;\n}\n\ninterface RawIssue {\n id: number;\n node_id: string;\n number: number;\n title: string;\n body?: string | null;\n state: string;\n state_reason?: string | null;\n labels: Array<string | { name?: string }>;\n user: RawUser | null;\n pull_request?: unknown;\n}\n\nfunction toActor(user: RawUser | null): IssueData[\"author\"] {\n return user\n ? { id: user.id, login: user.login, type: user.type }\n : { id: 0, login: \"ghost\", type: \"User\" };\n}\n\nfunction toIssue(raw: RawIssue): IssueData {\n return {\n id: raw.id,\n nodeId: raw.node_id,\n number: raw.number,\n title: raw.title,\n body: raw.body ?? \"\",\n state: raw.state === \"closed\" ? \"closed\" : \"open\",\n stateReason: raw.state_reason ?? null,\n labels: raw.labels\n .map((label) => (typeof label === \"string\" ? label : (label.name ?? \"\")))\n .filter(Boolean),\n author: toActor(raw.user),\n isPullRequest: raw.pull_request !== undefined && raw.pull_request !== null,\n };\n}\n\nexport async function connectRepository(\n octokit: GitHubClient,\n owner: string,\n repo: string,\n): Promise<OctokitGitHub> {\n const { data } = await octokit.rest.repos.get({ owner, repo });\n return new OctokitGitHub(octokit, { owner, repo, repositoryId: data.id }, data.default_branch);\n}\n\nexport class OctokitGitHub implements LocalGitHubPort {\n private readonly projectIds = new Map<string, string>();\n\n constructor(\n readonly octokit: GitHubClient,\n readonly repo: RepoRef,\n private defaultBranch?: string,\n ) {}\n\n private get base() {\n return { owner: this.repo.owner, repo: this.repo.repo };\n }\n\n async getDefaultBranch(): Promise<string> {\n if (!this.defaultBranch) {\n const { data } = await this.octokit.rest.repos.get(this.base);\n this.defaultBranch = data.default_branch;\n }\n return this.defaultBranch;\n }\n\n async readFile(path: string, ref?: string): Promise<string | null> {\n try {\n const { data } = await this.octokit.rest.repos.getContent({\n ...this.base,\n path,\n ...(ref ? { ref } : {}),\n });\n if (Array.isArray(data) || data.type !== \"file\" || !(\"content\" in data)) return null;\n return Buffer.from(data.content, \"base64\").toString(\"utf8\");\n } catch (error) {\n if (isStatus(error, 404)) return null;\n throw error;\n }\n }\n\n async getIssue(number: number): Promise<IssueData> {\n try {\n const { data } = await this.octokit.rest.issues.get({ ...this.base, issue_number: number });\n return toIssue(data as RawIssue);\n } catch (error) {\n if (isStatus(error, 404, 410))\n throw new AiDlcError(\"E_GITHUB_API\", `Issue #${number} was not found.`);\n throw error;\n }\n }\n\n async getComment(id: number): Promise<CommentData | null> {\n try {\n const { data } = await this.octokit.rest.issues.getComment({ ...this.base, comment_id: id });\n return { id: data.id, body: data.body ?? \"\", author: toActor(data.user as RawUser | null) };\n } catch (error) {\n if (isStatus(error, 404)) return null;\n throw error;\n }\n }\n\n async createIssue(input: { title: string; body: string; labels: string[] }): Promise<IssueData> {\n const { data } = await this.octokit.rest.issues.create({ ...this.base, ...input });\n return toIssue(data as RawIssue);\n }\n\n async listIssuesWithLabel(label: string): Promise<IssueData[]> {\n const items = await this.octokit.paginate(this.octokit.rest.issues.listForRepo, {\n ...this.base,\n labels: label,\n state: \"all\",\n per_page: 100,\n });\n return (items as RawIssue[]).map(toIssue).filter((issue) => !issue.isPullRequest);\n }\n\n async addLabels(issueNumber: number, labels: string[]): Promise<void> {\n await this.octokit.rest.issues.addLabels({ ...this.base, issue_number: issueNumber, labels });\n }\n\n async removeLabel(issueNumber: number, label: string): Promise<void> {\n try {\n await this.octokit.rest.issues.removeLabel({\n ...this.base,\n issue_number: issueNumber,\n name: label,\n });\n } catch (error) {\n if (!isStatus(error, 404)) throw error;\n }\n }\n\n async upsertComment(issueNumber: number, marker: string, body: string): Promise<void> {\n const comments = await this.octokit.paginate(this.octokit.rest.issues.listComments, {\n ...this.base,\n issue_number: issueNumber,\n per_page: 100,\n });\n // Only our own bot comments are updated; users could paste a marker into theirs.\n const existing = comments.find(\n (comment) => comment.user?.type === \"Bot\" && (comment.body ?? \"\").includes(marker),\n );\n const text = body.includes(marker) ? body : `${body}\\n${marker}`;\n if (existing) {\n await this.octokit.rest.issues.updateComment({\n ...this.base,\n comment_id: existing.id,\n body: text,\n });\n } else {\n await this.octokit.rest.issues.createComment({\n ...this.base,\n issue_number: issueNumber,\n body: text,\n });\n }\n }\n\n async closeIssue(issueNumber: number, reason: \"completed\" | \"not_planned\"): Promise<void> {\n await this.octokit.rest.issues.update({\n ...this.base,\n issue_number: issueNumber,\n state: \"closed\",\n state_reason: reason,\n });\n }\n\n async addSubIssue(parentNumber: number, childId: number): Promise<\"linked\" | \"unsupported\"> {\n try {\n await this.octokit.request(\"POST /repos/{owner}/{repo}/issues/{issue_number}/sub_issues\", {\n ...this.base,\n issue_number: parentNumber,\n sub_issue_id: childId,\n });\n return \"linked\";\n } catch (error) {\n if (isStatus(error, 404)) return \"unsupported\";\n throw error;\n }\n }\n\n private async projectId(owner: string, number: number): Promise<string> {\n const key = `${owner}/${number}`;\n const cached = this.projectIds.get(key);\n if (cached) return cached;\n const query = `query($owner: String!, $number: Int!) {\n organization(login: $owner) { projectV2(number: $number) { id } }\n }`;\n let id: string | undefined;\n try {\n const result = await this.octokit.graphql<{\n organization: { projectV2: { id: string } | null } | null;\n }>(query, { owner, number });\n id = result.organization?.projectV2?.id;\n } catch {\n const userQuery = `query($owner: String!, $number: Int!) { user(login: $owner) { projectV2(number: $number) { id } } }`;\n const result = await this.octokit.graphql<{\n user: { projectV2: { id: string } | null } | null;\n }>(userQuery, { owner, number });\n id = result.user?.projectV2?.id;\n }\n if (!id)\n throw new AiDlcError(\"E_GITHUB_API\", `Project ${key} was not found or is not accessible.`);\n this.projectIds.set(key, id);\n return id;\n }\n\n async addToProject(\n project: { owner: string; number: number },\n contentNodeId: string,\n ): Promise<void> {\n const projectId = await this.projectId(project.owner, project.number);\n await this.octokit.graphql(\n `mutation($projectId: ID!, $contentId: ID!) {\n addProjectV2ItemById(input: { projectId: $projectId, contentId: $contentId }) { item { id } }\n }`,\n { projectId, contentId: contentNodeId },\n );\n }\n\n async getPullRequest(number: number): Promise<PullRequestData> {\n const { data } = await this.octokit.rest.pulls.get({ ...this.base, pull_number: number });\n return {\n number: data.number,\n body: data.body ?? \"\",\n headSha: data.head.sha,\n labels: data.labels.map((label) => label.name),\n };\n }\n\n async listPullRequestFiles(number: number): Promise<string[]> {\n const files = await this.octokit.paginate(this.octokit.rest.pulls.listFiles, {\n ...this.base,\n pull_number: number,\n per_page: 100,\n });\n return files.flatMap((file) =>\n file.previous_filename ? [file.filename, file.previous_filename] : [file.filename],\n );\n }\n\n async setCommitStatus(\n sha: string,\n status: { state: CommitState; context: string; description: string },\n ): Promise<void> {\n await this.octokit.rest.repos.createCommitStatus({ ...this.base, sha, ...status });\n }\n\n async getWorkflowRun(runId: number): Promise<WorkflowRunData | null> {\n try {\n const { data } = await this.octokit.rest.actions.getWorkflowRun({\n ...this.base,\n run_id: runId,\n });\n return toRun(data);\n } catch (error) {\n if (isStatus(error, 404)) return null;\n throw error;\n }\n }\n\n async viewer(): Promise<Actor> {\n const { data } = await this.octokit.rest.users.getAuthenticated();\n return { id: data.id, login: data.login, type: data.type };\n }\n\n async listOpenIssuesWithLabel(label: string): Promise<IssueData[]> {\n const items = await this.octokit.paginate(this.octokit.rest.issues.listForRepo, {\n ...this.base,\n labels: label,\n state: \"open\",\n per_page: 100,\n });\n return (items as RawIssue[]).map(toIssue).filter((issue) => !issue.isPullRequest);\n }\n\n async createComment(issueNumber: number, body: string): Promise<CommentData> {\n const { data } = await this.octokit.rest.issues.createComment({\n ...this.base,\n issue_number: issueNumber,\n body,\n });\n return { id: data.id, body: data.body ?? \"\", author: toActor(data.user as RawUser | null) };\n }\n\n async findBotComment(issueNumber: number, marker: string): Promise<CommentData | null> {\n const comments = await this.octokit.paginate(this.octokit.rest.issues.listComments, {\n ...this.base,\n issue_number: issueNumber,\n per_page: 100,\n });\n const found = comments\n .filter((comment) => comment.user?.type === \"Bot\" && (comment.body ?? \"\").includes(marker))\n .at(-1);\n return found\n ? { id: found.id, body: found.body ?? \"\", author: toActor(found.user as RawUser | null) }\n : null;\n }\n\n async listSuccessfulRuns(\n workflowPath: string,\n branch: string,\n limit: number,\n ): Promise<WorkflowRunData[]> {\n try {\n const { data } = await this.octokit.rest.actions.listWorkflowRuns({\n ...this.base,\n workflow_id: workflowPath.split(\"/\").pop() ?? workflowPath,\n branch,\n event: \"push\",\n status: \"success\",\n per_page: limit,\n });\n return data.workflow_runs.map(toRun);\n } catch (error) {\n if (isStatus(error, 404)) return [];\n throw error;\n }\n }\n\n async ensureLabel(label: {\n name: string;\n color: string;\n description: string;\n }): Promise<\"created\" | \"exists\"> {\n try {\n await this.octokit.rest.issues.createLabel({ ...this.base, ...label });\n return \"created\";\n } catch (error) {\n if (isStatus(error, 422)) return \"exists\";\n throw error;\n }\n }\n}\n\ninterface RawRun {\n id: number;\n run_attempt?: number;\n path: string;\n event: string;\n head_branch: string | null;\n head_sha: string;\n status: string | null;\n conclusion: string | null;\n repository: { id: number };\n}\n\nfunction toRun(data: RawRun): WorkflowRunData {\n return {\n id: data.id,\n runAttempt: data.run_attempt ?? 1,\n path: data.path.split(\"@\")[0] ?? data.path,\n event: data.event,\n headBranch: data.head_branch,\n headSha: data.head_sha,\n status: data.status,\n conclusion: data.conclusion,\n repositoryId: data.repository.id,\n };\n}\n", "import { canonicalJson } from \"../core/canonical.js\";\nimport { AiDlcError } from \"../core/errors.js\";\nimport type { PlanRecord } from \"../core/plan.js\";\nimport type { CreationLedger, EvidenceStore, Logger, PlanStore } from \"../ports.js\";\n\nexport class MemoryEvidenceStore implements EvidenceStore {\n readonly files = new Map<string, string>();\n\n async read<T>(path: string): Promise<T | null> {\n const value = this.files.get(path);\n return value === undefined ? null : (JSON.parse(value) as T);\n }\n\n async write(path: string, value: unknown): Promise<\"created\" | \"unchanged\"> {\n const serialized = canonicalJson(value);\n const existing = this.files.get(path);\n if (existing === undefined) {\n this.files.set(path, serialized);\n return \"created\";\n }\n if (existing === serialized) return \"unchanged\";\n throw new AiDlcError(\n \"E_CONFLICT\",\n `Evidence already exists with different content at ${path}.`,\n );\n }\n\n async list(prefix: string): Promise<string[]> {\n return [...this.files.keys()].filter((path) => path.startsWith(prefix)).sort();\n }\n}\n\nexport class MemoryPlanStore implements PlanStore {\n readonly deliveries = new Set<string>();\n readonly plans = new Map<string, PlanRecord>();\n readonly ledgers = new Map<string, CreationLedger>();\n private readonly leases = new Map<string, { owner: string; until: number }>();\n\n async claimDelivery(deliveryId: string): Promise<boolean> {\n if (this.deliveries.has(deliveryId)) return false;\n this.deliveries.add(deliveryId);\n return true;\n }\n\n async releaseDelivery(deliveryId: string): Promise<void> {\n this.deliveries.delete(deliveryId);\n }\n\n async getPlan(planId: string): Promise<PlanRecord | null> {\n return structuredClone(this.plans.get(planId) ?? null);\n }\n\n async latestPlanForIssue(repositoryId: number, issueNumber: number): Promise<PlanRecord | null> {\n const candidates = [...this.plans.values()].filter(\n (plan) =>\n plan.source.repositoryId === repositoryId && plan.source.issueNumber === issueNumber,\n );\n candidates.sort((a, b) => b.revision - a.revision);\n return structuredClone(candidates[0] ?? null);\n }\n\n async savePlan(record: PlanRecord): Promise<void> {\n this.plans.set(record.planId, structuredClone(record));\n }\n\n async getLedger(planId: string): Promise<CreationLedger | null> {\n return structuredClone(this.ledgers.get(planId) ?? null);\n }\n\n async saveLedger(ledger: CreationLedger): Promise<void> {\n this.ledgers.set(ledger.planId, structuredClone(ledger));\n }\n\n async acquireLease(key: string, owner: string, ttlMs: number): Promise<boolean> {\n const current = this.leases.get(key);\n const now = Date.now();\n if (current && current.until > now && current.owner !== owner) return false;\n this.leases.set(key, { owner, until: now + ttlMs });\n return true;\n }\n\n async releaseLease(key: string, owner: string): Promise<void> {\n if (this.leases.get(key)?.owner === owner) this.leases.delete(key);\n }\n}\n\n/** JSON lines on stdout/stderr, which Cloud Logging parses as structured entries. */\nexport function createJsonLogger(base: Record<string, unknown> = {}): Logger {\n const write = (severity: string, message: string, fields?: Record<string, unknown>) => {\n const line = JSON.stringify({ severity, message, ...base, ...fields });\n if (severity === \"ERROR\") process.stderr.write(`${line}\\n`);\n else process.stdout.write(`${line}\\n`);\n };\n return {\n info: (message, fields) => write(\"INFO\", message, fields),\n warn: (message, fields) => write(\"WARNING\", message, fields),\n error: (message, fields) => write(\"ERROR\", message, fields),\n };\n}\n\nexport const silentLogger: Logger = { info: () => {}, warn: () => {}, error: () => {} };\n", "import { parse as parseYaml } from \"yaml\";\nimport { z } from \"zod\";\nimport { AiDlcError } from \"./errors.js\";\n\nconst Member = z.object({\n id: z.number().int().positive(),\n login: z.string().min(1),\n});\n\nconst Lane = z.object({\n requires_po_approval: z.boolean(),\n});\n\nexport const PolicySchema = z\n .object({\n version: z.literal(1),\n roles: z.object({\n po: z.array(Member).min(1),\n dev: z.array(Member).default([]),\n maintainer: z.array(Member).default([]),\n }),\n project: z\n .object({\n owner: z.string().min(1),\n number: z.number().int().positive(),\n })\n .optional(),\n lanes: z\n .object({\n fast: Lane,\n standard: Lane,\n strict: Lane,\n })\n .default({\n fast: { requires_po_approval: false },\n standard: { requires_po_approval: true },\n strict: { requires_po_approval: true },\n }),\n sensitive_paths: z.array(z.string().min(1)).default([]),\n evidence: z\n .object({ branch: z.string().min(1).default(\"ai-dlc-evidence\") })\n .default({ branch: \"ai-dlc-evidence\" }),\n acceptance: z\n .object({ build_workflows: z.array(z.string().min(1)).min(1) })\n .default({ build_workflows: [\".github/workflows/build.yml\"] }),\n planner: z\n .object({\n max_nodes: z.number().int().min(1).max(200).default(60),\n plan_ttl_days: z.number().int().min(1).max(90).default(30),\n })\n .default({ max_nodes: 60, plan_ttl_days: 30 }),\n })\n .superRefine((policy, ctx) => {\n const bots = [...policy.roles.po, ...policy.roles.dev, ...policy.roles.maintainer].filter(\n (member) => member.login.endsWith(\"[bot]\"),\n );\n for (const bot of bots) {\n ctx.addIssue({ code: \"custom\", message: `Bot account ${bot.login} cannot hold a role` });\n }\n });\n\nexport type Policy = z.infer<typeof PolicySchema>;\nexport type Role = \"po\" | \"dev\" | \"maintainer\";\nexport type LaneName = keyof Policy[\"lanes\"];\n\nexport const POLICY_PATH = \".github/ai-dlc/policy.yml\";\n\nexport function parsePolicy(source: string): Policy {\n let raw: unknown;\n try {\n raw = parseYaml(source);\n } catch (error) {\n throw new AiDlcError(\"E_POLICY_INVALID\", \"Policy file is not valid YAML.\", { cause: error });\n }\n const result = PolicySchema.safeParse(raw);\n if (!result.success) {\n throw new AiDlcError(\n \"E_POLICY_INVALID\",\n `Policy file is invalid:\\n${z.prettifyError(result.error)}`,\n );\n }\n return result.data;\n}\n\nexport function hasRole(policy: Policy, userId: number, role: Role): boolean {\n return policy.roles[role].some((member) => member.id === userId);\n}\n\nexport function rolesOf(policy: Policy, userId: number): Role[] {\n return ([\"po\", \"dev\", \"maintainer\"] as const).filter((role) => hasRole(policy, userId, role));\n}\n\n/** Minimal glob matcher supporting `*`, `**` and literal segments. */\nexport function matchesPath(pattern: string, path: string): boolean {\n let regex = \"\";\n for (let index = 0; index < pattern.length; index += 1) {\n const char = pattern[index] as string;\n if (char === \"*\") {\n if (pattern[index + 1] === \"*\") {\n regex += \".*\";\n index += 1;\n if (pattern[index + 1] === \"/\") index += 1;\n } else {\n regex += \"[^/]*\";\n }\n } else if (char === \"?\") {\n regex += \"[^/]\";\n } else {\n regex += char.replace(/[.+^${}()|[\\]\\\\]/gu, \"\\\\$&\");\n }\n }\n return new RegExp(`^${regex}$`, \"u\").test(path);\n}\n\nexport function isSensitive(policy: Policy, path: string): boolean {\n return policy.sensitive_paths.some((pattern) => matchesPath(pattern, path));\n}\n", "import type { PlanRecord } from \"./core/plan.js\";\n\nexport interface Actor {\n id: number;\n login: string;\n type: string;\n}\n\nexport interface RepoRef {\n owner: string;\n repo: string;\n repositoryId: number;\n}\n\nexport interface IssueData {\n id: number;\n nodeId: string;\n number: number;\n title: string;\n body: string;\n state: \"open\" | \"closed\";\n stateReason: string | null;\n labels: string[];\n author: Actor;\n isPullRequest: boolean;\n}\n\nexport interface CommentData {\n id: number;\n body: string;\n author: Actor;\n}\n\nexport interface PullRequestData {\n number: number;\n body: string;\n headSha: string;\n labels: string[];\n}\n\nexport interface WorkflowRunData {\n id: number;\n runAttempt: number;\n path: string;\n event: string;\n headBranch: string | null;\n headSha: string;\n status: string | null;\n conclusion: string | null;\n repositoryId: number;\n}\n\nexport type CommitState = \"success\" | \"failure\" | \"pending\" | \"error\";\n\n/** The subset of the GitHub API used by AI-DLC, scoped to one repository installation. */\nexport interface GitHubPort {\n readonly repo: RepoRef;\n getDefaultBranch(): Promise<string>;\n readFile(path: string, ref?: string): Promise<string | null>;\n getIssue(number: number): Promise<IssueData>;\n getComment(id: number): Promise<CommentData | null>;\n createIssue(input: { title: string; body: string; labels: string[] }): Promise<IssueData>;\n listIssuesWithLabel(label: string): Promise<IssueData[]>;\n addLabels(issueNumber: number, labels: string[]): Promise<void>;\n removeLabel(issueNumber: number, label: string): Promise<void>;\n /** Edits the bot comment containing `marker`, or creates it. */\n upsertComment(issueNumber: number, marker: string, body: string): Promise<void>;\n closeIssue(issueNumber: number, reason: \"completed\" | \"not_planned\"): Promise<void>;\n /** Links a child as a native sub-issue. Returns \"unsupported\" when the API is unavailable. */\n addSubIssue(parentNumber: number, childId: number): Promise<\"linked\" | \"unsupported\">;\n addToProject(project: { owner: string; number: number }, contentNodeId: string): Promise<void>;\n getPullRequest(number: number): Promise<PullRequestData>;\n listPullRequestFiles(number: number): Promise<string[]>;\n setCommitStatus(\n sha: string,\n status: { state: CommitState; context: string; description: string },\n ): Promise<void>;\n getWorkflowRun(runId: number): Promise<WorkflowRunData | null>;\n}\n\n/** Extra calls used by the local app, which acts with the signed-in user's own token. */\nexport interface LocalGitHubPort extends GitHubPort {\n viewer(): Promise<Actor>;\n listOpenIssuesWithLabel(label: string): Promise<IssueData[]>;\n createComment(issueNumber: number, body: string): Promise<CommentData>;\n /** Latest comment written by a bot that contains `marker`. */\n findBotComment(issueNumber: number, marker: string): Promise<CommentData | null>;\n /** Successful `push` runs of a workflow on `branch`, newest first. */\n listSuccessfulRuns(\n workflowPath: string,\n branch: string,\n limit: number,\n ): Promise<WorkflowRunData[]>;\n ensureLabel(label: {\n name: string;\n color: string;\n description: string;\n }): Promise<\"created\" | \"exists\">;\n}\n\n/** Append-only JSON store for baselines, decisions and revocations. */\nexport interface EvidenceStore {\n read<T>(path: string): Promise<T | null>;\n /** Creates the file; identical content is a no-op, different content is a conflict. */\n write(path: string, value: unknown): Promise<\"created\" | \"unchanged\">;\n list(prefix: string): Promise<string[]>;\n}\n\nexport interface ModelUsage {\n inputTokens: number;\n outputTokens: number;\n}\n\nexport interface ModelPort {\n readonly modelId: string;\n generateJson(input: {\n system: string;\n user: string;\n jsonSchema: Record<string, unknown>;\n }): Promise<{ text: string; usage: ModelUsage }>;\n}\n\nexport type LedgerItemState = \"creating\" | \"created\";\n\nexport interface LedgerItem {\n state: LedgerItemState;\n issueNumber?: number;\n issueId?: number;\n issueNodeId?: string;\n attemptedAt: string;\n subIssue?: \"linked\" | \"unsupported\" | \"failed\";\n project?: \"added\" | \"skipped\" | \"failed\";\n}\n\nexport interface CreationLedger {\n planId: string;\n planHash: string;\n status: \"creating\" | \"partial\" | \"created\";\n items: Record<string, LedgerItem>;\n errors: string[];\n updatedAt: string;\n}\n\nexport interface PlanStore {\n /** Returns false when the delivery was already claimed. */\n claimDelivery(deliveryId: string): Promise<boolean>;\n /** Undoes a claim when the job could not be queued, so a redelivery is accepted. */\n releaseDelivery(deliveryId: string): Promise<void>;\n getPlan(planId: string): Promise<PlanRecord | null>;\n latestPlanForIssue(repositoryId: number, issueNumber: number): Promise<PlanRecord | null>;\n savePlan(record: PlanRecord): Promise<void>;\n getLedger(planId: string): Promise<CreationLedger | null>;\n saveLedger(ledger: CreationLedger): Promise<void>;\n /** Short exclusive lease so only one worker creates Issues for a plan at a time. */\n acquireLease(key: string, owner: string, ttlMs: number): Promise<boolean>;\n releaseLease(key: string, owner: string): Promise<void>;\n}\n\nexport type PlannerJob =\n | {\n type: \"request\";\n deliveryId: string;\n installationId: number;\n owner: string;\n repo: string;\n issueNumber: number;\n }\n | {\n type: \"request-edited\";\n deliveryId: string;\n installationId: number;\n owner: string;\n repo: string;\n issueNumber: number;\n }\n | {\n type: \"command\";\n deliveryId: string;\n installationId: number;\n owner: string;\n repo: string;\n issueNumber: number;\n commentId: number;\n };\n\nexport interface JobQueue {\n enqueue(job: PlannerJob): Promise<void>;\n}\n\nexport interface Clock {\n now(): Date;\n}\n\nexport const systemClock: Clock = { now: () => new Date() };\n\nexport interface Logger {\n info(message: string, fields?: Record<string, unknown>): void;\n warn(message: string, fields?: Record<string, unknown>): void;\n error(message: string, fields?: Record<string, unknown>): void;\n}\n", "import { AiDlcError } from \"./errors.js\";\n\nconst NO_RESPONSE = \"_No response_\";\n\n/** Parses the `### Label` sections that GitHub renders for Issue forms. */\nexport function parseIssueForm(body: string | null | undefined): Map<string, string> {\n const sections = new Map<string, string>();\n const lines = (body ?? \"\").replace(/\\r\\n?/gu, \"\\n\").split(\"\\n\");\n let current: string | null = null;\n let buffer: string[] = [];\n const flush = () => {\n if (current === null) return;\n const value = buffer.join(\"\\n\").trim();\n sections.set(current, value === NO_RESPONSE ? \"\" : value);\n };\n for (const line of lines) {\n const heading = /^###\\s+(.+?)\\s*$/u.exec(line);\n if (heading) {\n flush();\n current = heading[1] as string;\n buffer = [];\n } else if (current !== null) {\n buffer.push(line);\n }\n }\n flush();\n return sections;\n}\n\nexport function requireSection(sections: Map<string, string>, label: string): string {\n const value = sections.get(label);\n if (value === undefined || value.length === 0) {\n throw new AiDlcError(\"E_FORM\", `Required section \\`### ${label}\\` is missing or empty.`);\n }\n return value;\n}\n\nexport interface Criterion {\n id: string;\n text: string;\n}\n\nconst CRITERION_LINE = /^-\\s+((?:AC|EC)-\\d{2,3}):\\s+(.+)$/u;\n\n/** Extracts AC/EC lines. Non-empty lines that look like bullets but are malformed are rejected. */\nexport function parseCriteria(text: string): Criterion[] {\n const criteria: Criterion[] = [];\n const seen = new Set<string>();\n for (const rawLine of text.split(\"\\n\")) {\n const line = rawLine.trim();\n if (line.length === 0) continue;\n const match = CRITERION_LINE.exec(line);\n if (!match) {\n if (/^-\\s+(AC|EC)/u.test(line)) {\n throw new AiDlcError(\n \"E_FORM\",\n `Malformed criterion line: \\`${line}\\`. Use \\`- AC-01: ...\\`.`,\n );\n }\n continue;\n }\n const id = match[1] as string;\n if (seen.has(id)) throw new AiDlcError(\"E_FORM\", `Duplicate criterion id \\`${id}\\`.`);\n seen.add(id);\n criteria.push({ id, text: (match[2] as string).trim() });\n }\n return criteria;\n}\n\n/** Parses `#12, #13` style references; only same-repository references are supported. */\nexport function parseIssueRefs(text: string | undefined): number[] {\n if (!text) return [];\n const refs = new Set<number>();\n for (const part of text.split(/[\\s,]+/u)) {\n if (part.length === 0) continue;\n const match = /^#(\\d+)$/u.exec(part);\n if (!match) {\n throw new AiDlcError(\"E_FORM\", `Invalid issue reference \\`${part}\\`. Use \\`#123\\`.`);\n }\n refs.add(Number(match[1]));\n }\n return [...refs].sort((a, b) => a - b);\n}\n", "/**\n * Labels and Issue form headings are part of the public contract: the parser\n * reads them back from Issues. Renaming one is a breaking change.\n */\nexport const LABELS = {\n request: \"ai-dlc:request\",\n planDraft: \"ai-dlc:plan-draft\",\n planCreated: \"ai-dlc:plan-created\",\n planPartial: \"ai-dlc:plan-partial\",\n fromPlan: \"ai-dlc:from-plan\",\n stale: \"ai-dlc:stale\",\n exempt: \"ai-dlc:exempt\",\n epic: \"type:epic\",\n story: \"type:story\",\n task: \"type:task\",\n} as const;\n\nexport type WorkItemKind = \"epic\" | \"story\" | \"task\";\n\nexport const KIND_LABEL: Record<WorkItemKind, string> = {\n epic: LABELS.epic,\n story: LABELS.story,\n task: LABELS.task,\n};\n\nexport const SECTIONS = {\n request: \"Y\u00EAu c\u1EA7u\",\n goal: \"M\u1EE5c ti\u00EAu v\u00E0 ng\u01B0\u1EDDi d\u00F9ng\",\n scope: \"Ph\u1EA1m vi\",\n parent: \"Issue cha\",\n blockedBy: \"Blocked by\",\n epicCriteria: \"Ti\u00EAu ch\u00ED nghi\u1EC7m thu Epic\",\n storyCriteria: \"Acceptance Criteria\",\n acRefs: \"AC li\u00EAn quan\",\n technicalRefs: \"Tham chi\u1EBFu k\u1EF9 thu\u1EADt\",\n risks: \"C\u00E2u h\u1ECFi v\u00E0 r\u1EE7i ro\",\n} as const;\n\n/** Sections that belong to the requirement content of each kind and therefore to its hash. */\nexport const REQUIREMENT_SECTIONS: Record<WorkItemKind, readonly string[]> = {\n epic: [\n SECTIONS.goal,\n SECTIONS.scope,\n SECTIONS.epicCriteria,\n SECTIONS.technicalRefs,\n SECTIONS.risks,\n ],\n story: [\n SECTIONS.goal,\n SECTIONS.scope,\n SECTIONS.parent,\n SECTIONS.blockedBy,\n SECTIONS.storyCriteria,\n SECTIONS.technicalRefs,\n SECTIONS.risks,\n ],\n task: [\n SECTIONS.goal,\n SECTIONS.scope,\n SECTIONS.parent,\n SECTIONS.blockedBy,\n SECTIONS.acRefs,\n SECTIONS.technicalRefs,\n SECTIONS.risks,\n ],\n};\n\nexport const CRITERIA_SECTION: Record<WorkItemKind, string | null> = {\n epic: SECTIONS.epicCriteria,\n story: SECTIONS.storyCriteria,\n task: null,\n};\n\nexport function kindFromLabels(labels: readonly string[]): WorkItemKind | null {\n const kinds = (Object.keys(KIND_LABEL) as WorkItemKind[]).filter((kind) =>\n labels.includes(KIND_LABEL[kind]),\n );\n return kinds.length === 1 ? (kinds[0] as WorkItemKind) : null;\n}\n", "import { CANONICAL_VERSION, contentHash, shortHash } from \"./canonical.js\";\nimport { AiDlcError } from \"./errors.js\";\nimport { parseCriteria, parseIssueForm, parseIssueRefs, type Criterion } from \"./issue-form.js\";\nimport {\n CRITERIA_SECTION,\n REQUIREMENT_SECTIONS,\n SECTIONS,\n kindFromLabels,\n type WorkItemKind,\n} from \"./vocabulary.js\";\n\nexport const BASELINE_SCHEMA_VERSION = 1;\n\nexport interface IssueSnapshotInput {\n repositoryId: number;\n issueNodeId: string;\n number: number;\n title: string;\n body: string | null;\n labels: readonly string[];\n}\n\nexport interface BaselineSnapshot {\n schemaVersion: typeof BASELINE_SCHEMA_VERSION;\n canonicalVersion: typeof CANONICAL_VERSION;\n baselineId: string;\n kind: WorkItemKind;\n source: { repositoryId: number; issueNodeId: string; issueNumber: number };\n requirements: {\n title: string;\n sections: Record<string, string>;\n criteria: Criterion[];\n };\n parent: number | null;\n blockedBy: number[];\n acRefs: string[];\n contentHash: string;\n}\n\nfunction hashedPart(snapshot: Omit<BaselineSnapshot, \"baselineId\" | \"contentHash\">) {\n return {\n schemaVersion: snapshot.schemaVersion,\n canonicalVersion: snapshot.canonicalVersion,\n kind: snapshot.kind,\n source: snapshot.source,\n requirements: snapshot.requirements,\n parent: snapshot.parent,\n blockedBy: snapshot.blockedBy,\n acRefs: snapshot.acRefs,\n };\n}\n\n/** Builds the immutable requirement snapshot from the current Issue content. */\nexport function buildBaseline(issue: IssueSnapshotInput): BaselineSnapshot {\n const kind = kindFromLabels(issue.labels);\n if (!kind) {\n throw new AiDlcError(\n \"E_FORM\",\n \"Issue needs exactly one of the labels type:epic, type:story or type:task.\",\n );\n }\n const parsed = parseIssueForm(issue.body);\n const sections: Record<string, string> = {};\n for (const label of REQUIREMENT_SECTIONS[kind]) sections[label] = parsed.get(label) ?? \"\";\n if (!sections[SECTIONS.goal]) {\n throw new AiDlcError(\"E_FORM\", `Section \\`### ${SECTIONS.goal}\\` is required.`);\n }\n const criteriaSection = CRITERIA_SECTION[kind];\n const criteria = criteriaSection ? parseCriteria(sections[criteriaSection] ?? \"\") : [];\n if (criteriaSection && criteria.length === 0) {\n throw new AiDlcError(\n \"E_FORM\",\n `Section \\`### ${criteriaSection}\\` needs at least one criterion line.`,\n );\n }\n const expectedPrefix = kind === \"epic\" ? \"EC-\" : \"AC-\";\n if (criteria.some((criterion) => !criterion.id.startsWith(expectedPrefix))) {\n throw new AiDlcError(\"E_FORM\", `${kind} criteria must use the ${expectedPrefix} prefix.`);\n }\n const parentRefs = parseIssueRefs(sections[SECTIONS.parent]);\n if (parentRefs.length > 1) throw new AiDlcError(\"E_FORM\", \"Only one parent Issue is allowed.\");\n const acRefs =\n kind === \"task\"\n ? (sections[SECTIONS.acRefs] ?? \"\")\n .split(/[\\s,]+/u)\n .filter((value) => value.length > 0)\n .map((value) => {\n if (!/^AC-\\d{2,3}$/u.test(value))\n throw new AiDlcError(\"E_FORM\", `Invalid AC reference \\`${value}\\`.`);\n return value;\n })\n : [];\n const base = {\n schemaVersion: BASELINE_SCHEMA_VERSION,\n canonicalVersion: CANONICAL_VERSION,\n kind,\n source: {\n repositoryId: issue.repositoryId,\n issueNodeId: issue.issueNodeId,\n issueNumber: issue.number,\n },\n requirements: { title: issue.title, sections, criteria },\n parent: parentRefs[0] ?? null,\n blockedBy: parseIssueRefs(sections[SECTIONS.blockedBy]),\n acRefs,\n } as const;\n const hash = contentHash(hashedPart(base));\n return { ...base, baselineId: `bl-${issue.number}-${shortHash(hash)}`, contentHash: hash };\n}\n\n/** Recomputes the hash of a stored snapshot to detect tampering or corruption. */\nexport function verifySnapshot(snapshot: BaselineSnapshot): boolean {\n return contentHash(hashedPart(snapshot)) === snapshot.contentHash;\n}\n\nexport function baselinePath(\n repositoryId: number,\n issueNumber: number,\n baselineId: string,\n): string {\n return `baselines/${repositoryId}/${issueNumber}/${baselineId}.json`;\n}\n", "import { AiDlcError } from \"./errors.js\";\n\nexport const COMMAND_PREFIX = \"/ai-dlc\";\n\ninterface CommandSpec {\n required: readonly string[];\n optional: readonly string[];\n handler: \"deterministic\" | \"planner\";\n}\n\nexport const COMMAND_SPECS = {\n baseline: { required: [], optional: [], handler: \"deterministic\" },\n approve: { required: [\"baseline\", \"hash\"], optional: [], handler: \"deterministic\" },\n ready: { required: [\"baseline\", \"hash\", \"lane\"], optional: [], handler: \"deterministic\" },\n accept: { required: [\"baseline\", \"run\", \"commit\"], optional: [], handler: \"deterministic\" },\n revoke: { required: [\"decision\", \"reason\"], optional: [], handler: \"deterministic\" },\n refine: { required: [\"plan\"], optional: [], handler: \"planner\" },\n \"create-plan\": { required: [\"plan\", \"hash\"], optional: [], handler: \"planner\" },\n \"resume-plan\": { required: [\"plan\"], optional: [], handler: \"planner\" },\n} as const satisfies Record<string, CommandSpec>;\n\nexport type CommandName = keyof typeof COMMAND_SPECS;\n\nexport interface ParsedCommand {\n name: CommandName;\n args: Record<string, string>;\n /** Text after the first line; used as free-form clarification for `refine`. */\n note: string;\n}\n\n/** Quick check used to route events without fully parsing them. */\nexport function looksLikeCommand(body: string | null | undefined): boolean {\n return (\n firstLine(body ?? \"\").startsWith(`${COMMAND_PREFIX} `) ||\n firstLine(body ?? \"\") === COMMAND_PREFIX\n );\n}\n\nexport function commandHandler(name: CommandName): \"deterministic\" | \"planner\" {\n return COMMAND_SPECS[name].handler;\n}\n\nfunction firstLine(body: string): string {\n return (body.replace(/\\r\\n?/gu, \"\\n\").split(\"\\n\")[0] ?? \"\").trim();\n}\n\nfunction tokenize(input: string): string[] {\n const tokens: string[] = [];\n const pattern = /([a-z][a-z-]*)=(?:\"((?:[^\"\\\\]|\\\\.)*)\"|(\\S+))|(\\S+)/gu;\n for (const match of input.matchAll(pattern)) {\n if (match[4] !== undefined) {\n throw new AiDlcError(\"E_SYNTAX\", `Unexpected token \\`${match[4]}\\`. Use key=value.`);\n }\n const value = match[2] !== undefined ? match[2].replace(/\\\\(.)/gu, \"$1\") : (match[3] as string);\n tokens.push(`${match[1]}=${value}`);\n }\n return tokens;\n}\n\n/**\n * Parses a command that must be on the first line of a comment.\n * Commands in quotes or code blocks never reach this function because their\n * first line does not start with the prefix.\n */\nexport function parseCommand(body: string): ParsedCommand {\n const normalized = body.replace(/\\r\\n?/gu, \"\\n\");\n const [head = \"\", ...rest] = normalized.split(\"\\n\");\n const line = head.trim();\n if (!line.startsWith(COMMAND_PREFIX)) {\n throw new AiDlcError(\n \"E_SYNTAX\",\n `Commands must start with \\`${COMMAND_PREFIX}\\` on the first line.`,\n );\n }\n const remainder = line.slice(COMMAND_PREFIX.length).trim();\n const [rawName = \"\", ...argParts] = remainder.split(/\\s+/u);\n if (!(rawName in COMMAND_SPECS)) {\n throw new AiDlcError(\n \"E_SYNTAX\",\n `Unknown command \\`${rawName || \"(empty)\"}\\`. Known commands: ${Object.keys(COMMAND_SPECS).join(\", \")}.`,\n );\n }\n const name = rawName as CommandName;\n const spec: CommandSpec = COMMAND_SPECS[name];\n const args: Record<string, string> = {};\n for (const token of tokenize(argParts.join(\" \"))) {\n const separator = token.indexOf(\"=\");\n const key = token.slice(0, separator);\n const value = token.slice(separator + 1);\n if (!spec.required.includes(key) && !spec.optional.includes(key)) {\n throw new AiDlcError(\"E_SYNTAX\", `Unknown argument \\`${key}\\` for \\`${name}\\`.`);\n }\n if (key in args) throw new AiDlcError(\"E_SYNTAX\", `Duplicate argument \\`${key}\\`.`);\n if (value.length === 0) throw new AiDlcError(\"E_SYNTAX\", `Argument \\`${key}\\` is empty.`);\n args[key] = value;\n }\n const missing = spec.required.filter((key) => !(key in args));\n if (missing.length > 0) {\n throw new AiDlcError(\"E_SYNTAX\", `Missing argument(s) for \\`${name}\\`: ${missing.join(\", \")}.`);\n }\n return { name, args, note: rest.join(\"\\n\").trim() };\n}\n", "import { sha256, shortHash } from \"./canonical.js\";\nimport { hasRole, type LaneName, type Policy, type Role } from \"./policy.js\";\n\nexport const DECISION_SCHEMA_VERSION = 1;\n\nexport type DecisionKind = \"approve\" | \"ready\" | \"accept\";\n\nexport const REQUIRED_ROLE: Record<DecisionKind, Role> = {\n approve: \"po\",\n ready: \"dev\",\n accept: \"po\",\n};\n\nexport interface BuildReference {\n runId: number;\n runAttempt: number;\n workflowPath: string;\n headSha: string;\n}\n\nexport interface DecisionReceipt {\n schemaVersion: typeof DECISION_SCHEMA_VERSION;\n decisionId: string;\n kind: DecisionKind;\n issueNumber: number;\n baselineId: string;\n baselineHash: string;\n actor: { id: number; login: string };\n source: { commentId: number; commentBodyDigest: string };\n lane: LaneName | null;\n build: BuildReference | null;\n policyVersion: number;\n recordedAt: string;\n}\n\nexport interface Revocation {\n schemaVersion: 1;\n decisionId: string;\n actor: { id: number; login: string };\n reason: string;\n source: { commentId: number };\n recordedAt: string;\n}\n\nexport function decisionId(kind: DecisionKind, commentId: number): string {\n return `dec-${shortHash(sha256(`${kind}:${commentId}`), 16)}`;\n}\n\nexport function commentDigest(body: string): string {\n return sha256(body.replace(/\\r\\n?/gu, \"\\n\"));\n}\n\nexport function decisionPath(repositoryId: number, issueNumber: number, id: string): string {\n return `decisions/${repositoryId}/${issueNumber}/${id}.json`;\n}\n\nexport function revocationPath(repositoryId: number, issueNumber: number, id: string): string {\n return `revocations/${repositoryId}/${issueNumber}/${id}.json`;\n}\n\n/** Facts gathered at check time. Validity is never stored; it is recomputed on every use. */\nexport interface ValidityFacts {\n policy: Policy;\n revoked: boolean;\n /** Current body of the source comment, or null when it was deleted. */\n currentCommentBody: string | null;\n /** Hash of the snapshot recomputed from storage, or null when missing/corrupt. */\n snapshotHash: string | null;\n /** Only for `accept`: whether the referenced build still satisfies acceptance rules. */\n buildValid?: boolean;\n}\n\nexport interface Validity {\n valid: boolean;\n reasons: string[];\n}\n\nexport function evaluateReceipt(receipt: DecisionReceipt, facts: ValidityFacts): Validity {\n const reasons: string[] = [];\n if (facts.revoked) reasons.push(\"decision was revoked\");\n if (facts.currentCommentBody === null) reasons.push(\"source comment was deleted\");\n else if (commentDigest(facts.currentCommentBody) !== receipt.source.commentBodyDigest) {\n reasons.push(\"source comment was edited\");\n }\n if (!hasRole(facts.policy, receipt.actor.id, REQUIRED_ROLE[receipt.kind])) {\n reasons.push(`actor no longer holds the ${REQUIRED_ROLE[receipt.kind]} role`);\n }\n if (facts.snapshotHash === null) reasons.push(\"baseline snapshot is missing or corrupt\");\n else if (facts.snapshotHash !== receipt.baselineHash) reasons.push(\"baseline hash mismatch\");\n if (receipt.kind === \"accept\" && facts.buildValid !== true)\n reasons.push(\"accepted build is no longer valid\");\n return { valid: reasons.length === 0, reasons };\n}\n", "import { AiDlcError } from \"./errors.js\";\n\nexport const PR_BLOCK_BEGIN = \"<!-- ai-dlc:begin -->\";\nexport const PR_BLOCK_END = \"<!-- ai-dlc:end -->\";\n\nexport interface PrBlock {\n issueNumber: number;\n baselineId: string;\n hash: string;\n acceptanceCriteria: string[];\n}\n\n/** Returns null when the PR has no block; throws when a block exists but is malformed. */\nexport function parsePrBlock(body: string | null | undefined): PrBlock | null {\n const text = (body ?? \"\").replace(/\\r\\n?/gu, \"\\n\");\n const begin = text.indexOf(PR_BLOCK_BEGIN);\n if (begin === -1) return null;\n if (text.indexOf(PR_BLOCK_BEGIN, begin + 1) !== -1) {\n throw new AiDlcError(\"E_PR_BLOCK\", \"PR body contains more than one AI-DLC block.\");\n }\n const end = text.indexOf(PR_BLOCK_END, begin);\n if (end === -1) throw new AiDlcError(\"E_PR_BLOCK\", \"AI-DLC block is not closed.\");\n const fields = new Map<string, string>();\n for (const line of text.slice(begin + PR_BLOCK_BEGIN.length, end).split(\"\\n\")) {\n const match = /^AI-DLC-([A-Za-z]+):\\s*(.*)$/u.exec(line.trim());\n if (match) fields.set((match[1] as string).toLowerCase(), (match[2] as string).trim());\n }\n const issue = /^#(\\d+)$/u.exec(fields.get(\"issue\") ?? \"\");\n const baselineId = fields.get(\"baseline\") ?? \"\";\n const hash = fields.get(\"hash\") ?? \"\";\n if (!issue)\n throw new AiDlcError(\"E_PR_BLOCK\", \"AI-DLC-Issue must be `#<number>` in the same repository.\");\n if (!/^bl-\\d+-[0-9a-f]{12}$/u.test(baselineId))\n throw new AiDlcError(\"E_PR_BLOCK\", \"AI-DLC-Baseline is missing or invalid.\");\n if (!/^sha256:[0-9a-f]{64}$/u.test(hash))\n throw new AiDlcError(\"E_PR_BLOCK\", \"AI-DLC-Hash is missing or invalid.\");\n const acceptanceCriteria = (fields.get(\"ac\") ?? \"\")\n .split(/[\\s,]+/u)\n .filter((value) => value.length > 0);\n for (const id of acceptanceCriteria) {\n if (!/^AC-\\d{2,3}$/u.test(id))\n throw new AiDlcError(\"E_PR_BLOCK\", `Invalid AC id \\`${id}\\` in AI-DLC-AC.`);\n }\n return { issueNumber: Number(issue[1]), baselineId, hash, acceptanceCriteria };\n}\n\nexport function renderPrBlock(block: PrBlock): string {\n return [\n PR_BLOCK_BEGIN,\n `AI-DLC-Issue: #${block.issueNumber}`,\n `AI-DLC-Baseline: ${block.baselineId}`,\n `AI-DLC-Hash: ${block.hash}`,\n `AI-DLC-AC: ${block.acceptanceCriteria.join(\", \")}`,\n PR_BLOCK_END,\n ].join(\"\\n\");\n}\n\n/** Issue numbers referenced with GitHub closing keywords, which would auto-close Issues on merge. */\nexport function closingReferences(body: string | null | undefined): number[] {\n const pattern = /\\b(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\\s*:?\\s+#(\\d+)\\b/giu;\n return [...new Set([...(body ?? \"\").matchAll(pattern)].map((match) => Number(match[1])))];\n}\n", "import { z } from \"zod\";\nimport { canonicalJson, sha256, shortHash } from \"./canonical.js\";\nimport { AiDlcError } from \"./errors.js\";\nimport type { WorkItemKind } from \"./vocabulary.js\";\n\nconst LOCAL_ID = /^[a-z0-9][a-z0-9-]{0,47}$/u;\nconst Text = (max: number) => z.string().trim().min(1).max(max);\n\nconst CriterionSchema = z.object({\n id: z.string().regex(/^(AC|EC)-\\d{2,3}$/u),\n text: Text(500),\n});\n\nconst NodeSchema = z.object({\n localId: z.string().regex(LOCAL_ID),\n kind: z.enum([\"epic\", \"story\", \"task\"]),\n parentLocalId: z.string().regex(LOCAL_ID).nullable(),\n title: Text(120),\n goal: Text(1000),\n scope: z.array(Text(300)).max(15),\n outOfScope: z.array(Text(300)).max(10),\n criteria: z.array(CriterionSchema).max(20),\n acRefs: z.array(z.string().regex(/^AC-\\d{2,3}$/u)).max(20),\n blockedBy: z.array(z.string().regex(LOCAL_ID)).max(10),\n riskNotes: z.array(Text(300)).max(10),\n});\n\n/** Shape the model must return. Server-owned fields (ids, hashes, source) are added later. */\nexport const ModelPlanSchema = z.object({\n rootKind: z.enum([\"epic\", \"story\"]),\n summary: Text(1000),\n assumptions: z.array(Text(300)).max(15),\n openQuestions: z.array(z.object({ text: Text(300), blocking: z.boolean() })).max(15),\n nodes: z.array(NodeSchema).min(1).max(200),\n});\n\nexport type ModelPlan = z.infer<typeof ModelPlanSchema>;\nexport type PlanNode = z.infer<typeof NodeSchema>;\n\nexport const PLAN_SCHEMA_VERSION = 1;\n\n/** JSON Schema handed to Gemini as `responseJsonSchema`. */\nexport function modelPlanJsonSchema(): Record<string, unknown> {\n return z.toJSONSchema(ModelPlanSchema, { target: \"draft-7\" }) as Record<string, unknown>;\n}\n\nexport interface PlanLimits {\n maxNodes: number;\n}\n\n/** Parses model output text and enforces structural and semantic rules. */\nexport function parseModelPlan(text: string, limits: PlanLimits): ModelPlan {\n let raw: unknown;\n try {\n raw = JSON.parse(text);\n } catch (error) {\n throw new AiDlcError(\"E_PLAN_SCHEMA\", \"Model output is not valid JSON.\", { cause: error });\n }\n const parsed = ModelPlanSchema.safeParse(raw);\n if (!parsed.success) {\n throw new AiDlcError(\n \"E_PLAN_SCHEMA\",\n `Model output does not match the plan schema:\\n${z.prettifyError(parsed.error)}`,\n );\n }\n validatePlanSemantics(parsed.data, limits);\n return parsed.data;\n}\n\nexport function validatePlanSemantics(plan: ModelPlan, limits: PlanLimits): void {\n if (plan.nodes.length > limits.maxNodes) {\n throw new AiDlcError(\n \"E_PLAN_LIMIT\",\n `Plan has ${plan.nodes.length} items; the limit is ${limits.maxNodes}. Split the request into smaller requests.`,\n );\n }\n const problems: string[] = [];\n const byId = new Map<string, PlanNode>();\n for (const node of plan.nodes) {\n if (byId.has(node.localId)) problems.push(`Duplicate localId \\`${node.localId}\\`.`);\n byId.set(node.localId, node);\n }\n const roots = plan.nodes.filter((node) => node.parentLocalId === null);\n if (roots.length !== 1) problems.push(`Plan must have exactly one root; found ${roots.length}.`);\n else if (roots[0]?.kind !== plan.rootKind) {\n problems.push(`Root kind \\`${roots[0]?.kind}\\` does not match rootKind \\`${plan.rootKind}\\`.`);\n }\n const expectedParent: Record<WorkItemKind, WorkItemKind | null> = {\n epic: null,\n story: \"epic\",\n task: \"story\",\n };\n for (const node of plan.nodes) {\n const label = `\\`${node.localId}\\``;\n if (node.parentLocalId !== null) {\n const parent = byId.get(node.parentLocalId);\n if (!parent) problems.push(`${label} references missing parent \\`${node.parentLocalId}\\`.`);\n else if (parent.kind !== expectedParent[node.kind]) {\n problems.push(\n `${label} (${node.kind}) cannot be a child of ${parent.kind} \\`${parent.localId}\\`.`,\n );\n }\n } else if (node.kind === \"task\") {\n problems.push(`${label}: a task cannot be the root.`);\n }\n if (node.kind === \"epic\" && plan.rootKind === \"story\")\n problems.push(`${label}: no epic allowed when rootKind is story.`);\n const prefix = node.kind === \"epic\" ? \"EC-\" : \"AC-\";\n if (node.kind !== \"task\") {\n if (node.criteria.length === 0) problems.push(`${label} must have at least one criterion.`);\n if (node.criteria.some((criterion) => !criterion.id.startsWith(prefix))) {\n problems.push(`${label} criteria must use the \\`${prefix}\\` prefix.`);\n }\n if (node.acRefs.length > 0) problems.push(`${label}: only tasks may use acRefs.`);\n } else {\n if (node.criteria.length > 0)\n problems.push(`${label}: tasks use acRefs instead of criteria.`);\n const parent = node.parentLocalId ? byId.get(node.parentLocalId) : undefined;\n const parentAc = new Set(parent?.criteria.map((criterion) => criterion.id));\n for (const ref of node.acRefs) {\n if (!parentAc.has(ref))\n problems.push(`${label} references \\`${ref}\\` that its story does not define.`);\n }\n }\n const ids = node.criteria.map((criterion) => criterion.id);\n if (new Set(ids).size !== ids.length) problems.push(`${label} has duplicate criterion ids.`);\n for (const dependency of node.blockedBy) {\n if (dependency === node.localId) problems.push(`${label} cannot block itself.`);\n else if (!byId.has(dependency))\n problems.push(`${label} is blocked by missing \\`${dependency}\\`.`);\n }\n }\n if (problems.length === 0) {\n try {\n creationOrder(plan.nodes);\n } catch (error) {\n problems.push((error as Error).message);\n }\n }\n if (problems.length > 0) {\n throw new AiDlcError(\"E_PLAN_SCHEMA\", `Plan failed validation:\\n- ${problems.join(\"\\n- \")}`);\n }\n}\n\n/**\n * Orders nodes so that every parent and every blocking item is created first,\n * which lets bodies reference real Issue numbers. Input order breaks ties.\n */\nexport function creationOrder(nodes: readonly PlanNode[]): PlanNode[] {\n const byId = new Map(nodes.map((node) => [node.localId, node]));\n const state = new Map<string, \"visiting\" | \"done\">();\n const ordered: PlanNode[] = [];\n const visit = (node: PlanNode, trail: string[]) => {\n const current = state.get(node.localId);\n if (current === \"done\") return;\n if (current === \"visiting\") {\n throw new Error(`Dependency cycle: ${[...trail, node.localId].join(\" -> \")}.`);\n }\n state.set(node.localId, \"visiting\");\n const prerequisites = [node.parentLocalId, ...node.blockedBy].filter(\n (id): id is string => id !== null,\n );\n for (const id of prerequisites) {\n const prerequisite = byId.get(id);\n if (prerequisite) visit(prerequisite, [...trail, node.localId]);\n }\n state.set(node.localId, \"done\");\n ordered.push(node);\n };\n for (const node of nodes) visit(node, []);\n return ordered;\n}\n\nexport type PlanStatus = \"draft\" | \"superseded\" | \"stale\" | \"creating\" | \"partial\" | \"created\";\n\nexport interface PlanSource {\n repositoryId: number;\n owner: string;\n repo: string;\n issueNumber: number;\n issueNodeId: string;\n requestDigest: string;\n}\n\nexport interface PlanRecord {\n schemaVersion: typeof PLAN_SCHEMA_VERSION;\n planId: string;\n revision: number;\n status: PlanStatus;\n source: PlanSource;\n model: string;\n plan: ModelPlan;\n planHash: string;\n clarifications: string[];\n requestedBy: number;\n createdAt: string;\n expiresAt: string;\n}\n\nexport function computePlanHash(requestDigest: string, plan: ModelPlan): string {\n return sha256(canonicalJson({ schemaVersion: PLAN_SCHEMA_VERSION, requestDigest, plan }));\n}\n\nexport function computeRequestDigest(title: string, body: string): string {\n return sha256(canonicalJson({ title, body }));\n}\n\nexport function buildPlanId(issueNumber: number, revision: number, planHash: string): string {\n return `plan-${issueNumber}-r${revision}-${shortHash(planHash, 8)}`;\n}\n\nexport function blockingQuestions(plan: ModelPlan): string[] {\n return plan.openQuestions\n .filter((question) => question.blocking)\n .map((question) => question.text);\n}\n", "import type { ModelPlan, PlanNode, PlanRecord } from \"./plan.js\";\nimport { blockingQuestions, creationOrder } from \"./plan.js\";\nimport { SECTIONS } from \"./vocabulary.js\";\n\n/**\n * Model and user text is untrusted. Neutralize mentions, hidden HTML comments\n * (which could forge automation markers) and raw HTML before posting it.\n */\nexport function sanitize(text: string): string {\n return text\n .replace(/<!--/gu, \"&lt;!--\")\n .replace(/</gu, \"&lt;\")\n .replace(/(^|[^\\w`])@(?=[\\w-])/gu, \"$1@\\u200b\")\n .replace(/^\\/ai-dlc/gmu, \"\\\\/ai-dlc\");\n}\n\nexport function marker(name: string, value: string): string {\n return `<!-- ai-dlc:${name}:${value} -->`;\n}\n\nexport function findMarker(body: string | null | undefined, name: string): string | null {\n const match = new RegExp(`<!-- ai-dlc:${name}:([^\\\\s>]+) -->`, \"u\").exec(body ?? \"\");\n return match ? (match[1] as string) : null;\n}\n\nexport function planNodeMarker(planId: string, localId: string): string {\n return marker(\"plan-node\", `${planId}/${localId}`);\n}\n\nconst KIND_TITLE = { epic: \"Epic\", story: \"Story\", task: \"Task\" } as const;\n\nexport function bulletList(items: readonly string[], empty = \"_(kh\u00F4ng c\u00F3)_\"): string {\n return items.length === 0 ? empty : items.map((item) => `- ${sanitize(item)}`).join(\"\\n\");\n}\n\nexport function issueTitle(node: PlanNode): string {\n return `[${KIND_TITLE[node.kind]}] ${sanitize(node.title).replace(/\\s+/gu, \" \")}`;\n}\n\n/** Body of an Issue created from a plan. Headings match the Issue forms so the same parser applies. */\nexport function renderNodeBody(\n record: PlanRecord,\n node: PlanNode,\n numbers: ReadonlyMap<string, number>,\n): string {\n const ref = (localId: string) => {\n const number = numbers.get(localId);\n if (number === undefined) throw new Error(`Issue number for ${localId} is not known yet`);\n return `#${number}`;\n };\n const scope = [\n ...node.scope.map((item) => `- Trong ph\u1EA1m vi: ${sanitize(item)}`),\n ...node.outOfScope.map((item) => `- Ngo\u00E0i ph\u1EA1m vi: ${sanitize(item)}`),\n ];\n const sections: [string, string][] = [\n [SECTIONS.goal, sanitize(node.goal)],\n [SECTIONS.scope, scope.join(\"\\n\") || \"_(ch\u01B0a x\u00E1c \u0111\u1ECBnh)_\"],\n ];\n if (node.kind !== \"epic\") {\n sections.push([SECTIONS.parent, node.parentLocalId ? ref(node.parentLocalId) : \"\"]);\n sections.push([SECTIONS.blockedBy, node.blockedBy.map(ref).join(\", \")]);\n }\n if (node.kind === \"epic\") {\n sections.push([\n SECTIONS.epicCriteria,\n node.criteria.map((c) => `- ${c.id}: ${sanitize(c.text)}`).join(\"\\n\"),\n ]);\n } else if (node.kind === \"story\") {\n sections.push([\n SECTIONS.storyCriteria,\n node.criteria.map((c) => `- ${c.id}: ${sanitize(c.text)}`).join(\"\\n\"),\n ]);\n } else {\n sections.push([SECTIONS.acRefs, node.acRefs.join(\", \")]);\n }\n sections.push([SECTIONS.technicalRefs, \"\"]);\n sections.push([SECTIONS.risks, bulletList(node.riskNotes, \"\")]);\n\n const rendered = sections\n .map(([heading, value]) => `### ${heading}\\n\\n${value || \"_No response_\"}`)\n .join(\"\\n\\n\");\n return [\n rendered,\n \"\",\n \"---\",\n `_T\u1EA1o t\u1EEB k\u1EBF ho\u1EA1ch \\`${record.planId}\\` cho request #${record.source.issueNumber} sau khi PO x\u00E1c nh\u1EADn. N\u1ED9i dung do AI \u0111\u1EC1 xu\u1EA5t; PO/DEV c\u00F3 th\u1EC3 ch\u1EC9nh s\u1EEDa tr\u01B0\u1EDBc khi ch\u1ED1t baseline._`,\n planNodeMarker(record.planId, node.localId),\n ].join(\"\\n\");\n}\n\nexport function renderTree(plan: ModelPlan): string {\n const children = new Map<string | null, PlanNode[]>();\n for (const node of plan.nodes) {\n const list = children.get(node.parentLocalId) ?? [];\n list.push(node);\n children.set(node.parentLocalId, list);\n }\n const lines: string[] = [];\n const walk = (parent: string | null, depth: number) => {\n for (const node of children.get(parent) ?? []) {\n const blocked =\n node.blockedBy.length > 0 ? ` _(blocked by ${node.blockedBy.join(\", \")})_` : \"\";\n lines.push(\n `${\" \".repeat(depth)}- **${KIND_TITLE[node.kind]}** \\`${node.localId}\\`: ${sanitize(node.title)}${blocked}`,\n );\n const criteria =\n node.kind === \"task\"\n ? node.acRefs.map((id) => `${id}`)\n : node.criteria.map((c) => `${c.id}: ${sanitize(c.text)}`);\n for (const criterion of criteria) lines.push(`${\" \".repeat(depth + 1)}- ${criterion}`);\n walk(node.localId, depth + 1);\n }\n };\n walk(null, 0);\n return lines.join(\"\\n\");\n}\n\nexport function renderPlanComment(record: PlanRecord): string {\n const { plan } = record;\n const blocking = blockingQuestions(plan);\n const nonBlocking = plan.openQuestions\n .filter((question) => !question.blocking)\n .map((question) => question.text);\n const counts = ([\"epic\", \"story\", \"task\"] as const)\n .map((kind) => [kind, plan.nodes.filter((node) => node.kind === kind).length] as const)\n .filter(([, count]) => count > 0)\n .map(([kind, count]) => `${count} ${KIND_TITLE[kind]}`)\n .join(\", \");\n const next =\n blocking.length > 0\n ? [\n \"**C\u1EA7n PO tr\u1EA3 l\u1EDDi c\u00E1c c\u00E2u h\u1ECFi ch\u1EB7n tr\u01B0\u1EDBc khi t\u1EA1o Issues.** Tr\u1EA3 l\u1EDDi b\u1EB1ng m\u1ED9t comment m\u1EDBi:\",\n \"\",\n \"```text\",\n `/ai-dlc refine plan=${record.planId}`,\n \"<c\u00E2u tr\u1EA3 l\u1EDDi c\u1EE7a b\u1EA1n, m\u1ED7i \u00FD m\u1ED9t d\u00F2ng>\",\n \"```\",\n ]\n : [\n \"**N\u1EBFu \u0111\u1ED3ng \u00FD, PO x\u00E1c nh\u1EADn \u0111\u1EC3 App t\u1EA1o c\u00E1c Issues:**\",\n \"\",\n \"```text\",\n `/ai-dlc create-plan plan=${record.planId} hash=${record.planHash}`,\n \"```\",\n \"\",\n `Mu\u1ED1n ch\u1EC9nh s\u1EEDa: \\`/ai-dlc refine plan=${record.planId}\\` k\u00E8m y\u00EAu c\u1EA7u \u1EDF c\u00E1c d\u00F2ng ti\u1EBFp theo.`,\n ];\n return [\n `## K\u1EBF ho\u1EA1ch \u0111\u1EC1 xu\u1EA5t (revision ${record.revision})`,\n \"\",\n sanitize(plan.summary),\n \"\",\n `**Ph\u1EA1m vi:** ${counts}. Model: \\`${record.model}\\`.`,\n \"\",\n \"### C\u00E2y c\u00F4ng vi\u1EC7c\",\n \"\",\n renderTree(plan),\n \"\",\n \"### C\u00E2u h\u1ECFi ch\u1EB7n\",\n \"\",\n bulletList(blocking),\n \"\",\n \"### C\u00E2u h\u1ECFi kh\u00E1c\",\n \"\",\n bulletList(nonBlocking),\n \"\",\n \"### Gi\u1EA3 \u0111\u1ECBnh c\u1EA7n x\u00E1c nh\u1EADn\",\n \"\",\n bulletList(plan.assumptions),\n \"\",\n ...next,\n \"\",\n `<sub>Plan \\`${record.planId}\\` \u00B7 hash \\`${record.planHash}\\` \u00B7 h\u1EBFt h\u1EA1n ${record.expiresAt.slice(0, 10)}. \u0110\u00E2y l\u00E0 \u0111\u1EC1 xu\u1EA5t c\u1EE7a AI, ch\u01B0a ph\u1EA3i quy\u1EBFt \u0111\u1ECBnh; ch\u01B0a c\u00F3 Issue n\u00E0o \u0111\u01B0\u1EE3c t\u1EA1o.</sub>`,\n marker(\"plan\", record.planId),\n ].join(\"\\n\");\n}\n\nexport function renderCreationSummary(\n record: PlanRecord,\n numbers: ReadonlyMap<string, number>,\n complete: boolean,\n failures: readonly string[],\n): string {\n const lines = creationOrder(record.plan.nodes).map((node) => {\n const number = numbers.get(node.localId);\n return `- ${KIND_TITLE[node.kind]} \\`${node.localId}\\`: ${number ? `#${number}` : \"_ch\u01B0a t\u1EA1o_\"}`;\n });\n return [\n complete\n ? `## \u0110\u00E3 t\u1EA1o Issues t\u1EEB \\`${record.planId}\\``\n : `## T\u1EA1o Issues ch\u01B0a ho\u00E0n t\u1EA5t cho \\`${record.planId}\\``,\n \"\",\n ...lines,\n \"\",\n ...(failures.length > 0 ? [\"**L\u1ED7i:**\", \"\", bulletList(failures), \"\"] : []),\n complete\n ? \"B\u01B0\u1EDBc ti\u1EBFp theo: PO \u01B0u ti\u00EAn trong Project; DEV review kh\u1EA3 thi v\u00E0 chia vi\u1EC7c; ch\u1ED1t baseline khi Story s\u1EB5n s\u00E0ng (`/ai-dlc baseline`).\"\n : `Kh\u00F4ng x\u00F3a c\u00E1c Issue \u0111\u00E3 t\u1EA1o. Th\u1EED l\u1EA1i an to\u00E0n b\u1EB1ng \\`/ai-dlc resume-plan plan=${record.planId}\\`.`,\n marker(\"plan-result\", record.planId),\n ].join(\"\\n\");\n}\n", "import {\n buildBaseline,\n baselinePath,\n verifySnapshot,\n type BaselineSnapshot,\n} from \"../core/baseline.js\";\nimport { commandHandler, parseCommand, type ParsedCommand } from \"../core/command.js\";\nimport {\n DECISION_SCHEMA_VERSION,\n REQUIRED_ROLE,\n commentDigest,\n decisionId,\n decisionPath,\n evaluateReceipt,\n revocationPath,\n type DecisionKind,\n type DecisionReceipt,\n type Revocation,\n} from \"../core/decision.js\";\nimport { AiDlcError, isAiDlcError } from \"../core/errors.js\";\nimport {\n POLICY_PATH,\n hasRole,\n isSensitive,\n parsePolicy,\n type LaneName,\n type Policy,\n} from \"../core/policy.js\";\nimport { closingReferences, parsePrBlock, renderPrBlock } from \"../core/pr-block.js\";\nimport { marker, sanitize } from \"../core/render.js\";\nimport { LABELS, kindFromLabels } from \"../core/vocabulary.js\";\nimport type { Clock, CommentData, EvidenceStore, GitHubPort, IssueData, Logger } from \"../ports.js\";\n\nexport const STATUS_CONTEXT = \"ai-dlc/baseline\";\n\nexport interface WorkflowDeps {\n github: GitHubPort;\n evidence: EvidenceStore;\n clock: Clock;\n logger: Logger;\n enabled: boolean;\n}\n\nexport interface PrCheckResult {\n state: \"success\" | \"failure\" | \"pending\";\n description: string;\n details: string[];\n}\n\nconst LANES: readonly LaneName[] = [\"fast\", \"standard\", \"strict\"];\n\nexport class WorkflowService {\n private policyCache: Policy | null = null;\n\n constructor(private readonly deps: WorkflowDeps) {}\n\n private get repositoryId(): number {\n return this.deps.github.repo.repositoryId;\n }\n\n async policy(): Promise<Policy> {\n if (this.policyCache) return this.policyCache;\n const branch = await this.deps.github.getDefaultBranch();\n const source = await this.deps.github.readFile(POLICY_PATH, branch);\n if (source === null)\n throw new AiDlcError(\"E_POLICY_INVALID\", `Missing ${POLICY_PATH} on ${branch}.`);\n this.policyCache = parsePolicy(source);\n return this.policyCache;\n }\n\n /** Entry point for `issue_comment` events on Issues. */\n async handleComment(\n issueNumber: number,\n commentId: number,\n action: \"created\" | \"edited\" | \"deleted\",\n ): Promise<void> {\n if (!this.deps.enabled) return;\n if (action !== \"created\") {\n await this.reportInvalidatedDecisions(issueNumber, commentId, action);\n return;\n }\n const comment = await this.deps.github.getComment(commentId);\n if (!comment || comment.author.type !== \"User\") return;\n let command: ParsedCommand;\n try {\n command = parseCommand(comment.body);\n } catch (error) {\n if (isAiDlcError(error)) await this.reply(issueNumber, commentId, errorReply(error));\n return;\n }\n if (commandHandler(command.name) !== \"deterministic\") return;\n try {\n const policy = await this.policy();\n const issue = await this.deps.github.getIssue(issueNumber);\n if (issue.isPullRequest)\n throw new AiDlcError(\"E_SYNTAX\", \"AI-DLC commands are only accepted on Issues.\");\n const message = await this.runCommand(command, issue, comment, policy);\n await this.reply(issueNumber, commentId, message);\n } catch (error) {\n if (!isAiDlcError(error)) throw error;\n await this.reply(issueNumber, commentId, errorReply(error));\n }\n }\n\n private async reply(issueNumber: number, commentId: number, body: string): Promise<void> {\n await this.deps.github.upsertComment(issueNumber, marker(\"reply\", String(commentId)), body);\n }\n\n private async runCommand(\n command: ParsedCommand,\n issue: IssueData,\n comment: CommentData,\n policy: Policy,\n ): Promise<string> {\n const actor = comment.author;\n switch (command.name) {\n case \"baseline\":\n this.requireRole(policy, actor.id, [\"po\", \"dev\"], \"baseline\");\n return this.createBaseline(issue);\n case \"approve\":\n case \"ready\":\n case \"accept\":\n this.requireRole(policy, actor.id, [REQUIRED_ROLE[command.name]], command.name);\n return this.recordDecision(command.name, command.args, issue, comment, policy);\n case \"revoke\":\n return this.revoke(command.args, issue, comment, policy);\n default:\n throw new AiDlcError(\n \"E_SYNTAX\",\n `\\`${command.name}\\` is handled by the planner, not this workflow.`,\n );\n }\n }\n\n private requireRole(\n policy: Policy,\n userId: number,\n roles: Array<\"po\" | \"dev\" | \"maintainer\">,\n action: string,\n ): void {\n if (!roles.some((role) => hasRole(policy, userId, role))) {\n throw new AiDlcError(\"E_ROLE\", `\\`${action}\\` requires the ${roles.join(\" or \")} role.`);\n }\n }\n\n snapshotOf(issue: IssueData): BaselineSnapshot {\n return buildBaseline({\n repositoryId: this.repositoryId,\n issueNodeId: issue.nodeId,\n number: issue.number,\n title: issue.title,\n body: issue.body,\n labels: issue.labels,\n });\n }\n\n private async createBaseline(issue: IssueData): Promise<string> {\n const snapshot = this.snapshotOf(issue);\n const result = await this.deps.evidence.write(\n baselinePath(this.repositoryId, issue.number, snapshot.baselineId),\n snapshot,\n );\n const criteria = snapshot.requirements.criteria.map(\n (criterion) => `- ${criterion.id}: ${sanitize(criterion.text)}`,\n );\n return [\n `**Baseline \\`${snapshot.baselineId}\\`** ${result === \"created\" ? \"\u0111\u00E3 \u0111\u01B0\u1EE3c t\u1EA1o\" : \"\u0111\u00E3 t\u1ED3n t\u1EA1i v\u1EDBi c\u00F9ng n\u1ED9i dung\"}.`,\n \"\",\n `Hash: \\`${snapshot.contentHash}\\``,\n ...(criteria.length > 0 ? [\"\", \"Ti\u00EAu ch\u00ED:\", ...criteria] : []),\n \"\",\n \"PO duy\u1EC7t nghi\u1EC7p v\u1EE5:\",\n \"```text\",\n `/ai-dlc approve baseline=${snapshot.baselineId} hash=${snapshot.contentHash}`,\n \"```\",\n \"DEV x\u00E1c nh\u1EADn s\u1EB5n s\u00E0ng (lane: fast | standard | strict):\",\n \"```text\",\n `/ai-dlc ready baseline=${snapshot.baselineId} hash=${snapshot.contentHash} lane=standard`,\n \"```\",\n ].join(\"\\n\");\n }\n\n private async loadSnapshot(issueNumber: number, baselineId: string): Promise<BaselineSnapshot> {\n if (!baselineId.startsWith(`bl-${issueNumber}-`)) {\n throw new AiDlcError(\n \"E_BASELINE_NOT_FOUND\",\n `Baseline \\`${baselineId}\\` does not belong to #${issueNumber}.`,\n );\n }\n const snapshot = await this.deps.evidence.read<BaselineSnapshot>(\n baselinePath(this.repositoryId, issueNumber, baselineId),\n );\n if (!snapshot || !verifySnapshot(snapshot)) {\n throw new AiDlcError(\n \"E_BASELINE_NOT_FOUND\",\n `Baseline \\`${baselineId}\\` is missing or corrupt.`,\n );\n }\n return snapshot;\n }\n\n /**\n * Loads the snapshot for a decision. When it was never stored but the id and hash\n * match the Issue's current content, it is stored now, so one command suffices.\n */\n private async snapshotForDecision(\n issue: IssueData,\n baselineId: string,\n hash: string | undefined,\n ): Promise<BaselineSnapshot> {\n const stored = await this.deps.evidence.read<BaselineSnapshot>(\n baselinePath(this.repositoryId, issue.number, baselineId),\n );\n if (stored || hash === undefined) return this.loadSnapshot(issue.number, baselineId);\n const current = this.snapshotOf(issue);\n if (current.baselineId !== baselineId || current.contentHash !== hash) {\n return this.loadSnapshot(issue.number, baselineId);\n }\n await this.deps.evidence.write(\n baselinePath(this.repositoryId, issue.number, current.baselineId),\n current,\n );\n return current;\n }\n\n /** Throws when the Issue no longer matches the baseline it is being decided on. */\n private assertCurrent(issue: IssueData, snapshot: BaselineSnapshot): void {\n if (this.snapshotOf(issue).contentHash !== snapshot.contentHash) {\n throw new AiDlcError(\n \"E_STALE\",\n \"The Issue changed after this baseline was created. Run `/ai-dlc baseline` again and decide on the new baseline.\",\n );\n }\n }\n\n private async recordDecision(\n kind: DecisionKind,\n args: Record<string, string>,\n issue: IssueData,\n comment: CommentData,\n policy: Policy,\n ): Promise<string> {\n const { github, evidence, clock } = this.deps;\n const snapshot =\n kind === \"accept\"\n ? await this.loadSnapshot(issue.number, args.baseline as string)\n : await this.snapshotForDecision(issue, args.baseline as string, args.hash);\n let lane: LaneName | null = null;\n let build: DecisionReceipt[\"build\"] = null;\n if (kind === \"approve\" || kind === \"ready\") {\n if (args.hash !== snapshot.contentHash) {\n throw new AiDlcError(\n \"E_HASH_MISMATCH\",\n \"The hash does not match the baseline. Copy it from the baseline reply.\",\n );\n }\n this.assertCurrent(issue, snapshot);\n }\n if (kind === \"ready\") {\n if (!LANES.includes(args.lane as LaneName)) {\n throw new AiDlcError(\"E_SYNTAX\", `Lane must be one of ${LANES.join(\", \")}.`);\n }\n lane = args.lane as LaneName;\n await this.assertApproved(snapshot, lane, policy);\n const open: number[] = [];\n for (const dependency of snapshot.blockedBy) {\n const blocker = await github.getIssue(dependency);\n if (blocker.state !== \"closed\" || blocker.stateReason !== \"completed\")\n open.push(dependency);\n }\n if (open.length > 0) {\n throw new AiDlcError(\n \"E_DEPENDENCY_OPEN\",\n `Blocked by unfinished Issue(s): ${open.map((n) => `#${n}`).join(\", \")}.`,\n );\n }\n }\n if (kind === \"accept\") {\n if (snapshot.kind === \"task\") {\n throw new AiDlcError(\n \"E_WRONG_KIND\",\n \"PO accepts stories and epics. A task is done when its PR is merged and its story is accepted.\",\n );\n }\n const ready = await this.findValidDecision(\n issue.number,\n snapshot.baselineId,\n \"ready\",\n policy,\n );\n if (!ready)\n throw new AiDlcError(\"E_NOT_READY\", \"There is no valid ready decision for this baseline.\");\n build = await this.verifyBuild(Number(args.run), args.commit as string, policy);\n }\n const receipt: DecisionReceipt = {\n schemaVersion: DECISION_SCHEMA_VERSION,\n decisionId: decisionId(kind, comment.id),\n kind,\n issueNumber: issue.number,\n baselineId: snapshot.baselineId,\n baselineHash: snapshot.contentHash,\n actor: { id: comment.author.id, login: comment.author.login },\n source: { commentId: comment.id, commentBodyDigest: commentDigest(comment.body) },\n lane,\n build,\n policyVersion: policy.version,\n recordedAt: clock.now().toISOString(),\n };\n await evidence.write(\n decisionPath(this.repositoryId, issue.number, receipt.decisionId),\n receipt,\n );\n if (kind === \"accept\") {\n await github.closeIssue(issue.number, \"completed\");\n return `**\u0110\u00E3 ghi nh\u1EADn nghi\u1EC7m thu** \\`${receipt.decisionId}\\` cho \\`${snapshot.baselineId}\\` tr\u00EAn build ${build?.runId} (\\`${build?.headSha.slice(0, 7)}\\`). Issue \u0111\u00E3 \u0111\u01B0\u1EE3c \u0111\u00F3ng.`;\n }\n if (kind === \"ready\") {\n const block = renderPrBlock({\n issueNumber: issue.number,\n baselineId: snapshot.baselineId,\n hash: snapshot.contentHash,\n acceptanceCriteria:\n snapshot.kind === \"task\"\n ? snapshot.acRefs\n : snapshot.requirements.criteria.map((c) => c.id),\n });\n return [\n `**S\u1EB5n s\u00E0ng tri\u1EC3n khai** \\`${receipt.decisionId}\\` (lane \\`${lane}\\`).`,\n \"\",\n \"D\u00E1n kh\u1ED1i sau v\u00E0o m\u00F4 t\u1EA3 Pull Request:\",\n \"```text\",\n block,\n \"```\",\n ].join(\"\\n\");\n }\n return `**\u0110\u00E3 duy\u1EC7t nghi\u1EC7p v\u1EE5** \\`${receipt.decisionId}\\` cho \\`${snapshot.baselineId}\\`. DEV c\u00F3 th\u1EC3 x\u00E1c nh\u1EADn \\`ready\\`.`;\n }\n\n private async verifyBuild(\n runId: number,\n commit: string,\n policy: Policy,\n ): Promise<NonNullable<DecisionReceipt[\"build\"]>> {\n if (!Number.isSafeInteger(runId) || runId <= 0)\n throw new AiDlcError(\"E_SYNTAX\", \"`run` must be a workflow run id.\");\n const problems = await this.buildProblems(runId, commit, policy);\n if (problems.problems.length > 0 || !problems.run) {\n throw new AiDlcError(\n \"E_BUILD_INVALID\",\n `Build cannot be accepted:\\n- ${problems.problems.join(\"\\n- \")}`,\n );\n }\n const { run } = problems;\n return {\n runId: run.id,\n runAttempt: run.runAttempt,\n workflowPath: run.path,\n headSha: run.headSha,\n };\n }\n\n private async buildProblems(runId: number, commit: string, policy: Policy) {\n const run = await this.deps.github.getWorkflowRun(runId);\n const problems: string[] = [];\n if (!run) return { run: null, problems: [`Workflow run ${runId} was not found.`] };\n const branch = await this.deps.github.getDefaultBranch();\n if (run.repositoryId !== this.repositoryId) problems.push(\"run belongs to another repository\");\n if (!policy.acceptance.build_workflows.includes(run.path))\n problems.push(`workflow \\`${run.path}\\` is not an acceptance workflow`);\n if (run.event !== \"push\" || run.headBranch !== branch)\n problems.push(`run must come from a push to \\`${branch}\\``);\n if (run.headSha !== commit) problems.push(\"run commit does not match `commit`\");\n if (run.status !== \"completed\" || run.conclusion !== \"success\")\n problems.push(\"run did not complete successfully\");\n return { run, problems };\n }\n\n private async revoke(\n args: Record<string, string>,\n issue: IssueData,\n comment: CommentData,\n policy: Policy,\n ): Promise<string> {\n const id = args.decision as string;\n const receipt = await this.deps.evidence.read<DecisionReceipt>(\n decisionPath(this.repositoryId, issue.number, id),\n );\n if (!receipt)\n throw new AiDlcError(\n \"E_DECISION_NOT_FOUND\",\n `Decision \\`${id}\\` was not found on this Issue.`,\n );\n const actorId = comment.author.id;\n const allowed =\n receipt.actor.id === actorId || hasRole(policy, actorId, REQUIRED_ROLE[receipt.kind]);\n if (!allowed)\n throw new AiDlcError(\n \"E_ROLE\",\n \"Only the author or a holder of the same role may revoke this decision.\",\n );\n const revocation: Revocation = {\n schemaVersion: 1,\n decisionId: id,\n actor: { id: actorId, login: comment.author.login },\n reason: args.reason as string,\n source: { commentId: comment.id },\n recordedAt: this.deps.clock.now().toISOString(),\n };\n const result = await this.deps.evidence.write(\n revocationPath(this.repositoryId, issue.number, id),\n revocation,\n );\n return result === \"created\" ? `**\u0110\u00E3 thu h\u1ED3i** \\`${id}\\`.` : `\\`${id}\\` \u0111\u00E3 b\u1ECB thu h\u1ED3i tr\u01B0\u1EDBc \u0111\u00F3.`;\n }\n\n async listDecisions(issueNumber: number): Promise<DecisionReceipt[]> {\n const paths = await this.deps.evidence.list(`decisions/${this.repositoryId}/${issueNumber}/`);\n const receipts: DecisionReceipt[] = [];\n for (const path of paths) {\n const receipt = await this.deps.evidence.read<DecisionReceipt>(path);\n if (receipt) receipts.push(receipt);\n }\n return receipts;\n }\n\n async isValid(\n receipt: DecisionReceipt,\n policy: Policy,\n ): Promise<{ valid: boolean; reasons: string[] }> {\n const { evidence, github } = this.deps;\n const revoked =\n (await evidence.read(\n revocationPath(this.repositoryId, receipt.issueNumber, receipt.decisionId),\n )) !== null;\n const comment = await github.getComment(receipt.source.commentId);\n const snapshot = await evidence.read<BaselineSnapshot>(\n baselinePath(this.repositoryId, receipt.issueNumber, receipt.baselineId),\n );\n const snapshotHash = snapshot && verifySnapshot(snapshot) ? snapshot.contentHash : null;\n let buildValid: boolean | undefined;\n if (receipt.kind === \"accept\" && receipt.build) {\n const { problems } = await this.buildProblems(\n receipt.build.runId,\n receipt.build.headSha,\n policy,\n );\n buildValid = problems.length === 0;\n }\n return evaluateReceipt(receipt, {\n policy,\n revoked,\n currentCommentBody: comment ? comment.body : null,\n snapshotHash,\n ...(buildValid === undefined ? {} : { buildValid }),\n });\n }\n\n async findValidDecision(\n issueNumber: number,\n baselineId: string,\n kind: DecisionKind,\n policy: Policy,\n ): Promise<DecisionReceipt | null> {\n for (const receipt of await this.listDecisions(issueNumber)) {\n if (receipt.kind !== kind || receipt.baselineId !== baselineId) continue;\n if ((await this.isValid(receipt, policy)).valid) return receipt;\n }\n return null;\n }\n\n private async reportInvalidatedDecisions(\n issueNumber: number,\n commentId: number,\n action: string,\n ): Promise<void> {\n const affected = (await this.listDecisions(issueNumber)).filter(\n (receipt) => receipt.source.commentId === commentId,\n );\n if (affected.length === 0) return;\n await this.deps.github.upsertComment(\n issueNumber,\n marker(\"invalidated\", String(commentId)),\n `Comment quy\u1EBFt \u0111\u1ECBnh \u0111\u00E3 b\u1ECB ${action === \"deleted\" ? \"x\u00F3a\" : \"s\u1EEDa\"}; c\u00E1c quy\u1EBFt \u0111\u1ECBnh sau kh\u00F4ng c\u00F2n hi\u1EC7u l\u1EF1c: ${affected\n .map((receipt) => `\\`${receipt.decisionId}\\` (${receipt.kind})`)\n .join(\", \")}.`,\n );\n }\n\n /** Evaluates the `ai-dlc/baseline` gate for a pull request and publishes a commit status. */\n async checkPullRequest(prNumber: number): Promise<PrCheckResult> {\n const pr = await this.deps.github.getPullRequest(prNumber);\n const result = this.deps.enabled\n ? await this.evaluatePullRequest(prNumber).catch((error: unknown) => {\n if (!isAiDlcError(error)) throw error;\n return {\n state: \"failure\" as const,\n description: `${error.code}: ${firstLine(error.message)}`,\n details: [error.message],\n };\n })\n : {\n state: \"pending\" as const,\n description: \"AI-DLC is disabled by the operator\",\n details: [],\n };\n await this.deps.github.setCommitStatus(pr.headSha, {\n state: result.state,\n context: STATUS_CONTEXT,\n description: truncate(result.description, 140),\n });\n return result;\n }\n\n private async evaluatePullRequest(prNumber: number): Promise<PrCheckResult> {\n const { github } = this.deps;\n const policy = await this.policy();\n const pr = await github.getPullRequest(prNumber);\n for (const reference of closingReferences(pr.body)) {\n const referenced = await github.getIssue(reference).catch(() => null);\n const kind = referenced ? kindFromLabels(referenced.labels) : null;\n if (kind === \"story\" || kind === \"epic\") {\n throw new AiDlcError(\n \"E_CLOSING_KEYWORD\",\n `Use \\`Refs #${reference}\\`; closing keywords would close the ${kind} without acceptance.`,\n );\n }\n }\n if (pr.labels.includes(LABELS.exempt)) {\n return { state: \"success\", description: \"Exempt by maintainer label\", details: [] };\n }\n const block = parsePrBlock(pr.body);\n if (!block)\n throw new AiDlcError(\n \"E_PR_BLOCK\",\n \"PR body has no AI-DLC block. Run the context CLI or use the ready reply.\",\n );\n const issue = await github.getIssue(block.issueNumber);\n const snapshot = await this.loadSnapshot(issue.number, block.baselineId);\n if (snapshot.contentHash !== block.hash)\n throw new AiDlcError(\"E_HASH_MISMATCH\", \"AI-DLC-Hash does not match the baseline.\");\n if (snapshot.kind === \"epic\")\n throw new AiDlcError(\"E_PR_BLOCK\", \"A PR must reference a story or task, not an epic.\");\n this.assertCurrent(issue, snapshot);\n const ready = await this.findValidDecision(issue.number, snapshot.baselineId, \"ready\", policy);\n if (!ready || !ready.lane)\n throw new AiDlcError(\n \"E_NOT_READY\",\n `#${issue.number} has no valid ready decision for this baseline.`,\n );\n await this.assertApproved(snapshot, ready.lane, policy);\n const allowedAc = new Set(\n snapshot.kind === \"task\" ? snapshot.acRefs : snapshot.requirements.criteria.map((c) => c.id),\n );\n const unknown = block.acceptanceCriteria.filter((id) => !allowedAc.has(id));\n if (unknown.length > 0)\n throw new AiDlcError(\"E_PR_BLOCK\", `Unknown AC for this baseline: ${unknown.join(\", \")}.`);\n if (snapshot.kind === \"task\" && snapshot.parent !== null)\n await this.assertParentReady(snapshot.parent, policy);\n if (ready.lane === \"fast\") {\n const sensitive = (await github.listPullRequestFiles(prNumber)).filter((path) =>\n isSensitive(policy, path),\n );\n if (sensitive.length > 0) {\n throw new AiDlcError(\n \"E_SENSITIVE_PATH\",\n `Lane fast cannot change sensitive paths: ${sensitive.slice(0, 5).join(\", \")}.`,\n );\n }\n }\n return {\n state: \"success\",\n description: `${snapshot.baselineId} ready (${ready.lane})`,\n details: [],\n };\n }\n\n /** PO approves stories; a task inherits the approval of its parent story's current content. */\n private async assertApproved(\n snapshot: BaselineSnapshot,\n lane: LaneName,\n policy: Policy,\n ): Promise<void> {\n if (!policy.lanes[lane].requires_po_approval) return;\n if (snapshot.kind === \"task\") {\n if (snapshot.parent === null) {\n throw new AiDlcError(\"E_FORM\", \"A task needs a parent story in `### Issue cha`.\");\n }\n if (!(await this.parentDecision(snapshot.parent, \"approve\", policy))) {\n throw new AiDlcError(\n \"E_NOT_APPROVED\",\n `Lane \\`${lane}\\` requires a valid PO approval of parent story #${snapshot.parent} for its current content.`,\n );\n }\n return;\n }\n if (\n !(await this.findValidDecision(\n snapshot.source.issueNumber,\n snapshot.baselineId,\n \"approve\",\n policy,\n ))\n ) {\n throw new AiDlcError(\n \"E_NOT_APPROVED\",\n `Lane \\`${lane}\\` requires a valid PO approval for this baseline.`,\n );\n }\n }\n\n private async parentDecision(\n parentNumber: number,\n kind: DecisionKind,\n policy: Policy,\n ): Promise<DecisionReceipt | null> {\n const parent = await this.deps.github.getIssue(parentNumber);\n if (kindFromLabels(parent.labels) !== \"story\") {\n throw new AiDlcError(\"E_WRONG_KIND\", `Parent #${parentNumber} of a task must be a story.`);\n }\n const current = this.snapshotOf(parent);\n return this.findValidDecision(parentNumber, current.baselineId, kind, policy);\n }\n\n private async assertParentReady(parentNumber: number, policy: Policy): Promise<void> {\n if (!(await this.parentDecision(parentNumber, \"ready\", policy))) {\n throw new AiDlcError(\n \"E_NOT_READY\",\n `Parent story #${parentNumber} has no valid ready decision for its current content.`,\n );\n }\n }\n}\n\nfunction errorReply(error: AiDlcError): string {\n return [`**AI-DLC: \\`${error.code}\\`**`, \"\", sanitize(error.message)].join(\"\\n\");\n}\n\nfunction firstLine(text: string): string {\n return text.split(\"\\n\")[0] ?? \"\";\n}\n\nfunction truncate(text: string, max: number): string {\n return text.length <= max ? text : `${text.slice(0, max - 1)}\u2026`;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { appendFile, readFile } from \"node:fs/promises\";\nimport { GitBranchEvidenceStore } from \"../adapters/git-evidence.js\";\nimport { connectRepository, octokitFromToken } from \"../adapters/github.js\";\nimport { createJsonLogger } from \"../adapters/memory.js\";\nimport { POLICY_PATH, LEGACY_POLICY_PATH, parsePolicy } from \"../core/policy.js\";\nimport { systemClock } from \"../ports.js\";\nimport { WorkflowService } from \"../workflow/service.js\";\n\n/** Runs inside GitHub Actions. Never checks out or executes pull request code. */\nasync function main(): Promise<void> {\n const eventName = requireEnv(\"GITHUB_EVENT_NAME\");\n const payload = JSON.parse(await readFile(requireEnv(\"GITHUB_EVENT_PATH\"), \"utf8\")) as {\n action?: string;\n issue?: { number: number; pull_request?: unknown };\n comment?: { id: number };\n pull_request?: { number: number };\n sender?: { type?: string };\n };\n const [owner, repo] = requireEnv(\"GITHUB_REPOSITORY\").split(\"/\") as [string, string];\n const logger = createJsonLogger({ component: \"huddle60-action\", event: eventName });\n const token =\n process.env.HUDDLE60_TOKEN ||\n process.env.AI_DLC_TOKEN ||\n requireEnv(\"HUDDLE60_TOKEN or AI_DLC_TOKEN\");\n const octokit = octokitFromToken(token);\n const github = await connectRepository(octokit, owner, repo);\n let policySource = await github.readFile(POLICY_PATH, await github.getDefaultBranch());\n if (!policySource) {\n policySource = await github.readFile(LEGACY_POLICY_PATH, await github.getDefaultBranch());\n }\n const branch = policySource ? parsePolicy(policySource).evidence.branch : \"huddle60-evidence\";\n const workflow = new WorkflowService({\n github,\n evidence: new GitBranchEvidenceStore(octokit, owner, repo, branch),\n clock: systemClock,\n logger,\n enabled: process.env.HUDDLE60_ENABLED !== \"false\" && process.env.AI_DLC_ENABLED !== \"false\",\n });\n\n if (eventName === \"issue_comment\") {\n if (\n !payload.issue ||\n payload.issue.pull_request ||\n !payload.comment ||\n payload.sender?.type === \"Bot\"\n )\n return;\n const action = payload.action as \"created\" | \"edited\" | \"deleted\";\n await workflow.handleComment(payload.issue.number, payload.comment.id, action);\n return;\n }\n if (eventName === \"pull_request_target\" && payload.pull_request) {\n const result = await workflow.checkPullRequest(payload.pull_request.number);\n await summary([\n `### huddle60/baseline: ${result.state}`,\n \"\",\n result.description,\n ...result.details.map((line) => `> ${line}`),\n ]);\n return;\n }\n logger.info(\"event ignored\");\n}\n\nfunction requireEnv(name: string): string {\n const value = process.env[name];\n if (!value) throw new Error(`Missing environment variable ${name}`);\n return value;\n}\n\nasync function summary(lines: string[]): Promise<void> {\n const file = process.env.GITHUB_STEP_SUMMARY;\n if (file) await appendFile(file, `${lines.join(\"\\n\")}\\n`);\n}\n\nmain().catch((error: unknown) => {\n process.stderr.write(\n `ai-dlc action failed: ${error instanceof Error ? error.stack : String(error)}\\n`,\n );\n process.exitCode = 1;\n});\n", "import { setTimeout as delay } from \"node:timers/promises\";\nimport { canonicalJson } from \"../core/canonical.js\";\nimport { AiDlcError } from \"../core/errors.js\";\nimport type { EvidenceStore } from \"../ports.js\";\nimport { isStatus, type GitHubClient } from \"./github.js\";\n\nconst MAX_ATTEMPTS = 5;\n\n/**\n * Append-only JSON files on a dedicated branch, written through the Git Data API.\n * Every file has a unique path, so concurrent writers only race on the branch ref\n * and simply retry on a non-fast-forward update.\n */\nexport class GitBranchEvidenceStore implements EvidenceStore {\n constructor(\n private readonly octokit: GitHubClient,\n private readonly owner: string,\n private readonly repo: string,\n private readonly branch: string,\n ) {}\n\n private get base() {\n return { owner: this.owner, repo: this.repo };\n }\n\n private async readAt<T>(path: string, ref: string): Promise<T | null> {\n try {\n const { data } = await this.octokit.rest.repos.getContent({ ...this.base, path, ref });\n if (Array.isArray(data) || data.type !== \"file\" || !(\"content\" in data)) return null;\n return JSON.parse(Buffer.from(data.content, \"base64\").toString(\"utf8\")) as T;\n } catch (error) {\n if (isStatus(error, 404)) return null;\n throw error;\n }\n }\n\n async read<T>(path: string): Promise<T | null> {\n return this.readAt<T>(path, this.branch);\n }\n\n async list(prefix: string): Promise<string[]> {\n const directory = prefix.replace(/\\/+$/u, \"\");\n try {\n const { data } = await this.octokit.rest.repos.getContent({\n ...this.base,\n path: directory,\n ref: this.branch,\n });\n if (!Array.isArray(data)) return [];\n return data\n .filter((entry) => entry.type === \"file\")\n .map((entry) => entry.path)\n .sort();\n } catch (error) {\n if (isStatus(error, 404)) return [];\n throw error;\n }\n }\n\n async write(path: string, value: unknown): Promise<\"created\" | \"unchanged\"> {\n const canonical = canonicalJson(value);\n const content = `${JSON.stringify(JSON.parse(canonical), null, 2)}\\n`;\n for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt += 1) {\n const head = await this.headCommit();\n const existing = await this.readAt<unknown>(path, head.sha);\n if (existing !== null) {\n if (canonicalJson(existing) === canonical) return \"unchanged\";\n throw new AiDlcError(\n \"E_CONFLICT\",\n `Evidence already exists with different content at ${path}.`,\n );\n }\n const blob = await this.octokit.rest.git.createBlob({\n ...this.base,\n content,\n encoding: \"utf-8\",\n });\n const tree = await this.octokit.rest.git.createTree({\n ...this.base,\n base_tree: head.treeSha,\n tree: [{ path, mode: \"100644\", type: \"blob\", sha: blob.data.sha }],\n });\n const commit = await this.octokit.rest.git.createCommit({\n ...this.base,\n message: `huddle60: add ${path}`,\n tree: tree.data.sha,\n parents: [head.sha],\n });\n try {\n await this.octokit.rest.git.updateRef({\n ...this.base,\n ref: `heads/${this.branch}`,\n sha: commit.data.sha,\n force: false,\n });\n return \"created\";\n } catch (error) {\n if (!isStatus(error, 409, 422) || attempt === MAX_ATTEMPTS) throw error;\n await delay(250 * 2 ** attempt);\n }\n }\n throw new AiDlcError(\"E_GITHUB_API\", `Could not write ${path} after ${MAX_ATTEMPTS} attempts.`);\n }\n\n private async headCommit(): Promise<{ sha: string; treeSha: string }> {\n try {\n const ref = await this.octokit.rest.git.getRef({ ...this.base, ref: `heads/${this.branch}` });\n const commit = await this.octokit.rest.git.getCommit({\n ...this.base,\n commit_sha: ref.data.object.sha,\n });\n return { sha: commit.data.sha, treeSha: commit.data.tree.sha };\n } catch (error) {\n if (isStatus(error, 404)) {\n throw new AiDlcError(\n \"E_GITHUB_API\",\n `Evidence branch \\`${this.branch}\\` does not exist. Run \\`huddle60 init\\`.`,\n );\n }\n throw error;\n }\n }\n\n /** Creates the evidence branch as an orphan commit. Safe to call when it already exists. */\n async initialize(): Promise<\"created\" | \"exists\"> {\n try {\n await this.octokit.rest.git.getRef({ ...this.base, ref: `heads/${this.branch}` });\n return \"exists\";\n } catch (error) {\n if (!isStatus(error, 404)) throw error;\n }\n const readme = [\n \"# AI-DLC evidence\",\n \"\",\n \"Append-only baselines, decision receipts and revocations written by the AI-DLC GitHub App.\",\n \"Do not edit or force-push this branch; protect it with a ruleset.\",\n \"\",\n ].join(\"\\n\");\n const blob = await this.octokit.rest.git.createBlob({\n ...this.base,\n content: readme,\n encoding: \"utf-8\",\n });\n const tree = await this.octokit.rest.git.createTree({\n ...this.base,\n tree: [{ path: \"README.md\", mode: \"100644\", type: \"blob\", sha: blob.data.sha }],\n });\n const commit = await this.octokit.rest.git.createCommit({\n ...this.base,\n message: \"huddle60: initialize evidence branch\",\n tree: tree.data.sha,\n parents: [],\n });\n await this.octokit.rest.git.createRef({\n ...this.base,\n ref: `refs/heads/${this.branch}`,\n sha: commit.data.sha,\n });\n return \"created\";\n }\n}\n", "import { createHash } from \"node:crypto\";\n\nexport const CANONICAL_VERSION = 1;\n\nexport type JsonValue =\n null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue };\n\n/**\n * Normalizes free text so that cosmetic edits do not change a hash:\n * Unicode NFC, LF line endings, no trailing whitespace, no leading/trailing blank lines.\n */\nexport function normalizeText(value: string): string {\n return value\n .normalize(\"NFC\")\n .replace(/\\r\\n?/g, \"\\n\")\n .split(\"\\n\")\n .map((line) => line.replace(/[ \\t]+$/u, \"\"))\n .join(\"\\n\")\n .replace(/^\\n+/u, \"\")\n .replace(/\\n+$/u, \"\");\n}\n\nfunction normalizeDeep(value: unknown, path: string): JsonValue {\n if (value === null) return null;\n if (typeof value === \"string\") return normalizeText(value);\n if (typeof value === \"boolean\") return value;\n if (typeof value === \"number\") {\n if (!Number.isFinite(value)) throw new TypeError(`Non-finite number at ${path}`);\n return value;\n }\n if (Array.isArray(value))\n return value.map((item, index) => normalizeDeep(item, `${path}[${index}]`));\n if (typeof value === \"object\") {\n const result: { [key: string]: JsonValue } = {};\n for (const [key, item] of Object.entries(value as Record<string, unknown>)) {\n if (item === undefined) continue;\n result[key] = normalizeDeep(item, `${path}.${key}`);\n }\n return result;\n }\n throw new TypeError(`Unsupported value of type ${typeof value} at ${path}`);\n}\n\n/**\n * RFC 8785 (JCS) serialization. Object keys are sorted by UTF-16 code units and\n * primitives use ECMAScript JSON serialization, which is what JCS specifies.\n */\nexport function canonicalJson(value: unknown): string {\n return serialize(normalizeDeep(value, \"$\"));\n}\n\nfunction serialize(value: JsonValue): string {\n if (value === null || typeof value !== \"object\") return JSON.stringify(value);\n if (Array.isArray(value)) return `[${value.map(serialize).join(\",\")}]`;\n const keys = Object.keys(value).sort();\n return `{${keys.map((key) => `${JSON.stringify(key)}:${serialize(value[key] as JsonValue)}`).join(\",\")}}`;\n}\n\nexport function sha256(text: string): string {\n return `sha256:${createHash(\"sha256\").update(text, \"utf8\").digest(\"hex\")}`;\n}\n\n/** Hash of a payload, ignoring its own `contentHash` field. */\nexport function contentHash(payload: Record<string, unknown>): string {\n const { contentHash: _ignored, ...rest } = payload;\n return sha256(canonicalJson(rest));\n}\n\nexport function shortHash(hash: string, length = 12): string {\n return hash.replace(/^sha256:/u, \"\").slice(0, length);\n}\n", "export const ErrorCodes = [\n \"E_POLICY_INVALID\",\n \"E_SYNTAX\",\n \"E_ROLE\",\n \"E_FORM\",\n \"E_HASH_MISMATCH\",\n \"E_BASELINE_NOT_FOUND\",\n \"E_NOT_APPROVED\",\n \"E_NOT_READY\",\n \"E_DEPENDENCY_OPEN\",\n \"E_BUILD_INVALID\",\n \"E_CONFLICT\",\n \"E_DECISION_NOT_FOUND\",\n \"E_GITHUB_API\",\n \"E_GEMINI\",\n \"E_PLAN_SCHEMA\",\n \"E_PLAN_NOT_FOUND\",\n \"E_PLAN_STALE\",\n \"E_PLAN_LIMIT\",\n \"E_PLAN_BLOCKED\",\n \"E_PLAN_PARTIAL\",\n \"E_PLANNER_DISABLED\",\n \"E_NOT_REQUEST\",\n \"E_PR_BLOCK\",\n \"E_STALE\",\n \"E_SENSITIVE_PATH\",\n \"E_CLOSING_KEYWORD\",\n \"E_WRONG_KIND\",\n \"E_CONFIG\",\n] as const;\n\nexport type ErrorCode = (typeof ErrorCodes)[number];\n\n/** An expected, user-facing failure. The message must be safe to post on GitHub. */\nexport class AiDlcError extends Error {\n readonly code: ErrorCode;\n\n constructor(code: ErrorCode, message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = \"AiDlcError\";\n this.code = code;\n }\n}\n\nexport function isAiDlcError(error: unknown): error is AiDlcError {\n return error instanceof AiDlcError;\n}\n", "import { createAppAuth } from \"@octokit/auth-app\";\nimport { retry } from \"@octokit/plugin-retry\";\nimport { Octokit } from \"@octokit/rest\";\nimport { AiDlcError } from \"../core/errors.js\";\nimport type {\n Actor,\n CommentData,\n CommitState,\n IssueData,\n LocalGitHubPort,\n PullRequestData,\n RepoRef,\n WorkflowRunData,\n} from \"../ports.js\";\n\nconst RetryingOctokit = Octokit.plugin(retry);\nexport type GitHubClient = InstanceType<typeof RetryingOctokit>;\n\nconst USER_AGENT = \"huddle60/0.1.0\";\n\nconst defaultLog = process.env.AI_DLC_DEBUG\n ? undefined\n : {\n debug: () => {},\n info: () => {},\n warn: () => {},\n error: () => {},\n };\n\nexport function octokitFromToken(token: string): GitHubClient {\n return new RetryingOctokit({ auth: token, userAgent: USER_AGENT, log: defaultLog });\n}\n\nexport function octokitForInstallation(\n appId: string,\n privateKey: string,\n installationId: number,\n): GitHubClient {\n return new RetryingOctokit({\n authStrategy: createAppAuth,\n auth: { appId, privateKey, installationId },\n userAgent: USER_AGENT,\n log: defaultLog,\n });\n}\n\nexport function isStatus(error: unknown, ...statuses: number[]): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n statuses.includes((error as { status?: number }).status ?? -1)\n );\n}\n\ninterface RawUser {\n id: number;\n login: string;\n type: string;\n}\n\ninterface RawIssue {\n id: number;\n node_id: string;\n number: number;\n title: string;\n body?: string | null;\n state: string;\n state_reason?: string | null;\n labels: Array<string | { name?: string }>;\n user: RawUser | null;\n pull_request?: unknown;\n}\n\nfunction toActor(user: RawUser | null): IssueData[\"author\"] {\n return user\n ? { id: user.id, login: user.login, type: user.type }\n : { id: 0, login: \"ghost\", type: \"User\" };\n}\n\nfunction toIssue(raw: RawIssue): IssueData {\n return {\n id: raw.id,\n nodeId: raw.node_id,\n number: raw.number,\n title: raw.title,\n body: raw.body ?? \"\",\n state: raw.state === \"closed\" ? \"closed\" : \"open\",\n stateReason: raw.state_reason ?? null,\n labels: raw.labels\n .map((label) => (typeof label === \"string\" ? label : (label.name ?? \"\")))\n .filter(Boolean),\n author: toActor(raw.user),\n isPullRequest: raw.pull_request !== undefined && raw.pull_request !== null,\n };\n}\n\nexport async function connectRepository(\n octokit: GitHubClient,\n owner: string,\n repo: string,\n): Promise<OctokitGitHub> {\n const { data } = await octokit.rest.repos.get({ owner, repo });\n return new OctokitGitHub(octokit, { owner, repo, repositoryId: data.id }, data.default_branch);\n}\n\nexport class OctokitGitHub implements LocalGitHubPort {\n private readonly projectIds = new Map<string, string>();\n\n constructor(\n readonly octokit: GitHubClient,\n readonly repo: RepoRef,\n private defaultBranch?: string,\n ) {}\n\n private get base() {\n return { owner: this.repo.owner, repo: this.repo.repo };\n }\n\n async getDefaultBranch(): Promise<string> {\n if (!this.defaultBranch) {\n const { data } = await this.octokit.rest.repos.get(this.base);\n this.defaultBranch = data.default_branch;\n }\n return this.defaultBranch;\n }\n\n async readFile(path: string, ref?: string): Promise<string | null> {\n try {\n const { data } = await this.octokit.rest.repos.getContent({\n ...this.base,\n path,\n ...(ref ? { ref } : {}),\n });\n if (Array.isArray(data) || data.type !== \"file\" || !(\"content\" in data)) return null;\n return Buffer.from(data.content, \"base64\").toString(\"utf8\");\n } catch (error) {\n if (isStatus(error, 404)) return null;\n throw error;\n }\n }\n\n async getIssue(number: number): Promise<IssueData> {\n try {\n const { data } = await this.octokit.rest.issues.get({ ...this.base, issue_number: number });\n return toIssue(data as RawIssue);\n } catch (error) {\n if (isStatus(error, 404, 410))\n throw new AiDlcError(\"E_GITHUB_API\", `Issue #${number} was not found.`);\n throw error;\n }\n }\n\n async getComment(id: number): Promise<CommentData | null> {\n try {\n const { data } = await this.octokit.rest.issues.getComment({ ...this.base, comment_id: id });\n return { id: data.id, body: data.body ?? \"\", author: toActor(data.user as RawUser | null) };\n } catch (error) {\n if (isStatus(error, 404)) return null;\n throw error;\n }\n }\n\n async createIssue(input: { title: string; body: string; labels: string[] }): Promise<IssueData> {\n const { data } = await this.octokit.rest.issues.create({ ...this.base, ...input });\n return toIssue(data as RawIssue);\n }\n\n async listIssuesWithLabel(label: string): Promise<IssueData[]> {\n const items = await this.octokit.paginate(this.octokit.rest.issues.listForRepo, {\n ...this.base,\n labels: label,\n state: \"all\",\n per_page: 100,\n });\n return (items as RawIssue[]).map(toIssue).filter((issue) => !issue.isPullRequest);\n }\n\n async addLabels(issueNumber: number, labels: string[]): Promise<void> {\n await this.octokit.rest.issues.addLabels({ ...this.base, issue_number: issueNumber, labels });\n }\n\n async removeLabel(issueNumber: number, label: string): Promise<void> {\n try {\n await this.octokit.rest.issues.removeLabel({\n ...this.base,\n issue_number: issueNumber,\n name: label,\n });\n } catch (error) {\n if (!isStatus(error, 404)) throw error;\n }\n }\n\n async upsertComment(issueNumber: number, marker: string, body: string): Promise<void> {\n const comments = await this.octokit.paginate(this.octokit.rest.issues.listComments, {\n ...this.base,\n issue_number: issueNumber,\n per_page: 100,\n });\n // Only our own bot comments are updated; users could paste a marker into theirs.\n const existing = comments.find(\n (comment) => comment.user?.type === \"Bot\" && (comment.body ?? \"\").includes(marker),\n );\n const text = body.includes(marker) ? body : `${body}\\n${marker}`;\n if (existing) {\n await this.octokit.rest.issues.updateComment({\n ...this.base,\n comment_id: existing.id,\n body: text,\n });\n } else {\n await this.octokit.rest.issues.createComment({\n ...this.base,\n issue_number: issueNumber,\n body: text,\n });\n }\n }\n\n async closeIssue(issueNumber: number, reason: \"completed\" | \"not_planned\"): Promise<void> {\n await this.octokit.rest.issues.update({\n ...this.base,\n issue_number: issueNumber,\n state: \"closed\",\n state_reason: reason,\n });\n }\n\n async addSubIssue(parentNumber: number, childId: number): Promise<\"linked\" | \"unsupported\"> {\n try {\n await this.octokit.request(\"POST /repos/{owner}/{repo}/issues/{issue_number}/sub_issues\", {\n ...this.base,\n issue_number: parentNumber,\n sub_issue_id: childId,\n });\n return \"linked\";\n } catch (error) {\n if (isStatus(error, 404)) return \"unsupported\";\n throw error;\n }\n }\n\n private async projectId(owner: string, number: number): Promise<string> {\n const key = `${owner}/${number}`;\n const cached = this.projectIds.get(key);\n if (cached) return cached;\n const query = `query($owner: String!, $number: Int!) {\n organization(login: $owner) { projectV2(number: $number) { id } }\n }`;\n let id: string | undefined;\n try {\n const result = await this.octokit.graphql<{\n organization: { projectV2: { id: string } | null } | null;\n }>(query, { owner, number });\n id = result.organization?.projectV2?.id;\n } catch {\n const userQuery = `query($owner: String!, $number: Int!) { user(login: $owner) { projectV2(number: $number) { id } } }`;\n const result = await this.octokit.graphql<{\n user: { projectV2: { id: string } | null } | null;\n }>(userQuery, { owner, number });\n id = result.user?.projectV2?.id;\n }\n if (!id)\n throw new AiDlcError(\"E_GITHUB_API\", `Project ${key} was not found or is not accessible.`);\n this.projectIds.set(key, id);\n return id;\n }\n\n async addToProject(\n project: { owner: string; number: number },\n contentNodeId: string,\n ): Promise<void> {\n const projectId = await this.projectId(project.owner, project.number);\n await this.octokit.graphql(\n `mutation($projectId: ID!, $contentId: ID!) {\n addProjectV2ItemById(input: { projectId: $projectId, contentId: $contentId }) { item { id } }\n }`,\n { projectId, contentId: contentNodeId },\n );\n }\n\n async getPullRequest(number: number): Promise<PullRequestData> {\n const { data } = await this.octokit.rest.pulls.get({ ...this.base, pull_number: number });\n return {\n number: data.number,\n body: data.body ?? \"\",\n headSha: data.head.sha,\n labels: data.labels.map((label) => label.name),\n };\n }\n\n async listPullRequestFiles(number: number): Promise<string[]> {\n const files = await this.octokit.paginate(this.octokit.rest.pulls.listFiles, {\n ...this.base,\n pull_number: number,\n per_page: 100,\n });\n return files.flatMap((file) =>\n file.previous_filename ? [file.filename, file.previous_filename] : [file.filename],\n );\n }\n\n async setCommitStatus(\n sha: string,\n status: { state: CommitState; context: string; description: string },\n ): Promise<void> {\n await this.octokit.rest.repos.createCommitStatus({ ...this.base, sha, ...status });\n }\n\n async getWorkflowRun(runId: number): Promise<WorkflowRunData | null> {\n try {\n const { data } = await this.octokit.rest.actions.getWorkflowRun({\n ...this.base,\n run_id: runId,\n });\n return toRun(data);\n } catch (error) {\n if (isStatus(error, 404)) return null;\n throw error;\n }\n }\n\n async viewer(): Promise<Actor> {\n const { data } = await this.octokit.rest.users.getAuthenticated();\n return { id: data.id, login: data.login, type: data.type };\n }\n\n async listOpenIssuesWithLabel(label: string): Promise<IssueData[]> {\n const items = await this.octokit.paginate(this.octokit.rest.issues.listForRepo, {\n ...this.base,\n labels: label,\n state: \"open\",\n per_page: 100,\n });\n return (items as RawIssue[]).map(toIssue).filter((issue) => !issue.isPullRequest);\n }\n\n async createComment(issueNumber: number, body: string): Promise<CommentData> {\n const { data } = await this.octokit.rest.issues.createComment({\n ...this.base,\n issue_number: issueNumber,\n body,\n });\n return { id: data.id, body: data.body ?? \"\", author: toActor(data.user as RawUser | null) };\n }\n\n async findBotComment(issueNumber: number, marker: string): Promise<CommentData | null> {\n const comments = await this.octokit.paginate(this.octokit.rest.issues.listComments, {\n ...this.base,\n issue_number: issueNumber,\n per_page: 100,\n });\n const found = comments\n .filter((comment) => comment.user?.type === \"Bot\" && (comment.body ?? \"\").includes(marker))\n .at(-1);\n return found\n ? { id: found.id, body: found.body ?? \"\", author: toActor(found.user as RawUser | null) }\n : null;\n }\n\n async listSuccessfulRuns(\n workflowPath: string,\n branch: string,\n limit: number,\n ): Promise<WorkflowRunData[]> {\n try {\n const { data } = await this.octokit.rest.actions.listWorkflowRuns({\n ...this.base,\n workflow_id: workflowPath.split(\"/\").pop() ?? workflowPath,\n branch,\n event: \"push\",\n status: \"success\",\n per_page: limit,\n });\n return data.workflow_runs.map(toRun);\n } catch (error) {\n if (isStatus(error, 404)) return [];\n throw error;\n }\n }\n\n async ensureLabel(label: {\n name: string;\n color: string;\n description: string;\n }): Promise<\"created\" | \"exists\"> {\n try {\n await this.octokit.rest.issues.createLabel({ ...this.base, ...label });\n return \"created\";\n } catch (error) {\n if (isStatus(error, 422)) return \"exists\";\n throw error;\n }\n }\n}\n\ninterface RawRun {\n id: number;\n run_attempt?: number;\n path: string;\n event: string;\n head_branch: string | null;\n head_sha: string;\n status: string | null;\n conclusion: string | null;\n repository: { id: number };\n}\n\nfunction toRun(data: RawRun): WorkflowRunData {\n return {\n id: data.id,\n runAttempt: data.run_attempt ?? 1,\n path: data.path.split(\"@\")[0] ?? data.path,\n event: data.event,\n headBranch: data.head_branch,\n headSha: data.head_sha,\n status: data.status,\n conclusion: data.conclusion,\n repositoryId: data.repository.id,\n };\n}\n", "import { canonicalJson } from \"../core/canonical.js\";\nimport { AiDlcError } from \"../core/errors.js\";\nimport type { PlanRecord } from \"../core/plan.js\";\nimport type { CreationLedger, EvidenceStore, Logger, PlanStore } from \"../ports.js\";\n\nexport class MemoryEvidenceStore implements EvidenceStore {\n readonly files = new Map<string, string>();\n\n async read<T>(path: string): Promise<T | null> {\n const value = this.files.get(path);\n return value === undefined ? null : (JSON.parse(value) as T);\n }\n\n async write(path: string, value: unknown): Promise<\"created\" | \"unchanged\"> {\n const serialized = canonicalJson(value);\n const existing = this.files.get(path);\n if (existing === undefined) {\n this.files.set(path, serialized);\n return \"created\";\n }\n if (existing === serialized) return \"unchanged\";\n throw new AiDlcError(\n \"E_CONFLICT\",\n `Evidence already exists with different content at ${path}.`,\n );\n }\n\n async list(prefix: string): Promise<string[]> {\n return [...this.files.keys()].filter((path) => path.startsWith(prefix)).sort();\n }\n}\n\nexport class MemoryPlanStore implements PlanStore {\n readonly deliveries = new Set<string>();\n readonly plans = new Map<string, PlanRecord>();\n readonly ledgers = new Map<string, CreationLedger>();\n private readonly leases = new Map<string, { owner: string; until: number }>();\n\n async claimDelivery(deliveryId: string): Promise<boolean> {\n if (this.deliveries.has(deliveryId)) return false;\n this.deliveries.add(deliveryId);\n return true;\n }\n\n async releaseDelivery(deliveryId: string): Promise<void> {\n this.deliveries.delete(deliveryId);\n }\n\n async getPlan(planId: string): Promise<PlanRecord | null> {\n return structuredClone(this.plans.get(planId) ?? null);\n }\n\n async latestPlanForIssue(repositoryId: number, issueNumber: number): Promise<PlanRecord | null> {\n const candidates = [...this.plans.values()].filter(\n (plan) =>\n plan.source.repositoryId === repositoryId && plan.source.issueNumber === issueNumber,\n );\n candidates.sort((a, b) => b.revision - a.revision);\n return structuredClone(candidates[0] ?? null);\n }\n\n async savePlan(record: PlanRecord): Promise<void> {\n this.plans.set(record.planId, structuredClone(record));\n }\n\n async getLedger(planId: string): Promise<CreationLedger | null> {\n return structuredClone(this.ledgers.get(planId) ?? null);\n }\n\n async saveLedger(ledger: CreationLedger): Promise<void> {\n this.ledgers.set(ledger.planId, structuredClone(ledger));\n }\n\n async acquireLease(key: string, owner: string, ttlMs: number): Promise<boolean> {\n const current = this.leases.get(key);\n const now = Date.now();\n if (current && current.until > now && current.owner !== owner) return false;\n this.leases.set(key, { owner, until: now + ttlMs });\n return true;\n }\n\n async releaseLease(key: string, owner: string): Promise<void> {\n if (this.leases.get(key)?.owner === owner) this.leases.delete(key);\n }\n}\n\n/** JSON lines on stdout/stderr, which Cloud Logging parses as structured entries. */\nexport function createJsonLogger(base: Record<string, unknown> = {}): Logger {\n const write = (severity: string, message: string, fields?: Record<string, unknown>) => {\n const line = JSON.stringify({ severity, message, ...base, ...fields });\n if (severity === \"ERROR\") process.stderr.write(`${line}\\n`);\n else process.stdout.write(`${line}\\n`);\n };\n return {\n info: (message, fields) => write(\"INFO\", message, fields),\n warn: (message, fields) => write(\"WARNING\", message, fields),\n error: (message, fields) => write(\"ERROR\", message, fields),\n };\n}\n\nexport const silentLogger: Logger = { info: () => {}, warn: () => {}, error: () => {} };\n", "import { parse as parseYaml } from \"yaml\";\nimport { z } from \"zod\";\nimport { AiDlcError } from \"./errors.js\";\n\nconst Member = z.object({\n id: z.number().int().positive(),\n login: z.string().min(1),\n});\n\nconst Lane = z.object({\n requires_po_approval: z.boolean(),\n});\n\nexport const PolicySchema = z\n .object({\n version: z.literal(1),\n roles: z.object({\n po: z.array(Member).min(1),\n dev: z.array(Member).default([]),\n maintainer: z.array(Member).default([]),\n }),\n project: z\n .object({\n owner: z.string().min(1),\n number: z.number().int().positive(),\n })\n .optional(),\n lanes: z\n .object({\n fast: Lane,\n standard: Lane,\n strict: Lane,\n })\n .default({\n fast: { requires_po_approval: false },\n standard: { requires_po_approval: true },\n strict: { requires_po_approval: true },\n }),\n sensitive_paths: z.array(z.string().min(1)).default([]),\n evidence: z\n .object({ branch: z.string().min(1).default(\"huddle60-evidence\") })\n .default({ branch: \"huddle60-evidence\" }),\n acceptance: z\n .object({ build_workflows: z.array(z.string().min(1)).min(1) })\n .default({ build_workflows: [\".github/workflows/build.yml\"] }),\n planner: z\n .object({\n max_nodes: z.number().int().min(1).max(200).default(60),\n plan_ttl_days: z.number().int().min(1).max(90).default(30),\n })\n .default({ max_nodes: 60, plan_ttl_days: 30 }),\n })\n .superRefine((policy, ctx) => {\n const bots = [...policy.roles.po, ...policy.roles.dev, ...policy.roles.maintainer].filter(\n (member) => member.login.endsWith(\"[bot]\"),\n );\n for (const bot of bots) {\n ctx.addIssue({ code: \"custom\", message: `Bot account ${bot.login} cannot hold a role` });\n }\n });\n\nexport type Policy = z.infer<typeof PolicySchema>;\nexport type Role = \"po\" | \"dev\" | \"maintainer\";\nexport type LaneName = keyof Policy[\"lanes\"];\n\nexport const POLICY_PATH = \".github/huddle60/policy.yml\";\nexport const LEGACY_POLICY_PATH = \".github/ai-dlc/policy.yml\";\n\nexport function parsePolicy(source: string): Policy {\n let raw: unknown;\n try {\n raw = parseYaml(source);\n } catch (error) {\n throw new AiDlcError(\"E_POLICY_INVALID\", \"Policy file is not valid YAML.\", { cause: error });\n }\n const result = PolicySchema.safeParse(raw);\n if (!result.success) {\n throw new AiDlcError(\n \"E_POLICY_INVALID\",\n `Policy file is invalid:\\n${z.prettifyError(result.error)}`,\n );\n }\n return result.data;\n}\n\nexport function hasRole(policy: Policy, userId: number, role: Role): boolean {\n return policy.roles[role].some((member) => member.id === userId);\n}\n\nexport function rolesOf(policy: Policy, userId: number): Role[] {\n return ([\"po\", \"dev\", \"maintainer\"] as const).filter((role) => hasRole(policy, userId, role));\n}\n\n/** Minimal glob matcher supporting `*`, `**` and literal segments. */\nexport function matchesPath(pattern: string, path: string): boolean {\n let regex = \"\";\n for (let index = 0; index < pattern.length; index += 1) {\n const char = pattern[index] as string;\n if (char === \"*\") {\n if (pattern[index + 1] === \"*\") {\n regex += \".*\";\n index += 1;\n if (pattern[index + 1] === \"/\") index += 1;\n } else {\n regex += \"[^/]*\";\n }\n } else if (char === \"?\") {\n regex += \"[^/]\";\n } else {\n regex += char.replace(/[.+^${}()|[\\]\\\\]/gu, \"\\\\$&\");\n }\n }\n return new RegExp(`^${regex}$`, \"u\").test(path);\n}\n\nexport function isSensitive(policy: Policy, path: string): boolean {\n return policy.sensitive_paths.some((pattern) => matchesPath(pattern, path));\n}\n", "import type { PlanRecord } from \"./core/plan.js\";\n\nexport interface Actor {\n id: number;\n login: string;\n type: string;\n}\n\nexport interface RepoRef {\n owner: string;\n repo: string;\n repositoryId: number;\n}\n\nexport interface IssueData {\n id: number;\n nodeId: string;\n number: number;\n title: string;\n body: string;\n state: \"open\" | \"closed\";\n stateReason: string | null;\n labels: string[];\n author: Actor;\n isPullRequest: boolean;\n}\n\nexport interface CommentData {\n id: number;\n body: string;\n author: Actor;\n}\n\nexport interface PullRequestData {\n number: number;\n body: string;\n headSha: string;\n labels: string[];\n}\n\nexport interface WorkflowRunData {\n id: number;\n runAttempt: number;\n path: string;\n event: string;\n headBranch: string | null;\n headSha: string;\n status: string | null;\n conclusion: string | null;\n repositoryId: number;\n}\n\nexport type CommitState = \"success\" | \"failure\" | \"pending\" | \"error\";\n\n/** The subset of the GitHub API used by AI-DLC, scoped to one repository installation. */\nexport interface GitHubPort {\n readonly repo: RepoRef;\n getDefaultBranch(): Promise<string>;\n readFile(path: string, ref?: string): Promise<string | null>;\n getIssue(number: number): Promise<IssueData>;\n getComment(id: number): Promise<CommentData | null>;\n createIssue(input: { title: string; body: string; labels: string[] }): Promise<IssueData>;\n listIssuesWithLabel(label: string): Promise<IssueData[]>;\n addLabels(issueNumber: number, labels: string[]): Promise<void>;\n removeLabel(issueNumber: number, label: string): Promise<void>;\n /** Edits the bot comment containing `marker`, or creates it. */\n upsertComment(issueNumber: number, marker: string, body: string): Promise<void>;\n closeIssue(issueNumber: number, reason: \"completed\" | \"not_planned\"): Promise<void>;\n /** Links a child as a native sub-issue. Returns \"unsupported\" when the API is unavailable. */\n addSubIssue(parentNumber: number, childId: number): Promise<\"linked\" | \"unsupported\">;\n addToProject(project: { owner: string; number: number }, contentNodeId: string): Promise<void>;\n getPullRequest(number: number): Promise<PullRequestData>;\n listPullRequestFiles(number: number): Promise<string[]>;\n setCommitStatus(\n sha: string,\n status: { state: CommitState; context: string; description: string },\n ): Promise<void>;\n getWorkflowRun(runId: number): Promise<WorkflowRunData | null>;\n}\n\n/** Extra calls used by the local app, which acts with the signed-in user's own token. */\nexport interface LocalGitHubPort extends GitHubPort {\n viewer(): Promise<Actor>;\n listOpenIssuesWithLabel(label: string): Promise<IssueData[]>;\n createComment(issueNumber: number, body: string): Promise<CommentData>;\n /** Latest comment written by a bot that contains `marker`. */\n findBotComment(issueNumber: number, marker: string): Promise<CommentData | null>;\n /** Successful `push` runs of a workflow on `branch`, newest first. */\n listSuccessfulRuns(\n workflowPath: string,\n branch: string,\n limit: number,\n ): Promise<WorkflowRunData[]>;\n ensureLabel(label: {\n name: string;\n color: string;\n description: string;\n }): Promise<\"created\" | \"exists\">;\n}\n\n/** Append-only JSON store for baselines, decisions and revocations. */\nexport interface EvidenceStore {\n read<T>(path: string): Promise<T | null>;\n /** Creates the file; identical content is a no-op, different content is a conflict. */\n write(path: string, value: unknown): Promise<\"created\" | \"unchanged\">;\n list(prefix: string): Promise<string[]>;\n}\n\nexport interface ModelUsage {\n inputTokens: number;\n outputTokens: number;\n}\n\nexport interface ModelPort {\n readonly modelId: string;\n generateJson(input: {\n system: string;\n user: string;\n jsonSchema: Record<string, unknown>;\n }): Promise<{ text: string; usage: ModelUsage }>;\n}\n\nexport type LedgerItemState = \"creating\" | \"created\";\n\nexport interface LedgerItem {\n state: LedgerItemState;\n issueNumber?: number;\n issueId?: number;\n issueNodeId?: string;\n attemptedAt: string;\n subIssue?: \"linked\" | \"unsupported\" | \"failed\";\n project?: \"added\" | \"skipped\" | \"failed\";\n}\n\nexport interface CreationLedger {\n planId: string;\n planHash: string;\n status: \"creating\" | \"partial\" | \"created\";\n items: Record<string, LedgerItem>;\n errors: string[];\n updatedAt: string;\n}\n\nexport interface PlanStore {\n /** Returns false when the delivery was already claimed. */\n claimDelivery(deliveryId: string): Promise<boolean>;\n /** Undoes a claim when the job could not be queued, so a redelivery is accepted. */\n releaseDelivery(deliveryId: string): Promise<void>;\n getPlan(planId: string): Promise<PlanRecord | null>;\n latestPlanForIssue(repositoryId: number, issueNumber: number): Promise<PlanRecord | null>;\n savePlan(record: PlanRecord): Promise<void>;\n getLedger(planId: string): Promise<CreationLedger | null>;\n saveLedger(ledger: CreationLedger): Promise<void>;\n /** Short exclusive lease so only one worker creates Issues for a plan at a time. */\n acquireLease(key: string, owner: string, ttlMs: number): Promise<boolean>;\n releaseLease(key: string, owner: string): Promise<void>;\n}\n\nexport type PlannerJob =\n | {\n type: \"request\";\n deliveryId: string;\n installationId: number;\n owner: string;\n repo: string;\n issueNumber: number;\n }\n | {\n type: \"request-edited\";\n deliveryId: string;\n installationId: number;\n owner: string;\n repo: string;\n issueNumber: number;\n }\n | {\n type: \"command\";\n deliveryId: string;\n installationId: number;\n owner: string;\n repo: string;\n issueNumber: number;\n commentId: number;\n };\n\nexport interface JobQueue {\n enqueue(job: PlannerJob): Promise<void>;\n}\n\nexport interface Clock {\n now(): Date;\n}\n\nexport const systemClock: Clock = { now: () => new Date() };\n\nexport interface Logger {\n info(message: string, fields?: Record<string, unknown>): void;\n warn(message: string, fields?: Record<string, unknown>): void;\n error(message: string, fields?: Record<string, unknown>): void;\n}\n", "import { AiDlcError } from \"./errors.js\";\n\nconst NO_RESPONSE = \"_No response_\";\n\n/** Parses the `### Label` sections that GitHub renders for Issue forms. */\nexport function parseIssueForm(body: string | null | undefined): Map<string, string> {\n const sections = new Map<string, string>();\n const lines = (body ?? \"\").replace(/\\r\\n?/gu, \"\\n\").split(\"\\n\");\n let current: string | null = null;\n let buffer: string[] = [];\n const flush = () => {\n if (current === null) return;\n const value = buffer.join(\"\\n\").trim();\n sections.set(current, value === NO_RESPONSE ? \"\" : value);\n };\n for (const line of lines) {\n const heading = /^###\\s+(.+?)\\s*$/u.exec(line);\n if (heading) {\n flush();\n current = heading[1] as string;\n buffer = [];\n } else if (current !== null) {\n buffer.push(line);\n }\n }\n flush();\n return sections;\n}\n\nexport function requireSection(sections: Map<string, string>, label: string): string {\n const value = sections.get(label);\n if (value === undefined || value.length === 0) {\n throw new AiDlcError(\"E_FORM\", `Required section \\`### ${label}\\` is missing or empty.`);\n }\n return value;\n}\n\nexport interface Criterion {\n id: string;\n text: string;\n}\n\nconst CRITERION_LINE = /^-\\s+((?:AC|EC)-\\d{2,3}):\\s+(.+)$/u;\n\n/** Extracts AC/EC lines. Non-empty lines that look like bullets but are malformed are rejected. */\nexport function parseCriteria(text: string): Criterion[] {\n const criteria: Criterion[] = [];\n const seen = new Set<string>();\n for (const rawLine of text.split(\"\\n\")) {\n const line = rawLine.trim();\n if (line.length === 0) continue;\n const match = CRITERION_LINE.exec(line);\n if (!match) {\n if (/^-\\s+(AC|EC)/u.test(line)) {\n throw new AiDlcError(\n \"E_FORM\",\n `Malformed criterion line: \\`${line}\\`. Use \\`- AC-01: ...\\`.`,\n );\n }\n continue;\n }\n const id = match[1] as string;\n if (seen.has(id)) throw new AiDlcError(\"E_FORM\", `Duplicate criterion id \\`${id}\\`.`);\n seen.add(id);\n criteria.push({ id, text: (match[2] as string).trim() });\n }\n return criteria;\n}\n\n/** Parses `#12, #13` style references; only same-repository references are supported. */\nexport function parseIssueRefs(text: string | undefined): number[] {\n if (!text) return [];\n const refs = new Set<number>();\n for (const part of text.split(/[\\s,]+/u)) {\n if (part.length === 0) continue;\n const match = /^#(\\d+)$/u.exec(part);\n if (!match) {\n throw new AiDlcError(\"E_FORM\", `Invalid issue reference \\`${part}\\`. Use \\`#123\\`.`);\n }\n refs.add(Number(match[1]));\n }\n return [...refs].sort((a, b) => a - b);\n}\n", "/**\n * Labels and Issue form headings are part of the public contract: the parser\n * reads them back from Issues. Renaming one is a breaking change.\n */\nexport const LABELS = {\n request: \"huddle60:request\",\n planDraft: \"huddle60:plan-draft\",\n planCreated: \"huddle60:plan-created\",\n planPartial: \"huddle60:plan-partial\",\n fromPlan: \"huddle60:from-plan\",\n stale: \"huddle60:stale\",\n exempt: \"huddle60:exempt\",\n epic: \"type:epic\",\n story: \"type:story\",\n task: \"type:task\",\n} as const;\n\nexport const LEGACY_LABELS = {\n request: \"ai-dlc:request\",\n planDraft: \"ai-dlc:plan-draft\",\n planCreated: \"ai-dlc:plan-created\",\n planPartial: \"ai-dlc:plan-partial\",\n fromPlan: \"ai-dlc:from-plan\",\n stale: \"ai-dlc:stale\",\n exempt: \"ai-dlc:exempt\",\n} as const;\n\nexport type WorkItemKind = \"epic\" | \"story\" | \"task\";\n\nexport const KIND_LABEL: Record<WorkItemKind, string> = {\n epic: LABELS.epic,\n story: LABELS.story,\n task: LABELS.task,\n};\n\nexport const SECTIONS = {\n request: \"Y\u00EAu c\u1EA7u\",\n goal: \"M\u1EE5c ti\u00EAu v\u00E0 ng\u01B0\u1EDDi d\u00F9ng\",\n scope: \"Ph\u1EA1m vi\",\n parent: \"Issue cha\",\n blockedBy: \"Blocked by\",\n epicCriteria: \"Ti\u00EAu ch\u00ED nghi\u1EC7m thu Epic\",\n storyCriteria: \"Acceptance Criteria\",\n acRefs: \"AC li\u00EAn quan\",\n technicalRefs: \"Tham chi\u1EBFu k\u1EF9 thu\u1EADt\",\n risks: \"C\u00E2u h\u1ECFi v\u00E0 r\u1EE7i ro\",\n} as const;\n\n/** Sections that belong to the requirement content of each kind and therefore to its hash. */\nexport const REQUIREMENT_SECTIONS: Record<WorkItemKind, readonly string[]> = {\n epic: [\n SECTIONS.goal,\n SECTIONS.scope,\n SECTIONS.epicCriteria,\n SECTIONS.technicalRefs,\n SECTIONS.risks,\n ],\n story: [\n SECTIONS.goal,\n SECTIONS.scope,\n SECTIONS.parent,\n SECTIONS.blockedBy,\n SECTIONS.storyCriteria,\n SECTIONS.technicalRefs,\n SECTIONS.risks,\n ],\n task: [\n SECTIONS.goal,\n SECTIONS.scope,\n SECTIONS.parent,\n SECTIONS.blockedBy,\n SECTIONS.acRefs,\n SECTIONS.technicalRefs,\n SECTIONS.risks,\n ],\n};\n\nexport const CRITERIA_SECTION: Record<WorkItemKind, string | null> = {\n epic: SECTIONS.epicCriteria,\n story: SECTIONS.storyCriteria,\n task: null,\n};\n\nexport function kindFromLabels(labels: readonly string[]): WorkItemKind | null {\n const kinds = (Object.keys(KIND_LABEL) as WorkItemKind[]).filter((kind) =>\n labels.includes(KIND_LABEL[kind]),\n );\n return kinds.length === 1 ? (kinds[0] as WorkItemKind) : null;\n}\n", "import { CANONICAL_VERSION, contentHash, shortHash } from \"./canonical.js\";\nimport { AiDlcError } from \"./errors.js\";\nimport { parseCriteria, parseIssueForm, parseIssueRefs, type Criterion } from \"./issue-form.js\";\nimport {\n CRITERIA_SECTION,\n REQUIREMENT_SECTIONS,\n SECTIONS,\n kindFromLabels,\n type WorkItemKind,\n} from \"./vocabulary.js\";\n\nexport const BASELINE_SCHEMA_VERSION = 1;\n\nexport interface IssueSnapshotInput {\n repositoryId: number;\n issueNodeId: string;\n number: number;\n title: string;\n body: string | null;\n labels: readonly string[];\n}\n\nexport interface BaselineSnapshot {\n schemaVersion: typeof BASELINE_SCHEMA_VERSION;\n canonicalVersion: typeof CANONICAL_VERSION;\n baselineId: string;\n kind: WorkItemKind;\n source: { repositoryId: number; issueNodeId: string; issueNumber: number };\n requirements: {\n title: string;\n sections: Record<string, string>;\n criteria: Criterion[];\n };\n parent: number | null;\n blockedBy: number[];\n acRefs: string[];\n contentHash: string;\n}\n\nfunction hashedPart(snapshot: Omit<BaselineSnapshot, \"baselineId\" | \"contentHash\">) {\n return {\n schemaVersion: snapshot.schemaVersion,\n canonicalVersion: snapshot.canonicalVersion,\n kind: snapshot.kind,\n source: snapshot.source,\n requirements: snapshot.requirements,\n parent: snapshot.parent,\n blockedBy: snapshot.blockedBy,\n acRefs: snapshot.acRefs,\n };\n}\n\n/** Builds the immutable requirement snapshot from the current Issue content. */\nexport function buildBaseline(issue: IssueSnapshotInput): BaselineSnapshot {\n const kind = kindFromLabels(issue.labels);\n if (!kind) {\n throw new AiDlcError(\n \"E_FORM\",\n \"Issue needs exactly one of the labels type:epic, type:story or type:task.\",\n );\n }\n const parsed = parseIssueForm(issue.body);\n const sections: Record<string, string> = {};\n for (const label of REQUIREMENT_SECTIONS[kind]) sections[label] = parsed.get(label) ?? \"\";\n if (!sections[SECTIONS.goal]) {\n throw new AiDlcError(\"E_FORM\", `Section \\`### ${SECTIONS.goal}\\` is required.`);\n }\n const criteriaSection = CRITERIA_SECTION[kind];\n const criteria = criteriaSection ? parseCriteria(sections[criteriaSection] ?? \"\") : [];\n if (criteriaSection && criteria.length === 0) {\n throw new AiDlcError(\n \"E_FORM\",\n `Section \\`### ${criteriaSection}\\` needs at least one criterion line.`,\n );\n }\n const expectedPrefix = kind === \"epic\" ? \"EC-\" : \"AC-\";\n if (criteria.some((criterion) => !criterion.id.startsWith(expectedPrefix))) {\n throw new AiDlcError(\"E_FORM\", `${kind} criteria must use the ${expectedPrefix} prefix.`);\n }\n const parentRefs = parseIssueRefs(sections[SECTIONS.parent]);\n if (parentRefs.length > 1) throw new AiDlcError(\"E_FORM\", \"Only one parent Issue is allowed.\");\n const acRefs =\n kind === \"task\"\n ? (sections[SECTIONS.acRefs] ?? \"\")\n .split(/[\\s,]+/u)\n .filter((value) => value.length > 0)\n .map((value) => {\n if (!/^AC-\\d{2,3}$/u.test(value))\n throw new AiDlcError(\"E_FORM\", `Invalid AC reference \\`${value}\\`.`);\n return value;\n })\n : [];\n const base = {\n schemaVersion: BASELINE_SCHEMA_VERSION,\n canonicalVersion: CANONICAL_VERSION,\n kind,\n source: {\n repositoryId: issue.repositoryId,\n issueNodeId: issue.issueNodeId,\n issueNumber: issue.number,\n },\n requirements: { title: issue.title, sections, criteria },\n parent: parentRefs[0] ?? null,\n blockedBy: parseIssueRefs(sections[SECTIONS.blockedBy]),\n acRefs,\n } as const;\n const hash = contentHash(hashedPart(base));\n return { ...base, baselineId: `bl-${issue.number}-${shortHash(hash)}`, contentHash: hash };\n}\n\n/** Recomputes the hash of a stored snapshot to detect tampering or corruption. */\nexport function verifySnapshot(snapshot: BaselineSnapshot): boolean {\n return contentHash(hashedPart(snapshot)) === snapshot.contentHash;\n}\n\nexport function baselinePath(\n repositoryId: number,\n issueNumber: number,\n baselineId: string,\n): string {\n return `baselines/${repositoryId}/${issueNumber}/${baselineId}.json`;\n}\n", "import { AiDlcError } from \"./errors.js\";\n\nexport const COMMAND_PREFIX = \"/huddle60\";\nexport const LEGACY_COMMAND_PREFIX = \"/ai-dlc\";\n\ninterface CommandSpec {\n required: readonly string[];\n optional: readonly string[];\n handler: \"deterministic\" | \"planner\";\n}\n\nexport const COMMAND_SPECS = {\n baseline: { required: [], optional: [], handler: \"deterministic\" },\n approve: { required: [\"baseline\", \"hash\"], optional: [], handler: \"deterministic\" },\n ready: { required: [\"baseline\", \"hash\", \"lane\"], optional: [], handler: \"deterministic\" },\n accept: { required: [\"baseline\", \"run\", \"commit\"], optional: [], handler: \"deterministic\" },\n revoke: { required: [\"decision\", \"reason\"], optional: [], handler: \"deterministic\" },\n refine: { required: [\"plan\"], optional: [], handler: \"planner\" },\n \"create-plan\": { required: [\"plan\", \"hash\"], optional: [], handler: \"planner\" },\n \"resume-plan\": { required: [\"plan\"], optional: [], handler: \"planner\" },\n} as const satisfies Record<string, CommandSpec>;\n\nexport type CommandName = keyof typeof COMMAND_SPECS;\n\nexport interface ParsedCommand {\n name: CommandName;\n args: Record<string, string>;\n /** Text after the first line; used as free-form clarification for `refine`. */\n note: string;\n}\n\n/** Quick check used to route events without fully parsing them. */\nexport function looksLikeCommand(body: string | null | undefined): boolean {\n const line = firstLine(body ?? \"\");\n return (\n line.startsWith(`${COMMAND_PREFIX} `) ||\n line === COMMAND_PREFIX ||\n line.startsWith(`${LEGACY_COMMAND_PREFIX} `) ||\n line === LEGACY_COMMAND_PREFIX\n );\n}\n\nexport function commandHandler(name: CommandName): \"deterministic\" | \"planner\" {\n return COMMAND_SPECS[name].handler;\n}\n\nfunction firstLine(body: string): string {\n return (body.replace(/\\r\\n?/gu, \"\\n\").split(\"\\n\")[0] ?? \"\").trim();\n}\n\nfunction tokenize(input: string): string[] {\n const tokens: string[] = [];\n const pattern = /([a-z][a-z-]*)=(?:\"((?:[^\"\\\\]|\\\\.)*)\"|(\\S+))|(\\S+)/gu;\n for (const match of input.matchAll(pattern)) {\n if (match[4] !== undefined) {\n throw new AiDlcError(\"E_SYNTAX\", `Unexpected token \\`${match[4]}\\`. Use key=value.`);\n }\n const value = match[2] !== undefined ? match[2].replace(/\\\\(.)/gu, \"$1\") : (match[3] as string);\n tokens.push(`${match[1]}=${value}`);\n }\n return tokens;\n}\n\n/**\n * Parses a command that must be on the first line of a comment.\n * Commands in quotes or code blocks never reach this function because their\n * first line does not start with the prefix.\n */\nexport function parseCommand(body: string): ParsedCommand {\n const normalized = body.replace(/\\r\\n?/gu, \"\\n\");\n const [head = \"\", ...rest] = normalized.split(\"\\n\");\n const line = head.trim();\n let prefix = \"\";\n if (line.startsWith(COMMAND_PREFIX)) {\n prefix = COMMAND_PREFIX;\n } else if (line.startsWith(LEGACY_COMMAND_PREFIX)) {\n prefix = LEGACY_COMMAND_PREFIX;\n } else {\n throw new AiDlcError(\n \"E_SYNTAX\",\n `Commands must start with \\`${COMMAND_PREFIX}\\` on the first line.`,\n );\n }\n const remainder = line.slice(prefix.length).trim();\n const [rawName = \"\", ...argParts] = remainder.split(/\\s+/u);\n if (!(rawName in COMMAND_SPECS)) {\n throw new AiDlcError(\n \"E_SYNTAX\",\n `Unknown command \\`${rawName || \"(empty)\"}\\`. Known commands: ${Object.keys(COMMAND_SPECS).join(\", \")}.`,\n );\n }\n const name = rawName as CommandName;\n const spec: CommandSpec = COMMAND_SPECS[name];\n const args: Record<string, string> = {};\n for (const token of tokenize(argParts.join(\" \"))) {\n const separator = token.indexOf(\"=\");\n const key = token.slice(0, separator);\n const value = token.slice(separator + 1);\n if (!spec.required.includes(key) && !spec.optional.includes(key)) {\n throw new AiDlcError(\"E_SYNTAX\", `Unknown argument \\`${key}\\` for \\`${name}\\`.`);\n }\n if (key in args) throw new AiDlcError(\"E_SYNTAX\", `Duplicate argument \\`${key}\\`.`);\n if (value.length === 0) throw new AiDlcError(\"E_SYNTAX\", `Argument \\`${key}\\` is empty.`);\n args[key] = value;\n }\n const missing = spec.required.filter((key) => !(key in args));\n if (missing.length > 0) {\n throw new AiDlcError(\"E_SYNTAX\", `Missing argument(s) for \\`${name}\\`: ${missing.join(\", \")}.`);\n }\n return { name, args, note: rest.join(\"\\n\").trim() };\n}\n", "import { sha256, shortHash } from \"./canonical.js\";\nimport { hasRole, type LaneName, type Policy, type Role } from \"./policy.js\";\n\nexport const DECISION_SCHEMA_VERSION = 1;\n\nexport type DecisionKind = \"approve\" | \"ready\" | \"accept\";\n\nexport const REQUIRED_ROLE: Record<DecisionKind, Role> = {\n approve: \"po\",\n ready: \"dev\",\n accept: \"po\",\n};\n\nexport interface BuildReference {\n runId: number;\n runAttempt: number;\n workflowPath: string;\n headSha: string;\n}\n\nexport interface DecisionReceipt {\n schemaVersion: typeof DECISION_SCHEMA_VERSION;\n decisionId: string;\n kind: DecisionKind;\n issueNumber: number;\n baselineId: string;\n baselineHash: string;\n actor: { id: number; login: string };\n source: { commentId: number; commentBodyDigest: string };\n lane: LaneName | null;\n build: BuildReference | null;\n policyVersion: number;\n recordedAt: string;\n}\n\nexport interface Revocation {\n schemaVersion: 1;\n decisionId: string;\n actor: { id: number; login: string };\n reason: string;\n source: { commentId: number };\n recordedAt: string;\n}\n\nexport function decisionId(kind: DecisionKind, commentId: number): string {\n return `dec-${shortHash(sha256(`${kind}:${commentId}`), 16)}`;\n}\n\nexport function commentDigest(body: string): string {\n return sha256(body.replace(/\\r\\n?/gu, \"\\n\"));\n}\n\nexport function decisionPath(repositoryId: number, issueNumber: number, id: string): string {\n return `decisions/${repositoryId}/${issueNumber}/${id}.json`;\n}\n\nexport function revocationPath(repositoryId: number, issueNumber: number, id: string): string {\n return `revocations/${repositoryId}/${issueNumber}/${id}.json`;\n}\n\n/** Facts gathered at check time. Validity is never stored; it is recomputed on every use. */\nexport interface ValidityFacts {\n policy: Policy;\n revoked: boolean;\n /** Current body of the source comment, or null when it was deleted. */\n currentCommentBody: string | null;\n /** Hash of the snapshot recomputed from storage, or null when missing/corrupt. */\n snapshotHash: string | null;\n /** Only for `accept`: whether the referenced build still satisfies acceptance rules. */\n buildValid?: boolean;\n}\n\nexport interface Validity {\n valid: boolean;\n reasons: string[];\n}\n\nexport function evaluateReceipt(receipt: DecisionReceipt, facts: ValidityFacts): Validity {\n const reasons: string[] = [];\n if (facts.revoked) reasons.push(\"decision was revoked\");\n if (facts.currentCommentBody === null) reasons.push(\"source comment was deleted\");\n else if (commentDigest(facts.currentCommentBody) !== receipt.source.commentBodyDigest) {\n reasons.push(\"source comment was edited\");\n }\n if (!hasRole(facts.policy, receipt.actor.id, REQUIRED_ROLE[receipt.kind])) {\n reasons.push(`actor no longer holds the ${REQUIRED_ROLE[receipt.kind]} role`);\n }\n if (facts.snapshotHash === null) reasons.push(\"baseline snapshot is missing or corrupt\");\n else if (facts.snapshotHash !== receipt.baselineHash) reasons.push(\"baseline hash mismatch\");\n if (receipt.kind === \"accept\" && facts.buildValid !== true)\n reasons.push(\"accepted build is no longer valid\");\n return { valid: reasons.length === 0, reasons };\n}\n", "import { AiDlcError } from \"./errors.js\";\n\nexport const PR_BLOCK_BEGIN = \"<!-- huddle60:begin -->\";\nexport const PR_BLOCK_END = \"<!-- huddle60:end -->\";\nexport const LEGACY_PR_BLOCK_BEGIN = \"<!-- ai-dlc:begin -->\";\nexport const LEGACY_PR_BLOCK_END = \"<!-- ai-dlc:end -->\";\n\nexport interface PrBlock {\n issueNumber: number;\n baselineId: string;\n hash: string;\n acceptanceCriteria: string[];\n}\n\n/** Returns null when the PR has no block; throws when a block exists but is malformed. */\nexport function parsePrBlock(body: string | null | undefined): PrBlock | null {\n const text = (body ?? \"\").replace(/\\r\\n?/gu, \"\\n\");\n let begin = text.indexOf(PR_BLOCK_BEGIN);\n let beginMarker = PR_BLOCK_BEGIN;\n let endMarker = PR_BLOCK_END;\n\n if (begin === -1) {\n begin = text.indexOf(LEGACY_PR_BLOCK_BEGIN);\n if (begin !== -1) {\n beginMarker = LEGACY_PR_BLOCK_BEGIN;\n endMarker = LEGACY_PR_BLOCK_END;\n }\n }\n if (begin === -1) return null;\n\n if (text.indexOf(beginMarker, begin + 1) !== -1) {\n throw new AiDlcError(\"E_PR_BLOCK\", \"PR body contains more than one huddle60 block.\");\n }\n const end = text.indexOf(endMarker, begin);\n if (end === -1) throw new AiDlcError(\"E_PR_BLOCK\", \"huddle60 block is not closed.\");\n const fields = new Map<string, string>();\n for (const line of text.slice(begin + beginMarker.length, end).split(\"\\n\")) {\n const match = /^(?:HUDDLE60|AI-DLC)-([A-Za-z]+):\\s*(.*)$/iu.exec(line.trim());\n if (match) fields.set((match[1] as string).toLowerCase(), (match[2] as string).trim());\n }\n const issue = /^#(\\d+)$/u.exec(fields.get(\"issue\") ?? \"\");\n const baselineId = fields.get(\"baseline\") ?? \"\";\n const hash = fields.get(\"hash\") ?? \"\";\n if (!issue)\n throw new AiDlcError(\n \"E_PR_BLOCK\",\n \"HUDDLE60-Issue must be `#<number>` in the same repository.\",\n );\n if (!/^bl-\\d+-[0-9a-f]{12}$/u.test(baselineId))\n throw new AiDlcError(\"E_PR_BLOCK\", \"HUDDLE60-Baseline is missing or invalid.\");\n if (!/^sha256:[0-9a-f]{64}$/u.test(hash))\n throw new AiDlcError(\"E_PR_BLOCK\", \"HUDDLE60-Hash is missing or invalid.\");\n const acceptanceCriteria = (fields.get(\"ac\") ?? \"\")\n .split(/[\\s,]+/u)\n .filter((value) => value.length > 0);\n for (const id of acceptanceCriteria) {\n if (!/^AC-\\d{2,3}$/u.test(id))\n throw new AiDlcError(\"E_PR_BLOCK\", `Invalid AC id \\`${id}\\` in HUDDLE60-AC.`);\n }\n return { issueNumber: Number(issue[1]), baselineId, hash, acceptanceCriteria };\n}\n\nexport function renderPrBlock(block: PrBlock): string {\n return [\n PR_BLOCK_BEGIN,\n `HUDDLE60-Issue: #${block.issueNumber}`,\n `HUDDLE60-Baseline: ${block.baselineId}`,\n `HUDDLE60-Hash: ${block.hash}`,\n `HUDDLE60-AC: ${block.acceptanceCriteria.join(\", \")}`,\n PR_BLOCK_END,\n ].join(\"\\n\");\n}\n\n/** Issue numbers referenced with GitHub closing keywords, which would auto-close Issues on merge. */\nexport function closingReferences(body: string | null | undefined): number[] {\n const pattern = /\\b(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\\s*:?\\s+#(\\d+)\\b/giu;\n return [...new Set([...(body ?? \"\").matchAll(pattern)].map((match) => Number(match[1])))];\n}\n", "import { z } from \"zod\";\nimport { canonicalJson, sha256, shortHash } from \"./canonical.js\";\nimport { AiDlcError } from \"./errors.js\";\nimport type { WorkItemKind } from \"./vocabulary.js\";\n\nconst LOCAL_ID = /^[a-z0-9][a-z0-9-]{0,47}$/u;\nconst Text = (max: number) => z.string().trim().min(1).max(max);\n\nconst CriterionSchema = z.object({\n id: z.string().regex(/^(AC|EC)-\\d{2,3}$/u),\n text: Text(500),\n});\n\nconst NodeSchema = z.object({\n localId: z.string().regex(LOCAL_ID),\n kind: z.enum([\"epic\", \"story\", \"task\"]),\n parentLocalId: z.string().regex(LOCAL_ID).nullable(),\n title: Text(120),\n goal: Text(1000),\n scope: z.array(Text(300)).max(15),\n outOfScope: z.array(Text(300)).max(10),\n criteria: z.array(CriterionSchema).max(20),\n acRefs: z.array(z.string().regex(/^AC-\\d{2,3}$/u)).max(20),\n blockedBy: z.array(z.string().regex(LOCAL_ID)).max(10),\n riskNotes: z.array(Text(300)).max(10),\n});\n\n/** Shape the model must return. Server-owned fields (ids, hashes, source) are added later. */\nexport const ModelPlanSchema = z.object({\n rootKind: z.enum([\"epic\", \"story\"]),\n summary: Text(1000),\n assumptions: z.array(Text(300)).max(15),\n openQuestions: z.array(z.object({ text: Text(300), blocking: z.boolean() })).max(15),\n nodes: z.array(NodeSchema).min(1).max(200),\n});\n\nexport type ModelPlan = z.infer<typeof ModelPlanSchema>;\nexport type PlanNode = z.infer<typeof NodeSchema>;\n\nexport const PLAN_SCHEMA_VERSION = 1;\n\n/** JSON Schema handed to Gemini as `responseJsonSchema`. */\nexport function modelPlanJsonSchema(): Record<string, unknown> {\n return z.toJSONSchema(ModelPlanSchema, { target: \"draft-7\" }) as Record<string, unknown>;\n}\n\nexport interface PlanLimits {\n maxNodes: number;\n}\n\n/** Parses model output text and enforces structural and semantic rules. */\nexport function parseModelPlan(text: string, limits: PlanLimits): ModelPlan {\n let raw: unknown;\n try {\n raw = JSON.parse(text);\n } catch (error) {\n throw new AiDlcError(\"E_PLAN_SCHEMA\", \"Model output is not valid JSON.\", { cause: error });\n }\n const parsed = ModelPlanSchema.safeParse(raw);\n if (!parsed.success) {\n throw new AiDlcError(\n \"E_PLAN_SCHEMA\",\n `Model output does not match the plan schema:\\n${z.prettifyError(parsed.error)}`,\n );\n }\n validatePlanSemantics(parsed.data, limits);\n return parsed.data;\n}\n\nexport function validatePlanSemantics(plan: ModelPlan, limits: PlanLimits): void {\n if (plan.nodes.length > limits.maxNodes) {\n throw new AiDlcError(\n \"E_PLAN_LIMIT\",\n `Plan has ${plan.nodes.length} items; the limit is ${limits.maxNodes}. Split the request into smaller requests.`,\n );\n }\n const problems: string[] = [];\n const byId = new Map<string, PlanNode>();\n for (const node of plan.nodes) {\n if (byId.has(node.localId)) problems.push(`Duplicate localId \\`${node.localId}\\`.`);\n byId.set(node.localId, node);\n }\n const roots = plan.nodes.filter((node) => node.parentLocalId === null);\n if (roots.length !== 1) problems.push(`Plan must have exactly one root; found ${roots.length}.`);\n else if (roots[0]?.kind !== plan.rootKind) {\n problems.push(`Root kind \\`${roots[0]?.kind}\\` does not match rootKind \\`${plan.rootKind}\\`.`);\n }\n const expectedParent: Record<WorkItemKind, WorkItemKind | null> = {\n epic: null,\n story: \"epic\",\n task: \"story\",\n };\n for (const node of plan.nodes) {\n const label = `\\`${node.localId}\\``;\n if (node.parentLocalId !== null) {\n const parent = byId.get(node.parentLocalId);\n if (!parent) problems.push(`${label} references missing parent \\`${node.parentLocalId}\\`.`);\n else if (parent.kind !== expectedParent[node.kind]) {\n problems.push(\n `${label} (${node.kind}) cannot be a child of ${parent.kind} \\`${parent.localId}\\`.`,\n );\n }\n } else if (node.kind === \"task\") {\n problems.push(`${label}: a task cannot be the root.`);\n }\n if (node.kind === \"epic\" && plan.rootKind === \"story\")\n problems.push(`${label}: no epic allowed when rootKind is story.`);\n const prefix = node.kind === \"epic\" ? \"EC-\" : \"AC-\";\n if (node.kind !== \"task\") {\n if (node.criteria.length === 0) problems.push(`${label} must have at least one criterion.`);\n if (node.criteria.some((criterion) => !criterion.id.startsWith(prefix))) {\n problems.push(`${label} criteria must use the \\`${prefix}\\` prefix.`);\n }\n if (node.acRefs.length > 0) problems.push(`${label}: only tasks may use acRefs.`);\n } else {\n if (node.criteria.length > 0)\n problems.push(`${label}: tasks use acRefs instead of criteria.`);\n const parent = node.parentLocalId ? byId.get(node.parentLocalId) : undefined;\n const parentAc = new Set(parent?.criteria.map((criterion) => criterion.id));\n for (const ref of node.acRefs) {\n if (!parentAc.has(ref))\n problems.push(`${label} references \\`${ref}\\` that its story does not define.`);\n }\n }\n const ids = node.criteria.map((criterion) => criterion.id);\n if (new Set(ids).size !== ids.length) problems.push(`${label} has duplicate criterion ids.`);\n for (const dependency of node.blockedBy) {\n if (dependency === node.localId) problems.push(`${label} cannot block itself.`);\n else if (!byId.has(dependency))\n problems.push(`${label} is blocked by missing \\`${dependency}\\`.`);\n }\n }\n if (problems.length === 0) {\n try {\n creationOrder(plan.nodes);\n } catch (error) {\n problems.push((error as Error).message);\n }\n }\n if (problems.length > 0) {\n throw new AiDlcError(\"E_PLAN_SCHEMA\", `Plan failed validation:\\n- ${problems.join(\"\\n- \")}`);\n }\n}\n\n/**\n * Orders nodes so that every parent and every blocking item is created first,\n * which lets bodies reference real Issue numbers. Input order breaks ties.\n */\nexport function creationOrder(nodes: readonly PlanNode[]): PlanNode[] {\n const byId = new Map(nodes.map((node) => [node.localId, node]));\n const state = new Map<string, \"visiting\" | \"done\">();\n const ordered: PlanNode[] = [];\n const visit = (node: PlanNode, trail: string[]) => {\n const current = state.get(node.localId);\n if (current === \"done\") return;\n if (current === \"visiting\") {\n throw new Error(`Dependency cycle: ${[...trail, node.localId].join(\" -> \")}.`);\n }\n state.set(node.localId, \"visiting\");\n const prerequisites = [node.parentLocalId, ...node.blockedBy].filter(\n (id): id is string => id !== null,\n );\n for (const id of prerequisites) {\n const prerequisite = byId.get(id);\n if (prerequisite) visit(prerequisite, [...trail, node.localId]);\n }\n state.set(node.localId, \"done\");\n ordered.push(node);\n };\n for (const node of nodes) visit(node, []);\n return ordered;\n}\n\nexport type PlanStatus = \"draft\" | \"superseded\" | \"stale\" | \"creating\" | \"partial\" | \"created\";\n\nexport interface PlanSource {\n repositoryId: number;\n owner: string;\n repo: string;\n issueNumber: number;\n issueNodeId: string;\n requestDigest: string;\n}\n\nexport interface PlanRecord {\n schemaVersion: typeof PLAN_SCHEMA_VERSION;\n planId: string;\n revision: number;\n status: PlanStatus;\n source: PlanSource;\n model: string;\n plan: ModelPlan;\n planHash: string;\n clarifications: string[];\n requestedBy: number;\n createdAt: string;\n expiresAt: string;\n}\n\nexport function computePlanHash(requestDigest: string, plan: ModelPlan): string {\n return sha256(canonicalJson({ schemaVersion: PLAN_SCHEMA_VERSION, requestDigest, plan }));\n}\n\nexport function computeRequestDigest(title: string, body: string): string {\n return sha256(canonicalJson({ title, body }));\n}\n\nexport function buildPlanId(issueNumber: number, revision: number, planHash: string): string {\n return `plan-${issueNumber}-r${revision}-${shortHash(planHash, 8)}`;\n}\n\nexport function blockingQuestions(plan: ModelPlan): string[] {\n return plan.openQuestions\n .filter((question) => question.blocking)\n .map((question) => question.text);\n}\n", "import type { ModelPlan, PlanNode, PlanRecord } from \"./plan.js\";\nimport { blockingQuestions, creationOrder } from \"./plan.js\";\nimport { SECTIONS } from \"./vocabulary.js\";\n\n/**\n * Model and user text is untrusted. Neutralize mentions, hidden HTML comments\n * (which could forge automation markers) and raw HTML before posting it.\n */\nexport function sanitize(text: string): string {\n return text\n .replace(/<!--/gu, \"&lt;!--\")\n .replace(/</gu, \"&lt;\")\n .replace(/(^|[^\\w`])@(?=[\\w-])/gu, \"$1@\\u200b\")\n .replace(/^\\/(?:huddle60|ai-dlc)/gmu, \"\\\\/huddle60\");\n}\n\nexport function marker(name: string, value: string): string {\n return `<!-- huddle60:${name}:${value} -->`;\n}\n\nexport function findMarker(body: string | null | undefined, name: string): string | null {\n const match = new RegExp(`<!-- (?:huddle60|ai-dlc):${name}:([^\\\\s>]+) -->`, \"u\").exec(body ?? \"\");\n return match ? (match[1] as string) : null;\n}\n\nexport function planNodeMarker(planId: string, localId: string): string {\n return marker(\"plan-node\", `${planId}/${localId}`);\n}\n\nconst KIND_TITLE = { epic: \"Epic\", story: \"Story\", task: \"Task\" } as const;\n\nexport function bulletList(items: readonly string[], empty = \"_(kh\u00F4ng c\u00F3)_\"): string {\n return items.length === 0 ? empty : items.map((item) => `- ${sanitize(item)}`).join(\"\\n\");\n}\n\nexport function issueTitle(node: PlanNode): string {\n return `[${KIND_TITLE[node.kind]}] ${sanitize(node.title).replace(/\\s+/gu, \" \")}`;\n}\n\n/** Body of an Issue created from a plan. Headings match the Issue forms so the same parser applies. */\nexport function renderNodeBody(\n record: PlanRecord,\n node: PlanNode,\n numbers: ReadonlyMap<string, number>,\n): string {\n const ref = (localId: string) => {\n const number = numbers.get(localId);\n if (number === undefined) throw new Error(`Issue number for ${localId} is not known yet`);\n return `#${number}`;\n };\n const scope = [\n ...node.scope.map((item) => `- Trong ph\u1EA1m vi: ${sanitize(item)}`),\n ...node.outOfScope.map((item) => `- Ngo\u00E0i ph\u1EA1m vi: ${sanitize(item)}`),\n ];\n const sections: [string, string][] = [\n [SECTIONS.goal, sanitize(node.goal)],\n [SECTIONS.scope, scope.join(\"\\n\") || \"_(ch\u01B0a x\u00E1c \u0111\u1ECBnh)_\"],\n ];\n if (node.kind !== \"epic\") {\n sections.push([SECTIONS.parent, node.parentLocalId ? ref(node.parentLocalId) : \"\"]);\n sections.push([SECTIONS.blockedBy, node.blockedBy.map(ref).join(\", \")]);\n }\n if (node.kind === \"epic\") {\n sections.push([\n SECTIONS.epicCriteria,\n node.criteria.map((c) => `- ${c.id}: ${sanitize(c.text)}`).join(\"\\n\"),\n ]);\n } else if (node.kind === \"story\") {\n sections.push([\n SECTIONS.storyCriteria,\n node.criteria.map((c) => `- ${c.id}: ${sanitize(c.text)}`).join(\"\\n\"),\n ]);\n } else {\n sections.push([SECTIONS.acRefs, node.acRefs.join(\", \")]);\n }\n sections.push([SECTIONS.technicalRefs, \"\"]);\n sections.push([SECTIONS.risks, bulletList(node.riskNotes, \"\")]);\n\n const rendered = sections\n .map(([heading, value]) => `### ${heading}\\n\\n${value || \"_No response_\"}`)\n .join(\"\\n\\n\");\n return [\n rendered,\n \"\",\n \"---\",\n `_T\u1EA1o t\u1EEB k\u1EBF ho\u1EA1ch \\`${record.planId}\\` cho request #${record.source.issueNumber} sau khi PO x\u00E1c nh\u1EADn. N\u1ED9i dung do AI \u0111\u1EC1 xu\u1EA5t; PO/DEV c\u00F3 th\u1EC3 ch\u1EC9nh s\u1EEDa tr\u01B0\u1EDBc khi ch\u1ED1t baseline._`,\n planNodeMarker(record.planId, node.localId),\n ].join(\"\\n\");\n}\n\nexport function renderTree(plan: ModelPlan): string {\n const children = new Map<string | null, PlanNode[]>();\n for (const node of plan.nodes) {\n const list = children.get(node.parentLocalId) ?? [];\n list.push(node);\n children.set(node.parentLocalId, list);\n }\n const lines: string[] = [];\n const walk = (parent: string | null, depth: number) => {\n for (const node of children.get(parent) ?? []) {\n const blocked =\n node.blockedBy.length > 0 ? ` _(blocked by ${node.blockedBy.join(\", \")})_` : \"\";\n lines.push(\n `${\" \".repeat(depth)}- **${KIND_TITLE[node.kind]}** \\`${node.localId}\\`: ${sanitize(node.title)}${blocked}`,\n );\n const criteria =\n node.kind === \"task\"\n ? node.acRefs.map((id) => `${id}`)\n : node.criteria.map((c) => `${c.id}: ${sanitize(c.text)}`);\n for (const criterion of criteria) lines.push(`${\" \".repeat(depth + 1)}- ${criterion}`);\n walk(node.localId, depth + 1);\n }\n };\n walk(null, 0);\n return lines.join(\"\\n\");\n}\n\nexport function renderPlanComment(record: PlanRecord): string {\n const { plan } = record;\n const blocking = blockingQuestions(plan);\n const nonBlocking = plan.openQuestions\n .filter((question) => !question.blocking)\n .map((question) => question.text);\n const counts = ([\"epic\", \"story\", \"task\"] as const)\n .map((kind) => [kind, plan.nodes.filter((node) => node.kind === kind).length] as const)\n .filter(([, count]) => count > 0)\n .map(([kind, count]) => `${count} ${KIND_TITLE[kind]}`)\n .join(\", \");\n const next =\n blocking.length > 0\n ? [\n \"**C\u1EA7n PO tr\u1EA3 l\u1EDDi c\u00E1c c\u00E2u h\u1ECFi ch\u1EB7n tr\u01B0\u1EDBc khi t\u1EA1o Issues.** Tr\u1EA3 l\u1EDDi b\u1EB1ng m\u1ED9t comment m\u1EDBi:\",\n \"\",\n \"```text\",\n `/huddle60 refine plan=${record.planId}`,\n \"<c\u00E2u tr\u1EA3 l\u1EDDi c\u1EE7a b\u1EA1n, m\u1ED7i \u00FD m\u1ED9t d\u00F2ng>\",\n \"```\",\n ]\n : [\n \"**N\u1EBFu \u0111\u1ED3ng \u00FD, PO x\u00E1c nh\u1EADn \u0111\u1EC3 App t\u1EA1o c\u00E1c Issues:**\",\n \"\",\n \"```text\",\n `/huddle60 create-plan plan=${record.planId} hash=${record.planHash}`,\n \"```\",\n \"\",\n `Mu\u1ED1n ch\u1EC9nh s\u1EEDa: \\`/huddle60 refine plan=${record.planId}\\` k\u00E8m y\u00EAu c\u1EA7u \u1EDF c\u00E1c d\u00F2ng ti\u1EBFp theo.`,\n ];\n return [\n `## K\u1EBF ho\u1EA1ch \u0111\u1EC1 xu\u1EA5t (revision ${record.revision})`,\n \"\",\n sanitize(plan.summary),\n \"\",\n `**Ph\u1EA1m vi:** ${counts}. Model: \\`${record.model}\\`.`,\n \"\",\n \"### C\u00E2y c\u00F4ng vi\u1EC7c\",\n \"\",\n renderTree(plan),\n \"\",\n \"### C\u00E2u h\u1ECFi ch\u1EB7n\",\n \"\",\n bulletList(blocking),\n \"\",\n \"### C\u00E2u h\u1ECFi kh\u00E1c\",\n \"\",\n bulletList(nonBlocking),\n \"\",\n \"### Gi\u1EA3 \u0111\u1ECBnh c\u1EA7n x\u00E1c nh\u1EADn\",\n \"\",\n bulletList(plan.assumptions),\n \"\",\n ...next,\n \"\",\n `<sub>Plan \\`${record.planId}\\` \u00B7 hash \\`${record.planHash}\\` \u00B7 h\u1EBFt h\u1EA1n ${record.expiresAt.slice(0, 10)}. \u0110\u00E2y l\u00E0 \u0111\u1EC1 xu\u1EA5t c\u1EE7a AI, ch\u01B0a ph\u1EA3i quy\u1EBFt \u0111\u1ECBnh; ch\u01B0a c\u00F3 Issue n\u00E0o \u0111\u01B0\u1EE3c t\u1EA1o.</sub>`,\n marker(\"plan\", record.planId),\n ].join(\"\\n\");\n}\n\nexport function renderCreationSummary(\n record: PlanRecord,\n numbers: ReadonlyMap<string, number>,\n complete: boolean,\n failures: readonly string[],\n): string {\n const lines = creationOrder(record.plan.nodes).map((node) => {\n const number = numbers.get(node.localId);\n return `- ${KIND_TITLE[node.kind]} \\`${node.localId}\\`: ${number ? `#${number}` : \"_ch\u01B0a t\u1EA1o_\"}`;\n });\n return [\n complete\n ? `## \u0110\u00E3 t\u1EA1o Issues t\u1EEB \\`${record.planId}\\``\n : `## T\u1EA1o Issues ch\u01B0a ho\u00E0n t\u1EA5t cho \\`${record.planId}\\``,\n \"\",\n ...lines,\n \"\",\n ...(failures.length > 0 ? [\"**L\u1ED7i:**\", \"\", bulletList(failures), \"\"] : []),\n complete\n ? \"B\u01B0\u1EDBc ti\u1EBFp theo: PO \u01B0u ti\u00EAn trong Project; DEV review kh\u1EA3 thi v\u00E0 chia vi\u1EC7c; ch\u1ED1t baseline khi Story s\u1EB5n s\u00E0ng (`/huddle60 baseline`).\"\n : `Kh\u00F4ng x\u00F3a c\u00E1c Issue \u0111\u00E3 t\u1EA1o. Th\u1EED l\u1EA1i an to\u00E0n b\u1EB1ng \\`/huddle60 resume-plan plan=${record.planId}\\`.`,\n marker(\"plan-result\", record.planId),\n ].join(\"\\n\");\n}\n", "import {\n buildBaseline,\n baselinePath,\n verifySnapshot,\n type BaselineSnapshot,\n} from \"../core/baseline.js\";\nimport { commandHandler, parseCommand, type ParsedCommand } from \"../core/command.js\";\nimport {\n DECISION_SCHEMA_VERSION,\n REQUIRED_ROLE,\n commentDigest,\n decisionId,\n decisionPath,\n evaluateReceipt,\n revocationPath,\n type DecisionKind,\n type DecisionReceipt,\n type Revocation,\n} from \"../core/decision.js\";\nimport { AiDlcError, isAiDlcError } from \"../core/errors.js\";\nimport {\n POLICY_PATH,\n LEGACY_POLICY_PATH,\n hasRole,\n isSensitive,\n parsePolicy,\n type LaneName,\n type Policy,\n} from \"../core/policy.js\";\nimport { closingReferences, parsePrBlock, renderPrBlock } from \"../core/pr-block.js\";\nimport { marker, sanitize } from \"../core/render.js\";\nimport { LABELS, kindFromLabels } from \"../core/vocabulary.js\";\nimport type { Clock, CommentData, EvidenceStore, GitHubPort, IssueData, Logger } from \"../ports.js\";\n\nexport const STATUS_CONTEXT = \"huddle60/baseline\";\n\nexport interface WorkflowDeps {\n github: GitHubPort;\n evidence: EvidenceStore;\n clock: Clock;\n logger: Logger;\n enabled: boolean;\n}\n\nexport interface PrCheckResult {\n state: \"success\" | \"failure\" | \"pending\";\n description: string;\n details: string[];\n}\n\nconst LANES: readonly LaneName[] = [\"fast\", \"standard\", \"strict\"];\n\nexport class WorkflowService {\n private policyCache: Policy | null = null;\n\n constructor(private readonly deps: WorkflowDeps) {}\n\n private get repositoryId(): number {\n return this.deps.github.repo.repositoryId;\n }\n\n async policy(): Promise<Policy> {\n if (this.policyCache) return this.policyCache;\n const branch = await this.deps.github.getDefaultBranch();\n let source = await this.deps.github.readFile(POLICY_PATH, branch);\n if (source === null) {\n source = await this.deps.github.readFile(LEGACY_POLICY_PATH, branch);\n }\n if (source === null)\n throw new AiDlcError(\"E_POLICY_INVALID\", `Missing ${POLICY_PATH} on ${branch}.`);\n this.policyCache = parsePolicy(source);\n return this.policyCache;\n }\n\n /** Entry point for `issue_comment` events on Issues. */\n async handleComment(\n issueNumber: number,\n commentId: number,\n action: \"created\" | \"edited\" | \"deleted\",\n ): Promise<void> {\n if (!this.deps.enabled) return;\n if (action !== \"created\") {\n await this.reportInvalidatedDecisions(issueNumber, commentId, action);\n return;\n }\n const comment = await this.deps.github.getComment(commentId);\n if (!comment || comment.author.type !== \"User\") return;\n let command: ParsedCommand;\n try {\n command = parseCommand(comment.body);\n } catch (error) {\n if (isAiDlcError(error)) await this.reply(issueNumber, commentId, errorReply(error));\n return;\n }\n if (commandHandler(command.name) !== \"deterministic\") return;\n try {\n const policy = await this.policy();\n const issue = await this.deps.github.getIssue(issueNumber);\n if (issue.isPullRequest)\n throw new AiDlcError(\"E_SYNTAX\", \"AI-DLC commands are only accepted on Issues.\");\n const message = await this.runCommand(command, issue, comment, policy);\n await this.reply(issueNumber, commentId, message);\n } catch (error) {\n if (!isAiDlcError(error)) throw error;\n await this.reply(issueNumber, commentId, errorReply(error));\n }\n }\n\n private async reply(issueNumber: number, commentId: number, body: string): Promise<void> {\n await this.deps.github.upsertComment(issueNumber, marker(\"reply\", String(commentId)), body);\n }\n\n private async runCommand(\n command: ParsedCommand,\n issue: IssueData,\n comment: CommentData,\n policy: Policy,\n ): Promise<string> {\n const actor = comment.author;\n switch (command.name) {\n case \"baseline\":\n this.requireRole(policy, actor.id, [\"po\", \"dev\"], \"baseline\");\n return this.createBaseline(issue);\n case \"approve\":\n case \"ready\":\n case \"accept\":\n this.requireRole(policy, actor.id, [REQUIRED_ROLE[command.name]], command.name);\n return this.recordDecision(command.name, command.args, issue, comment, policy);\n case \"revoke\":\n return this.revoke(command.args, issue, comment, policy);\n default:\n throw new AiDlcError(\n \"E_SYNTAX\",\n `\\`${command.name}\\` is handled by the planner, not this workflow.`,\n );\n }\n }\n\n private requireRole(\n policy: Policy,\n userId: number,\n roles: Array<\"po\" | \"dev\" | \"maintainer\">,\n action: string,\n ): void {\n if (!roles.some((role) => hasRole(policy, userId, role))) {\n throw new AiDlcError(\"E_ROLE\", `\\`${action}\\` requires the ${roles.join(\" or \")} role.`);\n }\n }\n\n snapshotOf(issue: IssueData): BaselineSnapshot {\n return buildBaseline({\n repositoryId: this.repositoryId,\n issueNodeId: issue.nodeId,\n number: issue.number,\n title: issue.title,\n body: issue.body,\n labels: issue.labels,\n });\n }\n\n private async createBaseline(issue: IssueData): Promise<string> {\n const snapshot = this.snapshotOf(issue);\n const result = await this.deps.evidence.write(\n baselinePath(this.repositoryId, issue.number, snapshot.baselineId),\n snapshot,\n );\n const criteria = snapshot.requirements.criteria.map(\n (criterion) => `- ${criterion.id}: ${sanitize(criterion.text)}`,\n );\n return [\n `**Baseline \\`${snapshot.baselineId}\\`** ${result === \"created\" ? \"\u0111\u00E3 \u0111\u01B0\u1EE3c t\u1EA1o\" : \"\u0111\u00E3 t\u1ED3n t\u1EA1i v\u1EDBi c\u00F9ng n\u1ED9i dung\"}.`,\n \"\",\n `Hash: \\`${snapshot.contentHash}\\``,\n ...(criteria.length > 0 ? [\"\", \"Ti\u00EAu ch\u00ED:\", ...criteria] : []),\n \"\",\n \"PO duy\u1EC7t nghi\u1EC7p v\u1EE5:\",\n \"```text\",\n `/huddle60 approve baseline=${snapshot.baselineId} hash=${snapshot.contentHash}`,\n \"```\",\n \"DEV x\u00E1c nh\u1EADn s\u1EB5n s\u00E0ng (lane: fast | standard | strict):\",\n \"```text\",\n `/huddle60 ready baseline=${snapshot.baselineId} hash=${snapshot.contentHash} lane=standard`,\n \"```\",\n ].join(\"\\n\");\n }\n\n private async loadSnapshot(issueNumber: number, baselineId: string): Promise<BaselineSnapshot> {\n if (!baselineId.startsWith(`bl-${issueNumber}-`)) {\n throw new AiDlcError(\n \"E_BASELINE_NOT_FOUND\",\n `Baseline \\`${baselineId}\\` does not belong to #${issueNumber}.`,\n );\n }\n const snapshot = await this.deps.evidence.read<BaselineSnapshot>(\n baselinePath(this.repositoryId, issueNumber, baselineId),\n );\n if (!snapshot || !verifySnapshot(snapshot)) {\n throw new AiDlcError(\n \"E_BASELINE_NOT_FOUND\",\n `Baseline \\`${baselineId}\\` is missing or corrupt.`,\n );\n }\n return snapshot;\n }\n\n /**\n * Loads the snapshot for a decision. When it was never stored but the id and hash\n * match the Issue's current content, it is stored now, so one command suffices.\n */\n private async snapshotForDecision(\n issue: IssueData,\n baselineId: string,\n hash: string | undefined,\n ): Promise<BaselineSnapshot> {\n const stored = await this.deps.evidence.read<BaselineSnapshot>(\n baselinePath(this.repositoryId, issue.number, baselineId),\n );\n if (stored || hash === undefined) return this.loadSnapshot(issue.number, baselineId);\n const current = this.snapshotOf(issue);\n if (current.baselineId !== baselineId || current.contentHash !== hash) {\n return this.loadSnapshot(issue.number, baselineId);\n }\n await this.deps.evidence.write(\n baselinePath(this.repositoryId, issue.number, current.baselineId),\n current,\n );\n return current;\n }\n\n /** Throws when the Issue no longer matches the baseline it is being decided on. */\n private assertCurrent(issue: IssueData, snapshot: BaselineSnapshot): void {\n if (this.snapshotOf(issue).contentHash !== snapshot.contentHash) {\n throw new AiDlcError(\n \"E_STALE\",\n \"The Issue changed after this baseline was created. Run `/huddle60 baseline` again and decide on the new baseline.\",\n );\n }\n }\n\n private async recordDecision(\n kind: DecisionKind,\n args: Record<string, string>,\n issue: IssueData,\n comment: CommentData,\n policy: Policy,\n ): Promise<string> {\n const { github, evidence, clock } = this.deps;\n const snapshot =\n kind === \"accept\"\n ? await this.loadSnapshot(issue.number, args.baseline as string)\n : await this.snapshotForDecision(issue, args.baseline as string, args.hash);\n let lane: LaneName | null = null;\n let build: DecisionReceipt[\"build\"] = null;\n if (kind === \"approve\" || kind === \"ready\") {\n if (args.hash !== snapshot.contentHash) {\n throw new AiDlcError(\n \"E_HASH_MISMATCH\",\n \"The hash does not match the baseline. Copy it from the baseline reply.\",\n );\n }\n this.assertCurrent(issue, snapshot);\n }\n if (kind === \"ready\") {\n if (!LANES.includes(args.lane as LaneName)) {\n throw new AiDlcError(\"E_SYNTAX\", `Lane must be one of ${LANES.join(\", \")}.`);\n }\n lane = args.lane as LaneName;\n await this.assertApproved(snapshot, lane, policy);\n const open: number[] = [];\n for (const dependency of snapshot.blockedBy) {\n const blocker = await github.getIssue(dependency);\n if (blocker.state !== \"closed\" || blocker.stateReason !== \"completed\")\n open.push(dependency);\n }\n if (open.length > 0) {\n throw new AiDlcError(\n \"E_DEPENDENCY_OPEN\",\n `Blocked by unfinished Issue(s): ${open.map((n) => `#${n}`).join(\", \")}.`,\n );\n }\n }\n if (kind === \"accept\") {\n if (snapshot.kind === \"task\") {\n throw new AiDlcError(\n \"E_WRONG_KIND\",\n \"PO accepts stories and epics. A task is done when its PR is merged and its story is accepted.\",\n );\n }\n const ready = await this.findValidDecision(\n issue.number,\n snapshot.baselineId,\n \"ready\",\n policy,\n );\n if (!ready)\n throw new AiDlcError(\"E_NOT_READY\", \"There is no valid ready decision for this baseline.\");\n build = await this.verifyBuild(Number(args.run), args.commit as string, policy);\n }\n const receipt: DecisionReceipt = {\n schemaVersion: DECISION_SCHEMA_VERSION,\n decisionId: decisionId(kind, comment.id),\n kind,\n issueNumber: issue.number,\n baselineId: snapshot.baselineId,\n baselineHash: snapshot.contentHash,\n actor: { id: comment.author.id, login: comment.author.login },\n source: { commentId: comment.id, commentBodyDigest: commentDigest(comment.body) },\n lane,\n build,\n policyVersion: policy.version,\n recordedAt: clock.now().toISOString(),\n };\n await evidence.write(\n decisionPath(this.repositoryId, issue.number, receipt.decisionId),\n receipt,\n );\n if (kind === \"accept\") {\n await github.closeIssue(issue.number, \"completed\");\n return `**\u0110\u00E3 ghi nh\u1EADn nghi\u1EC7m thu** \\`${receipt.decisionId}\\` cho \\`${snapshot.baselineId}\\` tr\u00EAn build ${build?.runId} (\\`${build?.headSha.slice(0, 7)}\\`). Issue \u0111\u00E3 \u0111\u01B0\u1EE3c \u0111\u00F3ng.`;\n }\n if (kind === \"ready\") {\n const block = renderPrBlock({\n issueNumber: issue.number,\n baselineId: snapshot.baselineId,\n hash: snapshot.contentHash,\n acceptanceCriteria:\n snapshot.kind === \"task\"\n ? snapshot.acRefs\n : snapshot.requirements.criteria.map((c) => c.id),\n });\n return [\n `**S\u1EB5n s\u00E0ng tri\u1EC3n khai** \\`${receipt.decisionId}\\` (lane \\`${lane}\\`).`,\n \"\",\n \"D\u00E1n kh\u1ED1i sau v\u00E0o m\u00F4 t\u1EA3 Pull Request:\",\n \"```text\",\n block,\n \"```\",\n ].join(\"\\n\");\n }\n return `**\u0110\u00E3 duy\u1EC7t nghi\u1EC7p v\u1EE5** \\`${receipt.decisionId}\\` cho \\`${snapshot.baselineId}\\`. DEV c\u00F3 th\u1EC3 x\u00E1c nh\u1EADn \\`ready\\`.`;\n }\n\n private async verifyBuild(\n runId: number,\n commit: string,\n policy: Policy,\n ): Promise<NonNullable<DecisionReceipt[\"build\"]>> {\n if (!Number.isSafeInteger(runId) || runId <= 0)\n throw new AiDlcError(\"E_SYNTAX\", \"`run` must be a workflow run id.\");\n const problems = await this.buildProblems(runId, commit, policy);\n if (problems.problems.length > 0 || !problems.run) {\n throw new AiDlcError(\n \"E_BUILD_INVALID\",\n `Build cannot be accepted:\\n- ${problems.problems.join(\"\\n- \")}`,\n );\n }\n const { run } = problems;\n return {\n runId: run.id,\n runAttempt: run.runAttempt,\n workflowPath: run.path,\n headSha: run.headSha,\n };\n }\n\n private async buildProblems(runId: number, commit: string, policy: Policy) {\n const run = await this.deps.github.getWorkflowRun(runId);\n const problems: string[] = [];\n if (!run) return { run: null, problems: [`Workflow run ${runId} was not found.`] };\n const branch = await this.deps.github.getDefaultBranch();\n if (run.repositoryId !== this.repositoryId) problems.push(\"run belongs to another repository\");\n if (!policy.acceptance.build_workflows.includes(run.path))\n problems.push(`workflow \\`${run.path}\\` is not an acceptance workflow`);\n if (run.event !== \"push\" || run.headBranch !== branch)\n problems.push(`run must come from a push to \\`${branch}\\``);\n if (run.headSha !== commit) problems.push(\"run commit does not match `commit`\");\n if (run.status !== \"completed\" || run.conclusion !== \"success\")\n problems.push(\"run did not complete successfully\");\n return { run, problems };\n }\n\n private async revoke(\n args: Record<string, string>,\n issue: IssueData,\n comment: CommentData,\n policy: Policy,\n ): Promise<string> {\n const id = args.decision as string;\n const receipt = await this.deps.evidence.read<DecisionReceipt>(\n decisionPath(this.repositoryId, issue.number, id),\n );\n if (!receipt)\n throw new AiDlcError(\n \"E_DECISION_NOT_FOUND\",\n `Decision \\`${id}\\` was not found on this Issue.`,\n );\n const actorId = comment.author.id;\n const allowed =\n receipt.actor.id === actorId || hasRole(policy, actorId, REQUIRED_ROLE[receipt.kind]);\n if (!allowed)\n throw new AiDlcError(\n \"E_ROLE\",\n \"Only the author or a holder of the same role may revoke this decision.\",\n );\n const revocation: Revocation = {\n schemaVersion: 1,\n decisionId: id,\n actor: { id: actorId, login: comment.author.login },\n reason: args.reason as string,\n source: { commentId: comment.id },\n recordedAt: this.deps.clock.now().toISOString(),\n };\n const result = await this.deps.evidence.write(\n revocationPath(this.repositoryId, issue.number, id),\n revocation,\n );\n return result === \"created\" ? `**\u0110\u00E3 thu h\u1ED3i** \\`${id}\\`.` : `\\`${id}\\` \u0111\u00E3 b\u1ECB thu h\u1ED3i tr\u01B0\u1EDBc \u0111\u00F3.`;\n }\n\n async listDecisions(issueNumber: number): Promise<DecisionReceipt[]> {\n const paths = await this.deps.evidence.list(`decisions/${this.repositoryId}/${issueNumber}/`);\n const receipts: DecisionReceipt[] = [];\n for (const path of paths) {\n const receipt = await this.deps.evidence.read<DecisionReceipt>(path);\n if (receipt) receipts.push(receipt);\n }\n return receipts;\n }\n\n async isValid(\n receipt: DecisionReceipt,\n policy: Policy,\n ): Promise<{ valid: boolean; reasons: string[] }> {\n const { evidence, github } = this.deps;\n const revoked =\n (await evidence.read(\n revocationPath(this.repositoryId, receipt.issueNumber, receipt.decisionId),\n )) !== null;\n const comment = await github.getComment(receipt.source.commentId);\n const snapshot = await evidence.read<BaselineSnapshot>(\n baselinePath(this.repositoryId, receipt.issueNumber, receipt.baselineId),\n );\n const snapshotHash = snapshot && verifySnapshot(snapshot) ? snapshot.contentHash : null;\n let buildValid: boolean | undefined;\n if (receipt.kind === \"accept\" && receipt.build) {\n const { problems } = await this.buildProblems(\n receipt.build.runId,\n receipt.build.headSha,\n policy,\n );\n buildValid = problems.length === 0;\n }\n return evaluateReceipt(receipt, {\n policy,\n revoked,\n currentCommentBody: comment ? comment.body : null,\n snapshotHash,\n ...(buildValid === undefined ? {} : { buildValid }),\n });\n }\n\n async findValidDecision(\n issueNumber: number,\n baselineId: string,\n kind: DecisionKind,\n policy: Policy,\n ): Promise<DecisionReceipt | null> {\n for (const receipt of await this.listDecisions(issueNumber)) {\n if (receipt.kind !== kind || receipt.baselineId !== baselineId) continue;\n if ((await this.isValid(receipt, policy)).valid) return receipt;\n }\n return null;\n }\n\n private async reportInvalidatedDecisions(\n issueNumber: number,\n commentId: number,\n action: string,\n ): Promise<void> {\n const affected = (await this.listDecisions(issueNumber)).filter(\n (receipt) => receipt.source.commentId === commentId,\n );\n if (affected.length === 0) return;\n await this.deps.github.upsertComment(\n issueNumber,\n marker(\"invalidated\", String(commentId)),\n `Comment quy\u1EBFt \u0111\u1ECBnh \u0111\u00E3 b\u1ECB ${action === \"deleted\" ? \"x\u00F3a\" : \"s\u1EEDa\"}; c\u00E1c quy\u1EBFt \u0111\u1ECBnh sau kh\u00F4ng c\u00F2n hi\u1EC7u l\u1EF1c: ${affected\n .map((receipt) => `\\`${receipt.decisionId}\\` (${receipt.kind})`)\n .join(\", \")}.`,\n );\n }\n\n /** Evaluates the `ai-dlc/baseline` gate for a pull request and publishes a commit status. */\n async checkPullRequest(prNumber: number): Promise<PrCheckResult> {\n const pr = await this.deps.github.getPullRequest(prNumber);\n const result = this.deps.enabled\n ? await this.evaluatePullRequest(prNumber).catch((error: unknown) => {\n if (!isAiDlcError(error)) throw error;\n return {\n state: \"failure\" as const,\n description: `${error.code}: ${firstLine(error.message)}`,\n details: [error.message],\n };\n })\n : {\n state: \"pending\" as const,\n description: \"huddle60 is disabled by the operator\",\n details: [],\n };\n await this.deps.github.setCommitStatus(pr.headSha, {\n state: result.state,\n context: STATUS_CONTEXT,\n description: truncate(result.description, 140),\n });\n return result;\n }\n\n private async evaluatePullRequest(prNumber: number): Promise<PrCheckResult> {\n const { github } = this.deps;\n const policy = await this.policy();\n const pr = await github.getPullRequest(prNumber);\n for (const reference of closingReferences(pr.body)) {\n const referenced = await github.getIssue(reference).catch(() => null);\n const kind = referenced ? kindFromLabels(referenced.labels) : null;\n if (kind === \"story\" || kind === \"epic\") {\n throw new AiDlcError(\n \"E_CLOSING_KEYWORD\",\n `Use \\`Refs #${reference}\\`; closing keywords would close the ${kind} without acceptance.`,\n );\n }\n }\n if (pr.labels.includes(LABELS.exempt)) {\n return { state: \"success\", description: \"Exempt by maintainer label\", details: [] };\n }\n const block = parsePrBlock(pr.body);\n if (!block)\n throw new AiDlcError(\n \"E_PR_BLOCK\",\n \"PR body has no huddle60 block. Run the context CLI or use the ready reply.\",\n );\n const issue = await github.getIssue(block.issueNumber);\n const snapshot = await this.loadSnapshot(issue.number, block.baselineId);\n if (snapshot.contentHash !== block.hash)\n throw new AiDlcError(\"E_HASH_MISMATCH\", \"HUDDLE60-Hash does not match the baseline.\");\n if (snapshot.kind === \"epic\")\n throw new AiDlcError(\"E_PR_BLOCK\", \"A PR must reference a story or task, not an epic.\");\n this.assertCurrent(issue, snapshot);\n const ready = await this.findValidDecision(issue.number, snapshot.baselineId, \"ready\", policy);\n if (!ready || !ready.lane)\n throw new AiDlcError(\n \"E_NOT_READY\",\n `#${issue.number} has no valid ready decision for this baseline.`,\n );\n await this.assertApproved(snapshot, ready.lane, policy);\n const allowedAc = new Set(\n snapshot.kind === \"task\" ? snapshot.acRefs : snapshot.requirements.criteria.map((c) => c.id),\n );\n const unknown = block.acceptanceCriteria.filter((id) => !allowedAc.has(id));\n if (unknown.length > 0)\n throw new AiDlcError(\"E_PR_BLOCK\", `Unknown AC for this baseline: ${unknown.join(\", \")}.`);\n if (snapshot.kind === \"task\" && snapshot.parent !== null)\n await this.assertParentReady(snapshot.parent, policy);\n if (ready.lane === \"fast\") {\n const sensitive = (await github.listPullRequestFiles(prNumber)).filter((path) =>\n isSensitive(policy, path),\n );\n if (sensitive.length > 0) {\n throw new AiDlcError(\n \"E_SENSITIVE_PATH\",\n `Lane fast cannot change sensitive paths: ${sensitive.slice(0, 5).join(\", \")}.`,\n );\n }\n }\n return {\n state: \"success\",\n description: `${snapshot.baselineId} ready (${ready.lane})`,\n details: [],\n };\n }\n\n /** PO approves stories; a task inherits the approval of its parent story's current content. */\n private async assertApproved(\n snapshot: BaselineSnapshot,\n lane: LaneName,\n policy: Policy,\n ): Promise<void> {\n if (!policy.lanes[lane].requires_po_approval) return;\n if (snapshot.kind === \"task\") {\n if (snapshot.parent === null) {\n throw new AiDlcError(\"E_FORM\", \"A task needs a parent story in `### Issue cha`.\");\n }\n if (!(await this.parentDecision(snapshot.parent, \"approve\", policy))) {\n throw new AiDlcError(\n \"E_NOT_APPROVED\",\n `Lane \\`${lane}\\` requires a valid PO approval of parent story #${snapshot.parent} for its current content.`,\n );\n }\n return;\n }\n if (\n !(await this.findValidDecision(\n snapshot.source.issueNumber,\n snapshot.baselineId,\n \"approve\",\n policy,\n ))\n ) {\n throw new AiDlcError(\n \"E_NOT_APPROVED\",\n `Lane \\`${lane}\\` requires a valid PO approval for this baseline.`,\n );\n }\n }\n\n private async parentDecision(\n parentNumber: number,\n kind: DecisionKind,\n policy: Policy,\n ): Promise<DecisionReceipt | null> {\n const parent = await this.deps.github.getIssue(parentNumber);\n if (kindFromLabels(parent.labels) !== \"story\") {\n throw new AiDlcError(\"E_WRONG_KIND\", `Parent #${parentNumber} of a task must be a story.`);\n }\n const current = this.snapshotOf(parent);\n return this.findValidDecision(parentNumber, current.baselineId, kind, policy);\n }\n\n private async assertParentReady(parentNumber: number, policy: Policy): Promise<void> {\n if (!(await this.parentDecision(parentNumber, \"ready\", policy))) {\n throw new AiDlcError(\n \"E_NOT_READY\",\n `Parent story #${parentNumber} has no valid ready decision for its current content.`,\n );\n }\n }\n}\n\nfunction errorReply(error: AiDlcError): string {\n return [`**huddle60: \\`${error.code}\\`**`, \"\", sanitize(error.message)].join(\"\\n\");\n}\n\nfunction firstLine(text: string): string {\n return text.split(\"\\n\")[0] ?? \"\";\n}\n\nfunction truncate(text: string, max: number): string {\n return text.length <= max ? text : `${text.slice(0, max - 1)}\u2026`;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["marker", "z", "z"]
7
7
  }