@selesai/code 0.3.9 → 0.4.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 (222) hide show
  1. package/dist/cli/args.d.ts.map +1 -1
  2. package/dist/cli/args.js +4 -4
  3. package/dist/cli/args.js.map +1 -1
  4. package/dist/cli/config-selector.d.ts +4 -2
  5. package/dist/cli/config-selector.d.ts.map +1 -1
  6. package/dist/cli/config-selector.js +1 -1
  7. package/dist/cli/config-selector.js.map +1 -1
  8. package/dist/cli/file-processor.d.ts.map +1 -1
  9. package/dist/cli/file-processor.js +13 -25
  10. package/dist/cli/file-processor.js.map +1 -1
  11. package/dist/core/agent-session.d.ts +22 -5
  12. package/dist/core/agent-session.d.ts.map +1 -1
  13. package/dist/core/agent-session.js +130 -49
  14. package/dist/core/agent-session.js.map +1 -1
  15. package/dist/core/auth-storage.d.ts.map +1 -1
  16. package/dist/core/auth-storage.js +13 -5
  17. package/dist/core/auth-storage.js.map +1 -1
  18. package/dist/core/cache-stats.d.ts +49 -0
  19. package/dist/core/cache-stats.d.ts.map +1 -0
  20. package/dist/core/cache-stats.js +101 -0
  21. package/dist/core/cache-stats.js.map +1 -0
  22. package/dist/core/compaction/compaction.d.ts +1 -2
  23. package/dist/core/compaction/compaction.d.ts.map +1 -1
  24. package/dist/core/compaction/compaction.js +56 -81
  25. package/dist/core/compaction/compaction.js.map +1 -1
  26. package/dist/core/extensions/index.d.ts +1 -1
  27. package/dist/core/extensions/index.d.ts.map +1 -1
  28. package/dist/core/extensions/index.js.map +1 -1
  29. package/dist/core/extensions/loader.d.ts.map +1 -1
  30. package/dist/core/extensions/loader.js +10 -0
  31. package/dist/core/extensions/loader.js.map +1 -1
  32. package/dist/core/extensions/runner.d.ts +5 -3
  33. package/dist/core/extensions/runner.d.ts.map +1 -1
  34. package/dist/core/extensions/runner.js +38 -0
  35. package/dist/core/extensions/runner.js.map +1 -1
  36. package/dist/core/extensions/types.d.ts +41 -12
  37. package/dist/core/extensions/types.d.ts.map +1 -1
  38. package/dist/core/extensions/types.js.map +1 -1
  39. package/dist/core/http-dispatcher.d.ts.map +1 -1
  40. package/dist/core/http-dispatcher.js +28 -1
  41. package/dist/core/http-dispatcher.js.map +1 -1
  42. package/dist/core/index.d.ts +1 -1
  43. package/dist/core/index.d.ts.map +1 -1
  44. package/dist/core/index.js.map +1 -1
  45. package/dist/core/keybindings.d.ts.map +1 -1
  46. package/dist/core/keybindings.js +3 -6
  47. package/dist/core/keybindings.js.map +1 -1
  48. package/dist/core/model-registry.d.ts +4 -6
  49. package/dist/core/model-registry.d.ts.map +1 -1
  50. package/dist/core/model-registry.js +34 -8
  51. package/dist/core/model-registry.js.map +1 -1
  52. package/dist/core/model-resolver.d.ts +10 -0
  53. package/dist/core/model-resolver.d.ts.map +1 -1
  54. package/dist/core/model-resolver.js +15 -18
  55. package/dist/core/model-resolver.js.map +1 -1
  56. package/dist/core/package-manager.d.ts +4 -1
  57. package/dist/core/package-manager.d.ts.map +1 -1
  58. package/dist/core/package-manager.js +68 -26
  59. package/dist/core/package-manager.js.map +1 -1
  60. package/dist/core/provider-attribution.d.ts.map +1 -1
  61. package/dist/core/provider-attribution.js +0 -10
  62. package/dist/core/provider-attribution.js.map +1 -1
  63. package/dist/core/resource-loader.d.ts +2 -2
  64. package/dist/core/resource-loader.d.ts.map +1 -1
  65. package/dist/core/resource-loader.js +8 -7
  66. package/dist/core/resource-loader.js.map +1 -1
  67. package/dist/core/sdk.d.ts +1 -1
  68. package/dist/core/sdk.d.ts.map +1 -1
  69. package/dist/core/sdk.js +8 -1
  70. package/dist/core/sdk.js.map +1 -1
  71. package/dist/core/session-manager.d.ts +21 -2
  72. package/dist/core/session-manager.d.ts.map +1 -1
  73. package/dist/core/session-manager.js +104 -72
  74. package/dist/core/session-manager.js.map +1 -1
  75. package/dist/core/settings-manager.d.ts +14 -3
  76. package/dist/core/settings-manager.d.ts.map +1 -1
  77. package/dist/core/settings-manager.js +29 -1
  78. package/dist/core/settings-manager.js.map +1 -1
  79. package/dist/core/slash-commands.d.ts +1 -0
  80. package/dist/core/slash-commands.d.ts.map +1 -1
  81. package/dist/core/slash-commands.js +3 -3
  82. package/dist/core/slash-commands.js.map +1 -1
  83. package/dist/core/timings.d.ts +4 -2
  84. package/dist/core/timings.d.ts.map +1 -1
  85. package/dist/core/timings.js +24 -14
  86. package/dist/core/timings.js.map +1 -1
  87. package/dist/core/tools/bash.d.ts.map +1 -1
  88. package/dist/core/tools/bash.js +20 -5
  89. package/dist/core/tools/bash.js.map +1 -1
  90. package/dist/core/tools/edit.d.ts.map +1 -1
  91. package/dist/core/tools/edit.js +2 -2
  92. package/dist/core/tools/edit.js.map +1 -1
  93. package/dist/core/tools/read.d.ts.map +1 -1
  94. package/dist/core/tools/read.js +12 -25
  95. package/dist/core/tools/read.js.map +1 -1
  96. package/dist/defaults/models.json +2 -3
  97. package/dist/extensions/caveman/index.js +16 -1
  98. package/dist/extensions/caveman/test/extension.test.js +7 -4
  99. package/dist/extensions/caveman/test/helpers.test.js +12 -1
  100. package/dist/extensions/context-compaction-reminder.test.ts +82 -0
  101. package/dist/extensions/context-compaction-reminder.ts +28 -0
  102. package/dist/extensions/handoff-new.test.ts +2 -13
  103. package/dist/extensions/handoff-new.ts +16 -25
  104. package/dist/extensions/package.json +1 -0
  105. package/dist/extensions/pi-subagents/agents/architect.md +25 -173
  106. package/dist/extensions/pi-subagents/agents/builder.md +16 -105
  107. package/dist/extensions/pi-subagents/agents/commentator.md +19 -116
  108. package/dist/extensions/pi-subagents/agents/explorer.md +13 -33
  109. package/dist/extensions/pi-subagents/agents/recapper.md +19 -11
  110. package/dist/extensions/pi-subagents/agents/researcher.md +10 -33
  111. package/dist/extensions/question/constants.ts +0 -7
  112. package/dist/extensions/question/index.ts +11 -108
  113. package/dist/extensions/question/schemas.ts +1 -26
  114. package/dist/extensions/question/shortcuts.ts +5 -14
  115. package/dist/extensions/question/tests/question-list.test.ts +8 -0
  116. package/dist/extensions/question/tests/ui-protocol.test.ts +1 -7
  117. package/dist/extensions/question/tui-adapter.ts +3 -20
  118. package/dist/extensions/question/types.ts +0 -6
  119. package/dist/extensions/question/ui-protocol.ts +2 -17
  120. package/dist/extensions/workflow/adapter.ts +384 -124
  121. package/dist/extensions/workflow/extension.ts +2 -1
  122. package/dist/extensions/workflow/modes/prototype.ts +6 -6
  123. package/dist/extensions/workflow/modes/quick.ts +6 -6
  124. package/dist/extensions/workflow/modes/task.ts +79 -0
  125. package/dist/extensions/workflow/run-state.ts +124 -0
  126. package/dist/extensions/workflow/state-machine.ts +4 -8
  127. package/dist/index.d.ts +3 -2
  128. package/dist/index.d.ts.map +1 -1
  129. package/dist/index.js +2 -1
  130. package/dist/index.js.map +1 -1
  131. package/dist/main.d.ts +2 -2
  132. package/dist/main.d.ts.map +1 -1
  133. package/dist/main.js +17 -4
  134. package/dist/main.js.map +1 -1
  135. package/dist/modes/interactive/components/assistant-message.d.ts +3 -1
  136. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  137. package/dist/modes/interactive/components/assistant-message.js +23 -15
  138. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  139. package/dist/modes/interactive/components/config-selector.d.ts +34 -3
  140. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  141. package/dist/modes/interactive/components/config-selector.js +280 -25
  142. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  143. package/dist/modes/interactive/components/custom-entry.d.ts +19 -0
  144. package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -0
  145. package/dist/modes/interactive/components/custom-entry.js +52 -0
  146. package/dist/modes/interactive/components/custom-entry.js.map +1 -0
  147. package/dist/modes/interactive/components/extension-editor.d.ts +3 -1
  148. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  149. package/dist/modes/interactive/components/extension-editor.js +12 -3
  150. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  151. package/dist/modes/interactive/components/footer.d.ts +4 -0
  152. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  153. package/dist/modes/interactive/components/footer.js +1 -1
  154. package/dist/modes/interactive/components/footer.js.map +1 -1
  155. package/dist/modes/interactive/components/oauth-selector.d.ts +3 -1
  156. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  157. package/dist/modes/interactive/components/oauth-selector.js +17 -6
  158. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  159. package/dist/modes/interactive/components/settings-selector.d.ts +4 -0
  160. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  161. package/dist/modes/interactive/components/settings-selector.js +25 -2
  162. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  163. package/dist/modes/interactive/components/status-indicator.d.ts +28 -0
  164. package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -0
  165. package/dist/modes/interactive/components/status-indicator.js +60 -0
  166. package/dist/modes/interactive/components/status-indicator.js.map +1 -0
  167. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  168. package/dist/modes/interactive/components/thinking-selector.js +2 -1
  169. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  170. package/dist/modes/interactive/components/user-message.d.ts +6 -2
  171. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  172. package/dist/modes/interactive/components/user-message.js +19 -6
  173. package/dist/modes/interactive/components/user-message.js.map +1 -1
  174. package/dist/modes/interactive/interactive-mode.d.ts +21 -10
  175. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  176. package/dist/modes/interactive/interactive-mode.js +417 -196
  177. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  178. package/dist/modes/interactive/theme/dark.json +1 -0
  179. package/dist/modes/interactive/theme/light.json +1 -0
  180. package/dist/modes/interactive/theme/theme-schema.json +6 -2
  181. package/dist/modes/interactive/theme/theme.d.ts +3 -2
  182. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  183. package/dist/modes/interactive/theme/theme.js +10 -3
  184. package/dist/modes/interactive/theme/theme.js.map +1 -1
  185. package/dist/modes/print-mode.d.ts.map +1 -1
  186. package/dist/modes/print-mode.js +1 -1
  187. package/dist/modes/print-mode.js.map +1 -1
  188. package/dist/modes/rpc/rpc-client.d.ts +21 -6
  189. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  190. package/dist/modes/rpc/rpc-client.js +17 -3
  191. package/dist/modes/rpc/rpc-client.js.map +1 -1
  192. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  193. package/dist/modes/rpc/rpc-mode.js +20 -1
  194. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  195. package/dist/modes/rpc/rpc-types.d.ts +26 -0
  196. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  197. package/dist/modes/rpc/rpc-types.js.map +1 -1
  198. package/dist/package-manager-cli.d.ts +2 -2
  199. package/dist/package-manager-cli.d.ts.map +1 -1
  200. package/dist/package-manager-cli.js +71 -17
  201. package/dist/package-manager-cli.js.map +1 -1
  202. package/dist/rpc-entry.d.ts +3 -0
  203. package/dist/rpc-entry.d.ts.map +1 -0
  204. package/dist/rpc-entry.js +10 -0
  205. package/dist/rpc-entry.js.map +1 -0
  206. package/dist/skills/workflow-creation/SKILL.md +72 -0
  207. package/dist/utils/clipboard-image.d.ts.map +1 -1
  208. package/dist/utils/clipboard-image.js +1 -1
  209. package/dist/utils/clipboard-image.js.map +1 -1
  210. package/dist/utils/image-convert.d.ts +1 -0
  211. package/dist/utils/image-convert.d.ts.map +1 -1
  212. package/dist/utils/image-convert.js +21 -15
  213. package/dist/utils/image-convert.js.map +1 -1
  214. package/dist/utils/image-process.d.ts +18 -0
  215. package/dist/utils/image-process.d.ts.map +1 -0
  216. package/dist/utils/image-process.js +83 -0
  217. package/dist/utils/image-process.js.map +1 -0
  218. package/dist/utils/mime.d.ts.map +1 -1
  219. package/dist/utils/mime.js +41 -0
  220. package/dist/utils/mime.js.map +1 -1
  221. package/docs/workflows.md +40 -6
  222. package/package.json +8 -5
@@ -112,47 +112,40 @@ export function getLatestCompactionEntry(entries) {
112
112
  }
113
113
  return null;
114
114
  }
115
- /**
116
- * Build the session context from entries using tree traversal.
117
- * If leafId is provided, walks from that entry to root.
118
- * Handles compaction and branch summaries along the path.
119
- */
120
- export function buildSessionContext(entries, leafId, byId) {
121
- // Build uuid index if not available
122
- if (!byId) {
123
- byId = new Map();
124
- for (const entry of entries) {
125
- byId.set(entry.id, entry);
126
- }
115
+ function buildEntryIndex(entries, byId) {
116
+ if (byId)
117
+ return byId;
118
+ const index = new Map();
119
+ for (const entry of entries) {
120
+ index.set(entry.id, entry);
127
121
  }
128
- // Find leaf
122
+ return index;
123
+ }
124
+ function buildSessionPath(entries, leafId, byId) {
125
+ const index = buildEntryIndex(entries, byId);
129
126
  let leaf;
130
127
  if (leafId === null) {
131
- // Explicitly null - return no messages (navigated to before first entry)
132
- return { messages: [], thinkingLevel: "off", model: null };
128
+ return [];
133
129
  }
134
130
  if (leafId) {
135
- leaf = byId.get(leafId);
131
+ leaf = index.get(leafId);
136
132
  }
133
+ leaf ??= entries[entries.length - 1];
137
134
  if (!leaf) {
138
- // Fallback to last entry (when leafId is undefined)
139
- leaf = entries[entries.length - 1];
140
- }
141
- if (!leaf) {
142
- return { messages: [], thinkingLevel: "off", model: null };
135
+ return [];
143
136
  }
144
- // Walk from leaf to root, collecting path
145
137
  const path = [];
146
138
  let current = leaf;
147
139
  while (current) {
148
140
  path.push(current);
149
- current = current.parentId ? byId.get(current.parentId) : undefined;
141
+ current = current.parentId ? index.get(current.parentId) : undefined;
150
142
  }
151
143
  path.reverse();
152
- // Extract settings and find compaction
144
+ return path;
145
+ }
146
+ function getSessionContextSettings(path) {
153
147
  let thinkingLevel = "off";
154
148
  let model = null;
155
- let compaction = null;
156
149
  for (const entry of path) {
157
150
  if (entry.type === "thinking_level_change") {
158
151
  thinkingLevel = entry.thinkingLevel;
@@ -163,55 +156,83 @@ export function buildSessionContext(entries, leafId, byId) {
163
156
  else if (entry.type === "message" && entry.message.role === "assistant") {
164
157
  model = { provider: entry.message.provider, modelId: entry.message.model };
165
158
  }
166
- else if (entry.type === "compaction") {
167
- compaction = entry;
168
- }
169
159
  }
170
- // Build messages and collect corresponding entries
171
- // When there's a compaction, we need to:
172
- // 1. Emit summary first (entry = compaction)
173
- // 2. Emit kept messages (from firstKeptEntryId up to compaction)
174
- // 3. Emit messages after compaction
175
- const messages = [];
176
- const appendMessage = (entry) => {
177
- if (entry.type === "message") {
178
- messages.push(entry.message);
179
- }
180
- else if (entry.type === "custom_message") {
181
- messages.push(createCustomMessage(entry.customType, entry.content, entry.display, entry.details, entry.timestamp));
182
- }
183
- else if (entry.type === "branch_summary" && entry.summary) {
184
- messages.push(createBranchSummaryMessage(entry.summary, entry.fromId, entry.timestamp));
185
- }
186
- };
187
- if (compaction) {
188
- // Emit summary first
189
- messages.push(createCompactionSummaryMessage(compaction.summary, compaction.tokensBefore, compaction.timestamp));
190
- // Find compaction index in path
191
- const compactionIdx = path.findIndex((e) => e.type === "compaction" && e.id === compaction.id);
192
- // Emit kept messages (before compaction, starting from firstKeptEntryId)
193
- let foundFirstKept = false;
194
- for (let i = 0; i < compactionIdx; i++) {
195
- const entry = path[i];
196
- if (entry.id === compaction.firstKeptEntryId) {
197
- foundFirstKept = true;
198
- }
199
- if (foundFirstKept) {
200
- appendMessage(entry);
201
- }
160
+ return { thinkingLevel, model };
161
+ }
162
+ /**
163
+ * Project one selected session entry into LLM/runtime messages.
164
+ * Plain custom entries are display/state entries and do not participate in context.
165
+ */
166
+ export function sessionEntryToContextMessages(entry) {
167
+ if (entry.type === "message") {
168
+ const message = entry.message;
169
+ // Session files are parsed without validation; old versions, forks, or
170
+ // hand-edited files can contain messages with null/missing content.
171
+ if ((message.role === "user" || message.role === "assistant" || message.role === "toolResult") &&
172
+ message.content == null) {
173
+ return [{ ...message, content: [] }];
202
174
  }
203
- // Emit messages after compaction
204
- for (let i = compactionIdx + 1; i < path.length; i++) {
205
- const entry = path[i];
206
- appendMessage(entry);
175
+ return [message];
176
+ }
177
+ if (entry.type === "custom_message") {
178
+ return [
179
+ createCustomMessage(entry.customType, entry.content ?? [], entry.display, entry.details, entry.timestamp),
180
+ ];
181
+ }
182
+ if (entry.type === "branch_summary" && entry.summary) {
183
+ return [createBranchSummaryMessage(entry.summary, entry.fromId, entry.timestamp)];
184
+ }
185
+ if (entry.type === "compaction") {
186
+ return [createCompactionSummaryMessage(entry.summary, entry.tokensBefore, entry.timestamp)];
187
+ }
188
+ return [];
189
+ }
190
+ /**
191
+ * Build the active, compaction-aware session entry list.
192
+ *
193
+ * This follows the current leaf path. If the path contains compaction entries,
194
+ * the latest compaction is represented by the compaction entry itself, followed
195
+ * by the kept entries starting at firstKeptEntryId and all entries after the
196
+ * compaction entry. Older summarized entries are omitted.
197
+ */
198
+ export function buildContextEntries(entries, leafId, byId) {
199
+ const path = buildSessionPath(entries, leafId, byId);
200
+ let compaction = null;
201
+ for (const entry of path) {
202
+ if (entry.type === "compaction") {
203
+ compaction = entry;
207
204
  }
208
205
  }
209
- else {
210
- // No compaction - emit all messages, handle branch summaries and custom messages
211
- for (const entry of path) {
212
- appendMessage(entry);
206
+ if (!compaction) {
207
+ return path;
208
+ }
209
+ const compactionIdx = path.findIndex((entry) => entry.id === compaction.id);
210
+ if (compactionIdx < 0) {
211
+ return path;
212
+ }
213
+ const contextEntries = [compaction];
214
+ let foundFirstKept = false;
215
+ for (let i = 0; i < compactionIdx; i++) {
216
+ const entry = path[i];
217
+ if (entry.id === compaction.firstKeptEntryId) {
218
+ foundFirstKept = true;
219
+ }
220
+ if (foundFirstKept) {
221
+ contextEntries.push(entry);
213
222
  }
214
223
  }
224
+ contextEntries.push(...path.slice(compactionIdx + 1));
225
+ return contextEntries;
226
+ }
227
+ /**
228
+ * Build the session context from entries using tree traversal.
229
+ * If leafId is provided, walks from that entry to root.
230
+ * Handles compaction and branch summaries along the path.
231
+ */
232
+ export function buildSessionContext(entries, leafId, byId) {
233
+ const path = buildSessionPath(entries, leafId, byId);
234
+ const { thinkingLevel, model } = getSessionContextSettings(path);
235
+ const messages = buildContextEntries(entries, leafId, byId).flatMap(sessionEntryToContextMessages);
215
236
  return { messages, thinkingLevel, model };
216
237
  }
217
238
  /**
@@ -533,10 +554,13 @@ export class SessionManager {
533
554
  this.sessionFile = resolvePath(sessionFile);
534
555
  if (existsSync(this.sessionFile)) {
535
556
  this.fileEntries = loadEntriesFromFile(this.sessionFile);
536
- // If file was empty or corrupted (no valid header), truncate and start fresh
537
- // to avoid appending messages without a session header (which breaks the session)
557
+ // If file was empty, initialize it with a valid session header. If it was
558
+ // non-empty but did not parse as a pi session, fail without modifying it.
538
559
  if (this.fileEntries.length === 0) {
539
560
  const explicitPath = this.sessionFile;
561
+ if (statSync(explicitPath).size > 0) {
562
+ throw new Error(`Session file is not a valid pi session: ${explicitPath}`);
563
+ }
540
564
  this.newSession();
541
565
  this.sessionFile = explicitPath;
542
566
  this._rewriteFile();
@@ -574,6 +598,7 @@ export class SessionManager {
574
598
  this.fileEntries = [header];
575
599
  this.byId.clear();
576
600
  this.labelsById.clear();
601
+ this.labelTimestampsById.clear();
577
602
  this.leafId = null;
578
603
  this.flushed = false;
579
604
  if (this.persist) {
@@ -864,6 +889,13 @@ export class SessionManager {
864
889
  path.reverse();
865
890
  return path;
866
891
  }
892
+ /**
893
+ * Build the active, compaction-aware entry list for context/rendering.
894
+ * Uses tree traversal from current leaf.
895
+ */
896
+ buildContextEntries() {
897
+ return buildContextEntries(this.getEntries(), this.leafId, this.byId);
898
+ }
867
899
  /**
868
900
  * Build the session context (what gets sent to the LLM).
869
901
  * Uses tree traversal from current leaf.
@@ -1113,8 +1145,8 @@ export class SessionManager {
1113
1145
  return new SessionManager(cwd, dir, undefined, true);
1114
1146
  }
1115
1147
  /** Create an in-memory session (no file persistence) */
1116
- static inMemory(cwd = process.cwd()) {
1117
- return new SessionManager(cwd, "", undefined, false);
1148
+ static inMemory(cwd = process.cwd(), options) {
1149
+ return new SessionManager(cwd, "", undefined, false, options);
1118
1150
  }
1119
1151
  /**
1120
1152
  * Fork a session from another project directory into the current project.