intentdocs 0.8.0 → 0.10.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 (34) hide show
  1. package/README.md +2 -1
  2. package/bin/intentdocs.js +2 -0
  3. package/dist/{chunk-4OWPN2RE.js → chunk-5USVG4DW.js} +24 -43
  4. package/dist/{chunk-IKF3ZLHK.js → chunk-EEKEF2FD.js} +65 -101
  5. package/dist/chunk-HEHHSSUM.js +43 -0
  6. package/dist/chunk-IDNUBI2P.js +317 -0
  7. package/dist/chunk-LQTPZL2Y.js +15 -0
  8. package/dist/chunk-LXQXJULN.js +105 -0
  9. package/dist/{chunk-6FGYJ3W2.js → chunk-NFIXRIHM.js} +43 -4
  10. package/dist/{chunk-ICOMMHKG.js → chunk-UF535HZL.js} +12 -1
  11. package/dist/{chunk-ITQUQYWB.js → chunk-UR73WX5I.js} +1 -1
  12. package/dist/chunk-UYTVTYNB.js +11 -0
  13. package/dist/{chunk-WPVDURTJ.js → chunk-WRRUCCVZ.js} +27 -3
  14. package/dist/chunk-YUW3W43S.js +170 -0
  15. package/dist/ci-LBOCMRKZ.js +11 -0
  16. package/dist/{complexity-NSSYVT54.js → complexity-ZOB3BPVD.js} +12 -7
  17. package/dist/{import-prd-CKV3R67G.js → import-prd-MJUCIMHX.js} +13 -11
  18. package/dist/index.js +420 -179
  19. package/dist/{keys-EDWET3WG.js → keys-5PA3D6CX.js} +8 -7
  20. package/dist/log-EVLWM64C.js +206 -0
  21. package/dist/{map-extract-I3AACTGL.js → map-extract-W6WJLVOF.js} +2 -1
  22. package/dist/{map-import-IYUMRASO.js → map-import-LL4AIAQE.js} +12 -10
  23. package/dist/{map-schema-JVL3O2TJ.js → map-schema-6GL2UKZQ.js} +1 -1
  24. package/dist/projects-F7GMH66U.js +37 -0
  25. package/dist/{prompt-WAWCRGHN.js → prompt-GOAFIKBZ.js} +3 -1
  26. package/dist/{research-6SXJ37TI.js → research-4ASCZSZN.js} +12 -10
  27. package/dist/scope-S3LZZ3KB.js +11 -0
  28. package/dist/setup-YLUPBLK6.js +14 -0
  29. package/package.json +4 -2
  30. package/dist/chunk-6XKB6RTU.js +0 -123
  31. package/dist/chunk-PCNDP5SX.js +0 -34
  32. package/dist/log-TT2UCJP7.js +0 -94
  33. package/dist/scope-OGKQ472D.js +0 -10
  34. package/dist/setup-SOI2HQAL.js +0 -11
@@ -0,0 +1,170 @@
1
+ import {
2
+ getAuth
3
+ } from "./chunk-LXQXJULN.js";
4
+
5
+ // src/lib/api.ts
6
+ var AuthError = class extends Error {
7
+ constructor(message) {
8
+ super(message);
9
+ this.name = "AuthError";
10
+ }
11
+ };
12
+ function checkoutMismatch(config, binding) {
13
+ const checkout = config.workspace;
14
+ if (!checkout || !checkout.orgId) return null;
15
+ const checkoutName = checkout.name ?? "another workspace";
16
+ const here = config.mapTitle ? `"${config.mapTitle}"` : "this checkout";
17
+ if (!binding) {
18
+ return `${here} belongs to ${checkoutName}, but your token is personal. Run \`intentdocs login\` and choose ${checkoutName}.`;
19
+ }
20
+ if (binding.orgId !== checkout.orgId) {
21
+ const bound = binding.workspaceName ?? "a different workspace";
22
+ return `This checkout is ${checkoutName}'s \u2014 ${here} \u2014 but your token is bound to ${bound}. Run \`intentdocs login\` and choose ${checkoutName}, or work from a checkout of ${bound}'s.`;
23
+ }
24
+ return null;
25
+ }
26
+ function syncHeaders(init, auth = getAuth()) {
27
+ const headers = {};
28
+ if (init) {
29
+ new Headers(init).forEach((value, key) => {
30
+ headers[key] = value;
31
+ });
32
+ }
33
+ if (auth?.token) headers["Authorization"] = `Bearer ${auth.token}`;
34
+ return headers;
35
+ }
36
+ async function refusalMessage(res) {
37
+ try {
38
+ const body = await res.clone().json();
39
+ if (typeof body.message === "string") return body.message;
40
+ if (body.error && typeof body.error === "object") return body.error.hint ?? body.error.message ?? null;
41
+ } catch {
42
+ }
43
+ return null;
44
+ }
45
+ async function apiFetch(config, path, init) {
46
+ const auth = getAuth();
47
+ const mismatch = checkoutMismatch(config, auth?.binding);
48
+ if (mismatch) throw new AuthError(mismatch);
49
+ if (!auth?.token) {
50
+ throw new AuthError("Not logged in \u2014 every sync runs as you now. Run `intentdocs login`.");
51
+ }
52
+ const withBearer = { ...init, headers: syncHeaders(init?.headers, auth) };
53
+ const res = await fetch(apiUrl(config, path), withBearer);
54
+ if (res.status === 401) {
55
+ const said = await refusalMessage(res);
56
+ throw new AuthError(said ?? "Your login is no longer valid. Run `intentdocs login`.");
57
+ }
58
+ if (res.status === 404) {
59
+ const said = await refusalMessage(res);
60
+ if (said) throw new AuthError(said);
61
+ }
62
+ if (res.status === 403) {
63
+ const said = await refusalMessage(res);
64
+ throw new AuthError(
65
+ said ?? "Access denied \u2014 you may not have permission for this project. Run `intentdocs login` to re-authenticate."
66
+ );
67
+ }
68
+ if (!res.ok) throw new Error(`API error: ${res.status}`);
69
+ return res;
70
+ }
71
+ function apiUrl(config, path) {
72
+ if (!config.mapId) {
73
+ throw new AuthError("This checkout has no map id. Run `intentdocs init` to reconnect it.");
74
+ }
75
+ return `${config.apiBase}/api/sync/${config.mapId}${path}`;
76
+ }
77
+ async function listStories(config) {
78
+ const res = await apiFetch(config, "/stories");
79
+ return res.json();
80
+ }
81
+ async function getContext(config) {
82
+ const res = await apiFetch(config, "/context");
83
+ return res.text();
84
+ }
85
+ async function updateStories(config, stories) {
86
+ const res = await apiFetch(config, "/stories", {
87
+ method: "PATCH",
88
+ headers: { "Content-Type": "application/json" },
89
+ body: JSON.stringify({ stories })
90
+ });
91
+ return res.json();
92
+ }
93
+ async function uploadScreenshot(config, storyId, screenshot) {
94
+ try {
95
+ const form = new FormData();
96
+ form.append("story_id", storyId);
97
+ form.append(
98
+ "image",
99
+ new Blob([Uint8Array.from(screenshot.buffer)], { type: screenshot.mimeType }),
100
+ screenshot.filename
101
+ );
102
+ const res = await apiFetch(config, "/screenshots", {
103
+ method: "POST",
104
+ body: form
105
+ });
106
+ return await res.json();
107
+ } catch {
108
+ return null;
109
+ }
110
+ }
111
+ async function createStories(config, stories) {
112
+ const res = await apiFetch(config, "/stories", {
113
+ method: "POST",
114
+ headers: { "Content-Type": "application/json" },
115
+ body: JSON.stringify({ stories })
116
+ });
117
+ return res.json();
118
+ }
119
+ async function reportCriteria(config, storyId, results) {
120
+ const res = await apiFetch(config, "/criteria", {
121
+ method: "PATCH",
122
+ headers: { "Content-Type": "application/json" },
123
+ body: JSON.stringify({ story_id: storyId, results })
124
+ });
125
+ return res.json();
126
+ }
127
+ async function raiseBlocker(config, payload) {
128
+ const res = await apiFetch(config, "/blocker", {
129
+ method: "POST",
130
+ headers: { "Content-Type": "application/json" },
131
+ body: JSON.stringify(payload)
132
+ });
133
+ return res.json();
134
+ }
135
+ async function listDecisions(config) {
136
+ const res = await apiFetch(config, "/decisions");
137
+ return res.json();
138
+ }
139
+ async function amendDecision(config, decisionId, fields) {
140
+ const res = await apiFetch(config, `/decisions/${decisionId}`, {
141
+ method: "PATCH",
142
+ headers: { "Content-Type": "application/json" },
143
+ body: JSON.stringify(fields)
144
+ });
145
+ return res.json();
146
+ }
147
+ async function retractDecision(config, decisionId, reason) {
148
+ const res = await apiFetch(config, `/decisions/${decisionId}`, {
149
+ method: "DELETE",
150
+ headers: { "Content-Type": "application/json" },
151
+ body: JSON.stringify({ reason })
152
+ });
153
+ return res.json();
154
+ }
155
+
156
+ export {
157
+ syncHeaders,
158
+ apiFetch,
159
+ apiUrl,
160
+ listStories,
161
+ getContext,
162
+ updateStories,
163
+ uploadScreenshot,
164
+ createStories,
165
+ reportCriteria,
166
+ raiseBlocker,
167
+ listDecisions,
168
+ amendDecision,
169
+ retractDecision
170
+ };
@@ -0,0 +1,11 @@
1
+ import {
2
+ ci
3
+ } from "./chunk-IDNUBI2P.js";
4
+ import "./chunk-HEHHSSUM.js";
5
+ import "./chunk-UF535HZL.js";
6
+ import "./chunk-WRRUCCVZ.js";
7
+ import "./chunk-LXQXJULN.js";
8
+ import "./chunk-UYTVTYNB.js";
9
+ export {
10
+ ci
11
+ };
@@ -1,15 +1,20 @@
1
1
  import {
2
2
  isPlanGated,
3
3
  printUpgradeMessage
4
- } from "./chunk-ITQUQYWB.js";
4
+ } from "./chunk-UR73WX5I.js";
5
+ import {
6
+ matchesStoryRef
7
+ } from "./chunk-LQTPZL2Y.js";
5
8
  import {
6
9
  apiUrl,
7
- listStories
8
- } from "./chunk-6XKB6RTU.js";
10
+ listStories,
11
+ syncHeaders
12
+ } from "./chunk-YUW3W43S.js";
9
13
  import {
10
14
  requireConfig
11
- } from "./chunk-ICOMMHKG.js";
12
- import "./chunk-PCNDP5SX.js";
15
+ } from "./chunk-UF535HZL.js";
16
+ import "./chunk-LXQXJULN.js";
17
+ import "./chunk-UYTVTYNB.js";
13
18
 
14
19
  // src/commands/complexity.ts
15
20
  import ora from "ora";
@@ -20,7 +25,7 @@ async function complexity(storyId) {
20
25
  const data = await listStories(config);
21
26
  let storyIds;
22
27
  if (storyId) {
23
- const match = data.stories.find((s) => s.id.startsWith(storyId));
28
+ const match = data.stories.find((s) => matchesStoryRef(s, storyId));
24
29
  if (!match) {
25
30
  spinner.fail(` No story found matching "${storyId}"`);
26
31
  return;
@@ -35,7 +40,7 @@ async function complexity(storyId) {
35
40
  }
36
41
  const res = await fetch(apiUrl(config, "/complexity"), {
37
42
  method: "POST",
38
- headers: { "Content-Type": "application/json" },
43
+ headers: syncHeaders({ "Content-Type": "application/json" }),
39
44
  body: JSON.stringify({ story_ids: storyIds })
40
45
  });
41
46
  if (!res.ok) {
@@ -1,18 +1,20 @@
1
- import {
2
- closePrompt,
3
- confirm
4
- } from "./chunk-WPVDURTJ.js";
5
1
  import {
6
2
  isPlanGated,
7
3
  printUpgradeMessage
8
- } from "./chunk-ITQUQYWB.js";
4
+ } from "./chunk-UR73WX5I.js";
9
5
  import {
10
- apiUrl
11
- } from "./chunk-6XKB6RTU.js";
6
+ apiUrl,
7
+ syncHeaders
8
+ } from "./chunk-YUW3W43S.js";
12
9
  import {
13
10
  requireConfig
14
- } from "./chunk-ICOMMHKG.js";
15
- import "./chunk-PCNDP5SX.js";
11
+ } from "./chunk-UF535HZL.js";
12
+ import {
13
+ closePrompt,
14
+ confirm
15
+ } from "./chunk-WRRUCCVZ.js";
16
+ import "./chunk-LXQXJULN.js";
17
+ import "./chunk-UYTVTYNB.js";
16
18
 
17
19
  // src/commands/import-prd.ts
18
20
  import { readFileSync, existsSync } from "fs";
@@ -48,7 +50,7 @@ async function importPrd(filePath) {
48
50
  try {
49
51
  const res = await fetch(apiUrl(config, "/import"), {
50
52
  method: "POST",
51
- headers: { "Content-Type": "application/json" },
53
+ headers: syncHeaders({ "Content-Type": "application/json" }),
52
54
  body: JSON.stringify({ prd: prdText, format })
53
55
  });
54
56
  if (!res.ok) {
@@ -103,7 +105,7 @@ async function importPrd(filePath) {
103
105
  }));
104
106
  const createRes = await fetch(apiUrl(config, "/map-import"), {
105
107
  method: "POST",
106
- headers: { "Content-Type": "application/json" },
108
+ headers: syncHeaders({ "Content-Type": "application/json" }),
107
109
  body: JSON.stringify({
108
110
  schema_version: "1.0",
109
111
  source: "prd-import",