@cortad/connector 0.6.0-rc.2 → 0.6.0-rc.3

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.
@@ -86,7 +86,7 @@ export function selected(raws, { now = Date.now(), secrets = [] } = {}) {
86
86
  }),
87
87
  });
88
88
  }
89
- return { conversations: out, messages: HISTORY_MESSAGES - room, scrubbed, left: Object.fromEntries(left), users: new Set(recent.map((c) => c.user).filter(Boolean)).size };
89
+ return { conversations: out, messages: HISTORY_MESSAGES - room, total: out.reduce((n, c) => n + c.messages.length, 0), scrubbed, left: Object.fromEntries(left), users: new Set(recent.map((c) => c.user).filter(Boolean)).size };
90
90
  }
91
91
 
92
92
  // The span of what will be sent, oldest message to newest.
@@ -14,7 +14,7 @@ export const header = (app) => [
14
14
  ];
15
15
 
16
16
  export const approveFirst = ({ spec, link, words, machine }) => lines(
17
- "This computer is not connected to Cortad yet.",
17
+ "This computer needs the person's approval to connect to Cortad.",
18
18
  `Give the person this link and the four characters, once: ${link} (characters ${words}, computer ${machine})`,
19
19
  "They approve it in a browser where they are signed in to Cortad. The page shows the same four characters and this computer's name; they approve only if both match.",
20
20
  `Once they have approved it, run npx -y ${spec} intelligence again. It waits up to a minute and a half for the approval.`,
@@ -22,6 +22,7 @@ export const approveFirst = ({ spec, link, words, machine }) => lines(
22
22
  export const pairExpired = (spec) => lines(`The approval link expired before it was approved. Run npx -y ${spec} intelligence again for a new one.`);
23
23
  export const paired = (app) => `This computer is now connected to Cortad for ${app}.`;
24
24
  export const gone = () => lines("This folder's app is no longer connected to Cortad. Connect it again from cortad.com/sim, then run this command again.");
25
+ export const keyRefused = "Cortad no longer accepts the key this computer kept for this folder, so it asks for a new approval.";
25
26
 
26
27
  export const keysWritten = (file, at) => [
27
28
  `Wrote CORTAD_INGEST_KEY and CORTAD_PUBLIC_KEY to ${file}, lines ${at.ingest} and ${at.page}${at.env ? `, and CORTAD_ENV=development on line ${at.env} so chats on this computer are never counted as your users'` : ""}. ${file} is git-ignored.`,
@@ -74,7 +75,7 @@ export function historySent({ result, picked, span, source, file }) {
74
75
  const left = Object.entries(picked.left).filter(([why]) => !shortened(why)).map(([why, n]) => `${num(n)} ${why}`);
75
76
  const cut = Object.entries(picked.left).filter(([why]) => shortened(why)).map(([why, n]) => `${num(n)} ${why}`);
76
77
  return [
77
- `Sent ${num(result.taken)} conversations from ${source}, ${num(result.messages)} messages, ${day(span.from)} to ${day(span.to)}.${result.already ? ` ${num(result.already)} were already in Cortad.` : ""}`,
78
+ `Sent ${num(result.taken)} conversations from ${source}, ${day(span.from)} to ${day(span.to)}: ${num(picked.total)} messages, ${num(result.messages)} of them your app's replies, which is what Cortad counts.${result.already ? ` ${num(result.already)} were already in Cortad.` : ""}`,
78
79
  ...(picked.scrubbed ? [`${num(picked.scrubbed)} keys, card numbers, emails or phone numbers were replaced on this computer before sending.`] : []),
79
80
  ...(left.length ? [`Left out: ${left.join(", ")}.`] : []),
80
81
  ...(cut.length ? [`Shortened: ${cut.join(", ")}.`] : []),
@@ -83,7 +84,7 @@ export function historySent({ result, picked, span, source, file }) {
83
84
  ];
84
85
  }
85
86
  export const historyDry = ({ picked, span, file }) => [
86
- `Read ${num(picked.conversations.length)} conversations, ${num(picked.messages)} messages, ${day(span.from)} to ${day(span.to)}. Nothing was sent.`,
87
+ `Read ${num(picked.conversations.length)} conversations, ${day(span.from)} to ${day(span.to)}: ${num(picked.total)} messages, ${num(picked.messages)} of them your app's replies. Nothing was sent.`,
87
88
  `What would be sent is in ${file}.`,
88
89
  ];
89
90
  export const historyLooksLikeDevelopment = ({ why, spec, rest }) => [
@@ -125,7 +126,7 @@ export function codeStep({ spec, stack, page, file, site, consent, host, settabl
125
126
  ...secondQuestion({ spec, host, settable, file, site }),
126
127
  ];
127
128
  }
128
- export const SDK = "0.3.2";
129
+ export const SDK = "0.3.3";
129
130
 
130
131
  function secondQuestion({ spec, host, settable, file, site }) {
131
132
  const h = HOSTS[host] ?? HOSTS.other;
@@ -29,9 +29,13 @@ export async function intelligence(args, ctx) {
29
29
  const { root, spec, token } = ctx;
30
30
  const api = (path, init = {}) => request(ctx, path, init);
31
31
  const opening = [];
32
- if (!token()) {
32
+ // A key Cortad no longer takes (revoked, idle a month, or its account gone) is the same as none: the
33
+ // person approves this computer again and the new key replaces it.
34
+ const refusedKey = token() ? (await api("/mcp/intelligence/start")).status === 401 : false;
35
+ if (refusedKey) opening.push(say.keyRefused);
36
+ if (!token() || refusedKey) {
33
37
  const result = await pair(ctx, (path, body) => request({ ...ctx, token: () => "" }, path, { method: "POST", body }));
34
- if (result.waiting) return { text: say.approveFirst({ spec, ...result }) };
38
+ if (result.waiting) return { text: [say.lines(opening), say.approveFirst({ spec, ...result })].filter(Boolean).join("\n") };
35
39
  if (result.expired) return { text: say.pairExpired(spec) };
36
40
  if (result.failed) return { text: say.lines(result.failed), code: 1 };
37
41
  opening.push(say.paired(result.app));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cortad/connector",
3
- "version": "0.6.0-rc.2",
3
+ "version": "0.6.0-rc.3",
4
4
  "description": "Connects the AI app on your machine to Cortad for test conversations, and gives your coding agent the MCP and skill to run them.",
5
5
  "bin": {
6
6
  "cortad": "local.mjs"