@brainervirus/workit-core 2.1.4 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/package.json +3 -2
  2. package/scripts/analyze-release-scope.ts +3 -3
  3. package/scripts/doctor-check.ts +1 -2
  4. package/scripts/sync-release-manifests.ts +4 -4
  5. package/src/core/authority.ts +8 -8
  6. package/src/core/auto-approval.ts +6 -6
  7. package/src/core/branch.ts +4 -4
  8. package/src/core/config-conversion.ts +1 -1
  9. package/src/core/config.ts +3 -3
  10. package/src/core/cutover.ts +6 -6
  11. package/src/core/doctor.ts +49 -3
  12. package/src/core/external-action-effects.ts +15 -15
  13. package/src/core/external-action.ts +16 -19
  14. package/src/core/logger.ts +2 -2
  15. package/src/core/methods.ts +5 -0
  16. package/src/core/policy-resolver.ts +9 -6
  17. package/src/core/registration.ts +3 -5
  18. package/src/core/repo-context.ts +1 -1
  19. package/src/core/setup.ts +2 -2
  20. package/src/core/skill-manifests.ts +1 -1
  21. package/src/core/store-lock.ts +301 -0
  22. package/src/core/support-matrix.ts +1 -1
  23. package/src/core/task-context.ts +3 -3
  24. package/src/core/task-contract.ts +129 -9
  25. package/src/core/task-engine.ts +159 -159
  26. package/src/core/task-evaluation.ts +3 -3
  27. package/src/core/task-store.ts +407 -89
  28. package/src/core/tracker-issues.ts +1 -1
  29. package/src/core/uninstall.ts +3 -3
  30. package/src/core/workers.ts +3 -3
  31. package/src/core/workspaces.ts +4 -6
  32. package/src/core/youtrack-tools.ts +1 -1
  33. package/src/core.ts +1 -1
  34. package/src/git/rev.ts +736 -0
  35. package/src/{core/session-context.ts → hooks/context.ts} +97 -10
  36. package/src/hooks/descriptor.ts +113 -0
  37. package/src/hooks/handle.ts +111 -0
  38. package/src/hooks/hosts/claude-code.ts +281 -0
  39. package/src/hooks/hosts/codex.ts +298 -0
  40. package/src/hooks/hosts/cursor.ts +321 -0
  41. package/src/hooks/hosts/fields.ts +55 -0
  42. package/src/hooks/hosts/opencode.ts +79 -0
  43. package/src/hooks/hosts/pi.ts +80 -0
  44. package/src/hooks/index.ts +43 -0
  45. package/src/hooks/policy.ts +14 -0
  46. package/src/hooks/protocol.ts +89 -0
  47. package/src/hooks/run.ts +52 -0
@@ -55,7 +55,7 @@ const defaultCli = (bin: string, available: boolean): TrackerCli | null => {
55
55
  return Promise.resolve({
56
56
  status: out.status ?? 1,
57
57
  stdout: out.stdout ?? "",
58
- stderr: (out.error as Error | undefined)?.message ?? out.stderr ?? "",
58
+ stderr: out.error?.message ?? out.stderr ?? "",
59
59
  });
60
60
  };
61
61
  };
@@ -125,7 +125,7 @@ function cleanCursorSettings(
125
125
  const next = { ...settings };
126
126
  let changed = false;
127
127
  if (isRecord(next.enabled_plugins)) {
128
- const enabled = { ...(next.enabled_plugins as Record<string, unknown>) };
128
+ const enabled = { ...next.enabled_plugins };
129
129
  for (const identity of ["workit", ...CURSOR_LEGACY_IDENTITIES]) {
130
130
  if (identity in enabled) {
131
131
  delete enabled[identity];
@@ -177,7 +177,7 @@ function cleanCursorMcp(mcp: Record<string, unknown>): {
177
177
  const next = { ...mcp };
178
178
  let changed = false;
179
179
  if (isRecord(next.mcpServers)) {
180
- const servers = { ...(next.mcpServers as Record<string, unknown>) };
180
+ const servers = { ...next.mcpServers };
181
181
  for (const name of ["workit", "workflow-toolkit"]) {
182
182
  if (name in servers) {
183
183
  delete servers[name];
@@ -211,7 +211,7 @@ function cleanPiConfig(config: Record<string, unknown>): {
211
211
  changed = true;
212
212
  }
213
213
  }
214
- const pi = isRecord(next.pi) ? { ...(next.pi as Record<string, unknown>) } : null;
214
+ const pi = isRecord(next.pi) ? { ...next.pi } : null;
215
215
  if (pi && Array.isArray(pi.extensions)) {
216
216
  const kept = pi.extensions.filter((entry) => !String(entry).includes("workit"));
217
217
  if (kept.length !== pi.extensions.length) {
@@ -117,7 +117,7 @@ const callerSession = (caller: CallerContext): HostSession =>
117
117
  const validPath = (value: unknown): value is string =>
118
118
  typeof value === "string" &&
119
119
  value.length > 0 &&
120
- ![...value].some((char) => {
120
+ !Array.from(value).some((char) => {
121
121
  const code = char.charCodeAt(0);
122
122
  return code < 32 || code === 127;
123
123
  }) &&
@@ -157,9 +157,9 @@ export function assertProductWriteAllowed(input: ProductWriteInput): Result<Owne
157
157
  return failure("invalid_input", "invalid product write path");
158
158
  if (!input.store) return failure("permission_denied", "write authorization requires core state");
159
159
  const task = input.store.readTask(input.task.id);
160
- if (!task.ok) return task as Result<never>;
160
+ if (!task.ok) return task;
161
161
  const workspace = input.store.readWorkspace();
162
- if (!workspace.ok) return workspace as Result<never>;
162
+ if (!workspace.ok) return workspace;
163
163
  if (!workspace.data) return failure("not_found", "workspace not found");
164
164
  const workspaceRecord = workspace.data;
165
165
  if (task.data.status !== "active")
@@ -552,6 +552,7 @@ const resolveRuntimeWorkspaceCandidate = (
552
552
  if ((error as NodeJS.ErrnoException).code === "ENOENT") return null;
553
553
  throw new Error(
554
554
  `${file} could not be read: ${error instanceof Error ? error.message : String(error)}`,
555
+ { cause: error },
555
556
  );
556
557
  }
557
558
  let parsed: unknown;
@@ -567,7 +568,7 @@ const resolveRuntimeWorkspaceCandidate = (
567
568
  .join("; ");
568
569
  throw new Error(`${file} has invalid workspace matching data: ${detail}`);
569
570
  }
570
- const entries = validated.data.workspaces as RuntimeWorkspaceCandidate[] | undefined;
571
+ const entries = validated.data.workspaces;
571
572
  for (const entry of entries ?? []) {
572
573
  const glob = validateWorkspaceGlob(entry.glob);
573
574
  if (!glob.ok) throw new Error(`${file} workspace ${entry.name}: ${glob.error}`);
@@ -619,10 +620,7 @@ export const resolveRuntimeWorkspacePolicy = (
619
620
  `workspace ${JSON.stringify(candidate.name)} has no profile ${JSON.stringify(profileName)}`,
620
621
  );
621
622
  const profilePolicy = profile?.[key] as WorkspaceBranchPolicy | WorkspaceCommitPolicy | undefined;
622
- const workspacePolicy = candidate[key] as
623
- | WorkspaceBranchPolicy
624
- | WorkspaceCommitPolicy
625
- | undefined;
623
+ const workspacePolicy = candidate[key];
626
624
  return {
627
625
  policy: profilePolicy ?? workspacePolicy,
628
626
  source: profilePolicy
@@ -700,7 +698,7 @@ export const selectReleaseTrack = (
700
698
  requestedTrack?: string,
701
699
  ): ReleaseTrackSelection => {
702
700
  const tracks = workspace.releaseTracks ?? {};
703
- const choices = Object.keys(tracks).sort();
701
+ const choices = Object.keys(tracks).toSorted();
704
702
  if (requestedTrack === undefined) {
705
703
  if (choices.length === 0) return { status: "not_configured" };
706
704
  if (choices.length > 1) return { status: "choice_required", choices };
@@ -84,7 +84,7 @@ export const defaultOperations: YouTrackOperations = {
84
84
  issueId,
85
85
  markdown,
86
86
  workspace_root: workspaceRoot,
87
- } as never),
87
+ }),
88
88
  ),
89
89
  logTime: async (input) => unwrap(await legacyLogTime(input as never)),
90
90
  };
package/src/core.ts CHANGED
@@ -7,6 +7,7 @@ export {
7
7
  POLICY_VERSION,
8
8
  OPERATION_FAMILIES,
9
9
  operationSchemas,
10
+ advertisedOperationSchemas,
10
11
  operationJsonSchema,
11
12
  boundedOperationJsonSchema,
12
13
  OPERATION_SCHEMA_DEPTH,
@@ -66,7 +67,6 @@ export type {
66
67
  RecoveryInput,
67
68
  TaskIndexEntry,
68
69
  } from "./core/task-store";
69
- export { sessionCompactContext, unfinishedTaskOffer } from "./core/session-context";
70
70
  export { compactTaskContext, reconcileResume } from "./core/task-context";
71
71
  export type {
72
72
  CompactTaskContext,