@danypops/papyrus 0.57.0 → 0.58.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 (40) hide show
  1. package/package.json +1 -1
  2. package/src/artifact/artifact-scope-store.ts +8 -8
  3. package/src/artifact/in-memory-artifact-scope-store.ts +7 -7
  4. package/src/artifact/sqlite-artifact-scope-store.ts +8 -8
  5. package/src/docs/docs-service.ts +1 -1
  6. package/src/domain-service-shared.ts +1 -1
  7. package/src/handlers/playbooks.ts +4 -4
  8. package/src/handlers/registry.ts +2 -2
  9. package/src/handlers/task-classifiers.ts +1 -1
  10. package/src/handlers/tasks.ts +2 -2
  11. package/src/index.ts +3 -3
  12. package/src/modules/playbooks.ts +4 -4
  13. package/src/modules/projects.ts +1 -1
  14. package/src/modules/tasks.ts +2 -2
  15. package/src/playbook/playbook-service.ts +1 -1
  16. package/src/playbook/workflow-execution.ts +6 -6
  17. package/src/project-registry/scope-source.ts +29 -0
  18. package/src/rules/rules-service.ts +1 -1
  19. package/src/service.ts +10 -10
  20. package/src/{task-create-request → task/create-request}/sqlite-task-create-request-store.ts +2 -2
  21. package/src/{task-event → task/event}/sqlite-task-event-store.ts +4 -4
  22. package/src/{task-event → task/event}/task-event-store.ts +15 -2
  23. package/src/{task-event → task/event}/task-event.ts +1 -1
  24. package/src/{task-focus → task/focus}/sqlite-task-focus-store.ts +4 -4
  25. package/src/{task-focus → task/focus}/task-focus-store.ts +1 -1
  26. package/src/{task-lease → task/lease}/sqlite-task-lease-store.ts +5 -5
  27. package/src/{task-lease → task/lease}/task-lease-store.ts +2 -2
  28. package/src/{task-lease → task/lease}/task-lease.ts +1 -1
  29. package/src/{task-mutation-request → task/mutation-request}/sqlite-task-mutation-request-store.ts +2 -6
  30. package/src/{task-scope → task/scope}/sqlite-task-scope-store.ts +5 -5
  31. package/src/{task-scope → task/scope}/task-scope-store.ts +18 -4
  32. package/src/{task-scope → task/scope}/task-scope.ts +8 -13
  33. package/src/task/task-edges.ts +2 -2
  34. package/src/task/task-focus-coordinator.ts +3 -3
  35. package/src/task/task-lease-coordinator.ts +2 -2
  36. package/src/task/task-mutation-coordinator.ts +1 -1
  37. package/src/task/task-project-scope.ts +4 -4
  38. package/src/task/task-service.ts +11 -11
  39. /package/src/{task-create-request → task/create-request}/task-create-request-store.ts +0 -0
  40. /package/src/{task-mutation-request → task/mutation-request}/task-mutation-request-store.ts +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danypops/papyrus",
3
- "version": "0.57.0",
3
+ "version": "0.58.0",
4
4
  "description": "Daemon-backed graph artifacts, evidence-bearing tasks, rules, skills, and native TUI workflows for Pi",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -1,5 +1,5 @@
1
+ import type { ScopeAssignmentSource } from "../project-registry/scope-source.ts";
1
2
  import type { ScopeMemberRef } from "../scope-group/scope-group.ts";
2
- import type { TaskScopeSource } from "../task-scope/task-scope.ts";
3
3
 
4
4
  /**
5
5
  * Project scoping for Docs/Rules/Playbooks: an artifact is explicitly "none" (hidden -- never
@@ -19,13 +19,13 @@ export interface ArtifactScope {
19
19
  mode: ArtifactScopeMode;
20
20
  /** Direct membership only (not expanded through nested groups) -- always empty when mode is "none"/"all", always non-empty when mode is "explicit". */
21
21
  members: ScopeMemberRef[];
22
- source: TaskScopeSource;
22
+ source: ScopeAssignmentSource;
23
23
  }
24
24
 
25
25
  export interface LegacyArtifactScope {
26
26
  artifactId: string;
27
27
  projectRoot?: string;
28
- source: TaskScopeSource;
28
+ source: ScopeAssignmentSource;
29
29
  }
30
30
 
31
31
  export interface ArtifactScopeStore {
@@ -34,15 +34,15 @@ export interface ArtifactScopeStore {
34
34
  /** Single-root compatibility view over scope(): an "all"/"none" or unscoped artifact omits projectRoot; an "explicit" mode artifact with exactly one project-type membership (and no group members) resolves it back to that project's current root; anything else (zero, more than one, or any group membership) omits projectRoot, since this shape cannot represent it. */
35
35
  get(artifactId: string): LegacyArtifactScope | undefined;
36
36
  /** Single-root compatibility shim: registers/resolves projectRoot and replaces the artifact's scope with exactly that one project membership, or setAll() when projectRoot is undefined. Every existing caller (rules/docs/playbooks assign_project) keeps working unchanged. */
37
- assign(artifactId: string, projectRoot: string | undefined, source: TaskScopeSource): LegacyArtifactScope;
37
+ assign(artifactId: string, projectRoot: string | undefined, source: ScopeAssignmentSource): LegacyArtifactScope;
38
38
  /** Sets an artifact to explicitly "all" (applies everywhere), clearing any membership. */
39
- setAll(artifactId: string, source: TaskScopeSource): ArtifactScope;
39
+ setAll(artifactId: string, source: ScopeAssignmentSource): ArtifactScope;
40
40
  /** Sets an artifact to explicitly "none" (fully hidden -- never applicable, never context-injected, regardless of project), clearing any membership. */
41
- setNone(artifactId: string, source: TaskScopeSource): ArtifactScope;
41
+ setNone(artifactId: string, source: ScopeAssignmentSource): ArtifactScope;
42
42
  /** Replaces an artifact's entire explicit membership set with exactly these (project and/or group) members -- must be non-empty; use setAll/setNone to clear scoping entirely. */
43
- replaceMembers(artifactId: string, members: readonly ScopeMemberRef[], source: TaskScopeSource): ArtifactScope;
43
+ replaceMembers(artifactId: string, members: readonly ScopeMemberRef[], source: ScopeAssignmentSource): ArtifactScope;
44
44
  /** Adds one member to an artifact's explicit membership (idempotent), switching mode to "explicit" if it was "all"/"none". Enforces the bounded maximum membership count. */
45
- addMember(artifactId: string, member: ScopeMemberRef, source: TaskScopeSource): ArtifactScope;
45
+ addMember(artifactId: string, member: ScopeMemberRef, source: ScopeAssignmentSource): ArtifactScope;
46
46
  /** Removes one member from an artifact's explicit membership (idempotent). Rejects removing the last membership while mode is "explicit": a caller must explicitly call setAll/setNone instead of accidentally broadening/narrowing scope by emptying the set. */
47
47
  removeMember(artifactId: string, member: ScopeMemberRef): ArtifactScope;
48
48
  /** Bounded id listing for one project root's EXACT direct membership (or the "all" bucket when projectRoot is undefined) -- an unregistered root always yields an empty list. Deliberately does not expand nested groups (audit semantics, matching this method's own pre-existing "exact membership" contract) -- use appliesToProjectRoot for the applicable/injection query instead. */
@@ -1,16 +1,16 @@
1
1
  import { ARTIFACT_SCOPE_MAX_MEMBERS_PER_ARTIFACT } from "../constants.ts";
2
2
  import { InMemoryProjectRegistryStore } from "../project-registry/in-memory-project-registry-store.ts";
3
3
  import type { ProjectRegistryStore } from "../project-registry/project-registry-store.ts";
4
+ import type { ScopeAssignmentSource } from "../project-registry/scope-source.ts";
4
5
  import { InMemoryScopeGroupStore } from "../scope-group/in-memory-scope-group-store.ts";
5
6
  import { type ScopeMemberRef, sameScopeMember } from "../scope-group/scope-group.ts";
6
7
  import type { ScopeGroupStore } from "../scope-group/scope-group-store.ts";
7
- import type { TaskScopeSource } from "../task-scope/task-scope.ts";
8
8
  import type { ArtifactScope, ArtifactScopeMode, ArtifactScopeStore, LegacyArtifactScope } from "./artifact-scope-store.ts";
9
9
 
10
10
  interface Row {
11
11
  mode: ArtifactScopeMode;
12
12
  members: ScopeMemberRef[];
13
- source: TaskScopeSource;
13
+ source: ScopeAssignmentSource;
14
14
  }
15
15
 
16
16
  export class InMemoryArtifactScopeStore implements ArtifactScopeStore {
@@ -45,7 +45,7 @@ export class InMemoryArtifactScopeStore implements ArtifactScopeStore {
45
45
  return { artifactId, ...(projectRoot === undefined ? {} : { projectRoot }), source: row.source };
46
46
  }
47
47
 
48
- assign(artifactId: string, projectRoot: string | undefined, source: TaskScopeSource): LegacyArtifactScope {
48
+ assign(artifactId: string, projectRoot: string | undefined, source: ScopeAssignmentSource): LegacyArtifactScope {
49
49
  if (projectRoot === undefined) {
50
50
  this.setAll(artifactId, source);
51
51
  return { artifactId, source };
@@ -55,19 +55,19 @@ export class InMemoryArtifactScopeStore implements ArtifactScopeStore {
55
55
  return { artifactId, projectRoot: project.projectRoot, source };
56
56
  }
57
57
 
58
- setAll(artifactId: string, source: TaskScopeSource): ArtifactScope {
58
+ setAll(artifactId: string, source: ScopeAssignmentSource): ArtifactScope {
59
59
  const row: Row = { mode: "all", members: [], source };
60
60
  this.rows.set(artifactId, row);
61
61
  return this.toScope(artifactId, row);
62
62
  }
63
63
 
64
- setNone(artifactId: string, source: TaskScopeSource): ArtifactScope {
64
+ setNone(artifactId: string, source: ScopeAssignmentSource): ArtifactScope {
65
65
  const row: Row = { mode: "none", members: [], source };
66
66
  this.rows.set(artifactId, row);
67
67
  return this.toScope(artifactId, row);
68
68
  }
69
69
 
70
- replaceMembers(artifactId: string, members: readonly ScopeMemberRef[], source: TaskScopeSource): ArtifactScope {
70
+ replaceMembers(artifactId: string, members: readonly ScopeMemberRef[], source: ScopeAssignmentSource): ArtifactScope {
71
71
  if (members.length === 0) throw new Error("replaceMembers requires at least one member; use setAll/setNone to clear scoping");
72
72
  if (members.length > ARTIFACT_SCOPE_MAX_MEMBERS_PER_ARTIFACT) {
73
73
  throw new Error(`an artifact cannot have more than ${ARTIFACT_SCOPE_MAX_MEMBERS_PER_ARTIFACT} scope members`);
@@ -78,7 +78,7 @@ export class InMemoryArtifactScopeStore implements ArtifactScopeStore {
78
78
  return this.toScope(artifactId, row);
79
79
  }
80
80
 
81
- addMember(artifactId: string, member: ScopeMemberRef, source: TaskScopeSource): ArtifactScope {
81
+ addMember(artifactId: string, member: ScopeMemberRef, source: ScopeAssignmentSource): ArtifactScope {
82
82
  const existing = this.rows.get(artifactId);
83
83
  const members = dedupeMembers(existing?.mode === "explicit" ? existing.members : []);
84
84
  if (!members.some((candidate) => sameScopeMember(candidate, member)) && members.length >= ARTIFACT_SCOPE_MAX_MEMBERS_PER_ARTIFACT) {
@@ -1,16 +1,16 @@
1
1
  import { ARTIFACT_SCOPE_MAX_MEMBERS_PER_ARTIFACT } from "../constants.ts";
2
2
  import type { Db } from "../db.ts";
3
3
  import { inTransaction } from "../db.ts";
4
+ import type { ScopeAssignmentSource } from "../project-registry/scope-source.ts";
4
5
  import { SQLiteProjectRegistryStore } from "../project-registry/sqlite-project-registry-store.ts";
5
6
  import type { ScopeMemberRef } from "../scope-group/scope-group.ts";
6
7
  import { SQLiteScopeGroupStore } from "../scope-group/sqlite-scope-group-store.ts";
7
- import type { TaskScopeSource } from "../task-scope/task-scope.ts";
8
8
  import type { ArtifactScope, ArtifactScopeMode, ArtifactScopeStore, LegacyArtifactScope } from "./artifact-scope-store.ts";
9
9
 
10
10
  interface ScopeRow {
11
11
  artifact_id: string;
12
12
  mode: ArtifactScopeMode;
13
- source: TaskScopeSource;
13
+ source: ScopeAssignmentSource;
14
14
  }
15
15
 
16
16
  interface MemberRow {
@@ -65,7 +65,7 @@ export class SQLiteArtifactScopeStore implements ArtifactScopeStore {
65
65
  return { artifactId, ...(project ? { projectRoot: project.projectRoot } : {}), source: row.source };
66
66
  }
67
67
 
68
- assign(artifactId: string, projectRoot: string | undefined, source: TaskScopeSource): LegacyArtifactScope {
68
+ assign(artifactId: string, projectRoot: string | undefined, source: ScopeAssignmentSource): LegacyArtifactScope {
69
69
  if (projectRoot === undefined) {
70
70
  this.setAll(artifactId, source);
71
71
  return { artifactId, source };
@@ -77,7 +77,7 @@ export class SQLiteArtifactScopeStore implements ArtifactScopeStore {
77
77
  });
78
78
  }
79
79
 
80
- private upsertScopeRow(artifactId: string, mode: ArtifactScopeMode, source: TaskScopeSource): void {
80
+ private upsertScopeRow(artifactId: string, mode: ArtifactScopeMode, source: ScopeAssignmentSource): void {
81
81
  this.db
82
82
  .prepare(`
83
83
  INSERT INTO artifact_scopes (artifact_id, project_root, mode, source, assigned_at)
@@ -91,7 +91,7 @@ export class SQLiteArtifactScopeStore implements ArtifactScopeStore {
91
91
  .run(artifactId, mode, source, new Date().toISOString());
92
92
  }
93
93
 
94
- setAll(artifactId: string, source: TaskScopeSource): ArtifactScope {
94
+ setAll(artifactId: string, source: ScopeAssignmentSource): ArtifactScope {
95
95
  return inTransaction(this.db, () => {
96
96
  this.upsertScopeRow(artifactId, "all", source);
97
97
  this.db.prepare("DELETE FROM artifact_scope_members WHERE artifact_id = ?").run(artifactId);
@@ -99,7 +99,7 @@ export class SQLiteArtifactScopeStore implements ArtifactScopeStore {
99
99
  });
100
100
  }
101
101
 
102
- setNone(artifactId: string, source: TaskScopeSource): ArtifactScope {
102
+ setNone(artifactId: string, source: ScopeAssignmentSource): ArtifactScope {
103
103
  return inTransaction(this.db, () => {
104
104
  this.upsertScopeRow(artifactId, "none", source);
105
105
  this.db.prepare("DELETE FROM artifact_scope_members WHERE artifact_id = ?").run(artifactId);
@@ -107,7 +107,7 @@ export class SQLiteArtifactScopeStore implements ArtifactScopeStore {
107
107
  });
108
108
  }
109
109
 
110
- replaceMembers(artifactId: string, members: readonly ScopeMemberRef[], source: TaskScopeSource): ArtifactScope {
110
+ replaceMembers(artifactId: string, members: readonly ScopeMemberRef[], source: ScopeAssignmentSource): ArtifactScope {
111
111
  if (members.length === 0) throw new Error("replaceMembers requires at least one member; use setAll/setNone to clear scoping");
112
112
  if (members.length > ARTIFACT_SCOPE_MAX_MEMBERS_PER_ARTIFACT) {
113
113
  throw new Error(`an artifact cannot have more than ${ARTIFACT_SCOPE_MAX_MEMBERS_PER_ARTIFACT} scope members`);
@@ -127,7 +127,7 @@ export class SQLiteArtifactScopeStore implements ArtifactScopeStore {
127
127
  });
128
128
  }
129
129
 
130
- addMember(artifactId: string, member: ScopeMemberRef, source: TaskScopeSource): ArtifactScope {
130
+ addMember(artifactId: string, member: ScopeMemberRef, source: ScopeAssignmentSource): ArtifactScope {
131
131
  return inTransaction(this.db, () => {
132
132
  const current = this.members(artifactId);
133
133
  const already = current.some((candidate) => candidate.type === member.type && candidate.id === member.id);
@@ -30,8 +30,8 @@ import {
30
30
  } from "../domain-service-shared.ts";
31
31
  import { NOTE_SUBTYPE } from "../note/note-service.ts";
32
32
  import type { ProjectRegistryStore } from "../project-registry/project-registry-store.ts";
33
+ import { normalizeProjectRoot } from "../project-registry/scope-source.ts";
33
34
  import type { ScopeGroupStore } from "../scope-group/scope-group-store.ts";
34
- import { normalizeProjectRoot } from "../task-scope/task-scope.ts";
35
35
 
36
36
  function rejectsNoteTemplate(artifacts: ArtifactStore, templateId: string | undefined, subtype: string | undefined): boolean {
37
37
  if (subtype === NOTE_SUBTYPE) return true;
@@ -19,9 +19,9 @@ import {
19
19
  } from "./constants.ts";
20
20
  import { resolveProjectReference } from "./project-registry/project-registry.ts";
21
21
  import type { ProjectRegistryStore } from "./project-registry/project-registry-store.ts";
22
+ import { normalizeProjectRoot } from "./project-registry/scope-source.ts";
22
23
  import { resolveScopeGroupReference } from "./scope-group/scope-group.ts";
23
24
  import type { ScopeGroupStore } from "./scope-group/scope-group-store.ts";
24
- import { normalizeProjectRoot } from "./task-scope/task-scope.ts";
25
25
 
26
26
  export interface UpdateContentInput {
27
27
  title?: string;
@@ -27,9 +27,9 @@ import { listPlaybooks } from "../playbook/playbook-service.ts";
27
27
  import type { ProjectRegistryStore } from "../project-registry/project-registry-store.ts";
28
28
  import type { ScopeGroupStore } from "../scope-group/scope-group-store.ts";
29
29
  import type { SessionIdentity } from "../session-identity/session-identity-service.ts";
30
+ import type { TaskEventSink } from "../task/event/task-event-store.ts";
31
+ import type { TaskScopeAssigner } from "../task/scope/task-scope-store.ts";
30
32
  import type { Tasks } from "../task/task-service.ts";
31
- import type { TaskEventStore } from "../task-event/task-event-store.ts";
32
- import type { TaskScopeStore } from "../task-scope/task-scope-store.ts";
33
33
  import {
34
34
  booleanProp,
35
35
  buildWorkflowRunContent,
@@ -53,8 +53,8 @@ const jsonObjectProp = {
53
53
 
54
54
  export interface PlaybooksVehicleDeps {
55
55
  artifacts: ArtifactStore;
56
- events: TaskEventStore;
57
- scopes: TaskScopeStore;
56
+ events: TaskEventSink;
57
+ scopes: TaskScopeAssigner;
58
58
  artifactScopes: ArtifactScopeStore;
59
59
  tasks: Tasks;
60
60
  sessionIdentity: SessionIdentity;
@@ -16,9 +16,9 @@ import type { Notes } from "../note/note-service.ts";
16
16
  import type { ProjectRegistryStore } from "../project-registry/project-registry-store.ts";
17
17
  import type { ScopeGroupStore } from "../scope-group/scope-group-store.ts";
18
18
  import type { SessionIdentity } from "../session-identity/session-identity-service.ts";
19
+ import type { TaskEventStore } from "../task/event/task-event-store.ts";
20
+ import type { TaskScopeStore } from "../task/scope/task-scope-store.ts";
19
21
  import type { Tasks } from "../task/task-service.ts";
20
- import type { TaskEventStore } from "../task-event/task-event-store.ts";
21
- import type { TaskScopeStore } from "../task-scope/task-scope-store.ts";
22
22
  import { registerArtifactTrashOperations } from "./artifact-trash.ts";
23
23
  import { registerDiscussVehicleOperations } from "./discuss.ts";
24
24
  import { registerDocsVehicleOperations } from "./docs.ts";
@@ -10,8 +10,8 @@
10
10
  import { VehicleError } from "@danypops/vehicle-core";
11
11
  import { PlaybookCompositionError } from "../playbook/playbook-definition.ts";
12
12
  import { InvalidSessionSecretError } from "../session-identity/session-identity-service.ts";
13
+ import { TaskCreateIdempotencyConflictError } from "../task/create-request/task-create-request-store.ts";
13
14
  import { TaskDependencyCycleError, TaskExecutionBoundExceededError } from "../task/task-execution.ts";
14
- import { TaskCreateIdempotencyConflictError } from "../task-create-request/task-create-request-store.ts";
15
15
 
16
16
  /**
17
17
  * tasks.focus/pause/unpause/clear_focus and playbooks.invoke all re-run
@@ -27,6 +27,8 @@ import { GATE_TYPES } from "../gate/gate.ts";
27
27
  import { tasksOperations } from "../modules/tasks.ts";
28
28
  import type { SessionIdentity } from "../session-identity/session-identity-service.ts";
29
29
  import { PROOF_TYPES } from "../task/checklist.ts";
30
+ import { TaskMutationIdempotencyConflictError, TaskMutationPendingError } from "../task/mutation-request/task-mutation-request-store.ts";
31
+ import type { TaskViewMode } from "../task/scope/task-scope.ts";
30
32
  import type { TaskExecutionPlan } from "../task/task-execution.ts";
31
33
  import {
32
34
  type TaskCompletion,
@@ -36,8 +38,6 @@ import {
36
38
  TaskProjectNotFoundError,
37
39
  type Tasks,
38
40
  } from "../task/task-service.ts";
39
- import { TaskMutationIdempotencyConflictError, TaskMutationPendingError } from "../task-mutation-request/task-mutation-request-store.ts";
40
- import type { TaskViewMode } from "../task-scope/task-scope.ts";
41
41
  import {
42
42
  booleanProp,
43
43
  classifySessionAuthorization,
package/src/index.ts CHANGED
@@ -28,6 +28,9 @@ export type { PlaybookInvocationResult, PlaybookMissingArguments } from "./playb
28
28
  export type { WorkflowRunResult } from "./playbook/workflow-execution.ts";
29
29
  export type { OperationName, SchemaState } from "./service.ts";
30
30
  export { checklistEntries, PROOF_TYPES, type ProofReference } from "./task/checklist.ts";
31
+ export type { TaskEvent, TaskHistoryPage } from "./task/event/task-event.ts";
32
+ export type { TaskLease, TaskLeaseView } from "./task/lease/task-lease.ts";
33
+ export type { TaskViewSelection } from "./task/scope/task-scope.ts";
31
34
  export { taskContext } from "./task/task-context.ts";
32
35
  export { projectTaskExecution, type TaskExecutionPlan, type TaskExecutionState } from "./task/task-execution.ts";
33
36
  export { projectTaskGraph, type TaskGraphView } from "./task/task-graph-view.ts";
@@ -41,6 +44,3 @@ export type {
41
44
  TaskStatus,
42
45
  } from "./task/task-service.ts";
43
46
  export { TaskInvalidTransitionError, TaskMutationReceiptNotFoundError } from "./task/task-service.ts";
44
- export type { TaskEvent, TaskHistoryPage } from "./task-event/task-event.ts";
45
- export type { TaskLease, TaskLeaseView } from "./task-lease/task-lease.ts";
46
- export type { TaskViewSelection } from "./task-scope/task-scope.ts";
@@ -40,9 +40,9 @@ import {
40
40
  import type { ProjectRegistryStore } from "../project-registry/project-registry-store.ts";
41
41
  import type { ScopeGroupStore } from "../scope-group/scope-group-store.ts";
42
42
  import type { SessionIdentity } from "../session-identity/session-identity-service.ts";
43
+ import type { TaskEventSink } from "../task/event/task-event-store.ts";
44
+ import type { TaskScopeAssigner } from "../task/scope/task-scope-store.ts";
43
45
  import type { Tasks } from "../task/task-service.ts";
44
- import type { TaskEventStore } from "../task-event/task-event-store.ts";
45
- import type { TaskScopeStore } from "../task-scope/task-scope-store.ts";
46
46
  import { type OperationInput, optionalBoolean, optionalNumber, optionalString, string } from "./operation-input.ts";
47
47
 
48
48
  const MODULE_ID = "playbooks";
@@ -105,8 +105,8 @@ export const PLAYBOOKS_OPERATION_NAMES = [
105
105
 
106
106
  export interface PlaybooksModuleDeps {
107
107
  artifacts: ArtifactStore;
108
- events: TaskEventStore;
109
- scopes: TaskScopeStore;
108
+ events: TaskEventSink;
109
+ scopes: TaskScopeAssigner;
110
110
  /** Docs/Rules/Skills/Playbooks project scoping (distinct from `scopes`, which is Task-run project scoping for playbooks.invoke's materialized tasks). */
111
111
  artifactScopes: ArtifactScopeStore;
112
112
  /** Used for exactly one thing: focusing the entry task after a successful invoke -- the one safety-checked Tasks operation this module needs, not bulk graph construction (that goes straight through artifacts/events/scopes in playbook/playbook-execution.ts, mirroring playbook/workflow-execution.ts). */
@@ -11,7 +11,7 @@ import { TASK_PROJECT_LIST_MAX_RESULTS } from "../constants.ts";
11
11
  import type { OperationDefinition } from "../module-registry.ts";
12
12
  import { assertRegisterProjectInputBounds, resolveProjectReference } from "../project-registry/project-registry.ts";
13
13
  import type { ProjectRegistryStore } from "../project-registry/project-registry-store.ts";
14
- import { normalizeProjectRoot } from "../task-scope/task-scope.ts";
14
+ import { normalizeProjectRoot } from "../project-registry/scope-source.ts";
15
15
  import { type OperationInput, optionalNumber, optionalString, optionalStringArray, string } from "./operation-input.ts";
16
16
 
17
17
  const MODULE_ID = "projects";
@@ -24,11 +24,11 @@ import type { ArtifactStore } from "../artifact/artifact-store.ts";
24
24
  import type { OperationDefinition } from "../module-registry.ts";
25
25
  import type { SessionIdentity } from "../session-identity/session-identity-service.ts";
26
26
  import type { Checklist } from "../task/checklist.ts";
27
+ import type { TaskEventContext, TaskEventDirection, TaskEventFeedQuery } from "../task/event/task-event.ts";
28
+ import type { TaskViewMode } from "../task/scope/task-scope.ts";
27
29
  import { taskContext } from "../task/task-context.ts";
28
30
  import { projectTaskExecution } from "../task/task-execution.ts";
29
31
  import type { TaskMutationRequestContext, TaskStatus, Tasks } from "../task/task-service.ts";
30
- import type { TaskEventContext, TaskEventDirection, TaskEventFeedQuery } from "../task-event/task-event.ts";
31
- import type { TaskViewMode } from "../task-scope/task-scope.ts";
32
32
  import { type OperationInput, optionalBoolean, optionalNumber, optionalString, optionalStringArray, string } from "./operation-input.ts";
33
33
 
34
34
  const MODULE_ID = "tasks";
@@ -57,8 +57,8 @@ import {
57
57
  type UpdateContentInput,
58
58
  } from "../domain-service-shared.ts";
59
59
  import type { ProjectRegistryStore } from "../project-registry/project-registry-store.ts";
60
+ import { normalizeProjectRoot } from "../project-registry/scope-source.ts";
60
61
  import type { ScopeGroupStore } from "../scope-group/scope-group-store.ts";
61
- import { normalizeProjectRoot } from "../task-scope/task-scope.ts";
62
62
  import {
63
63
  BLUEPRINT_INPUT_TYPES,
64
64
  type BlueprintArgumentValue,
@@ -9,13 +9,13 @@ import {
9
9
  SKILL_WORKFLOW_MAX_NESTING_DEPTH,
10
10
  TASK_EXECUTION_MAX_EDGES,
11
11
  } from "../constants.ts";
12
+ import { normalizeProjectRoot } from "../project-registry/scope-source.ts";
12
13
  import { validateChecklist } from "../task/checklist.ts";
14
+ import type { TaskEventContext } from "../task/event/task-event.ts";
15
+ import type { TaskEventSink } from "../task/event/task-event-store.ts";
16
+ import type { TaskScopeAssigner } from "../task/scope/task-scope-store.ts";
13
17
  import { projectTaskExecution, TaskExecutionBoundExceededError, type TaskExecutionPlan } from "../task/task-execution.ts";
14
18
  import type { TaskGraph, TaskNode, TaskStatus } from "../task/task-service.ts";
15
- import type { TaskEventContext } from "../task-event/task-event.ts";
16
- import type { TaskEventStore } from "../task-event/task-event-store.ts";
17
- import { normalizeProjectRoot } from "../task-scope/task-scope.ts";
18
- import type { TaskScopeStore } from "../task-scope/task-scope-store.ts";
19
19
  import {
20
20
  type BlueprintArgumentValue,
21
21
  type BlueprintDefinition,
@@ -167,8 +167,8 @@ function executionGraph(tasks: Artifact[], definition: BlueprintDefinition, ids:
167
167
  * other project's context.
168
168
  */
169
169
  export type WorkflowRunHistory = {
170
- events: TaskEventStore;
171
- scopes: TaskScopeStore;
170
+ events: TaskEventSink;
171
+ scopes: TaskScopeAssigner;
172
172
  artifactScopes?: ArtifactScopeStore;
173
173
  projectRoot?: string;
174
174
  context?: TaskEventContext;
@@ -0,0 +1,29 @@
1
+ import { basename, isAbsolute, normalize } from "node:path";
2
+ import { TASK_PROJECT_ROOT_MAX_LENGTH } from "../constants.ts";
3
+
4
+ /**
5
+ * How a project root ended up attached to a scoped artifact -- shared across every artifact kind
6
+ * (Tasks, Docs, Rules, Playbooks) rather than owned by Tasks alone, same category as Project
7
+ * itself in project-registry.ts. This lived inside task-scope.ts under the name
8
+ * `TaskScopeSource` until a SOLID audit (see Doc "SOLID pattern analysis: task-event/task-scope
9
+ * shared-kernel extraction") found it consumed identically by artifact/, docs-service.ts,
10
+ * rules-service.ts, playbook-service.ts, and modules/projects.ts -- a Role Interface split
11
+ * couldn't fix this half of the problem because there's no single supplier to narrow a contract
12
+ * for; every one of those five call sites is a peer owner of the same vocabulary. task-scope.ts
13
+ * keeps `TaskScopeSource` as a backward-compatible alias of this type for Task's own call sites.
14
+ */
15
+ export type ScopeAssignmentSource = "cwd" | "explicit" | "unscoped";
16
+
17
+ /**
18
+ * Same relocation as ScopeAssignmentSource above, for the same reason: a pure, artifact-kind-
19
+ * agnostic validation/normalization function that every non-Task scope-assigning service already
20
+ * called directly rather than through any Task-owned abstraction.
21
+ */
22
+ export function normalizeProjectRoot(value: string): string {
23
+ if (!isAbsolute(value)) throw new Error("project_root must be an absolute path");
24
+ const normalized = normalize(value);
25
+ if (normalized.length > TASK_PROJECT_ROOT_MAX_LENGTH) {
26
+ throw new Error(`project_root cannot exceed ${TASK_PROJECT_ROOT_MAX_LENGTH} characters`);
27
+ }
28
+ return normalized;
29
+ }
@@ -31,8 +31,8 @@ import {
31
31
  type UpdateContentInput,
32
32
  } from "../domain-service-shared.ts";
33
33
  import type { ProjectRegistryStore } from "../project-registry/project-registry-store.ts";
34
+ import { normalizeProjectRoot } from "../project-registry/scope-source.ts";
34
35
  import type { ScopeGroupStore } from "../scope-group/scope-group-store.ts";
35
- import { normalizeProjectRoot } from "../task-scope/task-scope.ts";
36
36
 
37
37
  export interface CreateRuleInput {
38
38
  title: string;
package/src/service.ts CHANGED
@@ -43,17 +43,17 @@ import { listInjectableRules } from "./rules/rules-service.ts";
43
43
  import { SQLiteScopeGroupStore } from "./scope-group/sqlite-scope-group-store.ts";
44
44
  import { InvalidSessionSecretError, SessionIdentity } from "./session-identity/session-identity-service.ts";
45
45
  import { SQLiteSessionIdentityStore } from "./session-identity/sqlite-session-identity-store.ts";
46
+ import { SQLiteTaskCreateRequestStore } from "./task/create-request/sqlite-task-create-request-store.ts";
47
+ import { SQLiteTaskEventStore } from "./task/event/sqlite-task-event-store.ts";
48
+ import type { TaskEventContext } from "./task/event/task-event.ts";
49
+ import type { TaskEventStore } from "./task/event/task-event-store.ts";
50
+ import { SQLiteTaskFocusStore } from "./task/focus/sqlite-task-focus-store.ts";
51
+ import { SQLiteTaskLeaseStore } from "./task/lease/sqlite-task-lease-store.ts";
52
+ import { SQLiteTaskMutationRequestStore } from "./task/mutation-request/sqlite-task-mutation-request-store.ts";
53
+ import { SQLiteTaskScopeStore } from "./task/scope/sqlite-task-scope-store.ts";
54
+ import type { TaskViewMode } from "./task/scope/task-scope.ts";
55
+ import type { TaskScopeStore } from "./task/scope/task-scope-store.ts";
46
56
  import { type TaskStatus, Tasks } from "./task/task-service.ts";
47
- import { SQLiteTaskCreateRequestStore } from "./task-create-request/sqlite-task-create-request-store.ts";
48
- import { SQLiteTaskEventStore } from "./task-event/sqlite-task-event-store.ts";
49
- import type { TaskEventContext } from "./task-event/task-event.ts";
50
- import type { TaskEventStore } from "./task-event/task-event-store.ts";
51
- import { SQLiteTaskFocusStore } from "./task-focus/sqlite-task-focus-store.ts";
52
- import { SQLiteTaskLeaseStore } from "./task-lease/sqlite-task-lease-store.ts";
53
- import { SQLiteTaskMutationRequestStore } from "./task-mutation-request/sqlite-task-mutation-request-store.ts";
54
- import { SQLiteTaskScopeStore } from "./task-scope/sqlite-task-scope-store.ts";
55
- import type { TaskViewMode } from "./task-scope/task-scope.ts";
56
- import type { TaskScopeStore } from "./task-scope/task-scope-store.ts";
57
57
  import { VERSION } from "./version.ts";
58
58
 
59
59
  /**
@@ -1,5 +1,5 @@
1
- import type { Db } from "../db.ts";
2
- import type { TaskCreateRequestRecord, TaskCreateRequestStore } from "../task-create-request/task-create-request-store.ts";
1
+ import type { Db } from "../../db.ts";
2
+ import type { TaskCreateRequestRecord, TaskCreateRequestStore } from "./task-create-request-store.ts";
3
3
 
4
4
  export class SQLiteTaskCreateRequestStore implements TaskCreateRequestStore {
5
5
  constructor(private readonly db: Db) {}
@@ -1,5 +1,5 @@
1
- import type { Db } from "../db.ts";
2
- import { inTransaction } from "../db.ts";
1
+ import type { Db } from "../../db.ts";
2
+ import { inTransaction } from "../../db.ts";
3
3
  import {
4
4
  type AppendTaskEvent,
5
5
  normalizeTaskEventFeedQuery,
@@ -13,8 +13,8 @@ import {
13
13
  type TaskHistoryQuery,
14
14
  type TaskLifecycleStatus,
15
15
  validateTaskEvent,
16
- } from "../task-event/task-event.ts";
17
- import type { TaskEventStore } from "../task-event/task-event-store.ts";
16
+ } from "./task-event.ts";
17
+ import type { TaskEventStore } from "./task-event-store.ts";
18
18
 
19
19
  interface TaskEventRow {
20
20
  id: number;
@@ -8,11 +8,24 @@ import {
8
8
  type TaskHistoryPage,
9
9
  type TaskHistoryQuery,
10
10
  validateTaskEvent,
11
- } from "../task-event/task-event.ts";
11
+ } from "./task-event.ts";
12
12
 
13
- export interface TaskEventStore {
13
+ /**
14
+ * Role Interface (Fowler: https://martinfowler.com/bliki/RoleInterface.html) for the one
15
+ * collaboration playbook workflow execution actually has with Task's event log: append one event
16
+ * inside a single atomic transaction. Extracted after a SOLID audit found TaskEventStore's full
17
+ * Header Interface (all 4 methods, including history/feed -- pagination concerns that exist
18
+ * purely for Task's own history/feed reader endpoints) threaded unchanged through
19
+ * handlers/playbooks.ts, modules/playbooks.ts, and playbook/workflow-execution.ts, which never
20
+ * calls history()/feed() at all. TaskEventStore still implements this structurally with zero
21
+ * changes to either concrete store; only the playbook-facing field type narrows to this.
22
+ */
23
+ export interface TaskEventSink {
14
24
  atomic<T>(operation: () => T): T;
15
25
  append(event: AppendTaskEvent): TaskEvent;
26
+ }
27
+
28
+ export interface TaskEventStore extends TaskEventSink {
16
29
  history(taskId: string, query?: TaskHistoryQuery): TaskHistoryPage;
17
30
  /** Bounded, sequenced, cross-task replay feed -- see TaskEventFeedQuery. */
18
31
  feed(query?: TaskEventFeedQuery): TaskEventFeedPage;
@@ -6,7 +6,7 @@ import {
6
6
  TASK_EVENT_REASON_MAX_LENGTH,
7
7
  TASK_HISTORY_DEFAULT_LIMIT,
8
8
  TASK_HISTORY_MAX_LIMIT,
9
- } from "../constants.ts";
9
+ } from "../../constants.ts";
10
10
  export type TaskLifecycleStatus = "todo" | "in-progress" | "review" | "rejected" | "done" | "canceled";
11
11
 
12
12
  export const TASK_EVENT_TYPES = [
@@ -1,7 +1,7 @@
1
- import { TASK_FOCUS_MAX_SCOPES } from "../constants.ts";
2
- import type { Db } from "../db.ts";
3
- import { inTransaction } from "../db.ts";
4
- import { normalizeFocusScope, type TaskFocusState, type TaskFocusStatus, type TaskFocusStore } from "../task-focus/task-focus-store.ts";
1
+ import { TASK_FOCUS_MAX_SCOPES } from "../../constants.ts";
2
+ import type { Db } from "../../db.ts";
3
+ import { inTransaction } from "../../db.ts";
4
+ import { normalizeFocusScope, type TaskFocusState, type TaskFocusStatus, type TaskFocusStore } from "./task-focus-store.ts";
5
5
 
6
6
  export class SQLiteTaskFocusStore implements TaskFocusStore {
7
7
  constructor(private readonly db: Db) {}
@@ -1,4 +1,4 @@
1
- import { TASK_FOCUS_DEFAULT_SCOPE, TASK_FOCUS_MAX_SCOPES, TASK_FOCUS_SCOPE_MAX_LENGTH } from "../constants.ts";
1
+ import { TASK_FOCUS_DEFAULT_SCOPE, TASK_FOCUS_MAX_SCOPES, TASK_FOCUS_SCOPE_MAX_LENGTH } from "../../constants.ts";
2
2
 
3
3
  export type TaskFocusStatus = "active" | "paused";
4
4
 
@@ -1,8 +1,8 @@
1
- import { TASK_LEASE_DEFAULT_TTL_MS } from "../constants.ts";
2
- import type { Db } from "../db.ts";
3
- import { inTransaction } from "../db.ts";
4
- import { isLeaseExpired, type TaskLease, validateLeaseNote, validateLeaseOwner, validateLeaseTtlMs } from "../task-lease/task-lease.ts";
5
- import type { TaskLeaseStore } from "../task-lease/task-lease-store.ts";
1
+ import { TASK_LEASE_DEFAULT_TTL_MS } from "../../constants.ts";
2
+ import type { Db } from "../../db.ts";
3
+ import { inTransaction } from "../../db.ts";
4
+ import { isLeaseExpired, type TaskLease, validateLeaseNote, validateLeaseOwner, validateLeaseTtlMs } from "./task-lease.ts";
5
+ import type { TaskLeaseStore } from "./task-lease-store.ts";
6
6
 
7
7
  interface TaskLeaseRow {
8
8
  task_id: string;
@@ -1,5 +1,5 @@
1
- import { TASK_LEASE_DEFAULT_TTL_MS } from "../constants.ts";
2
- import { isLeaseExpired, type TaskLease, validateLeaseNote, validateLeaseOwner, validateLeaseTtlMs } from "../task-lease/task-lease.ts";
1
+ import { TASK_LEASE_DEFAULT_TTL_MS } from "../../constants.ts";
2
+ import { isLeaseExpired, type TaskLease, validateLeaseNote, validateLeaseOwner, validateLeaseTtlMs } from "./task-lease.ts";
3
3
 
4
4
  export interface TaskLeaseStore {
5
5
  /**
@@ -1,4 +1,4 @@
1
- import { TASK_LEASE_MAX_TTL_MS, TASK_LEASE_MIN_TTL_MS, TASK_LEASE_NOTE_MAX_LENGTH, TASK_LEASE_OWNER_MAX_LENGTH } from "../constants.ts";
1
+ import { TASK_LEASE_MAX_TTL_MS, TASK_LEASE_MIN_TTL_MS, TASK_LEASE_NOTE_MAX_LENGTH, TASK_LEASE_OWNER_MAX_LENGTH } from "../../constants.ts";
2
2
 
3
3
  /**
4
4
  * A bounded work reservation on a Task, independent of both the Task's own lifecycle status
@@ -1,9 +1,5 @@
1
- import type { Db } from "../db.ts";
2
- import {
3
- TaskMutationPendingError,
4
- type TaskMutationRequestRecord,
5
- type TaskMutationRequestStore,
6
- } from "../task-mutation-request/task-mutation-request-store.ts";
1
+ import type { Db } from "../../db.ts";
2
+ import { TaskMutationPendingError, type TaskMutationRequestRecord, type TaskMutationRequestStore } from "./task-mutation-request-store.ts";
7
3
 
8
4
  interface TaskMutationRequestRow {
9
5
  request_scope: string;
@@ -1,6 +1,6 @@
1
- import type { Db } from "../db.ts";
2
- import { inTransaction } from "../db.ts";
3
- import { SQLiteProjectRegistryStore } from "../project-registry/sqlite-project-registry-store.ts";
1
+ import type { Db } from "../../db.ts";
2
+ import { inTransaction } from "../../db.ts";
3
+ import { SQLiteProjectRegistryStore } from "../../project-registry/sqlite-project-registry-store.ts";
4
4
  import type {
5
5
  RegisterTaskProjectInput,
6
6
  TaskProject,
@@ -8,8 +8,8 @@ import type {
8
8
  TaskScopeSource,
9
9
  TaskViewMode,
10
10
  TaskViewPreference,
11
- } from "../task-scope/task-scope.ts";
12
- import type { TaskScopeStore } from "../task-scope/task-scope-store.ts";
11
+ } from "./task-scope.ts";
12
+ import type { TaskScopeStore } from "./task-scope-store.ts";
13
13
 
14
14
  /** Rewrites every task_scopes/task_views row pinned to a project root that just moved -- called inside the same registerProject() transaction, so a rename/move is atomic with the rewrite. */
15
15
  function rewriteTaskRowsForMovedRoot(db: Db, previousRoot: string, nextRoot: string): void {
@@ -1,5 +1,5 @@
1
- import { InMemoryProjectRegistryStore } from "../project-registry/in-memory-project-registry-store.ts";
2
- import type { ProjectRegistryStore } from "../project-registry/project-registry-store.ts";
1
+ import { InMemoryProjectRegistryStore } from "../../project-registry/in-memory-project-registry-store.ts";
2
+ import type { ProjectRegistryStore } from "../../project-registry/project-registry-store.ts";
3
3
  import type {
4
4
  RegisterTaskProjectInput,
5
5
  TaskProject,
@@ -7,10 +7,24 @@ import type {
7
7
  TaskScopeSource,
8
8
  TaskViewMode,
9
9
  TaskViewPreference,
10
- } from "../task-scope/task-scope.ts";
10
+ } from "./task-scope.ts";
11
11
 
12
- export interface TaskScopeStore {
12
+ /**
13
+ * Role Interface (Fowler: https://martinfowler.com/bliki/RoleInterface.html) for the one
14
+ * collaboration playbook workflow execution actually has with Task's own scope bookkeeping:
15
+ * assigning a task's project scope when a playbook step creates/advances one. Extracted after a
16
+ * SOLID audit found TaskScopeStore's full Header Interface (all 8 methods -- project-catalog
17
+ * registration, view-preference bookkeeping, task-id listing, none of which playbook ever
18
+ * touches) threaded unchanged through handlers/playbooks.ts, modules/playbooks.ts, and
19
+ * playbook/workflow-execution.ts, which only ever calls .assign(). TaskScopeStore still
20
+ * implements this structurally with zero changes to either concrete store; only the
21
+ * playbook-facing field type narrows to this.
22
+ */
23
+ export interface TaskScopeAssigner {
13
24
  assign(taskId: string, projectRoot: string | undefined, source: TaskScopeSource): TaskProjectScope;
25
+ }
26
+
27
+ export interface TaskScopeStore extends TaskScopeAssigner {
14
28
  get(taskId: string): TaskProjectScope | undefined;
15
29
  taskIds(projectRoot: string | undefined, limit: number): string[];
16
30
  view(projectRoot: string): TaskViewPreference;
@@ -1,9 +1,13 @@
1
- import { basename, isAbsolute, normalize } from "node:path";
2
- import { TASK_PROJECT_ROOT_MAX_LENGTH } from "../constants.ts";
3
- import type { Project, RegisterProjectInput } from "../project-registry/project-registry.ts";
1
+ import { basename } from "node:path";
2
+ import type { Project, RegisterProjectInput } from "../../project-registry/project-registry.ts";
3
+ import type { ScopeAssignmentSource } from "../../project-registry/scope-source.ts";
4
+
5
+ export { normalizeProjectRoot } from "../../project-registry/scope-source.ts";
4
6
 
5
7
  export type TaskViewMode = "project" | "graph" | "all";
6
- export type TaskScopeSource = "cwd" | "explicit" | "unscoped";
8
+
9
+ /** Task's own name for the shared, kind-neutral scope-assignment provenance -- see scope-source.ts. Kept as a type alias so every existing Task-scope call site keeps working unchanged. */
10
+ export type TaskScopeSource = ScopeAssignmentSource;
7
11
 
8
12
  export interface TaskProjectScope {
9
13
  taskId: string;
@@ -29,15 +33,6 @@ export interface TaskViewSelection {
29
33
  rootTaskId?: string;
30
34
  }
31
35
 
32
- export function normalizeProjectRoot(value: string): string {
33
- if (!isAbsolute(value)) throw new Error("project_root must be an absolute path");
34
- const normalized = normalize(value);
35
- if (normalized.length > TASK_PROJECT_ROOT_MAX_LENGTH) {
36
- throw new Error(`project_root cannot exceed ${TASK_PROJECT_ROOT_MAX_LENGTH} characters`);
37
- }
38
- return normalized;
39
- }
40
-
41
36
  export function taskScopeLabel(mode: TaskViewMode, projectRoot?: string, rootTitle?: string): string {
42
37
  if (mode === "all") return "All projects";
43
38
  const project = projectRoot ? basename(projectRoot) || projectRoot : "Unscoped";
@@ -1,8 +1,8 @@
1
1
  import type { Artifact, ArtifactEdge } from "../artifact/artifact.ts";
2
2
  import type { ArtifactStore } from "../artifact/artifact-store.ts";
3
3
  import { TASK_EXECUTION_MAX_DEGREE } from "../constants.ts";
4
- import type { AppendTaskEvent, TaskEventContext } from "../task-event/task-event.ts";
5
- import type { TaskEventStore } from "../task-event/task-event-store.ts";
4
+ import type { AppendTaskEvent, TaskEventContext } from "./event/task-event.ts";
5
+ import type { TaskEventStore } from "./event/task-event-store.ts";
6
6
  import { assertDependencyEdgeAllowed, TaskExecutionBoundExceededError } from "./task-execution.ts";
7
7
  // Type-only import: erased entirely at compile time, so this does not create a real runtime
8
8
  // circular dependency even though task-service.ts also imports TaskEdges (a real value) from
@@ -1,9 +1,9 @@
1
1
  import type { Artifact } from "../artifact/artifact.ts";
2
2
  import type { ArtifactStore } from "../artifact/artifact-store.ts";
3
3
  import { TASK_FOCUS_STALE_AFTER_MS } from "../constants.ts";
4
- import { type AppendTaskEvent, type TaskEventContext, validateEventContext } from "../task-event/task-event.ts";
5
- import type { TaskEventStore } from "../task-event/task-event-store.ts";
6
- import type { TaskFocusStatus, TaskFocusStore } from "../task-focus/task-focus-store.ts";
4
+ import { type AppendTaskEvent, type TaskEventContext, validateEventContext } from "./event/task-event.ts";
5
+ import type { TaskEventStore } from "./event/task-event-store.ts";
6
+ import type { TaskFocusStatus, TaskFocusStore } from "./focus/task-focus-store.ts";
7
7
  import { TaskInvalidTransitionError } from "./task-lifecycle-errors.ts";
8
8
  import type { TaskMutationCoordinator, TaskMutationRequestContext } from "./task-mutation-coordinator.ts";
9
9
  // Type-only import: erased entirely at compile time, so this does not create a real runtime
@@ -1,6 +1,6 @@
1
1
  import type { Artifact } from "../artifact/artifact.ts";
2
- import type { TaskLease, TaskLeaseView } from "../task-lease/task-lease.ts";
3
- import type { TaskLeaseStore } from "../task-lease/task-lease-store.ts";
2
+ import type { TaskLease, TaskLeaseView } from "./lease/task-lease.ts";
3
+ import type { TaskLeaseStore } from "./lease/task-lease-store.ts";
4
4
 
5
5
  /**
6
6
  * Task lease management (claim/heartbeat/release/get/reap), split out of the Tasks god class as
@@ -6,7 +6,7 @@ import {
6
6
  TaskMutationPendingError,
7
7
  type TaskMutationRequestRecord,
8
8
  type TaskMutationRequestStore,
9
- } from "../task-mutation-request/task-mutation-request-store.ts";
9
+ } from "./mutation-request/task-mutation-request-store.ts";
10
10
 
11
11
  export class TaskMutationReceiptNotFoundError extends Error {}
12
12
 
@@ -1,8 +1,8 @@
1
1
  import type { Artifact } from "../artifact/artifact.ts";
2
2
  import { TASK_PROJECT_LIST_MAX_RESULTS } from "../constants.ts";
3
3
  import { assertRegisterProjectInputBounds } from "../project-registry/project-registry.ts";
4
- import type { AppendTaskEvent, TaskEventContext } from "../task-event/task-event.ts";
5
- import type { TaskEventStore } from "../task-event/task-event-store.ts";
4
+ import type { AppendTaskEvent, TaskEventContext } from "./event/task-event.ts";
5
+ import type { TaskEventStore } from "./event/task-event-store.ts";
6
6
  import {
7
7
  normalizeProjectRoot,
8
8
  type RegisterTaskProjectInput,
@@ -10,8 +10,8 @@ import {
10
10
  type TaskViewMode,
11
11
  type TaskViewSelection,
12
12
  taskScopeLabel,
13
- } from "../task-scope/task-scope.ts";
14
- import type { TaskScopeStore } from "../task-scope/task-scope-store.ts";
13
+ } from "./scope/task-scope.ts";
14
+ import type { TaskScopeStore } from "./scope/task-scope-store.ts";
15
15
 
16
16
  export class TaskProjectNotFoundError extends Error {}
17
17
  export class TaskProjectAmbiguousError extends Error {}
@@ -18,11 +18,12 @@ import { DISCUSSION_SUBTYPE, isDiscussionArtifact, readDiscussionExtra } from ".
18
18
  import type { TransitionTable } from "../domain-service-shared.ts";
19
19
  import { type Gate, type GateResult, validateGates } from "../gate/gate.ts";
20
20
  import type { GateRunner } from "../gate/gate-runner.ts";
21
+ import { type Checklist, checklistEntries, type ProofReference, validateChecklist } from "./checklist.ts";
21
22
  import {
22
23
  InMemoryTaskCreateRequestStore,
23
24
  TaskCreateIdempotencyConflictError,
24
25
  type TaskCreateRequestStore,
25
- } from "../task-create-request/task-create-request-store.ts";
26
+ } from "./create-request/task-create-request-store.ts";
26
27
  import type {
27
28
  AppendTaskEvent,
28
29
  TaskEventContext,
@@ -31,18 +32,18 @@ import type {
31
32
  TaskHistoryPage,
32
33
  TaskHistoryQuery,
33
34
  TaskLifecycleStatus,
34
- } from "../task-event/task-event.ts";
35
- import { validateEventContext } from "../task-event/task-event.ts";
36
- import { InMemoryTaskEventStore, type TaskEventStore } from "../task-event/task-event-store.ts";
37
- import { InMemoryTaskFocusStore, type TaskFocusStatus, type TaskFocusStore } from "../task-focus/task-focus-store.ts";
38
- import type { TaskLeaseView } from "../task-lease/task-lease.ts";
39
- import { InMemoryTaskLeaseStore, type TaskLeaseStore } from "../task-lease/task-lease-store.ts";
35
+ } from "./event/task-event.ts";
36
+ import { validateEventContext } from "./event/task-event.ts";
37
+ import { InMemoryTaskEventStore, type TaskEventStore } from "./event/task-event-store.ts";
38
+ import { InMemoryTaskFocusStore, type TaskFocusStatus, type TaskFocusStore } from "./focus/task-focus-store.ts";
39
+ import type { TaskLeaseView } from "./lease/task-lease.ts";
40
+ import { InMemoryTaskLeaseStore, type TaskLeaseStore } from "./lease/task-lease-store.ts";
40
41
  import {
41
42
  InMemoryTaskMutationRequestStore,
42
43
  TaskMutationPendingError,
43
44
  type TaskMutationRequestRecord,
44
45
  type TaskMutationRequestStore,
45
- } from "../task-mutation-request/task-mutation-request-store.ts";
46
+ } from "./mutation-request/task-mutation-request-store.ts";
46
47
  import {
47
48
  normalizeProjectRoot,
48
49
  type RegisterTaskProjectInput,
@@ -51,9 +52,8 @@ import {
51
52
  type TaskViewMode,
52
53
  type TaskViewSelection,
53
54
  taskScopeLabel,
54
- } from "../task-scope/task-scope.ts";
55
- import { InMemoryTaskScopeStore, type TaskScopeStore } from "../task-scope/task-scope-store.ts";
56
- import { type Checklist, checklistEntries, type ProofReference, validateChecklist } from "./checklist.ts";
55
+ } from "./scope/task-scope.ts";
56
+ import { InMemoryTaskScopeStore, type TaskScopeStore } from "./scope/task-scope-store.ts";
57
57
  import { TaskEdges } from "./task-edges.ts";
58
58
  import { TaskExecutionBoundExceededError } from "./task-execution.ts";
59
59
  import { type TaskFocus, TaskFocusCoordinator, type TaskFocusMutationResult } from "./task-focus-coordinator.ts";