passalong 1.6.0 → 1.7.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "passalong",
3
- "version": "1.6.0",
3
+ "version": "1.7.0",
4
4
  "description": "Work, projects, documents and files for a team and its agents: take work, hand it in with evidence, and keep what the team knows in its projects.",
5
5
  "mcpName": "io.github.codellyson/passalong",
6
6
  "keywords": [
package/src/api.js CHANGED
@@ -261,8 +261,9 @@ export const removeMember = (slug, who) =>
261
261
  export const join = (code) =>
262
262
  call(`/v1/invites/${encodeURIComponent(code)}/accept`, { method: "POST" });
263
263
 
264
- export const projects = (scope = "all", query = "") =>
265
- call(`/v1/projects${q({ scope, q: query })}`);
264
+ // `brief`: id, title, repos and counts, which is what an agent listing every project needs.
265
+ export const projects = (scope = "all", query = "", brief = false) =>
266
+ call(`/v1/projects${q({ scope, q: query, ...(brief ? { brief: "1" } : {}) })}`);
266
267
  export const createProject = (
267
268
  title,
268
269
  description = "",
@@ -270,8 +271,12 @@ export const createProject = (
270
271
  parent = "",
271
272
  color = "",
272
273
  repo = "",
274
+ repos = undefined,
273
275
  ) =>
274
- call("/v1/projects", { method: "POST", body: { title, description, team, parent, color, repo } });
276
+ call("/v1/projects", {
277
+ method: "POST",
278
+ body: { title, description, team, parent, color, repo, ...(repos ? { repos } : {}) },
279
+ });
275
280
  export const project = (id) => call(`/v1/projects/${encodeURIComponent(id)}`);
276
281
  export const updateProject = (id, changes) =>
277
282
  call(`/v1/projects/${encodeURIComponent(id)}`, { method: "PATCH", body: changes });
package/src/mcp.js CHANGED
@@ -758,7 +758,8 @@ export function buildServer() {
758
758
  description:
759
759
  "With `id`, one project: its documents, files and the projects inside it. With `query`, " +
760
760
  "the projects whose name, description or any document mentions those words, each naming " +
761
- "its matching documents. With neither, every project you can see. Each answer's `space` " +
761
+ "its matching documents. With neither, every project you can see, briefly: id, title, " +
762
+ "repos and how much is in it; ask for one by `id` for the rest. Each answer's `space` " +
762
763
  'says where it lives: private, or a named team; `repo` is the repo it is built from, "" ' +
763
764
  "when it has none. Read that repo when you write or check its documents.",
764
765
  inputSchema: {
@@ -768,7 +769,8 @@ export function buildServer() {
768
769
  },
769
770
  },
770
771
  run(({ id, query, scope }) =>
771
- id ? api.project(id) : api.projects(scope || "all", query || ""),
772
+ // Listing everything is brief; a search keeps the documents that matched.
773
+ id ? api.project(id) : api.projects(scope || "all", query || "", !query),
772
774
  ),
773
775
  );
774
776
 
@@ -779,9 +781,12 @@ export function buildServer() {
779
781
  annotations: ADDS,
780
782
  description:
781
783
  "With no `id`, make a project, after find_projects shows none fits: a `title` and a short " +
782
- "`description`, and its `repo` when it has one. Leave out `team` for a private one, and " +
784
+ "`description`, and its `repo` when it has one, or `repos` when it is built from several " +
785
+ "(a web app, its API, its mobile app: one product, one project). Leave out `team` for a " +
786
+ "private one, and " +
783
787
  "pass a team slug only when the person wants it shared; `parent` puts it inside another, " +
784
788
  'in that one\'s space. With `id`, change its title, description, repo ("" for none), ' +
789
+ "repos (the whole list, the main one first), " +
785
790
  'colour or place (`parent` "" for the top level); ' +
786
791
  "its space never changes. The answer's `space` says where it is: tell the person.",
787
792
  inputSchema: {
@@ -795,9 +800,16 @@ export function buildServer() {
795
800
  .string()
796
801
  .optional()
797
802
  .describe('the repo it is built from, e.g. github.com/acme/billing; "" for none'),
803
+ repos: z
804
+ .array(z.string())
805
+ .optional()
806
+ .describe(
807
+ "every repo it is built from, the main one first; replaces the list. Work written in " +
808
+ "any of them is filed in this project and its agents read this project's README",
809
+ ),
798
810
  },
799
811
  },
800
- run(({ id, title, description, team, parent, color, repo }) => {
812
+ run(({ id, title, description, team, parent, color, repo, repos }) => {
801
813
  if (!id) {
802
814
  if (!title) throw new Error("a new project needs a `title`");
803
815
  return api.createProject(
@@ -807,11 +819,12 @@ export function buildServer() {
807
819
  parent || "",
808
820
  color || "",
809
821
  repo || "",
822
+ repos,
810
823
  );
811
824
  }
812
825
  if (team) throw new Error("a project's space does not change; leave out `team`");
813
826
  const changes = Object.fromEntries(
814
- Object.entries({ title, description, parent, color, repo }).filter(
827
+ Object.entries({ title, description, parent, color, repo, repos }).filter(
815
828
  ([, v]) => v !== undefined,
816
829
  ),
817
830
  );
@@ -853,7 +866,11 @@ export function buildServer() {
853
866
  "(a newer edit is refused, so nobody\'s writing is lost) and/or `name` to rename it, " +
854
867
  "and/or `move_to` another project in the same space. Its id and history stay. Update the " +
855
868
  "page that already covers something rather than adding another. A document has no owner " +
856
- "and no state and tells nobody: anything someone must still act on is work (create_work).",
869
+ "and no state and tells nobody: anything someone must still act on is work (create_work). " +
870
+ "The README is special: an agent taking work in the project is shown its first 4,000 " +
871
+ "characters. Put there what it must know before changing anything (what this is, the " +
872
+ "rules not to break, the words used, where things are) and the detail on other pages, " +
873
+ "named in it. Refer to other pages by their names, not file names.",
857
874
  inputSchema: {
858
875
  project: z.string().describe("project id"),
859
876
  document: z.string().optional().describe("the document to change; leave out for a new one"),
package/src/passalong.js CHANGED
@@ -758,15 +758,23 @@ export function projectsNote(projects) {
758
758
  if (!Array.isArray(projects) || !projects.length) return "";
759
759
  const blocks = projects.map((p) => {
760
760
  const name = p.title || p.id;
761
- const where = `${name} (${p.id})${p.repo ? `, built from ${p.repo}` : ""}`;
761
+ const repos = p.repos?.length ? p.repos : p.repo ? [p.repo] : [];
762
+ const where = `${name} (${p.id})${repos.length ? `, built from ${repos.join(", ")}` : ""}`;
762
763
  const about = p.description ? ` ${p.description}` : "";
764
+ // A README cut short says so before it starts, and ends with an instruction rather than a
765
+ // pointer: agents took "it goes on" as optional and worked from the part they had (2026-11-07).
763
766
  const lead = p.readme
764
767
  ? `WHAT TO KNOW FIRST: this work is filed in the project ${where}.${about} Its README is ` +
765
- "below: read it before you start."
768
+ (p.readme.cut
769
+ ? "below, cut short: read all of it before you start."
770
+ : "below: read it before you start.")
766
771
  : `WHAT TO KNOW FIRST: this work is filed in the project ${where}.${about} It has no README yet.`;
767
772
  const readme = p.readme
768
773
  ? `\n\n--- README of ${name}: document ${p.readme.id} ---\n${p.readme.body.trimEnd()}\n` +
769
- (p.readme.cut ? `…it goes on: read_document ${p.readme.id} for the rest.\n` : "")
774
+ (p.readme.cut
775
+ ? `--- The README goes on past this point. Before you start, read the rest: read_document ` +
776
+ `project ${p.id}, document ${p.readme.id}. ---\n`
777
+ : "")
770
778
  : "\n";
771
779
  const docs = p.documents?.length
772
780
  ? "Its other documents: open the ones that bear on this with read_document: " +