wicked-crew 0.9.5 → 0.9.7

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 (61) hide show
  1. package/dist/api/delivery-assurance.d.ts.map +1 -1
  2. package/dist/api/delivery-assurance.js +3 -0
  3. package/dist/api/delivery-assurance.js.map +1 -1
  4. package/dist/api/routes.d.ts.map +1 -1
  5. package/dist/api/routes.js +32 -6
  6. package/dist/api/routes.js.map +1 -1
  7. package/dist/api/server.d.ts +6 -0
  8. package/dist/api/server.d.ts.map +1 -1
  9. package/dist/api/server.js +28 -0
  10. package/dist/api/server.js.map +1 -1
  11. package/dist/cli/index.d.ts.map +1 -1
  12. package/dist/cli/index.js +4 -0
  13. package/dist/cli/index.js.map +1 -1
  14. package/dist/core/adapter.d.ts.map +1 -1
  15. package/dist/core/adapter.js +8 -0
  16. package/dist/core/adapter.js.map +1 -1
  17. package/dist/core/council-settings.d.ts +18 -0
  18. package/dist/core/council-settings.d.ts.map +1 -0
  19. package/dist/core/council-settings.js +37 -0
  20. package/dist/core/council-settings.js.map +1 -0
  21. package/dist/learn/routes.d.ts +42 -0
  22. package/dist/learn/routes.d.ts.map +1 -0
  23. package/dist/learn/routes.js +87 -0
  24. package/dist/learn/routes.js.map +1 -0
  25. package/dist/learn/schedule-store.d.ts +41 -0
  26. package/dist/learn/schedule-store.d.ts.map +1 -0
  27. package/dist/learn/schedule-store.js +137 -0
  28. package/dist/learn/schedule-store.js.map +1 -0
  29. package/dist/learn/scheduler.d.ts +78 -0
  30. package/dist/learn/scheduler.d.ts.map +1 -0
  31. package/dist/learn/scheduler.js +236 -0
  32. package/dist/learn/scheduler.js.map +1 -0
  33. package/dist/learn/topics.d.ts +14 -0
  34. package/dist/learn/topics.d.ts.map +1 -0
  35. package/dist/learn/topics.js +95 -0
  36. package/dist/learn/topics.js.map +1 -0
  37. package/dist/projects/graph.d.ts +14 -0
  38. package/dist/projects/graph.d.ts.map +1 -1
  39. package/dist/projects/graph.js +41 -2
  40. package/dist/projects/graph.js.map +1 -1
  41. package/dist/projects/state-home-registry.d.ts.map +1 -1
  42. package/dist/projects/state-home-registry.js +2 -0
  43. package/dist/projects/state-home-registry.js.map +1 -1
  44. package/dist/qe/acceptance.d.ts +15 -2
  45. package/dist/qe/acceptance.d.ts.map +1 -1
  46. package/dist/qe/acceptance.js +43 -3
  47. package/dist/qe/acceptance.js.map +1 -1
  48. package/dist/qe/ledger.d.ts +32 -0
  49. package/dist/qe/ledger.d.ts.map +1 -1
  50. package/dist/qe/ledger.js +83 -1
  51. package/dist/qe/ledger.js.map +1 -1
  52. package/dist/studio/assets/index-CMfhDU4t.js +597 -0
  53. package/dist/studio/assets/index-JuaiK28Q.css +32 -0
  54. package/dist/studio/editors/wicked-page/editor.json +1 -1
  55. package/dist/studio/editors/wicked-page/index.html +1 -1
  56. package/dist/studio/index.html +2 -2
  57. package/dist/studio/testid-inventory.json +1078 -213
  58. package/endpoint-manifest.json +55 -1
  59. package/package.json +3 -3
  60. package/dist/studio/assets/index-BGfFmWw4.css +0 -32
  61. package/dist/studio/assets/index-U8MkVhYB.js +0 -567
@@ -0,0 +1,87 @@
1
+ /**
2
+ * `/api/v1/learn/schedules` (DES-learn-workflow §5.2): read, save, delete and run-now a learned
3
+ * topic's refresh schedule. Writes are a person's (the watch routes' human-operator predicate): a
4
+ * worker or system actor may read but never schedule spend.
5
+ */
6
+ import { z } from 'zod';
7
+ import { API_PREFIX } from '../api/api-prefix.js';
8
+ import { LOCAL_ACTOR } from '../api/auth.js';
9
+ import { isHumanOperator } from '../api/watch-routes.js';
10
+ import { readTopics } from './topics.js';
11
+ import { LEARN_SLUG, MAX_EVERY_HOURS, MIN_EVERY_HOURS, scheduleId } from './schedule-store.js';
12
+ const V = API_PREFIX;
13
+ export const LearnSchedulePutSchema = z
14
+ .object({
15
+ repoRef: z.string().min(1).max(256),
16
+ slug: z.string().regex(LEARN_SLUG, 'slug is kebab-case, at most 64 characters'),
17
+ topic: z.string().trim().min(1).max(200),
18
+ everyHours: z.number().int().min(MIN_EVERY_HOURS).max(MAX_EVERY_HOURS),
19
+ enabled: z.boolean().optional(),
20
+ projectId: z.string().min(1).max(128).optional(),
21
+ })
22
+ .strict();
23
+ function bad(reply, error) {
24
+ return reply.code(400).send({ error });
25
+ }
26
+ export function registerLearnRoutes(app, deps) {
27
+ const actorOf = (req) => req.actor ?? LOCAL_ACTOR;
28
+ const now = () => deps.now?.() ?? new Date();
29
+ const refuse = (reply) => reply.code(403).send({ error: 'Only a person can change a learn schedule (a worker or system actor cannot)' });
30
+ app.get(`${V}/learn/schedules`, { config: { manifest: { responseType: 'LearnSchedulesResponse', statusCodes: [200] } } }, async () => ({ schedules: deps.store.list() }));
31
+ // The learned topics of one registered repository, read from its checkout. A topic on a schedule
32
+ // goes stale after two of its intervals without re-verification; an unscheduled one after 60 days.
33
+ app.get(`${V}/learn/topics`, { config: { manifest: { responseType: 'LearnTopicsResponse', statusCodes: [200, 400, 404] } } }, async (req, reply) => {
34
+ const { repoRef } = req.query;
35
+ if (typeof repoRef !== 'string' || repoRef === '')
36
+ return bad(reply, 'repoRef is required');
37
+ const repo = (await deps.adapter.listRepos()).find((r) => r.id === repoRef);
38
+ if (repo === undefined)
39
+ return reply.code(404).send({ error: `no registered repository ${repoRef}` });
40
+ const schedules = deps.store.list().filter((s) => s.repoRef === repoRef);
41
+ const staleDays = (slug) => {
42
+ const s = schedules.find((x) => x.slug === slug);
43
+ return s !== undefined ? (2 * s.everyHours) / 24 : (deps.defaultStaleDays ?? 60);
44
+ };
45
+ return { repoRef, topics: await readTopics(repo.root_path, staleDays, now()) };
46
+ });
47
+ app.put(`${V}/learn/schedules/:id`, { config: { manifest: { requestType: 'LearnSchedulePutBody', responseType: 'LearnSchedule', statusCodes: [200, 400, 403, 404] } } }, async (req, reply) => {
48
+ const actor = actorOf(req);
49
+ if (!isHumanOperator(actor))
50
+ return refuse(reply);
51
+ const parsed = LearnSchedulePutSchema.safeParse(req.body);
52
+ if (!parsed.success)
53
+ return bad(reply, parsed.error.issues.map((i) => `${i.path.join('.') || 'body'}: ${i.message}`).join('; '));
54
+ const { id } = req.params;
55
+ const body = parsed.data;
56
+ if (id !== scheduleId(body.repoRef, body.slug))
57
+ return bad(reply, 'the id must be <repoRef>:<slug>');
58
+ if (!(await deps.adapter.listRepos()).some((r) => r.id === body.repoRef)) {
59
+ return reply.code(404).send({ error: `no registered repository ${body.repoRef}` });
60
+ }
61
+ const row = deps.store.put(body, now());
62
+ deps.audit.record('learn.schedule.saved', actor, { detail: { id, everyHours: row.everyHours, enabled: row.enabled } });
63
+ return row;
64
+ });
65
+ app.delete(`${V}/learn/schedules/:id`, { config: { manifest: { responseType: '{ deleted: true; id: string }', statusCodes: [200, 403, 404] } } }, async (req, reply) => {
66
+ const actor = actorOf(req);
67
+ if (!isHumanOperator(actor))
68
+ return refuse(reply);
69
+ const { id } = req.params;
70
+ if (!deps.store.delete(id))
71
+ return reply.code(404).send({ error: `no learn schedule ${id}` });
72
+ deps.audit.record('learn.schedule.deleted', actor, { detail: { id } });
73
+ return { deleted: true, id };
74
+ });
75
+ app.post(`${V}/learn/schedules/:id/run-now`, { config: { manifest: { responseType: 'LearnSchedule', statusCodes: [200, 403, 404] } } }, async (req, reply) => {
76
+ const actor = actorOf(req);
77
+ if (!isHumanOperator(actor))
78
+ return refuse(reply);
79
+ const { id } = req.params;
80
+ const row = deps.store.update(id, { nextDueAt: now().toISOString() }, now());
81
+ if (row === undefined)
82
+ return reply.code(404).send({ error: `no learn schedule ${id}` });
83
+ deps.audit.record('learn.schedule.run_now', actor, { detail: { id } });
84
+ return row;
85
+ });
86
+ }
87
+ //# sourceMappingURL=routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/learn/routes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * The learn schedule (DES-learn-workflow §5): a durable record per learned topic saying how often
3
+ * the daemon re-runs the `learn` workflow on it. Crew is the single source of truth for a
4
+ * schedule; the topic's files in the repository do not repeat it.
5
+ *
6
+ * Same storage posture as `projects/settings.ts`: a small JSON map in the daemon's state home
7
+ * (`learn-schedules.json`, following `--db`; `WICKED_CREW_LEARN_SCHEDULES` overrides), written
8
+ * atomically (tmp + rename), read tolerantly per row (a malformed row is dropped, never the map).
9
+ */
10
+ import type { LearnSchedule, LearnScheduleOutcome } from 'wicked-crew-api-types';
11
+ export type { LearnSchedule, LearnScheduleOutcome };
12
+ export declare const LEARN_SLUG: RegExp;
13
+ export declare const MIN_EVERY_HOURS = 24;
14
+ export declare const MAX_EVERY_HOURS = 2160;
15
+ export declare function scheduleId(repoRef: string, slug: string): string;
16
+ export declare function defaultSchedulesPath(env?: NodeJS.ProcessEnv): string;
17
+ /** What a caller asks to save (`PUT /learn/schedules/:id`). */
18
+ export interface LearnScheduleInput {
19
+ repoRef: string;
20
+ slug: string;
21
+ topic: string;
22
+ everyHours: number;
23
+ enabled?: boolean | undefined;
24
+ projectId?: string | undefined;
25
+ }
26
+ export declare class LearnScheduleStore {
27
+ private readonly path;
28
+ private readonly rows;
29
+ constructor(path?: string);
30
+ list(): LearnSchedule[];
31
+ get(id: string): LearnSchedule | undefined;
32
+ /** Create or update. A new row is first due one interval from now; an update keeps its run
33
+ * history and moves `nextDueAt` only when the interval changed. */
34
+ put(input: LearnScheduleInput, now: Date): LearnSchedule;
35
+ /** Merge a patch into an existing row (the scheduler's bookkeeping). `undefined` when unknown. */
36
+ update(id: string, patch: Partial<Omit<LearnSchedule, 'id' | 'repoRef' | 'slug'>>, now: Date): LearnSchedule | undefined;
37
+ delete(id: string): boolean;
38
+ private persist;
39
+ }
40
+ export declare const HOURS = 3600000;
41
+ //# sourceMappingURL=schedule-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schedule-store.d.ts","sourceRoot":"","sources":["../../src/learn/schedule-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAGjF,YAAY,EAAE,aAAa,EAAE,oBAAoB,EAAE,CAAC;AAEpD,eAAO,MAAM,UAAU,QAA2C,CAAC;AACnE,eAAO,MAAM,eAAe,KAAK,CAAC;AAClC,eAAO,MAAM,eAAe,OAAO,CAAC;AAIpC,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED,wBAAgB,oBAAoB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAEjF;AAmCD,+DAA+D;AAC/D,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AAED,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAoC;gBAE7C,IAAI,CAAC,EAAE,MAAM;IAazB,IAAI,IAAI,aAAa,EAAE;IAIvB,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAK1C;wEACoE;IACpE,GAAG,CAAC,KAAK,EAAE,kBAAkB,EAAE,GAAG,EAAE,IAAI,GAAG,aAAa;IA4BxD,kGAAkG;IAClG,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,GAAG,SAAS,GAAG,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,GAAG,aAAa,GAAG,SAAS;IASxH,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAM3B,OAAO,CAAC,OAAO;CAMhB;AAED,eAAO,MAAM,KAAK,UAAU,CAAC"}
@@ -0,0 +1,137 @@
1
+ /**
2
+ * The learn schedule (DES-learn-workflow §5): a durable record per learned topic saying how often
3
+ * the daemon re-runs the `learn` workflow on it. Crew is the single source of truth for a
4
+ * schedule; the topic's files in the repository do not repeat it.
5
+ *
6
+ * Same storage posture as `projects/settings.ts`: a small JSON map in the daemon's state home
7
+ * (`learn-schedules.json`, following `--db`; `WICKED_CREW_LEARN_SCHEDULES` overrides), written
8
+ * atomically (tmp + rename), read tolerantly per row (a malformed row is dropped, never the map).
9
+ */
10
+ import { mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
11
+ import { dirname, join } from 'node:path';
12
+ import { crewStateHome } from '../projects/state-home.js';
13
+ export const LEARN_SLUG = /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/;
14
+ export const MIN_EVERY_HOURS = 24;
15
+ export const MAX_EVERY_HOURS = 2160;
16
+ const HOUR_MS = 3_600_000;
17
+ const OUTCOMES = new Set(['launched', 'refused', 'completed', 'failed', 'cancelled']);
18
+ export function scheduleId(repoRef, slug) {
19
+ return `${repoRef}:${slug}`;
20
+ }
21
+ export function defaultSchedulesPath(env = process.env) {
22
+ return env['WICKED_CREW_LEARN_SCHEDULES'] ?? join(crewStateHome(), 'learn-schedules.json');
23
+ }
24
+ const str = (v) => typeof v === 'string';
25
+ const strOrNull = (v) => v === null || typeof v === 'string';
26
+ /** A row as read from disk, or `null` when it is malformed. */
27
+ function parseRow(id, raw) {
28
+ if (typeof raw !== 'object' || raw === null)
29
+ return null;
30
+ const r = raw;
31
+ if (!str(r['repoRef']) || !str(r['slug']) || !LEARN_SLUG.test(r['slug']) || !str(r['topic']))
32
+ return null;
33
+ if (id !== scheduleId(r['repoRef'], r['slug']))
34
+ return null;
35
+ const every = r['everyHours'];
36
+ if (typeof every !== 'number' || !Number.isInteger(every) || every < MIN_EVERY_HOURS || every > MAX_EVERY_HOURS)
37
+ return null;
38
+ if (typeof r['enabled'] !== 'boolean' || !str(r['nextDueAt']) || Number.isNaN(Date.parse(r['nextDueAt'])))
39
+ return null;
40
+ const outcome = r['lastOutcome'];
41
+ return {
42
+ id,
43
+ repoRef: r['repoRef'],
44
+ slug: r['slug'],
45
+ topic: r['topic'],
46
+ ...(str(r['projectId']) ? { projectId: r['projectId'] } : {}),
47
+ everyHours: every,
48
+ enabled: r['enabled'],
49
+ nextDueAt: r['nextDueAt'],
50
+ lastRunId: strOrNull(r['lastRunId']) ? r['lastRunId'] : null,
51
+ lastRunAt: strOrNull(r['lastRunAt']) ? r['lastRunAt'] : null,
52
+ lastOutcome: str(outcome) && OUTCOMES.has(outcome) ? outcome : null,
53
+ failures: typeof r['failures'] === 'number' && r['failures'] >= 0 ? Math.floor(r['failures']) : 0,
54
+ lastError: strOrNull(r['lastError']) ? r['lastError'] : null,
55
+ indexedTree: strOrNull(r['indexedTree']) ? r['indexedTree'] : null,
56
+ createdAt: str(r['createdAt']) ? r['createdAt'] : r['nextDueAt'],
57
+ updatedAt: str(r['updatedAt']) ? r['updatedAt'] : r['nextDueAt'],
58
+ };
59
+ }
60
+ export class LearnScheduleStore {
61
+ path;
62
+ rows = new Map();
63
+ constructor(path) {
64
+ this.path = path ?? defaultSchedulesPath();
65
+ try {
66
+ const parsed = JSON.parse(readFileSync(this.path, 'utf8'));
67
+ for (const [id, raw] of Object.entries(parsed?.schedules ?? {})) {
68
+ const row = parseRow(id, raw);
69
+ if (row !== null)
70
+ this.rows.set(id, row);
71
+ }
72
+ }
73
+ catch {
74
+ // Missing or malformed: start empty (no schedule fires), never fail the boot.
75
+ }
76
+ }
77
+ list() {
78
+ return [...this.rows.values()].sort((a, b) => a.nextDueAt.localeCompare(b.nextDueAt) || a.id.localeCompare(b.id));
79
+ }
80
+ get(id) {
81
+ const row = this.rows.get(id);
82
+ return row === undefined ? undefined : { ...row };
83
+ }
84
+ /** Create or update. A new row is first due one interval from now; an update keeps its run
85
+ * history and moves `nextDueAt` only when the interval changed. */
86
+ put(input, now) {
87
+ const id = scheduleId(input.repoRef, input.slug);
88
+ const prev = this.rows.get(id);
89
+ const iso = now.toISOString();
90
+ const due = new Date(now.getTime() + input.everyHours * HOUR_MS).toISOString();
91
+ const row = {
92
+ id,
93
+ repoRef: input.repoRef,
94
+ slug: input.slug,
95
+ topic: input.topic,
96
+ ...(input.projectId !== undefined ? { projectId: input.projectId } : {}),
97
+ everyHours: input.everyHours,
98
+ enabled: input.enabled ?? prev?.enabled ?? true,
99
+ nextDueAt: prev === undefined || prev.everyHours !== input.everyHours ? due : prev.nextDueAt,
100
+ lastRunId: prev?.lastRunId ?? null,
101
+ lastRunAt: prev?.lastRunAt ?? null,
102
+ lastOutcome: prev?.lastOutcome ?? null,
103
+ failures: prev?.failures ?? 0,
104
+ lastError: prev?.lastError ?? null,
105
+ indexedTree: prev?.indexedTree ?? null,
106
+ createdAt: prev?.createdAt ?? iso,
107
+ updatedAt: iso,
108
+ };
109
+ this.rows.set(id, row);
110
+ this.persist();
111
+ return { ...row };
112
+ }
113
+ /** Merge a patch into an existing row (the scheduler's bookkeeping). `undefined` when unknown. */
114
+ update(id, patch, now) {
115
+ const prev = this.rows.get(id);
116
+ if (prev === undefined)
117
+ return undefined;
118
+ const row = { ...prev, ...patch, updatedAt: now.toISOString() };
119
+ this.rows.set(id, row);
120
+ this.persist();
121
+ return { ...row };
122
+ }
123
+ delete(id) {
124
+ const had = this.rows.delete(id);
125
+ if (had)
126
+ this.persist();
127
+ return had;
128
+ }
129
+ persist() {
130
+ mkdirSync(dirname(this.path), { recursive: true });
131
+ const tmp = `${this.path}.tmp-${process.pid}`;
132
+ writeFileSync(tmp, JSON.stringify({ schedules: Object.fromEntries(this.rows) }, null, 2), 'utf8');
133
+ renameSync(tmp, this.path);
134
+ }
135
+ }
136
+ export const HOURS = HOUR_MS;
137
+ //# sourceMappingURL=schedule-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schedule-store.js","sourceRoot":"","sources":["../../src/learn/schedule-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * The learn schedule's tick (DES-learn-workflow §5.3). Once a minute:
3
+ *
4
+ * 1. RECONCILE — a schedule's last run that reached a terminal status records its outcome.
5
+ * 2. INDEX — a topic whose MERGED knowledge changed (`git fetch origin <default>`, then
6
+ * `git rev-parse origin/<default>:.wicked/knowledge/<slug>`; the checkout's working copy is never read)
7
+ * moved) is re-indexed into the estate knowledge store by garden's `scripts/learn/index.py`,
8
+ * spawned OUTSIDE any run (its env carries no run markers, so the estate opens writable), one
9
+ * spawn per sweep. Indexing reads the registered checkout, never an open pull request.
10
+ * 3. LAUNCH — at most ONE due schedule launches the `learn` workflow, and only while no schedule's
11
+ * run is still open and no run on the daemon is executing (one governed run at a time). The
12
+ * launch delivers a pull request behind the engine's human deliver gate; nothing auto-merges.
13
+ * A refused launch backs off exponentially (capped at a day); missed intervals coalesce.
14
+ *
15
+ * Never throws; a slow sweep never stacks (`sweeping`).
16
+ */
17
+ import type { CoreAdapter } from '../core/adapter.js';
18
+ import type { Actor, CoreEvent } from '../core/types.js';
19
+ import type { AuditLog } from '../api/audit.js';
20
+ import { type RunTimingIndex } from '../api/run-timing-index.js';
21
+ import { type LearnSchedule, type LearnScheduleStore } from './schedule-store.js';
22
+ export declare const LEARN_WORKFLOW = "learn";
23
+ export declare const LEARN_SCHEDULE_ACTOR: Actor;
24
+ export declare const DEFAULT_LEARN_SWEEP_MS = 60000;
25
+ /** How long a launched run the daemon no longer lists keeps the schedule's slot (48 h). */
26
+ export declare const STALE_LAUNCH_MS: number;
27
+ /** The env a governed unit carries; the index spawn drops every one so estate opens writable. */
28
+ export declare const RUN_MARKER_ENV: string[];
29
+ export interface ExecResult {
30
+ code: number;
31
+ stdout: string;
32
+ stderr: string;
33
+ }
34
+ export type Exec = (cmd: string, args: string[], opts: {
35
+ cwd?: string;
36
+ env?: NodeJS.ProcessEnv;
37
+ timeoutMs: number;
38
+ }) => Promise<ExecResult>;
39
+ export declare const defaultExec: Exec;
40
+ export interface LearnSchedulerDeps {
41
+ store: LearnScheduleStore;
42
+ adapter: Pick<CoreAdapter, 'listRepos' | 'sessionsDetail' | 'seatsForWorkflow' | 'launchRun'>;
43
+ audit: AuditLog;
44
+ runTimingIndex: RunTimingIndex;
45
+ fileRun: (runId: string, projectId: string) => void;
46
+ broadcast: (frame: CoreEvent) => void;
47
+ log: (msg: string) => void;
48
+ now?: () => Date;
49
+ exec?: Exec;
50
+ env?: NodeJS.ProcessEnv;
51
+ /** The live garden plugin root (tests inject it); default: the skills runtime's discovery. */
52
+ gardenRoot?: () => string | null;
53
+ }
54
+ /** The garden root the indexer runs from: `$WICKED_GARDEN_ROOT`, else the live plugin the daemon's
55
+ * skills runtime publishes from (E2E F-LEARN-5: an inherited `CLAUDE_PLUGIN_ROOT` pointing at an
56
+ * older checkout must never pick the script), else null (`wicked-garden` on PATH). */
57
+ export declare function gardenRootFor(env: NodeJS.ProcessEnv, live?: () => string | null): string | null;
58
+ /** The garden launcher under a root (`<root>/scripts/wicked-garden`), else `wicked-garden` on PATH. */
59
+ export declare function gardenLauncher(root: string | null): string;
60
+ /** `env` without the governed-run markers, pinned to the garden root it resolved (and no inherited
61
+ * `CLAUDE_PLUGIN_ROOT`, which the launcher would otherwise prefer). */
62
+ export declare function unmarkedEnv(env: NodeJS.ProcessEnv, root?: string | null): NodeJS.ProcessEnv;
63
+ export declare function refreshProblem(row: LearnSchedule): string;
64
+ export declare class LearnScheduler {
65
+ private readonly deps;
66
+ private timer;
67
+ private sweeping;
68
+ constructor(deps: LearnSchedulerDeps);
69
+ start(intervalMs?: number): void;
70
+ stop(): void;
71
+ private now;
72
+ /** One sweep. Never throws. */
73
+ sweep(): Promise<void>;
74
+ private reconcile;
75
+ private indexOne;
76
+ private launchOne;
77
+ }
78
+ //# sourceMappingURL=scheduler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../src/learn/scheduler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,236 @@
1
+ /**
2
+ * The learn schedule's tick (DES-learn-workflow §5.3). Once a minute:
3
+ *
4
+ * 1. RECONCILE — a schedule's last run that reached a terminal status records its outcome.
5
+ * 2. INDEX — a topic whose MERGED knowledge changed (`git fetch origin <default>`, then
6
+ * `git rev-parse origin/<default>:.wicked/knowledge/<slug>`; the checkout's working copy is never read)
7
+ * moved) is re-indexed into the estate knowledge store by garden's `scripts/learn/index.py`,
8
+ * spawned OUTSIDE any run (its env carries no run markers, so the estate opens writable), one
9
+ * spawn per sweep. Indexing reads the registered checkout, never an open pull request.
10
+ * 3. LAUNCH — at most ONE due schedule launches the `learn` workflow, and only while no schedule's
11
+ * run is still open and no run on the daemon is executing (one governed run at a time). The
12
+ * launch delivers a pull request behind the engine's human deliver gate; nothing auto-merges.
13
+ * A refused launch backs off exponentially (capped at a day); missed intervals coalesce.
14
+ *
15
+ * Never throws; a slow sweep never stacks (`sweeping`).
16
+ */
17
+ import { execFile } from 'node:child_process';
18
+ import { randomUUID } from 'node:crypto';
19
+ import { childEnvWithBootEstateDb } from '../core/governance-store.js';
20
+ import { gardenPluginRoot } from '../interactive/draft-skill.js';
21
+ import { recordRunLaunched } from '../api/run-timing-index.js';
22
+ import { HOURS } from './schedule-store.js';
23
+ export const LEARN_WORKFLOW = 'learn';
24
+ export const LEARN_SCHEDULE_ACTOR = { id: 'learn-schedule', kind: 'system', trust: 'operator' };
25
+ export const DEFAULT_LEARN_SWEEP_MS = 60_000;
26
+ /** How long a launched run the daemon no longer lists keeps the schedule's slot (48 h). */
27
+ export const STALE_LAUNCH_MS = 48 * HOURS;
28
+ /** A run that holds the host: one governed run at a time (a run parked on a human is not busy). */
29
+ const BUSY = new Set(['planning', 'distributing', 'executing']);
30
+ const TERMINAL = new Set(['completed', 'failed', 'cancelled']);
31
+ /** The env a governed unit carries; the index spawn drops every one so estate opens writable. */
32
+ export const RUN_MARKER_ENV = ['WICKED_RUN_ID', 'WICKED_GATE_SCOPE', 'WICKED_WRITE_ROOTS', 'WICKED_GOVERNED', 'WICKED_ESTATE_READONLY'];
33
+ export const defaultExec = (cmd, args, opts) => new Promise((resolve) => {
34
+ // crew#495: a child never inherits a daemon-exported governance store.
35
+ execFile(cmd, args, { cwd: opts.cwd, env: childEnvWithBootEstateDb(opts.env ?? process.env), timeout: opts.timeoutMs, maxBuffer: 4 * 1024 * 1024 }, (err, stdout, stderr) => {
36
+ const code = err === null ? 0 : typeof err.code === 'number' ? (err.code) : 1;
37
+ resolve({ code, stdout: String(stdout), stderr: String(stderr) });
38
+ });
39
+ });
40
+ /** The garden root the indexer runs from: `$WICKED_GARDEN_ROOT`, else the live plugin the daemon's
41
+ * skills runtime publishes from (E2E F-LEARN-5: an inherited `CLAUDE_PLUGIN_ROOT` pointing at an
42
+ * older checkout must never pick the script), else null (`wicked-garden` on PATH). */
43
+ export function gardenRootFor(env, live = gardenPluginRoot) {
44
+ const root = env['WICKED_GARDEN_ROOT'];
45
+ if (root !== undefined && root !== '')
46
+ return root.replace(/\/+$/, '');
47
+ return live();
48
+ }
49
+ /** The garden launcher under a root (`<root>/scripts/wicked-garden`), else `wicked-garden` on PATH. */
50
+ export function gardenLauncher(root) {
51
+ return root !== null ? `${root}/scripts/wicked-garden` : 'wicked-garden';
52
+ }
53
+ /** `env` without the governed-run markers, pinned to the garden root it resolved (and no inherited
54
+ * `CLAUDE_PLUGIN_ROOT`, which the launcher would otherwise prefer). */
55
+ export function unmarkedEnv(env, root = null) {
56
+ const out = { ...env };
57
+ for (const k of RUN_MARKER_ENV)
58
+ delete out[k];
59
+ delete out['CLAUDE_PLUGIN_ROOT'];
60
+ if (root !== null)
61
+ out['WICKED_GARDEN_ROOT'] = root;
62
+ return out;
63
+ }
64
+ export function refreshProblem(row) {
65
+ return (`Refresh learn topic "${row.topic}" (.wicked/knowledge/${row.slug}/): re-research what changed since the ` +
66
+ `topic's refreshed_at and propose only changes (confirm, supersede, contradict, retire) per the ` +
67
+ `wicked-garden-learn skill's refresh rules.`);
68
+ }
69
+ export class LearnScheduler {
70
+ deps;
71
+ timer = null;
72
+ sweeping = false;
73
+ constructor(deps) {
74
+ this.deps = deps;
75
+ }
76
+ start(intervalMs = DEFAULT_LEARN_SWEEP_MS) {
77
+ if (this.timer !== null)
78
+ return;
79
+ this.timer = setInterval(() => void this.sweep(), intervalMs);
80
+ this.timer.unref?.();
81
+ }
82
+ stop() {
83
+ if (this.timer !== null)
84
+ clearInterval(this.timer);
85
+ this.timer = null;
86
+ }
87
+ now() {
88
+ return this.deps.now?.() ?? new Date();
89
+ }
90
+ /** One sweep. Never throws. */
91
+ async sweep() {
92
+ if (this.sweeping)
93
+ return;
94
+ this.sweeping = true;
95
+ try {
96
+ const rows = this.deps.store.list();
97
+ if (rows.length === 0)
98
+ return;
99
+ const views = await this.deps.adapter.sessionsDetail();
100
+ const status = new Map(views.map((v) => [v.session.id, v.session.status]));
101
+ this.reconcile(rows, status);
102
+ await this.indexOne(this.deps.store.list());
103
+ await this.launchOne(this.deps.store.list(), status);
104
+ }
105
+ catch (err) {
106
+ this.deps.log(`[learn-schedule] sweep failed: ${err instanceof Error ? err.message : String(err)}`);
107
+ }
108
+ finally {
109
+ this.sweeping = false;
110
+ }
111
+ }
112
+ reconcile(rows, status) {
113
+ for (const row of rows) {
114
+ if (row.lastRunId === null || row.lastOutcome !== 'launched')
115
+ continue;
116
+ const s = status.get(row.lastRunId);
117
+ if (s !== undefined && TERMINAL.has(s)) {
118
+ this.deps.store.update(row.id, { lastOutcome: s }, this.now());
119
+ }
120
+ }
121
+ }
122
+ async indexOne(rows) {
123
+ const exec = this.deps.exec ?? defaultExec;
124
+ const env = this.deps.env ?? process.env;
125
+ const repos = await this.deps.adapter.listRepos();
126
+ for (const row of rows) {
127
+ if (!row.enabled)
128
+ continue;
129
+ const repo = repos.find((r) => r.id === row.repoRef);
130
+ if (repo === undefined || !repo.root_path)
131
+ continue;
132
+ // What MERGED: the remote default branch, fetched (a run's pull request merges there; the
133
+ // registered checkout itself is never pulled or modified, only its remote-tracking ref moves).
134
+ const branch = repo.default_branch || 'main';
135
+ const ref = `origin/${branch}`;
136
+ const fetched = await exec('git', ['-C', repo.root_path, 'fetch', '--quiet', 'origin', `${branch}:refs/remotes/origin/${branch}`], { timeoutMs: 30_000 });
137
+ // A failed fetch keeps the last fetched origin/<default> (codex r1): never the checkout's HEAD,
138
+ // which may be an unmerged branch. No remote-tracking ref at all: nothing merged to index.
139
+ if (fetched.code !== 0)
140
+ this.deps.log(`[learn-schedule] fetch of ${ref} for ${row.id} failed; using the last fetched ${ref}`);
141
+ const tree = await exec('git', ['-C', repo.root_path, 'rev-parse', `${ref}:.wicked/knowledge/${row.slug}`], { timeoutMs: 5_000 });
142
+ const sha = tree.code === 0 ? tree.stdout.trim() : '';
143
+ if (sha === '' || sha === row.indexedTree)
144
+ continue;
145
+ const root = gardenRootFor(env, this.deps.gardenRoot);
146
+ const res = await exec(gardenLauncher(root), ['run', 'scripts/learn/index.py', '--repo', repo.root_path, '--ref', ref, '--name', repo.name, '--slug', row.slug], { cwd: repo.root_path, env: unmarkedEnv(env, root), timeoutMs: 120_000 });
147
+ if (res.code === 0) {
148
+ this.deps.store.update(row.id, { indexedTree: sha }, this.now());
149
+ this.deps.log(`[learn-schedule] indexed ${row.id} at tree ${sha.slice(0, 12)}`);
150
+ }
151
+ else {
152
+ this.deps.log(`[learn-schedule] index of ${row.id} failed (exit ${res.code}): ${(res.stderr || res.stdout).slice(0, 300)}`);
153
+ }
154
+ return; // one index spawn per sweep
155
+ }
156
+ }
157
+ async launchOne(rows, status) {
158
+ const now = this.now();
159
+ // A launched run the list does not show (yet) counts as OPEN — never launch a second refresh
160
+ // on a guess — unless it was launched over STALE_LAUNCH_MS ago (archived or lost: stop waiting).
161
+ const open = rows.some((r) => {
162
+ if (r.lastRunId === null || r.lastOutcome !== 'launched')
163
+ return false;
164
+ const s = status.get(r.lastRunId);
165
+ if (s !== undefined)
166
+ return !TERMINAL.has(s);
167
+ return r.lastRunAt !== null && now.getTime() - Date.parse(r.lastRunAt) < STALE_LAUNCH_MS;
168
+ });
169
+ if (open)
170
+ return;
171
+ if ([...status.values()].some((s) => BUSY.has(s)))
172
+ return;
173
+ const due = rows
174
+ .filter((r) => r.enabled && Date.parse(r.nextDueAt) <= now.getTime())
175
+ .sort((a, b) => a.nextDueAt.localeCompare(b.nextDueAt))[0];
176
+ if (due === undefined)
177
+ return;
178
+ let runId;
179
+ try {
180
+ const clisJson = JSON.stringify(await this.deps.adapter.seatsForWorkflow(LEARN_WORKFLOW));
181
+ // Re-read right before the launch (codex r1): the index spawn and the seat read above can take
182
+ // minutes, and another surface may have started a run meanwhile.
183
+ const fresh = await this.deps.adapter.sessionsDetail();
184
+ if (fresh.some((v) => BUSY.has(v.session.status)))
185
+ return;
186
+ runId = await this.deps.adapter.launchRun({
187
+ problem: refreshProblem(due),
188
+ sessionId: randomUUID(),
189
+ clisJson,
190
+ workflow: LEARN_WORKFLOW,
191
+ repoRef: due.repoRef,
192
+ deliver: 'pr',
193
+ ...(due.projectId !== undefined ? { projectId: due.projectId } : {}),
194
+ });
195
+ }
196
+ catch (err) {
197
+ const failures = due.failures + 1;
198
+ const message = err instanceof Error ? err.message : String(err);
199
+ this.deps.store.update(due.id, {
200
+ failures,
201
+ lastOutcome: 'refused',
202
+ lastError: message.slice(0, 500),
203
+ nextDueAt: new Date(now.getTime() + Math.min(2 ** failures, 24) * HOURS).toISOString(),
204
+ }, now);
205
+ this.deps.log(`[learn-schedule] ${due.id} launch refused (${failures}): ${message}`);
206
+ return;
207
+ }
208
+ // The launch happened: record it FIRST, so a failure in the bookkeeping below can never
209
+ // misreport it as refused or free the slot for a second refresh (codex r1).
210
+ this.deps.store.update(due.id, {
211
+ lastRunId: runId,
212
+ lastRunAt: now.toISOString(),
213
+ lastOutcome: 'launched',
214
+ failures: 0,
215
+ lastError: null,
216
+ nextDueAt: new Date(now.getTime() + due.everyHours * HOURS).toISOString(),
217
+ }, now);
218
+ try {
219
+ recordRunLaunched(this.deps.audit, this.deps.runTimingIndex, LEARN_SCHEDULE_ACTOR, runId, {
220
+ workflow: LEARN_WORKFLOW,
221
+ repoRef: due.repoRef,
222
+ deliver: 'pr',
223
+ learnSchedule: due.id,
224
+ ...(due.projectId !== undefined ? { projectId: due.projectId } : {}),
225
+ });
226
+ if (due.projectId !== undefined)
227
+ this.deps.fileRun(runId, due.projectId);
228
+ this.deps.broadcast({ type: 'learnRefreshLaunched', session: runId, schedule: due.id });
229
+ }
230
+ catch (err) {
231
+ this.deps.log(`[learn-schedule] ${due.id} launched ${runId}, but its bookkeeping failed: ${err instanceof Error ? err.message : String(err)}`);
232
+ }
233
+ this.deps.log(`[learn-schedule] ${due.id} due → learn ${runId}`);
234
+ }
235
+ }
236
+ //# sourceMappingURL=scheduler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../../src/learn/scheduler.ts"],"names":[],"mappings":"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"}