plan-assistant 1.2.2 → 1.3.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/build/client/_app/immutable/assets/0.xgRkQ1lY.css +1 -0
- package/build/client/_app/immutable/chunks/{enKT794F.js → 4kGnLX4E.js} +1 -1
- package/build/client/_app/immutable/chunks/{Cfu7LlTl.js → 7xbSEO3e.js} +1 -1
- package/build/client/_app/immutable/chunks/{DK1EzMSE.js → 8MxYjPhT.js} +1 -1
- package/build/client/_app/immutable/chunks/{CAs7BFgw.js → B08Ypfzz.js} +1 -1
- package/build/client/_app/immutable/chunks/{C7_sUGKI.js → B0GxnfwX.js} +1 -1
- package/build/client/_app/immutable/chunks/B7OX4jyw.js +1 -0
- package/build/client/_app/immutable/chunks/{CdWYTPbj.js → B8WSglEQ.js} +1 -1
- package/build/client/_app/immutable/chunks/{CCvUv5wO.js → BJp2RePy.js} +1 -1
- package/build/client/_app/immutable/chunks/{Zl01-BCk.js → BU-OGCcV.js} +1 -1
- package/build/client/_app/immutable/chunks/{BQLlh6rw.js → BdCB6Hkm.js} +1 -1
- package/build/client/_app/immutable/chunks/BdoKnygS.js +2 -0
- package/build/client/_app/immutable/chunks/{De3MB1l1.js → BsZa0b3n.js} +1 -1
- package/build/client/_app/immutable/chunks/{BEd52Y9t.js → By3fFDb-.js} +42 -42
- package/build/client/_app/immutable/chunks/{DtRnjJCq.js → C086Yenj.js} +1 -1
- package/build/client/_app/immutable/chunks/{CpzGW5sx.js → CBHlb2YZ.js} +1 -1
- package/build/client/_app/immutable/chunks/{CZDB-NCS.js → CBa9vZiM.js} +1 -1
- package/build/client/_app/immutable/chunks/{BlhCArX0.js → CGP8mjtq.js} +1 -1
- package/build/client/_app/immutable/chunks/{DJPNFy2Z.js → CJxAoC6E.js} +1 -1
- package/build/client/_app/immutable/chunks/{BPiLmQNn.js → CPL6zTMB.js} +1 -1
- package/build/client/_app/immutable/chunks/{SLcsOks0.js → CTVsQ2Ui.js} +1 -1
- package/build/client/_app/immutable/chunks/{BgWVd2JH.js → CUBCWTHT.js} +1 -1
- package/build/client/_app/immutable/chunks/{CptLmxn7.js → CUC2CAIO.js} +1 -1
- package/build/client/_app/immutable/chunks/{BwE1zFLP.js → Ca2hAPtg.js} +1 -1
- package/build/client/_app/immutable/chunks/{D7AzvARu.js → Cau42fzj.js} +1 -1
- package/build/client/_app/immutable/chunks/{Ds2Jk9YM.js → CdGkhiK1.js} +1 -1
- package/build/client/_app/immutable/chunks/{Cnk3veQv.js → CgXGAMiM.js} +1 -1
- package/build/client/_app/immutable/chunks/{zzrVTw61.js → Cgy55mAM.js} +1 -1
- package/build/client/_app/immutable/chunks/{C6G9eLNg.js → CoA3knMy.js} +1 -1
- package/build/client/_app/immutable/chunks/{QOziFLFL.js → CpM0mLd3.js} +1 -1
- package/build/client/_app/immutable/chunks/{et9SQoBt.js → Cpo2wFOF.js} +41 -41
- package/build/client/_app/immutable/chunks/{D1smdH78.js → CttwL4ra.js} +1 -1
- package/build/client/_app/immutable/chunks/CxAtYDDR.js +1 -0
- package/build/client/_app/immutable/chunks/{B_m78aJo.js → D-H-CPld.js} +1 -1
- package/build/client/_app/immutable/chunks/{BcL-TGiq.js → D7CFUndx.js} +1 -1
- package/build/client/_app/immutable/chunks/{66S44dU2.js → DOtAj_GZ.js} +1 -1
- package/build/client/_app/immutable/chunks/{_8lNgEhN.js → DRKEKjIK.js} +1 -1
- package/build/client/_app/immutable/chunks/{C9sq1NiT.js → DTbrt1rD.js} +1 -1
- package/build/client/_app/immutable/chunks/{Rt06R0BH.js → DXS_Dtjh.js} +1 -1
- package/build/client/_app/immutable/chunks/{ChXJ3_8d.js → Dl1NBjmH.js} +1 -1
- package/build/client/_app/immutable/chunks/{yJkIcB-2.js → DmsNVoN7.js} +1 -1
- package/build/client/_app/immutable/chunks/{DYmr2Cu_.js → Dw-HKxM8.js} +1 -1
- package/build/client/_app/immutable/chunks/{CjU8zlr4.js → Dx677rWL.js} +1 -1
- package/build/client/_app/immutable/chunks/{B5wH4gxC.js → YynfXFWu.js} +1 -1
- package/build/client/_app/immutable/chunks/{C40UEiDa.js → emz7bQvw.js} +1 -1
- package/build/client/_app/immutable/chunks/{CEkljthY.js → jjKz4r1f.js} +1 -1
- package/build/client/_app/immutable/chunks/{D6mQqXUs.js → rWhUOneE.js} +1 -1
- package/build/client/_app/immutable/chunks/rqqKsjKJ.js +3 -0
- package/build/client/_app/immutable/chunks/{DV6acRrl.js → sQLF7fUM.js} +1 -1
- package/build/client/_app/immutable/entry/{app.drqszXmO.js → app.D4TrRYU9.js} +2 -2
- package/build/client/_app/immutable/entry/start.DkzPUV1T.js +1 -0
- package/build/client/_app/immutable/nodes/{1.BLhKeqW1.js → 1.D-cDAILr.js} +1 -1
- package/build/client/_app/immutable/nodes/{2.CNfAa1lN.js → 2.ZFWOqsMm.js} +1 -1
- package/build/client/_app/immutable/nodes/3.aypDVtOE.js +1 -0
- package/build/client/_app/version.json +1 -1
- package/build/server/chunks/{0-FD3Yst2W.js → 0-F8UDIQlw.js} +3 -3
- package/build/server/chunks/{0-FD3Yst2W.js.map → 0-F8UDIQlw.js.map} +1 -1
- package/build/server/chunks/{1-DPyxh1rx.js → 1-pb-FmDKD.js} +2 -2
- package/build/server/chunks/{1-DPyxh1rx.js.map → 1-pb-FmDKD.js.map} +1 -1
- package/build/server/chunks/{2-C9Pr1aKN.js → 2-tND4IT0j.js} +4 -4
- package/build/server/chunks/{2-C9Pr1aKN.js.map → 2-tND4IT0j.js.map} +1 -1
- package/build/server/chunks/{3-CsZto47z.js → 3-BnyLFe2W.js} +4 -4
- package/build/server/chunks/{3-CsZto47z.js.map → 3-BnyLFe2W.js.map} +1 -1
- package/build/server/chunks/{_page.svelte-C-jd6GOL.js → _page.svelte-BXgDoamA.js} +68 -60
- package/build/server/chunks/_page.svelte-BXgDoamA.js.map +1 -0
- package/build/server/chunks/{_page.svelte-CWIhxW51.js → _page.svelte-ByTjHRUq.js} +2 -2
- package/build/server/chunks/{_page.svelte-CWIhxW51.js.map → _page.svelte-ByTjHRUq.js.map} +1 -1
- package/build/server/chunks/{_server.ts-CpPXj3O_.js → _server.ts-BkcqX0Gw.js} +2 -2
- package/build/server/chunks/{_server.ts-CpPXj3O_.js.map → _server.ts-BkcqX0Gw.js.map} +1 -1
- package/build/server/chunks/{_server.ts-DJbYluhf.js → _server.ts-C9Rz5pqb.js} +2 -2
- package/build/server/chunks/{_server.ts-DJbYluhf.js.map → _server.ts-C9Rz5pqb.js.map} +1 -1
- package/build/server/chunks/{_server.ts-CY7NfbtD.js → _server.ts-DCa-_qe7.js} +5 -2
- package/build/server/chunks/_server.ts-DCa-_qe7.js.map +1 -0
- package/build/server/chunks/_server.ts-DVH0ejp0.js +12 -0
- package/build/server/chunks/_server.ts-DVH0ejp0.js.map +1 -0
- package/build/server/chunks/{_server.ts-CtgVvBfR.js → _server.ts-aWI5JVTi.js} +2 -2
- package/build/server/chunks/{_server.ts-CtgVvBfR.js.map → _server.ts-aWI5JVTi.js.map} +1 -1
- package/build/server/chunks/{_server.ts-K9S2g_-L.js → _server.ts-b4ynvdd4.js} +2 -2
- package/build/server/chunks/{_server.ts-K9S2g_-L.js.map → _server.ts-b4ynvdd4.js.map} +1 -1
- package/build/server/chunks/{_server.ts-DI8tBJml.js → _server.ts-r59HGb-h.js} +2 -2
- package/build/server/chunks/{_server.ts-DI8tBJml.js.map → _server.ts-r59HGb-h.js.map} +1 -1
- package/build/server/chunks/{hooks.server-BHuIRhU1.js → hooks.server-CeNxBnIX.js} +2 -4
- package/build/server/chunks/hooks.server-CeNxBnIX.js.map +1 -0
- package/build/server/chunks/{session-manager-CBzriHWC.js → session-manager-Vdr0BxAo.js} +7 -12
- package/build/server/chunks/session-manager-Vdr0BxAo.js.map +1 -0
- package/build/server/chunks/{status-BrtsDZqP.js → status-BV9je7QE.js} +10 -2
- package/build/server/chunks/status-BV9je7QE.js.map +1 -0
- package/build/server/index.js +2 -2
- package/build/server/index.js.map +1 -1
- package/build/server/manifest.js +12 -12
- package/build/server/manifest.js.map +1 -1
- package/dist/cli/commands/review.js +186 -39
- package/dist/cli/index.js +78 -9
- package/dist/cli/markdown-parser.js +3 -3
- package/dist/cli/markdown-to-plan.js +1 -19
- package/dist/cli/utils.js +14 -13
- package/package.json +13 -4
- package/build/client/_app/immutable/assets/0.DdHQkxqS.css +0 -1
- package/build/client/_app/immutable/chunks/9io9WUbM.js +0 -2
- package/build/client/_app/immutable/chunks/B1KfJkVF.js +0 -1
- package/build/client/_app/immutable/chunks/D5TNeoIz.js +0 -1
- package/build/client/_app/immutable/chunks/DtlciwlI.js +0 -3
- package/build/client/_app/immutable/entry/start.C0P0in9X.js +0 -1
- package/build/client/_app/immutable/nodes/3.nevoqbPf.js +0 -1
- package/build/server/chunks/_page.svelte-C-jd6GOL.js.map +0 -1
- package/build/server/chunks/_server.ts-CY7NfbtD.js.map +0 -1
- package/build/server/chunks/_server.ts-DAVgIfvo.js +0 -11
- package/build/server/chunks/_server.ts-DAVgIfvo.js.map +0 -1
- package/build/server/chunks/hooks.server-BHuIRhU1.js.map +0 -1
- package/build/server/chunks/session-manager-CBzriHWC.js.map +0 -1
- package/build/server/chunks/status-BrtsDZqP.js.map +0 -1
- /package/build/client/_app/immutable/nodes/{0.DJ6Q_WzM.js → 0.BZ6p9IRV.js} +0 -0
package/build/server/manifest.js
CHANGED
|
@@ -10,12 +10,12 @@ return {
|
|
|
10
10
|
assets: new Set(["favicon.png"]),
|
|
11
11
|
mimeTypes: {".png":"image/png"},
|
|
12
12
|
_: {
|
|
13
|
-
client: {start:"_app/immutable/entry/start.
|
|
13
|
+
client: {start:"_app/immutable/entry/start.DkzPUV1T.js",app:"_app/immutable/entry/app.D4TrRYU9.js",imports:["_app/immutable/entry/start.DkzPUV1T.js","_app/immutable/chunks/rqqKsjKJ.js","_app/immutable/chunks/CD_kQCcy.js","_app/immutable/chunks/BfABZbDO.js","_app/immutable/entry/app.D4TrRYU9.js","_app/immutable/chunks/1uq0WVax.js","_app/immutable/chunks/CD_kQCcy.js","_app/immutable/chunks/wOfVBGZS.js","_app/immutable/chunks/Dl-inTne.js","_app/immutable/chunks/BfABZbDO.js","_app/immutable/chunks/DteI5BLO.js","_app/immutable/chunks/2wZlHG5k.js"],stylesheets:[],fonts:[],uses_env_dynamic_public:false},
|
|
14
14
|
nodes: [
|
|
15
|
-
__memo(() => import('./chunks/0-
|
|
16
|
-
__memo(() => import('./chunks/1-
|
|
17
|
-
__memo(() => import('./chunks/2-
|
|
18
|
-
__memo(() => import('./chunks/3-
|
|
15
|
+
__memo(() => import('./chunks/0-F8UDIQlw.js')),
|
|
16
|
+
__memo(() => import('./chunks/1-pb-FmDKD.js')),
|
|
17
|
+
__memo(() => import('./chunks/2-tND4IT0j.js')),
|
|
18
|
+
__memo(() => import('./chunks/3-BnyLFe2W.js'))
|
|
19
19
|
],
|
|
20
20
|
remotes: {
|
|
21
21
|
|
|
@@ -33,49 +33,49 @@ return {
|
|
|
33
33
|
pattern: /^\/api\/health\/?$/,
|
|
34
34
|
params: [],
|
|
35
35
|
page: null,
|
|
36
|
-
endpoint: __memo(() => import('./chunks/_server.ts-
|
|
36
|
+
endpoint: __memo(() => import('./chunks/_server.ts-DVH0ejp0.js'))
|
|
37
37
|
},
|
|
38
38
|
{
|
|
39
39
|
id: "/api/sessions",
|
|
40
40
|
pattern: /^\/api\/sessions\/?$/,
|
|
41
41
|
params: [],
|
|
42
42
|
page: null,
|
|
43
|
-
endpoint: __memo(() => import('./chunks/_server.ts-
|
|
43
|
+
endpoint: __memo(() => import('./chunks/_server.ts-aWI5JVTi.js'))
|
|
44
44
|
},
|
|
45
45
|
{
|
|
46
46
|
id: "/api/sessions/[sessionId]",
|
|
47
47
|
pattern: /^\/api\/sessions\/([^/]+?)\/?$/,
|
|
48
48
|
params: [{"name":"sessionId","optional":false,"rest":false,"chained":false}],
|
|
49
49
|
page: null,
|
|
50
|
-
endpoint: __memo(() => import('./chunks/_server.ts-
|
|
50
|
+
endpoint: __memo(() => import('./chunks/_server.ts-C9Rz5pqb.js'))
|
|
51
51
|
},
|
|
52
52
|
{
|
|
53
53
|
id: "/api/sessions/[sessionId]/approve",
|
|
54
54
|
pattern: /^\/api\/sessions\/([^/]+?)\/approve\/?$/,
|
|
55
55
|
params: [{"name":"sessionId","optional":false,"rest":false,"chained":false}],
|
|
56
56
|
page: null,
|
|
57
|
-
endpoint: __memo(() => import('./chunks/_server.ts-
|
|
57
|
+
endpoint: __memo(() => import('./chunks/_server.ts-r59HGb-h.js'))
|
|
58
58
|
},
|
|
59
59
|
{
|
|
60
60
|
id: "/api/sessions/[sessionId]/feedback",
|
|
61
61
|
pattern: /^\/api\/sessions\/([^/]+?)\/feedback\/?$/,
|
|
62
62
|
params: [{"name":"sessionId","optional":false,"rest":false,"chained":false}],
|
|
63
63
|
page: null,
|
|
64
|
-
endpoint: __memo(() => import('./chunks/_server.ts-
|
|
64
|
+
endpoint: __memo(() => import('./chunks/_server.ts-DCa-_qe7.js'))
|
|
65
65
|
},
|
|
66
66
|
{
|
|
67
67
|
id: "/api/sessions/[sessionId]/versions",
|
|
68
68
|
pattern: /^\/api\/sessions\/([^/]+?)\/versions\/?$/,
|
|
69
69
|
params: [{"name":"sessionId","optional":false,"rest":false,"chained":false}],
|
|
70
70
|
page: null,
|
|
71
|
-
endpoint: __memo(() => import('./chunks/_server.ts-
|
|
71
|
+
endpoint: __memo(() => import('./chunks/_server.ts-BkcqX0Gw.js'))
|
|
72
72
|
},
|
|
73
73
|
{
|
|
74
74
|
id: "/api/sessions/[sessionId]/versions/[version]",
|
|
75
75
|
pattern: /^\/api\/sessions\/([^/]+?)\/versions\/([^/]+?)\/?$/,
|
|
76
76
|
params: [{"name":"sessionId","optional":false,"rest":false,"chained":false},{"name":"version","optional":false,"rest":false,"chained":false}],
|
|
77
77
|
page: null,
|
|
78
|
-
endpoint: __memo(() => import('./chunks/_server.ts-
|
|
78
|
+
endpoint: __memo(() => import('./chunks/_server.ts-b4ynvdd4.js'))
|
|
79
79
|
},
|
|
80
80
|
{
|
|
81
81
|
id: "/api/sse/[sessionId]",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.js","sources":["../../.svelte-kit/adapter-node/manifest.js"],"sourcesContent":["export const manifest = (() => {\nfunction __memo(fn) {\n\tlet value;\n\treturn () => value ??= (value = fn());\n}\n\nreturn {\n\tappDir: \"_app\",\n\tappPath: \"_app\",\n\tassets: new Set([\"favicon.png\"]),\n\tmimeTypes: {\".png\":\"image/png\"},\n\t_: {\n\t\tclient: {start:\"_app/immutable/entry/start.
|
|
1
|
+
{"version":3,"file":"manifest.js","sources":["../../.svelte-kit/adapter-node/manifest.js"],"sourcesContent":["export const manifest = (() => {\nfunction __memo(fn) {\n\tlet value;\n\treturn () => value ??= (value = fn());\n}\n\nreturn {\n\tappDir: \"_app\",\n\tappPath: \"_app\",\n\tassets: new Set([\"favicon.png\"]),\n\tmimeTypes: {\".png\":\"image/png\"},\n\t_: {\n\t\tclient: {start:\"_app/immutable/entry/start.DkzPUV1T.js\",app:\"_app/immutable/entry/app.D4TrRYU9.js\",imports:[\"_app/immutable/entry/start.DkzPUV1T.js\",\"_app/immutable/chunks/rqqKsjKJ.js\",\"_app/immutable/chunks/CD_kQCcy.js\",\"_app/immutable/chunks/BfABZbDO.js\",\"_app/immutable/entry/app.D4TrRYU9.js\",\"_app/immutable/chunks/1uq0WVax.js\",\"_app/immutable/chunks/CD_kQCcy.js\",\"_app/immutable/chunks/wOfVBGZS.js\",\"_app/immutable/chunks/Dl-inTne.js\",\"_app/immutable/chunks/BfABZbDO.js\",\"_app/immutable/chunks/DteI5BLO.js\",\"_app/immutable/chunks/2wZlHG5k.js\"],stylesheets:[],fonts:[],uses_env_dynamic_public:false},\n\t\tnodes: [\n\t\t\t__memo(() => import('./nodes/0.js')),\n\t\t\t__memo(() => import('./nodes/1.js')),\n\t\t\t__memo(() => import('./nodes/2.js')),\n\t\t\t__memo(() => import('./nodes/3.js'))\n\t\t],\n\t\tremotes: {\n\t\t\t\n\t\t},\n\t\troutes: [\n\t\t\t{\n\t\t\t\tid: \"/\",\n\t\t\t\tpattern: /^\\/$/,\n\t\t\t\tparams: [],\n\t\t\t\tpage: { layouts: [0,], errors: [1,], leaf: 2 },\n\t\t\t\tendpoint: null\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"/api/health\",\n\t\t\t\tpattern: /^\\/api\\/health\\/?$/,\n\t\t\t\tparams: [],\n\t\t\t\tpage: null,\n\t\t\t\tendpoint: __memo(() => import('./entries/endpoints/api/health/_server.ts.js'))\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"/api/sessions\",\n\t\t\t\tpattern: /^\\/api\\/sessions\\/?$/,\n\t\t\t\tparams: [],\n\t\t\t\tpage: null,\n\t\t\t\tendpoint: __memo(() => import('./entries/endpoints/api/sessions/_server.ts.js'))\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"/api/sessions/[sessionId]\",\n\t\t\t\tpattern: /^\\/api\\/sessions\\/([^/]+?)\\/?$/,\n\t\t\t\tparams: [{\"name\":\"sessionId\",\"optional\":false,\"rest\":false,\"chained\":false}],\n\t\t\t\tpage: null,\n\t\t\t\tendpoint: __memo(() => import('./entries/endpoints/api/sessions/_sessionId_/_server.ts.js'))\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"/api/sessions/[sessionId]/approve\",\n\t\t\t\tpattern: /^\\/api\\/sessions\\/([^/]+?)\\/approve\\/?$/,\n\t\t\t\tparams: [{\"name\":\"sessionId\",\"optional\":false,\"rest\":false,\"chained\":false}],\n\t\t\t\tpage: null,\n\t\t\t\tendpoint: __memo(() => import('./entries/endpoints/api/sessions/_sessionId_/approve/_server.ts.js'))\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"/api/sessions/[sessionId]/feedback\",\n\t\t\t\tpattern: /^\\/api\\/sessions\\/([^/]+?)\\/feedback\\/?$/,\n\t\t\t\tparams: [{\"name\":\"sessionId\",\"optional\":false,\"rest\":false,\"chained\":false}],\n\t\t\t\tpage: null,\n\t\t\t\tendpoint: __memo(() => import('./entries/endpoints/api/sessions/_sessionId_/feedback/_server.ts.js'))\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"/api/sessions/[sessionId]/versions\",\n\t\t\t\tpattern: /^\\/api\\/sessions\\/([^/]+?)\\/versions\\/?$/,\n\t\t\t\tparams: [{\"name\":\"sessionId\",\"optional\":false,\"rest\":false,\"chained\":false}],\n\t\t\t\tpage: null,\n\t\t\t\tendpoint: __memo(() => import('./entries/endpoints/api/sessions/_sessionId_/versions/_server.ts.js'))\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"/api/sessions/[sessionId]/versions/[version]\",\n\t\t\t\tpattern: /^\\/api\\/sessions\\/([^/]+?)\\/versions\\/([^/]+?)\\/?$/,\n\t\t\t\tparams: [{\"name\":\"sessionId\",\"optional\":false,\"rest\":false,\"chained\":false},{\"name\":\"version\",\"optional\":false,\"rest\":false,\"chained\":false}],\n\t\t\t\tpage: null,\n\t\t\t\tendpoint: __memo(() => import('./entries/endpoints/api/sessions/_sessionId_/versions/_version_/_server.ts.js'))\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"/api/sse/[sessionId]\",\n\t\t\t\tpattern: /^\\/api\\/sse\\/([^/]+?)\\/?$/,\n\t\t\t\tparams: [{\"name\":\"sessionId\",\"optional\":false,\"rest\":false,\"chained\":false}],\n\t\t\t\tpage: null,\n\t\t\t\tendpoint: __memo(() => import('./entries/endpoints/api/sse/_sessionId_/_server.ts.js'))\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"/plan/[sessionId]\",\n\t\t\t\tpattern: /^\\/plan\\/([^/]+?)\\/?$/,\n\t\t\t\tparams: [{\"name\":\"sessionId\",\"optional\":false,\"rest\":false,\"chained\":false}],\n\t\t\t\tpage: { layouts: [0,], errors: [1,], leaf: 3 },\n\t\t\t\tendpoint: null\n\t\t\t}\n\t\t],\n\t\tprerendered_routes: new Set([]),\n\t\tmatchers: async () => {\n\t\t\t\n\t\t\treturn { };\n\t\t},\n\t\tserver_assets: {}\n\t}\n}\n})();\n\nexport const prerendered = new Set([]);\n\nexport const base = \"\";"],"names":[],"mappings":"AAAY,MAAC,QAAQ,GAAG,CAAC,MAAM;AAC/B,SAAS,MAAM,CAAC,EAAE,EAAE;AACpB,CAAC,IAAI,KAAK;AACV,CAAC,OAAO,MAAM,KAAK,MAAM,KAAK,GAAG,EAAE,EAAE,CAAC;AACtC;;AAEA,OAAO;AACP,CAAC,MAAM,EAAE,MAAM;AACf,CAAC,OAAO,EAAE,MAAM;AAChB,CAAC,MAAM,EAAE,IAAI,GAAG,CAAC,CAAC,aAAa,CAAC,CAAC;AACjC,CAAC,SAAS,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC;AAChC,CAAC,CAAC,EAAE;AACJ,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,wCAAwC,CAAC,GAAG,CAAC,sCAAsC,CAAC,OAAO,CAAC,CAAC,wCAAwC,CAAC,mCAAmC,CAAC,mCAAmC,CAAC,mCAAmC,CAAC,sCAAsC,CAAC,mCAAmC,CAAC,mCAAmC,CAAC,mCAAmC,CAAC,mCAAmC,CAAC,mCAAmC,CAAC,mCAAmC,CAAC,mCAAmC,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,uBAAuB,CAAC,KAAK,CAAC;AAC7lB,EAAE,KAAK,EAAE;AACT,GAAG,MAAM,CAAC,MAAM,OAAO,wBAAc,CAAC,CAAC;AACvC,GAAG,MAAM,CAAC,MAAM,OAAO,wBAAc,CAAC,CAAC;AACvC,GAAG,MAAM,CAAC,MAAM,OAAO,wBAAc,CAAC,CAAC;AACvC,GAAG,MAAM,CAAC,MAAM,OAAO,wBAAc,CAAC;AACtC,GAAG;AACH,EAAE,OAAO,EAAE;AACX;AACA,GAAG;AACH,EAAE,MAAM,EAAE;AACV,GAAG;AACH,IAAI,EAAE,EAAE,GAAG;AACX,IAAI,OAAO,EAAE,MAAM;AACnB,IAAI,MAAM,EAAE,EAAE;AACd,IAAI,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE;AAClD,IAAI,QAAQ,EAAE;AACd,IAAI;AACJ,GAAG;AACH,IAAI,EAAE,EAAE,aAAa;AACrB,IAAI,OAAO,EAAE,oBAAoB;AACjC,IAAI,MAAM,EAAE,EAAE;AACd,IAAI,IAAI,EAAE,IAAI;AACd,IAAI,QAAQ,EAAE,MAAM,CAAC,MAAM,OAAO,iCAA8C,CAAC;AACjF,IAAI;AACJ,GAAG;AACH,IAAI,EAAE,EAAE,eAAe;AACvB,IAAI,OAAO,EAAE,sBAAsB;AACnC,IAAI,MAAM,EAAE,EAAE;AACd,IAAI,IAAI,EAAE,IAAI;AACd,IAAI,QAAQ,EAAE,MAAM,CAAC,MAAM,OAAO,iCAAgD,CAAC;AACnF,IAAI;AACJ,GAAG;AACH,IAAI,EAAE,EAAE,2BAA2B;AACnC,IAAI,OAAO,EAAE,gCAAgC;AAC7C,IAAI,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AAChF,IAAI,IAAI,EAAE,IAAI;AACd,IAAI,QAAQ,EAAE,MAAM,CAAC,MAAM,OAAO,iCAA4D,CAAC;AAC/F,IAAI;AACJ,GAAG;AACH,IAAI,EAAE,EAAE,mCAAmC;AAC3C,IAAI,OAAO,EAAE,yCAAyC;AACtD,IAAI,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AAChF,IAAI,IAAI,EAAE,IAAI;AACd,IAAI,QAAQ,EAAE,MAAM,CAAC,MAAM,OAAO,iCAAoE,CAAC;AACvG,IAAI;AACJ,GAAG;AACH,IAAI,EAAE,EAAE,oCAAoC;AAC5C,IAAI,OAAO,EAAE,0CAA0C;AACvD,IAAI,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AAChF,IAAI,IAAI,EAAE,IAAI;AACd,IAAI,QAAQ,EAAE,MAAM,CAAC,MAAM,OAAO,iCAAqE,CAAC;AACxG,IAAI;AACJ,GAAG;AACH,IAAI,EAAE,EAAE,oCAAoC;AAC5C,IAAI,OAAO,EAAE,0CAA0C;AACvD,IAAI,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AAChF,IAAI,IAAI,EAAE,IAAI;AACd,IAAI,QAAQ,EAAE,MAAM,CAAC,MAAM,OAAO,iCAAqE,CAAC;AACxG,IAAI;AACJ,GAAG;AACH,IAAI,EAAE,EAAE,8CAA8C;AACtD,IAAI,OAAO,EAAE,oDAAoD;AACjE,IAAI,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AACjJ,IAAI,IAAI,EAAE,IAAI;AACd,IAAI,QAAQ,EAAE,MAAM,CAAC,MAAM,OAAO,iCAA+E,CAAC;AAClH,IAAI;AACJ,GAAG;AACH,IAAI,EAAE,EAAE,sBAAsB;AAC9B,IAAI,OAAO,EAAE,2BAA2B;AACxC,IAAI,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AAChF,IAAI,IAAI,EAAE,IAAI;AACd,IAAI,QAAQ,EAAE,MAAM,CAAC,MAAM,OAAO,iCAAuD,CAAC;AAC1F,IAAI;AACJ,GAAG;AACH,IAAI,EAAE,EAAE,mBAAmB;AAC3B,IAAI,OAAO,EAAE,uBAAuB;AACpC,IAAI,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AAChF,IAAI,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE;AAClD,IAAI,QAAQ,EAAE;AACd;AACA,GAAG;AACH,EAAE,kBAAkB,EAAE,IAAI,GAAG,CAAC,EAAE,CAAC;AACjC,EAAE,QAAQ,EAAE,YAAY;AACxB;AACA,GAAG,OAAO,IAAI;AACd,EAAE,CAAC;AACH,EAAE,aAAa,EAAE;AACjB;AACA;AACA,CAAC;;AAEW,MAAC,WAAW,GAAG,IAAI,GAAG,CAAC,EAAE;;AAEzB,MAAC,IAAI,GAAG;;;;"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readFileSync, writeFileSync, existsSync } from "node:fs";
|
|
1
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync, unlinkSync } from "node:fs";
|
|
2
2
|
import { resolve, dirname, join } from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { spawn, execSync } from "node:child_process";
|
|
@@ -6,7 +6,8 @@ import { createServer } from "node:net";
|
|
|
6
6
|
import { watch } from "chokidar";
|
|
7
7
|
import { parseMarkdownToPlan, sessionIdFromPath } from "../markdown-to-plan.js";
|
|
8
8
|
import { outputJson } from "../output.js";
|
|
9
|
-
|
|
9
|
+
const EXIT_APPROVED = 0;
|
|
10
|
+
const EXIT_NEEDS_WORK = 3;
|
|
10
11
|
const DEFAULT_BASE_PORT = 5181;
|
|
11
12
|
const MAX_PORT = 5199;
|
|
12
13
|
function getPackageDir() {
|
|
@@ -30,7 +31,55 @@ async function checkHealth(port) {
|
|
|
30
31
|
return null;
|
|
31
32
|
}
|
|
32
33
|
}
|
|
34
|
+
function lockFilePath(sessionDir) {
|
|
35
|
+
return join(sessionDir, ".server-lock.json");
|
|
36
|
+
}
|
|
37
|
+
function readLock(sessionDir) {
|
|
38
|
+
const lockPath = lockFilePath(sessionDir);
|
|
39
|
+
if (!existsSync(lockPath))
|
|
40
|
+
return null;
|
|
41
|
+
try {
|
|
42
|
+
return JSON.parse(readFileSync(lockPath, "utf-8"));
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function writeLock(sessionDir, port, pid) {
|
|
49
|
+
mkdirSync(sessionDir, { recursive: true });
|
|
50
|
+
writeFileSync(lockFilePath(sessionDir), JSON.stringify({ port, pid }));
|
|
51
|
+
}
|
|
52
|
+
function clearLock(sessionDir) {
|
|
53
|
+
try {
|
|
54
|
+
unlinkSync(lockFilePath(sessionDir));
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// ignore
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function isPidAlive(pid) {
|
|
61
|
+
try {
|
|
62
|
+
process.kill(pid, 0);
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
33
69
|
async function findExistingServer(sessionDir, basePort) {
|
|
70
|
+
// Check lock file first (fast path, avoids port scan race)
|
|
71
|
+
const lock = readLock(sessionDir);
|
|
72
|
+
if (lock) {
|
|
73
|
+
if (isPidAlive(lock.pid)) {
|
|
74
|
+
const health = await checkHealth(lock.port);
|
|
75
|
+
if (health && health.sessionDir === sessionDir) {
|
|
76
|
+
return lock.port;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Stale lock — remove it
|
|
80
|
+
clearLock(sessionDir);
|
|
81
|
+
}
|
|
82
|
+
// Fallback: scan ports (handles lock-less legacy servers)
|
|
34
83
|
for (let port = basePort; port <= MAX_PORT; port++) {
|
|
35
84
|
const health = await checkHealth(port);
|
|
36
85
|
if (health && health.sessionDir === sessionDir) {
|
|
@@ -74,6 +123,7 @@ function startServer(sessionDir, port) {
|
|
|
74
123
|
detached: true,
|
|
75
124
|
});
|
|
76
125
|
child.unref();
|
|
126
|
+
const pid = child.pid;
|
|
77
127
|
let attempts = 0;
|
|
78
128
|
const maxAttempts = 30;
|
|
79
129
|
const interval = setInterval(async () => {
|
|
@@ -87,7 +137,7 @@ function startServer(sessionDir, port) {
|
|
|
87
137
|
clearTimeout(timeout);
|
|
88
138
|
if (res.ok) {
|
|
89
139
|
clearInterval(interval);
|
|
90
|
-
resolvePromise();
|
|
140
|
+
resolvePromise(pid);
|
|
91
141
|
}
|
|
92
142
|
}
|
|
93
143
|
catch {
|
|
@@ -99,6 +149,18 @@ function startServer(sessionDir, port) {
|
|
|
99
149
|
}, 500);
|
|
100
150
|
});
|
|
101
151
|
}
|
|
152
|
+
async function launchServer(sessionDir, port) {
|
|
153
|
+
process.stdout.write(`Starting Plan Assistant server on port ${port}...`);
|
|
154
|
+
try {
|
|
155
|
+
const pid = await startServer(sessionDir, port);
|
|
156
|
+
writeLock(sessionDir, port, pid);
|
|
157
|
+
console.log(" ready.");
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
console.error(` failed: ${err}`);
|
|
161
|
+
process.exit(1);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
102
164
|
function openBrowser(url) {
|
|
103
165
|
try {
|
|
104
166
|
const cmd = process.platform === "darwin"
|
|
@@ -164,9 +226,40 @@ export async function review(args) {
|
|
|
164
226
|
for (const warning of warnings) {
|
|
165
227
|
console.error(`Warning: ${warning}`);
|
|
166
228
|
}
|
|
229
|
+
if (plan.phases.length === 0) {
|
|
230
|
+
console.error(`
|
|
231
|
+
⚠ No phases found — plan will appear empty in the browser.
|
|
232
|
+
|
|
233
|
+
Use the correct format for phases:
|
|
234
|
+
|
|
235
|
+
## Phase 1: Phase Name
|
|
236
|
+
|
|
237
|
+
### Changes Required:
|
|
238
|
+
|
|
239
|
+
#### 1. Component Name
|
|
240
|
+
**File**: \`path/to/file.ext\`
|
|
241
|
+
Description of what to change.
|
|
242
|
+
|
|
243
|
+
### Success Criteria:
|
|
244
|
+
- [ ] \`npm test\`
|
|
245
|
+
|
|
246
|
+
Accepted phase keywords: "Phase N:", "Step N:", "Task N:" (H2 headings)
|
|
247
|
+
Run \`npx plan-assistant init --output <file>\` to generate a correctly-formatted template.
|
|
248
|
+
`);
|
|
249
|
+
}
|
|
167
250
|
// Write session files
|
|
168
|
-
|
|
169
|
-
|
|
251
|
+
mkdirSync(sessionPath, { recursive: true });
|
|
252
|
+
mkdirSync(join(sessionPath, "versions"), { recursive: true });
|
|
253
|
+
// Clear stale feedback from previous review cycle
|
|
254
|
+
const oldFeedbackPath = join(sessionPath, "feedback.json");
|
|
255
|
+
if (existsSync(oldFeedbackPath)) {
|
|
256
|
+
try {
|
|
257
|
+
unlinkSync(oldFeedbackPath);
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
// ignore
|
|
261
|
+
}
|
|
262
|
+
}
|
|
170
263
|
const meta = {
|
|
171
264
|
id: sessionId,
|
|
172
265
|
planTitle: plan.meta.title,
|
|
@@ -183,37 +276,18 @@ export async function review(args) {
|
|
|
183
276
|
// Find existing server for this session dir or start a new one
|
|
184
277
|
const basePort = requestedPort ?? DEFAULT_BASE_PORT;
|
|
185
278
|
let port = await findExistingServer(sessionDir, basePort);
|
|
186
|
-
if (port) {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
process.exit(1);
|
|
194
|
-
}
|
|
195
|
-
port = requestedPort;
|
|
196
|
-
process.stdout.write(`Starting Plan Assistant server on port ${port}...`);
|
|
197
|
-
try {
|
|
198
|
-
await startServer(sessionDir, port);
|
|
199
|
-
console.log(" ready.");
|
|
200
|
-
}
|
|
201
|
-
catch (err) {
|
|
202
|
-
console.error(` failed: ${err}`);
|
|
203
|
-
process.exit(1);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
else {
|
|
207
|
-
port = await findFreePort(basePort);
|
|
208
|
-
process.stdout.write(`Starting Plan Assistant server on port ${port}...`);
|
|
209
|
-
try {
|
|
210
|
-
await startServer(sessionDir, port);
|
|
211
|
-
console.log(" ready.");
|
|
279
|
+
if (!port) {
|
|
280
|
+
if (requestedPort) {
|
|
281
|
+
if (!(await isPortFree(requestedPort))) {
|
|
282
|
+
console.error(`Error: Port ${requestedPort} is already in use`);
|
|
283
|
+
process.exit(1);
|
|
284
|
+
}
|
|
285
|
+
port = requestedPort;
|
|
212
286
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
process.exit(1);
|
|
287
|
+
else {
|
|
288
|
+
port = await findFreePort(basePort);
|
|
216
289
|
}
|
|
290
|
+
await launchServer(sessionDir, port);
|
|
217
291
|
}
|
|
218
292
|
const url = `http://localhost:${port}/plan/${sessionId}`;
|
|
219
293
|
const feedbackPath = join(sessionPath, "feedback.json");
|
|
@@ -225,16 +299,24 @@ export async function review(args) {
|
|
|
225
299
|
feedbackPath,
|
|
226
300
|
});
|
|
227
301
|
openBrowser(url);
|
|
302
|
+
const noWait = args.flags["no-wait"] === true;
|
|
228
303
|
console.error(`\nPlan Assistant`);
|
|
229
304
|
console.error(` Review: ${url}`);
|
|
230
305
|
console.error(` Session: ${sessionPath}`);
|
|
231
306
|
console.error(` Feedback: ${feedbackPath}`);
|
|
232
|
-
|
|
307
|
+
if (noWait) {
|
|
308
|
+
console.error(`\nWatching ${absolutePath} for changes...`);
|
|
309
|
+
console.error(`Run \`plan-assistant status --wait ${markdownFile}\` to wait for feedback.`);
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
console.error(`\nWatching for changes and waiting for your feedback (Approve / Request Changes)...`);
|
|
313
|
+
console.error(`Press Ctrl+C to stop without waiting.`);
|
|
314
|
+
}
|
|
233
315
|
// Watch markdown file for changes
|
|
234
|
-
const
|
|
316
|
+
const mdWatcher = watch(absolutePath, {
|
|
235
317
|
awaitWriteFinish: { stabilityThreshold: 300, pollInterval: 100 },
|
|
236
318
|
});
|
|
237
|
-
|
|
319
|
+
mdWatcher.on("change", () => {
|
|
238
320
|
try {
|
|
239
321
|
const updated = readFileSync(absolutePath, "utf-8");
|
|
240
322
|
const existingPlan = JSON.parse(readFileSync(existingPlanPath, "utf-8"));
|
|
@@ -243,6 +325,9 @@ export async function review(args) {
|
|
|
243
325
|
for (const warning of newWarnings) {
|
|
244
326
|
console.error(`Warning: ${warning}`);
|
|
245
327
|
}
|
|
328
|
+
if (newPlan.phases.length === 0) {
|
|
329
|
+
console.error(`⚠ No phases found after reload — check format. Run \`npx plan-assistant init\` for a template.`);
|
|
330
|
+
}
|
|
246
331
|
writeFileSync(join(sessionPath, "plan.json"), JSON.stringify(newPlan, null, 2));
|
|
247
332
|
writeFileSync(join(sessionPath, "versions", `v${newVersion}.json`), JSON.stringify(newPlan, null, 2));
|
|
248
333
|
console.error(`[${new Date().toLocaleTimeString()}] Plan updated (v${newVersion})`);
|
|
@@ -251,10 +336,72 @@ export async function review(args) {
|
|
|
251
336
|
console.error(`Error re-parsing markdown: ${err}`);
|
|
252
337
|
}
|
|
253
338
|
});
|
|
254
|
-
//
|
|
339
|
+
// Wait for feedback unless --no-wait
|
|
340
|
+
if (!noWait) {
|
|
341
|
+
await waitForFeedback(feedbackPath, sessionId, plan.meta.title, mdWatcher);
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
// Keep process alive (--no-wait mode)
|
|
255
345
|
process.on("SIGINT", () => {
|
|
256
|
-
|
|
346
|
+
mdWatcher.close();
|
|
257
347
|
console.error("\nStopped watching.");
|
|
258
348
|
process.exit(0);
|
|
259
349
|
});
|
|
260
350
|
}
|
|
351
|
+
async function waitForFeedback(feedbackPath, sessionId, planTitle, mdWatcher) {
|
|
352
|
+
// Check if feedback already submitted
|
|
353
|
+
if (existsSync(feedbackPath)) {
|
|
354
|
+
try {
|
|
355
|
+
const existing = JSON.parse(readFileSync(feedbackPath, "utf-8"));
|
|
356
|
+
if (existing.status === "approved" || existing.status === "needs-work") {
|
|
357
|
+
mdWatcher.close();
|
|
358
|
+
outputFeedbackResult(existing, sessionId, planTitle);
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
catch {
|
|
363
|
+
/* ignore */
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return new Promise((resolve) => {
|
|
367
|
+
const fbWatcher = watch(feedbackPath, {
|
|
368
|
+
awaitWriteFinish: { stabilityThreshold: 200, pollInterval: 100 },
|
|
369
|
+
});
|
|
370
|
+
const check = () => {
|
|
371
|
+
try {
|
|
372
|
+
if (!existsSync(feedbackPath))
|
|
373
|
+
return;
|
|
374
|
+
const data = JSON.parse(readFileSync(feedbackPath, "utf-8"));
|
|
375
|
+
if (data.status === "approved" || data.status === "needs-work") {
|
|
376
|
+
fbWatcher.close();
|
|
377
|
+
mdWatcher.close();
|
|
378
|
+
outputFeedbackResult(data, sessionId, planTitle);
|
|
379
|
+
resolve();
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
catch {
|
|
383
|
+
/* ignore parse errors during writes */
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
fbWatcher.on("change", check);
|
|
387
|
+
fbWatcher.on("add", check);
|
|
388
|
+
process.on("SIGINT", () => {
|
|
389
|
+
fbWatcher.close();
|
|
390
|
+
mdWatcher.close();
|
|
391
|
+
console.error("\nStopped watching.");
|
|
392
|
+
process.exit(0);
|
|
393
|
+
});
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
function outputFeedbackResult(feedback, sessionId, planTitle) {
|
|
397
|
+
const unresolvedComments = feedback.comments.filter((c) => !c.resolved);
|
|
398
|
+
outputJson({
|
|
399
|
+
event: "feedback",
|
|
400
|
+
sessionId,
|
|
401
|
+
planTitle,
|
|
402
|
+
status: feedback.status,
|
|
403
|
+
comments: unresolvedComments,
|
|
404
|
+
commentCount: unresolvedComments.length,
|
|
405
|
+
});
|
|
406
|
+
process.exit(feedback.status === "approved" ? EXIT_APPROVED : EXIT_NEEDS_WORK);
|
|
407
|
+
}
|
package/dist/cli/index.js
CHANGED
|
@@ -42,26 +42,90 @@ export function parseArgs(argv) {
|
|
|
42
42
|
function usage() {
|
|
43
43
|
console.log(`plan-assistant - Review implementation plans in the browser
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
Workflow:
|
|
46
|
+
1. plan-assistant init --output plan.md Create correctly-formatted template
|
|
47
|
+
2. # Edit plan.md with your plan content
|
|
48
|
+
3. plan-assistant review plan.md Open in browser, wait for Approve/Request Changes
|
|
49
|
+
4. # review exits with the feedback result automatically
|
|
50
|
+
|
|
51
|
+
Commands:
|
|
52
|
+
plan-assistant init [--output <file>] Generate plan template (stdout if no --output)
|
|
46
53
|
plan-assistant review <markdown-file> Parse and review a plan
|
|
47
54
|
plan-assistant status <session-id-or-file> Check review status
|
|
48
55
|
plan-assistant feedback <session-id-or-file> Read feedback JSON
|
|
49
56
|
plan-assistant list [--dir <path>] List all sessions
|
|
50
|
-
plan-assistant init [--output <file>] Generate plan template
|
|
51
57
|
plan-assistant clean [--all] [--older-than <dur>] Remove old sessions
|
|
52
58
|
plan-assistant export <session-id-or-file> Export as HTML
|
|
59
|
+
plan-assistant help format Show the required plan format
|
|
53
60
|
plan-assistant help Show this help
|
|
54
61
|
|
|
55
62
|
Flags:
|
|
56
63
|
--pretty Human-readable output (default: JSON)
|
|
57
|
-
--port <N> Port for review server
|
|
64
|
+
--port <N> Port for review server (review command)
|
|
65
|
+
--no-wait Don't wait for feedback, just start server (review command)
|
|
58
66
|
--wait Block until feedback is submitted (status command)
|
|
59
67
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
68
|
+
TIP: Always start with \`plan-assistant init\` to get a correctly-formatted template.
|
|
69
|
+
Run \`plan-assistant help format\` to see the expected markdown structure.`);
|
|
70
|
+
}
|
|
71
|
+
function usageFormat() {
|
|
72
|
+
console.log(`plan-assistant - Expected plan markdown format
|
|
73
|
+
|
|
74
|
+
Always start with: npx plan-assistant init --output <file>
|
|
75
|
+
|
|
76
|
+
Required structure:
|
|
77
|
+
─────────────────────────────────────────────────────────────────
|
|
78
|
+
# Plan Title
|
|
79
|
+
|
|
80
|
+
## Overview
|
|
81
|
+
Brief description of what this plan accomplishes.
|
|
82
|
+
|
|
83
|
+
## Phase 1: Phase Name
|
|
84
|
+
|
|
85
|
+
### Changes Required:
|
|
86
|
+
|
|
87
|
+
#### 1. Component Name
|
|
88
|
+
**File**: \`path/to/file.ext\`
|
|
89
|
+
Description of what to change.
|
|
90
|
+
|
|
91
|
+
#### 2. Another Component
|
|
92
|
+
**File**: \`path/to/other.ts\`
|
|
93
|
+
Description of changes.
|
|
94
|
+
|
|
95
|
+
### Success Criteria:
|
|
96
|
+
|
|
97
|
+
#### Automated Verification:
|
|
98
|
+
- [ ] \`npm test\`
|
|
99
|
+
|
|
100
|
+
#### Manual Verification:
|
|
101
|
+
- [ ] Manually verify the feature works
|
|
102
|
+
|
|
103
|
+
## Phase 2: Phase Name
|
|
104
|
+
(same structure as Phase 1)
|
|
105
|
+
─────────────────────────────────────────────────────────────────
|
|
106
|
+
|
|
107
|
+
Phase heading formats (all accepted):
|
|
108
|
+
## Phase N: Name (canonical)
|
|
109
|
+
## Phase N - Name
|
|
110
|
+
## Step N: Name
|
|
111
|
+
## Task N: Name
|
|
112
|
+
|
|
113
|
+
Changes section heading alternatives:
|
|
114
|
+
### Changes Required: (canonical)
|
|
115
|
+
### Changes:
|
|
116
|
+
### Modifications:
|
|
117
|
+
|
|
118
|
+
Success Criteria heading alternatives:
|
|
119
|
+
### Success Criteria: (canonical)
|
|
120
|
+
### Criteria:
|
|
121
|
+
### Verification:
|
|
122
|
+
|
|
123
|
+
Optional top-level sections (all H2):
|
|
124
|
+
## Current State
|
|
125
|
+
## What We're NOT Doing
|
|
126
|
+
## Implementation Approach
|
|
127
|
+
## Testing Strategy
|
|
128
|
+
## References`);
|
|
65
129
|
}
|
|
66
130
|
export async function main(args) {
|
|
67
131
|
const parsed = parseArgs(args);
|
|
@@ -97,7 +161,12 @@ export async function main(args) {
|
|
|
97
161
|
case "help":
|
|
98
162
|
case "--help":
|
|
99
163
|
case "-h":
|
|
100
|
-
|
|
164
|
+
if (parsed.positional[0] === "format") {
|
|
165
|
+
usageFormat();
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
usage();
|
|
169
|
+
}
|
|
101
170
|
return;
|
|
102
171
|
default:
|
|
103
172
|
console.error(`Unknown command: ${parsed.command}`);
|
|
@@ -260,7 +260,7 @@ export function tryMatchPhaseHeading(heading, autoNumber) {
|
|
|
260
260
|
return null;
|
|
261
261
|
}
|
|
262
262
|
/** Known top-level section patterns that should NOT be treated as phases */
|
|
263
|
-
|
|
263
|
+
const KNOWN_SECTION_PATTERNS = [
|
|
264
264
|
/^Overview$/i,
|
|
265
265
|
/^Current\s+State/i,
|
|
266
266
|
/What\s+We.*NOT\s+Doing/i,
|
|
@@ -272,8 +272,8 @@ export const KNOWN_SECTION_PATTERNS = [
|
|
|
272
272
|
/^Version$/i,
|
|
273
273
|
/^Summary$/i,
|
|
274
274
|
];
|
|
275
|
-
|
|
276
|
-
|
|
275
|
+
const CHANGES_HEADING_PATTERN = /^(?:Changes\s+Required|Changes|File\s+Changes|Modifications):?$/i;
|
|
276
|
+
const SUCCESS_CRITERIA_HEADING_PATTERN = /^(?:Success\s+Criteria|Criteria|Verification):?$/i;
|
|
277
277
|
export function parsePhases(allSections, ctx) {
|
|
278
278
|
const phases = [];
|
|
279
279
|
let autoNumber = 1;
|
|
@@ -2,7 +2,7 @@ import { Lexer } from "marked";
|
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
3
|
import { basename } from "node:path";
|
|
4
4
|
import { generatePhaseFlowDiagram } from "./mermaid-gen.js";
|
|
5
|
-
import { createParseContext, splitIntoSections, tokensToMarkdown, findSection, collectSectionsUntilLevel, parseKeyDiscoveries, parseScopeExclusions, parsePhases, parseTestingStrategy, parseReferences, tryMatchPhaseHeading,
|
|
5
|
+
import { createParseContext, splitIntoSections, tokensToMarkdown, findSection, collectSectionsUntilLevel, parseKeyDiscoveries, parseScopeExclusions, parsePhases, parseTestingStrategy, parseReferences, tryMatchPhaseHeading, } from "./markdown-parser.js";
|
|
6
6
|
export function sessionIdFromPath(absolutePath) {
|
|
7
7
|
return createHash("sha256").update(absolutePath).digest("hex").slice(0, 8);
|
|
8
8
|
}
|
|
@@ -151,21 +151,3 @@ export function parseMarkdownToPlan(markdown, markdownPath, projectDir, version
|
|
|
151
151
|
};
|
|
152
152
|
return { plan, warnings: ctx.warnings };
|
|
153
153
|
}
|
|
154
|
-
// Export internals for testing
|
|
155
|
-
export const _internal = {
|
|
156
|
-
splitIntoSections,
|
|
157
|
-
tokensToMarkdown,
|
|
158
|
-
findSection,
|
|
159
|
-
collectSectionsUntilLevel,
|
|
160
|
-
parseKeyDiscoveries,
|
|
161
|
-
parseScopeExclusions,
|
|
162
|
-
parseChangesFromHeadings,
|
|
163
|
-
parseChangesFromList,
|
|
164
|
-
parseCriteria,
|
|
165
|
-
parsePhases,
|
|
166
|
-
parseTestingStrategy,
|
|
167
|
-
parseReferences,
|
|
168
|
-
tryMatchPhaseHeading,
|
|
169
|
-
extractFilePath,
|
|
170
|
-
createParseContext,
|
|
171
|
-
};
|
package/dist/cli/utils.js
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
import { existsSync, mkdirSync } from "node:fs";
|
|
2
1
|
export function parseDuration(s) {
|
|
3
2
|
const match = s.match(/^(\d+)(ms|s|m|h|d|w)$/);
|
|
4
3
|
if (!match)
|
|
5
4
|
return null;
|
|
6
5
|
const n = parseInt(match[1], 10);
|
|
7
6
|
switch (match[2]) {
|
|
8
|
-
case "ms":
|
|
9
|
-
|
|
10
|
-
case "
|
|
11
|
-
|
|
12
|
-
case "
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
7
|
+
case "ms":
|
|
8
|
+
return n;
|
|
9
|
+
case "s":
|
|
10
|
+
return n * 1000;
|
|
11
|
+
case "m":
|
|
12
|
+
return n * 60 * 1000;
|
|
13
|
+
case "h":
|
|
14
|
+
return n * 3600 * 1000;
|
|
15
|
+
case "d":
|
|
16
|
+
return n * 86400 * 1000;
|
|
17
|
+
case "w":
|
|
18
|
+
return n * 7 * 86400 * 1000;
|
|
19
|
+
default:
|
|
20
|
+
return null;
|
|
20
21
|
}
|
|
21
22
|
}
|