dawlad-paperclip-direction 0.3.0 → 0.3.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.
package/dist/manifest.js CHANGED
@@ -11,7 +11,7 @@ var route = (routeKey, method, path) => ({
11
11
  var manifest = {
12
12
  id: "dawlad.direction",
13
13
  apiVersion: 1,
14
- version: "0.3.0",
14
+ version: "0.3.1",
15
15
  displayName: "Direction",
16
16
  description: "Horizon, campaigns, milestones and one queue of decisions: where Dawlad is heading and what's in the way.",
17
17
  author: "Aly Solamon",
@@ -50,12 +50,15 @@ var manifest = {
50
50
  route("milestone", "POST", "/milestone"),
51
51
  route("campaign", "POST", "/campaign"),
52
52
  route("horizon", "POST", "/horizon"),
53
+ route("team", "POST", "/team"),
53
54
  route("baseline", "POST", "/baseline"),
54
55
  route("scenario", "POST", "/scenario")
55
56
  ],
56
57
  tools: [
57
58
  { name: "direction_read", displayName: "Read Direction", description: "Horizon, campaigns and milestones with health, forecast, slack and critical path.", parametersSchema: { type: "object", properties: {} } },
58
59
  { name: "direction_set_milestone", displayName: "Set a milestone", description: "Make a parent task a milestone or change its due date, duration, campaign, key-date flag or blockers.", parametersSchema: { type: "object", properties: { issueId: { type: "string" } }, required: ["issueId"] } },
60
+ { name: "direction_set_horizon", displayName: "Set the Horizon", description: "Save the Horizon statement Aly confirmed and its status (approved or draft).", parametersSchema: { type: "object", properties: { statement: { type: "string" }, status: { type: "string" } } } },
61
+ { name: "direction_set_team", displayName: "Set up a team", description: "Make a goal a team: its lead, short name and charter.", parametersSchema: { type: "object", properties: { goalId: { type: "string" } }, required: ["goalId"] } },
59
62
  { name: "direction_set_campaign", displayName: "Set a campaign", description: "Set a campaign's Horizon part, focus or parked, rank, dates, why, finish line and Aly's minutes.", parametersSchema: { type: "object", properties: { goalId: { type: "string" } }, required: ["goalId"] } },
60
63
  { name: "direction_save_baseline", displayName: "Save the plan", description: "Save today's dates as this cycle's plan.", parametersSchema: { type: "object", properties: {} } },
61
64
  { name: "direction_add_scenario", displayName: "Add a way back", description: "Add a way back for a slipping campaign.", parametersSchema: { type: "object", properties: { campaignGoalId: { type: "string" }, label: { type: "string" } }, required: ["campaignGoalId", "label"] } }
package/dist/worker.js CHANGED
@@ -371,8 +371,8 @@ function optionalKeys(shape) {
371
371
  }
372
372
  function pick(schema, mask) {
373
373
  const currDef = schema._zod.def;
374
- const checks = currDef.checks;
375
- const hasChecks = checks && checks.length > 0;
374
+ const checks2 = currDef.checks;
375
+ const hasChecks = checks2 && checks2.length > 0;
376
376
  if (hasChecks) {
377
377
  throw new Error(".pick() cannot be used on object schemas containing refinements");
378
378
  }
@@ -394,8 +394,8 @@ function maskedKeys(schema, mask) {
394
394
  }
395
395
  function omit(schema, mask) {
396
396
  const currDef = schema._zod.def;
397
- const checks = currDef.checks;
398
- const hasChecks = checks && checks.length > 0;
397
+ const checks2 = currDef.checks;
398
+ const hasChecks = checks2 && checks2.length > 0;
399
399
  if (hasChecks) {
400
400
  throw new Error(".omit() cannot be used on object schemas containing refinements");
401
401
  }
@@ -408,8 +408,8 @@ function extend(schema, shape) {
408
408
  if (!isPlainObject(shape)) {
409
409
  throw new Error("Invalid input to extend: expected a plain object");
410
410
  }
411
- const checks = schema._zod.def.checks;
412
- const hasChecks = checks && checks.length > 0;
411
+ const checks2 = schema._zod.def.checks;
412
+ const hasChecks = checks2 && checks2.length > 0;
413
413
  if (hasChecks) {
414
414
  const existingShape = sourceShape(schema);
415
415
  for (const key of Reflect.ownKeys(shape)) {
@@ -453,8 +453,8 @@ function merge(a, b) {
453
453
  }
454
454
  function partial(Class2, schema, mask, name = "partial") {
455
455
  const currDef = schema._zod.def;
456
- const checks = currDef.checks;
457
- const hasChecks = checks && checks.length > 0;
456
+ const checks2 = currDef.checks;
457
+ const hasChecks = checks2 && checks2.length > 0;
458
458
  if (hasChecks) {
459
459
  throw new Error(`.${name}() cannot be used on object schemas containing refinements`);
460
460
  }
@@ -2780,24 +2780,24 @@ var init_schemas = __esm({
2780
2780
  inst._zod.bag = inst._zod.bag || {};
2781
2781
  inst._zod.version = version;
2782
2782
  const defChecks = inst._zod.def.checks;
2783
- const checks = inst._zod.traits.has("$ZodCheck") ? [inst, ...defChecks ?? []] : defChecks?.length ? [...defChecks] : [];
2784
- for (const ch of checks) {
2783
+ const checks2 = inst._zod.traits.has("$ZodCheck") ? [inst, ...defChecks ?? []] : defChecks?.length ? [...defChecks] : [];
2784
+ for (const ch of checks2) {
2785
2785
  for (const fn of ch._zod.onattach) {
2786
2786
  fn(inst);
2787
2787
  }
2788
2788
  }
2789
- if (checks.length === 0) {
2789
+ if (checks2.length === 0) {
2790
2790
  (_a3 = inst._zod).deferred ?? (_a3.deferred = []);
2791
2791
  inst._zod.deferred?.push(() => {
2792
2792
  inst._zod.run = inst._zod.parse;
2793
2793
  });
2794
2794
  } else {
2795
- const runChecks = (payload, checks2, ctx) => {
2795
+ const runChecks = (payload, checks3, ctx) => {
2796
2796
  if (payload.memo)
2797
2797
  return payload;
2798
2798
  let isAborted = aborted(payload);
2799
2799
  let asyncResult;
2800
- for (const ch of checks2) {
2800
+ for (const ch of checks3) {
2801
2801
  if (ch._zod.def.when) {
2802
2802
  if (explicitlyAborted(payload))
2803
2803
  continue;
@@ -2843,7 +2843,7 @@ var init_schemas = __esm({
2843
2843
  canary.aborted = true;
2844
2844
  return canary;
2845
2845
  }
2846
- const checkResult = runChecks(payload, checks, ctx);
2846
+ const checkResult = runChecks(payload, checks2, ctx);
2847
2847
  if (checkResult instanceof Promise) {
2848
2848
  if (ctx.async === false)
2849
2849
  throw new $ZodAsyncError();
@@ -2868,9 +2868,9 @@ var init_schemas = __esm({
2868
2868
  if (result instanceof Promise) {
2869
2869
  if (ctx.async === false)
2870
2870
  throw new $ZodAsyncError();
2871
- return result.then((result2) => runChecks(result2, checks, ctx));
2871
+ return result.then((result2) => runChecks(result2, checks2, ctx));
2872
2872
  }
2873
- return runChecks(result, checks, ctx);
2873
+ return runChecks(result, checks2, ctx);
2874
2874
  };
2875
2875
  }
2876
2876
  }, {
@@ -20059,11 +20059,11 @@ var init_deep_partial = __esm({
20059
20059
  });
20060
20060
 
20061
20061
  // node_modules/zod/v4/classic/in-out.js
20062
- function withChecks(side, checks) {
20063
- if (!checks?.length)
20062
+ function withChecks(side, checks2) {
20063
+ if (!checks2?.length)
20064
20064
  return side;
20065
20065
  const def2 = side._zod.def;
20066
- return clone(side, mergeDefs(def2, { checks: [...def2.checks ?? [], ...checks] }), { parent: true });
20066
+ return clone(side, mergeDefs(def2, { checks: [...def2.checks ?? [], ...checks2] }), { parent: true });
20067
20067
  }
20068
20068
  function outSide(def2) {
20069
20069
  return withChecks(def2.out, def2.checks);
@@ -31192,7 +31192,7 @@ function build(raw, companyId, today) {
31192
31192
  baseline: raw.baseline ? { cycle: raw.baseline.cycle, savedAt: iso(raw.baseline.saved_at) } : null,
31193
31193
  alyBudgetMinutes: BUDGET_DEFAULT
31194
31194
  };
31195
- return { model, goalById, issueById, agentById, who, blockedBy, blocks, children, descendants, msIds, msOfIssue, plan, planItems, tasksOfCampaign, ref, campRow };
31195
+ return { model, goalById, issueById, agentById, who, blockedBy, blocks, children, descendants, msIds, msOfIssue, plan, planItems, tasksOfCampaign, ref, campRow, campaignOfGoal, teamOf };
31196
31196
  }
31197
31197
  function campaignDetail(b, goalId, scenarios) {
31198
31198
  const c = b.model.campaigns.find((x) => x.goalId === goalId);
@@ -31525,6 +31525,14 @@ async function setCampaign(ctx, companyId, p) {
31525
31525
  const goalId = String(p.goalId);
31526
31526
  const g = await ctx.goals.get(goalId, companyId);
31527
31527
  if (!g) throw new Error("No such goal in this company");
31528
+ const patch = {};
31529
+ if (S(p.teamGoalId)) {
31530
+ const t = await ctx.goals.get(String(p.teamGoalId), companyId);
31531
+ if (!t || t.level !== "team") throw new Error("teamGoalId must be a team (set it up with direction_set_team first)");
31532
+ patch.parentId = t.id;
31533
+ }
31534
+ if ("leadAgentId" in p) patch.ownerAgentId = S(p.leadAgentId);
31535
+ if (Object.keys(patch).length) await ctx.goals.update(goalId, patch, companyId);
31528
31536
  const cur = (await ctx.db.query(`select * from ${NS}.campaigns where goal_id = $1`, [goalId]))[0] ?? {};
31529
31537
  const pick2 = (k, col, f) => k in p ? f(p[k]) : cur[col] ?? null;
31530
31538
  const row = {
@@ -31620,6 +31628,25 @@ async function setHorizon(ctx, companyId, p) {
31620
31628
  }
31621
31629
  return { ok: true };
31622
31630
  }
31631
+ async function setTeam(ctx, companyId, p) {
31632
+ modelCache.clear();
31633
+ decisionCache.clear();
31634
+ const goalId = String(p.goalId ?? "");
31635
+ const g = await ctx.goals.get(goalId, companyId);
31636
+ if (!g) throw new Error("No such goal in this company: create the team goal with Paperclip's goals API first");
31637
+ const patch = {};
31638
+ if (g.level !== "team") patch.level = "team";
31639
+ if ("leadAgentId" in p) patch.ownerAgentId = S(p.leadAgentId);
31640
+ if (Object.keys(patch).length) await ctx.goals.update(goalId, patch, companyId);
31641
+ const cur = (await ctx.db.query(`select * from ${NS}.teams where goal_id = $1`, [goalId]))[0] ?? {};
31642
+ const pick2 = (k, col, f) => k in p ? f(p[k]) : cur[col] ?? null;
31643
+ await ctx.db.execute(
31644
+ `insert into ${NS}.teams (goal_id, company_id, short_name, charter, aly_minutes, rank) values ($1,$2,$3,$4,$5,$6)
31645
+ on conflict (goal_id) do update set short_name = excluded.short_name, charter = excluded.charter, aly_minutes = excluded.aly_minutes, rank = excluded.rank`,
31646
+ [goalId, companyId, pick2("shortName", "short_name", S), pick2("charter", "charter", S), pick2("alyMinutes", "aly_minutes", N), pick2("rank", "rank", N) ?? 0]
31647
+ );
31648
+ return { ok: true, goalId };
31649
+ }
31623
31650
  async function saveBaseline(ctx, companyId, cycle, by) {
31624
31651
  modelCache.clear();
31625
31652
  decisionCache.clear();
@@ -31683,16 +31710,41 @@ function contextPath(b, issueId) {
31683
31710
  c?.finishLine.length ? `Finish line: ${c.finishLine.map((f) => `[${f.status}] ${f.text}`).join("; ")}` : "",
31684
31711
  ms ? `MILESTONE: ${ms.identifier} ${ms.shortTitle}: due ${ms.due ?? "?"}, forecast ${ms.forecast ?? "?"}, slack ${ms.slack ?? "?"}${ms.critical ? ", on the critical path" : ""}${ms.late ? ", LATE" : ""}. Waits for: ${ms.waitsFor.map((w) => w.title).join(", ") || "nothing"}. Unlocks: ${ms.unlocks.map((w) => w.title).join(", ") || "nothing"}.` : "MILESTONE: none",
31685
31712
  outcome ? `OUTCOME: ${outcome.title}. Contract: ${(outcome.description ?? "").replace(/\s+/g, " ").slice(0, 600)}` : "",
31686
- `TASK: ${i.identifier} ${i.title} [${i.status}]`
31713
+ `TASK: ${i.identifier} ${i.title} [${i.status}]`,
31714
+ `WHO DECIDES, in order: ${[ms && ms.owner.kind !== "none" ? `${ms.owner.name} (milestone owner)` : "", c && c.owner.kind !== "none" ? `${c.owner.name} (campaign lead)` : "", "Jev (Chief of Staff)"].filter(Boolean).join(" \u2192 ")}. Only Jev takes a choice to Aly.`
31687
31715
  ].filter(Boolean);
31688
31716
  return { text: lines.join("\n"), found: true, campaignId: c?.goalId ?? null, milestoneId: ms?.issueId ?? null };
31689
31717
  }
31718
+ function checks(b) {
31719
+ const m = b.model;
31720
+ const out = [];
31721
+ if (m.horizon.fromGoal) out.push("The Horizon is not saved in Direction: save the confirmed text with direction_set_horizon (status approved).");
31722
+ else if (m.horizon.status !== "approved") out.push("The Horizon is still a draft: once Aly has confirmed it, set status approved with direction_set_horizon.");
31723
+ if (!m.teams.length) out.push("No teams: set each one up (a team-level goal with its lead and charter) with direction_set_team.");
31724
+ for (const t of m.teams) {
31725
+ if (t.owner.kind === "none") out.push(`Team ${t.name} has no lead${t.charter && /to hire/i.test(t.charter) ? " (to hire)" : ""}.`);
31726
+ if (!t.charter) out.push(`Team ${t.name} has no charter.`);
31727
+ }
31728
+ for (const c of m.campaigns) {
31729
+ if (!c.team) out.push(`Campaign "${c.title}" belongs to no team (direction_set_campaign teamGoalId).`);
31730
+ if (c.owner.kind === "none") out.push(`Campaign "${c.title}" has no lead.`);
31731
+ }
31732
+ for (const ms of m.milestones.filter((x) => !x.done)) {
31733
+ if (!ms.campaignId) out.push(`Milestone ${ms.identifier ?? ms.shortTitle} belongs to no campaign.`);
31734
+ if (ms.owner.kind === "none") out.push(`Milestone ${ms.identifier ?? ms.shortTitle} has no owner.`);
31735
+ if (!ms.due) out.push(`Milestone ${ms.identifier ?? ms.shortTitle} has no due date.`);
31736
+ }
31737
+ const unplaced = [...b.issueById.values()].filter((i) => !DONE.has(i.status) && !i.conversationAgentId && !b.msIds.has(i.id) && !b.msOfIssue.has(i.id) && !b.campaignOfGoal(i.goalId ?? null) && !b.teamOf(i.goalId ? b.goalById.get(i.goalId) : void 0));
31738
+ if (unplaced.length) out.push(`${unplaced.length} open task${unplaced.length === 1 ? "" : "s"} placed nowhere (no milestone, campaign or team): ${unplaced.slice(0, 12).map((i) => i.identifier ?? i.title.slice(0, 40)).join(", ")}${unplaced.length > 12 ? ", \u2026" : ""}.`);
31739
+ return out;
31740
+ }
31690
31741
  function describe3(m) {
31691
31742
  const lines = [`Horizon (${m.horizon.status}): ${m.horizon.statement}`];
31743
+ for (const t of m.teams) lines.push(`Team ${t.name} [${t.goalId}]: lead ${t.owner.kind === "none" ? "none" : t.owner.name}${t.charter ? "" : ", no charter"}`);
31692
31744
  for (const c of m.campaigns) {
31693
- lines.push(`- Campaign "${c.title}" [${c.goalId}] ${c.state}, ${c.health}, part: ${c.partName ?? "not placed"}, finish ${c.plannedFinish ?? "?"} (forecast ${c.forecastFinish ?? "?"}), milestones ${c.milestonesDone}/${c.milestoneIds.length}`);
31745
+ lines.push(`- Campaign "${c.title}" [${c.goalId}] team ${c.team?.name ?? "none"}, lead ${c.owner.kind === "none" ? "none" : c.owner.name}, ${c.state}, ${c.health}, part: ${c.partName ?? "not placed"}, finish ${c.plannedFinish ?? "?"} (forecast ${c.forecastFinish ?? "?"}), milestones ${c.milestonesDone}/${c.milestoneIds.length}`);
31694
31746
  for (const ms of m.milestones.filter((x) => x.campaignId === c.goalId))
31695
- lines.push(` - ${ms.identifier} ${ms.shortTitle}: due ${ms.due ?? "?"}, forecast ${ms.forecast ?? "?"}, slack ${ms.slack ?? "?"}${ms.late ? ", LATE" : ""}${ms.heldUp ? ", held up" : ""}${ms.critical ? ", critical" : ""}, status ${ms.status}`);
31747
+ lines.push(` - ${ms.identifier} ${ms.shortTitle} (owner ${ms.owner.kind === "none" ? "none" : ms.owner.name}): due ${ms.due ?? "?"}, forecast ${ms.forecast ?? "?"}, slack ${ms.slack ?? "?"}${ms.late ? ", LATE" : ""}${ms.heldUp ? ", held up" : ""}${ms.critical ? ", critical" : ""}, status ${ms.status}`);
31696
31748
  }
31697
31749
  return lines.join("\n");
31698
31750
  }
@@ -31787,7 +31839,14 @@ var plugin = definePlugin({
31787
31839
  "The Horizon, every campaign with its health and finish, and every milestone with due date, forecast, slack and critical path.",
31788
31840
  {},
31789
31841
  [],
31790
- async (companyId) => describe3((await model(companyId)).model)
31842
+ async (companyId) => {
31843
+ const b = await model(companyId);
31844
+ const ch = checks(b);
31845
+ return `${describe3(b.model)}${ch.length ? `
31846
+
31847
+ NEEDS FIXING (lab-anatomy):
31848
+ ${ch.map((x) => `- ${x}`).join("\n")}` : "\n\nAnatomy checks: all clear."}`;
31849
+ }
31791
31850
  );
31792
31851
  tool3(
31793
31852
  "direction_set_milestone",
@@ -31810,9 +31869,11 @@ var plugin = definePlugin({
31810
31869
  tool3(
31811
31870
  "direction_set_campaign",
31812
31871
  "Set a campaign",
31813
- "Set a campaign's (a Paperclip goal's) Horizon part, focus or parked, rank, planned start and finish, why it matters, finish line, Aly's minutes, review date.",
31872
+ "Set a campaign's (a Paperclip goal's) team and lead, Horizon part, focus or parked, rank, planned start and finish, why it matters, finish line, Aly's minutes, review date.",
31814
31873
  {
31815
31874
  goalId: { type: "string" },
31875
+ teamGoalId: { type: "string", description: "The team that owns this campaign" },
31876
+ leadAgentId: { type: "string", description: "The campaign's lead" },
31816
31877
  partId: { type: "string" },
31817
31878
  state: { type: "string", enum: ["focus", "parked"] },
31818
31879
  rankLabel: { type: "string", enum: ["Now", "Next", "Later"] },
@@ -31828,6 +31889,22 @@ var plugin = definePlugin({
31828
31889
  ["goalId"],
31829
31890
  (c, p) => setCampaign(ctx, c, p)
31830
31891
  );
31892
+ tool3(
31893
+ "direction_set_horizon",
31894
+ "Set the Horizon",
31895
+ "Save the Horizon statement Aly confirmed, and its status (approved once he has confirmed it, otherwise draft). The Horizon names no products, names or dates.",
31896
+ { statement: { type: "string" }, status: { type: "string", enum: ["approved", "draft"] }, note: { type: "string" } },
31897
+ [],
31898
+ (c, p) => setHorizon(ctx, c, { ...p, status: p.status === "confirmed" ? "approved" : p.status })
31899
+ );
31900
+ tool3(
31901
+ "direction_set_team",
31902
+ "Set up a team",
31903
+ "Make a goal a team (a standing area someone answers for): its lead, short name and charter. Create the goal first with Paperclip's goals API (level team, under the company goal). Leave leadAgentId out while the lead is still to hire, and say so in the charter.",
31904
+ { goalId: { type: "string" }, leadAgentId: { type: "string" }, shortName: { type: "string" }, charter: { type: "string" }, rank: { type: "number" } },
31905
+ ["goalId"],
31906
+ (c, p) => setTeam(ctx, c, p)
31907
+ );
31831
31908
  tool3(
31832
31909
  "direction_save_baseline",
31833
31910
  "Save the plan",
@@ -31857,7 +31934,7 @@ var plugin = definePlugin({
31857
31934
  switch (input2.routeKey) {
31858
31935
  case "read": {
31859
31936
  const b = build(await loadRaw(ctx, input2.companyId), input2.companyId, todayDay());
31860
- return { body: { text: describe3(b.model), model: b.model } };
31937
+ return { body: { text: describe3(b.model), checks: checks(b), model: b.model } };
31861
31938
  }
31862
31939
  case "context": {
31863
31940
  const b = build(await loadRaw(ctx, input2.companyId), input2.companyId, todayDay());
@@ -31869,6 +31946,8 @@ var plugin = definePlugin({
31869
31946
  return { body: await setCampaign(ctx, input2.companyId, body) };
31870
31947
  case "horizon":
31871
31948
  return { body: await setHorizon(ctx, input2.companyId, body) };
31949
+ case "team":
31950
+ return { body: await setTeam(ctx, input2.companyId, body) };
31872
31951
  case "baseline":
31873
31952
  return { body: await saveBaseline(ctx, input2.companyId, S(body.cycle), by) };
31874
31953
  case "scenario":
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dawlad-paperclip-direction",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "type": "module",
5
5
  "description": "Paperclip plugin: Horizon, campaigns and milestones (Direction page) for Da Applied AI Lab.",
6
6
  "paperclipPlugin": {